feat: fvm: add support for looking up past tipset CIDs (#9687)
* feat: add support for generating tipset CIDs (cherry-picked from feat/nv18-fevm) * feat: fvm: add support for looking up past tipset CIDs We do this by adding yet another "getter" to the VM that resolves an epoch into a TipSetKey. Co-authored-by: Kevin Li <ychiaoli18@users.noreply.github.com>
This commit is contained in:
parent
64de59ab44
commit
e78d1306ee
@ -100,6 +100,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
|
||||
NetworkVersion: sm.GetNetworkVersion(ctx, e),
|
||||
BaseFee: baseFee,
|
||||
LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts),
|
||||
TipSetGetter: stmgr.TipSetGetterForTipset(sm.ChainStore(), ts),
|
||||
Tracing: vmTracing,
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,7 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr
|
||||
NetworkVersion: nvGetter(ctx, vmHeight),
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
LookbackState: LookbackStateGetterForTipset(sm, ts),
|
||||
TipSetGetter: TipSetGetterForTipset(sm.cs, ts),
|
||||
Tracing: true,
|
||||
}
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
|
@ -95,6 +95,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
NetworkVersion: sm.GetNetworkVersion(ctx, height),
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
LookbackState: LookbackStateGetterForTipset(sm, ts),
|
||||
TipSetGetter: TipSetGetterForTipset(sm.cs, ts),
|
||||
Tracing: true,
|
||||
}
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
@ -131,6 +132,16 @@ func LookbackStateGetterForTipset(sm *StateManager, ts *types.TipSet) vm.Lookbac
|
||||
}
|
||||
}
|
||||
|
||||
func TipSetGetterForTipset(cs *store.ChainStore, ts *types.TipSet) vm.TipSetGetter {
|
||||
return func(ctx context.Context, round abi.ChainEpoch) (types.TipSetKey, error) {
|
||||
ts, err := cs.GetTipsetByHeight(ctx, round, ts, true)
|
||||
if err != nil {
|
||||
return types.EmptyTSK, err
|
||||
}
|
||||
return ts.Key(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, cid.Cid, error) {
|
||||
var lbr abi.ChainEpoch
|
||||
lb := policy.GetWinningPoStSectorSetLookback(sm.GetNetworkVersion(ctx, round))
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
@ -98,6 +99,28 @@ func (k *TipSetKey) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k TipSetKey) Cid() (cid.Cid, error) {
|
||||
blk, err := k.ToStorageBlock()
|
||||
if err != nil {
|
||||
return cid.Cid{}, err
|
||||
}
|
||||
return blk.Cid(), nil
|
||||
}
|
||||
|
||||
func (k TipSetKey) ToStorageBlock() (block.Block, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := k.MarshalCBOR(buf); err != nil {
|
||||
log.Errorf("failed to marshal ts key as CBOR: %s", k)
|
||||
}
|
||||
|
||||
cid, err := abi.CidBuilder.Sum(buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return block.NewBlockWithCid(buf.Bytes(), cid)
|
||||
}
|
||||
|
||||
func (k TipSetKey) MarshalCBOR(writer io.Writer) error {
|
||||
if err := typegen.WriteMajorTypeHeader(writer, typegen.MajByteString, uint64(len(k.Bytes()))); err != nil {
|
||||
return err
|
||||
|
@ -45,6 +45,7 @@ type FvmExtern struct {
|
||||
blockstore.Blockstore
|
||||
epoch abi.ChainEpoch
|
||||
lbState LookbackStateGetter
|
||||
tsGet TipSetGetter
|
||||
base cid.Cid
|
||||
}
|
||||
|
||||
@ -99,6 +100,14 @@ func (t *FvmExecutionTrace) ToExecutionTrace() types.ExecutionTrace {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (x *FvmExtern) TipsetCid(ctx context.Context, epoch abi.ChainEpoch) (cid.Cid, error) {
|
||||
tsk, err := x.tsGet(ctx, epoch)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
return tsk.Cid()
|
||||
}
|
||||
|
||||
// VerifyConsensusFault is similar to the one in syscalls.go used by the Lotus VM, 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) {
|
||||
@ -294,6 +303,7 @@ func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) {
|
||||
Rand: opts.Rand,
|
||||
Blockstore: opts.Bstore,
|
||||
lbState: opts.LookbackState,
|
||||
tsGet: opts.TipSetGetter,
|
||||
base: opts.StateBase,
|
||||
epoch: opts.Epoch,
|
||||
},
|
||||
|
@ -192,6 +192,7 @@ type (
|
||||
CircSupplyCalculator func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error)
|
||||
NtwkVersionGetter func(context.Context, abi.ChainEpoch) network.Version
|
||||
LookbackStateGetter func(context.Context, abi.ChainEpoch) (*state.StateTree, error)
|
||||
TipSetGetter func(context.Context, abi.ChainEpoch) (types.TipSetKey, error)
|
||||
)
|
||||
|
||||
var _ Interface = (*LegacyVM)(nil)
|
||||
@ -223,6 +224,7 @@ type VMOpts struct {
|
||||
NetworkVersion network.Version
|
||||
BaseFee abi.TokenAmount
|
||||
LookbackState LookbackStateGetter
|
||||
TipSetGetter TipSetGetter
|
||||
Tracing bool
|
||||
}
|
||||
|
||||
|
@ -203,6 +203,9 @@ type ExecuteMessageParams struct {
|
||||
|
||||
// Lookback is the LookbackStateGetter; returns the state tree at a given epoch.
|
||||
Lookback vm.LookbackStateGetter
|
||||
|
||||
// TipSetGetter returns the tipset key at any given epoch.
|
||||
TipSetGetter vm.TipSetGetter
|
||||
}
|
||||
|
||||
// ExecuteMessage executes a conformance test vector message in a temporary VM.
|
||||
@ -217,15 +220,26 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
params.Rand = NewFixedRand()
|
||||
}
|
||||
|
||||
// TODO: This lookback state returns the supplied precondition state tree, unconditionally.
|
||||
// This is obviously not correct, but the lookback state tree is only used to validate the
|
||||
// worker key when verifying a consensus fault. If the worker key hasn't changed in the
|
||||
// current finality window, this workaround is enough.
|
||||
// The correct solutions are documented in https://github.com/filecoin-project/ref-fvm/issues/381,
|
||||
// but they're much harder to implement, and the tradeoffs aren't clear.
|
||||
var lookback vm.LookbackStateGetter = func(ctx context.Context, epoch abi.ChainEpoch) (*state.StateTree, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
return state.LoadStateTree(cst, params.Preroot)
|
||||
if params.TipSetGetter == nil {
|
||||
// TODO: If/when we start writing conformance tests against the EVM, we'll need to
|
||||
// actually implement this and (unfortunately) capture any tipsets looked up by
|
||||
// messages.
|
||||
params.TipSetGetter = func(context.Context, abi.ChainEpoch) (types.TipSetKey, error) {
|
||||
return types.EmptyTSK, nil
|
||||
}
|
||||
}
|
||||
|
||||
if params.Lookback == nil {
|
||||
// TODO: This lookback state returns the supplied precondition state tree, unconditionally.
|
||||
// This is obviously not correct, but the lookback state tree is only used to validate the
|
||||
// worker key when verifying a consensus fault. If the worker key hasn't changed in the
|
||||
// current finality window, this workaround is enough.
|
||||
// The correct solutions are documented in https://github.com/filecoin-project/ref-fvm/issues/381,
|
||||
// but they're much harder to implement, and the tradeoffs aren't clear.
|
||||
params.Lookback = func(ctx context.Context, epoch abi.ChainEpoch) (*state.StateTree, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
return state.LoadStateTree(cst, params.Preroot)
|
||||
}
|
||||
}
|
||||
|
||||
vmOpts := &vm.VMOpts{
|
||||
@ -239,7 +253,8 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
Rand: params.Rand,
|
||||
BaseFee: params.BaseFee,
|
||||
NetworkVersion: params.NetworkVersion,
|
||||
LookbackState: lookback,
|
||||
LookbackState: params.Lookback,
|
||||
TipSetGetter: params.TipSetGetter,
|
||||
}
|
||||
|
||||
var vmi vm.Interface
|
||||
|
Loading…
Reference in New Issue
Block a user