diff --git a/src/script/interpreter.h b/src/script/interpreter.h --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -31,7 +31,7 @@ public: virtual bool VerifySignature(const std::vector &vchSig, const CPubKey &vchPubKey, - const uint256 &sighash) const; + const uint256 &sighash, uint32_t flags) const; virtual bool CheckSig(const std::vector &vchSigIn, const std::vector &vchPubKey, diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -942,7 +942,8 @@ .Write(vchMessage.data(), vchMessage.size()) .Finalize(vchHash.data()); fSuccess = checker.VerifySignature( - vchSig, CPubKey(vchPubKey), uint256(vchHash)); + vchSig, CPubKey(vchPubKey), uint256(vchHash), + flags); } if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && @@ -1464,7 +1465,13 @@ bool BaseSignatureChecker::VerifySignature(const std::vector &vchSig, const CPubKey &pubkey, - const uint256 &sighash) const { + const uint256 &sighash, + uint32_t flags) const { + /** + * This function is memoized by sigcache.cpp. If there are dependencies on + * flags, either explicit or implicit, they should be noted in sigcache.cpp + * by making sure said flags are omitted from INVARIANT_FLAGS. + */ return pubkey.VerifyECDSA(sighash, vchSig); } @@ -1487,7 +1494,7 @@ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount, this->txdata, flags); - if (!VerifySignature(vchSig, pubkey, sighash)) { + if (!VerifySignature(vchSig, pubkey, sighash, flags)) { return false; } diff --git a/src/script/sigcache.h b/src/script/sigcache.h --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -52,8 +52,8 @@ store(storeIn) {} bool VerifySignature(const std::vector &vchSig, - const CPubKey &vchPubKey, - const uint256 &sighash) const override; + const CPubKey &vchPubKey, const uint256 &sighash, + uint32_t flags) const override; }; void InitSignatureCache(); diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -16,6 +16,22 @@ namespace { +/** + * Declare which flags absolutely do not affect VerifySignature() result. + * The caching code in sighash.cpp uses this to reduce unnecessary cache + * misses (such as when policy and consensus flags differ on unrelated + * aspects). + */ +static const uint32_t INVARIANT_FLAGS = + SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_DERSIG | + SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_NULLDUMMY | SCRIPT_VERIFY_SIGPUSHONLY | + SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | + SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | + SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_MINIMALIF | + SCRIPT_VERIFY_NULLFAIL | SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE | + SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION | + SCRIPT_ENABLE_CHECKDATASIG; + /** * Valid signature cache, to avoid doing expensive ECDSA signature checking * twice for every transaction (once when accepted into memory pool, and @@ -23,7 +39,8 @@ */ class CSignatureCache { private: - //! Entries are SHA256(nonce || signature hash || public key || signature): + //! Entries are SHA256(nonce || signature || public key || signature hash || + //! flags): uint256 nonce; typedef CuckooCache::cache map_type; map_type setValid; @@ -32,14 +49,16 @@ public: CSignatureCache() { GetRandBytes(nonce.begin(), 32); } - void ComputeEntry(uint256 &entry, const uint256 &hash, - const std::vector &vchSig, - const CPubKey &pubkey) { + void ComputeEntry(uint256 &entry, const std::vector &vchSig, + const CPubKey &pubkey, const uint256 &hash, + uint32_t flags) { + flags &= ~INVARIANT_FLAGS; CSHA256() .Write(nonce.begin(), 32) - .Write(hash.begin(), 32) - .Write(&pubkey[0], pubkey.size()) .Write(&vchSig[0], vchSig.size()) + .Write(&pubkey[0], pubkey.size()) + .Write(hash.begin(), 32) + .Write(reinterpret_cast(&flags), sizeof(flags)) .Finalize(entry.begin()); } @@ -82,14 +101,14 @@ bool CachingTransactionSignatureChecker::VerifySignature( const std::vector &vchSig, const CPubKey &pubkey, - const uint256 &sighash) const { + const uint256 &sighash, uint32_t flags) const { uint256 entry; - signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); + signatureCache.ComputeEntry(entry, vchSig, pubkey, sighash, flags); if (signatureCache.Get(entry, !store)) { return true; } - if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, - sighash)) { + if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash, + flags)) { return false; } if (store) {