Skip to content

Commit 1704bbf

Browse files
committed
Merge bitcoin/bitcoin#22141: net processing: Remove hash and fValidatedHeaders from QueuedBlock
2f4ad6b scripted-diff: rename MarkBlockAs functions (John Newbery) 2c45f83 [net processing] Tidy up MarkBlockAsReceived() (John Newbery) 6299350 [net processing] Add IsBlockRequested() function (John Newbery) 4e90d2d [net processing] Remove QueuedBlock.hash (John Newbery) 156a19e scripted-diff: rename nPeersWithValidatedDownloads (John Newbery) b03de9c [net processing] Remove CNodeState.nBlocksInFlightValidHeaders (John Newbery) b4e29f2 [net processing] Remove QueuedBlock.fValidatedHeaders (John Newbery) 85e058b [net processing] Remove unnecessary hash arg from MarkBlockAsInFlight() (John Newbery) Pull request description: The QueuedBlock struct contains a `fValidatedHeaders` field that indicates whether we have already validated a header for the requested block. Since headers-first syncing, we only request blocks where the header is already validated, so `fValidatedHeaders` is always true. Remove it and clean up the logic that uses that field. Likewise, QueuedBlock contains a `hash` field that is set to the block hash. Since headers-first syncing, we always have a CBlockIndex, which contains the block hash, so remove the redundant `hash` field. Tidy up the logic and rename functions to better indicate what they're doing. ACKs for top commit: mjdietzx: crACK 2f4ad6b sipa: utACK 2f4ad6b MarcoFalke: review ACK 2f4ad6b 📊 Tree-SHA512: 3d31d2bcb4d35d0fdb7c1da624c2878203218026445e8f76c4a2df68cc7183ce0e7d0c47c7c0a3242e55efaca7c9f5532b683cf6ec7c03d23fa83764fdb82fd2
2 parents ef8f296 + 2f4ad6b commit 1704bbf

File tree

1 file changed

+68
-56
lines changed

1 file changed

+68
-56
lines changed

src/net_processing.cpp

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ static constexpr size_t MAX_ADDR_TO_SEND{1000};
159159
namespace {
160160
/** Blocks that are in flight, and that are in the queue to be downloaded. */
161161
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;
166166
};
167167

168168
/**
@@ -463,16 +463,20 @@ class PeerManagerImpl final : public PeerManager
463463
Mutex m_recent_confirmed_transactions_mutex;
464464
std::unique_ptr<CRollingBloomFilter> m_recent_confirmed_transactions GUARDED_BY(m_recent_confirmed_transactions_mutex);
465465

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
468472
*/
469-
bool MarkBlockAsReceived(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
473+
void RemoveBlockRequest(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
470474

471475
/* Mark a block as in flight
472476
* Returns false, still setting pit, if the block was already in flight from the same peer
473477
* pit will only be valid as long as the same cs_main lock is being held
474478
*/
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);
476480

477481
bool TipMayBeStale() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
478482

@@ -512,7 +516,7 @@ class PeerManagerImpl final : public PeerManager
512516
std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY(cs_main);
513517

514518
/** 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;
516520

517521
/** Storage for orphan information */
518522
TxOrphanage m_orphanage;
@@ -627,7 +631,6 @@ struct CNodeState {
627631
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
628632
std::chrono::microseconds m_downloading_since{0us};
629633
int nBlocksInFlight{0};
630-
int nBlocksInFlightValidHeaders{0};
631634
//! Whether we consider this a preferred download peer.
632635
bool fPreferredDownload{false};
633636
//! 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
758761
nPreferredDownload += state->fPreferredDownload;
759762
}
760763

761-
bool PeerManagerImpl::MarkBlockAsReceived(const uint256& hash)
764+
bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
762765
{
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;
781775
}
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);
783794
}
784795

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)
786797
{
798+
assert(pindex);
799+
const uint256& hash{pindex->GetBlockHash()};
800+
787801
CNodeState *state = State(nodeid);
788802
assert(state != nullptr);
789803

@@ -797,18 +811,15 @@ bool PeerManagerImpl::MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, co
797811
}
798812

799813
// Make sure it's not listed somewhere already.
800-
MarkBlockAsReceived(hash);
814+
RemoveBlockRequest(hash);
801815

