Populates per-block state read/write counts in slow-block JSON for BAL
blocks (which #34892 left as TBD), and adds reader-level read timing.
Builds on top of bal-devnet-3 — most of the PR's earlier slow-block log
infrastructure was adapted into upstream by that commit, so this change
is now scoped to the metric population that the BAL alone can derive.
- BAL helpers: BlockAccessList.{UniqueAccountCount, UniqueStorageSlotCount,
WrittenCounts}. WrittenCounts walks the BAL once and returns the
block-aggregate write counts.
- Reader-level read timing: *reader times all synchronous Account/Storage/
Code/CodeSize calls via atomic counters; exposed via ReadTimes()
ReadDurations and the new state.ReadTimer interface. Replaces StateDB-
level AccountReads/StorageReads/CodeReads tracking (the StateDB shouldn't
time its dependencies — the reader is where the I/O happens).
- Reader-level code-load dedup: *reader.codeLoaded sync.Map records the
first-seen byte length per address; CodeLoads() returns (count, bytes).
Exposed via state.CodeLoadTracker. Replaces StateDB CodeLoaded/
CodeLoadBytes tracking and the SnapshotCodeLoads aggregation pattern.
- BALStateTransition: caches BlockAccessList.WrittenCounts() once at
construction; tracks accountDeleted/storageDeleted atomics for the
parallel root-pass (the BAL alone can't distinguish a selfdestruct from
a balance/nonce reset). Exposes Deletions() DeletionCounts. Drops the
older accountUpdated/storageUpdated/codeUpdated/codeUpdateBytes counters
(now derived from WrittenCounts).
- BAL block stats path (blockchain.go): populates StateCounts directly —
AccountUpdated = WrittenCounts.Accounts - Deletions.Accounts (same for
storage). AccountLoaded/StorageLoaded come from BAL. CodeLoaded/
CodeLoadBytes come from the shared *reader (deduplicated across phase
StateDBs naturally because they share one reader instance).
- Non-BAL block stats path: read durations come from the reader; counts
from StateDB fields. StorageUpdated/StorageDeleted unified to int width.
- Hard type assertions: state.ReadTimer / state.CodeLoadTracker /
state.ReaderStater consumers use direct casts (no silent zero
fallback) — every Reader chain in production satisfies these
interfaces.
- Meter alignment: account/storage Updated meters subtract Deletions to
avoid double-reporting blocks under both Update and Delete dashboards.