From 2b0fcff7f26d59fed4bcafd1602325122a206c67 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 17 Mar 2020 20:02:48 -0700 Subject: Make VerifyWitnessProgram use a Span stack This allows for very cheap transformations on the range of elements that are to be passed to ExecuteWitnessScript. --- src/script/interpreter.cpp | 16 +++++++++------- src/span.h | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 5bf418472a..083022fbdd 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1478,9 +1478,9 @@ bool GenericTransactionSignatureChecker::CheckSequence(const CScriptNum& nSeq template class GenericTransactionSignatureChecker; template class GenericTransactionSignatureChecker; -static bool ExecuteWitnessScript(std::vector::const_iterator begin, std::vector::const_iterator end, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror) +static bool ExecuteWitnessScript(const Span& stack_span, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror) { - std::vector stack{begin, end}; + std::vector 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 +1499,29 @@ static bool ExecuteWitnessScript(std::vector::const_iterator begin, std static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { CScript scriptPubKey; + Span 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); } diff --git a/src/span.h b/src/span.h index 77de059fa6..9379b15c81 100644 --- a/src/span.h +++ b/src/span.h @@ -8,6 +8,7 @@ #include #include #include +#include /** A Span is an object that can refer to a contiguous sequence of objects. * @@ -27,6 +28,8 @@ public: constexpr C* data() const noexcept { return m_data; } constexpr C* begin() const noexcept { return m_data; } constexpr C* end() const noexcept { return m_data + m_size; } + constexpr C& front() const noexcept { return m_data[0]; } + constexpr C& back() const noexcept { return m_data[m_size - 1]; } constexpr std::ptrdiff_t size() const noexcept { return m_size; } constexpr C& operator[](std::ptrdiff_t pos) const noexcept { return m_data[pos]; } @@ -57,4 +60,15 @@ constexpr Span MakeSpan(A (&a)[N]) { return Span(a, N); } template constexpr Span().data())>::type> MakeSpan(V& v) { return Span().data())>::type>(v.data(), v.size()); } +/** Pop the last element off a span, and return a reference to that element. */ +template +T& SpanPopBack(Span& span) +{ + size_t size = span.size(); + assert(size > 0); + T& back = span[size - 1]; + span = Span(span.data(), size - 1); + return back; +} + #endif -- cgit v1.2.3