Merge pull request #8332 from filecoin-project/feat/fvm
FVM integration
This commit is contained in:
commit
ff244fba6c
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
312
chain/vm/fvm.go
Normal file
312
chain/vm/fvm.go
Normal file
@ -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()
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
27
chain/vm/vmi.go
Normal file
27
chain/vm/vmi.go
Normal file
@ -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)
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
2
extern/filecoin-ffi
vendored
2
extern/filecoin-ffi
vendored
@ -1 +1 @@
|
||||
Subproject commit 5ec5d805c01ea85224f6448dd6c6fa0a2a73c028
|
||||
Subproject commit c2668aa67ec589a773153022348b9c0ed6ed4d5d
|
5
go.sum
5
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=
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user