netsync: add TestStartSyncBlockFallback for block-only sync path
What changed, and why it matters
This commit only adds a new unit test to the Bitcoin-related btcd project. It checks that when the header chain is already up-to-date but the actual block chain is behind, the sync manager skips downloading headers and directly requests blocks. There is no change to production code, no bug fix, and no security-relevant behavior change.
No action needed; this is a test-only addition with no security implications.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff adds TestStartSyncBlockFallback in netsync/manager_test.go. The test constructs a SyncManager whose header chain is advanced to 11 blocks while the block chain remains at genesis, then adds a peer at the same height and calls startSync(). It asserts that a sync peer is selected and blocks are requested. No production logic is modified.
Changed components
netsync/manager_test.goInspect captured patch +42 / −0
diff --git a/netsync/manager_test.go b/netsync/manager_test.go
index 0b900b9..bafeb9b 100644
--- a/netsync/manager_test.go
+++ b/netsync/manager_test.go
@@ -1099,3 +1099,45 @@ func syncStalledHeaderRecovery(t *testing.T, sm *SyncManager,
replacementState := sm.peerStates[replacementPeer]
require.Equal(t, wantRequested, replacementState.requestedBlocks)
}
+
+// TestStartSyncBlockFallback verifies the startSync fallback path where
+// headers are already caught up but the block chain lags behind. In this
+// case startSync should skip header download and directly request blocks.
+func TestStartSyncBlockFallback(t *testing.T) {
+ t.Parallel()
+
+ params := chaincfg.RegressionNetParams
+ params.Checkpoints = nil
+
+ sm, tearDown := makeMockSyncManager(t, ¶ms)
+ defer tearDown()
+
+ // Process headers so the header chain is at numBlocks while the
+ // block chain stays at genesis.
+ const numBlocks = 11
+ blocks := generateTestBlocks(t, ¶ms, numBlocks)
+ for _, block := range blocks {
+ _, err := sm.chain.ProcessBlockHeader(
+ &block.MsgBlock().Header, blockchain.BFNone, false)
+ require.NoError(t, err)
+ }
+
+ // Add a peer whose height equals the header height.
+ // fetchHigherPeers(bestHeaderHeight) returns nothing because
+ // the peer is not strictly higher than our headers.
+ // fetchHigherPeers(bestBlockHeight=0) returns the peer.
+ syncPeer := peer.NewInboundPeer(&peer.Config{})
+ syncPeer.UpdateLastBlockHeight(int32(numBlocks))
+ sm.peerStates[syncPeer] = &peerSyncState{
+ syncCandidate: true,
+ requestedTxns: make(map[chainhash.Hash]struct{}),
+ requestedBlocks: make(map[chainhash.Hash]struct{}),
+ }
+
+ sm.startSync()
+
+ require.NotNil(t, sm.syncPeer,
+ "sync peer should be set for block download")
+ require.NotEmpty(t, sm.requestedBlocks,
+ "blocks should be requested via fetchHeaderBlocks")
+}
Why this scored 14/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.