Skip to content
Merged
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
12 changes: 12 additions & 0 deletions giga/evmonly/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ including for empty blocks. A receipt failure leaves state unchanged so the
block can be retried. A state failure can leave receipts behind, but retrying
the block overwrites them. `ResultSink` runs only after both stores succeed.

`ExecuteBlock` advances the state store's version itself, independently of any
ABCI `Commit`, so what the store holds after a restart is decided by the
storage layer (which flushes asynchronously and re-executes blocks from
BlockDB), not by which `Commit` calls the application saw. An ABCI application
built on the executor must therefore derive `Info()` from storage rather than
from memory: after a restart, the Giga router calls `InitChain` and replays
block 1 whenever `Info().LastBlockHeight` is zero, which fails against state
that already exists. `WithBlockChangeSetEncoder(...)` lets the application
commit its own named changesets (for example an execution cursor holding the
app hash and parent hash) in the same `CommitStateChanges` call as the block's
EVM state, so the two can never disagree on disk.

The FlatKV encoder persists balance, nonce, code, and storage changes, and the
executor reads them through the current Giga state view. EVM-only Autobahn load
tests use `WithMissingAccountState(...)` to supply the initial funded state for
Expand Down
14 changes: 12 additions & 2 deletions giga/evmonly/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ type Executor struct {
stateStore gigatypes.StateDB
receiptStore receipt.ReceiptStore
changeSetEncoder NamedChangeSetEncoder
missingState StateReader
closed atomic.Bool
// Optional: nil commits only the state encoder's changesets.
blockChangeSetEncoder BlockChangeSetEncoder
missingState StateReader
closed atomic.Bool
}

type Option func(*Executor)
Expand All @@ -50,6 +52,14 @@ func WithMissingAccountState(state StateReader) Option {
}
}

// WithBlockChangeSetEncoder commits the encoder's changesets alongside every
// block's state changes.
func WithBlockChangeSetEncoder(encoder BlockChangeSetEncoder) Option {
return func(e *Executor) {
e.blockChangeSetEncoder = encoder
}
}

// NewExecutor constructs an EVM-only executor. Call Close to disable future OCC
// execution on this executor.
func NewExecutor(cfg Config, opts ...Option) *Executor {
Expand Down
14 changes: 14 additions & 0 deletions giga/evmonly/giga_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ var _ StateReader = gigaSnapshotStateReader{}
// immutable and must not retain references to it after returning.
type NamedChangeSetEncoder func(StateChangeSet) ([]*proto.NamedChangeSet, error)

// BlockChangeSetEncoder contributes named changesets that are committed in the
// same CommitStateChanges call as the block's EVM state changes, so they are
// durable, rolled back and replayed together with that state. It is called
// after execution with the block's context and result, which it must treat as
// immutable. Changesets under keys.EVMStoreKey are reserved for the state encoder.
type BlockChangeSetEncoder func(BlockContext, *BlockResult) ([]*proto.NamedChangeSet, error)

func (e *Executor) executePreparedBlockWithStore(ctx context.Context, req PreparedBlock) (*BlockResult, error) {
stateStore := e.stateStore
if stateStore == nil {
Expand Down Expand Up @@ -84,6 +91,13 @@ func (e *Executor) executePreparedBlockWithStore(ctx context.Context, req Prepar
if err != nil {
return nil, fmt.Errorf("encode state changes for block %d: %w", req.Context.Number, err)
}
if e.blockChangeSetEncoder != nil {
extra, err := e.blockChangeSetEncoder(req.Context, result)
if err != nil {
return nil, fmt.Errorf("encode block changes for block %d: %w", req.Context.Number, err)
}
changesets = append(changesets, extra...)
}
if err := ctx.Err(); err != nil {
return nil, err
}
Expand Down
Loading
Loading