802816
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)});
804818
state->nBlocksInFlight++;
805-
state->nBlocksInFlightValidHeaders += it->fValidatedHeaders;
806819
if (state->nBlocksInFlight == 1) {
807820
// We're starting a block download (batch) from this peer.
808821
state->m_downloading_since = GetTime<std::chrono::microseconds>();
809-
}
810-
if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) {
811-
nPeersWithValidatedDownloads++;
822+
m_peers_downloading_from++;
812823
}
813824
itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first;
814825
if (pit)
@@ -978,7 +989,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
978989
if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain().Contains(pindex)) {
979990
if (pindex->HaveTxsDownloaded())
980991
state->pindexLastCommonBlock = pindex;
981-
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
992+
} else if (!IsBlockRequested(pindex->GetBlockHash())) {
982993
// The block is not already downloaded, and not yet in flight.
983994
if (pindex->nHeight > nWindowEnd) {
984995
// We reached the end of the window.
@@ -1129,13 +1140,13 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
11291140
nSyncStarted--;
11301141

11311142
for (const QueuedBlock& entry : state->vBlocksInFlight) {
1132-
mapBlocksInFlight.erase(entry.hash);
1143+
mapBlocksInFlight.erase(entry.pindex->GetBlockHash());
11331144
}
11341145
WITH_LOCK(g_cs_orphans, m_orphanage.EraseForPeer(nodeid));
11351146
m_txrequest.DisconnectedPeer(nodeid);
11361147
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);
11391150
m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
11401151
assert(m_outbound_peers_with_protect_from_disconnect >= 0);
11411152
m_wtxid_relay_peers -= state->m_wtxid_relay;
@@ -1147,7 +1158,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
11471158
// Do a consistency check after the last peer is removed.
11481159
assert(mapBlocksInFlight.empty());
11491160
assert(nPreferredDownload == 0);
1150-
assert(nPeersWithValidatedDownloads == 0);
1161+
assert(m_peers_downloading_from == 0);
11511162
assert(m_outbound_peers_with_protect_from_disconnect == 0);
11521163
assert(m_wtxid_relay_peers == 0);
11531164
assert(m_txrequest.Size() == 0);
@@ -2056,7 +2067,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
20562067
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
20572068
while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
20582069
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2059-
!mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
2070+
!IsBlockRequested(pindexWalk->GetBlockHash()) &&
20602071
(!IsWitnessEnabled(pindexWalk->pprev, m_chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) {
20612072
// We don't have this block, and it's not yet in flight.
20622073
vToFetch.push_back(pindexWalk);
@@ -2081,7 +2092,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
20812092
}
20822093
uint32_t nFetchFlags = GetFetchFlags(pfrom);
20832094
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
2084-
MarkBlockAsInFlight(pfrom.GetId(), pindex->GetBlockHash(), pindex);
2095+
BlockRequested(pfrom.GetId(), pindex);
20852096
LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
20862097
pindex->GetBlockHash().ToString(), pfrom.GetId());
20872098
}
@@ -2827,7 +2838,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
28272838
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
28282839

28292840
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
2830-
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
2841+
if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested(inv.hash)) {
28312842
// Headers-first is the primary method of announcement on
28322843
// the network. If a node fell back to sending blocks by inv,
28332844
// 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,
33843395
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
33853396
(fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) {
33863397
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
3387-
if (!MarkBlockAsInFlight(pfrom.GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) {
3398+
if (!BlockRequested(pfrom.GetId(), pindex, &queuedBlockIt)) {
33883399
if (!(*queuedBlockIt)->partialBlock)
33893400
(*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&m_mempool));
33903401
else {
@@ -3397,7 +3408,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
33973408
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
33983409
ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
33993410
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
34013412
Misbehaving(pfrom.GetId(), 100, "invalid compact block");
34023413
return;
34033414
} else if (status == READ_STATUS_FAILED) {
@@ -3492,7 +3503,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
34923503
// process from some other peer. We do this after calling
34933504
// ProcessNewBlock so that a malleated cmpctblock announcement
34943505
// can't be used to interfere with block relay.
3495-
MarkBlockAsReceived(pblock->GetHash());
3506+
RemoveBlockRequest(pblock->GetHash());
34963507
}
34973508
}
34983509
return;
@@ -3524,7 +3535,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
35243535
PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
35253536
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
35263537
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
35283539
Misbehaving(pfrom.GetId(), 100, "invalid compact block/non-matching block transactions");
35293540
return;
35303541
} else if (status == READ_STATUS_FAILED) {
@@ -3550,7 +3561,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
35503561
// though the block was successfully read, and rely on the
35513562
// handling in ProcessNewBlock to ensure the block index is
35523563
// updated, etc.
3553-
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
3564+
RemoveBlockRequest(resp.blockhash); // it is now an empty pointer
35543565
fBlockRead = true;
35553566
// mapBlockSource is used for potentially punishing peers and
35563567
// updating which peers send us compact blocks, so the race
@@ -3615,9 +3626,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
36153626
const uint256 hash(pblock->GetHash());
36163627
{
36173628
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);
36213633
// mapBlockSource is only used for punishing peers and setting
36223634
// which peers send us compact blocks, so the race between here and
36233635
// cs_main in ProcessNewBlock is fine.
@@ -4712,9 +4724,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
47124724
// to unreasonably increase our timeout.
47134725
if (state.vBlocksInFlight.size() > 0) {
47144726
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
4715-
int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0);
4727+
int nOtherPeersWithValidatedDownloads = m_peers_downloading_from - 1;
47164728
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());
47184730
pto->fDisconnect = true;
47194731
return true;
47204732
}
@@ -4767,7 +4779,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
47674779
for (const CBlockIndex *pindex : vToDownload) {
47684780
uint32_t nFetchFlags = GetFetchFlags(*pto);
47694781
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
4770-
MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), pindex);
4782+
BlockRequested(pto->GetId(), pindex);
47714783
LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
47724784
pindex->nHeight, pto->GetId());
47734785
}

0 commit comments

Comments
 (0)