Skip to content

fix(core): report a missing total difficulty instead of dereferencing nil - #2569

Open
gzliudan wants to merge 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:fix-missing-total-difficulty
Open

gzliudan wants to merge 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:fix-missing-total-difficulty

Conversation

@gzliudan

@gzliudan gzliudan commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

BlockChain.GetTd answers nil when the database has no total difficulty entry for the block, and three comparisons built on that value dereferenced it:

  • the parent's difficulty in the insertSidechain scan (core/blockchain.go:2081-2083 on dev-upgrade)
  • the head's difficulty right after that scan (:2102-2103)
  • both of them in getResultBlock (:2232-2233), the competing-block path

A node whose database is missing one of those entries crashed with a nil pointer dereference instead of reporting anything, on a path that runs for every sidechain import and every competing block. All three now log a warning and report errMissingTotalDifficulty instead.

Why a new error value, and what it does not do

errMissingTotalDifficulty is unexported and names what this node cannot do rather than blaming the block. Classifying it as a local condition - one the downloader cancels the content processing for instead of dropping the peer - belongs to #2566, which introduces core.IsLocalInsertError; once that lands, one line adds this error to the whitelist. Until then the failure surfaces the way any other unclassified InsertChain error does, but the node no longer crashes.

Tests

core/blockchain_test.go:

  • TestInsertSidechainReportsMissingParentTd - the segment's parent has no total difficulty on disk
  • TestInsertSidechainReportsMissingLocalTd - the segment carries one, the head's cannot be read
  • TestGetResultBlockReportsMissingTd - the competitor's parent total difficulty is unreadable

All three fail with runtime error: invalid memory address or nil pointer dereference when the guards are removed, and pass with them.

They are adapted to the dev-upgrade shape of the code under test: insertSidechain takes two parameters and the scan is driven through newInsertIterator with a synthetic result channel, and TestInsertSidechainReportsMissingLocalTd stores its side block with writeBlockWithoutState instead of re-importing a canonical block - the canonical re-import shape depends on the ghost-state false positive that only #2566 fixes.

@coderabbitai

coderabbitai Bot commented Sep 14, 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: Advanced

Run ID: 91342ac7-4878-4dc4-9cd4-2452b59c05d9

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

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.

🟡 Changes recommended

Stateful fork insertion retains an unguarded canonical-head TD dereference.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Prevents nil dereferences when total difficulty data is missing during sidechain and competing-block processing.

Changes:

  • Adds errMissingTotalDifficulty and guards three TD comparisons.
  • Adds regression tests for missing parent and local TD data.
File summaries
File Description
core/blockchain.go Reports missing TD instead of dereferencing nil.
core/blockchain_test.go Tests missing-TD insertion paths.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread core/blockchain.go
@gzliudan
gzliudan force-pushed the fix-missing-total-difficulty branch 4 times, most recently from c135070 to b68ec05 Compare September 15, 2026 04:34
… nil

The total difficulty the chain weighs a block against comes out of the database,
and GetTd answers nil when there is no entry for the block. Comparisons were
built on that value without a nil check - the parent's difficulty in the
insertSidechain scan, the head's difficulty right after that scan, the head's
difficulty in writeBlockWithState, the path every stateful block import goes
through, and the two in getResultBlock - so a node whose database is missing one
of those entries crashed on a nil pointer dereference instead of reporting
anything, on paths that run for every sidechain import, every imported block and
every competing block. The stateful path is the easiest to reach: a recently
executed side-fork block keeps its parent's difficulty readable, so importing its
child needs only the head's entry to be gone.

Report errMissingTotalDifficulty instead. The blocks themselves say nothing about
a number this node cannot read, so the error names what this node cannot do
instead of blaming them. On the stateful path the guard sits before the block and
its state are written, since without the head's number there is no way to tell
canonical from side. Classifying it as a local condition - one the downloader
cancels the content processing for rather than dropping the peer - belongs to the
change that introduces the local-insert sentinels.

Each site is covered by a regression test that drops the entry from both the
database and the read cache: the sidechain scan's parent and head, the stateful
insertion of a child of a side-fork block, and the competing-block lookup.
@gzliudan
gzliudan force-pushed the fix-missing-total-difficulty branch from b68ec05 to 1039647 Compare September 15, 2026 07:38
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.

3 participants