Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,181 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
// overloaded variant of above to operate on CNode*s | // overloaded variant of above to operate on CNode*s | ||||
static void Misbehaving(CNode *node, int howmuch, const std::string &reason) | static void Misbehaving(CNode *node, int howmuch, const std::string &reason) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
Misbehaving(node->GetId(), howmuch, reason); | Misbehaving(node->GetId(), howmuch, reason); | ||||
} | } | ||||
/** | |||||
* Returns true if the given validation state result may result in a peer | |||||
* banning/disconnecting us. We use this to determine which unaccepted | |||||
* transactions from a whitelisted peer that we can safely relay. | |||||
*/ | |||||
static bool TxRelayMayResultInDisconnect(const CValidationState &state) { | static bool TxRelayMayResultInDisconnect(const CValidationState &state) { | ||||
return state.GetDoS() > 0; | return state.GetReason() == ValidationInvalidReason::CONSENSUS; | ||||
} | } | ||||
/** | /** | ||||
* Potentially ban a node based on the contents of a CValidationState object | * Potentially ban a node based on the contents of a CValidationState object | ||||
* TODO: net_processing should make the punish decision based on the reason | |||||
* a tx/block was invalid, rather than just the nDoS score handed back by | |||||
* validation. | |||||
* | * | ||||
* @parameter via_compact_block: this bool is passed in because net_processing | * @param[in] via_compact_block: this bool is passed in because net_processing | ||||
* should punish peers differently depending on whether the data was provided in | * should punish peers differently depending on whether the data was provided in | ||||
* a compact block message or not. If the compact block had a valid header, but | * a compact block message or not. If the compact block had a valid header, but | ||||
* contained invalid txs, the peer should not be punished. See BIP 152. | * contained invalid txs, the peer should not be punished. See BIP 152. | ||||
* | |||||
* @return Returns true if the peer was punished (probably disconnected) | |||||
* | |||||
* Changes here may need to be reflected in TxRelayMayResultInDisconnect(). | |||||
*/ | */ | ||||
static bool MaybePunishNode(NodeId nodeid, const CValidationState &state, | static bool MaybePunishNode(NodeId nodeid, const CValidationState &state, | ||||
bool via_compact_block, | bool via_compact_block, | ||||
const std::string &message = "") { | const std::string &message = "") { | ||||
int nDoS = state.GetDoS(); | switch (state.GetReason()) { | ||||
if (nDoS > 0 && !via_compact_block) { | case ValidationInvalidReason::NONE: | ||||
break; | |||||
// The node is providing invalid data: | |||||
case ValidationInvalidReason::CONSENSUS: | |||||
case ValidationInvalidReason::BLOCK_MUTATED: | |||||
if (!via_compact_block) { | |||||
LOCK(cs_main); | |||||
Misbehaving(nodeid, 100, message); | |||||
return true; | |||||
} | |||||
break; | |||||
// Handled elsewhere for now | |||||
case ValidationInvalidReason::CACHED_INVALID: | |||||
break; | |||||
case ValidationInvalidReason::BLOCK_INVALID_HEADER: | |||||
case ValidationInvalidReason::BLOCK_CHECKPOINT: | |||||
case ValidationInvalidReason::BLOCK_INVALID_PREV: { | |||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(nodeid, nDoS, message); | Misbehaving(nodeid, 100, message); | ||||
} | |||||
return true; | return true; | ||||
case ValidationInvalidReason::BLOCK_FINALIZATION: { | |||||
// TODO: Use the state object to report this is probably not the | |||||
// best idea. This is effectively unreachable, unless there is a bug | |||||
// somewhere. | |||||
LOCK(cs_main); | |||||
Misbehaving(nodeid, 20, message); | |||||
} | |||||
return true; | |||||
// Conflicting (but not necessarily invalid) data or different policy: | |||||
case ValidationInvalidReason::BLOCK_MISSING_PREV: { | |||||
// TODO: Handle this much more gracefully (10 DoS points is super | |||||
// arbitrary) | |||||
LOCK(cs_main); | |||||
Misbehaving(nodeid, 10, message); | |||||
} | |||||
return true; | |||||
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE: | |||||
case ValidationInvalidReason::BLOCK_TIME_FUTURE: | |||||
case ValidationInvalidReason::TX_NOT_STANDARD: | |||||
case ValidationInvalidReason::TX_MISSING_INPUTS: | |||||
case ValidationInvalidReason::TX_CONFLICT: | |||||
case ValidationInvalidReason::TX_MEMPOOL_POLICY: | |||||
break; | |||||
} | } | ||||
if (message != "") { | if (message != "") { | ||||
LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); | LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||
▲ Show 20 Lines • Show All 1,806 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::TX) { | ||||
} | } | ||||
if (pfrom->HasPermission(PF_FORCERELAY)) { | if (pfrom->HasPermission(PF_FORCERELAY)) { | ||||
// Always relay transactions received from whitelisted peers, | // Always relay transactions received from whitelisted peers, | ||||
// even if they were already in the mempool or rejected from it | // even if they were already in the mempool or rejected from it | ||||
// due to policy, allowing the node to function as a gateway for | // due to policy, allowing the node to function as a gateway for | ||||
// nodes hidden behind it. | // nodes hidden behind it. | ||||
// | // | ||||
// Never relay transactions that we would assign a non-zero DoS | // Never relay transactions that might result in being | ||||
// score for, as we expect peers to do the same with us in that | // disconnected (or banned). | ||||
// case. | if (state.IsInvalid() && TxRelayMayResultInDisconnect(state)) { | ||||
if (!state.IsInvalid() || | |||||
!TxRelayMayResultInDisconnect(state)) { | |||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", | |||||
tx.GetId().ToString(), pfrom->GetId()); | |||||
RelayTransaction(tx.GetId(), *connman); | |||||
} else { | |||||
LogPrintf("Not relaying invalid transaction %s from " | LogPrintf("Not relaying invalid transaction %s from " | ||||
"whitelisted peer=%d (%s)\n", | "whitelisted peer=%d (%s)\n", | ||||
tx.GetId().ToString(), pfrom->GetId(), | tx.GetId().ToString(), pfrom->GetId(), | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} else { | |||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", | |||||
tx.GetId().ToString(), pfrom->GetId()); | |||||
RelayTransaction(tx.GetId(), *connman); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
// If a tx has been detected by recentRejects, we will have reached | // If a tx has been detected by recentRejects, we will have reached | ||||
// this point and the tx will have been ignored. Because we haven't run | // this point and the tx will have been ignored. Because we haven't run | ||||
// the tx through AcceptToMemoryPool, we won't have computed a DoS | // the tx through AcceptToMemoryPool, we won't have computed a DoS | ||||
// score for it or determined exactly why we consider it invalid. | // score for it or determined exactly why we consider it invalid. | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::CMPCTBLOCK) { | ||||
received_new_header = true; | received_new_header = true; | ||||
} | } | ||||
} | } | ||||
const CBlockIndex *pindex = nullptr; | const CBlockIndex *pindex = nullptr; | ||||
CValidationState state; | CValidationState state; | ||||
if (!ProcessNewBlockHeaders(config, {cmpctblock.header}, state, | if (!ProcessNewBlockHeaders(config, {cmpctblock.header}, state, | ||||
&pindex)) { | &pindex)) { | ||||
if (state.IsInvalid() && received_new_header) { | if (state.IsInvalid()) { | ||||
// In this situation, the block header is known to be invalid. | |||||
// If we never created a CBlockIndex entry for it, then the | |||||
// header must be bad just by inspection (and is not one that | |||||
// looked okay but the block later turned out to be invalid for | |||||
// some other reason). | |||||
// We should punish compact block peers that give us an invalid | |||||
// header (other than a "duplicate-invalid" one, see | |||||
// ProcessHeadersMessage), so set via_compact_block to false | |||||
// here. | |||||
// TODO: when we switch from DoS scores to reasons that | |||||
// tx/blocks are invalid, this call should set | |||||
// via_compact_block to true, since MaybePunishNode will have | |||||
// sufficient information to act correctly. | |||||
MaybePunishNode(pfrom->GetId(), state, | MaybePunishNode(pfrom->GetId(), state, | ||||
/*via_compact_block*/ false, | /*via_compact_block*/ true, | ||||
"invalid header via cmpctblock"); | "invalid header via cmpctblock"); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// When we succeed in decoding a block's txids from a cmpctblock | // When we succeed in decoding a block's txids from a cmpctblock | ||||
// message we typically jump to the BLOCKTXN handling code, with a | // message we typically jump to the BLOCKTXN handling code, with a | ||||
// dummy (empty) BLOCKTXN message, to re-use the logic there in | // dummy (empty) BLOCKTXN message, to re-use the logic there in | ||||
▲ Show 20 Lines • Show All 1,928 Lines • Show Last 20 Lines |