aboutsummaryrefslogtreecommitdiff
path: root/src/script/interpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/interpreter.cpp')
-rw-r--r--src/script/interpreter.cpp85
1 files changed, 55 insertions, 30 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 5bf418472a..23d5b72a5c 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -342,6 +342,35 @@ public:
};
}
+/** Helper for OP_CHECKSIG and OP_CHECKSIGVERIFY
+ *
+ * A return value of false means the script fails entirely. When true is returned, the
+ * fSuccess variable indicates whether the signature check itself succeeded.
+ */
+static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
+{
+ // Subset of script starting at the most recent codeseparator
+ CScript scriptCode(pbegincodehash, pend);
+
+ // Drop the signature in pre-segwit scripts but not segwit scripts
+ if (sigversion == SigVersion::BASE) {
+ 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)) {
+ //serror is set
+ return false;
+ }
+ fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
+
+ if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
+ return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
+
+ return true;
+}
+
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
@@ -985,25 +1014,8 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
valtype& vchSig = stacktop(-2);
valtype& vchPubKey = stacktop(-1);
- // Subset of script starting at the most recent codeseparator
- CScript scriptCode(pbegincodehash, pend);
-
- // Drop the signature in pre-segwit scripts but not segwit scripts
- if (sigversion == SigVersion::BASE) {
- 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)) {
- //serror is set
- return false;
- }
- bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
-
- if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
- return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
-
+ bool fSuccess = true;
+ if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, flags, checker, sigversion, serror, fSuccess)) return false;
popstack(stack);
popstack(stack);
stack.push_back(fSuccess ? vchTrue : vchFalse);
@@ -1279,18 +1291,29 @@ uint256 GetOutputsHash(const T& txTo)
} // namespace
template <class T>
-PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
+void PrecomputedTransactionData::Init(const T& txTo)
{
+ assert(!m_ready);
+
// Cache is calculated only for transactions with witness
if (txTo.HasWitness()) {
hashPrevouts = GetPrevoutHash(txTo);
hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo);
- ready = true;
}
+
+ m_ready = true;
+}
+
+template <class T>
+PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
+{
+ Init(txTo);
}
// explicit instantiation
+template void PrecomputedTransactionData::Init(const CTransaction& txTo);
+template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
@@ -1303,7 +1326,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
- const bool cacheready = cache && cache->ready;
+ const bool cacheready = cache && cache->m_ready;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
@@ -1478,9 +1501,9 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
-static bool ExecuteWitnessScript(std::vector<valtype>::const_iterator begin, std::vector<valtype>::const_iterator end, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror)
+static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror)
{
- std::vector<valtype> stack{begin, end};
+ std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
// Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
for (const valtype& elem : stack) {
@@ -1499,27 +1522,29 @@ static bool ExecuteWitnessScript(std::vector<valtype>::const_iterator begin, std
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
CScript scriptPubKey;
+ Span<const valtype> stack = MakeSpan(witness.stack);
if (witversion == 0) {
if (program.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
// Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness
- if (witness.stack.size() == 0) {
+ if (stack.size() == 0) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
}
- scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
+ const valtype& script_bytes = SpanPopBack(stack);
+ scriptPubKey = CScript(script_bytes.begin(), script_bytes.end());
uint256 hashScriptPubKey;
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
- return ExecuteWitnessScript(witness.stack.begin(), witness.stack.end() - 1, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
+ return ExecuteWitnessScript(stack, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
} else if (program.size() == WITNESS_V0_KEYHASH_SIZE) {
// Special case for pay-to-pubkeyhash; signature + pubkey in witness
- if (witness.stack.size() != 2) {
+ if (stack.size() != 2) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
}
scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
- return ExecuteWitnessScript(witness.stack.begin(), witness.stack.end(), scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
+ return ExecuteWitnessScript(stack, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
} else {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
}