Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filecoin Virtual Machine integration #8293

Merged
merged 37 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2a669b9
:Hook up the FVM
arajasek Dec 17, 2021
fc74a6c
update fvm/ffi bindings
Stebalien Jan 31, 2022
04092f3
update ffi
Stebalien Feb 2, 2022
279cdd0
fvm: fix implicit messages and message inclusion gas charging
Stebalien Feb 7, 2022
32b3618
fvm: feed in correct "base" circulating supply
Stebalien Feb 8, 2022
e8d771f
pass only fil-vested into FVM
Stebalien Feb 8, 2022
e8bdf81
chore: cleanup fil vested calculation
Stebalien Feb 9, 2022
7438628
ffi: update FFI for fvm changes
Stebalien Feb 9, 2022
0d6eb7f
ffi: update for fixed FVM lifetime management
Stebalien Feb 9, 2022
7ef1513
ffi: update fvm
Stebalien Feb 10, 2022
ee69899
Merge branch 'master' into feat/fvm
arajasek Feb 11, 2022
4767f3d
Merge pull request #8120 from filecoin-project/travis/set-current-net…
arajasek Feb 17, 2022
d835cad
chore: update FFI
Stebalien Feb 17, 2022
393479e
Fvm: impl VerifyConsensusFault
arajasek Feb 15, 2022
5be125a
address review feedback
arajasek Feb 17, 2022
562c59b
Merge pull request #8101 from filecoin-project/asr/fault
arajasek Feb 18, 2022
6e1d5c5
Merge branch 'master' into feat/fvm
arajasek Feb 18, 2022
aad3762
fvm: set gas costs to nil for implicit messages
Stebalien Feb 23, 2022
420c5fb
fvm: time message execution
Stebalien Feb 23, 2022
9bb936b
chore: refactor: rename NewVM to NewLotusVM
arajasek Feb 23, 2022
b6682f4
feat: use either lotus vm or fvm consistently
arajasek Feb 23, 2022
d58babe
fix: set FilVested when constructing VmOpts
arajasek Feb 23, 2022
2ba34ad
stmgr: call needs to flush VM before fetching nonce
arajasek Feb 24, 2022
755ce8c
Merge pull request #8174 from filecoin-project/asr/consistent-vm
arajasek Feb 24, 2022
dd91857
Merge branch 'master' into feat/fvm
arajasek Mar 1, 2022
0a67b6e
Merge branch 'master' into feat/fvm
arajasek Mar 2, 2022
d2054e8
FVM: support nv15
arajasek Mar 4, 2022
6d4fb88
Merge pull request #8197 from filecoin-project/asr/fvm/nv15
arajasek Mar 11, 2022
05fa9c8
Rename FVM envvar to LOTUS_USE_FVM_EXPERIMENTAL
arajasek Mar 12, 2022
67889b4
Merge branch 'master' into feat/fvm
arajasek Mar 12, 2022
1bf40ad
Fix broken go.sum
arajasek Mar 12, 2022
6c51adc
Update FFI: fix cargo.lock
arajasek Mar 15, 2022
673f558
Rename vm.VMI to vm.Interface
arajasek Mar 15, 2022
e6117c4
Address review
arajasek Mar 15, 2022
9ea623e
Rename the Lotus VM to LegacyVM
arajasek Mar 15, 2022
16128a0
Merge branch 'master' into feat/fvm
arajasek Mar 16, 2022
37539cc
CircSupply: Remove unused method
arajasek Mar 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions chain/consensus/filcns/compute_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package filcns

import (
"context"
"os"
"sync/atomic"

"github.com/filecoin-project/lotus/chain/rand"
Expand Down Expand Up @@ -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.VMI, error) {
vmopt := &vm.VMOpts{
StateBase: base,
Epoch: e,
Expand All @@ -108,10 +109,20 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, sm *stmgr.StateManager
LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts),
}

if os.Getenv("LOTUS_USE_FVM_EXPERIMENTAL") == "1" {
filVested, err := sm.GetFilVested(ctx, e)
if err != nil {
return nil, err
}

vmopt.FilVested = filVested
return vm.NewFVM(ctx, vmopt)
}

arajasek marked this conversation as resolved.
Show resolved Hide resolved
return sm.VMConstructor()(ctx, vmopt)
}

