@@ -569,6 +569,8 @@ class PeerManagerImpl final : public PeerManager
569
569
bool CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers) const ;
570
570
/* * Request further headers from this peer from a given block header */
571
571
void FetchMoreHeaders (CNode& pfrom, const CBlockIndex *pindexLast, const Peer& peer);
572
+ /* * Potentially fetch blocks from this peer upon receipt of new headers tip */
573
+ void HeadersDirectFetchBlocks (CNode& pfrom, const CBlockIndex* pindexLast);
572
574
573
575
void SendBlockTransactions (CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
574
576
@@ -2276,6 +2278,73 @@ void PeerManagerImpl::FetchMoreHeaders(CNode& pfrom, const CBlockIndex *pindexLa
2276
2278
m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::GETHEADERS, m_chainman.ActiveChain ().GetLocator (pindexLast), uint256 ()));
2277
2279
}
2278
2280
2281
+ /*
2282
+ * Given a new headers tip ending in pindexLast, potentially request blocks towards that tip.
2283
+ * We require that the given tip have at least as much work as our tip, and for
2284
+ * our current tip to be "close to synced" (see CanDirectFetch()).
2285
+ */
2286
+ void PeerManagerImpl::HeadersDirectFetchBlocks (CNode& pfrom, const CBlockIndex* pindexLast)
2287
+ {
2288
+ const CNetMsgMaker msgMaker (pfrom.GetCommonVersion ());
2289
+
2290
+ LOCK (cs_main);
2291
+ CNodeState *nodestate = State (pfrom.GetId ());
2292
+
2293
+ if (CanDirectFetch () && pindexLast->IsValid (BLOCK_VALID_TREE) && m_chainman.ActiveChain ().Tip ()->nChainWork <= pindexLast->nChainWork ) {
2294
+
2295
+ std::vector<const CBlockIndex*> vToFetch;
2296
+ const CBlockIndex *pindexWalk = pindexLast;
2297
+ // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
2298
+ while (pindexWalk && !m_chainman.ActiveChain ().Contains (pindexWalk) && vToFetch.size () <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2299
+ if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2300
+ !IsBlockRequested (pindexWalk->GetBlockHash ()) &&
2301
+ (!DeploymentActiveAt (*pindexWalk, m_chainman, Consensus::DEPLOYMENT_SEGWIT) || State (pfrom.GetId ())->fHaveWitness )) {
2302
+ // We don't have this block, and it's not yet in flight.
2303
+ vToFetch.push_back (pindexWalk);
2304
+ }
2305
+ pindexWalk = pindexWalk->pprev ;
2306
+ }
2307
+ // If pindexWalk still isn't on our main chain, we're looking at a
2308
+ // very large reorg at a time we think we're close to caught up to
2309
+ // the main chain -- this shouldn't really happen. Bail out on the
2310
+ // direct fetch and rely on parallel download instead.
2311
+ if (!m_chainman.ActiveChain ().Contains (pindexWalk)) {
2312
+ LogPrint (BCLog::NET, " Large reorg, won't direct fetch to %s (%d)\n " ,
2313
+ pindexLast->GetBlockHash ().ToString (),
2314
+ pindexLast->nHeight );
2315
+ } else {
2316
+ std::vector<CInv> vGetData;
2317
+ // Download as much as possible, from earliest to latest.
2318
+ for (const CBlockIndex *pindex : reverse_iterate (vToFetch)) {
2319
+ if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2320
+ // Can't download any more from this peer
2321
+ break ;
2322
+ }
2323
+ uint32_t nFetchFlags = GetFetchFlags (pfrom);
2324
+ vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
2325
+ BlockRequested (pfrom.GetId (), *pindex);
2326
+ LogPrint (BCLog::NET, " Requesting block %s from peer=%d\n " ,
2327
+ pindex->GetBlockHash ().ToString (), pfrom.GetId ());
2328
+ }
2329
+ if (vGetData.size () > 1 ) {
2330
+ LogPrint (BCLog::NET, " Downloading blocks toward %s (%d) via headers direct fetch\n " ,
2331
+ pindexLast->GetBlockHash ().ToString (), pindexLast->nHeight );
2332
+ }
2333
+ if (vGetData.size () > 0 ) {
2334
+ if (!m_ignore_incoming_txs &&
2335
+ nodestate->m_provides_cmpctblocks &&
2336
+ vGetData.size () == 1 &&
2337
+ mapBlocksInFlight.size () == 1 &&
2338
+ pindexLast->pprev ->IsValid (BLOCK_VALID_CHAIN)) {
2339
+ // In any case, we want to download using a compact block, not a regular one
2340
+ vGetData[0 ] = CInv (MSG_CMPCT_BLOCK, vGetData[0 ].hash );
2341
+ }
2342
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::GETDATA, vGetData));
2343
+ }
2344
+ }
2345
+ }
2346
+ }
2347
+
2279
2348
void PeerManagerImpl::ProcessHeadersMessage (CNode& pfrom, Peer& peer,
2280
2349
const std::vector<CBlockHeader>& headers,
2281
2350
bool via_compact_block)
@@ -2355,60 +2424,9 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
2355
2424
nodestate->m_last_block_announcement = GetTime ();
2356
2425
}
2357
2426
2358
- // If this set of headers is valid and ends in a block with at least as
2359
- // much work as our tip, download as much as possible.
2360
- if (CanDirectFetch () && pindexLast->IsValid (BLOCK_VALID_TREE) && m_chainman.ActiveChain ().Tip ()->nChainWork <= pindexLast->nChainWork ) {
2361
- std::vector<const CBlockIndex*> vToFetch;
2362
- const CBlockIndex *pindexWalk = pindexLast;
2363
- // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
2364
- while (pindexWalk && !m_chainman.ActiveChain ().Contains (pindexWalk) && vToFetch.size () <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2365
- if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2366
- !IsBlockRequested (pindexWalk->GetBlockHash ()) &&
2367
- (!DeploymentActiveAt (*pindexWalk, m_chainman, Consensus::DEPLOYMENT_SEGWIT) || State (pfrom.GetId ())->fHaveWitness )) {
2368
- // We don't have this block, and it's not yet in flight.
2369
- vToFetch.push_back (pindexWalk);
2370
- }
2371
- pindexWalk = pindexWalk->pprev ;
2372
- }
2373
- // If pindexWalk still isn't on our main chain, we're looking at a
2374
- // very large reorg at a time we think we're close to caught up to
2375
- // the main chain -- this shouldn't really happen. Bail out on the
2376
- // direct fetch and rely on parallel download instead.
2377
- if (!m_chainman.ActiveChain ().Contains (pindexWalk)) {
2378
- LogPrint (BCLog::NET, " Large reorg, won't direct fetch to %s (%d)\n " ,
2379
- pindexLast->GetBlockHash ().ToString (),
2380
- pindexLast->nHeight );
2381
- } else {
2382
- std::vector<CInv> vGetData;
2383
- // Download as much as possible, from earliest to latest.
2384
- for (const CBlockIndex *pindex : reverse_iterate (vToFetch)) {
2385
- if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2386
- // Can't download any more from this peer
2387
- break ;
2388
- }
2389
- uint32_t nFetchFlags = GetFetchFlags (pfrom);
2390
- vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
2391
- BlockRequested (pfrom.GetId (), *pindex);
2392
- LogPrint (BCLog::NET, " Requesting block %s from peer=%d\n " ,
2393
- pindex->GetBlockHash ().ToString (), pfrom.GetId ());
2394
- }
2395
- if (vGetData.size () > 1 ) {
2396
- LogPrint (BCLog::NET, " Downloading blocks toward %s (%d) via headers direct fetch\n " ,
2397
- pindexLast->GetBlockHash ().ToString (), pindexLast->nHeight );
2398
- }
2399
- if (vGetData.size () > 0 ) {
2400
- if (!m_ignore_incoming_txs &&
2401
- nodestate->m_provides_cmpctblocks &&
2402
- vGetData.size () == 1 &&
2403
- mapBlocksInFlight.size () == 1 &&
2404
- pindexLast->pprev ->IsValid (BLOCK_VALID_CHAIN)) {
2405
- // In any case, we want to download using a compact block, not a regular one
2406
- vGetData[0 ] = CInv (MSG_CMPCT_BLOCK, vGetData[0 ].hash );
2407
- }
2408
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::GETDATA, vGetData));
2409
- }
2410
- }
2411
- }
2427
+ // Consider immediately downloading blocks.
2428
+ HeadersDirectFetchBlocks (pfrom, pindexLast);
2429
+
2412
2430
// If we're in IBD, we want outbound peers that will serve us a useful
2413
2431
// chain. Disconnect peers that are on chains with insufficient work.
2414
2432
if (m_chainman.ActiveChainstate ().IsInitialBlockDownload () && nCount != MAX_HEADERS_RESULTS) {
0 commit comments