mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 15:19:07 +01:00
[validation] Add CValidationState subclasses
Split CValidationState into TxValidationState and BlockValidationState to store validation results for transactions and blocks respectively.
This commit is contained in:
@@ -982,14 +982,12 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
|
||||
* 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)
|
||||
{
|
||||
assert(IsTransactionReason(state.GetReason()));
|
||||
return state.GetReason() == ValidationInvalidReason::CONSENSUS;
|
||||
static bool TxRelayMayResultInDisconnect(const TxValidationState& state) {
|
||||
return state.GetResult() == TxValidationResult::TX_CONSENSUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Potentially ban a node based on the contents of a CValidationState object
|
||||
* Potentially ban a node based on the contents of a BlockValidationState object
|
||||
*
|
||||
* @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 a compact
|
||||
@@ -997,23 +995,21 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state)
|
||||
* 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, bool via_compact_block, const std::string& message = "") {
|
||||
switch (state.GetReason()) {
|
||||
case ValidationInvalidReason::NONE:
|
||||
static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "") {
|
||||
switch (state.GetResult()) {
|
||||
case BlockValidationResult::BLOCK_RESULT_UNSET:
|
||||
break;
|
||||
// The node is providing invalid data:
|
||||
case ValidationInvalidReason::CONSENSUS:
|
||||
case ValidationInvalidReason::BLOCK_MUTATED:
|
||||
case BlockValidationResult::BLOCK_CONSENSUS:
|
||||
case BlockValidationResult::BLOCK_MUTATED:
|
||||
if (!via_compact_block) {
|
||||
LOCK(cs_main);
|
||||
Misbehaving(nodeid, 100, message);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ValidationInvalidReason::CACHED_INVALID:
|
||||
case BlockValidationResult::BLOCK_CACHED_INVALID:
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CNodeState *node_state = State(nodeid);
|
||||
@@ -1029,30 +1025,24 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ValidationInvalidReason::BLOCK_INVALID_HEADER:
|
||||
case ValidationInvalidReason::BLOCK_CHECKPOINT:
|
||||
case ValidationInvalidReason::BLOCK_INVALID_PREV:
|
||||
case BlockValidationResult::BLOCK_INVALID_HEADER:
|
||||
case BlockValidationResult::BLOCK_CHECKPOINT:
|
||||
case BlockValidationResult::BLOCK_INVALID_PREV:
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(nodeid, 100, message);
|
||||
}
|
||||
return true;
|
||||
// Conflicting (but not necessarily invalid) data or different policy:
|
||||
case ValidationInvalidReason::BLOCK_MISSING_PREV:
|
||||
case BlockValidationResult::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_PREMATURE_SPEND:
|
||||
case ValidationInvalidReason::TX_WITNESS_MUTATED:
|
||||
case ValidationInvalidReason::TX_CONFLICT:
|
||||
case ValidationInvalidReason::TX_MEMPOOL_POLICY:
|
||||
case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
|
||||
case BlockValidationResult::BLOCK_TIME_FUTURE:
|
||||
break;
|
||||
}
|
||||
if (message != "") {
|
||||
@@ -1061,6 +1051,39 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Potentially ban a node based on the contents of a TxValidationState object
|
||||
*
|
||||
* @return Returns true if the peer was punished (probably disconnected)
|
||||
*
|
||||
* Changes here may need to be reflected in TxRelayMayResultInDisconnect().
|
||||
*/
|
||||
static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") {
|
||||
switch (state.GetResult()) {
|
||||
case TxValidationResult::TX_RESULT_UNSET:
|
||||
break;
|
||||
// The node is providing invalid data:
|
||||
case TxValidationResult::TX_CONSENSUS:
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(nodeid, 100, message);
|
||||
return true;
|
||||
}
|
||||
// Conflicting (but not necessarily invalid) data or different policy:
|
||||
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
|
||||
case TxValidationResult::TX_NOT_STANDARD:
|
||||
case TxValidationResult::TX_MISSING_INPUTS:
|
||||
case TxValidationResult::TX_PREMATURE_SPEND:
|
||||
case TxValidationResult::TX_WITNESS_MUTATED:
|
||||
case TxValidationResult::TX_CONFLICT:
|
||||
case TxValidationResult::TX_MEMPOOL_POLICY:
|
||||
break;
|
||||
}
|
||||
if (message != "") {
|
||||
LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1229,7 +1252,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
|
||||
* Handle invalid block rejection and consequent peer banning, maintain which
|
||||
* peers announce compact blocks.
|
||||
*/
|
||||
void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
|
||||
void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
||||
LOCK(cs_main);
|
||||
|
||||
const uint256 hash(block.GetHash());
|
||||
@@ -1240,7 +1263,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
|
||||
if (state.IsInvalid() &&
|
||||
it != mapBlockSource.end() &&
|
||||
State(it->second.first)) {
|
||||
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||
MaybePunishNodeForBlock(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||
}
|
||||
// Check that:
|
||||
// 1. The block is valid
|
||||
@@ -1378,7 +1401,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
|
||||
}
|
||||
} // release cs_main before calling ActivateBestChain
|
||||
if (need_activate_chain) {
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!ActivateBestChain(state, Params(), a_recent_block)) {
|
||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||
}
|
||||
@@ -1674,11 +1697,11 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
|
||||
}
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
CBlockHeader first_invalid_header;
|
||||
if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
|
||||
if (state.IsInvalid()) {
|
||||
MaybePunishNode(pfrom->GetId(), state, via_compact_block, "invalid header received");
|
||||
MaybePunishNodeForBlock(pfrom->GetId(), state, via_compact_block, "invalid header received");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1815,10 +1838,10 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
|
||||
const CTransaction& orphanTx = *porphanTx;
|
||||
NodeId fromPeer = orphan_it->second.fromPeer;
|
||||
bool fMissingInputs2 = false;
|
||||
// Use a new CValidationState because orphans come from different peers (and we call
|
||||
// MaybePunishNode based on the source peer from the orphan map, not based on the peer
|
||||
// Use a new TxValidationState because orphans come from different peers (and we call
|
||||
// MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer
|
||||
// that relayed the previous transaction).
|
||||
CValidationState orphan_state;
|
||||
TxValidationState orphan_state;
|
||||
|
||||
if (setMisbehaving.count(fromPeer)) continue;
|
||||
if (AcceptToMemoryPool(mempool, orphan_state, porphanTx, &fMissingInputs2, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||
@@ -1837,7 +1860,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
|
||||
} else if (!fMissingInputs2) {
|
||||
if (orphan_state.IsInvalid()) {
|
||||
// Punish peer that gave us an invalid orphan tx
|
||||
if (MaybePunishNode(fromPeer, orphan_state, /*via_compact_block*/ false)) {
|
||||
if (MaybePunishNodeForTx(fromPeer, orphan_state)) {
|
||||
setMisbehaving.insert(fromPeer);
|
||||
}
|
||||
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
||||
@@ -1845,8 +1868,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
|
||||
// Has inputs but not accepted to mempool
|
||||
// Probably non-standard or insufficient fee
|
||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
||||
assert(IsTransactionReason(orphan_state.GetReason()));
|
||||
if (!orphanTx.HasWitness() && orphan_state.GetReason() != ValidationInvalidReason::TX_WITNESS_MUTATED) {
|
||||
if (!orphanTx.HasWitness() && orphan_state.GetResult() != TxValidationResult::TX_WITNESS_MUTATED) {
|
||||
// Do not use rejection cache for witness transactions or
|
||||
// witness-stripped transactions, as they can have been malleated.
|
||||
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
||||
@@ -2291,7 +2313,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
LOCK(cs_most_recent_block);
|
||||
a_recent_block = most_recent_block;
|
||||
}
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!ActivateBestChain(state, Params(), a_recent_block)) {
|
||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||
}
|
||||
@@ -2472,7 +2494,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
LOCK2(cs_main, g_cs_orphans);
|
||||
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
TxValidationState state;
|
||||
|
||||
CNodeState* nodestate = State(pfrom->GetId());
|
||||
nodestate->m_tx_download.m_tx_announced.erase(inv.hash);
|
||||
@@ -2537,8 +2559,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
recentRejects->insert(tx.GetHash());
|
||||
}
|
||||
} else {
|
||||
assert(IsTransactionReason(state.GetReason()));
|
||||
if (!tx.HasWitness() && state.GetReason() != ValidationInvalidReason::TX_WITNESS_MUTATED) {
|
||||
if (!tx.HasWitness() && state.GetResult() != TxValidationResult::TX_WITNESS_MUTATED) {
|
||||
// Do not use rejection cache for witness transactions or
|
||||
// witness-stripped transactions, as they can have been malleated.
|
||||
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
||||
@@ -2593,7 +2614,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
|
||||
pfrom->GetId(),
|
||||
FormatStateMessage(state));
|
||||
MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ false);
|
||||
MaybePunishNodeForTx(pfrom->GetId(), state);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2627,10 +2648,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
}
|
||||
|
||||
const CBlockIndex *pindex = nullptr;
|
||||
CValidationState state;
|
||||
BlockValidationState state;
|
||||
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
||||
if (state.IsInvalid()) {
|
||||
MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
|
||||
MaybePunishNodeForBlock(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user