diff --git a/.gitmodules b/.gitmodules index ad09aba35..4b450aaf3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ [submodule "extern/test-vectors"] path = extern/test-vectors url = https://github.com/filecoin-project/test-vectors.git +[submodule "extern/fil-blst"] + path = extern/fil-blst + url = https://github.com/filecoin-project/fil-blst.git diff --git a/api/api_full.go b/api/api_full.go index a604028fb..23226443a 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -118,7 +118,8 @@ type FullNode interface { // The exported chain data includes the header chain from the given tipset // back to genesis, the entire genesis state, and the most recent 'nroots' // state trees. - ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) + // If oldmsgskip is set, messages from before the requested roots are also not included. + ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) // MethodGroup: Beacon // The Beacon method group contains methods for interacting with the random beacon (DRAND) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 6f32d204b..fdb9843ff 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -95,7 +95,7 @@ type FullNodeStruct struct { ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"` ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"` ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"` - ChainExport func(context.Context, abi.ChainEpoch, types.TipSetKey) (<-chan []byte, error) `perm:"read"` + ChainExport func(context.Context, abi.ChainEpoch, bool, types.TipSetKey) (<-chan []byte, error) `perm:"read"` BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` @@ -692,8 +692,8 @@ func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey, return c.Internal.ChainGetPath(ctx, from, to) } -func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) { - return c.Internal.ChainExport(ctx, nroots, tsk) +func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, iom bool, tsk types.TipSetKey) (<-chan []byte, error) { + return c.Internal.ChainExport(ctx, nroots, iom, tsk) } func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) { diff --git a/api/test/window_post.go b/api/test/window_post.go index 59d7ac1d6..3f15c754b 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -192,7 +192,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector // Drop the partition err = parts[0].Sectors.ForEach(func(sid uint64) error { - return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(abi.SectorID{ + return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkCorrupted(abi.SectorID{ Miner: abi.ActorID(mid), Number: abi.SectorNumber(sid), }, true) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 06cbe65e7..f86d2ccf0 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -12,6 +12,7 @@ import ( "time" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" @@ -160,6 +161,22 @@ func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount { return types.BigAdd(minPrice, types.NewInt(1)) } +func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) { + if maxFee.Equals(big.Zero()) { + maxFee = types.NewInt(build.FilecoinPrecision / 10) + } + + gl := types.NewInt(uint64(msg.GasLimit)) + totalFee := types.BigMul(msg.GasFeeCap, gl) + + if totalFee.LessThanEqual(maxFee) { + return + } + + msg.GasFeeCap = big.Div(maxFee, gl) + msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap +} + func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) { nextNonce := ms.nextNonce nonceGap := false @@ -399,7 +416,7 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T publish := local if strictBaseFeeValidation && len(curTs.Blocks()) > 0 { baseFee := curTs.Blocks()[0].ParentBaseFee - baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { if local { log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)", @@ -1282,3 +1299,12 @@ func (mp *MessagePool) Clear(local bool) { delete(mp.pending, a) } } + +func getBaseFeeLowerBound(baseFee types.BigInt) types.BigInt { + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + if baseFeeLowerBound.LessThan(minimumBaseFee) { + baseFeeLowerBound = minimumBaseFee + } + + return baseFeeLowerBound +} diff --git a/chain/messagepool/pruning.go b/chain/messagepool/pruning.go index d1290e386..fd8199b89 100644 --- a/chain/messagepool/pruning.go +++ b/chain/messagepool/pruning.go @@ -46,13 +46,21 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro if err != nil { return xerrors.Errorf("computing basefee: %w", err) } + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) pending, _ := mp.getPendingMessages(ts, ts) - // priority actors -- not pruned - priority := make(map[address.Address]struct{}) + // protected actors -- not pruned + protected := make(map[address.Address]struct{}) + + // we never prune priority addresses for _, actor := range mp.cfg.PriorityAddrs { - priority[actor] = struct{}{} + protected[actor] = struct{}{} + } + + // we also never prune locally published messages + for actor := range mp.localAddrs { + protected[actor] = struct{}{} } // Collect all messages to track which ones to remove and create chains for block inclusion @@ -61,18 +69,18 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro var chains []*msgChain for actor, mset := range pending { - // we never prune priority actors - _, keep := priority[actor] + // we never prune protected actors + _, keep := protected[actor] if keep { keepCount += len(mset) continue } - // not a priority actor, track the messages and create chains + // not a protected actor, track the messages and create chains for _, m := range mset { pruneMsgs[m.Message.Cid()] = m } - actorChains := mp.createMessageChains(actor, mset, baseFee, ts) + actorChains := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts) chains = append(chains, actorChains...) } diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index fd0324d0a..7e651e426 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -27,11 +27,7 @@ func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Unlock() return xerrors.Errorf("computing basefee: %w", err) } - - baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) - if baseFeeLowerBoundFactor.LessThan(minimumBaseFee) { - baseFeeLowerBound = minimumBaseFee - } + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) pending := make(map[address.Address]map[uint64]*types.SignedMessage) mp.lk.Lock() diff --git a/chain/store/store.go b/chain/store/store.go index c85f547a1..d5ecf95ef 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -1159,7 +1159,7 @@ func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid. return in, rerr } -func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, w io.Writer) error { +func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error { if ts == nil { ts = cs.GetHeaviestTipSet() } @@ -1197,9 +1197,13 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err) } - cids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages}) - if err != nil { - return xerrors.Errorf("recursing messages failed: %w", err) + var cids []cid.Cid + if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots { + mcids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages}) + if err != nil { + return xerrors.Errorf("recursing messages failed: %w", err) + } + cids = mcids } if b.Height > 0 { diff --git a/chain/store/store_test.go b/chain/store/store_test.go index 1e3673f44..e56bab4c9 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) { } buf := new(bytes.Buffer) - if err := cg.ChainStore().Export(context.TODO(), last, 0, buf); err != nil { + if err := cg.ChainStore().Export(context.TODO(), last, 0, false, buf); err != nil { t.Fatal(err) } diff --git a/cli/chain.go b/cli/chain.go index ce1660641..36288c7d7 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -844,6 +844,9 @@ var chainExportCmd = &cli.Command{ Name: "recent-stateroots", Usage: "specify the number of recent state roots to include in the export", }, + &cli.BoolFlag{ + Name: "skip-old-msgs", + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -878,7 +881,13 @@ var chainExportCmd = &cli.Command{ return err } - stream, err := api.ChainExport(ctx, rsrs, ts.Key()) + skipold := cctx.Bool("skip-old-msgs") + + if rsrs == 0 && skipold { + return fmt.Errorf("must pass recent stateroots along with skip-old-msgs") + } + + stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key()) if err != nil { return err } diff --git a/cli/mpool.go b/cli/mpool.go index 6ae94356a..65f4ef942 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -303,6 +303,10 @@ var mpoolReplaceCmd = &cli.Command{ Name: "auto", Usage: "automatically reprice the specified message", }, + &cli.StringFlag{ + Name: "max-fee", + Usage: "Spend up to X FIL for this message (applicable for auto mode)", + }, }, ArgsUsage: "[from] [nonce]", Action: func(cctx *cli.Context) error { @@ -353,17 +357,30 @@ var mpoolReplaceCmd = &cli.Command{ msg := found.Message if cctx.Bool("auto") { + minRBF := messagepool.ComputeMinRBF(msg.GasPremium) + + var mss *lapi.MessageSendSpec + if cctx.IsSet("max-fee") { + maxFee, err := types.BigFromString(cctx.String("max-fee")) + if err != nil { + return fmt.Errorf("parsing max-spend: %w", err) + } + mss = &lapi.MessageSendSpec{ + MaxFee: maxFee, + } + } + // msg.GasLimit = 0 // TODO: need to fix the way we estimate gas limits to account for the messages already being in the mempool msg.GasFeeCap = abi.NewTokenAmount(0) msg.GasPremium = abi.NewTokenAmount(0) - retm, err := api.GasEstimateMessageGas(ctx, &msg, &lapi.MessageSendSpec{}, types.EmptyTSK) + retm, err := api.GasEstimateMessageGas(ctx, &msg, mss, types.EmptyTSK) if err != nil { return fmt.Errorf("failed to estimate gas values: %w", err) } - msg.GasFeeCap = retm.GasFeeCap - minRBF := messagepool.ComputeMinRBF(msg.GasPremium) msg.GasPremium = big.Max(retm.GasPremium, minRBF) + msg.GasFeeCap = big.Max(retm.GasFeeCap, msg.GasPremium) + messagepool.CapGasFee(&msg, mss.Get().MaxFee) } else { msg.GasLimit = cctx.Int64("gas-limit") msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) diff --git a/cli/paych.go b/cli/paych.go index bcd8e33f0..57fd1c142 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -28,6 +28,7 @@ var paychCmd = &cli.Command{ paychListCmd, paychVoucherCmd, paychSettleCmd, + paychStatusCmd, paychCloseCmd, }, } diff --git a/cli/state.go b/cli/state.go index f84375782..1036e8fe5 100644 --- a/cli/state.go +++ b/cli/state.go @@ -27,6 +27,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/exported" @@ -122,7 +123,7 @@ var stateMinerInfo = &cli.Command{ }, } -func parseTipSetString(ts string) ([]cid.Cid, error) { +func ParseTipSetString(ts string) ([]cid.Cid, error) { strs := strings.Split(ts, ",") var cids []cid.Cid @@ -160,7 +161,7 @@ func ParseTipSetRef(ctx context.Context, api api.FullNode, tss string) (*types.T return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK) } - cids, err := parseTipSetString(tss) + cids, err := ParseTipSetString(tss) if err != nil { return nil, err } @@ -1384,7 +1385,7 @@ var stateCallCmd = &cli.Command{ } if ret.MsgRct.ExitCode != 0 { - return fmt.Errorf("invocation failed (exit: %d): %s", ret.MsgRct.ExitCode, ret.Error) + return fmt.Errorf("invocation failed (exit: %d, gasUsed: %d): %s", ret.MsgRct.ExitCode, ret.MsgRct.GasUsed, ret.Error) } s, err := formatOutput(cctx.String("ret"), ret.MsgRct.Return) @@ -1392,6 +1393,7 @@ var stateCallCmd = &cli.Command{ return fmt.Errorf("failed to format output: %s", err) } + fmt.Printf("gas used: %d\n", ret.MsgRct.GasUsed) fmt.Printf("return: %s\n", s) return nil @@ -1465,11 +1467,11 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er f := methods[method] rf := reflect.TypeOf(f) - if rf.NumIn() != 3 { + if rf.NumIn() != 2 { return nil, fmt.Errorf("expected referenced method to have three arguments") } - paramObj := rf.In(2).Elem() + paramObj := rf.In(1).Elem() if paramObj.NumField() != len(args) { return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField()) } @@ -1489,6 +1491,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er return nil, err } p.Elem().Field(i).Set(reflect.ValueOf(val)) + case reflect.TypeOf(abi.ChainEpoch(0)): + val, err := strconv.ParseInt(args[i], 10, 64) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(abi.ChainEpoch(val))) + case reflect.TypeOf(big.Int{}): + val, err := big.FromString(args[i]) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(val)) case reflect.TypeOf(peer.ID("")): pid, err := peer.Decode(args[i]) if err != nil { diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go new file mode 100644 index 000000000..c12cbd82d --- /dev/null +++ b/cmd/lotus-shed/export.go @@ -0,0 +1,123 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/lotus/node/repo" +) + +var exportChainCmd = &cli.Command{ + Name: "export", + Description: "Export chain from repo (requires node to be offline)", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.StringFlag{ + Name: "tipset", + Usage: "tipset to export from", + }, + &cli.Int64Flag{ + Name: "recent-stateroots", + }, + &cli.BoolFlag{ + Name: "full-state", + }, + &cli.BoolFlag{ + Name: "skip-old-msgs", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return lcli.ShowHelp(cctx, fmt.Errorf("must specify file name to write export to")) + } + + ctx := context.TODO() + + r, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return xerrors.Errorf("opening fs repo: %w", err) + } + + exists, err := r.Exists() + if err != nil { + return err + } + if !exists { + return xerrors.Errorf("lotus repo doesn't exist") + } + + lr, err := r.Lock(repo.FullNode) + if err != nil { + return err + } + defer lr.Close() //nolint:errcheck + + fi, err := os.Create(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("opening the output file: %w", err) + } + + defer fi.Close() //nolint:errcheck + + ds, err := lr.Datastore("/chain") + if err != nil { + return err + } + + mds, err := lr.Datastore("/metadata") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + + cs := store.NewChainStore(bs, mds, nil) + if err := cs.Load(); err != nil { + return err + } + + nroots := abi.ChainEpoch(cctx.Int64("recent-stateroots")) + fullstate := cctx.Bool("full-state") + skipoldmsgs := cctx.Bool("skip-old-msgs") + + var ts *types.TipSet + if tss := cctx.String("tipset"); tss != "" { + cids, err := lcli.ParseTipSetString(tss) + if err != nil { + return xerrors.Errorf("failed to parse tipset (%q): %w", tss, err) + } + + tsk := types.NewTipSetKey(cids...) + + selts, err := cs.LoadTipSet(tsk) + if err != nil { + return xerrors.Errorf("loading tipset: %w", err) + } + ts = selts + } else { + ts = cs.GetHeaviestTipSet() + } + + if fullstate { + nroots = ts.Height() + 1 + } + + if err := cs.Export(ctx, ts, nroots, skipoldmsgs, fi); err != nil { + return xerrors.Errorf("export failed: %w", err) + } + + return nil + }, +} diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 4944b67aa..cff3059b6 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -34,6 +34,7 @@ func main() { genesisVerifyCmd, mathCmd, mpoolStatsCmd, + exportChainCmd, } app := &cli.App{ diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go new file mode 100644 index 000000000..a08267022 --- /dev/null +++ b/conformance/chaos/actor_test.go @@ -0,0 +1,153 @@ +package chaos + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/specs-actors/support/mock" + atesting "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestSingleton(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + msg := "constructor should not be called; the Chaos actor is a singleton actor" + rt.ExpectAssertionFailure(msg, func() { + rt.Call(a.Constructor, abi.Empty) + }) + rt.Verify() +} + +func TestDeleteActor(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + beneficiary := atesting.NewIDAddr(t, 101) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.ExpectDeleteActor(beneficiary) + rt.Call(a.DeleteActor, &beneficiary) + rt.Verify() +} + +func TestMutateStateInTransaction(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateInTransaction, + }) + + var st State + rt.GetState(&st) + + if st.Value != val { + t.Fatal("state was not updated") + } + + rt.Verify() +} + +func TestMutateStateAfterTransaction(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateAfterTransaction, + }) + + var st State + rt.GetState(&st) + + // state should be updated successfully _in_ the transaction but not outside + if st.Value != val+"-in" { + t.Fatal("state was not updated") + } + + rt.Verify() +} + +func TestMutateStateReadonly(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateReadonly, + }) + + var st State + rt.GetState(&st) + + if st.Value != "" { + t.Fatal("state was not expected to be updated") + } + + rt.Verify() +} + +func TestAbortWith(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + msg := "__test forbidden" + rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, msg, func() { + rt.Call(a.AbortWith, &AbortWithArgs{ + Code: exitcode.ErrForbidden, + Message: msg, + Uncontrolled: false, + }) + }) + rt.Verify() +} + +func TestAbortWithUncontrolled(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + msg := "__test uncontrolled panic" + rt.ExpectAssertionFailure(msg, func() { + rt.Call(a.AbortWith, &AbortWithArgs{ + Message: msg, + Uncontrolled: true, + }) + }) + rt.Verify() +} diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 7c2d91881..27875eca1 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -284,6 +284,7 @@ ChainExport returns a stream of bytes with CAR dump of chain data. The exported chain data includes the header chain from the given tipset back to genesis, the entire genesis state, and the most recent 'nroots' state trees. +If oldmsgskip is set, messages from before the requested roots are also not included. Perms: read @@ -292,6 +293,7 @@ Inputs: ```json [ 10101, + true, [ { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" diff --git a/extern/fil-blst b/extern/fil-blst new file mode 160000 index 000000000..5f93488fc --- /dev/null +++ b/extern/fil-blst @@ -0,0 +1 @@ +Subproject commit 5f93488fc0dbfb450f2355269f18fc67010d59bb diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 405691046..f640612a1 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 40569104603407c999d6c9e4c3f1228cbd4d0e5c +Subproject commit f640612a1a1f7a2dd8b3a49e1531db0aa0f63447 diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index ae1ede7eb..d59de2cab 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -168,50 +168,34 @@ func (s *seal) unseal(t *testing.T, sb *Sealer, sp *basicfs.Provider, si abi.Sec } } -func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time { - /*randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7} +func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) { + randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7} - sis := make([]abi.SectorInfo, len(seals)) + sis := make([]saproof.SectorInfo, len(seals)) for i, s := range seals { - sis[i] = abi.SectorInfo{ - RegisteredProof: sealProofType, - SectorNumber: s.id.Number, - SealedCID: s.cids.Sealed, + sis[i] = saproof.SectorInfo{ + SealProof: sealProofType, + SectorNumber: s.id.Number, + SealedCID: s.cids.Sealed, } } - candidates, err := sealer.GenerateEPostCandidates(context.TODO(), seals[0].id.Miner, sis, randomness, []abi.SectorNumber{}) - if err != nil { - t.Fatalf("%+v", err) - }*/ - - fmt.Println("skipping post") - - genCandidates := time.Now() - - /*if len(candidates) != 1 { - t.Fatal("expected 1 candidate") + proofs, skp, err := sealer.GenerateWindowPoSt(context.TODO(), seals[0].id.Miner, sis, randomness) + if len(skipped) > 0 { + require.Error(t, err) + require.EqualValues(t, skipped, skp) + return } - candidatesPrime := make([]abi.PoStCandidate, len(candidates)) - for idx := range candidatesPrime { - candidatesPrime[idx] = candidates[idx].Candidate - } - - proofs, err := sealer.ComputeElectionPoSt(context.TODO(), seals[0].id.Miner, sis, randomness, candidatesPrime) if err != nil { t.Fatalf("%+v", err) } - ePoStChallengeCount := ElectionPostChallengeCount(uint64(len(sis)), 0) - - ok, err := ProofVerifier.VerifyElectionPost(context.TODO(), abi.PoStVerifyInfo{ - Randomness: randomness, - Candidates: candidatesPrime, - Proofs: proofs, - EligibleSectors: sis, - Prover: seals[0].id.Miner, - ChallengeCount: ePoStChallengeCount, + ok, err := ProofVerifier.VerifyWindowPoSt(context.TODO(), saproof.WindowPoStVerifyInfo{ + Randomness: randomness, + Proofs: proofs, + ChallengedSectors: sis, + Prover: seals[0].id.Miner, }) if err != nil { t.Fatalf("%+v", err) @@ -219,8 +203,21 @@ func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time { if !ok { t.Fatal("bad post") } - */ - return genCandidates +} + +func corrupt(t *testing.T, sealer *Sealer, id abi.SectorID) { + paths, done, err := sealer.sectors.AcquireSector(context.Background(), id, stores.FTSealed, 0, stores.PathStorage) + require.NoError(t, err) + defer done() + + log.Infof("corrupt %s", paths.Sealed) + f, err := os.OpenFile(paths.Sealed, os.O_RDWR, 0664) + require.NoError(t, err) + + _, err = f.WriteAt(bytes.Repeat([]byte{'d'}, 2048), 0) + require.NoError(t, err) + + require.NoError(t, f.Close()) } func getGrothParamFileAndVerifyingKeys(s abi.SectorSize) { @@ -299,11 +296,11 @@ func TestSealAndVerify(t *testing.T) { commit := time.Now() - genCandidiates := post(t, sb, s) + post(t, sb, nil, s) epost := time.Now() - post(t, sb, s) + post(t, sb, nil, s) if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil { t.Fatalf("%+v", err) @@ -313,8 +310,7 @@ func TestSealAndVerify(t *testing.T) { fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String()) fmt.Printf("Commit: %s\n", commit.Sub(precommit).String()) - fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(commit).String()) - fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String()) + fmt.Printf("EPoSt: %s\n", epost.Sub(commit).String()) } func TestSealPoStNoCommit(t *testing.T) { @@ -370,16 +366,15 @@ func TestSealPoStNoCommit(t *testing.T) { t.Fatal(err) } - genCandidiates := post(t, sb, s) + post(t, sb, nil, s) epost := time.Now() fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String()) - fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(precommit).String()) - fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String()) + fmt.Printf("EPoSt: %s\n", epost.Sub(precommit).String()) } -func TestSealAndVerify2(t *testing.T) { +func TestSealAndVerify3(t *testing.T) { defer requireFDsClosed(t, openFDs(t)) if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware @@ -419,22 +414,32 @@ func TestSealAndVerify2(t *testing.T) { si1 := abi.SectorID{Miner: miner, Number: 1} si2 := abi.SectorID{Miner: miner, Number: 2} + si3 := abi.SectorID{Miner: miner, Number: 3} s1 := seal{id: si1} s2 := seal{id: si2} + s3 := seal{id: si3} - wg.Add(2) + wg.Add(3) go s1.precommit(t, sb, si1, wg.Done) //nolint: staticcheck time.Sleep(100 * time.Millisecond) go s2.precommit(t, sb, si2, wg.Done) //nolint: staticcheck + time.Sleep(100 * time.Millisecond) + go s3.precommit(t, sb, si3, wg.Done) //nolint: staticcheck wg.Wait() - wg.Add(2) + wg.Add(3) go s1.commit(t, sb, wg.Done) //nolint: staticcheck go s2.commit(t, sb, wg.Done) //nolint: staticcheck + go s3.commit(t, sb, wg.Done) //nolint: staticcheck wg.Wait() - post(t, sb, s1, s2) + post(t, sb, nil, s1, s2, s3) + + corrupt(t, sb, si1) + corrupt(t, sb, si2) + + post(t, sb, []abi.SectorID{si1, si2}, s1, s2, s3) } func BenchmarkWriteWithAlignment(b *testing.B) { diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index 0af12da0b..d6c0ae35f 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -40,8 +40,21 @@ func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, s } defer done() - proof, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) - return proof, skipped, err + if len(skipped) > 0 { + return nil, skipped, xerrors.Errorf("pubSectorToPriv skipped some sectors") + } + + proof, faulty, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) + + var faultyIDs []abi.SectorID + for _, f := range faulty { + faultyIDs = append(faultyIDs, abi.SectorID{ + Miner: minerID, + Number: f, + }) + } + + return proof, faultyIDs, err } func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index b70350ef8..64207e66d 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -66,8 +66,9 @@ const ( ) type sectorState struct { - pieces []cid.Cid - failed bool + pieces []cid.Cid + failed bool + corrupted bool state int @@ -251,6 +252,18 @@ func (mgr *SectorMgr) MarkFailed(sid abi.SectorID, failed bool) error { return nil } +func (mgr *SectorMgr) MarkCorrupted(sid abi.SectorID, corrupted bool) error { + mgr.lk.Lock() + defer mgr.lk.Unlock() + ss, ok := mgr.sectors[sid] + if !ok { + return fmt.Errorf("no such sector in storage") + } + + ss.corrupted = corrupted + return nil +} + func opFinishWait(ctx context.Context) { val, ok := ctx.Value("opfinish").(chan struct{}) if !ok { @@ -275,6 +288,8 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI si := make([]proof.SectorInfo, 0, len(sectorInfo)) var skipped []abi.SectorID + var err error + for _, info := range sectorInfo { sid := abi.SectorID{ Miner: minerID, @@ -283,13 +298,18 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI _, found := mgr.sectors[sid] - if found && !mgr.sectors[sid].failed { + if found && !mgr.sectors[sid].failed && !mgr.sectors[sid].corrupted { si = append(si, info) } else { skipped = append(skipped, sid) + err = xerrors.Errorf("skipped some sectors") } } + if err != nil { + return nil, skipped, err + } + return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil } diff --git a/go.mod b/go.mod index 0cfa1ba9b..4cedea65f 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/filecoin-project/lotus go 1.14 -replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-alpha.1 - require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 @@ -15,7 +13,7 @@ require ( github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e - github.com/dgraph-io/badger/v2 v2.0.3 + github.com/dgraph-io/badger/v2 v2.2007.2 github.com/docker/go-units v0.4.0 github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32 github.com/drand/kyber v1.1.2 @@ -29,7 +27,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.6.0 + github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 @@ -135,6 +133,8 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi -replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 - replace github.com/filecoin-project/test-vectors => ./extern/test-vectors + +replace github.com/supranational/blst => ./extern/fil-blst/blst + +replace github.com/filecoin-project/fil-blst => ./extern/fil-blst diff --git a/go.sum b/go.sum index 1d18f7b42..d5eb25358 100644 --- a/go.sum +++ b/go.sum @@ -167,8 +167,10 @@ github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhY github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= -github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 h1:PIPH4SLjYXMMlX/cQqV7nIRatv7556yqUfWY+KBjrtQ= -github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= @@ -225,8 +227,8 @@ github.com/filecoin-project/go-data-transfer v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGR github.com/filecoin-project/go-data-transfer v0.6.3/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q= -github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw= +github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c h1:YGoyYmELQ0LHwDj/WcOvY3oYt+3iM0wdrAhqJQUAIy4= +github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c/go.mod h1:PLr9svZxsnHkae1Ky7+66g7fP9AlneVxIVu+oSMq56A= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= @@ -1323,8 +1325,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/supranational/blst v0.1.2-alpha.1 h1:v0UqVlvbRNZIaSeMPr+T01kvTUq1h0EZuZ6gnDR1Mlg= -github.com/supranational/blst v0.1.2-alpha.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 4f7361d00..4168792da 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -501,12 +501,12 @@ func (c *ClientNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetToke return head.Key().Bytes(), head.Height(), nil } -func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { +func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error { receipt, err := c.StateWaitMsg(ctx, mcid, build.MessageConfidence) if err != nil { - return cb(0, nil, err) + return cb(0, nil, cid.Undef, err) } - return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil) } func (c *ClientNodeAdapter) GetMinerInfo(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*storagemarket.StorageProviderInfo, error) { diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index 9c4a5946e..49be6fe41 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -355,12 +355,12 @@ func (n *ProviderNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetTo return head.Key().Bytes(), head.Height(), nil } -func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { +func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error { receipt, err := n.StateWaitMsg(ctx, mcid, 2*build.MessageConfidence) if err != nil { - return cb(0, nil, err) + return cb(0, nil, cid.Undef, err) } - return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil) } func (n *ProviderNodeAdapter) GetDataCap(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*verifreg.DataCap, error) { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index c5dd5c9a9..ad2c2944c 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -495,7 +495,7 @@ func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Mess return cm.VMMessage(), nil } -func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) { +func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey) (<-chan []byte, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -508,7 +508,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t bw := bufio.NewWriterSize(w, 1<<20) defer bw.Flush() //nolint:errcheck // it is a write to a pipe - if err := a.Chain.Export(ctx, ts, nroots, bw); err != nil { + if err := a.Chain.Export(ctx, ts, nroots, skipoldmsgs, bw); err != nil { log.Errorf("chain export call failed: %s", err) return } diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 40ab88b6b..a597059e4 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -211,23 +211,7 @@ func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, msg.GasFeeCap = feeCap } - capGasFee(msg, spec.Get().MaxFee) + messagepool.CapGasFee(msg, spec.Get().MaxFee) return msg, nil } - -func capGasFee(msg *types.Message, maxFee abi.TokenAmount) { - if maxFee.Equals(big.Zero()) { - maxFee = types.NewInt(build.FilecoinPrecision / 10) - } - - gl := types.NewInt(uint64(msg.GasLimit)) - totalFee := types.BigMul(msg.GasFeeCap, gl) - - if totalFee.LessThanEqual(maxFee) { - return - } - - msg.GasFeeCap = big.Div(maxFee, gl) - msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap -} diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 84831ecf2..cff110d18 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -337,94 +337,114 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty Proofs: nil, } - var sinfos []proof.SectorInfo - sidToPart := map[abi.SectorNumber]uint64{} skipCount := uint64(0) + postSkipped := bitfield.New() + var postOut []proof.PoStProof - for partIdx, partition := range partitions { - // TODO: Can do this in parallel - toProve, err := partition.ActiveSectors() + for retries := 0; retries < 5; retries++ { + var sinfos []proof.SectorInfo + sidToPart := map[abi.SectorNumber]int{} + + for partIdx, partition := range partitions { + // TODO: Can do this in parallel + toProve, err := partition.ActiveSectors() + if err != nil { + return nil, xerrors.Errorf("getting active sectors: %w", err) + } + + toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) + if err != nil { + return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) + } + + toProve, err = bitfield.SubtractBitField(toProve, postSkipped) + if err != nil { + return nil, xerrors.Errorf("toProve - postSkipped: %w", err) + } + + good, err := s.checkSectors(ctx, toProve) + if err != nil { + return nil, xerrors.Errorf("checking sectors to skip: %w", err) + } + + skipped, err := bitfield.SubtractBitField(toProve, good) + if err != nil { + return nil, xerrors.Errorf("toProve - good: %w", err) + } + + sc, err := skipped.Count() + if err != nil { + return nil, xerrors.Errorf("getting skipped sector count: %w", err) + } + + skipCount += sc + + ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) + if err != nil { + return nil, xerrors.Errorf("getting sorted sector info: %w", err) + } + + if len(ssi) == 0 { + continue + } + + sinfos = append(sinfos, ssi...) + for _, si := range ssi { + sidToPart[si.SectorNumber] = partIdx + } + + params.Partitions = append(params.Partitions, miner.PoStPartition{ + Index: uint64(partIdx), + Skipped: skipped, + }) + } + + if len(sinfos) == 0 { + // nothing to prove.. + return nil, errNoPartitions + } + + log.Infow("running windowPost", + "chain-random", rand, + "deadline", di, + "height", ts.Height(), + "skipped", skipCount) + + tsStart := build.Clock.Now() + + mid, err := address.IDFromAddress(s.actor) if err != nil { - return nil, xerrors.Errorf("getting active sectors: %w", err) + return nil, err } - toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) - if err != nil { - return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) + var ps []abi.SectorID + postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) + elapsed := time.Since(tsStart) + + log.Infow("computing window PoSt", "elapsed", elapsed) + + if err == nil { + break } - good, err := s.checkSectors(ctx, toProve) - if err != nil { - return nil, xerrors.Errorf("checking sectors to skip: %w", err) + if len(ps) == 0 { + return nil, xerrors.Errorf("running post failed: %w", err) } - skipped, err := bitfield.SubtractBitField(toProve, good) - if err != nil { - return nil, xerrors.Errorf("toProve - good: %w", err) + log.Warnw("generate window PoSt skipped sectors", "sectors", ps, "error", err, "try", retries) + + skipCount += uint64(len(ps)) + for _, sector := range ps { + postSkipped.Set(uint64(sector.Number)) } - - sc, err := skipped.Count() - if err != nil { - return nil, xerrors.Errorf("getting skipped sector count: %w", err) - } - - skipCount += sc - - ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) - if err != nil { - return nil, xerrors.Errorf("getting sorted sector info: %w", err) - } - - if len(ssi) == 0 { - continue - } - - sinfos = append(sinfos, ssi...) - for _, si := range ssi { - sidToPart[si.SectorNumber] = uint64(partIdx) - } - - params.Partitions = append(params.Partitions, miner.PoStPartition{ - Index: uint64(partIdx), - Skipped: skipped, - }) - } - - if len(sinfos) == 0 { - // nothing to prove.. - return nil, errNoPartitions - } - - log.Infow("running windowPost", - "chain-random", rand, - "deadline", di, - "height", ts.Height(), - "skipped", skipCount) - - tsStart := build.Clock.Now() - - mid, err := address.IDFromAddress(s.actor) - if err != nil { - return nil, err - } - - postOut, postSkipped, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) - if err != nil { - return nil, xerrors.Errorf("running post failed: %w", err) } if len(postOut) == 0 { - return nil, xerrors.Errorf("received proofs back from generate window post") + return nil, xerrors.Errorf("received no proofs back from generate window post") } params.Proofs = postOut - for _, sector := range postSkipped { - params.Partitions[sidToPart[sector.Number]].Skipped.Set(uint64(sector.Number)) - } - - elapsed := time.Since(tsStart) - commEpoch := di.Open commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, nil) if err != nil { @@ -433,7 +453,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty params.ChainCommitEpoch = commEpoch params.ChainCommitRand = commRand - log.Infow("submitting window PoSt", "elapsed", elapsed) + log.Infow("submitting window PoSt") return params, nil }