From 234d2e63cb8245f2b05e45abdfee837e26b92b4d Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Thu, 8 Sep 2016 21:56:30 +0800 Subject: [PATCH] Enforce mandatory softfork flags for segwit block/tx --- src/main.cpp | 17 ++++++++++------- src/main.h | 2 +- src/policy/policy.h | 2 ++ src/script/standard.h | 10 ++++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d32a7e9be5c..12105eb1a88 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1122,6 +1122,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C std::vector& vHashTxnToUncache) { const uint256 hash = tx.GetHash(); + const bool fHaveWitness = !tx.wit.IsNull(); + unsigned int mandatoryScriptVerifyFlags = fHaveWitness ? MANDATORY_SEGWIT_SCRIPT_VERIFY_FLAGS : MANDATORY_SCRIPT_VERIFY_FLAGS; AssertLockHeld(cs_main); if (pfMissingInputs) *pfMissingInputs = false; @@ -1497,12 +1499,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. PrecomputedTransactionData txdata(tx); - if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) { + if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata, NULL, fHaveWitness)) { // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we // need to turn both off, and compare against just turning off CLEANSTACK // to see if the failure is specifically due to witness validation. - if (tx.wit.IsNull() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) && - !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) { + if (tx.wit.IsNull() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata, NULL, fHaveWitness) && + !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata, NULL, fHaveWitness)) { // Only the witness is missing, so the transaction itself may be fine. state.SetCorruptionPossible(); } @@ -1518,7 +1520,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks, however allowing such transactions into the mempool // can be exploited as a DoS attack. - if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata)) + if (!CheckInputs(tx, state, view, true, mandatoryScriptVerifyFlags, true, txdata, NULL, fHaveWitness)) { return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); @@ -1974,7 +1976,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins } }// namespace Consensus -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector *pvChecks) +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector *pvChecks, const bool fHaveWitness) { if (!tx.IsCoinBase()) { @@ -2006,7 +2008,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); } else if (!check()) { - if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { + unsigned int notMandatoryScriptVerifyFlags = fHaveWitness ? STANDARD_NOT_MANDATORY_SEGWIT_VERIFY_FLAGS : STANDARD_NOT_MANDATORY_VERIFY_FLAGS; + if (flags & notMandatoryScriptVerifyFlags) { // Check whether the failure was caused by a // non-mandatory script verification check, such as // non-standard DER encodings or non-null dummy @@ -2014,7 +2017,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // avoid splitting the network between upgraded and // non-upgraded nodes. CScriptCheck check2(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata); + flags & ~notMandatoryScriptVerifyFlags, cacheStore, &txdata); if (check2()) return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } diff --git a/src/main.h b/src/main.h index 18d674612f9..85812114961 100644 --- a/src/main.h +++ b/src/main.h @@ -348,7 +348,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i * instead of being performed inline. */ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = NULL); + unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = NULL, const bool fHaveWitness = false); /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); diff --git a/src/policy/policy.h b/src/policy/policy.h index 6bf5ca0ee55..47d010dd901 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -51,6 +51,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY /** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; +static const unsigned int STANDARD_NOT_MANDATORY_SEGWIT_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SEGWIT_SCRIPT_VERIFY_FLAGS; + /** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */ static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST; diff --git a/src/script/standard.h b/src/script/standard.h index 72aaea0b7be..3e99c9c520a 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -42,6 +42,16 @@ extern unsigned nMaxDatacarrierBytes; */ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; +/** + * If a transaction contains any witness data, it must comply with + * all known soft-fork rules at the time of segwit activation. + */ +static const unsigned int MANDATORY_SEGWIT_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | + SCRIPT_VERIFY_DERSIG | + SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | + SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | + SCRIPT_VERIFY_WITNESS; + enum txnouttype { TX_NONSTANDARD,