-
Notifications
You must be signed in to change notification settings - Fork 2.5k
blockchain, netsync: implement a complete headers-first download during ibd #2428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Roasbeef
merged 26 commits into
btcsuite:master
from
kcalvinalvin:2025-09-16-new-parallel-block-downloads
Mar 24, 2026
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
5f25cf0
blockchain: add bestHeader to BlockChain
kcalvinalvin b60c2c3
blockchain: add statusHeaderStored for blockNode status
kcalvinalvin 743d0a2
blockchain: add ErrKnownInvalidBlock error code
kcalvinalvin fd16786
blockchain: add maybeAcceptHeader
kcalvinalvin c1a4612
blockchain: add ProcessBlockHeader
kcalvinalvin f9645f0
blockchain: reuse existing header node in maybeAcceptBlock
kcalvinalvin 9e45f60
blockchain: don't flush blockNodes that we don't have the data for
kcalvinalvin e4b38e0
blockchain: change HaveBlock to also check for block data availability
kcalvinalvin eeb2d43
blockchain: add exports methods based on block header tip
kcalvinalvin b1aef3a
netsync: add checkHeadersList
kcalvinalvin ddf80b8
netsync: add fetchHigherPeers
kcalvinalvin 51576a4
netsync: add isInIBDMode
kcalvinalvin 2f2364d
netsync: add fetchHeaders
kcalvinalvin 26c2459
netsync: use ProcessBlockHeader in handleBlockHeader
kcalvinalvin 28b6690
blockchain: add BestChainHeaderForkHeight to return the fork point
kcalvinalvin dc90f8c
netsync: change fetchHeaderBlocks to be based on the processed block
kcalvinalvin 8588a25
netsync: require peer argument in fetchHeaderBlocks
kcalvinalvin 7179268
integration: add reorg regression test for fetchHeaderBlocks fork point
kcalvinalvin 46574cc
netsync: change startSync to be based off of processed headers
kcalvinalvin 9530eda
netsync: update handleBlockMsg
kcalvinalvin 5af7680
netsync: remove unused headerList and checkpoint code
kcalvinalvin 0b1c7b7
netsync: rename headersFirstMode to ibdMode
kcalvinalvin dc6e096
netsync: add TestSyncStateMachine for end-to-end IBD sync flow
kcalvinalvin ce09426
netsync: add TestStartSyncBlockFallback for block-only sync path
kcalvinalvin 570d3c8
netsync: add TestStallNoDisconnectAtSameHeight for stall handler
kcalvinalvin 2aae8a6
netsync: add TestStartSyncChainCurrent for chain-current noop path
kcalvinalvin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| // Copyright (c) 2013-2026 The btcsuite developers | ||
| // Use of this source code is governed by an ISC | ||
| // license that can be found in the LICENSE file. | ||
|
|
||
| package blockchain | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/btcsuite/btcd/blockchain/internal/testhelper" | ||
| "github.com/btcsuite/btcd/btcutil" | ||
| ) | ||
|
|
||
| // TestMaybeAcceptBlockReusesHeaderNode ensures that when a block header is | ||
| // processed first via ProcessBlockHeader and later the full block arrives via | ||
| // ProcessBlock, the existing blockNode pointer is reused rather than replaced. | ||
| // Replacing the pointer would orphan the entry held by bestHeader's chainView, | ||
| // causing bestHeader.Contains(index.LookupNode(hash)) to return false and | ||
| // breaking IsValidHeader and downstream netsync checks. | ||
| func TestMaybeAcceptBlockReusesHeaderNode(t *testing.T) { | ||
| chain, params, tearDown := utxoCacheTestChain( | ||
| "TestMaybeAcceptBlockReusesHeaderNode") | ||
| defer tearDown() | ||
|
|
||
| // Build a base chain of 3 blocks. | ||
| // | ||
| // genesis -> 1 -> 2 -> 3 | ||
| tip := btcutil.NewBlock(params.GenesisBlock) | ||
| _, _, err := addBlocks(3, chain, tip, []*testhelper.SpendableOut{}) | ||
| if err != nil { | ||
| t.Fatalf("failed to build base chain: %v", err) | ||
| } | ||
|
|
||
| // Create block 4 without processing it. | ||
| prevBlock, err := chain.BlockByHeight(3) | ||
| if err != nil { | ||
| t.Fatalf("failed to get block at height 3: %v", err) | ||
| } | ||
| block4, _, err := newBlock(chain, prevBlock, nil) | ||
| if err != nil { | ||
| t.Fatalf("failed to create block 4: %v", err) | ||
| } | ||
|
|
||
| // Process block 4's header first. | ||
| block4Hash := block4.Hash() | ||
| _, err = chain.ProcessBlockHeader( | ||
| &block4.MsgBlock().Header, BFNone, false) | ||
| if err != nil { | ||
| t.Fatalf("ProcessBlockHeader fail: %v", err) | ||
| } | ||
|
|
||
| // Capture the header-only node pointer from the index. | ||
| headerNode := chain.index.LookupNode(block4Hash) | ||
| if headerNode == nil { | ||
| t.Fatal("header node not found in block index") | ||
| } | ||
|
|
||
| // Now process the full block. | ||
| _, _, err = chain.ProcessBlock(block4, BFNone) | ||
| if err != nil { | ||
| t.Fatalf("ProcessBlock fail: %v", err) | ||
| } | ||
|
|
||
| // The index must still hold the same pointer that bestHeader has. | ||
| // Before the fix, maybeAcceptBlock would create a fresh node and | ||
| // overwrite the index entry, orphaning the pointer in bestHeader. | ||
| fullBlockNode := chain.index.LookupNode(block4Hash) | ||
| if fullBlockNode != headerNode { | ||
| t.Fatal("ProcessBlock replaced the header node pointer " + | ||
| "instead of reusing it") | ||
| } | ||
| if !chain.bestHeader.Contains(fullBlockNode) { | ||
| t.Fatal("node no longer in bestHeader after ProcessBlock") | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.