aboutsummaryrefslogtreecommitdiff
path: root/src/consensus/validation.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/consensus/validation.h')
-rw-r--r--src/consensus/validation.h85
1 files changed, 80 insertions, 5 deletions
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 163b17e629..787b171eea 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -22,6 +22,50 @@ static const unsigned char REJECT_NONSTANDARD = 0x40;
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
static const unsigned char REJECT_CHECKPOINT = 0x43;
+/** A "reason" why something was invalid, suitable for determining whether the
+ * provider of the object should be banned/ignored/disconnected/etc.
+ * These are much more granular than the rejection codes, which may be more
+ * useful for some other use-cases.
+ */
+enum class ValidationInvalidReason {
+ // txn and blocks:
+ NONE, //!< not actually invalid
+ CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
+ /**
+ * Invalid by a change to consensus rules more recent than SegWit.
+ * Currently unused as there are no such consensus rule changes, and any download
+ * sources realistically need to support SegWit in order to provide useful data,
+ * so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
+ * is uninteresting.
+ */
+ RECENT_CONSENSUS_CHANGE,
+ // Only blocks (or headers):
+ CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why
+ BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
+ BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
+ BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
+ BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
+ BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
+ BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
+ // Only loose txn:
+ TX_NOT_STANDARD, //!< didn't meet our local policy rules
+ TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs (or its inputs were spent at < coinbase maturity height)
+ /**
+ * Transaction might be missing a witness, have a witness prior to SegWit
+ * activation, or witness may have been malleated (which includes
+ * non-standard witnesses).
+ */
+ TX_WITNESS_MUTATED,
+ /**
+ * Tx already in mempool or conflicts with a tx in the chain
+ * (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
+ * TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
+ * TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
+ */
+ TX_CONFLICT,
+ TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits
+};
+
/** Capture information about block/transaction validation */
class CValidationState {
private:
@@ -30,31 +74,35 @@ private:
MODE_INVALID, //!< network rule violation (DoS value may be set)
MODE_ERROR, //!< run-time error
} mode;
+ ValidationInvalidReason m_reason;
int nDoS;
std::string strRejectReason;
unsigned int chRejectCode;
bool corruptionPossible;
std::string strDebugMessage;
public:
- CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {}
- bool DoS(int level, bool ret = false,
+ CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), nDoS(0), chRejectCode(0), corruptionPossible(false) {}
+ bool DoS(int level, ValidationInvalidReason reasonIn, bool ret = false,
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
bool corruptionIn=false,
const std::string &strDebugMessageIn="") {
+ m_reason = reasonIn;
chRejectCode = chRejectCodeIn;
strRejectReason = strRejectReasonIn;
corruptionPossible = corruptionIn;
strDebugMessage = strDebugMessageIn;
+ nDoS += level;
+ assert(nDoS == GetDoSForReason());
+ assert(corruptionPossible == (m_reason == ValidationInvalidReason::BLOCK_MUTATED || m_reason == ValidationInvalidReason::TX_WITNESS_MUTATED));
if (mode == MODE_ERROR)
return ret;
- nDoS += level;
mode = MODE_INVALID;
return ret;
}
- bool Invalid(bool ret = false,
+ bool Invalid(ValidationInvalidReason _reason, bool ret = false,
unsigned int _chRejectCode=0, const std::string &_strRejectReason="",
const std::string &_strDebugMessage="") {
- return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage);
+ return DoS(0, _reason, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage);
}
bool Error(const std::string& strRejectReasonIn) {
if (mode == MODE_VALID)
@@ -72,12 +120,39 @@ public:
return mode == MODE_ERROR;
}
bool CorruptionPossible() const {
+ assert(corruptionPossible == (m_reason == ValidationInvalidReason::BLOCK_MUTATED || m_reason == ValidationInvalidReason::TX_WITNESS_MUTATED));
return corruptionPossible;
}
void SetCorruptionPossible() {
corruptionPossible = true;
+ assert(corruptionPossible == (m_reason == ValidationInvalidReason::BLOCK_MUTATED || m_reason == ValidationInvalidReason::TX_WITNESS_MUTATED));
}
int GetDoS(void) const { return nDoS; }
+ int GetDoSForReason() const {
+ switch (m_reason) {
+ case ValidationInvalidReason::NONE:
+ return 0;
+ case ValidationInvalidReason::CONSENSUS:
+ case ValidationInvalidReason::BLOCK_MUTATED:
+ case ValidationInvalidReason::BLOCK_INVALID_HEADER:
+ case ValidationInvalidReason::BLOCK_CHECKPOINT:
+ case ValidationInvalidReason::BLOCK_INVALID_PREV:
+ return 100;
+ case ValidationInvalidReason::BLOCK_MISSING_PREV:
+ return 10;
+ case ValidationInvalidReason::CACHED_INVALID:
+ case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
+ case ValidationInvalidReason::BLOCK_TIME_FUTURE:
+ case ValidationInvalidReason::TX_NOT_STANDARD:
+ case ValidationInvalidReason::TX_MISSING_INPUTS:
+ case ValidationInvalidReason::TX_WITNESS_MUTATED:
+ case ValidationInvalidReason::TX_CONFLICT:
+ case ValidationInvalidReason::TX_MEMPOOL_POLICY:
+ return 0;
+ }
+ return 0;
+ }
+ ValidationInvalidReason GetReason() const { return m_reason; }
unsigned int GetRejectCode() const { return chRejectCode; }
std::string GetRejectReason() const { return strRejectReason; }
std::string GetDebugMessage() const { return strDebugMessage; }