mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
Pass Peer& to Misbehaving()
`Misbehaving` has several coding related issues (ignoring the conceptual issues here for now): * It is public, but it is not supposed to be called from outside of net_processing. Fix that by making it private and creating a public `UnitTestMisbehaving` method for unit testing only. * It doesn't do anything if a `nullptr` is passed. It would be less confusing to just skip the call instead. Fix that by passing `Peer&` to `Misbehaving()`. * It calls `GetPeerRef`, causing `!m_peer_mutex` lock annotations to be propagated. This is harmless, but verbose. Fix it by removing the no longer needed call to `GetPeerRef` and the no longer needed lock annotations.
This commit is contained in:
parent
3ba6dd6f4b
commit
fa8aa0aa81
@ -492,7 +492,7 @@ public:
|
||||
void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
void SetBestHeight(int height) override { m_best_height = height; };
|
||||
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
void UnitTestMisbehaving(NodeId peer_id, int howmuch) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), howmuch, ""); };
|
||||
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
|
||||
const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex);
|
||||
@ -516,6 +516,12 @@ private:
|
||||
* May return an empty shared_ptr if the Peer object can't be found. */
|
||||
PeerRef RemovePeer(NodeId id) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
|
||||
/**
|
||||
* Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node
|
||||
* to be discouraged, meaning the peer might be disconnected and added to the discouragement filter.
|
||||
*/
|
||||
void Misbehaving(Peer& peer, int howmuch, const std::string& message);
|
||||
|
||||
/**
|
||||
* Potentially mark a node discouraged based on the contents of a BlockValidationState object
|
||||
*
|
||||
@ -549,13 +555,12 @@ private:
|
||||
void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
/** Process a single headers message from a peer. */
|
||||
void ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
|
||||
void ProcessHeadersMessage(CNode& pfrom, Peer& peer,
|
||||
const std::vector<CBlockHeader>& headers,
|
||||
bool via_compact_block)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
|
||||
void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
|
||||
void SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
|
||||
|
||||
/** Register with TxRequestTracker that an INV has been received from a
|
||||
* peer. The announcement parameters are decided in PeerManager and then
|
||||
@ -1441,33 +1446,31 @@ void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)
|
||||
vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn;
|
||||
}
|
||||
|
||||
void PeerManagerImpl::Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
|
||||
void PeerManagerImpl::Misbehaving(Peer& peer, int howmuch, const std::string& message)
|
||||
{
|
||||
assert(howmuch > 0);
|
||||
|
||||
PeerRef peer = GetPeerRef(pnode);
|
||||
if (peer == nullptr) return;
|
||||
|
||||
LOCK(peer->m_misbehavior_mutex);
|
||||
const int score_before{peer->m_misbehavior_score};
|
||||
peer->m_misbehavior_score += howmuch;
|
||||
const int score_now{peer->m_misbehavior_score};
|
||||
LOCK(peer.m_misbehavior_mutex);
|
||||
const int score_before{peer.m_misbehavior_score};
|
||||
peer.m_misbehavior_score += howmuch;
|
||||
const int score_now{peer.m_misbehavior_score};
|
||||
|
||||
const std::string message_prefixed = message.empty() ? "" : (": " + message);
|
||||
std::string warning;
|
||||
|
||||
if (score_now >= DISCOURAGEMENT_THRESHOLD && score_before < DISCOURAGEMENT_THRESHOLD) {
|
||||
warning = " DISCOURAGE THRESHOLD EXCEEDED";
|
||||
peer->m_should_discourage = true;
|
||||
peer.m_should_discourage = true;
|
||||
}
|
||||
|
||||
LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s%s\n",
|
||||
pnode, score_before, score_now, warning, message_prefixed);
|
||||
peer.m_id, score_before, score_now, warning, message_prefixed);
|
||||
}
|
||||
|
||||
bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
|
||||
bool via_compact_block, const std::string& message)
|
||||
{
|
||||
PeerRef peer{GetPeerRef(nodeid)};
|
||||
switch (state.GetResult()) {
|
||||
case BlockValidationResult::BLOCK_RESULT_UNSET:
|
||||
break;
|
||||
@ -1475,7 +1478,7 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
|
||||
case BlockValidationResult::BLOCK_CONSENSUS:
|
||||
case BlockValidationResult::BLOCK_MUTATED:
|
||||
if (!via_compact_block) {
|
||||
Misbehaving(nodeid, 100, message);
|
||||
if (peer) Misbehaving(*peer, 100, message);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -1490,7 +1493,7 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
|
||||
// Discourage outbound (but not inbound) peers if on an invalid chain.
|
||||
// Exempt HB compact block peers. Manual connections are always protected from discouragement.
|
||||
if (!via_compact_block && !node_state->m_is_inbound) {
|
||||
Misbehaving(nodeid, 100, message);
|
||||
if (peer) Misbehaving(*peer, 100, message);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -1498,12 +1501,12 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
|
||||
case BlockValidationResult::BLOCK_INVALID_HEADER:
|
||||
case BlockValidationResult::BLOCK_CHECKPOINT:
|
||||
case BlockValidationResult::BLOCK_INVALID_PREV:
|
||||
Misbehaving(nodeid, 100, message);
|
||||
if (peer) Misbehaving(*peer, 100, message);
|
||||
return true;
|
||||
// Conflicting (but not necessarily invalid) data or different policy:
|
||||
case BlockValidationResult::BLOCK_MISSING_PREV:
|
||||
// TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
|
||||
Misbehaving(nodeid, 10, message);
|
||||
if (peer) Misbehaving(*peer, 10, message);
|
||||
return true;
|
||||
case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
|
||||
case BlockValidationResult::BLOCK_TIME_FUTURE:
|
||||
@ -1517,12 +1520,13 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
|
||||
|
||||
bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
|
||||
{
|
||||
PeerRef peer{GetPeerRef(nodeid)};
|
||||
switch (state.GetResult()) {
|
||||
case TxValidationResult::TX_RESULT_UNSET:
|
||||
break;
|
||||
// The node is providing invalid data:
|
||||
case TxValidationResult::TX_CONSENSUS:
|
||||
Misbehaving(nodeid, 100, message);
|
||||
if (peer) Misbehaving(*peer, 100, message);
|
||||
return true;
|
||||
// Conflicting (but not necessarily invalid) data or different policy:
|
||||
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
|
||||
@ -2172,12 +2176,12 @@ uint32_t PeerManagerImpl::GetFetchFlags(const CNode& pfrom) const EXCLUSIVE_LOCK
|
||||
return nFetchFlags;
|
||||
}
|
||||
|
||||
void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req)
|
||||
void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req)
|
||||
{
|
||||
BlockTransactions resp(req);
|
||||
for (size_t i = 0; i < req.indexes.size(); i++) {
|
||||
if (req.indexes[i] >= block.vtx.size()) {
|
||||
Misbehaving(pfrom.GetId(), 100, "getblocktxn with out-of-bounds tx indices");
|
||||
Misbehaving(peer, 100, "getblocktxn with out-of-bounds tx indices");
|
||||
return;
|
||||
}
|
||||
resp.txn[i] = block.vtx[req.indexes[i]];
|
||||
@ -2187,7 +2191,7 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, c
|
||||
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCKTXN, resp));
|
||||
}
|
||||
|
||||
void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
|
||||
void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
|
||||
const std::vector<CBlockHeader>& headers,
|
||||
bool via_compact_block)
|
||||
{
|
||||
@ -2227,7 +2231,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
|
||||
UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash());
|
||||
|
||||
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("%d non-connecting headers", nodestate->nUnconnectingHeaders));
|
||||
Misbehaving(peer, 20, strprintf("%d non-connecting headers", nodestate->nUnconnectingHeaders));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -2235,7 +2239,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
|
||||
uint256 hashLastBlock;
|
||||
for (const CBlockHeader& header : headers) {
|
||||
if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
|
||||
Misbehaving(pfrom.GetId(), 20, "non-continuous headers sequence");
|
||||
Misbehaving(peer, 20, "non-continuous headers sequence");
|
||||
return;
|
||||
}
|
||||
hashLastBlock = header.GetHash();
|
||||
@ -2998,7 +3002,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
|
||||
if (vAddr.size() > MAX_ADDR_TO_SEND)
|
||||
{
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("%s message size = %u", msg_type, vAddr.size()));
|
||||
Misbehaving(*peer, 20, strprintf("%s message size = %u", msg_type, vAddr.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3079,7 +3083,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
vRecv >> vInv;
|
||||
if (vInv.size() > MAX_INV_SZ)
|
||||
{
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("inv message size = %u", vInv.size()));
|
||||
Misbehaving(*peer, 20, strprintf("inv message size = %u", vInv.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3154,7 +3158,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
vRecv >> vInv;
|
||||
if (vInv.size() > MAX_INV_SZ)
|
||||
{
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("getdata message size = %u", vInv.size()));
|
||||
Misbehaving(*peer, 20, strprintf("getdata message size = %u", vInv.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3252,7 +3256,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
// Unlock m_most_recent_block_mutex to avoid cs_main lock inversion
|
||||
}
|
||||
if (recent_block) {
|
||||
SendBlockTransactions(pfrom, *recent_block, req);
|
||||
SendBlockTransactions(pfrom, *peer, *recent_block, req);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3270,7 +3274,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus());
|
||||
assert(ret);
|
||||
|
||||
SendBlockTransactions(pfrom, block, req);
|
||||
SendBlockTransactions(pfrom, *peer, block, req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -3678,7 +3682,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
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
|
||||
Misbehaving(pfrom.GetId(), 100, "invalid compact block");
|
||||
Misbehaving(*peer, 100, "invalid compact block");
|
||||
return;
|
||||
} else if (status == READ_STATUS_FAILED) {
|
||||
// Duplicate txindexes, the block is now in-flight, so just request it
|
||||
@ -3805,7 +3809,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
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
|
||||
Misbehaving(pfrom.GetId(), 100, "invalid compact block/non-matching block transactions");
|
||||
Misbehaving(*peer, 100, "invalid compact block/non-matching block transactions");
|
||||
return;
|
||||
} else if (status == READ_STATUS_FAILED) {
|
||||
// Might have collided, fall back to getdata now :(
|
||||
@ -3866,7 +3870,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
|
||||
unsigned int nCount = ReadCompactSize(vRecv);
|
||||
if (nCount > MAX_HEADERS_RESULTS) {
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("headers message size = %u", nCount));
|
||||
Misbehaving(*peer, 20, strprintf("headers message size = %u", nCount));
|
||||
return;
|
||||
}
|
||||
headers.resize(nCount);
|
||||
@ -4060,7 +4064,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
if (!filter.IsWithinSizeConstraints())
|
||||
{
|
||||
// There is no excuse for sending a too-large filter
|
||||
Misbehaving(pfrom.GetId(), 100, "too-large bloom filter");
|
||||
Misbehaving(*peer, 100, "too-large bloom filter");
|
||||
} else if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) {
|
||||
{
|
||||
LOCK(tx_relay->m_bloom_filter_mutex);
|
||||
@ -4095,7 +4099,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||
}
|
||||
}
|
||||
if (bad) {
|
||||
Misbehaving(pfrom.GetId(), 100, "bad filteradd message");
|
||||
Misbehaving(*peer, 100, "bad filteradd message");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -71,12 +71,8 @@ public:
|
||||
/** Set the best height */
|
||||
virtual void SetBestHeight(int height) = 0;
|
||||
|
||||
/**
|
||||
* Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node
|
||||
* to be discouraged, meaning the peer might be disconnected and added to the discouragement filter.
|
||||
* Public for unit testing.
|
||||
*/
|
||||
virtual void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) = 0;
|
||||
/* Public for unit testing. */
|
||||
virtual void UnitTestMisbehaving(NodeId peer_id, int howmuch) = 0;
|
||||
|
||||
/**
|
||||
* Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound.
|
||||
|
@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
peerLogic->InitializeNode(nodes[0]);
|
||||
nodes[0]->fSuccessfullyConnected = true;
|
||||
connman->AddTestNode(*nodes[0]);
|
||||
peerLogic->Misbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD, /*message=*/""); // Should be discouraged
|
||||
peerLogic->UnitTestMisbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
|
||||
{
|
||||
LOCK(nodes[0]->cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(nodes[0]));
|
||||
@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
peerLogic->InitializeNode(nodes[1]);
|
||||
nodes[1]->fSuccessfullyConnected = true;
|
||||
connman->AddTestNode(*nodes[1]);
|
||||
peerLogic->Misbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1, /*message=*/"");
|
||||
peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1);
|
||||
{
|
||||
LOCK(nodes[1]->cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(nodes[1]));
|
||||
@ -339,7 +339,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
// [1] is not discouraged/disconnected yet.
|
||||
BOOST_CHECK(!banman->IsDiscouraged(addr[1]));
|
||||
BOOST_CHECK(!nodes[1]->fDisconnect);
|
||||
peerLogic->Misbehaving(nodes[1]->GetId(), 1, /*message=*/""); // [1] reaches discouragement threshold
|
||||
peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), 1); // [1] reaches discouragement threshold
|
||||
{
|
||||
LOCK(nodes[1]->cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(nodes[1]));
|
||||
@ -366,7 +366,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
peerLogic->InitializeNode(nodes[2]);
|
||||
nodes[2]->fSuccessfullyConnected = true;
|
||||
connman->AddTestNode(*nodes[2]);
|
||||
peerLogic->Misbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD, /*message=*/"");
|
||||
peerLogic->UnitTestMisbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD);
|
||||
{
|
||||
LOCK(nodes[2]->cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(nodes[2]));
|
||||
@ -411,7 +411,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
peerLogic->InitializeNode(&dummyNode);
|
||||
dummyNode.fSuccessfullyConnected = true;
|
||||
|
||||
peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD, /*message=*/"");
|
||||
peerLogic->UnitTestMisbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
|
||||
{
|
||||
LOCK(dummyNode.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
|
||||
|
Loading…
Reference in New Issue
Block a user