Skip to content

fix(seismic/txpool): rebuild recent block cache on next-height reorgs - #484

Draft
dieutx wants to merge 1 commit into
SeismicSystems:seismicfrom
dieutx:fix/reorg-recent-block-cache-continuity
Draft

fix(seismic/txpool): rebuild recent block cache on next-height reorgs#484
dieutx wants to merge 1 commit into
SeismicSystems:seismicfrom
dieutx:fix/reorg-recent-block-cache-continuity

Conversation

@dieutx

@dieutx dieutx commented Aug 21, 2026

Copy link
Copy Markdown

Problem

RecentBlockCache::update treated every head at cached_height + 1 as a direct extension. Height adjacency alone does not prove chain continuity: after a reorg, the replacement chain can reach one block above the cached losing fork while the new tip's parent differs from the cached tip.

In that case the fast path appended only the new tip and returned without rebuilding. Old-fork hashes remained cached, while hashes from the replacement segment were absent.

Why it matters

The txpool uses this cache to validate the recent_block_hash carried by Seismic transactions and to evict transactions made stale by a reorg. A stale cache can reject otherwise-valid transactions referencing replacement-chain blocks and delay removal of transactions that reference the losing fork until those hashes age out.

Reproduction

  1. Seed a five-entry RecentBlockCache with old-fork blocks 8, 9, and 10.
  2. Notify it of replacement-chain block 11 whose parent is the replacement hash at height 10, not the cached old-fork hash at height 10.
  3. Provide canonical replacement hashes for heights 6 through 10.
  4. On the base revision, 11 == cached_height + 1 takes the append-only path without consulting the canonical hashes. The old hashes at heights 8 through 10 remain and the replacement hashes are missing.

The added test_update_next_height_reorg_triggers_rebuild encodes this scenario. Applied as a test-only change to base commit 39d04d158da383324b12c2e3397b0b28f3c3ee36, it fails at the assertion that the old height-8 hash was removed. It passes with this fix and verifies that the cache contains the replacement window for heights 7 through 11.

Fix

Pass the notified block's parent hash into the cache update. The O(1), callback-free append path now requires both adjacent height and parent continuity. An adjacent-height parent mismatch rebuilds the canonical window immediately.

Both the validator and freshness-maintenance callers now pass the sealed tip's actual parent hash.

Tests

  • cargo test -p reth-seismic-txpool recent_block_cache::tests::test_update_next_height_reorg_triggers_rebuild -- --exact — pass
  • cargo test -p reth-seismic-txpool — pass (32 tests plus doc tests)
  • cargo clippy -p 'reth-seismic*' -p 'seismic-reth*' --lib --tests --no-deps -- -D warnings -W clippy::unwrap_used -W clippy::expect_used -W clippy::indexing_slicing -W clippy::panic -W clippy::unreachable -W clippy::todo — pass
  • cargo +nightly fmt --all --check — pass
  • cargo check --workspace — pass
  • RUSTFLAGS="-D warnings" cargo check — pass

MSRV 1.88, pinned workspace clippy 1.91.1, and workspace nextest were not run locally because those toolchains/tools are unavailable in the local environment; GitHub CI will provide those results. dprint and zepter were also unavailable locally; this change does not modify TOML, dependencies, or feature propagation.

Risk

The change is limited to the recent-block cache update contract and its two production callers. Normal direct extensions retain the callback-free fast path; existing gap and same/lower-height reorg handling is unchanged. There are no consensus, storage-format, dependency, feature, or lookback-capacity changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant