fix: Fix eth_getLogs pending state handling, and more e2e pending state coverage#267
fix: Fix eth_getLogs pending state handling, and more e2e pending state coverage#267louisliu2048 merged 4 commits intomainfrom
Conversation
Add two new e2e tests that exercise flashblocks pending state ahead of canonical: fb_pending_native_balance_delta_test verifies sender/recipient balance deltas and sender nonce increment on Pending immediately after a native transfer; fb_pending_erc20_balance_delta_test verifies sender and recipient ERC20 balance deltas on Pending via eth_call(balanceOf). Add sleep_one_blocktime (~1 block) at the start of pending-state tests that send transactions so tests do not race with block boundaries, and add an erc20_balance_of_pending helper that reads balanceOf via manual calldata to avoid sol! macro name collisions. Rework fb_pending_get_logs_test and fb_get_logs_cross_boundary_range_test to query via the Pending tag instead of waiting for the canonical chain to reach the tx block. Snapshot canonical height before send and assert that tx_block is ahead of canonical_before so the log is verifiably served from the flashblocks state cache overlay. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
eth_getLogs on the flashblocks RPC delegated the whole filter to the canonical filter whenever get_rpc_block returned None for the toBlock tag. This happened in a brief window after a pending sequence was promoted (pending_cache = None) or after canonical catch-up evicted the confirm-cache entry at confirm_height, causing the canonical filter to resolve Pending/Latest against canonical and drop logs from confirm- cache blocks ahead of canonical. Resolve Pending/Latest directly to pending_height/confirm_height from the flashblocks state cache and let the existing range scan handle cross-boundary fallback via get_canonical_logs. Distinguish "no bound supplied" (Option::None) from "unsupported tag" (Earliest/Safe/Finalized) and delegate the whole filter to canonical only for the latter, so those tags are not silently collapsed to the FB cache range. Drop the now-unused eth_api field and its main.rs arg since the new logic no longer needs convert_block_number. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@claude review for me |
XLayer-Bot
left a comment
There was a problem hiding this comment.
The core filter.rs fix is correct and well-designed. Resolving Pending/Latest directly to the cached heights eliminates the delegation race during the pending_cache = None window, and resolve_fb_bound cleanly separates FB-served tags from canonical-only ones (Earliest/Safe/Finalized). Removing the unused eth_api field is a good clean-up. Two concerns in the new test code below.
The stale `from > confirm_height → empty` guard short-circuited valid queries when a tx landed in the currently-building pending sequence (from = pending_height, confirm_height = pending_height - 1). With Pending/Latest now resolving to flashblocks cache heights, the pending block is a valid range bound: its block and receipts are served directly from the pending sequence in the FB cache. Drop the stale guard. Keep the existing `from > pending_height → error` and add a symmetric `to > pending_height → error` so the range scan only runs for ranges within the flashblocks cache tip. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@claude review again |
XLayer-Bot
left a comment
There was a problem hiding this comment.
Both previously flagged concerns have been fully addressed:
-
L1 data fee in sender-balance assertion — accepted design: XLayer devnet uses zero L1 fee oracle scalars, so is effectively zero and the simplified gas cost computation is correct.
-
**Stale guard causing empty-result race in ** — fixed in commit 63fd06e: the guard is removed, now resolves to via , and is a valid range served directly from the FB cache. Only now returns .
The rest of the changes look clean:
- Removing the now-unused field from is a good simplification.
- covers all variants correctly (// delegate to canonical).
- The additions reduce block-boundary flakiness across the pending-state tests.
- New and are well-structured and correctly account for gas cost.
- The ABI encoding (selector + 12-byte padding + 20-byte address = 36 bytes) is correct.
The 500ms receipt poll interval dominated the measured confirmation latency in fb_benchmark_*_tx_confirmation tests: flashblocks nodes can confirm in well under one block time, so every sample rounded up to the next 500ms tick and the benchmark never reflected true sub-block latency. 10ms aligns the poll interval below a flashblock slot (~250ms) so benchmarks report accurate confirmation timings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
🔧 CI running — workflow run |
|
✅ XLayer Reth CI passed for commit
|
Description
Two related changes to the flashblocks RPC layer.
Fix
eth_getLogspending-state handling (crates/rpc/src/filter.rs)toBlock=Pending/Latestdelegated the whole filter to the canonical filter wheneverget_rpc_blockreturnedNone— which happens in the brief window after a pending sequence is promoted (pending_cache = None) or after canonical catch-up evicts the confirm-cache entry. The canonical filter then resolvesPending/Latestagainst canonical and drops logs from confirm-cache blocks ahead of canonical.Now resolves
Pending/Latestdirectly topending_height/confirm_heightfrom the flashblocks state cache; the existing range scan handles cross-boundary fallback viaget_canonical_logs.Earliest/Safe/Finalizeddelegate the whole filter to canonical (they are not served by the FB cache), distinguished from "no bound supplied" so the bound is not silently collapsed into the FB cache range.More e2e pending-state coverage (
crates/tests/flashblocks-tests/main.rs)fb_pending_native_balance_delta_test— asserts sender/recipient balance deltas and sender nonce increment onPendingimmediately after a native transfer.fb_pending_erc20_balance_delta_test— asserts sender/recipient ERC20 balance deltas onPendingviaeth_call(balanceOf)immediately after an ERC20 transfer.sleep_one_blocktime()(~1 block) at the start of pending-state tests that send transactions to avoid block-boundary races.fb_pending_get_logs_testandfb_get_logs_cross_boundary_range_testto query viaPending/Number(tx_block)ahead-of-canonical ranges instead of waiting for canonical catch-up — exercising the actual flashblocks overlay.Type of Change
FlashblocksEthFilterExt::logsflowTesting
cargo check -p xlayer-rpc,cargo clippy -p xlayer-rpc --all-targets -- -D warnings,cargo fmt -p xlayer-rpc -- --checkcargo check/clippy/fmt -p xlayer-e2e-test --test flashblocks_testsfb_pending_get_logs_testreliably passes against a running devnet, including in thepending_cache = Nonewindow that previously caused intermittent failures.Additional Notes
None — no public API changes outside
FlashblocksEthFilterExt::newdropping the unusedeth_apiparameter (bin/node/src/main.rsupdated in the same commit).