@@ -22,6 +22,50 @@ static const unsigned char REJECT_NONSTANDARD = 0x40;
22
22
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42 ;
23
23
static const unsigned char REJECT_CHECKPOINT = 0x43 ;
24
24
25
+ /* * A "reason" why something was invalid, suitable for determining whether the
26
+ * provider of the object should be banned/ignored/disconnected/etc.
27
+ * These are much more granular than the rejection codes, which may be more
28
+ * useful for some other use-cases.
29
+ */
30
+ enum class ValidationInvalidReason {
31
+ // txn and blocks:
32
+ NONE, // !< not actually invalid
33
+ CONSENSUS, // !< invalid by consensus rules (excluding any below reasons)
34
+ /* *
35
+ * Invalid by a change to consensus rules more recent than SegWit.
36
+ * Currently unused as there are no such consensus rule changes, and any download
37
+ * sources realistically need to support SegWit in order to provide useful data,
38
+ * so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
39
+ * is uninteresting.
40
+ */
41
+ RECENT_CONSENSUS_CHANGE,
42
+ // Only blocks (or headers):
43
+ CACHED_INVALID, // !< this object was cached as being invalid, but we don't know why
44
+ BLOCK_INVALID_HEADER, // !< invalid proof of work or time too old
45
+ BLOCK_MUTATED, // !< the block's data didn't match the data committed to by the PoW
46
+ BLOCK_MISSING_PREV, // !< We don't have the previous block the checked one is built on
47
+ BLOCK_INVALID_PREV, // !< A block this one builds on is invalid
48
+ BLOCK_TIME_FUTURE, // !< block timestamp was > 2 hours in the future (or our clock is bad)
49
+ BLOCK_CHECKPOINT, // !< the block failed to meet one of our checkpoints
50
+ // Only loose txn:
51
+ TX_NOT_STANDARD, // !< didn't meet our local policy rules
52
+ TX_MISSING_INPUTS, // !< a transaction was missing some of its inputs (or its inputs were spent at < coinbase maturity height)
53
+ /* *
54
+ * Transaction might be missing a witness, have a witness prior to SegWit
55
+ * activation, or witness may have been malleated (which includes
56
+ * non-standard witnesses).
57
+ */
58
+ TX_WITNESS_MUTATED,
59
+ /* *
60
+ * Tx already in mempool or conflicts with a tx in the chain
61
+ * (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
62
+ * TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
63
+ * TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
64
+ */
65
+ TX_CONFLICT,
66
+ TX_MEMPOOL_POLICY, // !< violated mempool's fee/size/descendant/RBF/etc limits
67
+ };
68
+
25
69
/* * Capture information about block/transaction validation */
26
70
class CValidationState {
27
71
private:
@@ -30,31 +74,35 @@ class CValidationState {
30
74
MODE_INVALID, // !< network rule violation (DoS value may be set)
31
75
MODE_ERROR, // !< run-time error
32
76
} mode;
77
+ ValidationInvalidReason m_reason;
33
78
int nDoS;
34
79
std::string strRejectReason;
35
80
unsigned int chRejectCode;
36
81
bool corruptionPossible;
37
82
std::string strDebugMessage;
38
83
public:
39
- CValidationState () : mode(MODE_VALID), nDoS(0 ), chRejectCode(0 ), corruptionPossible(false ) {}
40
- bool DoS (int level, bool ret = false ,
84
+ CValidationState () : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), nDoS(0 ), chRejectCode(0 ), corruptionPossible(false ) {}
85
+ bool DoS (int level, ValidationInvalidReason reasonIn, bool ret = false ,
41
86
unsigned int chRejectCodeIn=0 , const std::string &strRejectReasonIn=" " ,
42
87
bool corruptionIn=false ,
43
88
const std::string &strDebugMessageIn=" " ) {
89
+ m_reason = reasonIn;
44
90
chRejectCode = chRejectCodeIn;
45
91
strRejectReason = strRejectReasonIn;
46
92
corruptionPossible = corruptionIn;
47
93
strDebugMessage = strDebugMessageIn;
94
+ nDoS += level;
95
+ assert (nDoS == GetDoSForReason ());
96
+ assert (corruptionPossible == (m_reason == ValidationInvalidReason::BLOCK_MUTATED || m_reason == ValidationInvalidReason::TX_WITNESS_MUTATED));
48
97
if (mode == MODE_ERROR)
49
98
return ret;
50
- nDoS += level;
51
99
mode = MODE_INVALID;
52
100
return ret;
53
101
}
54
- bool Invalid (bool ret = false ,
102
+ bool Invalid (ValidationInvalidReason _reason, bool ret = false ,
55
103
unsigned int _chRejectCode=0 , const std::string &_strRejectReason=" " ,
56
104
const std::string &_strDebugMessage=" " ) {
57
- return DoS (0 , ret, _chRejectCode, _strRejectReason, false , _strDebugMessage);
105
+ return DoS (0 , _reason, ret, _chRejectCode, _strRejectReason, false , _strDebugMessage);
58
106
}
59
107
bool Error (const std::string& strRejectReasonIn) {
60
108
if (mode == MODE_VALID)
@@ -72,12 +120,39 @@ class CValidationState {
72
120
return mode == MODE_ERROR;
73
121
}
74
122
bool CorruptionPossible () const {
123
+ assert (corruptionPossible == (m_reason == ValidationInvalidReason::BLOCK_MUTATED || m_reason == ValidationInvalidReason::TX_WITNESS_MUTATED));
75
124
return corruptionPossible;
76
125
}
77
126
void SetCorruptionPossible () {
78
127
corruptionPossible = true ;
128
+ assert (corruptionPossible == (m_reason == ValidationInvalidReason::BLOCK_MUTATED || m_reason == ValidationInvalidReason::TX_WITNESS_MUTATED));
79
129
}
80
130
int GetDoS (void ) const { return nDoS; }
131
+ int GetDoSForReason () const {
132
+ switch (m_reason) {
133
+ case ValidationInvalidReason::NONE:
134
+ return 0 ;
135
+ case ValidationInvalidReason::CONSENSUS:
136
+ case ValidationInvalidReason::BLOCK_MUTATED:
137
+ case ValidationInvalidReason::BLOCK_INVALID_HEADER:
138
+ case ValidationInvalidReason::BLOCK_CHECKPOINT:
139
+ case ValidationInvalidReason::BLOCK_INVALID_PREV:
140
+ return 100 ;
141
+ case ValidationInvalidReason::BLOCK_MISSING_PREV:
142
+ return 10 ;
143
+ case ValidationInvalidReason::CACHED_INVALID:
144
+ case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
145
+ case ValidationInvalidReason::BLOCK_TIME_FUTURE:
146
+ case ValidationInvalidReason::TX_NOT_STANDARD:
147
+ case ValidationInvalidReason::TX_MISSING_INPUTS:
148
+ case ValidationInvalidReason::TX_WITNESS_MUTATED:
149
+ case ValidationInvalidReason::TX_CONFLICT:
150
+ case ValidationInvalidReason::TX_MEMPOOL_POLICY:
151
+ return 0 ;
152
+ }
153
+ return 0 ;
154
+ }
155
+ ValidationInvalidReason GetReason () const { return m_reason; }
81
156
unsigned int GetRejectCode () const { return chRejectCode; }
82
157
std::string GetRejectReason () const { return strRejectReason; }
83
158
std::string GetDebugMessage () const { return strDebugMessage; }
0 commit comments