Skip to content

fix(core): clean up dangling/orphan blocks on SetHead#2442

Open
gzliudan wants to merge 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:fix-set-head
Open

fix(core): clean up dangling/orphan blocks on SetHead#2442
gzliudan wants to merge 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:fix-set-head

Conversation

@gzliudan

@gzliudan gzliudan commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Proposed changes

SetHead rewinds the chain to a lower block height. Without comprehensive cleanup,
the downloader can jump to stale blocks instead of resyncing intermediate ranges.

SetHead previously only deleted the canonical chain segment, leaving orphaned/fork
blocks intact. The downloader's HasBlock() check would hit these orphaned entries,
incorrectly reporting ancestors found, skipping intermediate resync.

Root cause: Original implementation used a contiguous upward scan (checking
head+1, head+2, ...) that stopped at the first height with no header, leaving
orphaned segments above gaps intact.

Solution: Replace contiguous scan with ReadAllDanglingHashes(), which walks
the header keyspace directly via iterator and returns ALL headers above head
regardless of gaps. SetHead now performs post-loop sweep deleting all header/td/
body/receipt/canonical data above the new head.

For bad blocks: Only delete records strictly above the new head, preserving
debugging data for blocks at/below head for operator review (respects
DeleteAllBadBlocks config).

Optimization: Use two-phase batch commits to avoid duplicate deletes.

Changes:

  • Add ReadAllDanglingHashes() for iterator-based orphan detection
  • Add DeleteBadBlocksAbove() for selective bad block cleanup
  • Refactor SetHead() with two-phase batch writes and iterator-based sweep
  • Add TestSetHeadCleansDanglingBlocksAcrossGap for gap-handling validation
  • Add TestSetHeadCleansOnlyBadBlocksAboveHead for bad block preservation

Verification: 5/5 unit tests pass, remote testnet verified

Types of changes

What types of changes does your code introduce to XDC network?
Put an in the boxes that apply

  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Changes that don't change source code or tests
  • docs: Documentation only changes
  • feat: A new feature
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that neither fixes a bug nor adds a feature
  • revert: Revert something
  • style: Changes that do not affect the meaning of the code
  • test: Adding missing tests or correcting existing tests

Impacted Components

Which parts of the codebase does this PR touch?
Put an in the boxes that apply

  • Consensus
  • Account
  • Network
  • Geth
  • Smart Contract
  • External components
  • Not sure (Please specify below)

Checklist

Put an in the boxes once you have confirmed below actions (or provide reasons on not doing so) that

  • This PR has sufficient test coverage (unit/integration test) OR I have provided reason in the PR description for not having test coverage
  • Tested on a private network from the genesis block and monitored the chain operating correctly for multiple epochs.
  • Provide an end-to-end test plan in the PR description on how to manually test it on the devnet/testnet.
  • Tested the backwards compatibility.
  • Tested with XDC nodes running this version co-exist with those running the previous version.
  • Relevant documentation has been updated as part of this PR
  • N/A

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 505f306a-dc0c-4f0e-b838-3374e03f8e28

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR ports upstream geth HeaderChain.SetHead cleanup behavior into XDPoSChain to ensure rewinds fully delete orphan/dangling block data above the rollback target, preventing stale hash-keyed block data from misleading the downloader’s ancestor search after restarts.

Changes:

  • Add rawdb.ReadAllHashes to enumerate all block hashes stored at a given height.
  • Extend core/HeaderChain.SetHead to also delete data for all hashes at each rewound height and to additionally wipe “leftover” heights above the current head on the first iteration.
  • Add core/blockchain_sethead_test.go to verify dangling blocks above head are fully wiped by SetHead.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
core/rawdb/accessors_chain.go Adds ReadAllHashes helper to enumerate hashes stored at a specific block height.
core/headerchain.go Updates HeaderChain.SetHead to remove side-fork/orphan data and leftover heights above head during rewinds.
core/blockchain_sethead_test.go Adds regression test ensuring dangling block data above head is removed after SetHead.

Comment thread core/headerchain.go Outdated
Comment thread core/headerchain.go Outdated
Comment thread core/rawdb/accessors_chain.go
Comment thread core/rawdb/accessors_chain.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread core/headerchain.go Outdated
@gzliudan gzliudan force-pushed the fix-set-head branch 3 times, most recently from 2d3c33e to c14dd35 Compare July 7, 2026 06:31
@gzliudan gzliudan changed the title fix(core): wipe dangling/orphan blocks above head on SetHead fix(core): clean up dangling/orphan/bad blocks on SetHead Jul 7, 2026
@gzliudan gzliudan requested a review from Copilot July 7, 2026 08:01
@gzliudan gzliudan changed the title fix(core): clean up dangling/orphan/bad blocks on SetHead fix(core): wipe orphaned blocks above head across gaps on SetHead Jul 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread core/headerchain.go
Comment thread core/headerchain.go Outdated
@gzliudan gzliudan changed the title fix(core): wipe orphaned blocks above head across gaps on SetHead fix(core): clean up dangling/orphan blocks on SetHead Jul 7, 2026
@gzliudan gzliudan requested a review from Copilot July 7, 2026 08:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread core/rawdb/accessors_chain.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread core/headerchain.go
SetHead rewinds the chain to a lower block height. Without comprehensive cleanup,
the downloader can jump to stale blocks instead of resyncing intermediate ranges.

SetHead previously only deleted the canonical chain segment, leaving orphaned/fork
blocks intact. The downloader's HasBlock() check would hit these orphaned entries,
incorrectly reporting ancestors found, skipping intermediate resync.

Root cause: Original implementation used a contiguous upward scan (checking
head+1, head+2, ...) that stopped at the first height with no header, leaving
orphaned segments above gaps intact. Real-world data showed orphaned fork
segments can sit ABOVE gaps (e.g., head at 83,531,000 with no markers at
83,531,501–83,532,999 but orphaned data at 83,533,000–83,599,999).

Solution: Replace contiguous scan with ReadAllDanglingHashes(), which walks
the header keyspace directly via iterator and returns ALL headers above head
regardless of gaps. SetHead now performs post-loop sweep deleting all header/td/
body/receipt/canonical data above the new head.

For bad blocks: Only delete records strictly above the new head, preserving
debugging data for blocks at/below head for operator review (respects
DeleteAllBadBlocks config).

Optimization: Use two-phase batch commits to avoid duplicate deletes. Flush
rewind deletions to database before scanning for dangling data, preventing
ReadAllDanglingHashes from re-observing already-deleted segments.

Changes:
- Add ReadAllDanglingHashes(db, head) for iterator-based orphan detection
- Add DeleteBadBlocksAbove(db, head) for selective bad block cleanup
- Refactor SetHead() with two-phase batch writes and iterator-based sweep
- Add TestSetHeadCleansDanglingBlocksAcrossGap for gap-handling validation
- Add TestSetHeadCleansOnlyBadBlocksAboveHead for bad block preservation

Verification:
- 5/5 SetHead unit tests pass
- Remote testnet: rollback 83,531,500→83,531,000 cleaned 69,000 heights,
  sequential block import without bad block jumps
- Full core test suite passes
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