Expand description
Event → state pipeline (Pillar B.2 — the reader half of the event pipeline).
Phase 3 (state_update) built the writer half: the
generic StateUpdate vocabulary and the cold-aware
apply_updates that consumes it. This
module builds the reader half: it turns an on-chain Log into that same
vocabulary and drives it through the cache, keeping event-derived state
reactively fresh.
§The flow
Log ─▶ EventDecoder::decode(log, &StateView) ─▶ Vec<StateUpdate>
│
apply_updates ▼
EvmCache (+ StateDiff)A DecoderRegistry dispatches a log to the decoders registered for its
emitting address (plus any global decoders) and concatenates their output. An
EventPipeline orchestrates a block’s logs: ingest_logs decodes and
applies them log-by-log in order (so a later log’s decode observes the
effects of earlier ones through the StateView), reorg_to purges the
addresses touched after a new head, and reconcile re-reads sampled
event-derived slots against chain truth (correct and alarm).
§Decoders are pure data functions
EventDecoder::decode is a pure function of (log, pre-state): it performs
no I/O and emits serializable, replayable StateUpdate data. Most updates
need no pre-state (SlotDelta and
SlotMasked are read-modify-write at apply
time), but stateful external adapters may read the narrow read-only
StateView to compute a post-state from cached pre-state. The view never touches RPC; a
slot absent from the cache reads None (cold), and a decoder that cannot
compute against a cold word surfaces a skip rather than inventing a value.
§!Send cache discipline
EvmCache is !Send (it owns the mutable fork and
blocks on RPC internally). All of EventPipeline’s core methods
(ingest_logs /
reorg_to /
reconcile) take &mut EvmCache and are
synchronous — they never .await, so the cache is never held across a
yield point. This is what makes the core deterministically testable offline.
The async drive convenience holds the cache only across the log source
await (the source future is Send; the cache is untouched during it).
§Freshness wiring
BlockDigest::touched_slots surfaces the (address, slot) set written for a
block so a caller can classify event-derived slots in a
FreshnessRegistry — typically pin them
(Validity::Pinned) or mark them
Validity::ValidThrough so the
optimistic validator does not waste RPC re-verifying state the pipeline keeps
fresh — then call
FreshnessController::on_new_block.
No controller internals change. Periodically call
reconcile to sample-check those slots against the
chain (honest freshness).
Modules§
- erc20
- Generic ERC-20
Transferdecoder (generic core).
Structs§
- Block
Digest - Per-block result of
EventPipeline::ingest_logs. - Decoder
Registry - Dispatches a log to the decoders registered for its emitting address (and any global decoders) and concatenates their output.
- Event
Pipeline - Orchestrates decoding, applying, reorg handling, and reconciliation of a
block’s logs against an
EvmCache. - Reconcile
Report - Result of
EventPipeline::reconcile. - Reorg
Config - How a reorg purges the addresses touched after the new head.
Traits§
- Event
Decoder - Decode one log into zero or more targeted
StateUpdates. - LogSource
- An async source of blocks of logs for
drive. - State
View - Read-only view of current cached state handed to a decoder.
Functions§
- drive
- Drive
pipelineoversource, ingesting each block (reorging first when signalled) and invokingon_blockafter each ingest.
Type Aliases§
- Reorg
Signal - A signalled reorg accompanying a block from a
LogSource.