@@ -791,6 +791,11 @@ void PeerManager::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) {
791
791
LOCK (cs_main);
792
792
int misbehavior{0 };
793
793
{
794
+ // We remove the PeerRef from g_peer_map here, but we don't always
795
+ // destruct the Peer. Sometimes another thread is still holding a
796
+ // PeerRef, so the refcount is >= 1. Be careful not to do any
797
+ // processing here that assumes Peer won't be changed before it's
798
+ // destructed.
794
799
PeerRef peer = RemovePeer (nodeid);
795
800
assert (peer != nullptr );
796
801
misbehavior = WITH_LOCK (peer->m_misbehavior_mutex , return peer->m_misbehavior_score );
@@ -870,6 +875,7 @@ bool PeerManager::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
870
875
PeerRef peer = GetPeerRef (nodeid);
871
876
if (peer == nullptr ) return false ;
872
877
stats.m_misbehavior_score = WITH_LOCK (peer->m_misbehavior_mutex , return peer->m_misbehavior_score );
878
+ stats.m_starting_height = peer->m_starting_height ;
873
879
874
880
return true ;
875
881
}
@@ -1309,13 +1315,17 @@ void PeerManager::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInde
1309
1315
}
1310
1316
}
1311
1317
1312
- // Relay to all peers
1313
- m_connman.ForEachNode ([&vHashes](CNode* pnode) {
1314
- LOCK (pnode->cs_inventory );
1315
- for (const uint256& hash : reverse_iterate (vHashes)) {
1316
- pnode->vBlockHashesToAnnounce .push_back (hash);
1318
+ {
1319
+ LOCK (m_peer_mutex);
1320
+ for (auto & it : m_peer_map) {
1321
+ Peer& peer = *it.second ;
1322
+ LOCK (peer.m_block_inv_mutex );
1323
+ for (const uint256& hash : reverse_iterate (vHashes)) {
1324
+ peer.m_blocks_for_headers_relay .push_back (hash);
1325
+ }
1317
1326
}
1318
- });
1327
+ }
1328
+
1319
1329
m_connman.WakeMessageHandler ();
1320
1330
}
1321
1331
@@ -1465,7 +1475,7 @@ static void RelayAddress(const CNode& originator,
1465
1475
connman.ForEachNodeThen (std::move (sortfunc), std::move (pushfunc));
1466
1476
}
1467
1477
1468
- void static ProcessGetBlockData (CNode& pfrom, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
1478
+ void static ProcessGetBlockData (CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
1469
1479
{
1470
1480
bool send = false ;
1471
1481
std::shared_ptr<const CBlock> a_recent_block;
@@ -1605,16 +1615,18 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
1605
1615
}
1606
1616
}
1607
1617
1608
- // Trigger the peer node to send a getblocks request for the next batch of inventory
1609
- if (inv.hash == pfrom.hashContinue )
1610
1618
{
1611
- // Send immediately. This must send even if redundant,
1612
- // and we want it right after the last block so they don't
1613
- // wait for other stuff first.
1614
- std::vector<CInv> vInv;
1615
- vInv.push_back (CInv (MSG_BLOCK, ::ChainActive ().Tip ()->GetBlockHash ()));
1616
- connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::INV, vInv));
1617
- pfrom.hashContinue .SetNull ();
1619
+ LOCK (peer.m_block_inv_mutex );
1620
+ // Trigger the peer node to send a getblocks request for the next batch of inventory
1621
+ if (inv.hash == peer.m_continuation_block ) {
1622
+ // Send immediately. This must send even if redundant,
1623
+ // and we want it right after the last block so they don't
1624
+ // wait for other stuff first.
1625
+ std::vector<CInv> vInv;
1626
+ vInv.push_back (CInv (MSG_BLOCK, ::ChainActive ().Tip ()->GetBlockHash ()));
1627
+ connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::INV, vInv));
1628
+ peer.m_continuation_block .SetNull ();
1629
+ }
1618
1630
}
1619
1631
}
1620
1632
}
@@ -1714,7 +1726,7 @@ void static ProcessGetData(CNode& pfrom, Peer& peer, const CChainParams& chainpa
1714
1726
if (it != peer.m_getdata_requests .end () && !pfrom.fPauseSend ) {
1715
1727
const CInv &inv = *it++;
1716
1728
if (inv.IsGenBlkMsg ()) {
1717
- ProcessGetBlockData (pfrom, chainparams, inv, connman);
1729
+ ProcessGetBlockData (pfrom, peer, chainparams, inv, connman);
1718
1730
}
1719
1731
// else: If the first item on the queue is an unknown type, we erase it
1720
1732
// and continue processing the queue on the next call.
@@ -1764,7 +1776,9 @@ void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const
1764
1776
m_connman.PushMessage (&pfrom, msgMaker.Make (nSendFlags, NetMsgType::BLOCKTXN, resp));
1765
1777
}
1766
1778
1767
- void PeerManager::ProcessHeadersMessage (CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block)
1779
+ void PeerManager::ProcessHeadersMessage (CNode& pfrom, const Peer& peer,
1780
+ const std::vector<CBlockHeader>& headers,
1781
+ bool via_compact_block)
1768
1782
{
1769
1783
const CNetMsgMaker msgMaker (pfrom.GetCommonVersion ());
1770
1784
size_t nCount = headers.size ();
@@ -1854,7 +1868,8 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe
1854
1868
// Headers message had its maximum size; the peer may have more headers.
1855
1869
// TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue
1856
1870
// from there instead.
1857
- LogPrint (BCLog::NET, " more getheaders (%d) to end to peer=%d (startheight:%d)\n " , pindexLast->nHeight , pfrom.GetId (), pfrom.nStartingHeight );
1871
+ LogPrint (BCLog::NET, " more getheaders (%d) to end to peer=%d (startheight:%d)\n " ,
1872
+ pindexLast->nHeight , pfrom.GetId (), peer.m_starting_height );
1858
1873
m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::GETHEADERS, ::ChainActive ().GetLocator (pindexLast), uint256 ()));
1859
1874
}
1860
1875
@@ -2280,7 +2295,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
2280
2295
ServiceFlags nServices;
2281
2296
int nVersion;
2282
2297
std::string cleanSubVer;
2283
- int nStartingHeight = -1 ;
2298
+ int starting_height = -1 ;
2284
2299
bool fRelay = true ;
2285
2300
2286
2301
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
@@ -2311,7 +2326,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
2311
2326
cleanSubVer = SanitizeString (strSubVer);
2312
2327
}
2313
2328
if (!vRecv.empty ()) {
2314
- vRecv >> nStartingHeight ;
2329
+ vRecv >> starting_height ;
2315
2330
}
2316
2331
if (!vRecv.empty ())
2317
2332
vRecv >> fRelay ;
@@ -2360,7 +2375,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
2360
2375
LOCK (pfrom.cs_SubVer );
2361
2376
pfrom.cleanSubVer = cleanSubVer;
2362
2377
}
2363
- pfrom. nStartingHeight = nStartingHeight ;
2378
+ peer-> m_starting_height = starting_height ;
2364
2379
2365
2380
// set nodes not relaying blocks and tx and not serving (parts) of the historical blockchain as "clients"
2366
2381
pfrom.fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED));
@@ -2440,7 +2455,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
2440
2455
2441
2456
LogPrint (BCLog::NET, " receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n " ,
2442
2457
cleanSubVer, pfrom.nVersion ,
2443
- pfrom. nStartingHeight , addrMe.ToString (), pfrom.GetId (),
2458
+ peer-> m_starting_height , addrMe.ToString (), pfrom.GetId (),
2444
2459
remoteAddr);
2445
2460
2446
2461
int64_t nTimeOffset = nTime - GetTime ();
@@ -2474,7 +2489,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
2474
2489
2475
2490
if (!pfrom.IsInboundConn ()) {
2476
2491
LogPrintf (" New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n " ,
2477
- pfrom.nVersion .load (), pfrom. nStartingHeight ,
2492
+ pfrom.nVersion .load (), peer-> m_starting_height ,
2478
2493
pfrom.GetId (), (fLogIPs ? strprintf (" , peeraddr=%s" , pfrom.addr .ToString ()) : " " ),
2479
2494
pfrom.ConnectionTypeAsString ());
2480
2495
}
@@ -2786,13 +2801,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
2786
2801
LogPrint (BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n " , pindex->nHeight , pindex->GetBlockHash ().ToString ());
2787
2802
break ;
2788
2803
}
2789
- WITH_LOCK (pfrom.cs_inventory , pfrom.vInventoryBlockToSend .push_back (pindex->GetBlockHash ()));
2790
- if (--nLimit <= 0 )
2791
- {
2804
+ WITH_LOCK (peer->m_block_inv_mutex , peer->m_blocks_for_inv_relay .push_back (pindex->GetBlockHash ()));
2805
+ if (--nLimit <= 0 ) {
2792
2806
// When this block is requested, we'll send an inv that'll
2793
2807
// trigger the peer to getblocks the next batch of inventory.
2794
2808
LogPrint (BCLog::NET, " getblocks stopping at limit %d %s\n " , pindex->nHeight , pindex->GetBlockHash ().ToString ());
2795
- pfrom. hashContinue = pindex->GetBlockHash ();
2809
+ WITH_LOCK (peer-> m_block_inv_mutex , {peer-> m_continuation_block = pindex->GetBlockHash ();} );
2796
2810
break ;
2797
2811
}
2798
2812
}
@@ -3316,7 +3330,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
3316
3330
// the peer if the header turns out to be for an invalid block.
3317
3331
// Note that if a peer tries to build on an invalid chain, that
3318
3332
// will be detected and the peer will be disconnected/discouraged.
3319
- return ProcessHeadersMessage (pfrom, {cmpctblock.header }, /* via_compact_block=*/ true );
3333
+ return ProcessHeadersMessage (pfrom, *peer, {cmpctblock.header }, /* via_compact_block=*/ true );
3320
3334
}
3321
3335
3322
3336
if (fBlockReconstructed ) {
@@ -3459,7 +3473,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
3459
3473
ReadCompactSize (vRecv); // ignore tx count; assume it is 0.
3460
3474
}
3461
3475
3462
- return ProcessHeadersMessage (pfrom, headers, /* via_compact_block=*/ false );
3476
+ return ProcessHeadersMessage (pfrom, *peer, headers, /* via_compact_block=*/ false );
3463
3477
}
3464
3478
3465
3479
if (msg_type == NetMsgType::BLOCK)
@@ -4067,6 +4081,7 @@ class CompareInvMempoolOrder
4067
4081
4068
4082
bool PeerManager::SendMessages (CNode* pto)
4069
4083
{
4084
+ PeerRef peer = GetPeerRef (pto->GetId ());
4070
4085
const Consensus::Params& consensusParams = m_chainparams.GetConsensus ();
4071
4086
4072
4087
// We must call MaybeDiscourageAndDisconnect first, to ensure that we'll
@@ -4192,7 +4207,7 @@ bool PeerManager::SendMessages(CNode* pto)
4192
4207
got back an empty response. */
4193
4208
if (pindexStart->pprev )
4194
4209
pindexStart = pindexStart->pprev ;
4195
- LogPrint (BCLog::NET, " initial getheaders (%d) to peer=%d (startheight:%d)\n " , pindexStart->nHeight , pto->GetId (), pto-> nStartingHeight );
4210
+ LogPrint (BCLog::NET, " initial getheaders (%d) to peer=%d (startheight:%d)\n " , pindexStart->nHeight , pto->GetId (), peer-> m_starting_height );
4196
4211
m_connman.PushMessage (pto, msgMaker.Make (NetMsgType::GETHEADERS, ::ChainActive ().GetLocator (pindexStart), uint256 ()));
4197
4212
}
4198
4213
}
@@ -4208,11 +4223,11 @@ bool PeerManager::SendMessages(CNode* pto)
4208
4223
// If no header would connect, or if we have too many
4209
4224
// blocks, or if the peer doesn't want headers, just
4210
4225
// add all to the inv queue.
4211
- LOCK (pto-> cs_inventory );
4226
+ LOCK (peer-> m_block_inv_mutex );
4212
4227
std::vector<CBlock> vHeaders;
4213
4228
bool fRevertToInv = ((!state.fPreferHeaders &&
4214
- (!state.fPreferHeaderAndIDs || pto-> vBlockHashesToAnnounce .size () > 1 )) ||
4215
- pto-> vBlockHashesToAnnounce .size () > MAX_BLOCKS_TO_ANNOUNCE);
4229
+ (!state.fPreferHeaderAndIDs || peer-> m_blocks_for_headers_relay .size () > 1 )) ||
4230
+ peer-> m_blocks_for_headers_relay .size () > MAX_BLOCKS_TO_ANNOUNCE);
4216
4231
const CBlockIndex *pBestIndex = nullptr ; // last header queued for delivery
4217
4232
ProcessBlockAvailability (pto->GetId ()); // ensure pindexBestKnownBlock is up-to-date
4218
4233
@@ -4221,7 +4236,7 @@ bool PeerManager::SendMessages(CNode* pto)
4221
4236
// Try to find first header that our peer doesn't have, and
4222
4237
// then send all headers past that one. If we come across any
4223
4238
// headers that aren't on ::ChainActive(), give up.
4224
- for (const uint256 & hash : pto-> vBlockHashesToAnnounce ) {
4239
+ for (const uint256& hash : peer-> m_blocks_for_headers_relay ) {
4225
4240
const CBlockIndex* pindex = LookupBlockIndex (hash);
4226
4241
assert (pindex);
4227
4242
if (::ChainActive ()[pindex->nHeight ] != pindex) {
@@ -4238,7 +4253,7 @@ bool PeerManager::SendMessages(CNode* pto)
4238
4253
// which should be caught by the prior check), but one
4239
4254
// way this could happen is by using invalidateblock /
4240
4255
// reconsiderblock repeatedly on the tip, causing it to
4241
- // be added multiple times to vBlockHashesToAnnounce .
4256
+ // be added multiple times to m_blocks_for_headers_relay .
4242
4257
// Robustly deal with this rare situation by reverting
4243
4258
// to an inv.
4244
4259
fRevertToInv = true ;
@@ -4310,10 +4325,10 @@ bool PeerManager::SendMessages(CNode* pto)
4310
4325
}
4311
4326
if (fRevertToInv ) {
4312
4327
// If falling back to using an inv, just try to inv the tip.
4313
- // The last entry in vBlockHashesToAnnounce was our tip at some point
4328
+ // The last entry in m_blocks_for_headers_relay was our tip at some point
4314
4329
// in the past.
4315
- if (!pto-> vBlockHashesToAnnounce .empty ()) {
4316
- const uint256 & hashToAnnounce = pto-> vBlockHashesToAnnounce .back ();
4330
+ if (!peer-> m_blocks_for_headers_relay .empty ()) {
4331
+ const uint256& hashToAnnounce = peer-> m_blocks_for_headers_relay .back ();
4317
4332
const CBlockIndex* pindex = LookupBlockIndex (hashToAnnounce);
4318
4333
assert (pindex);
4319
4334
@@ -4327,32 +4342,32 @@ bool PeerManager::SendMessages(CNode* pto)
4327
4342
4328
4343
// If the peer's chain has this block, don't inv it back.
4329
4344
if (!PeerHasHeader (&state, pindex)) {
4330
- pto-> vInventoryBlockToSend .push_back (hashToAnnounce);
4345
+ peer-> m_blocks_for_inv_relay .push_back (hashToAnnounce);
4331
4346
LogPrint (BCLog::NET, " %s: sending inv peer=%d hash=%s\n " , __func__,
4332
4347
pto->GetId (), hashToAnnounce.ToString ());
4333
4348
}
4334
4349
}
4335
4350
}
4336
- pto-> vBlockHashesToAnnounce .clear ();
4351
+ peer-> m_blocks_for_headers_relay .clear ();
4337
4352
}
4338
4353
4339
4354
//
4340
4355
// Message: inventory
4341
4356
//
4342
4357
std::vector<CInv> vInv;
4343
4358
{
4344
- LOCK (pto-> cs_inventory );
4345
- vInv.reserve (std::max<size_t >(pto-> vInventoryBlockToSend .size (), INVENTORY_BROADCAST_MAX));
4359
+ LOCK (peer-> m_block_inv_mutex );
4360
+ vInv.reserve (std::max<size_t >(peer-> m_blocks_for_inv_relay .size (), INVENTORY_BROADCAST_MAX));
4346
4361
4347
4362
// Add blocks
4348
- for (const uint256& hash : pto-> vInventoryBlockToSend ) {
4363
+ for (const uint256& hash : peer-> m_blocks_for_inv_relay ) {
4349
4364
vInv.push_back (CInv (MSG_BLOCK, hash));
4350
4365
if (vInv.size () == MAX_INV_SZ) {
4351
4366
m_connman.PushMessage (pto, msgMaker.Make (NetMsgType::INV, vInv));
4352
4367
vInv.clear ();
4353
4368
}
4354
4369
}
4355
- pto-> vInventoryBlockToSend .clear ();
4370
+ peer-> m_blocks_for_inv_relay .clear ();
4356
4371
4357
4372
if (pto->m_tx_relay != nullptr ) {
4358
4373
LOCK (pto->m_tx_relay ->cs_tx_inventory );
0 commit comments