From 2a669b95fbd898942440330a9dd6bdb0d051e374 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 16 Dec 2021 22:38:13 -0500 Subject: [PATCH] :Hook up the FVM --- chain/consensus/filcns/compute_state.go | 9 +- chain/vm/fvm.go | 154 ++++++++++++++++++++++++ chain/vm/vm.go | 2 + chain/vm/vmi.go | 14 +++ extern/filecoin-ffi | 2 +- 5 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 chain/vm/fvm.go create mode 100644 chain/vm/vmi.go diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index f7f6284d0..37e78874d 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" @@ -92,7 +93,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, sm *stmgr.StateManager partDone() }() - 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, @@ -106,10 +107,14 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, sm *stmgr.StateManager LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts), } + if os.Getenv("LOTUS_USE_FVM_DOESNT_WORK_YET") == "1" { + return vm.NewFVM(ctx, vmopt) + } + return sm.VMConstructor()(ctx, vmopt) } - runCron := func(vmCron *vm.VM, epoch abi.ChainEpoch) error { + runCron := func(vmCron vm.VMI, epoch abi.ChainEpoch) error { cronMsg := &types.Message{ To: cron.Address, From: builtin.SystemActorAddr, diff --git a/chain/vm/fvm.go b/chain/vm/fvm.go new file mode 100644 index 000000000..0630c145b --- /dev/null +++ b/chain/vm/fvm.go @@ -0,0 +1,154 @@ +package vm + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/chain/actors/aerrors" + "github.com/filecoin-project/specs-actors/v7/actors/runtime" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/state" + cbor "github.com/ipfs/go-ipld-cbor" + + ffi "github.com/filecoin-project/filecoin-ffi" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +var _ VMI = (*FVM)(nil) + +type Extern interface { + GetRandomnessFromTickets(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness + GetRandomnessFromBeacon(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness + VerifyConsensusFault(a, b, extra []byte) (address.Address, abi.ChainEpoch, runtime.ConsensusFaultType) +} +type FvmExtern struct { + rand Rand +} + +func (e *FvmExtern) GetRandomnessFromTickets(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness { + res, err := e.rand.GetChainRandomness(context.Background(), personalization, randEpoch, entropy) + + if err != nil { + panic(aerrors.Fatalf("could not get ticket randomness: %s", err)) + } + return res +} + +func (e *FvmExtern) GetRandomnessFromBeacon(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness { + res, err := e.rand.GetBeaconRandomness(context.Background(), personalization, randEpoch, entropy) + + if err != nil { + panic(aerrors.Fatalf("could not get ticket randomness: %s", err)) + } + return res +} + +type FVM struct { + machineId uint64 + extern FvmExtern +} + +func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) { + buf := blockstore.NewBuffered(opts.Bstore) + cst := cbor.NewCborStore(buf) + state, err := state.LoadStateTree(cst, opts.StateBase) + if err != nil { + return nil, err + } + + baseCirc, err := opts.CircSupplyCalc(ctx, opts.Epoch, state) + if err != nil { + return nil, err + } + + id, err := ffi.CreateFVM(0, opts.Epoch, opts.BaseFee, baseCirc, opts.NetworkVersion, opts.StateBase) + if err != nil { + return nil, err + } + + return &FVM{ + extern: FvmExtern{rand: opts.Rand}, + machineId: id, + }, nil +} + +func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) { + msgBytes, err := cmsg.VMMessage().Serialize() + if err != nil { + return nil, xerrors.Errorf("serializing msg: %w", err) + } + + ret, err := ffi.ApplyMessage(vm.machineId, 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: &GasOutputs{ + // TODO: do the other optional fields eventually + BaseFeeBurn: abi.TokenAmount{}, + OverEstimationBurn: abi.TokenAmount{}, + MinerPenalty: ret.MinerPenalty, + MinerTip: ret.MinerTip, + Refund: abi.TokenAmount{}, + GasRefund: 0, + GasBurned: 0, + }, + // TODO: do these eventually, not consensus critical + ActorErr: nil, + ExecutionTrace: types.ExecutionTrace{}, + Duration: 0, + }, nil +} + +func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*ApplyRet, error) { + msgBytes, err := cmsg.VMMessage().Serialize() + if err != nil { + return nil, xerrors.Errorf("serializing msg: %w", err) + } + + ret, err := ffi.ApplyMessage(vm.machineId, 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: &GasOutputs{ + // TODO: do the other optional fields eventually + BaseFeeBurn: abi.TokenAmount{}, + OverEstimationBurn: abi.TokenAmount{}, + MinerPenalty: ret.MinerPenalty, + MinerTip: ret.MinerTip, + Refund: abi.TokenAmount{}, + GasRefund: 0, + GasBurned: 0, + }, + // TODO: do these eventually, not consensus critical + ActorErr: nil, + ExecutionTrace: types.ExecutionTrace{}, + Duration: 0, + }, nil +} + +func (vm *FVM) Flush(ctx context.Context) (cid.Cid, error) { + return cid.Undef, nil +} diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 1ab97bc33..2ee732d5e 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -201,6 +201,8 @@ type ( LookbackStateGetter func(context.Context, abi.ChainEpoch) (*state.StateTree, error) ) +var _ VMI = (*VM)(nil) + type VM struct { cstate *state.StateTree cst *cbor.BasicIpldStore diff --git a/chain/vm/vmi.go b/chain/vm/vmi.go new file mode 100644 index 000000000..4903354d2 --- /dev/null +++ b/chain/vm/vmi.go @@ -0,0 +1,14 @@ +package vm + +import ( + "context" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +type VMI interface { + ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) + ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) + Flush(ctx context.Context) (cid.Cid, error) +} diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index e660df561..7e1f3a991 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit e660df5616e397b2d8ac316f45ddfa7a44637971 +Subproject commit 7e1f3a991e410a71ed9ef33becee8d56d5cb9d26