aboutsummaryrefslogtreecommitdiff
path: root/src/policy/policy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/policy/policy.cpp')
-rw-r--r--src/policy/policy.cpp56
1 files changed, 46 insertions, 10 deletions
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 0e9820da1e..4e33fd6cb5 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -9,7 +9,7 @@
#include <consensus/validation.h>
#include <coins.h>
-
+#include <span.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
{
@@ -92,14 +92,15 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
for (const CTxIn& txin : tx.vin)
{
- // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
- // keys (remember the 520 byte limit on redeemScript size). That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
- // bytes of scriptSig, which we round off to 1650 bytes for some minor
- // future-proofing. That's also enough to spend a 20-of-20
- // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
- // considered standard.
- if (txin.scriptSig.size() > 1650) {
+ // Biggest 'standard' txin involving only keys is a 15-of-15 P2SH
+ // multisig with compressed keys (remember the 520 byte limit on
+ // redeemScript size). That works out to a (15*(33+1))+3=513 byte
+ // redeemScript, 513+1+15*(73+1)+3=1627 bytes of scriptSig, which
+ // we round off to 1650(MAX_STANDARD_SCRIPTSIG_SIZE) bytes for
+ // some minor future-proofing. That's also enough to spend a
+ // 20-of-20 CHECKMULTISIG scriptPubKey, though such a scriptPubKey
+ // is not considered standard.
+ if (txin.scriptSig.size() > MAX_STANDARD_SCRIPTSIG_SIZE) {
reason = "scriptsig-size";
return false;
}
@@ -155,7 +156,7 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
*
* Note that only the non-witness portion of the transaction is checked here.
*/
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active)
{
if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
@@ -183,6 +184,9 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
return false;
}
+ } else if (whichType == TxoutType::WITNESS_V1_TAPROOT) {
+ // Don't allow Taproot spends unless Taproot is active.
+ if (!taproot_active) return false;
}
}
@@ -206,6 +210,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// get the scriptPubKey corresponding to this input:
CScript prevScript = prev.scriptPubKey;
+ bool p2sh = false;
if (prevScript.IsPayToScriptHash()) {
std::vector <std::vector<unsigned char> > stack;
// If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
@@ -216,6 +221,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
if (stack.empty())
return false;
prevScript = CScript(stack.back().begin(), stack.back().end());
+ p2sh = true;
}
int witnessversion = 0;
@@ -237,6 +243,36 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
return false;
}
}
+
+ // Check policy limits for Taproot spends:
+ // - MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE limit for stack item size
+ // - No annexes
+ if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) {
+ // Taproot spend (non-P2SH-wrapped, version 1, witness program size 32; see BIP 341)
+ auto stack = MakeSpan(tx.vin[i].scriptWitness.stack);
+ if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
+ // Annexes are nonstandard as long as no semantics are defined for them.
+ return false;
+ }
+ if (stack.size() >= 2) {
+ // Script path spend (2 or more stack elements after removing optional annex)
+ const auto& control_block = SpanPopBack(stack);
+ SpanPopBack(stack); // Ignore script
+ if (control_block.empty()) return false; // Empty control block is invalid
+ if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
+ // Leaf version 0xc0 (aka Tapscript, see BIP 342)
+ for (const auto& item : stack) {
+ if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false;
+ }
+ }
+ } else if (stack.size() == 1) {
+ // Key path spend (1 stack element after removing optional annex)
+ // (no policy rules apply)
+ } else {
+ // 0 stack elements; this is already invalid by consensus rules
+ return false;
+ }
+ }
}
return true;
}