Simplify and harden re-org handling (single writer path in mapping-sync)#1820
Simplify and harden re-org handling (single writer path in mapping-sync)#1820
Conversation
📝 WalkthroughWalkthroughThis PR introduces a canonical reconciliation engine for the KV mapping-sync layer that aligns frontier's canonical state with on-chain state, refactors block synchronization to use this engine, improves RPC block resolution with cached readable hash detection, and updates integration tests to handle asynchronous block availability more robustly. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant KVBackend as KV Backend
participant Reconciler as Canonical Reconciler
participant Storage as Storage Override
participant Frontier as Frontier DB
Client->>Reconciler: build_reconcile_window(reorg_info, new_best_hash)
Reconciler->>KVBackend: query headers & reorg state
KVBackend-->>Reconciler: header data
Reconciler-->>Client: ReconcileWindow {start, end}
Client->>Reconciler: reconcile_reorg_window(window, sync_from)
loop For each block in range
Reconciler->>KVBackend: get block header
KVBackend-->>Reconciler: header
Reconciler->>Storage: get canonical mapping
Storage-->>Reconciler: mapping
Reconciler->>Frontier: update canonical hash
Frontier-->>Reconciler: ack
end
Reconciler->>KVBackend: update_repair_cursor(strategy)
KVBackend-->>Reconciler: cursor updated
Reconciler->>Reconciler: validate_latest_pointer_invariant()
Reconciler-->>Client: ReconcileStats {scanned, updated, lag_blocks}
sequenceDiagram
participant Eth as Eth RPC Handler
participant Cache as Readable Hash Cache
participant Client as Substrate Client
participant Backend as FC Backend
Eth->>Eth: latest_indexed_hash_with_block()
Eth->>Cache: check cached hash
alt Cache hit & valid
Cache-->>Eth: cached hash
else Cache miss or invalid
Eth->>Client: get latest indexed block
Client-->>Eth: latest block number
Eth->>Eth: find_readable_hash_from_number_desc(bounded range)
loop Descending block scan
Eth->>Backend: is_readable(block_number)
Backend-->>Eth: readable: bool
end
Eth->>Cache: update cache with readable hash
Cache-->>Eth: ack
end
Eth-->>Eth: return hash with metadata
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
Comment |
| type RuntimeStorageOverride = (); | ||
| } | ||
|
|
||
| const LATEST_READABLE_SCAN_LIMIT: u64 = 128; |
There was a problem hiding this comment.
Shouldn't users be able to easily change this? Maybe adding an extra (optional) param for it (in EthConfiguration)?
…nc) (#1820) * rework re-orgs handling * rustfmt * clippy * Batch reconciliation should scan backward * On slow runners fee-history cache lags slightly behind block production * keep block queries non-null on missing statuses; bound + cache latest fallback * Harden RPC/latest consistency and stabilize flaky ts-tests under indexing lag
…nc) (polkadot-evm#1820) * rework re-orgs handling * rustfmt * clippy * Batch reconciliation should scan backward * On slow runners fee-history cache lags slightly behind block production * keep block queries non-null on missing statuses; bound + cache latest fallback * Harden RPC/latest consistency and stabilize flaky ts-tests under indexing lag
…nc) (polkadot-evm#1820) * rework re-orgs handling * rustfmt * clippy * Batch reconciliation should scan backward * On slow runners fee-history cache lags slightly behind block production * keep block queries non-null on missing statuses; bound + cache latest fallback * Harden RPC/latest consistency and stabilize flaky ts-tests under indexing lag
…ntier#1824 (#3677) * update frontier pin * Configure AllowUnprotectedTxs to false * Fix compile error * Temporary allow unprotected txs to not break tests * fix dev tests * fix tracing tests * fix coderabbit suggestion
…ntier#1824 (#3677) * update frontier pin * Configure AllowUnprotectedTxs to false * Fix compile error * Temporary allow unprotected txs to not break tests * fix dev tests * fix tracing tests * fix coderabbit suggestion
Goal
Simplify and harden re-org handling by moving canonical block-number mapping updates to a single writer path in mapping-sync, while keeping RPC reads non-mutating and preserving non-null
eth_getBlockByNumber("latest")behavior.What Changed
Centralized canonical block-number reconciliation in mapping-sync:
client/mapping-sync/src/kv/canonical_reconciler.rsas the single path that updates canonical number-to-hash mappings.Removed opportunistic mapping writes outside that path:
sync_blockno longer conditionally writes number mappings.Kept RPC reads non-mutating and resilient:
resolve_canonical_substrate_hash_by_numberis read-only.latestresolution now uses latest indexed block with bounded fallback to nearest readable canonical ancestor (LATEST_READABLE_SCAN_LIMIT = 128) plus a cached readable-latest hint.eth_getBlockByNumber/eth_getBlockByHashnow still return rich blocks when tx statuses are temporarily missing (status slots are filled asNone) to avoid transient nulls.Tests
Rust:
TS:
ts-tests/tests/test-latest-block-consistency.ts: stress polling + re-org storm coverage to assert non-null latest/explicit block queries and eventual convergence.ts-tests/tests/test-fee-history.ts: added bounded wait helper to handle short cache lag and reduce flakiness.Reviewer Notes
latestalways equals immediate tip during indexing lag.Compatibility / Ops Impact