fix(engine-api): preserve finalized tags during safe imports#130
fix(engine-api): preserve finalized tags during safe imports#130panos-xyz wants to merge 1 commit into
Conversation
|
Warning Review limit reached
More reviews will be available in 14 minutes. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughBlock-tag tracking is simplified to cache only an L1-derived finalized hash via BlockTagTracker::record_finalized_hash; safe tags are advanced from imports but not seeded into finalized. FCU imports set safe_block_hash = B256::ZERO and use the cached L1-finalized hash (or zero) via resolve_fcu_finalized_hash. Tests assert unsafe imports don't advance safe and reorgs don't retain stale safe state. ChangesFinalized-only FCU tag forwarding
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
b0edf79 to
f03cb53
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/engine-api/src/builder.rs (1)
93-95: ⚡ Quick winUpdate stale safe-tag documentation to match FCU behavior.
This comment says FCU safe is derived from the head’s parent, but Line 917 now unconditionally sends
B256::ZEROforsafe_block_hash. Keeping contradictory docs in this path is risky for future changes.♻️ Suggested doc fix
-/// Only finalized is cached: the FCU's safe hash is derived from the head's parent -/// (always a canonical ancestor), not from a cache, because a cached safe recorded -/// per import would be left dangling by a `new_safe_l2_block(parent_hash)` reorg. +/// Only finalized is cached. +/// +/// FCU safe is intentionally sent as `B256::ZERO` (not cached and not derived from +/// parent) so unsafe imports never advance the RPC-visible safe tag. Safe is advanced +/// only through `set_block_tags` / `new_safe_l2_block`.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/engine-api/src/builder.rs` around lines 93 - 95, The doc comment about the FCU safe being derived from the head's parent is now stale because the code unconditionally sends B256::ZERO for safe_block_hash (see the usage of safe_block_hash and B256::ZERO in the FCU interaction); update the comment in builder.rs near the FCU/safe export to state that safe_block_hash may be B256::ZERO and is currently sent unconditionally (rather than claiming it’s derived from head’s parent), and mention the rationale briefly (unconditional zero sentinel) so the doc matches the behavior of the safe_block_hash variable and the code path that constructs the FCU message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/node/tests/it/engine.rs`:
- Around line 406-420: After creating header_2a and computing block2a_hash, add
a precondition assertion that the provider actually marked 2A as the safe block
before you construct safe_2b; call the same client.request RPC pattern to fetch
the provider's current safe/canonical L2 block (the endpoint used elsewhere in
tests) and assert its hash equals block2a_hash so the test cannot false-pass
when 2A was never promoted to safe prior to the reorg attempt.
---
Nitpick comments:
In `@crates/engine-api/src/builder.rs`:
- Around line 93-95: The doc comment about the FCU safe being derived from the
head's parent is now stale because the code unconditionally sends B256::ZERO for
safe_block_hash (see the usage of safe_block_hash and B256::ZERO in the FCU
interaction); update the comment in builder.rs near the FCU/safe export to state
that safe_block_hash may be B256::ZERO and is currently sent unconditionally
(rather than claiming it’s derived from head’s parent), and mention the
rationale briefly (unconditional zero sentinel) so the doc matches the behavior
of the safe_block_hash variable and the code path that constructs the FCU
message.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1f211d35-32fe-4e10-b9c2-13e5ba884a84
📒 Files selected for processing (2)
crates/engine-api/src/builder.rscrates/node/tests/it/engine.rs
Verification against the pinned reth
|
Historical context: the premise was valid in older reth — but it was fixed upstream before
|
| date | |
|---|---|
| reth #21354 (adds the finalized-unset eviction fallback) | 2026-01-23 |
pinned v2.2.0 tag (88505c7) |
2026-04-29 |
git merge-base --is-ancestor 22a68756c71 v2.2.0 → YES — the fix predates our pinned tag by ~3 months and is included in it.
So: the rationale was defending against a real reth behavior, but that behavior was already resolved upstream before the version we pin. Against v2.2.0 specifically, reth evicts changesets at tip-64 regardless of finalized, so the synthetic-finalized mechanism is no longer needed for changeset/memory cleanup. (Canonical in-memory block reclamation was always unconditional; only the changeset-cache path ever had the finalized gate.)
88a8632 to
9991c0f
Compare
9991c0f to
b41738e
Compare
Summary
Why
Morph main validator mode may not run the external BlockTagService, so reth still needs a non-zero finalized bound for engine-tree cleanup. At the same time, FCU safe must not be synthesized from the parent because unsafe imports would incorrectly mark their parent safe, and cached safe hashes can break parent-hash reorgs.
Verification
Summary by CodeRabbit
Bug Fixes
Tests