Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1021,8 +1021,11 @@ class PeerManagerImpl final : public PeerManager
/** Remove this block from our tracked requested blocks. Called if:
* - the block has been recieved from a peer
* - the request for the block has timed out
* If "from_peer" is specified, then only remove the block if it is in
* flight from that peer (to avoid one peer's network traffic from
* affecting another's state).
*/
void RemoveBlockRequest(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

/* Mark a block as in flight
* Returns false, still setting pit, if the block was already in flight from the same peer
Expand Down Expand Up @@ -1220,7 +1223,7 @@ bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
return mapBlocksInFlight.find(hash) != mapBlocksInFlight.end();
}

void PeerManagerImpl::RemoveBlockRequest(const uint256& hash)
void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)
{
auto it = mapBlocksInFlight.find(hash);
if (it == mapBlocksInFlight.end()) {
Expand All @@ -1229,6 +1232,12 @@ void PeerManagerImpl::RemoveBlockRequest(const uint256& hash)
}

auto [node_id, list_it] = it->second;

if (from_peer && node_id != *from_peer) {
// Block was requested by another peer
return;
}

CNodeState *state = State(node_id);
assert(state != nullptr);

Expand Down Expand Up @@ -1264,7 +1273,7 @@ bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, st
}

// Make sure it's not listed somewhere already.
RemoveBlockRequest(hash);
RemoveBlockRequest(hash, std::nullopt);

std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
{&block, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&m_mempool) : nullptr)});
Expand Down Expand Up @@ -3573,6 +3582,11 @@ void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlo
m_chainman.ProcessNewBlock(m_chainparams, block, force_processing, &new_block);
if (new_block) {
node.m_last_block_time = GetTime<std::chrono::seconds>();
// In case this block came from a different peer than we requested
// from, we can erase the block request now anyway (as we just stored
// this block to disk).
LOCK(cs_main);
RemoveBlockRequest(block->GetHash(), std::nullopt);
} else {
LOCK(cs_main);
mapBlockSource.erase(block->GetHash());
Expand Down Expand Up @@ -4870,7 +4884,7 @@ void PeerManagerImpl::ProcessMessage(
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status == READ_STATUS_INVALID) {
RemoveBlockRequest(pindex->GetBlockHash()); // Reset in-flight state in case Misbehaving does not result in a disconnect
RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
Misbehaving(pfrom.GetId(), 100, "invalid compact block");
return;
} else if (status == READ_STATUS_FAILED) {
Expand Down Expand Up @@ -4964,7 +4978,7 @@ void PeerManagerImpl::ProcessMessage(
// process from some other peer. We do this after calling
// ProcessNewBlock so that a malleated cmpctblock announcement
// can't be used to interfere with block relay.
RemoveBlockRequest(pblock->GetHash());
RemoveBlockRequest(pblock->GetHash(), std::nullopt);
}
}
return;
Expand Down Expand Up @@ -4996,7 +5010,7 @@ void PeerManagerImpl::ProcessMessage(
PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
if (status == READ_STATUS_INVALID) {
RemoveBlockRequest(resp.blockhash); // Reset in-flight state in case Misbehaving does not result in a disconnect
RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
Misbehaving(pfrom.GetId(), 100, "invalid compact block/non-matching block transactions");
return;
} else if (status == READ_STATUS_FAILED) {
Expand All @@ -5022,7 +5036,7 @@ void PeerManagerImpl::ProcessMessage(
// though the block was successfully read, and rely on the
// handling in ProcessNewBlock to ensure the block index is
// updated, etc.
RemoveBlockRequest(resp.blockhash); // it is now an empty pointer
RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // it is now an empty pointer
fBlockRead = true;
// mapBlockSource is used for potentially punishing peers and
// updating which peers send us compact blocks, so the race
Expand Down Expand Up @@ -5104,7 +5118,7 @@ void PeerManagerImpl::ProcessMessage(
// Always process the block if we requested it, since we may
// need it even when it's not a candidate for a new best tip.
forceProcessing = IsBlockRequested(hash);
RemoveBlockRequest(hash);
RemoveBlockRequest(hash, pfrom.GetId());
// mapBlockSource is only used for punishing peers and setting
// which peers send us compact blocks, so the race between here and
// cs_main in ProcessNewBlock is fine.
Expand Down