Skip to content

execution/execmodule, node/shards: remove the global Events.LatestSD published-SD pointer (decouple readers via a publication id) #22494

Description

@mh0lt

Summary

node/shards.Events.LatestSD is a process-global atomic.Pointer[execctx.SharedDomains], set by PublishOverlay at each FCU and read by many consumers (RPC cache via execmodule.Cache, txpool OnNewBlock, the block builder, etc.). It is the only way to refer to "the current state publication," and that single mutable global is a source of coupling that this issue proposes to remove.

The coupling effect

  • No identity. The global names only "latest." A consumer cannot reference a specific publication, wait for one, or check it is reading the same one another consumer used. Coordination between consumers therefore degrades to matching by block number (lastSeenBlock / ParentBlockNum in the txpool's best()), which is fork/reorg-ambiguous (same height, different SD).
  • Unsynchronized read-fills. Readers off the global run without the exec-module semaphore, so the cache read-fills they trigger (commitment BranchCache, account/storage StateCache) can land from positions not synchronized with the FCU flush/refresh cycle. This is the coherence hazard already tracked in execution/execmodule: audit published-SD readers (Events.LatestSD, bg-commit) for shared-cache coherence #22214 — a symptom of the global, not a separate problem.
  • No lifetime / refcount. Because the global hands out a bare pointer with no reference tracking, in-flight generations cannot be freed precisely: ExecModule.drainCommittedGens is intentionally a no-op (model A) and generations are only released as a unit at shutdown.

Motivating use case (observed)

Under fcuBackgroundCommit=true, TestAssembleBlockWithStateVerification intermittently built a block with 0 transactions. Root cause: when building block N+1, the txpool had correctly processed block N (lastSeenBlock=N, nonce-N+1 txns pending), but the block builder's state reader was not pinned to the same publication of block N — so it saw a pre-N sender nonce and filtered every valid txn as nonce-gapped. The pool and the builder agreed on the block by number, but nothing pinned them to the same publication. (Fixed as a stopgap on PR #21414 by pinning the builder to the newest generation's retained SD — the same SD the pool reads — but the publication is identified implicitly as "newest generation" rather than by an explicit id.)

Goal

Remove the mutable Events.LatestSD global. Consumers should reference a specific state publication by a stable identifier and coordinate on it, rather than racing to read "the latest global."

Subtask: introduce a (db.sd) publication id

A monotonic major.minor identifier for each published state:

  • major = DB state version — already exists (rawdb.GetStateVersion / IncrementStateVersion, bumped per durable commit).
  • minor = SD id — new; numbers the in-flight generations published between two DB commits (ExecModule.gens). 0 under foreground commit, so it degenerates to today's behaviour when bg-commit is off.

This id gives: (a) a fork-unambiguous handle so the txpool can tag the txns it yields with the publication they are valid at and the builder can wait for that id or build on the parent; (b) a replacement for "latest global" references; (c) the refcount key that lets drainCommittedGens free generations precisely.

Related

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions