Skip to content

Commit dbfc748

Browse files
committed
Merge bitcoin/bitcoin#27608: p2p: Avoid prematurely clearing download state for other peers
52e5207 p2p: Avoid prematurely clearing download state for other peers (Suhas Daftuar) Pull request description: Avoid letting one peer send us data that clears out the download request (and related timers etc) from another peer. The exception is if a block is definitely stored to disk, in which case we'll clear the download state (just as we do for compact blocks). ACKs for top commit: jamesob: ACK 52e5207 ([`jamesob/ackr/27608.1.sdaftuar.p2p_avoid_prematurely_cl`](https://github.com/jamesob/bitcoin/tree/ackr/27608.1.sdaftuar.p2p_avoid_prematurely_cl)) instagibbs: ACK 52e5207 fjahr: Code review ACK 52e5207 mzumsande: Code Review ACK 52e5207 Tree-SHA512: 3ee92507edc3303c16c70ca44ba6c28c104afe95196e4b9167032590ed23d4f569f654f8eb8758940bd6536bc9ca810d2a77d2739db386b927e8b3f3cf55cb16
2 parents fc06881 + 52e5207 commit dbfc748

File tree

1 file changed

+22
-8
lines changed

1 file changed

+22
-8
lines changed

src/net_processing.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -883,8 +883,11 @@ class PeerManagerImpl final : public PeerManager
883883
/** Remove this block from our tracked requested blocks. Called if:
884884
* - the block has been received from a peer
885885
* - the request for the block has timed out
886+
* If "from_peer" is specified, then only remove the block if it is in
887+
* flight from that peer (to avoid one peer's network traffic from
888+
* affecting another's state).
886889
*/
887-
void RemoveBlockRequest(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
890+
void RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
888891

889892
/* Mark a block as in flight
890893
* Returns false, still setting pit, if the block was already in flight from the same peer
@@ -1120,7 +1123,7 @@ bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
11201123
return mapBlocksInFlight.find(hash) != mapBlocksInFlight.end();
11211124
}
11221125

1123-
void PeerManagerImpl::RemoveBlockRequest(const uint256& hash)
1126+
void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)
11241127
{
11251128
auto it = mapBlocksInFlight.find(hash);
11261129
if (it == mapBlocksInFlight.end()) {
@@ -1129,6 +1132,12 @@ void PeerManagerImpl::RemoveBlockRequest(const uint256& hash)
11291132
}
11301133

11311134
auto [node_id, list_it] = it->second;
1135+
1136+
if (from_peer && node_id != *from_peer) {
1137+
// Block was requested by another peer
1138+
return;
1139+
}
1140+
11321141
CNodeState *state = State(node_id);
11331142
assert(state != nullptr);
11341143

@@ -1164,7 +1173,7 @@ bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, st
11641173
}
11651174

11661175
// Make sure it's not listed somewhere already.
1167-
RemoveBlockRequest(hash);
1176+
RemoveBlockRequest(hash, std::nullopt);
11681177

11691178
std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
11701179
{&block, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&m_mempool) : nullptr)});
@@ -3155,6 +3164,11 @@ void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlo
31553164
m_chainman.ProcessNewBlock(block, force_processing, min_pow_checked, &new_block);
31563165
if (new_block) {
31573166
node.m_last_block_time = GetTime<std::chrono::seconds>();
3167+
// In case this block came from a different peer than we requested
3168+
// from, we can erase the block request now anyway (as we just stored
3169+
// this block to disk).
3170+
LOCK(cs_main);
3171+
RemoveBlockRequest(block->GetHash(), std::nullopt);
31583172
} else {
31593173
LOCK(cs_main);
31603174
mapBlockSource.erase(block->GetHash());
@@ -4305,7 +4319,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
43054319
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
43064320
ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
43074321
if (status == READ_STATUS_INVALID) {
4308-
RemoveBlockRequest(pindex->GetBlockHash()); // Reset in-flight state in case Misbehaving does not result in a disconnect
4322+
RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
43094323
Misbehaving(*peer, 100, "invalid compact block");
43104324
return;
43114325
} else if (status == READ_STATUS_FAILED) {
@@ -4400,7 +4414,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
44004414
// process from some other peer. We do this after calling
44014415
// ProcessNewBlock so that a malleated cmpctblock announcement
44024416
// can't be used to interfere with block relay.
4403-
RemoveBlockRequest(pblock->GetHash());
4417+
RemoveBlockRequest(pblock->GetHash(), std::nullopt);
44044418
}
44054419
}
44064420
return;
@@ -4432,7 +4446,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
44324446
PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
44334447
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
44344448
if (status == READ_STATUS_INVALID) {
4435-
RemoveBlockRequest(resp.blockhash); // Reset in-flight state in case Misbehaving does not result in a disconnect
4449+
RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
44364450
Misbehaving(*peer, 100, "invalid compact block/non-matching block transactions");
44374451
return;
44384452
} else if (status == READ_STATUS_FAILED) {
@@ -4458,7 +4472,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
44584472
// though the block was successfully read, and rely on the
44594473
// handling in ProcessNewBlock to ensure the block index is
44604474
// updated, etc.
4461-
RemoveBlockRequest(resp.blockhash); // it is now an empty pointer
4475+
RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // it is now an empty pointer
44624476
fBlockRead = true;
44634477
// mapBlockSource is used for potentially punishing peers and
44644478
// updating which peers send us compact blocks, so the race
@@ -4547,7 +4561,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
45474561
// Always process the block if we requested it, since we may
45484562
// need it even when it's not a candidate for a new best tip.
45494563
forceProcessing = IsBlockRequested(hash);
4550-
RemoveBlockRequest(hash);
4564+
RemoveBlockRequest(hash, pfrom.GetId());
45514565
// mapBlockSource is only used for punishing peers and setting
45524566
// which peers send us compact blocks, so the race between here and
45534567
// cs_main in ProcessNewBlock is fine.

0 commit comments

Comments
 (0)