diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index 44b792854..9b2183a59 100644 --- a/chain/consensus/filcns/compute_state.go +++ b/chain/consensus/filcns/compute_state.go @@ -2,6 +2,7 @@ package filcns import ( "context" + "os" "sync/atomic" "github.com/filecoin-project/lotus/chain/rand" @@ -94,7 +95,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, sm *stmgr.StateManager }() ctx = blockstore.WithHotView(ctx) - makeVmWithBaseStateAndEpoch := func(base cid.Cid, e abi.ChainEpoch) (*vm.VM, error) { + makeVmWithBaseStateAndEpoch := func(base cid.Cid, e abi.ChainEpoch) (vm.Interface, error) { vmopt := &vm.VMOpts{ StateBase: base, Epoch: e, @@ -108,10 +109,23 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, sm *stmgr.StateManager LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts), } + if os.Getenv("LOTUS_USE_FVM_EXPERIMENTAL") == "1" { + // This is needed so that the FVM does not have to duplicate the genesis vesting schedule, one + // of the components of the circ supply calc. + // This field is NOT needed by the LegacyVM, and also NOT needed by the FVM from v15 onwards. + filVested, err := sm.GetFilVested(ctx, e) + if err != nil { + return nil, err + } + + vmopt.FilVested = filVested + return vm.NewFVM(ctx, vmopt) + } + return sm.VMConstructor()(ctx, vmopt) } - runCron := func(vmCron *vm.VM, epoch abi.ChainEpoch) error { + runCron := func(vmCron vm.Interface, epoch abi.ChainEpoch) error { cronMsg := &types.Message{ To: cron.Address, From: builtin.SystemActorAddr, diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 6ab101e78..a1d1d01b8 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -491,12 +491,13 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.Sysca Actors: filcns.NewActorRegistry(), Syscalls: mkFakedSigSyscalls(sys), CircSupplyCalc: csc, + FilVested: big.Zero(), NetworkVersion: nv, - BaseFee: types.NewInt(0), + BaseFee: big.Zero(), } - vm, err := vm.NewVM(ctx, &vmopt) + vm, err := vm.NewLegacyVM(ctx, &vmopt) if err != nil { - return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) + return cid.Undef, xerrors.Errorf("failed to create NewLegacyVM: %w", err) } for mi, m := range template.Miners { diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 274918147..fd83a7640 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -95,12 +95,13 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal Syscalls: mkFakedSigSyscalls(sys), CircSupplyCalc: csc, NetworkVersion: nv, - BaseFee: types.NewInt(0), + BaseFee: big.Zero(), + FilVested: big.Zero(), } - vm, err := vm.NewVM(ctx, vmopt) + vm, err := vm.NewLegacyVM(ctx, vmopt) if err != nil { - return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) + return cid.Undef, xerrors.Errorf("failed to create NewLegacyVM: %w", err) } if len(miners) == 0 { @@ -520,7 +521,7 @@ func (fr *fakeRand) GetBeaconRandomness(ctx context.Context, personalization cry return out, nil } -func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*power0.CurrentTotalPowerReturn, error) { +func currentTotalPower(ctx context.Context, vm *vm.LegacyVM, maddr address.Address) (*power0.CurrentTotalPowerReturn, error) { pwret, err := doExecValue(ctx, vm, power.Address, maddr, big.Zero(), builtin0.MethodsPower.CurrentTotalPower, nil) if err != nil { return nil, err @@ -533,7 +534,7 @@ func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (* return &pwr, nil } -func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch, av actors.Version) (abi.DealWeight, abi.DealWeight, error) { +func dealWeight(ctx context.Context, vm *vm.LegacyVM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch, av actors.Version) (abi.DealWeight, abi.DealWeight, error) { // TODO: This hack should move to market actor wrapper if av <= actors.Version2 { params := &market0.VerifyDealsForActivationParams{ @@ -593,7 +594,7 @@ func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs [ return dealWeights.Sectors[0].DealWeight, dealWeights.Sectors[0].VerifiedDealWeight, nil } -func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Address, av actors.Version) (abi.StoragePower, builtin.FilterEstimate, error) { +func currentEpochBlockReward(ctx context.Context, vm *vm.LegacyVM, maddr address.Address, av actors.Version) (abi.StoragePower, builtin.FilterEstimate, error) { rwret, err := doExecValue(ctx, vm, reward.Address, maddr, big.Zero(), reward.Methods.ThisEpochReward, nil) if err != nil { return big.Zero(), builtin.FilterEstimate{}, err @@ -628,7 +629,7 @@ func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Addre return epochReward.ThisEpochBaselinePower, builtin.FilterEstimate(epochReward.ThisEpochRewardSmoothed), nil } -func circSupply(ctx context.Context, vmi *vm.VM, maddr address.Address) abi.TokenAmount { +func circSupply(ctx context.Context, vmi *vm.LegacyVM, maddr address.Address) abi.TokenAmount { unsafeVM := &vm.UnsafeVM{VM: vmi} rt := unsafeVM.MakeRuntime(ctx, &types.Message{ GasLimit: 1_000_000_000, diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go index 67a4e9579..452bc835b 100644 --- a/chain/gen/genesis/util.go +++ b/chain/gen/genesis/util.go @@ -21,7 +21,7 @@ func mustEnc(i cbg.CBORMarshaler) []byte { return enc } -func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) { +func doExecValue(ctx context.Context, vm *vm.LegacyVM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) { act, err := vm.StateTree().GetActor(from) if err != nil { return nil, xerrors.Errorf("doExec failed to get from actor (%s): %w", from, err) diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 31639701d..5db508008 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -5,6 +5,12 @@ import ( "errors" "fmt" + cbor "github.com/ipfs/go-ipld-cbor" + + "github.com/filecoin-project/lotus/chain/state" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/rand" "github.com/filecoin-project/go-address" @@ -64,6 +70,8 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. pheight = ts.Height() - 1 } + // Since we're simulating a future message, pretend we're applying it in the "next" tipset + vmHeight := pheight + 1 bstate := ts.ParentState() // Run the (not expensive) migration. @@ -72,9 +80,14 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. return nil, fmt.Errorf("failed to handle fork: %w", err) } + filVested, err := sm.GetFilVested(ctx, vmHeight) + if err != nil { + return nil, err + } + vmopt := &vm.VMOpts{ StateBase: bstate, - Epoch: pheight + 1, + Epoch: vmHeight, Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, sm.GetNetworkVersion), Bstore: sm.cs.StateBlockstore(), Actors: sm.tsExec.NewActorRegistry(), @@ -82,6 +95,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. CircSupplyCalc: sm.GetVMCirculatingSupply, NetworkVersion: sm.GetNetworkVersion(ctx, pheight+1), BaseFee: types.NewInt(0), + FilVested: filVested, LookbackState: LookbackStateGetterForTipset(sm, ts), } @@ -112,7 +126,12 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. ) } - fromActor, err := vmi.StateTree().GetActor(msg.From) + stTree, err := sm.StateTree(bstate) + if err != nil { + return nil, xerrors.Errorf("failed to load state tree: %w", err) + } + + fromActor, err := stTree.GetActor(msg.From) if err != nil { return nil, xerrors.Errorf("call raw get actor: %s", err) } @@ -175,13 +194,16 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri } } - state, _, err := sm.TipSetState(ctx, ts) + // Since we're simulating a future message, pretend we're applying it in the "next" tipset + vmHeight := ts.Height() + 1 + + stateCid, _, err := sm.TipSetState(ctx, ts) if err != nil { return nil, xerrors.Errorf("computing tipset state: %w", err) } // Technically, the tipset we're passing in here should be ts+1, but that may not exist. - state, err = sm.HandleStateForks(ctx, state, ts.Height(), nil, ts) + stateCid, err = sm.HandleStateForks(ctx, stateCid, ts.Height(), nil, ts) if err != nil { return nil, fmt.Errorf("failed to handle fork: %w", err) } @@ -196,16 +218,23 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri ) } + filVested, err := sm.GetFilVested(ctx, vmHeight) + if err != nil { + return nil, err + } + + buffStore := blockstore.NewBuffered(sm.cs.StateBlockstore()) vmopt := &vm.VMOpts{ - StateBase: state, - Epoch: ts.Height() + 1, + StateBase: stateCid, + Epoch: vmHeight, Rand: r, - Bstore: sm.cs.StateBlockstore(), + Bstore: buffStore, Actors: sm.tsExec.NewActorRegistry(), Syscalls: sm.Syscalls, CircSupplyCalc: sm.GetVMCirculatingSupply, NetworkVersion: sm.GetNetworkVersion(ctx, ts.Height()+1), BaseFee: ts.Blocks()[0].ParentBaseFee, + FilVested: filVested, LookbackState: LookbackStateGetterForTipset(sm, ts), } vmi, err := sm.newVM(ctx, vmopt) @@ -219,7 +248,19 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri } } - fromActor, err := vmi.StateTree().GetActor(msg.From) + // We flush to get the VM's view of the state tree after applying the above messages + // This is needed to get the correct nonce from the actor state to match the VM + stateCid, err = vmi.Flush(ctx) + if err != nil { + return nil, xerrors.Errorf("flushing vm: %w", err) + } + + stTree, err := state.LoadStateTree(cbor.NewCborStore(buffStore), stateCid) + if err != nil { + return nil, xerrors.Errorf("loading state tree: %w", err) + } + + fromActor, err := stTree.GetActor(msg.From) if err != nil { return nil, xerrors.Errorf("call raw get actor: %s", err) } diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 4fad1e4fc..938973429 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -166,8 +166,8 @@ func TestForkHeightTriggers(t *testing.T) { inv := filcns.NewActorRegistry() inv.Register(nil, testActor{}) - sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { - nvm, err := vm.NewVM(ctx, vmopt) + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { + nvm, err := vm.NewLegacyVM(ctx, vmopt) if err != nil { return nil, err } @@ -281,8 +281,8 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) { inv := filcns.NewActorRegistry() inv.Register(nil, testActor{}) - sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { - nvm, err := vm.NewVM(ctx, vmopt) + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { + nvm, err := vm.NewLegacyVM(ctx, vmopt) if err != nil { return nil, err } @@ -500,8 +500,8 @@ func TestForkPreMigration(t *testing.T) { inv := filcns.NewActorRegistry() inv.Register(nil, testActor{}) - sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { - nvm, err := vm.NewVM(ctx, vmopt) + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { + nvm, err := vm.NewLegacyVM(ctx, vmopt) if err != nil { return nil, err } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 45dd52ec8..d0bdd73e9 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -84,7 +84,7 @@ type StateManager struct { compWait map[string]chan struct{} stlk sync.Mutex genesisMsigLk sync.Mutex - newVM func(context.Context, *vm.VMOpts) (*vm.VM, error) + newVM func(context.Context, *vm.VMOpts) (vm.Interface, error) Syscalls vm.SyscallBuilder preIgnitionVesting []msig0.State postIgnitionVesting []msig0.State @@ -347,12 +347,12 @@ func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) err return nil } -func (sm *StateManager) SetVMConstructor(nvm func(context.Context, *vm.VMOpts) (*vm.VM, error)) { +func (sm *StateManager) SetVMConstructor(nvm func(context.Context, *vm.VMOpts) (vm.Interface, error)) { sm.newVM = nvm } -func (sm *StateManager) VMConstructor() func(context.Context, *vm.VMOpts) (*vm.VM, error) { - return func(ctx context.Context, opts *vm.VMOpts) (*vm.VM, error) { +func (sm *StateManager) VMConstructor() func(context.Context, *vm.VMOpts) (vm.Interface, error) { + return func(ctx context.Context, opts *vm.VMOpts) (vm.Interface, error) { return sm.newVM(ctx, opts) } } diff --git a/chain/stmgr/supply.go b/chain/stmgr/supply.go index 0744c02aa..7c55a1a0d 100644 --- a/chain/stmgr/supply.go +++ b/chain/stmgr/supply.go @@ -196,8 +196,32 @@ func (sm *StateManager) setupPostCalicoVesting(ctx context.Context) error { // GetVestedFunds returns all funds that have "left" actors that are in the genesis state: // - For Multisigs, it counts the actual amounts that have vested at the given epoch // - For Accounts, it counts max(currentBalance - genesisBalance, 0). -func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) { +func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch) (abi.TokenAmount, error) { vf := big.Zero() + + sm.genesisMsigLk.Lock() + defer sm.genesisMsigLk.Unlock() + + // TODO: combine all this? + if sm.preIgnitionVesting == nil || sm.genesisPledge.IsZero() || sm.genesisMarketFunds.IsZero() { + err := sm.setupGenesisVestingSchedule(ctx) + if err != nil { + return vf, xerrors.Errorf("failed to setup pre-ignition vesting schedule: %w", err) + } + } + if sm.postIgnitionVesting == nil { + err := sm.setupPostIgnitionVesting(ctx) + if err != nil { + return vf, xerrors.Errorf("failed to setup post-ignition vesting schedule: %w", err) + } + } + if sm.postCalicoVesting == nil { + err := sm.setupPostCalicoVesting(ctx) + if err != nil { + return vf, xerrors.Errorf("failed to setup post-calico vesting schedule: %w", err) + } + } + if height <= build.UpgradeIgnitionHeight { for _, v := range sm.preIgnitionVesting { au := big.Sub(v.InitialBalance, v.AmountLocked(height)) @@ -282,7 +306,7 @@ func getFilPowerLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmoun return pst.TotalLocked() } -func (sm *StateManager) GetFilLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { +func GetFilLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { filMarketLocked, err := getFilMarketLocked(ctx, st) if err != nil { @@ -316,28 +340,7 @@ func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.C } func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) { - sm.genesisMsigLk.Lock() - defer sm.genesisMsigLk.Unlock() - if sm.preIgnitionVesting == nil || sm.genesisPledge.IsZero() || sm.genesisMarketFunds.IsZero() { - err := sm.setupGenesisVestingSchedule(ctx) - if err != nil { - return api.CirculatingSupply{}, xerrors.Errorf("failed to setup pre-ignition vesting schedule: %w", err) - } - } - if sm.postIgnitionVesting == nil { - err := sm.setupPostIgnitionVesting(ctx) - if err != nil { - return api.CirculatingSupply{}, xerrors.Errorf("failed to setup post-ignition vesting schedule: %w", err) - } - } - if sm.postCalicoVesting == nil { - err := sm.setupPostCalicoVesting(ctx) - if err != nil { - return api.CirculatingSupply{}, xerrors.Errorf("failed to setup post-calico vesting schedule: %w", err) - } - } - - filVested, err := sm.GetFilVested(ctx, height, st) + filVested, err := sm.GetFilVested(ctx, height) if err != nil { return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err) } @@ -360,7 +363,7 @@ func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, heig return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filBurnt: %w", err) } - filLocked, err := sm.GetFilLocked(ctx, st) + filLocked, err := GetFilLocked(ctx, st) if err != nil { return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filLocked: %w", err) } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 2a84c777b..49dd4700a 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -79,6 +79,11 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, // future. It's not guaranteed to be accurate... but that's fine. } + filVested, err := sm.GetFilVested(ctx, height) + if err != nil { + return cid.Undef, nil, err + } + r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, sm.GetNetworkVersion) vmopt := &vm.VMOpts{ StateBase: base, @@ -90,6 +95,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, CircSupplyCalc: sm.GetVMCirculatingSupply, NetworkVersion: sm.GetNetworkVersion(ctx, height), BaseFee: ts.Blocks()[0].ParentBaseFee, + FilVested: filVested, LookbackState: LookbackStateGetterForTipset(sm, ts), } vmi, err := sm.newVM(ctx, vmopt) diff --git a/chain/vm/fvm.go b/chain/vm/fvm.go new file mode 100644 index 000000000..922eb77c5 --- /dev/null +++ b/chain/vm/fvm.go @@ -0,0 +1,312 @@ +package vm + +import ( + "bytes" + "context" + "time" + + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/state" + cbor "github.com/ipfs/go-ipld-cbor" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/lotus/lib/sigs" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/blockstore" + + ffi "github.com/filecoin-project/filecoin-ffi" + ffi_cgo "github.com/filecoin-project/filecoin-ffi/cgo" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +var _ Interface = (*FVM)(nil) +var _ ffi_cgo.Externs = (*FvmExtern)(nil) + +type FvmExtern struct { + Rand + blockstore.Blockstore + epoch abi.ChainEpoch + lbState LookbackStateGetter + base cid.Cid +} + +// VerifyConsensusFault is similar to the one in syscalls.go used by the LegacyVM, except it never errors +// Errors are logged and "no fault" is returned, which is functionally what go-actors does anyway +func (x *FvmExtern) VerifyConsensusFault(ctx context.Context, a, b, extra []byte) (*ffi_cgo.ConsensusFault, int64) { + totalGas := int64(0) + ret := &ffi_cgo.ConsensusFault{ + Type: ffi_cgo.ConsensusFaultNone, + } + + // Note that block syntax is not validated. Any validly signed block will be accepted pursuant to the below conditions. + // Whether or not it could ever have been accepted in a chain is not checked/does not matter here. + // for that reason when checking block parent relationships, rather than instantiating a Tipset to do so + // (which runs a syntactic check), we do it directly on the CIDs. + + // (0) cheap preliminary checks + + // can blocks be decoded properly? + var blockA, blockB types.BlockHeader + if decodeErr := blockA.UnmarshalCBOR(bytes.NewReader(a)); decodeErr != nil { + log.Info("invalid consensus fault: cannot decode first block header: %w", decodeErr) + return ret, totalGas + } + + if decodeErr := blockB.UnmarshalCBOR(bytes.NewReader(b)); decodeErr != nil { + log.Info("invalid consensus fault: cannot decode second block header: %w", decodeErr) + return ret, totalGas + } + + // are blocks the same? + if blockA.Cid().Equals(blockB.Cid()) { + log.Info("invalid consensus fault: submitted blocks are the same") + return ret, totalGas + } + // (1) check conditions necessary to any consensus fault + + // were blocks mined by same miner? + if blockA.Miner != blockB.Miner { + log.Info("invalid consensus fault: blocks not mined by the same miner") + return ret, totalGas + } + + // block a must be earlier or equal to block b, epoch wise (ie at least as early in the chain). + if blockB.Height < blockA.Height { + log.Info("invalid consensus fault: first block must not be of higher height than second") + return ret, totalGas + } + + ret.Epoch = blockB.Height + + faultType := ffi_cgo.ConsensusFaultNone + + // (2) check for the consensus faults themselves + // (a) double-fork mining fault + if blockA.Height == blockB.Height { + faultType = ffi_cgo.ConsensusFaultDoubleForkMining + } + + // (b) time-offset mining fault + // strictly speaking no need to compare heights based on double fork mining check above, + // but at same height this would be a different fault. + if types.CidArrsEqual(blockA.Parents, blockB.Parents) && blockA.Height != blockB.Height { + faultType = ffi_cgo.ConsensusFaultTimeOffsetMining + } + + // (c) parent-grinding fault + // Here extra is the "witness", a third block that shows the connection between A and B as + // A's sibling and B's parent. + // Specifically, since A is of lower height, it must be that B was mined omitting A from its tipset + // + // B + // | + // [A, C] + var blockC types.BlockHeader + if len(extra) > 0 { + if decodeErr := blockC.UnmarshalCBOR(bytes.NewReader(extra)); decodeErr != nil { + log.Info("invalid consensus fault: cannot decode extra: %w", decodeErr) + return ret, totalGas + } + + if types.CidArrsEqual(blockA.Parents, blockC.Parents) && blockA.Height == blockC.Height && + types.CidArrsContains(blockB.Parents, blockC.Cid()) && !types.CidArrsContains(blockB.Parents, blockA.Cid()) { + faultType = ffi_cgo.ConsensusFaultParentGrinding + } + } + + // (3) return if no consensus fault by now + if faultType == ffi_cgo.ConsensusFaultNone { + log.Info("invalid consensus fault: no fault detected") + return ret, totalGas + } + + // else + // (4) expensive final checks + + // check blocks are properly signed by their respective miner + // note we do not need to check extra's: it is a parent to block b + // which itself is signed, so it was willingly included by the miner + gasA, sigErr := x.VerifyBlockSig(ctx, &blockA) + totalGas += gasA + if sigErr != nil { + log.Info("invalid consensus fault: cannot verify first block sig: %w", sigErr) + return ret, totalGas + } + + gas2, sigErr := x.VerifyBlockSig(ctx, &blockB) + totalGas += gas2 + if sigErr != nil { + log.Info("invalid consensus fault: cannot verify second block sig: %w", sigErr) + return ret, totalGas + } + + ret.Type = faultType + ret.Target = blockA.Miner + + return ret, totalGas +} + +func (x *FvmExtern) VerifyBlockSig(ctx context.Context, blk *types.BlockHeader) (int64, error) { + waddr, gasUsed, err := x.workerKeyAtLookback(ctx, blk.Miner, blk.Height) + if err != nil { + return gasUsed, err + } + + return gasUsed, sigs.CheckBlockSignature(ctx, blk, waddr) +} + +func (x *FvmExtern) workerKeyAtLookback(ctx context.Context, minerId address.Address, height abi.ChainEpoch) (address.Address, int64, error) { + gasUsed := int64(0) + gasAdder := func(gc GasCharge) { + // technically not overflow safe, but that's fine + gasUsed += gc.Total() + } + + cstWithoutGas := cbor.NewCborStore(x.Blockstore) + cbb := &gasChargingBlocks{gasAdder, PricelistByEpoch(x.epoch), x.Blockstore} + cstWithGas := cbor.NewCborStore(cbb) + + lbState, err := x.lbState(ctx, height) + if err != nil { + return address.Undef, gasUsed, err + } + // get appropriate miner actor + act, err := lbState.GetActor(minerId) + if err != nil { + return address.Undef, gasUsed, err + } + + // use that to get the miner state + mas, err := miner.Load(adt.WrapStore(ctx, cstWithGas), act) + if err != nil { + return address.Undef, gasUsed, err + } + + info, err := mas.Info() + if err != nil { + return address.Undef, gasUsed, err + } + + stateTree, err := state.LoadStateTree(cstWithoutGas, x.base) + if err != nil { + return address.Undef, gasUsed, err + } + + raddr, err := ResolveToKeyAddr(stateTree, cstWithGas, info.Worker) + if err != nil { + return address.Undef, gasUsed, err + } + + return raddr, gasUsed, nil +} + +type FVM struct { + fvm *ffi.FVM +} + +func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) { + circToReport := opts.FilVested + // For v14 (and earlier), we perform the FilVested portion of the calculation, and let the FVM dynamically do the rest + // v15 and after, the circ supply is always constant per epoch, so we calculate the base and report it at creation + if opts.NetworkVersion >= network.Version15 { + state, err := state.LoadStateTree(cbor.NewCborStore(opts.Bstore), opts.StateBase) + if err != nil { + return nil, err + } + + circToReport, err = opts.CircSupplyCalc(ctx, opts.Epoch, state) + if err != nil { + return nil, err + } + } + + fvm, err := ffi.CreateFVM(0, + &FvmExtern{Rand: opts.Rand, Blockstore: opts.Bstore, lbState: opts.LookbackState, base: opts.StateBase, epoch: opts.Epoch}, + opts.Epoch, opts.BaseFee, circToReport, opts.NetworkVersion, opts.StateBase, + ) + if err != nil { + return nil, err + } + + return &FVM{ + fvm: fvm, + }, nil +} + +func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) { + start := build.Clock.Now() + msgBytes, err := cmsg.VMMessage().Serialize() + if err != nil { + return nil, xerrors.Errorf("serializing msg: %w", err) + } + + ret, err := vm.fvm.ApplyMessage(msgBytes, uint(cmsg.ChainLength())) + if err != nil { + return nil, xerrors.Errorf("applying msg: %w", err) + } + + return &ApplyRet{ + MessageReceipt: types.MessageReceipt{ + Return: ret.Return, + ExitCode: exitcode.ExitCode(ret.ExitCode), + GasUsed: ret.GasUsed, + }, + GasCosts: &GasOutputs{ + // TODO: do the other optional fields eventually + BaseFeeBurn: big.Zero(), + OverEstimationBurn: big.Zero(), + MinerPenalty: ret.MinerPenalty, + MinerTip: ret.MinerTip, + Refund: big.Zero(), + GasRefund: 0, + GasBurned: 0, + }, + // TODO: do these eventually, not consensus critical + // https://github.com/filecoin-project/ref-fvm/issues/318 + ActorErr: nil, + ExecutionTrace: types.ExecutionTrace{}, + Duration: time.Since(start), + }, nil +} + +func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*ApplyRet, error) { + start := build.Clock.Now() + msgBytes, err := cmsg.VMMessage().Serialize() + if err != nil { + return nil, xerrors.Errorf("serializing msg: %w", err) + } + ret, err := vm.fvm.ApplyImplicitMessage(msgBytes) + if err != nil { + return nil, xerrors.Errorf("applying msg: %w", err) + } + + return &ApplyRet{ + MessageReceipt: types.MessageReceipt{ + Return: ret.Return, + ExitCode: exitcode.ExitCode(ret.ExitCode), + GasUsed: ret.GasUsed, + }, + GasCosts: nil, + // TODO: do these eventually, not consensus critical + // https://github.com/filecoin-project/ref-fvm/issues/318 + ActorErr: nil, + ExecutionTrace: types.ExecutionTrace{}, + Duration: time.Since(start), + }, nil +} + +func (vm *FVM) Flush(ctx context.Context) (cid.Cid, error) { + return vm.fvm.Flush() +} diff --git a/chain/vm/gas.go b/chain/vm/gas.go index e75c86b9f..5beaae40b 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -50,7 +50,7 @@ func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge { } } -// Pricelist provides prices for operations in the VM. +// Pricelist provides prices for operations in the LegacyVM. // // Note: this interface should be APPEND ONLY since last chain checkpoint type Pricelist interface { diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index 1bda6dfae..7e0ece769 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -50,7 +50,7 @@ type pricelistV0 struct { // whether it succeeds or fails in application) is given by: // OnChainMessageBase + len(serialized message)*OnChainMessagePerByte // Together, these account for the cost of message propagation and validation, - // up to but excluding any actual processing by the VM. + // up to but excluding any actual processing by the LegacyVM. // This is the cost a block producer burns when including an invalid message. onChainMessageComputeBase int64 onChainMessageStorageBase int64 @@ -83,11 +83,11 @@ type pricelistV0 struct { sendInvokeMethod int64 // Gas cost for any Get operation to the IPLD store - // in the runtime VM context. + // in the runtime LegacyVM context. ipldGetBase int64 // Gas cost (Base + len*PerByte) for any Put operation to the IPLD store - // in the runtime VM context. + // in the runtime LegacyVM context. // // Note: these costs should be significantly higher than the costs for Get // operations, since they reflect not only serialization/deserialization diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index fb9910ecd..e75d0c854 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -135,7 +135,7 @@ func TestInvokerBasic(t *testing.T) { { _, aerr := code[1](&Runtime{ - vm: &VM{networkVersion: network.Version0}, + vm: &LegacyVM{networkVersion: network.Version0}, Message: &basicRtMessage{}, }, []byte{99}) if aerrors.IsFatal(aerr) { @@ -146,7 +146,7 @@ func TestInvokerBasic(t *testing.T) { { _, aerr := code[1](&Runtime{ - vm: &VM{networkVersion: network.Version7}, + vm: &LegacyVM{networkVersion: network.Version7}, Message: &basicRtMessage{}, }, []byte{99}) if aerrors.IsFatal(aerr) { diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 0e2adc879..c27c45371 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -65,7 +65,7 @@ type Runtime struct { ctx context.Context - vm *VM + vm *LegacyVM state *state.StateTree height abi.ChainEpoch cst ipldcbor.IpldStore @@ -158,7 +158,7 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act defer func() { if r := recover(); r != nil { if ar, ok := r.(aerrors.ActorError); ok { - log.Warnf("VM.Call failure in call from: %s to %s: %+v", rt.Caller(), rt.Receiver(), ar) + log.Warnf("LegacyVM.Call failure in call from: %s to %s: %+v", rt.Caller(), rt.Receiver(), ar) aerr = ar return } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 1ab97bc33..a0ca446a7 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -122,7 +122,7 @@ func (bs *gasChargingBlocks) Put(ctx context.Context, blk block.Block) error { return nil } -func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runtime) *Runtime { +func (vm *LegacyVM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runtime) *Runtime { rt := &Runtime{ ctx: ctx, vm: vm, @@ -188,7 +188,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runti } type UnsafeVM struct { - VM *VM + VM *LegacyVM } func (vm *UnsafeVM) MakeRuntime(ctx context.Context, msg *types.Message) *Runtime { @@ -201,7 +201,9 @@ type ( LookbackStateGetter func(context.Context, abi.ChainEpoch) (*state.StateTree, error) ) -type VM struct { +var _ Interface = (*LegacyVM)(nil) + +type LegacyVM struct { cstate *state.StateTree cst *cbor.BasicIpldStore buf *blockstore.BufferedBlockstore @@ -225,12 +227,14 @@ type VMOpts struct { Actors *ActorRegistry Syscalls SyscallBuilder CircSupplyCalc CircSupplyCalculator + // Amount of FIL vested from genesis actors. + FilVested abi.TokenAmount NetworkVersion network.Version BaseFee abi.TokenAmount LookbackState LookbackStateGetter } -func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { +func NewLegacyVM(ctx context.Context, opts *VMOpts) (*LegacyVM, error) { buf := blockstore.NewBuffered(opts.Bstore) cst := cbor.NewCborStore(buf) state, err := state.LoadStateTree(cst, opts.StateBase) @@ -243,7 +247,7 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { return nil, err } - return &VM{ + return &LegacyVM{ cstate: state, cst: cst, buf: buf, @@ -272,7 +276,7 @@ type ApplyRet struct { GasCosts *GasOutputs } -func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, +func (vm *LegacyVM) send(ctx context.Context, msg *types.Message, parent *Runtime, gasCharge *GasCharge, start time.Time) ([]byte, aerrors.ActorError, *Runtime) { defer atomic.AddUint64(&StatSends, 1) @@ -391,7 +395,7 @@ func checkMessage(msg *types.Message) error { return nil } -func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { +func (vm *LegacyVM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { start := build.Clock.Now() defer atomic.AddUint64(&StatApplied, 1) ret, actorErr, rt := vm.send(ctx, msg, nil, nil, start) @@ -409,7 +413,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap }, actorErr } -func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) { +func (vm *LegacyVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) { start := build.Clock.Now() ctx, span := trace.StartSpan(ctx, "vm.ApplyMessage") defer span.End() @@ -616,7 +620,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, }, nil } -func (vm *VM) ShouldBurn(ctx context.Context, st *state.StateTree, msg *types.Message, errcode exitcode.ExitCode) (bool, error) { +func (vm *LegacyVM) ShouldBurn(ctx context.Context, st *state.StateTree, msg *types.Message, errcode exitcode.ExitCode) (bool, error) { if vm.networkVersion <= network.Version12 { // Check to see if we should burn funds. We avoid burning on successful // window post. This won't catch _indirect_ window post calls, but this @@ -646,7 +650,7 @@ func (vm *VM) ShouldBurn(ctx context.Context, st *state.StateTree, msg *types.Me type vmFlushKey struct{} -func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { +func (vm *LegacyVM) Flush(ctx context.Context) (cid.Cid, error) { _, span := trace.StartSpan(ctx, "vm.Flush") defer span.End() @@ -665,9 +669,9 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { return root, nil } -// Get the buffered blockstore associated with the VM. This includes any temporary blocks produced -// during this VM's execution. -func (vm *VM) ActorStore(ctx context.Context) adt.Store { +// Get the buffered blockstore associated with the LegacyVM. This includes any temporary blocks produced +// during this LegacyVM's execution. +func (vm *LegacyVM) ActorStore(ctx context.Context) adt.Store { return adt.WrapStore(ctx, vm.cst) } @@ -820,11 +824,11 @@ func copyRec(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid, return nil } -func (vm *VM) StateTree() types.StateTree { +func (vm *LegacyVM) StateTree() types.StateTree { return vm.cstate } -func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { +func (vm *LegacyVM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { ctx, span := trace.StartSpan(rt.ctx, "vm.Invoke") defer span.End() if span.IsRecordingEvents() { @@ -847,11 +851,11 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params return ret, nil } -func (vm *VM) SetInvoker(i *ActorRegistry) { +func (vm *LegacyVM) SetInvoker(i *ActorRegistry) { vm.areg = i } -func (vm *VM) GetCircSupply(ctx context.Context) (abi.TokenAmount, error) { +func (vm *LegacyVM) GetCircSupply(ctx context.Context) (abi.TokenAmount, error) { // Before v15, this was recalculated on each invocation as the state tree was mutated if vm.networkVersion <= network.Version14 { return vm.circSupplyCalc(ctx, vm.blockHeight, vm.cstate) @@ -860,14 +864,14 @@ func (vm *VM) GetCircSupply(ctx context.Context) (abi.TokenAmount, error) { return vm.baseCircSupply, nil } -func (vm *VM) incrementNonce(addr address.Address) error { +func (vm *LegacyVM) incrementNonce(addr address.Address) error { return vm.cstate.MutateActor(addr, func(a *types.Actor) error { a.Nonce++ return nil }) } -func (vm *VM) transfer(from, to address.Address, amt types.BigInt, networkVersion network.Version) aerrors.ActorError { +func (vm *LegacyVM) transfer(from, to address.Address, amt types.BigInt, networkVersion network.Version) aerrors.ActorError { var f *types.Actor var fromID, toID address.Address var err error @@ -955,7 +959,7 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt, networkVersio return nil } -func (vm *VM) transferToGasHolder(addr address.Address, gasHolder *types.Actor, amt types.BigInt) error { +func (vm *LegacyVM) transferToGasHolder(addr address.Address, gasHolder *types.Actor, amt types.BigInt) error { if amt.LessThan(types.NewInt(0)) { return xerrors.Errorf("attempted to transfer negative value to gas holder") } @@ -969,7 +973,7 @@ func (vm *VM) transferToGasHolder(addr address.Address, gasHolder *types.Actor, }) } -func (vm *VM) transferFromGasHolder(addr address.Address, gasHolder *types.Actor, amt types.BigInt) error { +func (vm *LegacyVM) transferFromGasHolder(addr address.Address, gasHolder *types.Actor, amt types.BigInt) error { if amt.LessThan(types.NewInt(0)) { return xerrors.Errorf("attempted to transfer negative value from gas holder") } diff --git a/chain/vm/vmi.go b/chain/vm/vmi.go new file mode 100644 index 000000000..9ffd8d830 --- /dev/null +++ b/chain/vm/vmi.go @@ -0,0 +1,27 @@ +package vm + +import ( + "context" + "os" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +type Interface interface { + // Applies the given message onto the VM's current state, returning the result of the execution + ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) + // Same as above but for system messages (the Cron invocation and block reward payments). + // Must NEVER fail. + ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) + // Flush all buffered objects into the state store provided to the VM at construction. + Flush(ctx context.Context) (cid.Cid, error) +} + +func NewVM(ctx context.Context, opts *VMOpts) (Interface, error) { + if os.Getenv("LOTUS_USE_FVM_EXPERIMENTAL") == "1" { + return NewFVM(ctx, opts) + } + + return NewLegacyVM(ctx, opts) +} diff --git a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go index fb822eb6e..392eaa7c8 100644 --- a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go +++ b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go @@ -44,7 +44,7 @@ type BlockBuilder struct { parentTs *types.TipSet parentSt *state.StateTree - vm *vm.VM + vm *vm.LegacyVM sm *stmgr.StateManager gasTotal int64 @@ -73,9 +73,9 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S parentSt: parentSt, } - // Then we construct a VM to execute messages for gas estimation. + // Then we construct a LegacyVM to execute messages for gas estimation. // - // Most parts of this VM are "real" except: + // Most parts of this LegacyVM are "real" except: // 1. We don't charge a fee. // 2. The runtime has "fake" proof logic. // 3. We don't actually save any of the results. @@ -92,7 +92,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S BaseFee: abi.NewTokenAmount(0), LookbackState: stmgr.LookbackStateGetterForTipset(sm, parentTs), } - bb.vm, err = vm.NewVM(bb.ctx, vmopt) + bb.vm, err = vm.NewLegacyVM(bb.ctx, vmopt) if err != nil { return nil, err } @@ -190,12 +190,12 @@ func (bb *BlockBuilder) PushMessage(msg *types.Message) (*types.MessageReceipt, return &ret.MessageReceipt, nil } -// ActorStore returns the VM's current (pending) blockstore. +// ActorStore returns the LegacyVM's current (pending) blockstore. func (bb *BlockBuilder) ActorStore() adt.Store { return bb.vm.ActorStore(bb.ctx) } -// StateTree returns the VM's current (pending) state-tree. This includes any changes made by +// StateTree returns the LegacyVM's current (pending) state-tree. This includes any changes made by // successfully pushed messages. // // You probably want ParentStateTree diff --git a/conformance/driver.go b/conformance/driver.go index a065d1530..f6ca9f9db 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -155,12 +155,12 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params results: []*vm.ApplyRet{}, } - sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { vmopt.CircSupplyCalc = func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) { return big.Zero(), nil } - return vm.NewVM(ctx, vmopt) + return vm.NewLegacyVM(ctx, vmopt) }) postcid, receiptsroot, err := tse.ApplyBlocks(context.Background(), @@ -226,7 +226,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP NetworkVersion: params.NetworkVersion, } - lvm, err := vm.NewVM(context.TODO(), vmOpts) + lvm, err := vm.NewLegacyVM(context.TODO(), vmOpts) if err != nil { return nil, cid.Undef, err } diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 5ec5d805c..c2668aa67 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 5ec5d805c01ea85224f6448dd6c6fa0a2a73c028 +Subproject commit c2668aa67ec589a773153022348b9c0ed6ed4d5d diff --git a/go.sum b/go.sum index 8bbe3340a..79629f1b5 100644 --- a/go.sum +++ b/go.sum @@ -330,7 +330,6 @@ github.com/filecoin-project/go-data-transfer v1.15.0/go.mod h1:RaJIYjh6x6z+FXKNv github.com/filecoin-project/go-ds-versioning v0.0.0-20211206185234-508abd7c2aff/go.mod h1:C9/l9PnB1+mwPa26BBVpCjG/XQCB0yj/q5CK2J8X1I4= github.com/filecoin-project/go-ds-versioning v0.1.1 h1:JiyBqaQlwC+UM0WhcBtVEeT3XrX59mQhT8U3p7nu86o= github.com/filecoin-project/go-ds-versioning v0.1.1/go.mod h1:C9/l9PnB1+mwPa26BBVpCjG/XQCB0yj/q5CK2J8X1I4= -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-commcid v0.0.0-20201016201715-d41df56b4f6a/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-commcid v0.1.0 h1:3R4ds1A9r6cr8mvZBfMYxTS88OqLYEo6roi+GiIeOh8= github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= @@ -390,8 +389,8 @@ github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4U github.com/filecoin-project/specs-actors/v6 v6.0.0/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= github.com/filecoin-project/specs-actors/v6 v6.0.1 h1:laxvHNsvrq83Y9n+W7znVCePi3oLyRf0Rkl4jFO8Wew= github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211222192039-c83bea50c402/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= +github.com/filecoin-project/specs-actors/v7 v7.0.0-rc1.0.20220118005651-2470cb39827e/go.mod h1:TA5FwCna+Yi36POaT7SLKXsgEDvJwc0V/L6ZsO19B9M= github.com/filecoin-project/specs-actors/v7 v7.0.0 h1:FQN7tjt3o68hfb3qLFSJBoLMuOFY0REkFVLO/zXj8RU= github.com/filecoin-project/specs-actors/v7 v7.0.0/go.mod h1:TA5FwCna+Yi36POaT7SLKXsgEDvJwc0V/L6ZsO19B9M= github.com/filecoin-project/specs-storage v0.2.0 h1:Y4UDv0apRQ3zI2GiPPubi8JblpUZZphEdaJUxCutfyg= @@ -1943,6 +1942,7 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:f github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210303213153-67a261a1d291/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210713220151-be142a5ae1a8/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20220224212727-7a699437a831/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20220302191723-37c43cae8e14 h1:vo2wkP2ceHyGyZwFFtAabpot03EeSxxwAe57pOI9E/4= github.com/whyrusleeping/cbor-gen v0.0.0-20220302191723-37c43cae8e14/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= @@ -2447,7 +2447,6 @@ golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201112185108-eeaa07dd7696/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= diff --git a/node/builder_chain.go b/node/builder_chain.go index afee868fd..226ecac68 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -65,7 +65,7 @@ var ChainNode = Options( Override(new(ffiwrapper.Verifier), ffiwrapper.ProofVerifier), Override(new(ffiwrapper.Prover), ffiwrapper.ProofProver), - // Consensus: VM + // Consensus: LegacyVM Override(new(vm.SyscallBuilder), vm.Syscalls), // Consensus: Chain storage/access