From 5facf3c80f61a610b3a333a8663c284c7550bf98 Mon Sep 17 00:00:00 2001 From: lateminer <9951982+lateminer@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:12:33 +0100 Subject: [PATCH] policy: Reject transactions with witness before SegWit activates --- src/policy/policy.cpp | 9 +++++---- src/policy/policy.h | 4 ++-- src/validation.cpp | 8 +++++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 764a50f19a..be99d86b54 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -69,7 +69,7 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn)); } -bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType) +bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType, const bool witnessEnabled) { std::vector<std::vector<unsigned char> > vSolutions; whichType = Solver(scriptPubKey, vSolutions); @@ -88,12 +88,13 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_ if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) { return false; } + } else if (!witnessEnabled && (whichType == TxoutType::WITNESS_V0_SCRIPTHASH || whichType == TxoutType::WITNESS_V0_KEYHASH || whichType == TxoutType::WITNESS_V1_TAPROOT || whichType == TxoutType::WITNESS_UNKNOWN)) { + return false; } - return true; } -bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) +bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason, const bool witnessEnabled) { if ((!Params().GetConsensus().IsProtocolV3_1(tx.nTime ? (int64_t)tx.nTime : GetAdjustedTimeSeconds()) && (tx.nVersion > TX_MAX_STANDARD_VERSION-1)) || tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) { reason = "version"; @@ -133,7 +134,7 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat unsigned int nDataOut = 0; TxoutType whichType; for (const CTxOut& txout : tx.vout) { - if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) { + if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType, witnessEnabled)) { reason = "scriptpubkey"; return false; } diff --git a/src/policy/policy.h b/src/policy/policy.h index 1347d41728..8b8a10d28d 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -102,7 +102,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee); bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee); -bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType); +bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType, const bool witnessEnabled = false); // Changing the default transaction version requires a two step process: first @@ -114,7 +114,7 @@ static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2}; * Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason); +bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason, const bool witnessEnabled = false); /** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending diff --git a/src/validation.cpp b/src/validation.cpp index 9a6a751b17..a33eef9b70 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -715,9 +715,15 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (m_pool.m_require_standard && tx.nVersion >= TX_MAX_STANDARD_VERSION && !Params().GetConsensus().IsProtocolV3_1(nTimeTx)) return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "premature-version2-tx"); + // Reject transactions with witness before segregated witness activates (override with -prematurewitness) + bool witnessEnabled = DeploymentActiveAfter(m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman, Consensus::DEPLOYMENT_SEGWIT); + if (!gArgs.GetBoolArg("-prematurewitness", false) && tx.HasWitness() && !witnessEnabled) { + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "no-witness-yet"); + } + // Rather not work on nonstandard transactions (unless -testnet/-regtest) std::string reason; - if (m_pool.m_require_standard && !IsStandardTx(tx, m_pool.m_max_datacarrier_bytes, m_pool.m_permit_bare_multisig, m_pool.m_dust_relay_feerate, reason)) { + if (m_pool.m_require_standard && !IsStandardTx(tx, m_pool.m_max_datacarrier_bytes, m_pool.m_permit_bare_multisig, m_pool.m_dust_relay_feerate, reason, witnessEnabled)) { return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); }