This commit is contained in:
Luke Dashjr 2024-04-29 04:31:19 +02:00 committed by GitHub
commit b377237b88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 3 deletions

View File

@ -908,6 +908,9 @@ private:
/** Have we requested this block from an outbound peer */
bool IsBlockRequestedFromOutbound(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Have we requested this block from a specific peer */
bool IsBlockRequestedFromPeer(const uint256& hash, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Remove this block from our tracked requested blocks. Called if:
* - the block has been received from a peer
* - the request for the block has timed out
@ -1200,6 +1203,16 @@ bool PeerManagerImpl::IsBlockRequestedFromOutbound(const uint256& hash)
return false;
}
bool PeerManagerImpl::IsBlockRequestedFromPeer(const uint256& hash, NodeId peer)
{
for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
auto [nodeid, block_it] = range.first->second;
if (nodeid == peer) return true;
}
return false;
}
void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)
{
auto range = mapBlocksInFlight.equal_range(hash);
@ -1930,16 +1943,19 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
// Ignore pre-segwit peers
if (!CanServeWitnesses(*peer)) return "Pre-SegWit peer";
const uint256& hash{block_index.GetBlockHash()};
LOCK(cs_main);
if (IsBlockRequestedFromPeer(hash, peer_id)) return "Already requested from this peer";
// Forget about all prior requests
RemoveBlockRequest(block_index.GetBlockHash(), std::nullopt);
RemoveBlockRequest(hash, std::nullopt);
// Mark block as in-flight
if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer";
Assume(BlockRequested(peer_id, block_index));
// Construct message to request the block
const uint256& hash{block_index.GetBlockHash()};
std::vector<CInv> invs{CInv(MSG_BLOCK | MSG_WITNESS_FLAG, hash)};
// Send block request message to the peer

View File

@ -84,6 +84,14 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
presegwit_peer_id = peers[1]["id"]
assert_raises_rpc_error(-1, "Pre-SegWit peer", self.nodes[0].getblockfrompeer, short_tip, presegwit_peer_id)
self.log.info("Fetching from same peer twice generates error")
self.nodes[0].add_p2p_connection(P2PInterface())
peers = self.nodes[0].getpeerinfo()
assert_equal(len(peers), 3)
slow_peer_id = peers[2]["id"]
assert_equal(self.nodes[0].getblockfrompeer(short_tip, slow_peer_id), {})
assert_raises_rpc_error(-1, "Already requested from this peer", self.nodes[0].getblockfrompeer, short_tip, slow_peer_id)
self.log.info("Successful fetch")
result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id)
self.wait_until(lambda: self.check_for_block(node=0, hash=short_tip), timeout=1)
@ -92,6 +100,9 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
self.log.info("Don't fetch blocks we already have")
assert_raises_rpc_error(-1, "Block already downloaded", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id)
self.log.info("Non-existent peer generates error, even if we already have the block")
assert_raises_rpc_error(-1, "Block already downloaded", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id + 1)
self.log.info("Don't fetch blocks while the node has not synced past it yet")
# For this test we need node 1 in prune mode and as a side effect this also disconnects
# the nodes which is also necessary for the rest of the test.