runCron := func(vmCron *vm.VM, epoch abi.ChainEpoch) error {
runCron := func(vmCron vm.VMI, epoch abi.ChainEpoch) error {
arajasek marked this conversation as resolved.
Show resolved Hide resolved
cronMsg := &types.Message{
To: cron.Address,
From: builtin.SystemActorAddr,
Expand Down
7 changes: 4 additions & 3 deletions chain/gen/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.NewLotusVM(ctx, &vmopt)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
return cid.Undef, xerrors.Errorf("failed to create NewLotusVM: %w", err)
}

for mi, m := range template.Miners {
Expand Down
7 changes: 4 additions & 3 deletions chain/gen/genesis/miners.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're only passing these opts into legacy VMs from here correct? So this is just nice zero value setting for clarity and won't cause v14 devnets to read bad values for the vested fil?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, yeah. Also Vested fil is equal to zero at genesis, so should be consistent.

}

vm, err := vm.NewVM(ctx, vmopt)
vm, err := vm.NewLotusVM(ctx, vmopt)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
return cid.Undef, xerrors.Errorf("failed to create NewLotusVM: %w", err)
}

if len(miners) == 0 {
Expand Down
53 changes: 45 additions & 8 deletions chain/stmgr/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -64,6 +70,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
pheight = ts.Height() - 1
}

vmHeight := pheight + 1
arajasek marked this conversation as resolved.
Show resolved Hide resolved
bstate := ts.ParentState()

// Run the (not expensive) migration.
Expand All @@ -72,16 +79,22 @@ 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(),
Syscalls: sm.Syscalls,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NetworkVersion: sm.GetNetworkVersion(ctx, pheight+1),
BaseFee: types.NewInt(0),
FilVested: filVested,
LookbackState: LookbackStateGetterForTipset(sm, ts),
}

Expand Down Expand Up @@ -112,7 +125,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, err
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be an error behaviour change in here. Mind explaining?

Copy link
Contributor

@arajasek arajasek Mar 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raulk Well, there's a new potential error here, if that's what you mean, I can add a descreptive error message. The cause of the change is just that we don't have (or want) the StateTree method on the VM interface.


fromActor, err := stTree.GetActor(msg.From)
if err != nil {
return nil, xerrors.Errorf("call raw get actor: %s", err)
}
Expand Down Expand Up @@ -175,13 +193,15 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
}
}

state, _, err := sm.TipSetState(ctx, ts)
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)
}
Expand All @@ -196,16 +216,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,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, was this method writing directly into the state store without any buffering?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, the Lotus VM wraps the store you give it in a buffered store, so this was going into a buffer there (that then got thrown away cuz we never flushed, while still being accessible for determining the state of the sender in between messages).

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)
Expand All @@ -219,7 +246,17 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
}
}

fromActor, err := vmi.StateTree().GetActor(msg.From)
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)
}
Comment on lines +253 to +261
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Let's add a comment here stating why we need to flush and load the state tree.
  2. This Flush wouldn't be necessary with the intrinsic VM, so consider adding a specialization here, since the Lotus VM is not going anywhere for the foreseeable future and this would cause a small perf regression.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Will do.
  2. Eh, I don't think I care enough -- the minor perf hit to simulating messages seems fine. I'd rather not have more IF FVM clauses than strictly necessary.


fromActor, err := stTree.GetActor(msg.From)
if err != nil {
return nil, xerrors.Errorf("call raw get actor: %s", err)
}
Expand Down
12 changes: 6 additions & 6 deletions chain/stmgr/forks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.VMI, error) {
nvm, err := vm.NewLotusVM(ctx, vmopt)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -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.VMI, error) {
nvm, err := vm.NewLotusVM(ctx, vmopt)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -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.VMI, error) {
nvm, err := vm.NewLotusVM(ctx, vmopt)
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions chain/stmgr/stmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.VMI, error)
Syscalls vm.SyscallBuilder
preIgnitionVesting []msig0.State
postIgnitionVesting []msig0.State
Expand Down Expand Up @@ -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.VMI, 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.VMI, error) {
return func(ctx context.Context, opts *vm.VMOpts) (vm.VMI, error) {
return sm.newVM(ctx, opts)
}
}
Expand Down
57 changes: 32 additions & 25 deletions chain/stmgr/supply.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -315,29 +339,12 @@ func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.C
return cs.FilCirculating, err
}

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)
}
}
func (sm *StateManager) loadGenesisMsigs(ctx context.Context) error {
return nil
}
arajasek marked this conversation as resolved.
Show resolved Hide resolved

filVested, err := sm.GetFilVested(ctx, height, st)
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
filVested, err := sm.GetFilVested(ctx, height)
if err != nil {
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
}
Expand All @@ -360,7 +367,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)
}
Expand Down
6 changes: 6 additions & 0 deletions chain/stmgr/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand Down
Loading