@@ -2421,55 +2421,77 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
2421
2421
}
2422
2422
}
2423
2423
2424
- LOCK (cs_main);
2425
- const CBlockIndex* pindex = m_chainman.m_blockman .LookupBlockIndex (inv.hash );
2426
- if (!pindex) {
2427
- return ;
2428
- }
2429
- if (!BlockRequestAllowed (pindex)) {
2430
- LogPrint (BCLog::NET, " %s: ignoring request from peer=%i for old block that isn't in the main chain\n " , __func__, pfrom.GetId ());
2431
- return ;
2432
- }
2433
- // disconnect node in case we have reached the outbound limit for serving historical blocks
2434
- if (m_connman.OutboundTargetReached (true ) &&
2435
- (((m_chainman.m_best_header != nullptr ) && (m_chainman.m_best_header ->GetBlockTime () - pindex->GetBlockTime () > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk ()) &&
2436
- !pfrom.HasPermission (NetPermissionFlags::Download) // nodes with the download permission may exceed target
2437
- ) {
2438
- LogPrint (BCLog::NET, " historical block serving limit reached, disconnect peer=%d\n " , pfrom.GetId ());
2439
- pfrom.fDisconnect = true ;
2440
- return ;
2441
- }
2442
- // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
2443
- if (!pfrom.HasPermission (NetPermissionFlags::NoBan) && (
2444
- (((peer.m_our_services & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((peer.m_our_services & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain ().Tip ()->nHeight - pindex->nHeight > (int )NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */ ) )
2445
- )) {
2446
- LogPrint (BCLog::NET, " Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n " , pfrom.GetId ());
2447
- // disconnect node and prevent it from stalling (would otherwise wait for the missing block)
2448
- pfrom.fDisconnect = true ;
2449
- return ;
2450
- }
2451
- // Pruned nodes may have deleted the block, so check whether
2452
- // it's available before trying to send.
2453
- if (!(pindex->nStatus & BLOCK_HAVE_DATA)) {
2454
- return ;
2424
+ const CBlockIndex* pindex{nullptr };
2425
+ const CBlockIndex* tip{nullptr };
2426
+ bool can_direct_fetch{false };
2427
+ FlatFilePos block_pos{};
2428
+ {
2429
+ LOCK (cs_main);
2430
+ pindex = m_chainman.m_blockman .LookupBlockIndex (inv.hash );
2431
+ if (!pindex) {
2432
+ return ;
2433
+ }
2434
+ if (!BlockRequestAllowed (pindex)) {
2435
+ LogPrint (BCLog::NET, " %s: ignoring request from peer=%i for old block that isn't in the main chain\n " , __func__, pfrom.GetId ());
2436
+ return ;
2437
+ }
2438
+ // disconnect node in case we have reached the outbound limit for serving historical blocks
2439
+ if (m_connman.OutboundTargetReached (true ) &&
2440
+ (((m_chainman.m_best_header != nullptr ) && (m_chainman.m_best_header ->GetBlockTime () - pindex->GetBlockTime () > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk ()) &&
2441
+ !pfrom.HasPermission (NetPermissionFlags::Download) // nodes with the download permission may exceed target
2442
+ ) {
2443
+ LogPrint (BCLog::NET, " historical block serving limit reached, disconnect peer=%d\n " , pfrom.GetId ());
2444
+ pfrom.fDisconnect = true ;
2445
+ return ;
2446
+ }
2447
+ tip = m_chainman.ActiveChain ().Tip ();
2448
+ // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
2449
+ if (!pfrom.HasPermission (NetPermissionFlags::NoBan) && (
2450
+ (((peer.m_our_services & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((peer.m_our_services & NODE_NETWORK) != NODE_NETWORK) && (tip->nHeight - pindex->nHeight > (int )NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */ ) )
2451
+ )) {
2452
+ LogPrint (BCLog::NET, " Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n " , pfrom.GetId ());
2453
+ // disconnect node and prevent it from stalling (would otherwise wait for the missing block)
2454
+ pfrom.fDisconnect = true ;
2455
+ return ;
2456
+ }
2457
+ // Pruned nodes may have deleted the block, so check whether
2458
+ // it's available before trying to send.
2459
+ if (!(pindex->nStatus & BLOCK_HAVE_DATA)) {
2460
+ return ;
2461
+ }
2462
+ can_direct_fetch = CanDirectFetch ();
2463
+ block_pos = pindex->GetBlockPos ();
2455
2464
}
2465
+
2456
2466
std::shared_ptr<const CBlock> pblock;
2457
2467
if (a_recent_block && a_recent_block->GetHash () == pindex->GetBlockHash ()) {
2458
2468
pblock = a_recent_block;
2459
2469
} else if (inv.IsMsgWitnessBlk ()) {
2460
2470
// Fast-path: in this case it is possible to serve the block directly from disk,
2461
2471
// as the network format matches the format on disk
2462
2472
std::vector<uint8_t > block_data;
2463
- if (!m_chainman.m_blockman .ReadRawBlockFromDisk (block_data, pindex->GetBlockPos ())) {
2464
- assert (!" cannot load block from disk" );
2473
+ if (!m_chainman.m_blockman .ReadRawBlockFromDisk (block_data, block_pos)) {
2474
+ if (WITH_LOCK (m_chainman.GetMutex (), return m_chainman.m_blockman .IsBlockPruned (*pindex))) {
2475
+ LogPrint (BCLog::NET, " Block was pruned before it could be read, disconnect peer=%s\n " , pfrom.GetId ());
2476
+ } else {
2477
+ LogError (" Cannot load block from disk, disconnect peer=%d\n " , pfrom.GetId ());
2478
+ }
2479
+ pfrom.fDisconnect = true ;
2480
+ return ;
2465
2481
}
2466
2482
MakeAndPushMessage (pfrom, NetMsgType::BLOCK, Span{block_data});
2467
2483
// Don't set pblock as we've sent the block
2468
2484
} else {
2469
2485
// Send block from disk
2470
2486
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
2471
- if (!m_chainman.m_blockman .ReadBlockFromDisk (*pblockRead, *pindex)) {
2472
- assert (!" cannot load block from disk" );
2487
+ if (!m_chainman.m_blockman .ReadBlockFromDisk (*pblockRead, block_pos)) {
2488
+ if (WITH_LOCK (m_chainman.GetMutex (), return m_chainman.m_blockman .IsBlockPruned (*pindex))) {
2489
+ LogPrint (BCLog::NET, " Block was pruned before it could be read, disconnect peer=%s\n " , pfrom.GetId ());
2490
+ } else {
2491
+ LogError (" Cannot load block from disk, disconnect peer=%d\n " , pfrom.GetId ());
2492
+ }
2493
+ pfrom.fDisconnect = true ;
2494
+ return ;
2473
2495
}
2474
2496
pblock = pblockRead;
2475
2497
}
@@ -2507,7 +2529,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
2507
2529
// they won't have a useful mempool to match against a compact block,
2508
2530
// and we don't feel like constructing the object for them, so
2509
2531
// instead we respond with the full, non-compact block.
2510
- if (CanDirectFetch () && pindex->nHeight >= m_chainman. ActiveChain (). Height () - MAX_CMPCTBLOCK_DEPTH) {
2532
+ if (can_direct_fetch && pindex->nHeight >= tip-> nHeight - MAX_CMPCTBLOCK_DEPTH) {
2511
2533
if (a_recent_compact_block && a_recent_compact_block->header .GetHash () == pindex->GetBlockHash ()) {
2512
2534
MakeAndPushMessage (pfrom, NetMsgType::CMPCTBLOCK, *a_recent_compact_block);
2513
2535
} else {
@@ -2528,7 +2550,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
2528
2550
// and we want it right after the last block so they don't
2529
2551
// wait for other stuff first.
2530
2552
std::vector<CInv> vInv;
2531
- vInv.emplace_back (MSG_BLOCK, m_chainman. ActiveChain (). Tip () ->GetBlockHash ());
2553
+ vInv.emplace_back (MSG_BLOCK, tip ->GetBlockHash ());
2532
2554
MakeAndPushMessage (pfrom, NetMsgType::INV, vInv);
2533
2555
peer.m_continuation_block .SetNull ();
2534
2556
}
0 commit comments