Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 2: [PATCH 02/17] feat(policy): preserve Roots parsing and local transaction checks

src/policy/policy.cpp

Before: src/policy/policy.cpp · After: src/policy/policy.cpp

File metadata
index 46ec238c3b18fd1c0a5ce35f25d1b619317dafda..d0455dd98cedea3adbc884b10ed5a1e58c570eb1 100644

Download original patch · Release notes

Diff rows 401–550 of 550. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/policy/policy.cpp CHANGED
@@ -277,9 +477,15 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) (continued)
486
+ out_reason = reason_prefix + "scriptcheck-missing";
282
487
  return false;
488
+ }
283
489
  prevScript = CScript(stack.back().begin(), stack.back().end());
284
490
  p2sh = true;
285
491
  }
@@ -289,18 +495,25 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
289
495
 
290
496
  // Non-witness program must not be associated with any witness
291
497
  if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
498
+ {
499
+ out_reason = reason_prefix + "nonwitness-input";
292
500
  return false;
501
+ }
502
+
503
+ if (GetSerializeSize(tx.vin[i].scriptWitness.stack) > g_script_size_policy_limit) {
504
+ MaybeReject("witness-size");
505
+ }
293
506
 
294
507
  // Check P2WSH standard limits
295
508
  if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
296
509
  if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
297
- return false;
510
+ MaybeReject("script-size");
298
511
  size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
299
512
  if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
300
- return false;
513
+ MaybeReject("stackitem-count");
301
514
  for (unsigned int j = 0; j < sizeWitnessStack; j++) {
302
515
  if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
303
- return false;
516
+ MaybeReject("stackitem-size");
304
517
  }
305
518
  }
306
519
 
@@ -312,17 +525,28 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
312
525
  std::span stack{tx.vin[i].scriptWitness.stack};
313
526
  if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
314
527
  // Annexes are nonstandard as long as no semantics are defined for them.
315
- return false;
528
+ MaybeReject("taproot-annex");
529
+ // If reject reason is ignored, continue as if the annex wasn't there.
530
+ SpanPopBack(stack);
316
531
  }
317
532
  if (stack.size() >= 2) {
318
533
  // Script path spend (2 or more stack elements after removing optional annex)
319
534
  const auto& control_block = SpanPopBack(stack);
320
535
  SpanPopBack(stack); // Ignore script
321
- if (control_block.empty()) return false; // Empty control block is invalid
536
+ if (control_block.empty()) {
537
+ // Empty control block is invalid
538
+ out_reason = reason_prefix + "taproot-control-missing";
539
+ return false;
540
+ }
322
541
  if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
323
542
  // Leaf version 0xc0 (aka Tapscript, see BIP 342)
543
+ if (!ignore_rejects.count(reason_prefix + "taproot-stackitem-size")) {
324
544
  for (const auto& item : stack) {
325
- if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false;
545
+ if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) {
546
+ out_reason = reason_prefix + "taproot-stackitem-size";
547
+ return false;
548
+ }
549
+ }
326
550
  }
327
551
  }
328
552
  } else if (stack.size() == 1) {
@@ -330,6 +554,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
330
554
  // (no policy rules apply)
331
555
  } else {
332
556
  // 0 stack elements; this is already invalid by consensus rules
557
+ out_reason = reason_prefix + "taproot-witness-missing";
333
558
  return false;
334
559
  }
335
560
  }
@@ -392,3 +617,78 @@ int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost, un
392
617
  {
393
618
  return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost, bytes_per_sigop);
394
619
  }
620
+
621
+ std::pair<CScript, unsigned int> GetScriptForTransactionInput(CScript prevScript, const CTxIn& txin)
622
+ {
623
+ bool p2sh = false;
624
+ if (prevScript.IsPayToScriptHash()) {
625
+ std::vector <std::vector<unsigned char> > stack;
626
+ if (!EvalScript(stack, txin.scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) {
627
+ return std::make_pair(CScript(), 0);
628
+ }
629
+ if (stack.empty()) {
630
+ return std::make_pair(CScript(), 0);
631
+ }
632
+ prevScript = CScript(stack.back().begin(), stack.back().end());
633
+ p2sh = true;
634
+ }
635
+
636
+ int witnessversion = 0;
637
+ std::vector<unsigned char> witnessprogram;
638
+
639
+ if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram)) {
640
+ // For P2SH, scriptSig is always push-only, so the actual script is only the last stack item
641
+ // For non-P2SH, prevScript is likely the real script, but not part of this transaction, and scriptSig could very well be executable, so return the latter instead
642
+ return std::make_pair(p2sh ? prevScript : txin.scriptSig, WITNESS_SCALE_FACTOR);
643
+ }
644
+
645
+ std::span stack{txin.scriptWitness.stack};
646
+
647
+ if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
648
+ if (stack.empty()) return std::make_pair(CScript(), 0); // invalid
649
+ auto& script_data = stack.back();
650
+ prevScript = CScript(script_data.begin(), script_data.end());
651
+ return std::make_pair(prevScript, 1);
652
+ }
653
+
654
+ if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) {
655
+ if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
656
+ SpanPopBack(stack);
657
+ }
658
+ if (stack.size() >= 2) {
659
+ SpanPopBack(stack); // Ignore control block
660
+ prevScript = CScript(stack.back().begin(), stack.back().end());
661
+ return std::make_pair(prevScript, 1);
662
+ }
663
+ }
664
+
665
+ return std::make_pair(CScript(), 0);
666
+ }
667
+
668
+ std::pair<size_t, size_t> DatacarrierBytes(const CTransaction& tx, const CCoinsViewCache& view)
669
+ {
670
+ std::pair<size_t, size_t> ret{0, 0};
671
+
672
+ for (const CTxIn& txin : tx.vin) {
673
+ const CTxOut &utxo = view.AccessCoin(txin.prevout).out;
674
+ auto[script, consensus_weight_per_byte] = GetScriptForTransactionInput(utxo.scriptPubKey, txin);
675
+ const auto dcb = ScriptDatacarrierBytes(script, 0, &txin.scriptWitness);
676
+ ret.first += dcb.first;
677
+ ret.second += dcb.second;
678
+ }
679
+ for (size_t i{tx.vout.size()}; i; ) {
680
+ const CTxOut& txout = tx.vout[--i];
681
+ const auto dcb = ScriptDatacarrierBytes(txout.scriptPubKey, tx.vout.size() - i);
682
+ ret.first += dcb.first;
683
+ ret.second += dcb.second;
684
+ }
685
+
686
+ return ret;
687
+ }
688
+
689
+
690
+ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& inputs)
691
+ {
692
+ std::string reason;
693
+ return IsWitnessStandard(tx, inputs, "", reason);
694
+ }