Skip to content

Commit

Permalink
feat: fvm: add support for looking up past tipset CIDs
Browse files Browse the repository at this point in the history
We do this by adding yet another "getter" to the VM that resolves an
epoch into a TipSetKey.
  • Loading branch information
Stebalien committed Nov 19, 2022
1 parent 16e0799 commit 2e5cfb2
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 10 deletions.
1 change: 1 addition & 0 deletions chain/consensus/filcns/compute_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
2 changes: 2 additions & 0 deletions chain/stmgr/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
NetworkVersion: sm.GetNetworkVersion(ctx, pheight+1),
BaseFee: types.NewInt(0),
LookbackState: LookbackStateGetterForTipset(sm, ts),
TipSetGetter: TipSetGetterForTipset(sm.cs, ts),
Tracing: true,
}

Expand Down Expand Up @@ -226,6 +227,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
NetworkVersion: sm.GetNetworkVersion(ctx, ts.Height()+1),
BaseFee: ts.Blocks()[0].ParentBaseFee,
LookbackState: LookbackStateGetterForTipset(sm, ts),
TipSetGetter: TipSetGetterForTipset(sm.cs, ts),
Tracing: true,
}
vmi, err := sm.newVM(ctx, vmopt)
Expand Down
11 changes: 11 additions & 0 deletions chain/stmgr/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down
10 changes: 10 additions & 0 deletions chain/vm/fvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type FvmExtern struct {
blockstore.Blockstore
epoch abi.ChainEpoch
lbState LookbackStateGetter
tsGet TipSetGetter
base cid.Cid
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
},
Expand Down
2 changes: 2 additions & 0 deletions chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -223,6 +224,7 @@ type VMOpts struct {
NetworkVersion network.Version
BaseFee abi.TokenAmount
LookbackState LookbackStateGetter
TipSetGetter TipSetGetter
Tracing bool
}

Expand Down
35 changes: 25 additions & 10 deletions conformance/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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{
Expand All @@ -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
Expand Down

0 comments on commit 2e5cfb2

Please sign in to comment.