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

feat: discard state writes in StateCompute and StateReplay. #10457

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 14 additions & 11 deletions chain/consensus/compute_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
bms []FilecoinBlockMessages,
epoch abi.ChainEpoch,
r vm.Rand,
em stmgr.ExecMonitor,
vmTracing bool,
opts *stmgr.ExecutorOpts,
baseFee abi.TokenAmount,
ts *types.TipSet) (cid.Cid, cid.Cid, error) {
done := metrics.Timer(ctx, metrics.VMApplyBlocksTotal)
Expand All @@ -91,22 +90,27 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
partDone()
}()

bs := sm.ChainStore().StateBlockstore()
if opts.DiscardState {
bs = blockstore.NewBuffered(bs)
}

ctx = blockstore.WithHotView(ctx)
makeVm := func(base cid.Cid, e abi.ChainEpoch, timestamp uint64) (vm.Interface, error) {
vmopt := &vm.VMOpts{
StateBase: base,
Epoch: e,
Timestamp: timestamp,
Rand: r,
Bstore: sm.ChainStore().StateBlockstore(),
Bstore: bs,
Actors: NewActorRegistry(),
Syscalls: sm.Syscalls,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NetworkVersion: sm.GetNetworkVersion(ctx, e),
BaseFee: baseFee,
LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts),
TipSetGetter: stmgr.TipSetGetterForTipset(sm.ChainStore(), ts),
Tracing: vmTracing,
Tracing: opts.VmTracing,
ReturnEvents: sm.ChainStore().IsStoringEvents(),
}

Expand All @@ -130,7 +134,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
return xerrors.Errorf("running cron: %w", err)
}

if em != nil {
if em := opts.ExecMonitor; em != nil {
if err := em.MessageApplied(ctx, ts, cronMsg.Cid(), cronMsg, ret, true); err != nil {
return xerrors.Errorf("callback failed on cron message: %w", err)
}
Expand Down Expand Up @@ -175,7 +179,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,

// handle state forks
// XXX: The state tree
pstate, err = sm.HandleStateForks(ctx, pstate, i, em, ts)
pstate, err = sm.HandleStateForks(ctx, pstate, i, opts.ExecMonitor, ts)
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err)
}
Expand Down Expand Up @@ -219,7 +223,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
events = append(events, r.Events)
}

if em != nil {
if em := opts.ExecMonitor; em != nil {
if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil {
return cid.Undef, cid.Undef, err
}
Expand All @@ -233,7 +237,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
GasReward: gasReward,
WinCount: b.WinCount,
}
rErr := t.reward(ctx, vmi, em, epoch, ts, params)
rErr := t.reward(ctx, vmi, opts.ExecMonitor, epoch, ts, params)
if rErr != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("error applying reward: %w", rErr)
}
Expand Down Expand Up @@ -291,8 +295,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
func (t *TipSetExecutor) ExecuteTipSet(ctx context.Context,
sm *stmgr.StateManager,
ts *types.TipSet,
em stmgr.ExecMonitor,
vmTracing bool) (stateroot cid.Cid, rectsroot cid.Cid, err error) {
opts *stmgr.ExecutorOpts) (stateroot cid.Cid, rectsroot cid.Cid, err error) {
ctx, span := trace.StartSpan(ctx, "computeTipSetState")
defer span.End()

Expand Down Expand Up @@ -340,7 +343,7 @@ func (t *TipSetExecutor) ExecuteTipSet(ctx context.Context,
}
baseFee := blks[0].ParentBaseFee

return t.ApplyBlocks(ctx, sm, parentEpoch, pstate, fbmsgs, blks[0].Height, r, em, vmTracing, baseFee, ts)
return t.ApplyBlocks(ctx, sm, parentEpoch, pstate, fbmsgs, blks[0].Height, r, opts, baseFee, ts)
}

func (t *TipSetExecutor) StoreEventsAMT(ctx context.Context, cs *store.ChainStore, events []types.Event) (cid.Cid, error) {
Expand Down
6 changes: 5 additions & 1 deletion chain/stmgr/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,11 @@ func (sm *StateManager) Replay(ctx context.Context, ts *types.TipSet, mcid cid.C
// message to find
finder.mcid = mcid

_, _, err := sm.tsExec.ExecuteTipSet(ctx, sm, ts, &finder, true)
_, _, err := sm.tsExec.ExecuteTipSet(ctx, sm, ts, &ExecutorOpts{
ExecMonitor: &finder,
VmTracing: true,
DiscardState: true, // safe to skip the write since this is throwaway state.
})
if err != nil && !xerrors.Is(err, errHaltExecution) {
return nil, nil, xerrors.Errorf("unexpected error during execution: %w", err)
}
Expand Down
20 changes: 18 additions & 2 deletions chain/stmgr/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ import (
)

func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st cid.Cid, rec cid.Cid, err error) {
return sm.TipSetStateWithOpts(ctx, ts, &TipSetStateOpts{})
}

type TipSetStateOpts struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced this is necessary? With the existing tipsetstate cache, and the newly added fast lookup in #10445, I think we can drop this. We'll only wind up executing the tipset (making the write) if:

  • we're executing a tipset that isn't in our main chain
  • we're missing the actual state / receipts root.

// DiscardState: see ExecutorOpts.DiscardState.
DiscardState bool
}

