Enforce mandatory softfork flags for segwit block/tx #8635

Open
wants to merge 1 commit into
from
Jump to file or symbol
Failed to load files and symbols.
+23 −8
Split
View
@@ -1122,6 +1122,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
std::vector<uint256>& 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<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks, const bool fHaveWitness)
{
if (!tx.IsCoinBase())
{
@@ -2006,15 +2008,16 @@ 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
// arguments; if so, don't trigger DoS protection to
// 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())));
}
View
@@ -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<CScriptCheck> *pvChecks = NULL);
+ unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *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);
View
@@ -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;
View
@@ -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,