@@ -159,10 +159,10 @@ static constexpr size_t MAX_ADDR_TO_SEND{1000};
159
159
namespace {
160
160
/* * Blocks that are in flight, and that are in the queue to be downloaded. */
161
161
struct QueuedBlock {
162
- uint256 hash;
163
- const CBlockIndex* pindex; // !< Optional.
164
- bool fValidatedHeaders ; // !< Whether this block has validated headers at the time of request.
165
- std::unique_ptr<PartiallyDownloadedBlock> partialBlock; // !< Optional, used for CMPCTBLOCK downloads
162
+ /* * BlockIndex. We must have this since we only request blocks when we've already validated the header. */
163
+ const CBlockIndex* pindex;
164
+ /* * Optional, used for CMPCTBLOCK downloads */
165
+ std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
166
166
};
167
167
168
168
/* *
@@ -463,16 +463,20 @@ class PeerManagerImpl final : public PeerManager
463
463
Mutex m_recent_confirmed_transactions_mutex;
464
464
std::unique_ptr<CRollingBloomFilter> m_recent_confirmed_transactions GUARDED_BY (m_recent_confirmed_transactions_mutex);
465
465
466
- /* Returns a bool indicating whether we requested this block.
467
- * Also used if a block was /not/ received and timed out or started with another peer
466
+ /* * Have we requested this block from a peer */
467
+ bool IsBlockRequested (const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
468
+
469
+ /* * Remove this block from our tracked requested blocks. Called if:
470
+ * - the block has been recieved from a peer
471
+ * - the request for the block has timed out
468
472
*/
469
- bool MarkBlockAsReceived (const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
473
+ void RemoveBlockRequest (const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
470
474
471
475
/* Mark a block as in flight
472
476
* Returns false, still setting pit, if the block was already in flight from the same peer
473
477
* pit will only be valid as long as the same cs_main lock is being held
474
478
*/
475
- bool MarkBlockAsInFlight (NodeId nodeid, const uint256& hash, const CBlockIndex* pindex = nullptr , std::list<QueuedBlock>::iterator** pit = nullptr ) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
479
+ bool BlockRequested (NodeId nodeid, const CBlockIndex* pindex, std::list<QueuedBlock>::iterator** pit = nullptr ) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
476
480
477
481
bool TipMayBeStale () EXCLUSIVE_LOCKS_REQUIRED(cs_main);
478
482
@@ -512,7 +516,7 @@ class PeerManagerImpl final : public PeerManager
512
516
std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY (cs_main);
513
517
514
518
/* * Number of peers from which we're downloading blocks. */
515
- int nPeersWithValidatedDownloads GUARDED_BY (cs_main) = 0;
519
+ int m_peers_downloading_from GUARDED_BY (cs_main) = 0;
516
520
517
521
/* * Storage for orphan information */
518
522
TxOrphanage m_orphanage;
@@ -627,7 +631,6 @@ struct CNodeState {
627
631
// ! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
628
632
std::chrono::microseconds m_downloading_since{0us};
629
633
int nBlocksInFlight{0 };
630
- int nBlocksInFlightValidHeaders{0 };
631
634
// ! Whether we consider this a preferred download peer.
632
635
bool fPreferredDownload {false };
633
636
// ! Whether this peer wants invs or headers (when possible) for block announcements.
@@ -758,32 +761,43 @@ static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUS
758
761
nPreferredDownload += state->fPreferredDownload ;
759
762
}
760
763
761
- bool PeerManagerImpl::MarkBlockAsReceived (const uint256& hash)
764
+ bool PeerManagerImpl::IsBlockRequested (const uint256& hash)
762
765
{
763
- std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find (hash);
764
- if (itInFlight != mapBlocksInFlight.end ()) {
765
- CNodeState *state = State (itInFlight->second .first );
766
- assert (state != nullptr );
767
- state->nBlocksInFlightValidHeaders -= itInFlight->second .second ->fValidatedHeaders ;
768
- if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second .second ->fValidatedHeaders ) {
769
- // Last validated block on the queue was received.
770
- nPeersWithValidatedDownloads--;
771
- }
772
- if (state->vBlocksInFlight .begin () == itInFlight->second .second ) {
773
- // First block on the queue was received, update the start download time for the next one
774
- state->m_downloading_since = std::max (state->m_downloading_since , GetTime<std::chrono::microseconds>());
775
- }
776
- state->vBlocksInFlight .erase (itInFlight->second .second );
777
- state->nBlocksInFlight --;
778
- state->m_stalling_since = 0us;
779
- mapBlocksInFlight.erase (itInFlight);
780
- return true ;
766
+ return mapBlocksInFlight.find (hash) != mapBlocksInFlight.end ();
767
+ }
768
+
769
+ void PeerManagerImpl::RemoveBlockRequest (const uint256& hash)
770
+ {
771
+ auto it = mapBlocksInFlight.find (hash);
772
+ if (it == mapBlocksInFlight.end ()) {
773
+ // Block was not requested
774
+ return ;
781
775
}
782
- return false ;
776
+
777
+ auto [node_id, list_it] = it->second ;
778
+ CNodeState *state = State (node_id);
779
+ assert (state != nullptr );
780
+
781
+ if (state->vBlocksInFlight .begin () == list_it) {
782
+ // First block on the queue was received, update the start download time for the next one
783
+ state->m_downloading_since = std::max (state->m_downloading_since , GetTime<std::chrono::microseconds>());
784
+ }
785
+ state->vBlocksInFlight .erase (list_it);
786
+
787
+ state->nBlocksInFlight --;
788
+ if (state->nBlocksInFlight == 0 ) {
789
+ // Last validated block on the queue was received.
790
+ m_peers_downloading_from--;
791
+ }
792
+ state->m_stalling_since = 0us;
793
+ mapBlocksInFlight.erase (it);
783
794
}
784
795
785
- bool PeerManagerImpl::MarkBlockAsInFlight (NodeId nodeid, const uint256& hash , const CBlockIndex* pindex, std::list<QueuedBlock>::iterator** pit)
796
+ bool PeerManagerImpl::BlockRequested (NodeId nodeid, const CBlockIndex* pindex, std::list<QueuedBlock>::iterator** pit)
786
797
{
798
+ assert (pindex);
799
+ const uint256& hash{pindex->GetBlockHash ()};
800
+
787
801
CNodeState *state = State (nodeid);
788
802
assert (state != nullptr );
789
803
@@ -797,18 +811,15 @@ bool PeerManagerImpl::MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, co
797
811
}
798
812
799
813
// Make sure it's not listed somewhere already.
800
- MarkBlockAsReceived (hash);
814
+ RemoveBlockRequest (hash);
801
815
802
816
std::list<QueuedBlock>::iterator it = state->vBlocksInFlight .insert (state->vBlocksInFlight .end (),
803
- {hash, pindex, pindex != nullptr , std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock (&m_mempool) : nullptr )});
817
+ {pindex, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock (&m_mempool) : nullptr )});
804
818
state->nBlocksInFlight ++;
805
- state->nBlocksInFlightValidHeaders += it->fValidatedHeaders ;
806
819
if (state->nBlocksInFlight == 1 ) {
807
820
// We're starting a block download (batch) from this peer.
808
821
state->m_downloading_since = GetTime<std::chrono::microseconds>();
809
- }
810
- if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr ) {
811
- nPeersWithValidatedDownloads++;
822
+ m_peers_downloading_from++;
812
823
}
813
824
itInFlight = mapBlocksInFlight.insert (std::make_pair (hash, std::make_pair (nodeid, it))).first ;
814
825
if (pit)
@@ -978,7 +989,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
978
989
if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain ().Contains (pindex)) {
979
990
if (pindex->HaveTxsDownloaded ())
980
991
state->pindexLastCommonBlock = pindex;
981
- } else if (mapBlocksInFlight. count (pindex->GetBlockHash ()) == 0 ) {
992
+ } else if (! IsBlockRequested (pindex->GetBlockHash ())) {
982
993
// The block is not already downloaded, and not yet in flight.
983
994
if (pindex->nHeight > nWindowEnd) {
984
995
// We reached the end of the window.
@@ -1129,13 +1140,13 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
1129
1140
nSyncStarted--;
1130
1141
1131
1142
for (const QueuedBlock& entry : state->vBlocksInFlight ) {
1132
- mapBlocksInFlight.erase (entry.hash );
1143
+ mapBlocksInFlight.erase (entry.pindex -> GetBlockHash () );
1133
1144
}
1134
1145
WITH_LOCK (g_cs_orphans, m_orphanage.EraseForPeer (nodeid));
1135
1146
m_txrequest.DisconnectedPeer (nodeid);
1136
1147
nPreferredDownload -= state->fPreferredDownload ;
1137
- nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0 );
1138
- assert (nPeersWithValidatedDownloads >= 0 );
1148
+ m_peers_downloading_from -= (state->nBlocksInFlight != 0 );
1149
+ assert (m_peers_downloading_from >= 0 );
1139
1150
m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync .m_protect ;
1140
1151
assert (m_outbound_peers_with_protect_from_disconnect >= 0 );
1141
1152
m_wtxid_relay_peers -= state->m_wtxid_relay ;
@@ -1147,7 +1158,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
1147
1158
// Do a consistency check after the last peer is removed.
1148
1159
assert (mapBlocksInFlight.empty ());
1149
1160
assert (nPreferredDownload == 0 );
1150
- assert (nPeersWithValidatedDownloads == 0 );
1161
+ assert (m_peers_downloading_from == 0 );
1151
1162
assert (m_outbound_peers_with_protect_from_disconnect == 0 );
1152
1163
assert (m_wtxid_relay_peers == 0 );
1153
1164
assert (m_txrequest.Size () == 0 );
@@ -2056,7 +2067,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2056
2067
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
2057
2068
while (pindexWalk && !m_chainman.ActiveChain ().Contains (pindexWalk) && vToFetch.size () <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2058
2069
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2059
- !mapBlocksInFlight. count (pindexWalk->GetBlockHash ()) &&
2070
+ !IsBlockRequested (pindexWalk->GetBlockHash ()) &&
2060
2071
(!IsWitnessEnabled (pindexWalk->pprev , m_chainparams.GetConsensus ()) || State (pfrom.GetId ())->fHaveWitness )) {
2061
2072
// We don't have this block, and it's not yet in flight.
2062
2073
vToFetch.push_back (pindexWalk);
@@ -2081,7 +2092,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2081
2092
}
2082
2093
uint32_t nFetchFlags = GetFetchFlags (pfrom);
2083
2094
vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
2084
- MarkBlockAsInFlight (pfrom.GetId (), pindex-> GetBlockHash (), pindex);
2095
+ BlockRequested (pfrom.GetId (), pindex);
2085
2096
LogPrint (BCLog::NET, " Requesting block %s from peer=%d\n " ,
2086
2097
pindex->GetBlockHash ().ToString (), pfrom.GetId ());
2087
2098
}
@@ -2827,7 +2838,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
2827
2838
LogPrint (BCLog::NET, " got inv: %s %s peer=%d\n " , inv.ToString (), fAlreadyHave ? " have" : " new" , pfrom.GetId ());
2828
2839
2829
2840
UpdateBlockAvailability (pfrom.GetId (), inv.hash );
2830
- if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight. count (inv.hash )) {
2841
+ if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested (inv.hash )) {
2831
2842
// Headers-first is the primary method of announcement on
2832
2843
// the network. If a node fell back to sending blocks by inv,
2833
2844
// it's probably for a re-org. The final block hash
@@ -3384,7 +3395,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3384
3395
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
3385
3396
(fAlreadyInFlight && blockInFlightIt->second .first == pfrom.GetId ())) {
3386
3397
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr ;
3387
- if (!MarkBlockAsInFlight (pfrom.GetId (), pindex-> GetBlockHash (), pindex, &queuedBlockIt)) {
3398
+ if (!BlockRequested (pfrom.GetId (), pindex, &queuedBlockIt)) {
3388
3399
if (!(*queuedBlockIt)->partialBlock )
3389
3400
(*queuedBlockIt)->partialBlock .reset (new PartiallyDownloadedBlock (&m_mempool));
3390
3401
else {
@@ -3397,7 +3408,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3397
3408
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock ;
3398
3409
ReadStatus status = partialBlock.InitData (cmpctblock, vExtraTxnForCompact);
3399
3410
if (status == READ_STATUS_INVALID) {
3400
- MarkBlockAsReceived (pindex->GetBlockHash ()); // Reset in-flight state in case Misbehaving does not result in a disconnect
3411
+ RemoveBlockRequest (pindex->GetBlockHash ()); // Reset in-flight state in case Misbehaving does not result in a disconnect
3401
3412
Misbehaving (pfrom.GetId (), 100 , " invalid compact block" );
3402
3413
return ;
3403
3414
} else if (status == READ_STATUS_FAILED) {
@@ -3492,7 +3503,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3492
3503
// process from some other peer. We do this after calling
3493
3504
// ProcessNewBlock so that a malleated cmpctblock announcement
3494
3505
// can't be used to interfere with block relay.
3495
- MarkBlockAsReceived (pblock->GetHash ());
3506
+ RemoveBlockRequest (pblock->GetHash ());
3496
3507
}
3497
3508
}
3498
3509
return ;
@@ -3524,7 +3535,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3524
3535
PartiallyDownloadedBlock& partialBlock = *it->second .second ->partialBlock ;
3525
3536
ReadStatus status = partialBlock.FillBlock (*pblock, resp.txn );
3526
3537
if (status == READ_STATUS_INVALID) {
3527
- MarkBlockAsReceived (resp.blockhash ); // Reset in-flight state in case Misbehaving does not result in a disconnect
3538
+ RemoveBlockRequest (resp.blockhash ); // Reset in-flight state in case Misbehaving does not result in a disconnect
3528
3539
Misbehaving (pfrom.GetId (), 100 , " invalid compact block/non-matching block transactions" );
3529
3540
return ;
3530
3541
} else if (status == READ_STATUS_FAILED) {
@@ -3550,7 +3561,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3550
3561
// though the block was successfully read, and rely on the
3551
3562
// handling in ProcessNewBlock to ensure the block index is
3552
3563
// updated, etc.
3553
- MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
3564
+ RemoveBlockRequest (resp.blockhash ); // it is now an empty pointer
3554
3565
fBlockRead = true ;
3555
3566
// mapBlockSource is used for potentially punishing peers and
3556
3567
// updating which peers send us compact blocks, so the race
@@ -3615,9 +3626,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3615
3626
const uint256 hash (pblock->GetHash ());
3616
3627
{
3617
3628
LOCK (cs_main);
3618
- // Also always process if we requested the block explicitly, as we may
3619
- // need it even though it is not a candidate for a new best tip.
3620
- forceProcessing |= MarkBlockAsReceived (hash);
3629
+ // Always process the block if we requested it, since we may
3630
+ // need it even when it's not a candidate for a new best tip.
3631
+ forceProcessing = IsBlockRequested (hash);
3632
+ RemoveBlockRequest (hash);
3621
3633
// mapBlockSource is only used for punishing peers and setting
3622
3634
// which peers send us compact blocks, so the race between here and
3623
3635
// cs_main in ProcessNewBlock is fine.
@@ -4712,9 +4724,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4712
4724
// to unreasonably increase our timeout.
4713
4725
if (state.vBlocksInFlight .size () > 0 ) {
4714
4726
QueuedBlock &queuedBlock = state.vBlocksInFlight .front ();
4715
- int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state. nBlocksInFlightValidHeaders > 0 ) ;
4727
+ int nOtherPeersWithValidatedDownloads = m_peers_downloading_from - 1 ;
4716
4728
if (current_time > state.m_downloading_since + std::chrono::seconds{consensusParams.nPowTargetSpacing } * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) {
4717
- LogPrintf (" Timeout downloading block %s from peer=%d, disconnecting\n " , queuedBlock.hash .ToString (), pto->GetId ());
4729
+ LogPrintf (" Timeout downloading block %s from peer=%d, disconnecting\n " , queuedBlock.pindex -> GetBlockHash () .ToString (), pto->GetId ());
4718
4730
pto->fDisconnect = true ;
4719
4731
return true ;
4720
4732
}
@@ -4767,7 +4779,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4767
4779
for (const CBlockIndex *pindex : vToDownload) {
4768
4780
uint32_t nFetchFlags = GetFetchFlags (*pto);
4769
4781
vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
4770
- MarkBlockAsInFlight (pto->GetId (), pindex-> GetBlockHash (), pindex);
4782
+ BlockRequested (pto->GetId (), pindex);
4771
4783
LogPrint (BCLog::NET, " Requesting block %s (%d) peer=%d\n " , pindex->GetBlockHash ().ToString (),
4772
4784
pindex->nHeight , pto->GetId ());
4773
4785
}
0 commit comments