@@ -898,7 +898,8 @@ class PeerManagerImpl final : public PeerManager
898
898
*/
899
899
void FindNextBlocksToDownload (const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
900
900
901
- typedef std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> BlockDownloadMap;
901
+ /* Multimap used to preserve insertion order */
902
+ typedef std::multimap<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> BlockDownloadMap;
902
903
BlockDownloadMap mapBlocksInFlight GUARDED_BY (cs_main);
903
904
904
905
/* * When our tip was last updated. */
@@ -1122,34 +1123,40 @@ bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
1122
1123
1123
1124
void PeerManagerImpl::RemoveBlockRequest (const uint256& hash, std::optional<NodeId> from_peer)
1124
1125
{
1125
- auto it = mapBlocksInFlight.find (hash);
1126
- if (it == mapBlocksInFlight. end () ) {
1127
- // Block was not requested
1126
+ auto range = mapBlocksInFlight.equal_range (hash);
1127
+ if (range. first == range. second ) {
1128
+ // Block was not requested from any peer
1128
1129
return ;
1129
1130
}
1130
1131
1131
- auto [node_id, list_it] = it->second ;
1132
+ // Currently we don't request more than one peer for same block
1133
+ Assume (mapBlocksInFlight.count (hash) == 1 );
1132
1134
1133
- if (from_peer && node_id != *from_peer) {
1134
- // Block was requested by another peer
1135
- return ;
1136
- }
1135
+ while (range.first != range.second ) {
1136
+ auto [node_id, list_it] = range.first ->second ;
1137
1137
1138
- CNodeState *state = State (node_id);
1139
- assert (state != nullptr );
1138
+ if (from_peer && *from_peer != node_id) {
1139
+ range.first ++;
1140
+ continue ;
1141
+ }
1140
1142
1141
- if (state->vBlocksInFlight .begin () == list_it) {
1142
- // First block on the queue was received, update the start download time for the next one
1143
- state->m_downloading_since = std::max (state->m_downloading_since , GetTime<std::chrono::microseconds>());
1144
- }
1145
- state->vBlocksInFlight .erase (list_it);
1143
+ CNodeState *state = State (node_id);
1144
+ assert (state != nullptr );
1146
1145
1147
- if (state->vBlocksInFlight .empty ()) {
1148
- // Last validated block on the queue was received.
1149
- m_peers_downloading_from--;
1146
+ if (state->vBlocksInFlight .begin () == list_it) {
1147
+ // First block on the queue was received, update the start download time for the next one
1148
+ state->m_downloading_since = std::max (state->m_downloading_since , GetTime<std::chrono::microseconds>());
1149
+ }
1150
+ state->vBlocksInFlight .erase (list_it);
1151
+
1152
+ if (state->vBlocksInFlight .empty ()) {
1153
+ // Last validated block on the queue for this peer was received.
1154
+ m_peers_downloading_from--;
1155
+ }
1156
+ state->m_stalling_since = 0us;
1157
+
1158
+ range.first = mapBlocksInFlight.erase (range.first );
1150
1159
}
1151
- state->m_stalling_since = 0us;
1152
- mapBlocksInFlight.erase (it);
1153
1160
}
1154
1161
1155
1162
bool PeerManagerImpl::BlockRequested (NodeId nodeid, const CBlockIndex& block, std::list<QueuedBlock>::iterator** pit)
@@ -1160,12 +1167,13 @@ bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, st
1160
1167
assert (state != nullptr );
1161
1168
1162
1169
// Short-circuit most stuff in case it is from the same node
1163
- BlockDownloadMap::iterator itInFlight = mapBlocksInFlight.find (hash);
1164
- if (itInFlight != mapBlocksInFlight.end () && itInFlight->second .first == nodeid) {
1165
- if (pit) {
1166
- *pit = &itInFlight->second .second ;
1170
+ for (auto range = mapBlocksInFlight.equal_range (hash); range.first != range.second ; range.first ++) {
1171
+ if (range.first ->second .first == nodeid) {
1172
+ if (pit) {
1173
+ *pit = &range.first ->second .second ;
1174
+ }
1175
+ return false ;
1167
1176
}
1168
- return false ;
1169
1177
}
1170
1178
1171
1179
// Make sure it's not listed somewhere already.
@@ -1178,7 +1186,7 @@ bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, st
1178
1186
state->m_downloading_since = GetTime<std::chrono::microseconds>();
1179
1187
m_peers_downloading_from++;
1180
1188
}
1181
- itInFlight = mapBlocksInFlight.insert (std::make_pair (hash, std::make_pair (nodeid, it))). first ;
1189
+ auto itInFlight = mapBlocksInFlight.insert (std::make_pair (hash, std::make_pair (nodeid, it)));
1182
1190
if (pit) {
1183
1191
*pit = &itInFlight->second .second ;
1184
1192
}
@@ -1381,7 +1389,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
1381
1389
}
1382
1390
} else if (waitingfor == -1 ) {
1383
1391
// This is the first already-in-flight block.
1384
- waitingfor = mapBlocksInFlight[ pindex->GetBlockHash ()] .first ;
1392
+ waitingfor = mapBlocksInFlight. lower_bound ( pindex->GetBlockHash ())-> second .first ;
1385
1393
}
1386
1394
}
1387
1395
}
@@ -1511,7 +1519,15 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
1511
1519
nSyncStarted--;
1512
1520
1513
1521
for (const QueuedBlock& entry : state->vBlocksInFlight ) {
1514
- mapBlocksInFlight.erase (entry.pindex ->GetBlockHash ());
1522
+ auto range = mapBlocksInFlight.equal_range (entry.pindex ->GetBlockHash ());
1523
+ while (range.first != range.second ) {
1524
+ auto [node_id, list_it] = range.first ->second ;
1525
+ if (node_id != nodeid) {
1526
+ range.first ++;
1527
+ } else {
1528
+ range.first = mapBlocksInFlight.erase (range.first );
1529
+ }
1530
+ }
1515
1531
}
1516
1532
m_orphanage.EraseForPeer (nodeid);
1517
1533
m_txrequest.DisconnectedPeer (nodeid);
@@ -4272,12 +4288,21 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4272
4288
nodestate->m_last_block_announcement = GetTime ();
4273
4289
}
4274
4290
4275
- BlockDownloadMap::iterator blockInFlightIt = mapBlocksInFlight.find (pindex->GetBlockHash ());
4276
- bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end ();
4277
-
4278
4291
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
4279
4292
return ;
4280
4293
4294
+ auto range_flight = mapBlocksInFlight.equal_range (pindex->GetBlockHash ());
4295
+ bool fAlreadyInFlight = range_flight.first != range_flight.second ;
4296
+ bool in_flight_same_peer{false };
4297
+
4298
+ while (range_flight.first != range_flight.second ) {
4299
+ if (range_flight.first ->second .first == pfrom.GetId ()) {
4300
+ in_flight_same_peer = true ;
4301
+ break ;
4302
+ }
4303
+ range_flight.first ++;
4304
+ }
4305
+
4281
4306
if (pindex->nChainWork <= m_chainman.ActiveChain ().Tip ()->nChainWork || // We know something better
4282
4307
pindex->nTx != 0 ) { // We had this block at some point, but pruned it
4283
4308
if (fAlreadyInFlight ) {
@@ -4299,7 +4324,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4299
4324
// possibilities in compact block processing...
4300
4325
if (pindex->nHeight <= m_chainman.ActiveChain ().Height () + 2 ) {
4301
4326
if ((!fAlreadyInFlight && nodestate->vBlocksInFlight .size () < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
4302
- ( fAlreadyInFlight && blockInFlightIt-> second . first == pfrom. GetId ()) ) {
4327
+ in_flight_same_peer ) {
4303
4328
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr ;
4304
4329
if (!BlockRequested (pfrom.GetId (), *pindex, &queuedBlockIt)) {
4305
4330
if (!(*queuedBlockIt)->partialBlock )
@@ -4431,14 +4456,23 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4431
4456
{
4432
4457
LOCK (cs_main);
4433
4458
4434
- BlockDownloadMap::iterator it = mapBlocksInFlight.find (resp.blockhash );
4435
- if (it == mapBlocksInFlight.end () || !it->second .second ->partialBlock ||
4436
- it->second .first != pfrom.GetId ()) {
4459
+ bool expected_blocktxn = false ;
4460
+ auto range_flight = mapBlocksInFlight.equal_range (resp.blockhash );
4461
+ while (range_flight.first != range_flight.second ) {
4462
+ auto [node_id, block_it] = range_flight.first ->second ;
4463
+ if (node_id == pfrom.GetId () && block_it->partialBlock ) {
4464
+ expected_blocktxn = true ;
4465
+ break ;
4466
+ }
4467
+ range_flight.first ++;
4468
+ }
4469
+
4470
+ if (!expected_blocktxn) {
4437
4471
LogPrint (BCLog::NET, " Peer %d sent us block transactions for block we weren't expecting\n " , pfrom.GetId ());
4438
4472
return ;
4439
4473
}
4440
4474
4441
- PartiallyDownloadedBlock& partialBlock = *it ->second .second ->partialBlock ;
4475
+ PartiallyDownloadedBlock& partialBlock = *range_flight. first ->second .second ->partialBlock ;
4442
4476
ReadStatus status = partialBlock.FillBlock (*pblock, resp.txn );
4443
4477
if (status == READ_STATUS_INVALID) {
4444
4478
RemoveBlockRequest (resp.blockhash , pfrom.GetId ()); // Reset in-flight state in case Misbehaving does not result in a disconnect
0 commit comments