@@ -67,6 +67,10 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
67
67
return (txout.nValue < GetDustThreshold (txout, dustRelayFeeIn));
68
68
}
69
69
70
+ /* *
71
+ * Note this must assign whichType even if returning false, in case
72
+ * IsStandardTx ignores the "scriptpubkey" rejection.
73
+ */
70
74
bool IsStandard (const CScript& scriptPubKey, const std::optional<unsigned >& max_datacarrier_bytes, TxoutType& whichType)
71
75
{
72
76
std::vector<std::vector<unsigned char > > vSolutions;
@@ -91,11 +95,27 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
91
95
return true ;
92
96
}
93
97
94
- bool IsStandardTx (const CTransaction& tx, const std::optional<unsigned >& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
98
+ static inline bool MaybeReject_ (std::string& out_reason, const std::string& reason, const std::string& reason_prefix, const ignore_rejects_type& ignore_rejects) {
99
+ if (ignore_rejects.count (reason_prefix + reason)) {
100
+ return false ;
101
+ }
102
+
103
+ out_reason = reason_prefix + reason;
104
+ return true ;
105
+ }
106
+
107
+ #define MaybeReject (reason ) do { \
108
+ if (MaybeReject_ (out_reason, reason, reason_prefix, ignore_rejects)) { \
109
+ return false ; \
110
+ } \
111
+ } while (0 )
112
+
113
+ bool IsStandardTx (const CTransaction& tx, const std::optional<unsigned >& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
95
114
{
115
+ const std::string reason_prefix;
116
+
96
117
if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1 ) {
97
- reason = " version" ;
98
- return false ;
118
+ MaybeReject (" version" );
99
119
}
100
120
101
121
// Extremely large transactions with lots of inputs can cost the network
@@ -104,8 +124,7 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
104
124
// to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks.
105
125
unsigned int sz = GetTransactionWeight (tx);
106
126
if (sz > MAX_STANDARD_TX_WEIGHT) {
107
- reason = " tx-size" ;
108
- return false ;
127
+ MaybeReject (" tx-size" );
109
128
}
110
129
111
130
for (const CTxIn& txin : tx.vin )
@@ -119,38 +138,39 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
119
138
// 20-of-20 CHECKMULTISIG scriptPubKey, though such a scriptPubKey
120
139
// is not considered standard.
121
140
if (txin.scriptSig .size () > MAX_STANDARD_SCRIPTSIG_SIZE) {
122
- reason = " scriptsig-size" ;
123
- return false ;
141
+ MaybeReject (" scriptsig-size" );
124
142
}
125
143
if (!txin.scriptSig .IsPushOnly ()) {
126
- reason = " scriptsig-not-pushonly" ;
127
- return false ;
144
+ MaybeReject (" scriptsig-not-pushonly" );
128
145
}
129
146
}
130
147
131
148
unsigned int nDataOut = 0 ;
132
149
TxoutType whichType;
133
150
for (const CTxOut& txout : tx.vout ) {
134
151
if (!::IsStandard (txout.scriptPubKey , max_datacarrier_bytes, whichType)) {
135
- reason = " scriptpubkey" ;
136
- return false ;
152
+ if (whichType == TxoutType::WITNESS_UNKNOWN) {
153
+ MaybeReject (" scriptpubkey-unknown-witnessversion" );
154
+ } else {
155
+ MaybeReject (" scriptpubkey" );
156
+ }
137
157
}
138
158
139
- if (whichType == TxoutType::NULL_DATA)
159
+ if (whichType == TxoutType::NULL_DATA) {
140
160
nDataOut++;
161
+ continue ;
162
+ }
141
163
else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
142
- reason = " bare-multisig" ;
143
- return false ;
144
- } else if (IsDust (txout, dust_relay_fee)) {
145
- reason = " dust" ;
146
- return false ;
164
+ MaybeReject (" bare-multisig" );
165
+ }
166
+ if (IsDust (txout, dust_relay_fee)) {
167
+ MaybeReject (" dust" );
147
168
}
148
169
}
149
170
150
171
// only one OP_RETURN txout is permitted
151
172
if (nDataOut > 1 ) {
152
- reason = " multi-op-return" ;
153
- return false ;
173
+ MaybeReject (" multi-op-return" );
154
174
}
155
175
156
176
return true ;
@@ -174,7 +194,7 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
174
194
*
175
195
* Note that only the non-witness portion of the transaction is checked here.
176
196
*/
177
- bool AreInputsStandard (const CTransaction& tx, const CCoinsViewCache& mapInputs)
197
+ bool AreInputsStandard (const CTransaction& tx, const CCoinsViewCache& mapInputs, const std::string& reason_prefix, std::string& out_reason, const ignore_rejects_type& ignore_rejects )
178
198
{
179
199
if (tx.IsCoinBase ()) {
180
200
return true ; // Coinbases don't use vin normally
@@ -185,30 +205,46 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
185
205
186
206
std::vector<std::vector<unsigned char > > vSolutions;
187
207
TxoutType whichType = Solver (prev.scriptPubKey , vSolutions);
188
- if (whichType == TxoutType::NONSTANDARD || whichType == TxoutType::WITNESS_UNKNOWN) {
208
+ if (whichType == TxoutType::NONSTANDARD) {
209
+ MaybeReject (" script-unknown" );
210
+ } else if (whichType == TxoutType::WITNESS_UNKNOWN) {
189
211
// WITNESS_UNKNOWN failures are typically also caught with a policy
190
212
// flag in the script interpreter, but it can be helpful to catch
191
213
// this type of NONSTANDARD transaction earlier in transaction
192
214
// validation.
193
- return false ;
215
+ MaybeReject ( " witness-unknown " ) ;
194
216
} else if (whichType == TxoutType::SCRIPTHASH) {
217
+ if (!tx.vin [i].scriptSig .IsPushOnly ()) {
218
+ // The only way we got this far, is if the user ignored scriptsig-not-pushonly.
219
+ // However, this case is invalid, and will be caught later on.
220
+ // But for now, we don't want to run the [possibly expensive] script here.
221
+ continue ;
222
+ }
195
223
std::vector<std::vector<unsigned char > > stack;
196
224
// convert the scriptSig into a stack, so we can inspect the redeemScript
197
225
if (!EvalScript (stack, tx.vin [i].scriptSig , SCRIPT_VERIFY_NONE, BaseSignatureChecker (), SigVersion::BASE))
226
+ {
227
+ // This case is also invalid or a bug
228
+ out_reason = reason_prefix + " scriptsig-failure" ;
198
229
return false ;
230
+ }
199
231
if (stack.empty ())
232
+ {
233
+ // Also invalid
234
+ out_reason = reason_prefix + " scriptcheck-missing" ;
200
235
return false ;
236
+ }
201
237
CScript subscript (stack.back ().begin (), stack.back ().end ());
202
238
if (subscript.GetSigOpCount (true ) > MAX_P2SH_SIGOPS) {
203
- return false ;
239
+ MaybeReject ( " scriptcheck-sigops " ) ;
204
240
}
205
241
}
206
242
}
207
243
208
244
return true ;
209
245
}
210
246
211
- bool IsWitnessStandard (const CTransaction& tx, const CCoinsViewCache& mapInputs)
247
+ bool IsWitnessStandard (const CTransaction& tx, const CCoinsViewCache& mapInputs, const std::string& reason_prefix, std::string& out_reason, const ignore_rejects_type& ignore_rejects )
212
248
{
213
249
if (tx.IsCoinBase ())
214
250
return true ; // Coinbases are skipped
@@ -227,7 +263,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
227
263
228
264
// witness stuffing detected
229
265
if (prevScript.IsPayToAnchor ()) {
230
- return false ;
266
+ MaybeReject ( " anchor-not-empty " ) ;
231
267
}
232
268
233
269
bool p2sh = false ;
@@ -237,9 +273,15 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
237
273
// into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
238
274
// If the check fails at this stage, we know that this txid must be a bad one.
239
275
if (!EvalScript (stack, tx.vin [i].scriptSig , SCRIPT_VERIFY_NONE, BaseSignatureChecker (), SigVersion::BASE))
276
+ {
277
+ out_reason = reason_prefix + " scriptsig-failure" ;
240
278
return false ;
279
+ }
241
280
if (stack.empty ())
281
+ {
282
+ out_reason = reason_prefix + " scriptcheck-missing" ;
242
283
return false ;
284
+ }
243
285
prevScript = CScript (stack.back ().begin (), stack.back ().end ());
244
286
p2sh = true ;
245
287
}
@@ -249,18 +291,21 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
249
291
250
292
// Non-witness program must not be associated with any witness
251
293
if (!prevScript.IsWitnessProgram (witnessversion, witnessprogram))
294
+ {
295
+ out_reason = reason_prefix + " nonwitness-input" ;
252
296
return false ;
297
+ }
253
298
254
299
// Check P2WSH standard limits
255
300
if (witnessversion == 0 && witnessprogram.size () == WITNESS_V0_SCRIPTHASH_SIZE) {
256
301
if (tx.vin [i].scriptWitness .stack .back ().size () > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
257
- return false ;
302
+ MaybeReject ( " script-size " ) ;
258
303
size_t sizeWitnessStack = tx.vin [i].scriptWitness .stack .size () - 1 ;
259
304
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
260
- return false ;
305
+ MaybeReject ( " stackitem-count " ) ;
261
306
for (unsigned int j = 0 ; j < sizeWitnessStack; j++) {
262
307
if (tx.vin [i].scriptWitness .stack [j].size () > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
263
- return false ;
308
+ MaybeReject ( " stackitem-size " ) ;
264
309
}
265
310
}
266
311
@@ -272,24 +317,36 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
272
317
Span stack{tx.vin [i].scriptWitness .stack };
273
318
if (stack.size () >= 2 && !stack.back ().empty () && stack.back ()[0 ] == ANNEX_TAG) {
274
319
// Annexes are nonstandard as long as no semantics are defined for them.
275
- return false ;
320
+ MaybeReject (" taproot-annex" );
321
+ // If reject reason is ignored, continue as if the annex wasn't there.
322
+ SpanPopBack (stack);
276
323
}
277
324
if (stack.size () >= 2 ) {
278
325
// Script path spend (2 or more stack elements after removing optional annex)
279
326
const auto & control_block = SpanPopBack (stack);
280
327
SpanPopBack (stack); // Ignore script
281
- if (control_block.empty ()) return false ; // Empty control block is invalid
328
+ if (control_block.empty ()) {
329
+ // Empty control block is invalid
330
+ out_reason = reason_prefix + " taproot-control-missing" ;
331
+ return false ;
332
+ }
282
333
if ((control_block[0 ] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
283
334
// Leaf version 0xc0 (aka Tapscript, see BIP 342)
335
+ if (!ignore_rejects.count (reason_prefix + " taproot-stackitem-size" )) {
284
336
for (const auto & item : stack) {
285
- if (item.size () > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false ;
337
+ if (item.size () > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) {
338
+ out_reason = reason_prefix + " taproot-stackitem-size" ;
339
+ return false ;
340
+ }
341
+ }
286
342
}
287
343
}
288
344
} else if (stack.size () == 1 ) {
289
345
// Key path spend (1 stack element after removing optional annex)
290
346
// (no policy rules apply)
291
347
} else {
292
348
// 0 stack elements; this is already invalid by consensus rules
349
+ out_reason = reason_prefix + " taproot-witness-missing" ;
293
350
return false ;
294
351
}
295
352
}
0 commit comments