diff --git a/src/Makefile.test.include b/src/Makefile.test.include index afaa224186..260977ace5 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,190 +1,191 @@ # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. TESTS += test/test_bitcoin LOG_DRIVER = $(srcdir)/test/test-bitcoin-driver EXTRA_DIST += test/test-bitcoin-driver bin_PROGRAMS += test/test_bitcoin noinst_PROGRAMS += test/test_bitcoin_fuzzy TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) JSON_TEST_FILES = \ test/data/script_tests.json \ test/data/base58_keys_valid.json \ test/data/base58_encode_decode.json \ test/data/base58_keys_invalid.json \ test/data/tx_invalid.json \ test/data/tx_valid.json \ test/data/sighash.json RAW_TEST_FILES = GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) # test_bitcoin binary # BITCOIN_TESTS =\ test/arith_uint256_tests.cpp \ test/scriptnum10.h \ test/addrman_tests.cpp \ test/amount_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bip32_tests.cpp \ test/blockcheck_tests.cpp \ test/blockencodings_tests.cpp \ test/blockindex_tests.cpp \ test/blockstatus_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ test/cashaddr_tests.cpp \ test/cashaddrenc_tests.cpp \ test/checkdatasig_tests.cpp \ test/checkpoints_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/config_tests.cpp \ test/core_io_tests.cpp \ test/crypto_tests.cpp \ test/cuckoocache_tests.cpp \ test/dbwrapper_tests.cpp \ test/DoS_tests.cpp \ test/dstencode_tests.cpp \ test/excessiveblock_tests.cpp \ test/getarg_tests.cpp \ test/hash_tests.cpp \ test/inv_tests.cpp \ test/jsonutil.cpp \ test/jsonutil.h \ test/key_tests.cpp \ test/limitedmap_tests.cpp \ test/main_tests.cpp \ test/mempool_tests.cpp \ test/merkle_tests.cpp \ test/miner_tests.cpp \ test/monolith_opcodes.cpp \ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ test/prevector_tests.cpp \ test/raii_event_tests.cpp \ test/random_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ test/sanity_tests.cpp \ test/scheduler_tests.cpp \ test/script_commitment_tests.cpp \ test/script_P2SH_tests.cpp \ test/script_tests.cpp \ test/scriptflags.cpp \ test/scriptflags.h \ test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ + test/sigencoding_tests.cpp \ test/sighash_tests.cpp \ test/sighashtype_tests.cpp \ test/sigopcount_tests.cpp \ test/sigutil.cpp \ test/sigutil.h \ test/skiplist_tests.cpp \ test/streams_tests.cpp \ test/test_bitcoin.cpp \ test/test_bitcoin.h \ test/test_bitcoin_main.cpp \ test/testutil.cpp \ test/testutil.h \ test/timedata_tests.cpp \ test/transaction_tests.cpp \ test/txvalidationcache_tests.cpp \ test/versionbits_tests.cpp \ test/uint256_tests.cpp \ test/undo_tests.cpp \ test/univalue_tests.cpp \ test/util_tests.cpp \ test/validation_tests.cpp \ test/work_comparator_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ wallet/test/wallet_test_fixture.cpp \ wallet/test/wallet_test_fixture.h \ wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/walletdb_tests.cpp \ wallet/test/crypto_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) test_test_bitcoin_LDADD = if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static if ENABLE_ZMQ test_test_bitcoin_LDADD += $(ZMQ_LIBS) endif # # test_bitcoin_fuzzy binary # test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_test_bitcoin_fuzzy_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) $(BITCOIN_TESTS): $(GENERATED_TEST_FILES) CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) bitcoin_test: $(TEST_BINARY) bitcoin_test_check: $(TEST_BINARY) FORCE $(MAKE) check-TESTS TESTS=$^ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: @echo "Running test/util/bitcoin-util-test.py..." $(top_builddir)/test/util/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check endif %.json.h: %.json @$(MKDIR_P) $(@D) @{ \ echo "namespace json_tests{" && \ echo "static unsigned const char $(*F)[] = {" && \ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ echo "};};"; \ } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 80c4ee0b98..ed68666248 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,160 +1,161 @@ # Copyright (c) 2018 The Bitcoin developers project(bitcoin-test) # Process json files. find_program(PYTHON python) function(gen_json_header NAME) set(HEADERS "") foreach(f ${ARGN}) set(h "${CMAKE_CURRENT_BINARY_DIR}/${f}.h") # Get the proper name for the test variable. get_filename_component(TEST_NAME ${f} NAME_WE) add_custom_command(OUTPUT ${h} COMMAND ${PYTHON} ARGS "${CMAKE_CURRENT_SOURCE_DIR}/data/generate_header.py" "${TEST_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/${f}" > ${h} MAIN_DEPENDENCY ${f} DEPENDS "data/generate_header.py" VERBATIM ) list(APPEND HEADERS ${h}) endforeach(f) set(${NAME} "${HEADERS}" PARENT_SCOPE) endfunction() gen_json_header(JSON_HEADERS data/script_tests.json data/base58_keys_valid.json data/base58_encode_decode.json data/base58_keys_invalid.json data/tx_invalid.json data/tx_valid.json data/sighash.json ) include(TestSuite) create_test_suite(bitcoin) add_dependencies(check check-bitcoin) add_test_to_suite(bitcoin test_bitcoin arith_uint256_tests.cpp addrman_tests.cpp amount_tests.cpp allocator_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp bip32_tests.cpp blockcheck_tests.cpp blockencodings_tests.cpp blockindex_tests.cpp blockstatus_tests.cpp bloom_tests.cpp bswap_tests.cpp cashaddr_tests.cpp cashaddrenc_tests.cpp checkdatasig_tests.cpp checkpoints_tests.cpp coins_tests.cpp compress_tests.cpp config_tests.cpp core_io_tests.cpp crypto_tests.cpp cuckoocache_tests.cpp dbwrapper_tests.cpp DoS_tests.cpp dstencode_tests.cpp excessiveblock_tests.cpp getarg_tests.cpp hash_tests.cpp inv_tests.cpp jsonutil.cpp key_tests.cpp limitedmap_tests.cpp main_tests.cpp mempool_tests.cpp merkle_tests.cpp miner_tests.cpp monolith_opcodes.cpp multisig_tests.cpp net_tests.cpp netbase_tests.cpp pmt_tests.cpp policyestimator_tests.cpp pow_tests.cpp prevector_tests.cpp raii_event_tests.cpp random_tests.cpp reverselock_tests.cpp rpc_tests.cpp sanity_tests.cpp scheduler_tests.cpp script_commitment_tests.cpp script_P2SH_tests.cpp script_tests.cpp scriptflags.cpp scriptnum_tests.cpp serialize_tests.cpp + sigencoding_tests.cpp sighash_tests.cpp sighashtype_tests.cpp sigopcount_tests.cpp sigutil.cpp skiplist_tests.cpp streams_tests.cpp test_bitcoin.cpp test_bitcoin_main.cpp testutil.cpp timedata_tests.cpp transaction_tests.cpp txvalidationcache_tests.cpp versionbits_tests.cpp uint256_tests.cpp undo_tests.cpp univalue_tests.cpp util_tests.cpp validation_tests.cpp work_comparator_tests.cpp # Tests generated from JSON ${JSON_HEADERS} ) target_include_directories(test_bitcoin PUBLIC # To access the generated json headers. ${CMAKE_CURRENT_BINARY_DIR} PRIVATE ${OPENSSL_INCLUDE_DIR} ) find_package(Boost 1.58 REQUIRED unit_test_framework) target_link_libraries(test_bitcoin Boost::unit_test_framework rpcclient server) # We need to detect if the BOOST_TEST_DYN_LINK flag is required. set(CMAKE_REQUIRED_LIBRARIES Boost::unit_test_framework) check_cxx_source_compiles(" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include " BOOST_TEST_DYN_LINK) if(BOOST_TEST_DYN_LINK) target_compile_definitions(test_bitcoin PRIVATE BOOST_TEST_DYN_LINK) endif(BOOST_TEST_DYN_LINK) if(BUILD_BITCOIN_WALLET) target_sources(test_bitcoin PRIVATE ../wallet/test/wallet_test_fixture.cpp ../wallet/test/accounting_tests.cpp ../wallet/test/wallet_tests.cpp ../wallet/test/walletdb_tests.cpp ../wallet/test/crypto_tests.cpp ) endif() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 5f49e4addf..7c0b111c2b 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -1,439 +1,441 @@ // Copyright (c) 2012-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "core_io.h" #include "key.h" #include "keystore.h" #include "policy/policy.h" #include "script/ismine.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" #include "test/test_bitcoin.h" #include "validation.h" #include #include // Helpers: static std::vector Serialize(const CScript &s) { std::vector sSerialized(s.begin(), s.end()); return sSerialized; } static bool Verify(const CScript &scriptSig, const CScript &scriptPubKey, bool fStrict, ScriptError &err) { // Create dummy to/from transactions: CMutableTransaction txFrom; txFrom.vout.resize(1); txFrom.vout[0].scriptPubKey = scriptPubKey; CMutableTransaction txTo; txTo.vin.resize(1); txTo.vout.resize(1); txTo.vin[0].prevout = COutPoint(txFrom.GetId(), 0); txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = Amount(1); return VerifyScript( scriptSig, scriptPubKey, (fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE) | SCRIPT_ENABLE_SIGHASH_FORKID, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); } BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sign) { LOCK(cs_main); // Pay-to-script-hash looks like this: // scriptSig: // scriptPubKey: HASH160 EQUAL // Test SignSignature() (and therefore the version of Solver() that signs // transactions) CBasicKeyStore keystore; CKey key[4]; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); } // 8 Scripts: checking all combinations of // different keys, straight/P2SH, pubkey/pubkeyhash CScript standardScripts[4]; standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID()); standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID()); CScript evalScripts[4]; for (int i = 0; i < 4; i++) { keystore.AddCScript(standardScripts[i]); evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); } CMutableTransaction txFrom; // Funding transaction: std::string reason; txFrom.vout.resize(8); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = evalScripts[i]; txFrom.vout[i].nValue = COIN; txFrom.vout[i + 4].scriptPubKey = standardScripts[i]; txFrom.vout[i + 4].nValue = COIN; } BOOST_CHECK(IsStandardTx(CTransaction(txFrom), reason)); CMutableTransaction txTo[8]; // Spending transactions for (int i = 0; i < 8; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout = COutPoint(txFrom.GetId(), i); txTo[i].vout[0].nValue = Amount(1); BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); } for (int i = 0; i < 8; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SigHashType().withForkId()), strprintf("SignSignature %d", i)); } // All of the above should be OK, and the txTos have valid signatures // Check to make sure signature verification fails if we use the wrong // ScriptSig: for (int i = 0; i < 8; i++) { CTransaction tx(txTo[i]); PrecomputedTransactionData txdata(tx); for (int j = 0; j < 8; j++) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; const CTxOut &output = txFrom.vout[txTo[i].vin[0].prevout.GetN()]; bool sigOK = CScriptCheck( output.scriptPubKey, output.nValue, CTransaction(txTo[i]), 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID, false, txdata)(); if (i == j) { BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); } else { BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j)); } txTo[i].vin[0].scriptSig = sigSave; } } } BOOST_AUTO_TEST_CASE(norecurse) { ScriptError err; // Make sure only the outer pay-to-script-hash does the // extra-validation thing: CScript invalidAsScript; invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript)); CScript scriptSig; scriptSig << Serialize(invalidAsScript); // Should not verify, because it will try to execute OP_INVALIDOPCODE BOOST_CHECK(!Verify(scriptSig, p2sh, true, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err)); // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh)); CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(set) { LOCK(cs_main); // Test the CScript::Set* methods CBasicKeyStore keystore; CKey key[4]; std::vector keys; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); keys.push_back(key[i].GetPubKey()); } CScript inner[4]; inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID()); inner[1] = GetScriptForMultisig( 2, std::vector(keys.begin(), keys.begin() + 2)); inner[2] = GetScriptForMultisig( 1, std::vector(keys.begin(), keys.begin() + 2)); inner[3] = GetScriptForMultisig( 2, std::vector(keys.begin(), keys.begin() + 3)); CScript outer[4]; for (int i = 0; i < 4; i++) { outer[i] = GetScriptForDestination(CScriptID(inner[i])); keystore.AddCScript(inner[i]); } // Funding transaction: CMutableTransaction txFrom; std::string reason; txFrom.vout.resize(4); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = outer[i]; txFrom.vout[i].nValue = CENT; } BOOST_CHECK(IsStandardTx(CTransaction(txFrom), reason)); // Spending transactions CMutableTransaction txTo[4]; for (int i = 0; i < 4; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout = COutPoint(txFrom.GetId(), i); txTo[i].vout[0].nValue = 1 * CENT; txTo[i].vout[0].scriptPubKey = inner[i]; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); } for (int i = 0; i < 4; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SigHashType().withForkId()), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(IsStandardTx(CTransaction(txTo[i]), reason), strprintf("txTo[%d].IsStandard", i)); } } BOOST_AUTO_TEST_CASE(is) { // Test CScript::IsPayToScriptHash() uint160 dummy; CScript p2sh; p2sh << OP_HASH160 << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(p2sh.IsPayToScriptHash()); // Not considered pay-to-script-hash if using one of the OP_PUSHDATA // opcodes: static const uint8_t direct[] = {OP_HASH160, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK(CScript(direct, direct + sizeof(direct)).IsPayToScriptHash()); static const uint8_t pushdata1[] = {OP_HASH160, OP_PUSHDATA1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK( !CScript(pushdata1, pushdata1 + sizeof(pushdata1)).IsPayToScriptHash()); static const uint8_t pushdata2[] = {OP_HASH160, OP_PUSHDATA2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK( !CScript(pushdata2, pushdata2 + sizeof(pushdata2)).IsPayToScriptHash()); static const uint8_t pushdata4[] = {OP_HASH160, OP_PUSHDATA4, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK( !CScript(pushdata4, pushdata4 + sizeof(pushdata4)).IsPayToScriptHash()); CScript not_p2sh; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); not_p2sh.clear(); not_p2sh << OP_NOP << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << OP_CHECKSIG; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); } BOOST_AUTO_TEST_CASE(switchover) { // Test switch over code CScript notValid; ScriptError err; notValid << OP_11 << OP_12 << OP_EQUALVERIFY; CScript scriptSig; scriptSig << Serialize(notValid); CScript fund = GetScriptForDestination(CScriptID(notValid)); // Validation should succeed under old rules (hash is correct): BOOST_CHECK(Verify(scriptSig, fund, false, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); // Fail under new: BOOST_CHECK(!Verify(scriptSig, fund, true, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(AreInputsStandard) { LOCK(cs_main); CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); CBasicKeyStore keystore; CKey key[6]; std::vector keys; for (int i = 0; i < 6; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); } - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { keys.push_back(key[i].GetPubKey()); + } CMutableTransaction txFrom; txFrom.vout.resize(7); // First three are standard: CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); keystore.AddCScript(pay1); CScript pay1of3 = GetScriptForMultisig(1, keys); // P2SH (OP_CHECKSIG) txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); txFrom.vout[0].nValue = Amount(1000); // ordinary OP_CHECKSIG txFrom.vout[1].scriptPubKey = pay1; txFrom.vout[1].nValue = Amount(2000); // ordinary OP_CHECKMULTISIG txFrom.vout[2].scriptPubKey = pay1of3; txFrom.vout[2].nValue = Amount(3000); // vout[3] is complicated 1-of-3 AND 2-of-3 // ... that is OK if wrapped in P2SH: CScript oneAndTwo; oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()); oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY; oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey()); oneAndTwo << OP_3 << OP_CHECKMULTISIG; keystore.AddCScript(oneAndTwo); txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); txFrom.vout[3].nValue = Amount(4000); // vout[4] is max sigops: CScript fifteenSigops; fifteenSigops << OP_1; - for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++) + for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++) { fifteenSigops << ToByteVector(key[i % 3].GetPubKey()); + } fifteenSigops << OP_15 << OP_CHECKMULTISIG; keystore.AddCScript(fifteenSigops); txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); txFrom.vout[4].nValue = Amount(5000); // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG; keystore.AddCScript(sixteenSigops); txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); txFrom.vout[5].nValue = Amount(5000); CScript twentySigops; twentySigops << OP_CHECKMULTISIG; keystore.AddCScript(twentySigops); txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops)); txFrom.vout[6].nValue = Amount(6000); AddCoins(coins, CTransaction(txFrom), 0); CMutableTransaction txTo; txTo.vout.resize(1); txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txTo.vin.resize(5); for (int i = 0; i < 5; i++) { txTo.vin[i].prevout = COutPoint(txFrom.GetId(), i); } BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType().withForkId())); BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 1, SigHashType().withForkId())); BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 2, SigHashType().withForkId())); // SignSignature doesn't know how to sign these. We're not testing // validating signatures, so just create dummy signatures that DO include // the correct P2SH scripts: txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector(oneAndTwo.begin(), oneAndTwo.end()); txTo.vin[4].scriptSig << std::vector(fifteenSigops.begin(), fifteenSigops.end()); BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txTo), coins), 22U); CMutableTransaction txToNonStd1; txToNonStd1.vout.resize(1); txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txToNonStd1.vout[0].nValue = Amount(1000); txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout = COutPoint(txFrom.GetId(), 5); txToNonStd1.vin[0].scriptSig << std::vector(sixteenSigops.begin(), sixteenSigops.end()); BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd1), coins), 16U); CMutableTransaction txToNonStd2; txToNonStd2.vout.resize(1); txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txToNonStd2.vout[0].nValue = Amount(1000); txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout = COutPoint(txFrom.GetId(), 6); txToNonStd2.vin[0].scriptSig << std::vector(twentySigops.begin(), twentySigops.end()); BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd2), coins), 20U); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 0b60b03483..ff933eaed7 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,1872 +1,1871 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "data/script_tests.json.h" #include "core_io.h" #include "key.h" #include "keystore.h" #include "rpc/server.h" #include "script/script.h" #include "script/script_error.h" #include "script/sighashtype.h" #include "script/sign.h" #include "test/jsonutil.h" #include "test/scriptflags.h" #include "test/sigutil.h" #include "test/test_bitcoin.h" #include "util.h" #include "utilstrencodings.h" #if defined(HAVE_CONSENSUS_LIB) #include "script/bitcoinconsensus.h" #endif #include #include #include #include #include #include // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; struct ScriptErrorDesc { ScriptError_t err; const char *name; }; static ScriptErrorDesc script_errors[] = { {SCRIPT_ERR_OK, "OK"}, {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"}, {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"}, {SCRIPT_ERR_OP_RETURN, "OP_RETURN"}, {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"}, {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"}, {SCRIPT_ERR_OP_COUNT, "OP_COUNT"}, {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"}, {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"}, {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"}, {SCRIPT_ERR_INVALID_OPERAND_SIZE, "OPERAND_SIZE"}, {SCRIPT_ERR_INVALID_NUMBER_RANGE, "INVALID_NUMBER_RANGE"}, {SCRIPT_ERR_IMPOSSIBLE_ENCODING, "IMPOSSIBLE_ENCODING"}, {SCRIPT_ERR_INVALID_SPLIT_RANGE, "SPLIT_RANGE"}, {SCRIPT_ERR_VERIFY, "VERIFY"}, {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"}, {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"}, {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"}, {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"}, {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"}, {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"}, {SCRIPT_ERR_SIG_DER, "SIG_DER"}, {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"}, {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"}, {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"}, {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"}, {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"}, {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"}, {SCRIPT_ERR_MINIMALIF, "MINIMALIF"}, {SCRIPT_ERR_SIG_NULLFAIL, "NULLFAIL"}, {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"}, {SCRIPT_ERR_NONCOMPRESSED_PUBKEY, "NONCOMPRESSED_PUBKEY"}, {SCRIPT_ERR_ILLEGAL_FORKID, "ILLEGAL_FORKID"}, {SCRIPT_ERR_MUST_USE_FORKID, "MISSING_FORKID"}, {SCRIPT_ERR_DIV_BY_ZERO, "DIV_BY_ZERO"}, {SCRIPT_ERR_MOD_BY_ZERO, "MOD_BY_ZERO"}, }; const char *FormatScriptError(ScriptError_t err) { for (size_t i = 0; i < ARRAYLEN(script_errors); ++i) { if (script_errors[i].err == err) { return script_errors[i].name; } } BOOST_ERROR("Unknown scripterror enumeration value, update script_errors " "in script_tests.cpp."); return ""; } ScriptError_t ParseScriptError(const std::string &name) { for (size_t i = 0; i < ARRAYLEN(script_errors); ++i) { if (script_errors[i].name == name) { return script_errors[i].err; } } BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description"); return SCRIPT_ERR_UNKNOWN_ERROR; } BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup) static CMutableTransaction BuildCreditingTransaction(const CScript &scriptPubKey, const Amount nValue) { CMutableTransaction txCredit; txCredit.nVersion = 1; txCredit.nLockTime = 0; txCredit.vin.resize(1); txCredit.vout.resize(1); txCredit.vin[0].prevout = COutPoint(); txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txCredit.vout[0].scriptPubKey = scriptPubKey; txCredit.vout[0].nValue = nValue; return txCredit; } static CMutableTransaction BuildSpendingTransaction(const CScript &scriptSig, const CMutableTransaction &txCredit) { CMutableTransaction txSpend; txSpend.nVersion = 1; txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); txSpend.vin[0].prevout = COutPoint(txCredit.GetId(), 0); txSpend.vin[0].scriptSig = scriptSig; txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = txCredit.vout[0].nValue; return txSpend; } static void DoTest(const CScript &scriptPubKey, const CScript &scriptSig, int flags, const std::string &message, int scriptError, const Amount nValue) { bool expect = (scriptError == SCRIPT_ERR_OK); if (flags & SCRIPT_VERIFY_CLEANSTACK) { flags |= SCRIPT_VERIFY_P2SH; } ScriptError err; CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx2 = tx; BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker( &tx, 0, txCredit.vout[0].nValue), &err) == expect, message); BOOST_CHECK_MESSAGE( err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << tx2; int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL; if (libconsensus_flags == flags) { if (flags & bitcoinconsensus_SCRIPT_ENABLE_SIGHASH_FORKID) { BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount( scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue.GetSatoshis(), (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); } else { BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount( scriptPubKey.data(), scriptPubKey.size(), 0, (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script( scriptPubKey.data(), scriptPubKey.size(), (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); } } #endif } namespace { const uint8_t vchKey0[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; const uint8_t vchKey1[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}; const uint8_t vchKey2[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; struct KeyData { CKey key0, key0C, key1, key1C, key2, key2C; CPubKey pubkey0, pubkey0C, pubkey0H; CPubKey pubkey1, pubkey1C; CPubKey pubkey2, pubkey2C; KeyData() { - key0.Set(vchKey0, vchKey0 + 32, false); key0C.Set(vchKey0, vchKey0 + 32, true); pubkey0 = key0.GetPubKey(); pubkey0H = key0.GetPubKey(); pubkey0C = key0C.GetPubKey(); *const_cast(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); key1.Set(vchKey1, vchKey1 + 32, false); key1C.Set(vchKey1, vchKey1 + 32, true); pubkey1 = key1.GetPubKey(); pubkey1C = key1C.GetPubKey(); key2.Set(vchKey2, vchKey2 + 32, false); key2C.Set(vchKey2, vchKey2 + 32, true); pubkey2 = key2.GetPubKey(); pubkey2C = key2C.GetPubKey(); } }; class TestBuilder { private: //! Actually executed script CScript script; //! The P2SH redeemscript CScript redeemscript; CTransactionRef creditTx; CMutableTransaction spendTx; bool havePush; std::vector push; std::string comment; int flags; int scriptError; Amount nValue; void DoPush() { if (havePush) { spendTx.vin[0].scriptSig << push; havePush = false; } } void DoPush(const std::vector &data) { DoPush(); push = data; havePush = true; } public: TestBuilder(const CScript &script_, const std::string &comment_, int flags_, bool P2SH = false, Amount nValue_ = Amount(0)) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_) { CScript scriptPubKey = script; if (P2SH) { redeemscript = scriptPubKey; scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL; } creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue)); spendTx = BuildSpendingTransaction(CScript(), *creditTx); } TestBuilder &ScriptError(ScriptError_t err) { scriptError = err; return *this; } TestBuilder &Add(const CScript &_script) { DoPush(); spendTx.vin[0].scriptSig += _script; return *this; } TestBuilder &Num(int num) { DoPush(); spendTx.vin[0].scriptSig << num; return *this; } TestBuilder &Push(const std::string &hex) { DoPush(ParseHex(hex)); return *this; } TestBuilder &Push(const CScript &_script) { DoPush(std::vector(_script.begin(), _script.end())); return *this; } TestBuilder &PushSig(const CKey &key, SigHashType sigHashType = SigHashType(), unsigned int lenR = 32, unsigned int lenS = 32, Amount amount = Amount(0), uint32_t flags = SCRIPT_ENABLE_SIGHASH_FORKID) { uint256 hash = SignatureHash(script, CTransaction(spendTx), 0, sigHashType, amount, nullptr, flags); std::vector vchSig, r, s; uint32_t iter = 0; do { key.Sign(hash, vchSig, iter++); if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) { NegateSignatureS(vchSig); } r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); s = std::vector(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); } while (lenR != r.size() || lenS != s.size()); vchSig.push_back(static_cast(sigHashType.getRawSigHashType())); DoPush(vchSig); return *this; } TestBuilder &Push(const CPubKey &pubkey) { DoPush(std::vector(pubkey.begin(), pubkey.end())); return *this; } TestBuilder &PushRedeem() { DoPush(std::vector(redeemscript.begin(), redeemscript.end())); return *this; } TestBuilder &EditPush(unsigned int pos, const std::string &hexin, const std::string &hexout) { assert(havePush); std::vector datain = ParseHex(hexin); std::vector dataout = ParseHex(hexout); assert(pos + datain.size() <= push.size()); BOOST_CHECK_MESSAGE( std::vector(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); push.erase(push.begin() + pos, push.begin() + pos + datain.size()); push.insert(push.begin() + pos, dataout.begin(), dataout.end()); return *this; } TestBuilder &DamagePush(unsigned int pos) { assert(havePush); assert(pos < push.size()); push[pos] ^= 1; return *this; } TestBuilder &Test() { // Make a copy so we can rollback the push. TestBuilder copy = *this; DoPush(); DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, comment, scriptError, nValue); *this = copy; return *this; } UniValue GetJSON() { DoPush(); UniValue array(UniValue::VARR); if (nValue != Amount(0)) { UniValue amount(UniValue::VARR); amount.push_back(ValueFromAmount(nValue)); array.push_back(amount); } array.push_back(FormatScript(spendTx.vin[0].scriptSig)); array.push_back(FormatScript(creditTx->vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); array.push_back(FormatScriptError((ScriptError_t)scriptError)); array.push_back(comment); return array; } std::string GetComment() { return comment; } const CScript &GetScriptPubKey() { return creditTx->vout[0].scriptPubKey; } }; std::string JSONPrettyPrint(const UniValue &univalue) { std::string ret = univalue.write(4); // Workaround for libunivalue pretty printer, which puts a space between // commas and newlines size_t pos = 0; while ((pos = ret.find(" \n", pos)) != std::string::npos) { ret.replace(pos, 2, "\n"); pos++; } return ret; } } // namespace BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; std::vector tests; tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK", 0) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK, bad sig", 0) .PushSig(keys.key0) .DamagePush(10) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH", 0) .PushSig(keys.key1) .Push(keys.pubkey1C)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH, bad pubkey", 0) .PushSig(keys.key2) .Push(keys.pubkey2C) .DamagePush(5) .ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay", 0) .PushSig(keys.key1, SigHashType().withAnyoneCanPay())); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay marked with normal hashtype", 0) .PushSig(keys.key1, SigHashType().withAnyoneCanPay()) .EditPush(70, "81", "01") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem() .DamagePush(10) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH)", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .Push(keys.pubkey0) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true) .PushSig(keys.key0) .DamagePush(10) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .DamagePush(10) .PushRedeem() .ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3", 0) .Num(0) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3, 2 sigs", 0) .Num(0) .PushSig(keys.key0) .PushSig(keys.key1) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true) .Num(0) .PushSig(keys.key1) .PushSig(keys.key2) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true) .Num(0) .PushSig(keys.key1) .Num(0) .PushRedeem() .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding but no DERSIG", 0) .PushSig(keys.key1, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding but no DERSIG", 0) .PushSig(keys.key1) .EditPush(1, "44", "45") .EditPush(37, "20", "2100")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1) .EditPush(1, "44", "45") .EditPush(37, "20", "2100") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding but no DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, without DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, without DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, without DERSIG", 0) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, without DERSIG", 0) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG, non-null DER-compliant signature", SCRIPT_VERIFY_DERSIG) .Push("300602010102010101")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG and NULLFAIL", SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLFAIL) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG and NULLFAIL, " "non-null DER-compliant signature", SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLFAIL) .Push("300602010102010101") .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, without DERSIG", 0) .Num(1) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(1) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, without DERSIG", 0) .Num(1)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(1) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, without DERSIG", 0) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, without DERSIG", 0) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, without DERSIG", 0) .PushSig(keys.key2) .EditPush(70, "01", "0101")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2) .EditPush(70, "01", "0101") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S but no LOW_S", 0) .PushSig(keys.key2, SigHashType(), 32, 33)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S", SCRIPT_VERIFY_LOW_S) .PushSig(keys.key2, SigHashType(), 32, 33) .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0, SigHashType()) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0) .DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0) .DamagePush(10) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0) .Num(0) .PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .Num(0) .PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .Num(0) .PushSig(keys.key1) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype but no STRICTENC", 0) .PushSig(keys.key1, SigHashType(5))); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, SigHashType(5)) .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); // Generate P2PKH tests for invalid SigHashType tests.push_back( TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH with invalid sighashtype", 0) .PushSig(keys.key0, SigHashType(0x21), 32, 32, Amount(0), 0) .Push(keys.pubkey0)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH with invalid sighashtype and STRICTENC", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0, SigHashType(0x21), 32, 32, Amount(0), SCRIPT_VERIFY_STRICTENC) .Push(keys.pubkey0) // Should fail for STRICTENC .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); // Generate P2SH tests for invalid SigHashType tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2SH(P2PK) with invalid sighashtype", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key1, SigHashType(0x21)) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2SH(P2PK) with invalid sighashtype and STRICTENC", SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, true) .PushSig(keys.key1, SigHashType(0x21)) .PushRedeem() // Should fail for STRICTENC .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0) .PushSig(keys.key1, SigHashType(5)) .DamagePush(10)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, SigHashType(5)) .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy but no NULLDUMMY", 0) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back( TestBuilder( CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .DamagePush(10)); tests.push_back( TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs " "pushed using OP_DUP but no SIGPUSHONLY", 0) .Num(0) .PushSig(keys.key1) .Add(CScript() << OP_DUP)); tests.push_back( TestBuilder( CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY) .Num(0) .PushSig(keys.key1) .Add(CScript() << OP_DUP) .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with non-push scriptSig but with P2SH validation", 0) .PushSig(keys.key2) .Add(CScript() << OP_NOP8)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem() .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem() .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY) .Num(0) .PushSig(keys.key1) .PushSig(keys.key1)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH) .Num(11) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH) .Num(11) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true) .Num(11) .PushSig(keys.key0) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) .Num(11) .PushSig(keys.key0) .PushRedeem() .ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem()); static const Amount TEST_AMOUNT(12345000000000); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK FORKID", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID AMOUNT", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT + Amount(1)) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID FORKID", SCRIPT_VERIFY_STRICTENC, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT) .ScriptError(SCRIPT_ERR_ILLEGAL_FORKID)); // Test replay protection tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK REPLAY PROTECTED", SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT, SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK REPLAY PROTECTED", SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT, SCRIPT_ENABLE_SIGHASH_FORKID) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); std::set tests_set; { UniValue json_tests = read_json(std::string( json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < json_tests.size(); idx++) { const UniValue &tv = json_tests[idx]; tests_set.insert(JSONPrettyPrint(tv.get_array())); } } std::string strGen; for (TestBuilder &test : tests) { test.Test(); std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE( false, "Missing auto script_valid test: " + test.GetComment()); } #endif strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS FILE *file = fopen("script_tests.json.gen", "w"); fputs(strGen.c_str(), file); fclose(file); #endif } BOOST_AUTO_TEST_CASE(script_json_test) { // Read tests from test/data/script_tests.json // Format is an array of arrays // Inner arrays are [ ["wit"..., nValue]?, "scriptSig", "scriptPubKey", // "flags", "expected_scripterror" ] // ... where scriptSig and scriptPubKey are stringified // scripts. UniValue tests = read_json(std::string( json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; std::string strTest = test.write(); Amount nValue(0); unsigned int pos = 0; if (test.size() > 0 && test[pos].isArray()) { nValue = AmountFromValue(test[pos][0]); pos++; } // Allow size > 3; extra stuff ignored (useful for comments) if (test.size() < 4 + pos) { if (test.size() != 1) { BOOST_ERROR("Bad test: " << strTest); } continue; } std::string scriptSigString = test[pos++].get_str(); std::string scriptPubKeyString = test[pos++].get_str(); try { CScript scriptSig = ParseScript(scriptSigString); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); int scriptError = ParseScriptError(test[pos++].get_str()); DoTest(scriptPubKey, scriptSig, scriptflags, strTest, scriptError, nValue); } catch (std::runtime_error &e) { BOOST_TEST_MESSAGE("Script test failed. scriptSig: " << scriptSigString << " scriptPubKey: " << scriptPubKeyString); BOOST_TEST_MESSAGE("Exception: " << e.what()); throw; } } } BOOST_AUTO_TEST_CASE(script_PushData) { // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // the stack as the 1-75 opcodes do. static const uint8_t direct[] = {1, 0x5a}; static const uint8_t pushdata1[] = {OP_PUSHDATA1, 1, 0x5a}; static const uint8_t pushdata2[] = {OP_PUSHDATA2, 1, 0, 0x5a}; static const uint8_t pushdata4[] = {OP_PUSHDATA4, 1, 0, 0, 0, 0x5a}; ScriptError err; std::vector> directStack; BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata1Stack; BOOST_CHECK(EvalScript( pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata2Stack; BOOST_CHECK(EvalScript( pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata4Stack; BOOST_CHECK(EvalScript( pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SigHashType(), Amount(0)); CScript result; // // NOTE: CHECKMULTISIG has an unfortunate bug; it requires one extra item on // the stack, before the signatures. Putting OP_0 on the stack is the // workaround; fixing the bug would mean splitting the block chain (old // clients would not accept new CHECKMULTISIG transactions, and vice-versa) // result << OP_0; for (const CKey &key : keys) { std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL)); result << vchSig; } return result; } CScript sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) { std::vector keys; keys.push_back(key); return sign_multisig(scriptPubKey, keys, transaction); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); CScript scriptPubKey12; scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12, Amount(0)); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, CTransaction(txTo12)); BOOST_CHECK(VerifyScript( goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = Amount(2); BOOST_CHECK(!VerifyScript( goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, CTransaction(txTo12)); BOOST_CHECK(VerifyScript( goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, CTransaction(txTo12)); BOOST_CHECK(!VerifyScript( badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); key4.MakeNewKey(false); CScript scriptPubKey23; scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG; CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23, Amount(0)); CMutableTransaction mutableTxTo23 = BuildSpendingTransaction(CScript(), txFrom23); // after it has been set up, mutableTxTo23 does not change in this test, // so we can convert it to readonly transaction and use // TransactionSignatureChecker // instead of MutableTransactionSignatureChecker const CTransaction txTo23(mutableTxTo23); std::vector keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig1, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig2, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig3, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig1, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig2, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig3, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig4, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig5, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig6, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function Amount amount(0); CBasicKeyStore keystore; std::vector keys; std::vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; key.MakeNewKey(i % 2 == 1); keys.push_back(key); pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } CMutableTransaction txFrom = BuildCreditingTransaction( GetScriptForDestination(keys[0].GetPubKey().GetID()), Amount(0)); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); CScript &scriptPubKey = txFrom.vout[0].scriptPubKey; CScript &scriptSig = txTo.vin[0].scriptSig; // Although it looks like CMutableTransaction is not modified after it’s // been set up (it is not passed as parameter to any non-const function), // it is actually modified when new value is assigned to scriptPubKey, // which points to mutableTxFrom.vout[0].scriptPubKey. Therefore we can // not use single instance of CTransaction in this test. // CTransaction creates a copy of CMutableTransaction and is not modified // when scriptPubKey is assigned to. SignatureData empty; SignatureData combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); // changes scriptSig combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose // non-placeholder: scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: std::vector sig1; uint256 hash1 = SignatureHash(scriptPubKey, CTransaction(txTo), 0, SigHashType(), Amount(0)); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; uint256 hash2 = SignatureHash( scriptPubKey, CTransaction(txTo), 0, SigHashType().withBaseType(BaseSigHashType::NONE), Amount(0)); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; uint256 hash3 = SignatureHash( scriptPubKey, CTransaction(txTo), 0, SigHashType().withBaseType(BaseSigHashType::SINGLE), Amount(0)); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); // Not fussy about order (or even existence) of placeholders or signatures: CScript partial1a = CScript() << OP_0 << sig1 << OP_0; CScript partial1b = CScript() << OP_0 << OP_0 << sig1; CScript partial2a = CScript() << OP_0 << sig2; CScript partial2b = CScript() << sig2 << OP_0; CScript partial3a = CScript() << sig3; CScript partial3b = CScript() << OP_0 << OP_0 << sig3; CScript partial3c = CScript() << OP_0 << sig3 << OP_0; CScript complete12 = CScript() << OP_0 << sig1 << sig2; CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == partial1a); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == complete13); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == partial3c); } BOOST_AUTO_TEST_CASE(script_standard_push) { ScriptError err; for (int i = 0; i < 67000; i++) { CScript script; script << i; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } for (unsigned int i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) { std::vector data(i, '\111'); CScript script; script << data; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) { // IsPushOnly returns false when given a script containing only pushes that // are invalid due to truncation. IsPushOnly() is consensus critical because // P2SH evaluation uses it, although this specific behavior should not be // consensus critical as the P2SH evaluation would fail first due to the // invalid push. Still, it doesn't hurt to test it explicitly. static const uint8_t direct[] = {1}; BOOST_CHECK(!CScript(direct, direct + sizeof(direct)).IsPushOnly()); } BOOST_AUTO_TEST_CASE(script_GetScriptAsm) { BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true)); BOOST_CHECK_EQUAL( "OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e" "3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38" "d782e53023ee313d741ad0cfbc0c5090"); std::string pubKey( "03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); std::vector vchPubKey = ToByteVector(ParseHex(pubKey)); BOOST_CHECK_EQUAL( derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "41")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c1")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "42")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c2")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "43")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c3")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } static CScript ScriptFromHex(const char *hex) { std::vector data = ParseHex(hex); return CScript(data.begin(), data.end()); } BOOST_AUTO_TEST_CASE(script_FindAndDelete) { // Exercise the FindAndDelete functionality CScript s; CScript d; CScript expect; s = CScript() << OP_1 << OP_2; // delete nothing should be a no-op d = CScript(); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = CScript() << OP_1 << OP_2 << OP_3; d = CScript() << OP_2; expect = CScript() << OP_1 << OP_3; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3; d = CScript() << OP_3; expect = CScript() << OP_1 << OP_4; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4); BOOST_CHECK(s == expect); // PUSH 0x02ff03 onto stack s = ScriptFromHex("0302ff03"); d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); // PUSH 0x2ff03 PUSH 0x2ff03 s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("02"); expect = s; // FindAndDelete matches entire opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("ff"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // This is an odd edge case: strip of the push-three-bytes prefix, leaving // 02ff03 which is push-two-bytes: s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("03"); expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Byte sequence that spans multiple opcodes: // PUSH(0xfeed) OP_1 OP_VERIFY s = ScriptFromHex("02feed5169"); d = ScriptFromHex("feed51"); expect = s; // doesn't match 'inside' opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // PUSH(0xfeed) OP_1 OP_VERIFY s = ScriptFromHex("02feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("69"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("feed51"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("516969"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass expect = CScript() << OP_0 << OP_1; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass expect = CScript() << OP_0 << OP_1; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Another weird edge case: // End with invalid push (not enough data)... s = ScriptFromHex("0003feed"); // ... can remove the invalid push d = ScriptFromHex("03feed"); expect = ScriptFromHex("00"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("0003feed"); d = ScriptFromHex("00"); expect = ScriptFromHex("03feed"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigencoding_tests.cpp b/src/test/sigencoding_tests.cpp new file mode 100644 index 0000000000..71becfe714 --- /dev/null +++ b/src/test/sigencoding_tests.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test/test_bitcoin.h" + +#include "script/script_flags.h" +#include "script/sigencoding.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(sigencoding_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(checkpubkeyencoding_test) { + valtype compressedKey0{0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, + 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}; + valtype compressedKey1{0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, + 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, + 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}; + valtype fullKey{0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, + 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, + 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, + 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, + 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x0f, 0xff}; + + std::vector invalidKeys{ + // Degenerate keys. + {}, + {0x00}, + {0x42}, + {0xff}, + // Invalid first byte 0x00. + {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Invalid first byte 0x01. + {0x01, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Invalid first byte 0x05. + {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Invalid first byte 0xff. + {0xff, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + {0xff, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Compressed key too short. + {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + {0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, + 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, + 0xf0, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Compressed key too long. + {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, + 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a, + 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + {0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xab, + 0xba, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Compressed key, full key size. + {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + {0x03, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Full key, too short. + {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, + 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Full key, too long. + {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, + 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x56, 0x78, 0xab, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, + 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xde, + 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, + // Full key, compressed key size. + {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, + 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a, + 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + }; + + // If we add many more flags, this loop can get too expensive, but we can + // rewrite in the future to randomly pick a set of flags to evaluate. + for (uint32_t flags = 0; flags < (1U << 17); flags++) { + ScriptError err = SCRIPT_ERR_OK; + + // Compressed pubkeys are always valid. + BOOST_CHECK(CheckPubKeyEncoding(compressedKey0, flags, &err)); + BOOST_CHECK(CheckPubKeyEncoding(compressedKey1, flags, &err)); + + // If SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is specified, full key are + // disabled. + bool allowFullKey = (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) == 0; + BOOST_CHECK_EQUAL(CheckPubKeyEncoding(fullKey, flags, &err), + allowFullKey); + + // If SCRIPT_VERIFY_STRICTENC or SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is + // specified, we rule out invalid keys. + bool allowInvalidKeys = + allowFullKey && (flags & SCRIPT_VERIFY_STRICTENC) == 0; + for (const valtype &key : invalidKeys) { + BOOST_CHECK_EQUAL(CheckPubKeyEncoding(key, flags, &err), + allowInvalidKeys); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index ad35fb7ca8..dc352f5a12 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -1,392 +1,392 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "config.h" #include "consensus/validation.h" #include "key.h" #include "keystore.h" #include "miner.h" #include "pubkey.h" #include "random.h" #include "script/scriptcache.h" #include "script/sighashtype.h" #include "script/sign.h" #include "script/standard.h" #include "test/sigutil.h" #include "test/test_bitcoin.h" #include "txmempool.h" #include "utiltime.h" #include "validation.h" #include BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) static bool ToMemPool(CMutableTransaction &tx) { LOCK(cs_main); CValidationState state; return AcceptToMemoryPool(GetConfig(), mempool, state, MakeTransactionRef(tx), false, nullptr, true, Amount(0)); } BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) { // Make sure skipping validation of transctions that were validated going // into the memory pool does not allow double-spends in blocks to pass // validation when they should not. CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; // Create a double-spend of mature coinbase txn: std::vector spends; spends.resize(2); for (int i = 0; i < 2; i++) { spends[i].nVersion = 1; spends[i].vin.resize(1); spends[i].vin[0].prevout = COutPoint(coinbaseTxns[0].GetId(), 0); spends[i].vout.resize(1); spends[i].vout[0].nValue = 11 * CENT; spends[i].vout[0].scriptPubKey = scriptPubKey; // Sign: std::vector vchSig; uint256 hash = SignatureHash(scriptPubKey, CTransaction(spends[i]), 0, SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); spends[i].vin[0].scriptSig << vchSig; } CBlock block; // Test 1: block with both of those transactions should be rejected. block = CreateAndProcessBlock(spends, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); // Test 2: ... and should be rejected if spend1 is in the memory pool BOOST_CHECK(ToMemPool(spends[0])); block = CreateAndProcessBlock(spends, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); mempool.clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(spends, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); mempool.clear(); // Final sanity test: first spend in mempool, second in block, that's OK: std::vector oneSpend; oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(oneSpend, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); // spends[1] should have been removed from the mempool when the block with // spends[0] is accepted: BOOST_CHECK_EQUAL(mempool.size(), 0); } // Run CheckInputs (using pcoinsTip) on the given transaction, for all script // flags. Test that CheckInputs passes for all flags that don't overlap with the // failing_flags argument, but otherwise fails. // CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may // get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if the // script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain // CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain // OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution // should fail. // Capture this interaction with the upgraded_nop argument: set it when // evaluating any script flag that is implemented as an upgraded NOP code. void ValidateCheckInputsForAllFlags(const CMutableTransaction &mutableTx, uint32_t failing_flags, bool add_to_cache, bool upgraded_nop) { const CTransaction tx(mutableTx); PrecomputedTransactionData txdata(tx); // If we add many more flags, this loop can get too expensive, but we can // rewrite in the future to randomly pick a set of flags to evaluate. - for (size_t test_flags = 0; test_flags < (1U << 17); test_flags += 1) { + for (uint32_t test_flags = 0; test_flags < (1U << 17); test_flags += 1) { CValidationState state; // Make sure the mandatory flags are enabled. test_flags |= MANDATORY_SCRIPT_VERIFY_FLAGS; bool ret = CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, nullptr); // CheckInputs should succeed iff test_flags doesn't intersect with // failing_flags bool expected_return_value = !(test_flags & failing_flags); if (expected_return_value && upgraded_nop) { // If the script flag being tested corresponds to an upgraded NOP, // then script execution should fail if DISCOURAGE_UPGRADABLE_NOPS // is set. expected_return_value = !(test_flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS); } BOOST_CHECK_EQUAL(ret, expected_return_value); // Test the caching if (ret && add_to_cache) { // Check that we get a cache hit if the tx was valid std::vector scriptchecks; BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK(scriptchecks.empty()); } else { // Check that we get script executions to check, if the transaction // was invalid, or we didn't add to cache. std::vector scriptchecks; BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); } } } BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { // Test that passing CheckInputs with one set of script flags doesn't imply // that we would pass again with a different set of flags. InitScriptExecutionCache(); CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey)); CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); CBasicKeyStore keystore; keystore.AddKey(coinbaseKey); keystore.AddCScript(p2pk_scriptPubKey); // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, // SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed // pubkey thing // Create 2 outputs that match the three scripts above, spending the first // coinbase tx. CMutableTransaction mutableSpend_tx; mutableSpend_tx.nVersion = 1; mutableSpend_tx.vin.resize(1); mutableSpend_tx.vin[0].prevout = COutPoint(coinbaseTxns[0].GetId(), 0); mutableSpend_tx.vout.resize(4); mutableSpend_tx.vout[0].nValue = 11 * CENT; mutableSpend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; mutableSpend_tx.vout[1].nValue = 11 * CENT; mutableSpend_tx.vout[1].scriptPubKey = CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; mutableSpend_tx.vout[2].nValue = 11 * CENT; mutableSpend_tx.vout[2].scriptPubKey = CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; mutableSpend_tx.vout[3].nValue = 11 * CENT; mutableSpend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; // Sign, and push an extra element on the stack. { std::vector vchSig; uint256 hash = SignatureHash( p2pk_scriptPubKey, CTransaction(mutableSpend_tx), 0, SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); mutableSpend_tx.vin[0].scriptSig << OP_TRUE << vchSig; } const CTransaction spend_tx(mutableSpend_tx); LOCK(cs_main); // Test that invalidity under a set of flags doesn't preclude validity under // other (eg consensus) flags. // spend_tx is invalid according to DERSIG CValidationState state; { PrecomputedTransactionData ptd_spend_tx(spend_tx); BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip, true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_CLEANSTACK, true, true, ptd_spend_tx, nullptr)); // If we call again asking for scriptchecks (as happens in // ConnectBlock), we should add a script check object for this -- we're // not caching invalidity (if that changes, delete this test case). std::vector scriptchecks; BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip, true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_CLEANSTACK, true, true, ptd_spend_tx, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), 1); // Test that CheckInputs returns true iff cleanstack-enforcing flags are // not present. Don't add these checks to the cache, so that we can test // later that block validation works fine in the absence of cached // successes. ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_CLEANSTACK, false, false); // And if we produce a block with this tx, it should be valid (LOW_S not // enabled yet), even though there's no cache entry. CBlock block; block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); } // Test P2SH: construct a transaction that is valid without P2SH, and then // test validity with P2SH. { CMutableTransaction invalid_under_p2sh_tx; invalid_under_p2sh_tx.nVersion = 1; invalid_under_p2sh_tx.vin.resize(1); invalid_under_p2sh_tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 0); invalid_under_p2sh_tx.vout.resize(1); invalid_under_p2sh_tx.vout[0].nValue = 11 * CENT; invalid_under_p2sh_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; std::vector vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end()); invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2; ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true, false); } // Test CHECKLOCKTIMEVERIFY { CMutableTransaction invalid_with_cltv_tx; invalid_with_cltv_tx.nVersion = 1; invalid_with_cltv_tx.nLockTime = 100; invalid_with_cltv_tx.vin.resize(1); invalid_with_cltv_tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 1); invalid_with_cltv_tx.vin[0].nSequence = 0; invalid_with_cltv_tx.vout.resize(1); invalid_with_cltv_tx.vout[0].nValue = 11 * CENT; invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign std::vector vchSig; uint256 hash = SignatureHash( spend_tx.vout[1].scriptPubKey, CTransaction(invalid_with_cltv_tx), 0, SigHashType().withForkId(), spend_tx.vout[1].nValue); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true); // Make it valid, and check again invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; CTransaction transaction(invalid_with_cltv_tx); PrecomputedTransactionData txdata(transaction); BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip, true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); } // TEST CHECKSEQUENCEVERIFY { CMutableTransaction invalid_with_csv_tx; invalid_with_csv_tx.nVersion = 2; invalid_with_csv_tx.vin.resize(1); invalid_with_csv_tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 2); invalid_with_csv_tx.vin[0].nSequence = 100; invalid_with_csv_tx.vout.resize(1); invalid_with_csv_tx.vout[0].nValue = 11 * CENT; invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign std::vector vchSig; uint256 hash = SignatureHash( spend_tx.vout[2].scriptPubKey, CTransaction(invalid_with_csv_tx), 0, SigHashType().withForkId(), spend_tx.vout[2].nValue); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; ValidateCheckInputsForAllFlags( invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true); // Make it valid, and check again invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; CTransaction transaction(invalid_with_csv_tx); PrecomputedTransactionData txdata(transaction); BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip, true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); } // TODO: add tests for remaining script flags { // Test a transaction with multiple inputs. CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(2); tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 0); tx.vin[1].prevout = COutPoint(spend_tx.GetId(), 3); tx.vout.resize(1); tx.vout[0].nValue = 22 * CENT; tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign SignatureData sigdata; ProduceSignature( MutableTransactionSignatureCreator(&keystore, &tx, 0, 11 * CENT, SigHashType().withForkId()), spend_tx.vout[0].scriptPubKey, sigdata); UpdateTransaction(tx, 0, sigdata); ProduceSignature( MutableTransactionSignatureCreator(&keystore, &tx, 1, 11 * CENT, SigHashType().withForkId()), spend_tx.vout[3].scriptPubKey, sigdata); UpdateTransaction(tx, 1, sigdata); // This should be valid under all script flags ValidateCheckInputsForAllFlags(tx, 0, true, false); // Check that if the second input is invalid, but the first input is // valid, the transaction is not cached. // Invalidate vin[1] tx.vin[1].scriptSig = CScript(); CValidationState state; CTransaction transaction(tx); PrecomputedTransactionData txdata(transaction); // This transaction is now invalid because the second signature is // missing. BOOST_CHECK(!CheckInputs(transaction, state, pcoinsTip, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, txdata, nullptr)); // Make sure this transaction was not cached (ie becausethe first input // was valid) std::vector scriptchecks; BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, txdata, &scriptchecks)); // Should get 2 script checks back -- caching is on a whole-transaction // basis. BOOST_CHECK_EQUAL(scriptchecks.size(), 2); } } BOOST_AUTO_TEST_SUITE_END()