diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -65,7 +65,7 @@ // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. - unsigned int sz = tx.GetTotalSize(); + uint32_t sz = tx.GetTotalSize(); if (sz >= MAX_STANDARD_TX_SIZE) { reason = "tx-size"; return false; @@ -147,7 +147,8 @@ } CScript subscript(stack.back().begin(), stack.back().end()); - if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { + if (subscript.GetSigOpCount(STANDARD_CHECKDATASIG_VERIFY_FLAGS, + true) > MAX_P2SH_SIGOPS) { return false; } } diff --git a/src/script/script.h b/src/script/script.h --- a/src/script/script.h +++ b/src/script/script.h @@ -619,13 +619,13 @@ * are counted more accurately, assuming they are of the form * ... OP_N CHECKMULTISIG ... */ - unsigned int GetSigOpCount(bool fAccurate) const; + uint32_t GetSigOpCount(uint32_t flags, bool fAccurate) const; /** * Accurately count sigOps, including sigOps in pay-to-script-hash * transactions: */ - unsigned int GetSigOpCount(const CScript &scriptSig) const; + uint32_t GetSigOpCount(uint32_t flags, const CScript &scriptSig) const; bool IsPayToScriptHash() const; bool IsCommitment(const std::vector &data) const; diff --git a/src/script/script.cpp b/src/script/script.cpp --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -5,6 +5,7 @@ #include "script.h" +#include "script/script_flags.h" #include "tinyformat.h" #include "utilstrencodings.h" @@ -342,8 +343,8 @@ return true; } -unsigned int CScript::GetSigOpCount(bool fAccurate) const { - unsigned int n = 0; +uint32_t CScript::GetSigOpCount(uint32_t flags, bool fAccurate) const { + uint32_t n = 0; const_iterator pc = begin(); opcodetype lastOpcode = OP_INVALIDOPCODE; while (pc < end()) { @@ -376,9 +377,10 @@ return n; } -unsigned int CScript::GetSigOpCount(const CScript &scriptSig) const { - if (!IsPayToScriptHash()) { - return GetSigOpCount(true); +uint32_t CScript::GetSigOpCount(uint32_t flags, + const CScript &scriptSig) const { + if ((flags & SCRIPT_VERIFY_P2SH) == 0 || !IsPayToScriptHash()) { + return GetSigOpCount(flags, true); } // This is a pay-to-script-hash scriptPubKey; @@ -398,7 +400,7 @@ /// ... and return its opcount: CScript subscript(data.begin(), data.end()); - return subscript.GetSigOpCount(true); + return subscript.GetSigOpCount(flags, true); } bool CScript::IsPayToScriptHash() const { diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -42,7 +42,7 @@ } // - // Check that the signature is a coumpound structure of proper size. + // Check that the signature is a compound structure of proper size. // // A signature is of type 0x30 (compound). diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -5,6 +5,7 @@ #include "consensus/consensus.h" #include "consensus/validation.h" #include "key.h" +#include "policy/policy.h" // For STANDARD_CHECKDATASIG_VERIFY_FLAGS. #include "pubkey.h" #include "script/interpreter.h" #include "script/script.h" @@ -28,15 +29,23 @@ void CheckScriptSigOps(const CScript &script, uint32_t accurate_sigops, uint32_t inaccurate_sigops) { - BOOST_CHECK_EQUAL(script.GetSigOpCount(false), inaccurate_sigops); - BOOST_CHECK_EQUAL(script.GetSigOpCount(true), accurate_sigops); + const uint32_t flags = STANDARD_CHECKDATASIG_VERIFY_FLAGS; + + BOOST_CHECK_EQUAL(script.GetSigOpCount(flags, false), inaccurate_sigops); + BOOST_CHECK_EQUAL(script.GetSigOpCount(flags, true), accurate_sigops); const CScript p2sh = GetScriptForDestination(CScriptID(script)); const CScript scriptSig = CScript() << OP_0 << Serialize(script); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), accurate_sigops); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(flags, scriptSig), accurate_sigops); + + // Check that GetSigOpCount do not report sigops in the P2SH script when the + // P2SH flags isn't passed in. + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(SCRIPT_VERIFY_NONE, scriptSig), 0U); // Check that GetSigOpCount report the exact count when not passed a P2SH. - BOOST_CHECK_EQUAL(script.GetSigOpCount(p2sh), accurate_sigops); + BOOST_CHECK_EQUAL(script.GetSigOpCount(flags, p2sh), accurate_sigops); + BOOST_CHECK_EQUAL(script.GetSigOpCount(SCRIPT_VERIFY_NONE, p2sh), + accurate_sigops); } BOOST_AUTO_TEST_CASE(GetSigOpCount) { @@ -68,7 +77,9 @@ CScript scriptSig2; scriptSig2 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << Serialize(s3); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); + BOOST_CHECK_EQUAL( + p2sh.GetSigOpCount(STANDARD_CHECKDATASIG_VERIFY_FLAGS, scriptSig2), 3U); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(SCRIPT_VERIFY_NONE, scriptSig2), 0U); } /** diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -384,10 +384,10 @@ uint64_t GetSigOpCountWithoutP2SH(const CTransaction &tx, uint32_t flags) { uint64_t nSigOps = 0; for (const auto &txin : tx.vin) { - nSigOps += txin.scriptSig.GetSigOpCount(false); + nSigOps += txin.scriptSig.GetSigOpCount(flags, false); } for (const auto &txout : tx.vout) { - nSigOps += txout.scriptPubKey.GetSigOpCount(false); + nSigOps += txout.scriptPubKey.GetSigOpCount(flags, false); } return nSigOps; } @@ -402,7 +402,7 @@ for (auto &i : tx.vin) { const CTxOut &prevout = view.GetOutputFor(i); if (prevout.scriptPubKey.IsPayToScriptHash()) { - nSigOps += prevout.scriptPubKey.GetSigOpCount(i.scriptSig); + nSigOps += prevout.scriptPubKey.GetSigOpCount(flags, i.scriptSig); } }