func (sm *StateManager) TipSetStateWithOpts(ctx context.Context, ts *types.TipSet, opts *TipSetStateOpts) (st cid.Cid, rec cid.Cid, err error) {
ctx, span := trace.StartSpan(ctx, "tipSetState")
defer span.End()
if span.IsRecordingEvents() {
Expand Down Expand Up @@ -59,7 +68,10 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
return st, rec, nil
}

st, rec, err = sm.tsExec.ExecuteTipSet(ctx, sm, ts, sm.tsExecMonitor, false)
st, rec, err = sm.tsExec.ExecuteTipSet(ctx, sm, ts, &ExecutorOpts{
ExecMonitor: sm.tsExecMonitor,
DiscardState: opts.DiscardState,
})
if err != nil {
return cid.Undef, cid.Undef, err
}
Expand Down Expand Up @@ -113,7 +125,11 @@ func tryLookupTipsetState(ctx context.Context, cs *store.ChainStore, ts *types.T
}

func (sm *StateManager) ExecutionTraceWithMonitor(ctx context.Context, ts *types.TipSet, em ExecMonitor) (cid.Cid, error) {
st, _, err := sm.tsExec.ExecuteTipSet(ctx, sm, ts, em, true)
st, _, err := sm.tsExec.ExecuteTipSet(ctx, sm, ts, &ExecutorOpts{
ExecMonitor: em,
VmTracing: true,
DiscardState: true, // safe to discard the output state since we're creating no new state anyway.
})
return st, err
}

Expand Down
12 changes: 11 additions & 1 deletion chain/stmgr/stmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,19 @@ func (m *migrationResultCache) Store(ctx context.Context, root cid.Cid, resultCi
return nil
}

// ExecutorOpts defines options for the execution.
type ExecutorOpts struct {
ExecMonitor ExecMonitor
VmTracing bool
// DiscardState, when enabled, skips writing the output state tree into the
// blockstore. This is useful when requesting execution traces for tipsets
// already in the chain, or for speculative executions.
DiscardState bool
}

type Executor interface {
NewActorRegistry() *vm.ActorRegistry
ExecuteTipSet(ctx context.Context, sm *StateManager, ts *types.TipSet, em ExecMonitor, vmTracing bool) (stateroot cid.Cid, rectsroot cid.Cid, err error)
ExecuteTipSet(ctx context.Context, sm *StateManager, ts *types.TipSet, opts *ExecutorOpts) (stateroot cid.Cid, rectsroot cid.Cid, err error)
}

type StateManager struct {
Expand Down
4 changes: 3 additions & 1 deletion chain/stmgr/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
gstStore "github.com/filecoin-project/go-state-types/store"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/blockstore"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
"github.com/filecoin-project/lotus/chain/actors/policy"
Expand Down Expand Up @@ -86,13 +87,14 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
// future. It's not guaranteed to be accurate... but that's fine.
}

bs := blockstore.NewBuffered(sm.cs.StateBlockstore())
r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, sm.GetNetworkVersion)
vmopt := &vm.VMOpts{
StateBase: base,
Epoch: height,
Timestamp: ts.MinTimestamp(),
Rand: r,
Bstore: sm.cs.StateBlockstore(),
Bstore: bs,
Actors: sm.tsExec.NewActorRegistry(),
Syscalls: sm.Syscalls,
CircSupplyCalc: sm.GetVMCirculatingSupply,
Expand Down
6 changes: 4 additions & 2 deletions conformance/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,10 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
blocks,
params.ExecEpoch,
params.Rand,
recordOutputs,
true,
&stmgr.ExecutorOpts{
ExecMonitor: recordOutputs,
VmTracing: true,
},
params.BaseFee,
nil,
)
Expand Down
2 changes: 1 addition & 1 deletion node/impl/full/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -1843,7 +1843,7 @@ func messagesAndReceipts(ctx context.Context, ts *types.TipSet, cs *store.ChainS
return nil, nil, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err)
}

_, rcptRoot, err := sa.StateManager.TipSetState(ctx, ts)
_, rcptRoot, err := sa.StateManager.TipSetStateWithOpts(ctx, ts, &stmgr.TipSetStateOpts{DiscardState: true})
if err != nil {
return nil, nil, xerrors.Errorf("failed to compute state: %w", err)
}
Expand Down