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);
     }