@@ -892,6 +892,38 @@ class PeerManagerImpl final : public PeerManager
892
892
*/
893
893
void FindNextBlocksToDownload (const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
894
894
895
+ /* * Request blocks for the background chainstate, if one is in use. */
896
+ void TryDownloadingHistoricalBlocks (const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, const CBlockIndex* from_tip, const CBlockIndex* target_block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
897
+
898
+ /* *
899
+ * \brief Find next blocks to download from a peer after a starting block.
900
+ *
901
+ * \param vBlocks Vector of blocks to download which will be appended to.
902
+ * \param peer Peer which blocks will be downloaded from.
903
+ * \param state Pointer to the state of the peer.
904
+ * \param pindexWalk Pointer to the starting block to add to vBlocks.
905
+ * \param count Maximum number of blocks to allow in vBlocks. No more
906
+ * blocks will be added if it reaches this size.
907
+ * \param nWindowEnd Maximum height of blocks to allow in vBlocks. No
908
+ * blocks will be added above this height.
909
+ * \param activeChain Optional pointer to a chain to compare against. If
910
+ * provided, any next blocks which are already contained
911
+ * in this chain will not be appended to vBlocks, but
912
+ * instead will be used to update the
913
+ * state->pindexLastCommonBlock pointer.
914
+ * \param nodeStaller Optional pointer to a NodeId variable that will receive
915
+ * the ID of another peer that might be causing this peer
916
+ * to stall. This is set to the ID of the peer which
917
+ * first requested the first in-flight block in the
918
+ * download window. It is only set if vBlocks is empty at
919
+ * the end of this function call and if increasing
920
+ * nWindowEnd by 1 would cause it to be non-empty (which
921
+ * indicates the download might be stalled because every
922
+ * block in the window is in flight and no other peer is
923
+ * trying to download the next block).
924
+ */
925
+ void FindNextBlocks (std::vector<const CBlockIndex*>& vBlocks, const Peer& peer, CNodeState *state, const CBlockIndex *pindexWalk, unsigned int count, int nWindowEnd, const CChain* activeChain=nullptr , NodeId* nodeStaller=nullptr ) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
926
+
895
927
/* Multimap used to preserve insertion order */
896
928
typedef std::multimap<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> BlockDownloadMap;
897
929
BlockDownloadMap mapBlocksInFlight GUARDED_BY (cs_main);
@@ -1312,6 +1344,7 @@ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash
1312
1344
}
1313
1345
}
1314
1346
1347
+ // Logic for calculating which blocks to download from a given peer, given our current tip.
1315
1348
void PeerManagerImpl::FindNextBlocksToDownload (const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)
1316
1349
{
1317
1350
if (count == 0 )
@@ -1341,12 +1374,47 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
1341
1374
if (state->pindexLastCommonBlock == state->pindexBestKnownBlock )
1342
1375
return ;
1343
1376
1344
- std::vector<const CBlockIndex*> vToFetch;
1345
1377
const CBlockIndex *pindexWalk = state->pindexLastCommonBlock ;
1346
1378
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
1347
1379
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
1348
1380
// download that next block if the window were 1 larger.
1349
1381
int nWindowEnd = state->pindexLastCommonBlock ->nHeight + BLOCK_DOWNLOAD_WINDOW;
1382
+
1383
+ FindNextBlocks (vBlocks, peer, state, pindexWalk, count, nWindowEnd, &m_chainman.ActiveChain (), &nodeStaller);
1384
+ }
1385
+
1386
+ void PeerManagerImpl::TryDownloadingHistoricalBlocks (const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, const CBlockIndex *from_tip, const CBlockIndex* target_block)
1387
+ {
1388
+ Assert (from_tip);
1389
+ Assert (target_block);
1390
+
1391
+ if (vBlocks.size () >= count) {
1392
+ return ;
1393
+ }
1394
+
1395
+ vBlocks.reserve (count);
1396
+ CNodeState *state = Assert (State (peer.m_id ));
1397
+
1398
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock ->GetAncestor (target_block->nHeight ) != target_block) {
1399
+ // This peer can't provide us the complete series of blocks leading up to the
1400
+ // assumeutxo snapshot base.
1401
+ //
1402
+ // Presumably this peer's chain has less work than our ActiveChain()'s tip, or else we
1403
+ // will eventually crash when we try to reorg to it. Let other logic
1404
+ // deal with whether we disconnect this peer.
1405
+ //
1406
+ // TODO at some point in the future, we might choose to request what blocks
1407
+ // this peer does have from the historical chain, despite it not having a
1408
+ // complete history beneath the snapshot base.
1409
+ return ;
1410
+ }
1411
+
1412
+ FindNextBlocks (vBlocks, peer, state, from_tip, count, std::min<int >(from_tip->nHeight + BLOCK_DOWNLOAD_WINDOW, target_block->nHeight ));
1413
+ }
1414
+
1415
+ void PeerManagerImpl::FindNextBlocks (std::vector<const CBlockIndex*>& vBlocks, const Peer& peer, CNodeState *state, const CBlockIndex *pindexWalk, unsigned int count, int nWindowEnd, const CChain* activeChain, NodeId* nodeStaller)
1416
+ {
1417
+ std::vector<const CBlockIndex*> vToFetch;
1350
1418
int nMaxHeight = std::min<int >(state->pindexBestKnownBlock ->nHeight , nWindowEnd + 1 );
1351
1419
NodeId waitingfor = -1 ;
1352
1420
while (pindexWalk->nHeight < nMaxHeight) {
@@ -1374,16 +1442,16 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
1374
1442
// We wouldn't download this block or its descendants from this peer.
1375
1443
return ;
1376
1444
}
1377
- if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman. ActiveChain (). Contains (pindex)) {
1378
- if (pindex->HaveTxsDownloaded ())
1445
+ if (pindex->nStatus & BLOCK_HAVE_DATA || (activeChain && activeChain-> Contains (pindex) )) {
1446
+ if (activeChain && pindex->HaveTxsDownloaded ())
1379
1447
state->pindexLastCommonBlock = pindex;
1380
1448
} else if (!IsBlockRequested (pindex->GetBlockHash ())) {
1381
1449
// The block is not already downloaded, and not yet in flight.
1382
1450
if (pindex->nHeight > nWindowEnd) {
1383
1451
// We reached the end of the window.
1384
1452
if (vBlocks.size () == 0 && waitingfor != peer.m_id ) {
1385
1453
// We aren't able to fetch anything, but we would be if the download window was one larger.
1386
- nodeStaller = waitingfor;
1454
+ if (nodeStaller) * nodeStaller = waitingfor;
1387
1455
}
1388
1456
return ;
1389
1457
}
@@ -5847,7 +5915,20 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
5847
5915
if (CanServeBlocks (*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer (*peer)) || !m_chainman.IsInitialBlockDownload ()) && state.vBlocksInFlight .size () < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
5848
5916
std::vector<const CBlockIndex*> vToDownload;
5849
5917
NodeId staller = -1 ;
5850
- FindNextBlocksToDownload (*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.vBlocksInFlight .size (), vToDownload, staller);
5918
+ auto get_inflight_budget = [&state]() {
5919
+ return std::max (0 , MAX_BLOCKS_IN_TRANSIT_PER_PEER - static_cast <int >(state.vBlocksInFlight .size ()));
5920
+ };
5921
+
5922
+ // If a snapshot chainstate is in use, we want to find its next blocks
5923
+ // before the background chainstate to prioritize getting to network tip.
5924
+ FindNextBlocksToDownload (*peer, get_inflight_budget (), vToDownload, staller);
5925
+ if (m_chainman.BackgroundSyncInProgress () && !IsLimitedPeer (*peer)) {
5926
+ TryDownloadingHistoricalBlocks (
5927
+ *peer,
5928
+ get_inflight_budget (),
5929
+ vToDownload, m_chainman.GetBackgroundSyncTip (),
5930
+ Assert (m_chainman.GetSnapshotBaseBlock ()));
5931
+ }
5851
5932
for (const CBlockIndex *pindex : vToDownload) {
5852
5933
uint32_t nFetchFlags = GetFetchFlags (*peer);
5853
5934
vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
0 commit comments