aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2020-03-27 13:07:35 +0800
committerfanquake <fanquake@gmail.com>2020-03-27 14:49:50 +0800
commit54646167db5ec86e1f532b6dcf8a1713ea026b6b (patch)
treee76d49ef9cbb9e88c152bcf8c756984e6166d6ed
parente3154aacf444a29f9f5642b6c937e875ab9a2c13 (diff)
parent2b0fcff7f26d59fed4bcafd1602325122a206c67 (diff)
downloadbitcoin-54646167db5ec86e1f532b6dcf8a1713ea026b6b.tar.xz
Merge #18388: Make VerifyWitnessProgram use a Span stack
2b0fcff7f26d59fed4bcafd1602325122a206c67 Make VerifyWitnessProgram use a Span stack (Pieter Wuille) Pull request description: Here is a follow-up to #18002, again with the goal of simplifying (potential) BIP341 code. Instead of passing a begin and end iterator of the initial stack to `ExecuteWitnessScript`, they are turned into a `Span<const valtype>`, representing a span of `valtype`s in memory. This allows `VerifyWitnessProgram` to operate on that span directly, instead of juggling iterators around (which would be exacerbated by #17977 if trying to avoid copying the stack). ACKs for top commit: ajtowns: ACK 2b0fcff7f26d59fed4bcafd1602325122a206c67 elichai: ReACK on the diff 2b0fcff7f26d59fed4bcafd1602325122a206c67 instagibbs: re-ACK https://github.com/bitcoin/bitcoin/pull/18388/commits/2b0fcff7f26d59fed4bcafd1602325122a206c67 theStack: re-ACK https://github.com/bitcoin/bitcoin/commit/2b0fcff7f26d59fed4bcafd1602325122a206c67 Empact: ACK https://github.com/bitcoin/bitcoin/commit/2b0fcff7f26d59fed4bcafd1602325122a206c67 jnewbery: utACK 2b0fcff7f26d59fed4bcafd1602325122a206c67 Tree-SHA512: 38eb4ce17f1947674c1c274caa40feb6ea8266bd96134d9cf1bc41e6fbf1114d4dde6c7a9e26e1ca8f3d0155429ef0911cc8ec0c1037d8fe7d6ec7f9e7184e93
-rw-r--r--src/script/interpreter.cpp16
-rw-r--r--src/span.h14
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<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 +1499,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);
}
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 <type_traits>
#include <cstddef>
#include <algorithm>
+#include <assert.h>
/** 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<A> MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
template<typename V>
constexpr Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type> MakeSpan(V& v) { return Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type>(v.data(), v.size()); }
+/** Pop the last element off a span, and return a reference to that element. */
+template <typename T>
+T& SpanPopBack(Span<T>& span)
+{
+ size_t size = span.size();
+ assert(size > 0);
+ T& back = span[size - 1];
+ span = Span<T>(span.data(), size - 1);
+ return back;
+}
+
#endif