From ce094262ff24ba172ad18a83a0b7dcc7adc6b0de Mon Sep 17 00:00:00 2001 From: Calvin Kim Date: Thu, 26 Feb 2026 22:05:57 +0900 Subject: [PATCH] netsync: add TestStartSyncBlockFallback for block-only sync path Verify that startSync skips header download and directly requests blocks when the header chain is already caught up to the peer's height but the block chain lags behind. --- netsync/manager_test.go | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/netsync/manager_test.go b/netsync/manager_test.go index 0b900b96..bafeb9ba 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") +}