diff options
Diffstat (limited to 'src/script/interpreter.cpp')
-rw-r--r-- | src/script/interpreter.cpp | 63 |
1 files changed, 48 insertions, 15 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e0d193fa38..4b982d647d 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -336,6 +336,10 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& opcode == OP_RSHIFT) return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes. + // With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in non-segwit script is rejected even in an unexecuted branch + if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE)) + return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR); + if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { return set_error(serror, SCRIPT_ERR_MINIMALDATA); @@ -899,6 +903,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& case OP_CODESEPARATOR: { + // If SCRIPT_VERIFY_CONST_SCRIPTCODE flag is set, use of OP_CODESEPARATOR is rejected in pre-segwit + // script, even in an unexecuted branch (this is checked above the opcode case statement). + // Hash starts after the code separator pbegincodehash = pc; } @@ -919,7 +926,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& // Drop the signature in pre-segwit scripts but not segwit scripts if (sigversion == SigVersion::BASE) { - FindAndDelete(scriptCode, CScript(vchSig)); + int found = FindAndDelete(scriptCode, CScript(vchSig)); + if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE)) + return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE); } if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) { @@ -983,7 +992,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& { valtype& vchSig = stacktop(-isig-k); if (sigversion == SigVersion::BASE) { - FindAndDelete(scriptCode, CScript(vchSig)); + int found = FindAndDelete(scriptCode, CScript(vchSig)); + if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE)) + return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE); } } @@ -1078,9 +1089,11 @@ namespace { * Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ -class CTransactionSignatureSerializer { +template <class T> +class CTransactionSignatureSerializer +{ private: - const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized) + const T& txTo; //!< reference to the spending transaction (the one being serialized) const CScript& scriptCode; //!< output script being consumed const unsigned int nIn; //!< input index of txTo being signed const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set @@ -1088,7 +1101,7 @@ private: const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE public: - CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : + CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), @@ -1169,7 +1182,9 @@ public: } }; -uint256 GetPrevoutHash(const CTransaction& txTo) { +template <class T> +uint256 GetPrevoutHash(const T& txTo) +{ CHashWriter ss(SER_GETHASH, 0); for (const auto& txin : txTo.vin) { ss << txin.prevout; @@ -1177,7 +1192,9 @@ uint256 GetPrevoutHash(const CTransaction& txTo) { return ss.GetHash(); } -uint256 GetSequenceHash(const CTransaction& txTo) { +template <class T> +uint256 GetSequenceHash(const T& txTo) +{ CHashWriter ss(SER_GETHASH, 0); for (const auto& txin : txTo.vin) { ss << txin.nSequence; @@ -1185,7 +1202,9 @@ uint256 GetSequenceHash(const CTransaction& txTo) { return ss.GetHash(); } -uint256 GetOutputsHash(const CTransaction& txTo) { +template <class T> +uint256 GetOutputsHash(const T& txTo) +{ CHashWriter ss(SER_GETHASH, 0); for (const auto& txout : txTo.vout) { ss << txout; @@ -1195,7 +1214,8 @@ uint256 GetOutputsHash(const CTransaction& txTo) { } // namespace -PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) +template <class T> +PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo) { // Cache is calculated only for transactions with witness if (txTo.HasWitness()) { @@ -1206,7 +1226,12 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) } } -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) +// explicit instantiation +template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo); +template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo); + +template <class T> +uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { assert(nIn < txTo.vin.size()); @@ -1267,7 +1292,7 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig } // Wrapper to serialize only the necessary parts of the transaction being signed - CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); + CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); @@ -1275,12 +1300,14 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +template <class T> +bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { return pubkey.Verify(sighash, vchSig); } -bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1301,7 +1328,8 @@ bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vch return true; } -bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const { // There are two kinds of nLockTime: lock-by-blockheight // and lock-by-blocktime, distinguished by whether @@ -1337,7 +1365,8 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con return true; } -bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSequence) const { // Relative lock times are supported by comparing the passed // in operand to the sequence number of the input. @@ -1383,6 +1412,10 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con return true; } +// explicit instantiation +template class GenericTransactionSignatureChecker<CTransaction>; +template class GenericTransactionSignatureChecker<CMutableTransaction>; + static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { std::vector<std::vector<unsigned char> > stack; |