Verify all incoming txs unless too big or too much hashing #8593
Open
Jump to file or symbol
Failed to load files and symbols.
64
src/main.cpp
| @@ -1026,6 +1026,22 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in | ||
| return nSigOps; | ||
| } | ||
| +unsigned int GetAccurateBaseSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs, int flags) | ||
| +{ | ||
| + if (tx.IsCoinBase()) | ||
| + return 0; | ||
| + unsigned int nSigOps = 0; | ||
| + for (unsigned int i = 0; i < tx.vin.size(); i++) | ||
| + { | ||
| + nSigOps += tx.vin[i].scriptSig.GetSigOpCount(true); | ||
| + const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); | ||
| + nSigOps += prevout.scriptPubKey.GetSigOpCount(true); | ||
| + if (flags & SCRIPT_VERIFY_P2SH && prevout.scriptPubKey.IsPayToScriptHash()) | ||
| + nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); | ||
| + } | ||
| + return nSigOps; | ||
| +} | ||
| + | ||
| int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags) | ||
| { | ||
| int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR; | ||
| @@ -1260,6 +1276,34 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C | ||
| return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); | ||
| } | ||
| + int64_t nSigOpsHashing = GetWitnessStrippedTransactionWeight(tx) * GetAccurateBaseSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS) / WITNESS_SCALE_FACTOR; | ||
| + if (fRequireStandard && nSigOpsHashing > MAX_STANDARD_TX_SIGOPS_HASHING) | ||
| + return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops-hashing", false, | ||
| + strprintf("%d", nSigOpsHashing)); | ||
| + | ||
| + unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; | ||
| + if (!Params().RequireStandard()) { | ||
| + scriptVerifyFlags = GetArg("-promiscuousmempoolflags", scriptVerifyFlags); | ||
| + } | ||
| + | ||
| + // Check against previous transactions | ||
| + PrecomputedTransactionData txdata(tx); | ||
| + if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) { | ||
| + // 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 (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)) { | ||
| + // Only the witness is wrong, so the transaction itself may be fine. | ||
| + state.SetCorruptionPossible(); | ||
| + } | ||
| + return false; | ||
| + } | ||
| + | ||
| + // Now we know the witness is valid. We could check the size with witness | ||
| + if (fRequireStandard && GetTransactionWeight(tx) >= MAX_STANDARD_TX_WEIGHT) | ||
dcousens
Contributor
|
||
| + return state.DoS(0, false, REJECT_NONSTANDARD, "tx-size"); | ||
| + | ||
| // Check for non-standard pay-to-script-hash in inputs | ||
| if (fRequireStandard && !AreInputsStandard(tx, view)) | ||
| return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); | ||
| @@ -1489,26 +1533,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C | ||
| } | ||
| } | ||
| - unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; | ||
| - if (!Params().RequireStandard()) { | ||
| - scriptVerifyFlags = GetArg("-promiscuousmempoolflags", scriptVerifyFlags); | ||
| - } | ||
| - | ||
| - // 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)) { | ||
| - // 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 (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)) { | ||
| - // Only the witness is wrong, so the transaction itself may be fine. | ||
| - state.SetCorruptionPossible(); | ||
| - } | ||
| - return false; | ||
| - } | ||
| - | ||
| // Check again against just the consensus-critical mandatory script | ||
| // verification flags, in case of bugs in the standard flags that cause | ||
| // transactions to pass as valid when they're actually invalid. For | ||
can't a relay node stuff in a too-large valid witness causing this to enter rejection cache?