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. Before is on the left; after is on the right. Unified view fits narrow screens more easily.
src/policy/policy.cpp
CHANGED
|
@@ -277,9 +477,15 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) (continued)
|
|
|
|
|
| 282 |
return false;
|
|
|
|
| 283 |
prevScript = CScript(stack.back().begin(), stack.back().end());
|
| 284 |
p2sh = true;
|
| 285 |
}
|
|
@@ -289,18 +495,25 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|
| 289 |
|
| 290 |
// Non-witness program must not be associated with any witness
|
| 291 |
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
|
|
|
|
|
|
|
| 292 |
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
|
| 294 |
// Check P2WSH standard limits
|
| 295 |
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
|
| 296 |
if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
|
| 297 |
-
return false;
|
| 298 |
size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
|
| 299 |
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
|
| 300 |
-
return false;
|
| 301 |
for (unsigned int j = 0; j < sizeWitnessStack; j++) {
|
| 302 |
if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
|
| 303 |
-
return false;
|
| 304 |
}
|
| 305 |
}
|
| 306 |
|
|
@@ -312,17 +525,28 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|
| 312 |
std::span stack{tx.vin[i].scriptWitness.stack};
|
| 313 |
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
|
| 314 |
// Annexes are nonstandard as long as no semantics are defined for them.
|
| 315 |
-
return false;
|
|
|
|
|
|
|
| 316 |
}
|
| 317 |
if (stack.size() >= 2) {
|
| 318 |
// Script path spend (2 or more stack elements after removing optional annex)
|
| 319 |
const auto& control_block = SpanPopBack(stack);
|
| 320 |
SpanPopBack(stack); // Ignore script
|
| 321 |
-
if (control_block.empty()) return false; // Empty control block is invalid
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
|
| 323 |
// Leaf version 0xc0 (aka Tapscript, see BIP 342)
|
|
|
|
| 324 |
for (const auto& item : stack) {
|
| 325 |
-
if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
}
|
| 327 |
}
|
| 328 |
} else if (stack.size() == 1) {
|
|
@@ -330,6 +554,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|
| 330 |
// (no policy rules apply)
|
| 331 |
} else {
|
| 332 |
// 0 stack elements; this is already invalid by consensus rules
|
|
|
|
| 333 |
return false;
|
| 334 |
}
|
| 335 |
}
|
|
@@ -392,3 +617,78 @@ int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost, un
|
|
| 392 |
{
|
| 393 |
return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost, bytes_per_sigop);
|
| 394 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
+
out_reason = reason_prefix + "scriptcheck-missing";
|
| 487 |
return false;
|
| 488 |
+
}
|
| 489 |
prevScript = CScript(stack.back().begin(), stack.back().end());
|
| 490 |
p2sh = true;
|
| 491 |
}
|
|
|
|
| 495 |
|
| 496 |
// Non-witness program must not be associated with any witness
|
| 497 |
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
|
| 498 |
+
{
|
| 499 |
+
out_reason = reason_prefix + "nonwitness-input";
|
| 500 |
return false;
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
if (GetSerializeSize(tx.vin[i].scriptWitness.stack) > g_script_size_policy_limit) {
|
| 504 |
+
MaybeReject("witness-size");
|
| 505 |
+
}
|
| 506 |
|
| 507 |
// Check P2WSH standard limits
|
| 508 |
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
|
| 509 |
if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
|
| 510 |
+
MaybeReject("script-size");
|
| 511 |
size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
|
| 512 |
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
|
| 513 |
+
MaybeReject("stackitem-count");
|
| 514 |
for (unsigned int j = 0; j < sizeWitnessStack; j++) {
|
| 515 |
if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
|
| 516 |
+
MaybeReject("stackitem-size");
|
| 517 |
}
|
| 518 |
}
|
| 519 |
|
|
|
|
| 525 |
std::span stack{tx.vin[i].scriptWitness.stack};
|
| 526 |
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
|
| 527 |
// Annexes are nonstandard as long as no semantics are defined for them.
|
| 528 |
+
MaybeReject("taproot-annex");
|
| 529 |
+
// If reject reason is ignored, continue as if the annex wasn't there.
|
| 530 |
+
SpanPopBack(stack);
|
| 531 |
}
|
| 532 |
if (stack.size() >= 2) {
|
| 533 |
// Script path spend (2 or more stack elements after removing optional annex)
|
| 534 |
const auto& control_block = SpanPopBack(stack);
|
| 535 |
SpanPopBack(stack); // Ignore script
|
| 536 |
+
if (control_block.empty()) {
|
| 537 |
+
// Empty control block is invalid
|
| 538 |
+
out_reason = reason_prefix + "taproot-control-missing";
|
| 539 |
+
return false;
|
| 540 |
+
}
|
| 541 |
if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
|
| 542 |
// Leaf version 0xc0 (aka Tapscript, see BIP 342)
|
| 543 |
+
if (!ignore_rejects.count(reason_prefix + "taproot-stackitem-size")) {
|
| 544 |
for (const auto& item : stack) {
|
| 545 |
+
if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) {
|
| 546 |
+
out_reason = reason_prefix + "taproot-stackitem-size";
|
| 547 |
+
return false;
|
| 548 |
+
}
|
| 549 |
+
}
|
| 550 |
}
|
| 551 |
}
|
| 552 |
} else if (stack.size() == 1) {
|
|
|
|
| 554 |
// (no policy rules apply)
|
| 555 |
} else {
|
| 556 |
// 0 stack elements; this is already invalid by consensus rules
|
| 557 |
+
out_reason = reason_prefix + "taproot-witness-missing";
|
| 558 |
return false;
|
| 559 |
}
|
| 560 |
}
|
|
|
|
| 617 |
{
|
| 618 |
return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost, bytes_per_sigop);
|
| 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 |
+
}
|