diff options
-rw-r--r-- | Makefile.am | 24 | ||||
-rw-r--r-- | build_msvc/bitcoin_config.h | 3 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rwxr-xr-x | contrib/devtools/security-check.py | 10 | ||||
-rwxr-xr-x | contrib/devtools/test-security-check.py | 29 | ||||
-rw-r--r-- | src/core_read.cpp | 8 | ||||
-rw-r--r-- | src/interfaces/chain.cpp | 9 | ||||
-rw-r--r-- | src/protocol.cpp | 9 | ||||
-rw-r--r-- | src/protocol.h | 4 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 6 | ||||
-rw-r--r-- | src/script/interpreter.cpp | 16 | ||||
-rw-r--r-- | src/span.h | 14 | ||||
-rw-r--r-- | src/test/data/script_tests.json | 26 | ||||
-rw-r--r-- | src/test/data/tx_invalid.json | 2 | ||||
-rw-r--r-- | src/test/data/tx_valid.json | 6 | ||||
-rw-r--r-- | test/util/data/bitcoin-util-test.json | 40 | ||||
-rw-r--r-- | test/util/data/txcreatescript5.hex | 1 | ||||
-rw-r--r-- | test/util/data/txcreatescript6.hex | 1 |
18 files changed, 165 insertions, 45 deletions
diff --git a/Makefile.am b/Makefile.am index 5428ba93ee..c35f5080aa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,7 +68,7 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ COVERAGE_INFO = baseline.info \ test_bitcoin_filtered.info total_coverage.info \ baseline_filtered.info functional_test.info functional_test_filtered.info \ - test_bitcoin_coverage.info test_bitcoin.info + test_bitcoin_coverage.info test_bitcoin.info fuzz.info fuzz_coverage.info dist-hook: -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - @@ -199,6 +199,15 @@ baseline_filtered.info: baseline.info $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ $(LCOV) -a $@ $(LCOV_OPTS) -o $@ +fuzz.info: baseline_filtered.info + @TIMEOUT=15 test/fuzz/test_runner.py qa-assets/fuzz_seed_corpus -l DEBUG + $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t fuzz-tests -o $@ + $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src + +fuzz_filtered.info: fuzz.info + $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ + $(LCOV) -a $@ $(LCOV_OPTS) -o $@ + test_bitcoin.info: baseline_filtered.info $(MAKE) -C src/ check $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src -t test_bitcoin -o $@ @@ -217,12 +226,19 @@ functional_test_filtered.info: functional_test.info $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ $(LCOV) -a $@ $(LCOV_OPTS) -o $@ +fuzz_coverage.info: fuzz_filtered.info + $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a fuzz_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt + test_bitcoin_coverage.info: baseline_filtered.info test_bitcoin_filtered.info $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -o $@ total_coverage.info: test_bitcoin_filtered.info functional_test_filtered.info $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt +fuzz.coverage/.dirstamp: fuzz_coverage.info + $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) + @touch $@ + test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) @touch $@ @@ -231,6 +247,8 @@ total.coverage/.dirstamp: total_coverage.info $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) @touch $@ +cov_fuzz: fuzz.coverage/.dirstamp + cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp endif @@ -292,6 +310,8 @@ EXTRA_DIST += \ test/util/data/txcreatescript3.json \ test/util/data/txcreatescript4.hex \ test/util/data/txcreatescript4.json \ + test/util/data/txcreatescript5.hex \ + test/util/data/txcreatescript6.hex \ test/util/data/txcreatesignv1.hex \ test/util/data/txcreatesignv1.json \ test/util/data/txcreatesignv2.hex \ @@ -319,6 +339,6 @@ clean-docs: rm -rf doc/doxygen clean-local: clean-docs - rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP) + rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ fuzz.coverage/ test/tmp/ cache/ $(OSX_APP) rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache share/rpcauth/__pycache__ rm -rf osx_volname dist/ dpi36.background.tiff dpi72.background.tiff diff --git a/build_msvc/bitcoin_config.h b/build_msvc/bitcoin_config.h index ea304dc9fc..5f0640ac27 100644 --- a/build_msvc/bitcoin_config.h +++ b/build_msvc/bitcoin_config.h @@ -304,9 +304,6 @@ /* Define this symbol to build in assembly routines */ //#define USE_ASM 1 -/* Define this symbol if coverage is enabled */ -/* #undef USE_COVERAGE */ - /* Define if dbus support should be compiled in */ /* #undef USE_DBUS */ diff --git a/configure.ac b/configure.ac index ef87d759f1..1f85dd3a99 100644 --- a/configure.ac +++ b/configure.ac @@ -649,7 +649,6 @@ if test x$use_lcov = xyes; then [AC_MSG_ERROR("lcov testing requested but --coverage linker flag does not work")]) AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"], [AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")]) - AC_DEFINE(USE_COVERAGE, 1, [Define this symbol if coverage is enabled]) CXXFLAGS="$CXXFLAGS -Og" fi @@ -1609,6 +1608,7 @@ AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/spl AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])]) AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py]) +AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py]) AC_CONFIG_LINKS([test/util/bitcoin-util-test.py:test/util/bitcoin-util-test.py]) AC_CONFIG_LINKS([test/util/rpcauth-test.py:test/util/rpcauth-test.py]) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 21d64e893d..c05c38d513 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -197,6 +197,15 @@ def check_MACHO_NOUNDEFS(executable) -> bool: return True return False +def check_MACHO_NX(executable) -> bool: + ''' + Check for no stack execution + ''' + flags = get_MACHO_executable_flags(executable) + if 'ALLOW_STACK_EXECUTION' in flags: + return False + return True + CHECKS = { 'ELF': [ ('PIE', check_ELF_PIE), @@ -212,6 +221,7 @@ CHECKS = { 'MACHO': [ ('PIE', check_MACHO_PIE), ('NOUNDEFS', check_MACHO_NOUNDEFS), + ('NX', check_MACHO_NX) ] } diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 438d5f6bf0..e2a8154f16 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -43,16 +43,35 @@ class TestSecurityChecks(unittest.TestCase): self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']), (0, '')) - def test_64bit_PE(self): + def test_PE(self): source = 'test1.c' executable = 'test1.exe' cc = 'x86_64-w64-mingw32-gcc' write_testcode(source) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va']), (1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA NX')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va']), (1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--no-high-entropy-va']), (1, executable+': failed HIGH_ENTROPY_VA')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va']), (0, '')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va']), + (1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA NX')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va']), + (1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--no-high-entropy-va']), + (1, executable+': failed HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va']), + (0, '')) + + def test_MACHO(self): + source = 'test1.c' + executable = 'test1' + cc = 'clang' + write_testcode(source) + + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace', '-Wl,-allow_stack_execute']), + (1, executable+': failed PIE NOUNDEFS NX')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace']), + (1, executable+': failed PIE NOUNDEFS')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie']), + (1, executable+': failed PIE')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-pie']), + (0, '')) if __name__ == '__main__': unittest.main() diff --git a/src/core_read.cpp b/src/core_read.cpp index 9a65b02585..d036955641 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -59,6 +59,14 @@ CScript ParseScript(const std::string& s) { // Number int64_t n = atoi64(*w); + + //limit the range of numbers ParseScript accepts in decimal + //since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts + if (n > int64_t{0xffffffff} || n < -1 * int64_t{0xffffffff}) { + throw std::runtime_error("script parse error: decimal numeric value only allowed in the " + "range -0xFFFFFFFF...0xFFFFFFFF"); + } + result << n; } else if (w->substr(0,2) == "0x" && w->size() > 2 && IsHex(std::string(w->begin()+2, w->end()))) diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 9dc0d37cd9..775a89f4cf 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -234,11 +234,10 @@ public: explicit ChainImpl(NodeContext& node) : m_node(node) {} std::unique_ptr<Chain::Lock> lock(bool try_lock) override { - auto result = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); - if (try_lock && result && !*result) return {}; - // std::move necessary on some compilers due to conversion from - // LockImpl to Lock pointer - return std::move(result); + auto lock = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); + if (try_lock && lock && !*lock) return {}; + std::unique_ptr<Chain::Lock> result = std::move(lock); // Temporary to avoid CWG 1579 + return result; } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { diff --git a/src/protocol.cpp b/src/protocol.cpp index e49e5523ac..bd3ed25a8a 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -85,8 +85,13 @@ CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn) CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn) { memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE); - memset(pchCommand, 0, sizeof(pchCommand)); - strncpy(pchCommand, pszCommand, COMMAND_SIZE); + + // Copy the command name, zero-padding to COMMAND_SIZE bytes + size_t i = 0; + for (; i < COMMAND_SIZE && pszCommand[i] != 0; ++i) pchCommand[i] = pszCommand[i]; + assert(pszCommand[i] == 0); // Assert that the command name passed in is not longer than COMMAND_SIZE + for (; i < COMMAND_SIZE; ++i) pchCommand[i] = 0; + nMessageSize = nMessageSizeIn; memset(pchChecksum, 0, CHECKSUM_SIZE); } diff --git a/src/protocol.h b/src/protocol.h index db07efb9f9..6639ae2aac 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -37,6 +37,10 @@ public: typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; explicit CMessageHeader(const MessageStartChars& pchMessageStartIn); + + /** Construct a P2P message header from message-start characters, a command and the size of the message. + * @note Passing in a `pszCommand` longer than COMMAND_SIZE will result in a run-time assertion error. + */ CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn); std::string GetCommand() const; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d6a45dd9e0..c132f265d2 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -270,7 +270,7 @@ static UniValue waitforblock(const JSONRPCRequest& request) {RPCResult::Type::NUM, "height", "Block height"}, }}, RPCExamples{ - HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000") + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") }, }.Check(request); @@ -314,8 +314,8 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) {RPCResult::Type::NUM, "height", "Block height"}, }}, RPCExamples{ - HelpExampleCli("waitforblockheight", "\"100\", 1000") - + HelpExampleRpc("waitforblockheight", "\"100\", 1000") + HelpExampleCli("waitforblockheight", "100 1000") + + HelpExampleRpc("waitforblockheight", "100, 1000") }, }.Check(request); int timeout = 0; 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 diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 3241f32f56..c01ef307b7 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -121,9 +121,9 @@ ["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], ["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], ["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], -["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], -["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], -["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], +["0x05ffffffff7f", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["0x06000000008000", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], +["0x08ffffffffffffff7f", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], ["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], ["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], ["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], @@ -133,9 +133,9 @@ ["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], ["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], ["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], -["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], -["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], -["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], +["0x05ffffffffff", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["0x06000000008080", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], +["0x08ffffffffffffffff", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], ["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC", "OK"], ["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "OK", "SIZE does not consume argument"], @@ -360,9 +360,9 @@ ["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC", "OK"], ["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], ["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC", "OK"], -["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], -["549755813888", "0x06 0x000000008000 EQUAL", "P2SH,STRICTENC", "OK"], -["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["0x05ffffffff7f", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["0x06000000008000", "0x06 0x000000008000 EQUAL", "P2SH,STRICTENC", "OK"], +["0x08ffffffffffffff7f", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], ["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "OK", "Numbers are little-endian with the MSB being a sign bit"], ["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC", "OK"], ["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC", "OK"], @@ -373,9 +373,9 @@ ["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], ["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC", "OK"], ["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC", "OK"], -["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], -["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC", "OK"], -["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["0x05ffffffffff", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["0x06000000008080", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC", "OK"], +["0x08ffffffffffffffff", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], ["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "OK", "We can do math on 4-byte integers, and compare 5-byte ones"], ["2147483647", "1ADD 1", "P2SH,STRICTENC", "OK"], @@ -2521,7 +2521,7 @@ ["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], ["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], ["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], -["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", +["0x050000000001", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], ["MINIMALIF tests"], diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index d22175d660..3b1db449b2 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -174,7 +174,7 @@ "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument 2^32 with nLockTime=2^32-1"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 CHECKLOCKTIMEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000000001 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], ["Same, but with nLockTime=2^31-1"], diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 4a1c77166d..11634c90f0 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -292,11 +292,11 @@ "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument 3<<31 with various nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000008001 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000008001 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000008001 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["5 byte non-minimally-encoded operandss are valid"], diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index 761923a818..99cd4ab695 100644 --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -219,6 +219,12 @@ "description": "Parses a transaction with no inputs and a single output script (output in json)" }, { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:123badscript"], + "return_code": 1, + "error_txt": "error: script parse error", + "description": "Create a new transaction with an invalid output script" + }, + { "exec": "./bitcoin-tx", "args": ["-create", "outscript=0:OP_DROP", "nversion=1"], "output_cmp": "txcreatescript1.hex", "description": "Create a new transaction with a single output script (OP_DROP)" @@ -259,6 +265,40 @@ "description": "Create a new transaction with a single output script (OP_DROP) in a P2SH, wrapped in a P2SH (output as json)" }, { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:9999999999"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number above the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:4294967296"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number just above the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:4294967295"], + "output_cmp": "txcreatescript5.hex", + "description": "Try to parse an output script with a decimal number at the upper limit of the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:-9999999999"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number below the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:-4294967296"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number just below the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:-4294967295"], + "output_cmp": "txcreatescript6.hex", + "description": "Try to parse an output script with a decimal number at the lower limit of the allowed range" + }, + { "exec": "./bitcoin-tx", "args": ["-create", "nversion=1", "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", diff --git a/test/util/data/txcreatescript5.hex b/test/util/data/txcreatescript5.hex new file mode 100644 index 0000000000..48e0a12b0c --- /dev/null +++ b/test/util/data/txcreatescript5.hex @@ -0,0 +1 @@ +02000000000100000000000000000605ffffffff0000000000 diff --git a/test/util/data/txcreatescript6.hex b/test/util/data/txcreatescript6.hex new file mode 100644 index 0000000000..b98293813d --- /dev/null +++ b/test/util/data/txcreatescript6.hex @@ -0,0 +1 @@ +02000000000100000000000000000605ffffffff8000000000 |