Skip to content

refactor(block_tree): compute reorg split via parent-walk LCA#1432

Merged
glottologist merged 3 commits into
masterfrom
jason/remove_lca_indirection
May 29, 2026
Merged

refactor(block_tree): compute reorg split via parent-walk LCA#1432
glottologist merged 3 commits into
masterfrom
jason/remove_lca_indirection

Conversation

@glottologist

@glottologist glottologist commented May 28, 2026

Copy link
Copy Markdown
Contributor

Describe the changes
Before: LCA derived from ChainState::Onchain flag scan via get_fork_blocks, fed into prune_chains_at_ancestor. Stale flags → wrong LCA →Err("common ancestor X not in new chain") → service exit.

After: BlockTree::find_reorg_split walks both lineages through previous_block_hash links, intersects them, returns LCA's sealed block + oldest-first LCA-exclusive divergent suffixes. Caller invokes it before cache.prune. prune_chains_at_ancestor deleted.

Related Issue(s)
Please link to the issue(s) that will be closed with this PR.

Checklist

  • Tests have been added/updated for the changes.
  • Documentation has been updated for the changes (if applicable).
  • The code follows Rust's style guidelines.

Additional Context
Add any other context about the pull request here.

Summary by CodeRabbit

  • Improvements

    • More accurate reorganization handling with improved fork-point detection and safer pruning to reduce spurious downstream errors.
    • Added a cache-window safety check to abort reorg processing when pruning would remove required state.
  • Tests

    • Strengthened fork-recovery and mempool tests to enforce lowest-common-ancestor correctness and cover additional edge cases.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 86943f53-4b54-4b96-b762-c936901c9669

📥 Commits

Reviewing files that changed from the base of the PR and between 0766e48 and 9de4cd2.

📒 Files selected for processing (1)
  • crates/chain-tests/src/utils.rs

📝 Walkthrough

Walkthrough

Compute reorg split with new ReorgSplit abstraction before pruning, validate fork-point against post-prune cache window, prune, derive fork/divergent suffixes from ReorgSplit, remove old prune helper and tests, and add integration assertions enforcing that reorg_event.fork_parent is the LCA.

Changes

Reorg fork-point refactoring

Layer / File(s) Summary
ReorgSplit data model and algorithm
crates/domain/src/models/block_tree.rs
Adds ReorgSplit and ReorgTips and implements BlockTree::find_reorg_split() to parent-walk two tips, find their LCA, and return LCA-exclusive oldest-first divergent suffixes; includes comprehensive unit tests.
Block tree service reorg handling
crates/actors/src/block_tree_service.rs
Refactors on_block_validation_finished to call cache.find_reorg_split() before pruning, adds validate_reorg_within_cache_window() to abort reorgs that would reference data evicted by prune, derives fork/fork-height/blocks-to-confirm directly from ReorgSplit, removes prune_chains_at_ancestor() and its unit tests, and updates imports.
Integration test reorg contract validation
crates/chain-tests/src/multi_node/fork_recovery.rs, crates/chain-tests/src/multi_node/mempool_tests.rs, crates/chain-tests/src/utils.rs
Adds assert_reorg_event_lca_contract() test helper and calls it from affected integration tests to assert that reorg_event.fork_parent is the LCA of the divergent forks' first blocks.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Irys-xyz/irys#1132: Modifies the same block validation completion path (on_block_validation_finished) and may intersect with reorg/prune logic changes.

Suggested reviewers

  • DanMacDonald
  • antouhou
  • roberts-pumpurs
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main refactoring change: computing reorg split via parent-walk LCA algorithm, which aligns with the core objective and the primary architectural change in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jason/remove_lca_indirection

Comment @coderabbitai help to get the list of available commands and usage tips.

@DanMacDonald

DanMacDonald commented May 28, 2026

Copy link
Copy Markdown
Collaborator

like that this yanks out a bunch of complexity

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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/chain-tests/src/multi_node/fork_recovery.rs`:
- Around line 340-365: The current if let (Some(first_old), Some(first_new)) =
(reorg_event.old_fork.first(), reorg_event.new_fork.first()) can silently skip
LCA assertions when either fork is empty; instead assert that both
reorg_event.old_fork and reorg_event.new_fork are non-empty up front (e.g.,
assert!(!reorg_event.old_fork.is_empty(), ...) and
assert!(!reorg_event.new_fork.is_empty(), ...)) to fail the test immediately if
find_reorg_split contract is violated, then unwrap or call .first().unwrap() to
bind first_old/first_new and proceed with the existing fork_parent checks
(referencing reorg_event, old_fork, new_fork, fork_parent, and
find_reorg_split).

In `@crates/chain-tests/src/multi_node/mempool_tests.rs`:
- Around line 968-993: The test currently uses a defensive `if let
(Some(first_old), Some(first_new)) = (reorg_event.old_fork.first(),
reorg_event.new_fork.first())` which can silently skip LCA checks if either fork
is empty; instead, assert that both forks are non-empty up front (e.g.
assert!(!reorg_event.old_fork.is_empty()) and
assert!(!reorg_event.new_fork.is_empty())), then safely obtain
first_old/first_new (via unwrap() or by calling first() after the asserts) and
perform the existing assertions comparing reorg_event.fork_parent.block_hash and
height to first_old.header().previous_block_hash / first_old.header().height and
similarly for first_new; this ensures violations of the find_reorg_split
contract fail the test rather than being ignored.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8725ec61-663a-4b5e-aa05-0d535d2387ba

📥 Commits

Reviewing files that changed from the base of the PR and between 04bfa3f and 0327c37.

📒 Files selected for processing (4)
  • crates/actors/src/block_tree_service.rs
  • crates/chain-tests/src/multi_node/fork_recovery.rs
  • crates/chain-tests/src/multi_node/mempool_tests.rs
  • crates/domain/src/models/block_tree.rs

Comment thread crates/chain-tests/src/multi_node/fork_recovery.rs Outdated
Comment thread crates/chain-tests/src/multi_node/mempool_tests.rs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

@glottologist glottologist merged commit f1b3791 into master May 29, 2026
34 of 38 checks passed
@glottologist glottologist deleted the jason/remove_lca_indirection branch May 29, 2026 09:37
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.

2 participants