From 2be1604405ffcf06e605bea61572fb209fd043a2 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 3 Apr 2021 09:25:48 +0200 Subject: [PATCH 01/11] Merge #20459: rpc: Fail to return undocumented return values fa8192f42e1d24444f1d0433c96dbce1adf76967 rpc: Fail to return undocumented return values (MarcoFalke) Pull request description: Currently a few return values are undocumented. This is causing confusion at the least. See for example #18476 Fix this by treating it as an internal bug to return undocumented return values. ACKs for top commit: ryanofsky: Code review ACK fa8192f42e1d24444f1d0433c96dbce1adf76967. Only changes: rebase, no const_cast suggestion, and tostring cleanups needed after suggestion Tree-SHA512: c006905639bafe3045de152b00c34d9864731becb3c4f468bdd61a392f10d7e7cd89a54862c8daa8c11ac4eea0eb5f13b0f647d21e21a0a797b54191cff7238c --- src/qt/test/rpcnestedtests.cpp | 2 +- src/rpc/misc.cpp | 2 +- src/rpc/server.cpp | 5 ++-- src/rpc/util.cpp | 42 +++++++++++++++++++++++++++++++++- src/rpc/util.h | 5 +++- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index 36f4ffc1367d7..bb6e07663a0d5 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -26,7 +26,7 @@ static RPCHelpMan rpcNestedTest_rpc() {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, }, - {}, + RPCResult{RPCResult::Type::ANY, "", ""}, RPCExamples{""}, [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { return request.params.write(0, 0); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 0a28cf8862849..08f46113da9d4 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1392,7 +1392,7 @@ static RPCHelpMan echo(const std::string& name) {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, }, - RPCResult{RPCResult::Type::NONE, "", "Returns whatever was passed in"}, + RPCResult{RPCResult::Type::ANY, "", "Returns whatever was passed in"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 73ba4b75c6cec..eb179b143b1ee 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -171,8 +171,9 @@ static RPCHelpMan help() {"command", RPCArg::Type::STR, /* default */ "all commands", "The command to get help on"}, {"subcommand", RPCArg::Type::STR, /* default */ "all subcommands", "The subcommand to get help on."}, }, - RPCResult{ - RPCResult::Type::STR, "", "The help text" + { + RPCResult{RPCResult::Type::STR, "", "The help text"}, + RPCResult{RPCResult::Type::ANY, "", ""}, }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 265fb438c8cb7..3b02da632f693 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -476,6 +476,7 @@ std::string RPCResults::ToDescriptionString() const { std::string result; for (const auto& r : m_results) { + if (r.m_type == RPCResult::Type::ANY) continue; // for testing only if (r.m_cond.empty()) { result += "\nResult:\n"; } else { @@ -493,7 +494,7 @@ std::string RPCExamples::ToDescriptionString() const return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples; } -UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) +UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const { if (request.mode == JSONRPCRequest::GET_ARGS) { return GetArgMap(); @@ -710,6 +711,9 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const sections.PushSection({indent + "..." + maybe_separator, m_description}); return; } + case Type::ANY: { + CHECK_NONFATAL(false); // Only for testing + } case Type::NONE: { sections.PushSection({indent + "null" + maybe_separator, Description("json null")}); return; @@ -775,6 +779,42 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const CHECK_NONFATAL(false); } +bool RPCResult::MatchesType(const UniValue& result) const +{ + switch (m_type) { + case Type::ELISION: { + return false; + } + case Type::ANY: { + return true; + } + case Type::NONE: { + return UniValue::VNULL == result.getType(); + } + case Type::STR: + case Type::STR_HEX: { + return UniValue::VSTR == result.getType(); + } + case Type::NUM: + case Type::STR_AMOUNT: + case Type::NUM_TIME: { + return UniValue::VNUM == result.getType(); + } + case Type::BOOL: { + return UniValue::VBOOL == result.getType(); + } + case Type::ARR_FIXED: + case Type::ARR: { + return UniValue::VARR == result.getType(); + } + case Type::OBJ_DYN: + case Type::OBJ: { + return UniValue::VOBJ == result.getType(); + } + } // no default case, so the compiler can warn about missing cases + CHECK_NONFATAL(false); +} + std::string RPCArg::ToStringObj(const bool oneline) const { std::string res; diff --git a/src/rpc/util.h b/src/rpc/util.h index ae422dc744332..c9192a3a10a1e 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -230,6 +230,7 @@ struct RPCResult { NUM, BOOL, NONE, + ANY, //!< Special type to disable type checks (for testing only) STR_AMOUNT, //!< Special string to represent a floating point amount STR_HEX, //!< Special string with only hex chars OBJ_DYN, //!< Special dictionary with keys that are not literals @@ -302,6 +303,8 @@ struct RPCResult { std::string ToStringObj() const; /** Return the description string, including the result type. */ std::string ToDescriptionString() const; + /** Check whether the result JSON type matches. */ + bool MatchesType(const UniValue& result) const; }; struct RPCResults { @@ -340,7 +343,7 @@ class RPCHelpMan using RPCMethodImpl = std::function; RPCHelpMan(std::string name, std::string description, std::vector args, RPCResults results, RPCExamples examples, RPCMethodImpl fun); - UniValue HandleRequest(const JSONRPCRequest& request); + UniValue HandleRequest(const JSONRPCRequest& request) const; std::string ToString() const; /** Return the named args that need to be converted from string to another JSON type */ UniValue GetArgMap() const; From cc169c2457a004ee60e6e9a8c7faf80fc5a65e4d Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 5 Jan 2021 11:53:15 +0100 Subject: [PATCH 02/11] partial Merge #20842: docs: consolidate typo & url fixing BACKPORT NOTICE: missing changes in src/test/validation_tests.cpp (signet) 1112035d32ffe73a4522226c8cb2f6a5878d3ada doc: fix various typos (Ikko Ashimine) e8640849c775efcf202dbd34736fed8d61379c49 doc: Use https URLs where possible (Sawyer Billings) Pull request description: Consolidates / fixes the changes from #20762, #20836, #20810. There is no output when `test/lint/lint-all.sh` is run. Closes #20807. ACKs for top commit: MarcoFalke: ACK 1112035d32ffe73a4522226c8cb2f6a5878d3ada Tree-SHA512: 22ca824688758281a74e5ebc6a84a358142351434e34c88c6b36045d2d241ab95fd0958565fd2060f98317e62e683323b5320cc7ec13592bf340e6922294ed78 --- depends/patches/fontconfig/gperf_header_regen.patch | 2 +- src/core_io.h | 2 +- src/merkleblock.cpp | 2 +- src/qt/bitcoin.cpp | 2 +- src/qt/test/rpcnestedtests.cpp | 8 ++++---- src/qt/walletcontroller.cpp | 2 +- src/wallet/sqlite.h | 2 +- src/wallet/walletdb.cpp | 2 +- test/functional/feature_nulldummy.py | 2 +- test/functional/wallet_encryption.py | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/depends/patches/fontconfig/gperf_header_regen.patch b/depends/patches/fontconfig/gperf_header_regen.patch index 7401b83d840ff..3ffd1674e03bc 100644 --- a/depends/patches/fontconfig/gperf_header_regen.patch +++ b/depends/patches/fontconfig/gperf_header_regen.patch @@ -2,7 +2,7 @@ commit 7b6eb33ecd88768b28c67ce5d2d68a7eed5936b6 Author: fanquake Date: Tue Aug 25 14:34:53 2020 +0800 - Remove rule that causes inadvertant header regeneration + Remove rule that causes inadvertent header regeneration Otherwise the makefile will needlessly attempt to re-generate the headers with gperf. This can be dropped once the upstream build is fixed. diff --git a/src/core_io.h b/src/core_io.h index 91a8f01617597..a24d7d5d7f081 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -31,7 +31,7 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); /** * Parse a hex string into 256 bits * @param[in] strHex a hex-formatted, 64-character string - * @param[out] result the result of the parasing + * @param[out] result the result of the parsing * @returns true if successful, false if not * * @see ParseHashV for an RPC-oriented version of this diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index 7051d88cb02be..cfd164c64544b 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -73,7 +73,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve //if we do not have this assert, we can hit a memory access violation when indexing into vTxid assert(vTxid.size() != 0); if (height == 0) { - // hash at height 0 is the txids themself + // hash at height 0 is the txids themselves return vTxid[pos]; } else { // calculate left hash diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a6759efec1c4f..f3155c596ef7a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -85,7 +85,7 @@ static void RegisterMetaTypes() #ifdef ENABLE_WALLET qRegisterMetaType(); #endif - // Register typedefs (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType) + // Register typedefs (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType) // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1) qRegisterMetaType("CAmount"); qRegisterMetaType("size_t"); diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index bb6e07663a0d5..dd19a00326431 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -129,10 +129,10 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments - (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackts + (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackets QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(True)"), UniValue); //invalid argument QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "a(getblockchaininfo(True))"), UniValue); //method not found - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using , - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tolerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tolerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tolerate empty arguments when using , } diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index cc4e42177c5ae..d8c60b9e93022 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -153,7 +153,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr> checksum; if (!(checksum_valid = Hash(vchPrivKey) == checksum)) { - strErr = "Error reading wallet database: Crypted key corrupt"; + strErr = "Error reading wallet database: Encrypted key corrupt"; return false; } } diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index 480b0b5c8a86a..6769aa6b54480 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -65,7 +65,7 @@ def run_test(self): self.pubkey = w0.getaddressinfo(self.address)['pubkey'] self.ms_address = wmulti.addmultisigaddress(1, [self.pubkey])['address'] if not self.options.descriptors: - # Legacy wallets need to import these so that they are watched by the wallet. This is unnecssary (and does not need to be tested) for descriptor wallets + # Legacy wallets need to import these so that they are watched by the wallet. This is unnecessary (and does not need to be tested) for descriptor wallets wmulti.importaddress(self.ms_address) self.coinbase_blocks = self.nodes[0].generate(2) # block height = 2 diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index a3bbe7005ed7f..25f19baf8e3c8 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -79,7 +79,7 @@ def run_test(self): expected_time = self.mocktime + MAX_VALUE - 600 self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600) self.bump_mocktime(1) - # give buffer for walletpassphrase, since it iterates over all crypted keys + # give buffer for walletpassphrase, since it iterates over all encrypted keys expected_time_with_buffer = self.mocktime + MAX_VALUE - 600 actual_time = self.nodes[0].getwalletinfo()['unlocked_until'] assert_greater_than_or_equal(actual_time, expected_time) From 81d21eea143e32bda92c1d793f3ef67dd4f43cc8 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 6 Apr 2021 08:35:55 +0200 Subject: [PATCH 03/11] Merge #21557: test: small cleanup in RPCNestedTests tests 6526a1644cd1723e47054aa83b3ae8eacf84bf84 test: small cleanup in RPCNestedTests tests (fanquake) Pull request description: Remove QtDir & QtGlobal (dea086f498097d19a2c9acbfc753c9c2d68dbb03) Add missing includes. Remove obsolete comment about Qt 5.3 (fd46c4c0018c41d36cd892ccb47485b572d65837) Top commit has no ACKs. Tree-SHA512: 097e603fc31a19be1817459ad4c5a9692708f8a39a0ae87e4a60eabc22bf4f6141b577ba68746044fd594f92e36848b7cd56d60dccd262f83f8ec7310ab7d1bc --- src/qt/test/rpcnestedtests.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index dd19a00326431..60f9963a707ba 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -13,8 +13,10 @@ #include -#include -#include +#include + +#include +#include static RPCHelpMan rpcNestedTest_rpc() { @@ -28,7 +30,7 @@ static RPCHelpMan rpcNestedTest_rpc() }, RPCResult{RPCResult::Type::ANY, "", ""}, RPCExamples{""}, - [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { return request.params.write(0, 0); }, }; @@ -70,13 +72,13 @@ void RPCNestedTests::rpcNestedTests() RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo "); //whitespace at the end will be tolerated QVERIFY(result.substr(0,1) == "{"); - (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()[\"chain\"]"); //Quote path identifier are allowed, but look after a child containing the quotes in the key QVERIFY(result == "null"); - (RPCConsole::RPCExecuteCommandLine(m_node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed - (RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed + RPCConsole::RPCExecuteCommandLine(m_node, result, "createrawtransaction [] {} 0"); //parameter not in brackets are allowed + RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction([],{},0)"); //parameter in brackets are allowed QVERIFY(result == result2); - (RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed + RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction( [], {} , 0 )"); //whitespace between parameters is allowed QVERIFY(result == result2); RPCConsole::RPCExecuteCommandLine(m_node, result, "getblock(getbestblockhash())[tx][0]", &filtered); @@ -125,11 +127,10 @@ void RPCNestedTests::rpcNestedTests() RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest( abc , cba )"); QVERIFY(result == "[\"abc\",\"cba\"]"); - // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax - (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments - (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackets + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo("); //tolerate non closing brackets if we have no arguments + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()"); //tolerate non command brackets QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(True)"), UniValue); //invalid argument QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "a(getblockchaininfo(True))"), UniValue); //method not found QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tolerate empty arguments when using , From 1dffe3ab9fc05b910b41eefe833493ab19cc251c Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 6 May 2021 16:52:45 +0200 Subject: [PATCH 04/11] Merge bitcoin/bitcoin#21867: test: use MiniWallet for p2p_blocksonly.py 9f767e84381d678ed24e3f7f981976f9da34971e test: use MiniWallet for p2p_blocksonly.py (Sebastian Falbesoner) Pull request description: This PR enables one more of the non-wallet functional tests (p2p_blocksonly.py) to be run even with the Bitcoin Core wallet disabled by using the new MiniWallet instead, as proposed in #20078. Note that MiniWallet creates segwit transactions by default, i.e. txid and wtxid are not identical and we have to return both from `check_p2p_tx_violation(...)`: wtxid is needed to match an expected `"received getdata for: wtx ..."` debug output, whereas the txid is needed to wait for a certain tx via `wait_for_tx(...)`. ACKs for top commit: jonatack: ACK 9f767e84381d678ed24e3f7f981976f9da34971e tested with `--disable-wallet` Tree-SHA512: f08001f02c3c310ccdf713af0ba17304368a36414f412749908bbe8c03ad1e902190b8768b79f3b4909855762f285e7ab1b627cc4f45c90b42bb097a43cb4318 --- test/functional/p2p_blocksonly.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 2703fe4e2df72..9e2f2bcba6ad7 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -6,22 +6,25 @@ import time -from test_framework.blocktools import create_transaction from test_framework.messages import msg_tx from test_framework.p2p import P2PInterface, P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal +from test_framework.wallet import MiniWallet class P2PBlocksOnly(BitcoinTestFramework): def set_test_params(self): + self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-blocksonly"]] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): + self.miniwallet = MiniWallet(self.nodes[0]) + # Add enough mature utxos to the wallet, so that all txs spend confirmed coins + self.miniwallet.generate(2) + self.nodes[0].generate(100) + self.blocksonly_mode_tests() self.blocks_relay_conn_tests() @@ -96,19 +99,18 @@ def blocks_relay_conn_tests(self): def check_p2p_tx_violation(self, index=1): self.log.info('Check that txs from P2P are rejected and result in disconnect') input_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(index), 2)['tx'][0]['txid'] - tx = create_transaction(self.nodes[0], input_txid, self.nodes[0].getnewaddress(), amount=(500 - 0.001)) - txid = tx.rehash() - tx_hex = tx.serialize().hex() + utxo_to_spend = self.miniwallet.get_utxo(txid=input_txid) + spendtx = self.miniwallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_to_spend) with self.nodes[0].assert_debug_log(['tx sent in violation of protocol peer=0']): - self.nodes[0].p2ps[0].send_message(msg_tx(tx)) + self.nodes[0].p2ps[0].send_message(msg_tx(spendtx['tx'])) self.nodes[0].p2ps[0].wait_for_disconnect() assert_equal(self.nodes[0].getmempoolinfo()['size'], 0) # Remove the disconnected peer del self.nodes[0].p2ps[0] - return tx, txid, tx_hex + return spendtx['tx'], spendtx['txid'], spendtx['hex'] if __name__ == '__main__': From c6f603c26f58c134514a24db44944dabbb379cb8 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 10 May 2021 08:43:59 +0200 Subject: [PATCH 05/11] Merge bitcoin/bitcoin#21897: rpc: adjust incorrect RPCHelpMan types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 7031721f2cc3eef30c46ff50c52328e9ba8090e0 rpc/listaddressgroupings: redefine inner-most array as ARR_FIXED (Karl-Johan Alm) 8500f7bf54d3e27fd2fa7fda15ad833f5688c331 rpc/createrawtransaction: redefine addresses as OBJ_USER_KEYS (Karl-Johan Alm) d9e2183c50f50465b9f173171fee240949bf8bd2 rpc: include OBJ_USER_KEY in RPCArg constructor checks (Karl-Johan Alm) Pull request description: This PR adjusts the two issues I encountered while developing a tool that converts RPCHelpMan objects into bindings for other language(s). The first is in createrawtransaction, where the address part, e.g. bc1qabc in > createrawtransaction '[]' '[{"bc1qabc": 1.0}]' is declared as a `Type::OBJ`, when in reality it should be a `Type::OBJ_USER_KEYS`, defined as such: https://github.com/bitcoin/bitcoin/blob/5925f1e652768a9502831b9ccf78d16cf3c37d29/src/rpc/util.h#L126 (coincidentally, this is the first and only (afaict) usage of this `RPCArg::Type`). The second is in the `listaddressgroupings` RPC, which returns an array of arrays of arrays, where the innermost one is a tuple-thingie with an optional 3rd item; this is an `ARR_FIXED`, not an `ARR`. ACKs for top commit: MarcoFalke: ACK 7031721f2cc3eef30c46ff50c52328e9ba8090e0 🐀 Tree-SHA512: 769377416c6226d1738a956fb685498e009f9e7eb2d45bc679b81c5364b9520fdbcb49392c937ab45598aa0d33589e8e6a59ccc101cf8d8e7dfdafd58d4eefd0 --- src/rpc/rawtransaction.cpp | 2 +- src/rpc/util.h | 4 ++-- src/wallet/rpcwallet.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3164e7884a1a0..e5ffa1f317a67 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -753,7 +753,7 @@ static RPCHelpMan createrawtransaction() "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" " accepted as second parameter.", { - {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "", { {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the Dash address, the value (float or string) is the amount in " + CURRENCY_UNIT}, }, diff --git a/src/rpc/util.h b/src/rpc/util.h index c9192a3a10a1e..189551cd03793 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -174,7 +174,7 @@ struct RPCArg { m_oneline_description{std::move(oneline_description)}, m_type_str{std::move(type_str)} { - CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ); + CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ && type != Type::OBJ_USER_KEYS); } RPCArg( @@ -194,7 +194,7 @@ struct RPCArg { m_oneline_description{std::move(oneline_description)}, m_type_str{std::move(type_str)} { - CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ); + CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ || type == Type::OBJ_USER_KEYS); } bool IsOptional() const; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7a0760f898861..71d2c2c15cbfe 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -535,7 +535,7 @@ static RPCHelpMan listaddressgroupings() { {RPCResult::Type::ARR, "", "", { - {RPCResult::Type::ARR, "", "", + {RPCResult::Type::ARR_FIXED, "", "", { {RPCResult::Type::STR, "address", "The Dash address"}, {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT}, From 7522ee9868d0a1646be03c9a14c04513abf64088 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 10 May 2021 17:50:15 +0200 Subject: [PATCH 06/11] Merge bitcoin/bitcoin#21900: test: use MiniWallet for feature_csv_activation.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bd7f27d16dacf6f7de3b4f6bd052def41d9601be refactor: feature_csv_activation.py: move tx helper functions to methods (Sebastian Falbesoner) 2eca46b0aa0ecf4738500b53523d7013985b387d test: use MiniWallet for feature_csv_activation.py (Sebastian Falbesoner) Pull request description: This PR enables one more of the non-wallet functional tests (feature_csv_activation.py) to be run even with the Bitcoin Core wallet disabled by using the new MiniWallet instead, as proposed in #20078. Short reviewers guideline: - Since we exclusively work with anyone-can-spend outputs here (raw scriptPubKey = OP_TRUE), signing is not needed anymore. The function `sign_transaction` and its calls are removed, after changing a tx (e.g. its scriptSig or nVersion) a simple `.rehash()` call is sufficient. Also, generating an address `self.nodeaddress` (and with that, passing it to the the various test tx creation/sending helper methods) is not needed anymore and removed. - The test repeatedly uses the same input for creating different txs (e.g. with different txversions 1 and 2). To let `MiniWallet` create a tx with a specific input, we have to call `.get_utxo()` before which also marks the UTXO as spent. The method is changed to also support keeping the UTXO in its internal list (`mark_as_spent=False`). With the behaviour on master, the second call to `.get_utxo()` with the same input would fail. - To keep the diff in the first commit short, the `miniwallet` is set as a global variable, to avoid passing it on every tx creation/spending helper. The global is eliminated in the second (refactoring) commit, where all the helpers are moved to the test class as methods. By that, we can use `self.nodes[0]` directly in the helpers and don't have to pass it again and again. I think there could still be a lot of improvements/refactoring done in the test, but that should hopefully serve as a good basis. ACKs for top commit: laanwj: Code review ACK bd7f27d16dacf6f7de3b4f6bd052def41d9601be MarcoFalke: review ACK bd7f27d16dacf6f7de3b4f6bd052def41d9601be 🐕 Tree-SHA512: 24fb6a0f7702bae40d5271d197119827067d4b597e954d182e4c1aa5d0fa870368eb3ffed469b26713fa8ff8eb3ecc06abc80b2449cd68156d5559e7ae8a2b11 --- test/functional/feature_csv_activation.py | 202 +++++++++++----------- test/functional/test_framework/wallet.py | 7 +- 2 files changed, 104 insertions(+), 105 deletions(-) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 5fca60414c9ee..2bd31623710bd 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -37,12 +37,13 @@ bip112tx_special - test negative argument to OP_CSV bip112tx_emptystack - test empty stack (= no argument) OP_CSV """ -from decimal import Decimal from itertools import product -from io import BytesIO -from test_framework.blocktools import create_coinbase, create_block, create_transaction, TIME_GENESIS_BLOCK -from test_framework.messages import CTransaction +from test_framework.blocktools import ( + create_block, + create_coinbase, + TIME_GENESIS_BLOCK, +) from test_framework.p2p import P2PDataStore from test_framework.script import ( CScript, @@ -52,9 +53,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - hex_str_to_bytes, softfork_active, ) +from test_framework.wallet import MiniWallet TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above) COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs @@ -82,66 +83,6 @@ def relative_locktime(sdf, srhb, stf, srlb): def all_rlt_txs(txs): return [tx['tx'] for tx in txs] -def sign_transaction(node, unsignedtx): - rawtx = unsignedtx.serialize().hex() - signresult = node.signrawtransactionwithwallet(rawtx) - tx = CTransaction() - f = BytesIO(hex_str_to_bytes(signresult['hex'])) - tx.deserialize(f) - return tx - -def create_bip112special(node, input, txversion, address): - tx = create_transaction(node, input, address, amount=Decimal("499.98")) - tx.nVersion = txversion - signtx = sign_transaction(node, tx) - signtx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) - return signtx - -def create_bip112emptystack(node, input, txversion, address): - tx = create_transaction(node, input, address, amount=Decimal("499.98")) - tx.nVersion = txversion - signtx = sign_transaction(node, tx) - signtx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(signtx.vin[0].scriptSig))) - return signtx - -def send_generic_input_tx(node, coinbases, address): - return node.sendrawtransaction(sign_transaction(node, create_transaction(node, node.getblock(coinbases.pop())['tx'][0], address, amount=Decimal("499.99"))).serialize().hex()) - -def create_bip68txs(node, bip68inputs, txversion, address, locktime_delta=0): - """Returns a list of bip68 transactions with different bits set.""" - txs = [] - assert len(bip68inputs) >= 16 - for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)): - locktime = relative_locktime(sdf, srhb, stf, srlb) - tx = create_transaction(node, bip68inputs[i], address, amount=Decimal("499.98")) - tx.nVersion = txversion - tx.vin[0].nSequence = locktime + locktime_delta - tx = sign_transaction(node, tx) - tx.rehash() - txs.append({'tx': tx, 'sdf': sdf, 'stf': stf}) - - return txs - -def create_bip112txs(node, bip112inputs, varyOP_CSV, txversion, address, locktime_delta=0): - """Returns a list of bip68 transactions with different bits set.""" - txs = [] - assert len(bip112inputs) >= 16 - for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)): - locktime = relative_locktime(sdf, srhb, stf, srlb) - tx = create_transaction(node, bip112inputs[i], address, amount=Decimal("499.98")) - if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed - tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta - else: # vary nSequence instead, OP_CSV is fixed - tx.vin[0].nSequence = locktime + locktime_delta - tx.nVersion = txversion - signtx = sign_transaction(node, tx) - if (varyOP_CSV): - signtx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) - else: - signtx.vin[0].scriptSig = CScript([BASE_RELATIVE_LOCKTIME, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) - tx.rehash() - txs.append({'tx': signtx, 'sdf': sdf, 'stf': stf}) - return txs class BIP68_112_113Test(BitcoinTestFramework): def set_test_params(self): @@ -152,6 +93,7 @@ def set_test_params(self): self.extra_args = [[ '-whitelist=noban@127.0.0.1', '-maxtipage=600100', '-dip3params=2000:2000', + '-acceptnonstdtxn=1', '-par=1', # Use only one script thread to get the exact reject reason for testing ]] self.supports_cli = False @@ -159,8 +101,61 @@ def set_test_params(self): def setup_network(self): self.setup_nodes() - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() + def create_self_transfer_from_utxo(self, input_tx): + utxo = self.miniwallet.get_utxo(txid=input_tx.rehash(), mark_as_spent=False) + tx = self.miniwallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo)['tx'] + return tx + + def create_bip112special(self, input, txversion): + tx = self.create_self_transfer_from_utxo(input) + tx.nVersion = txversion + tx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) + return tx + + def create_bip112emptystack(self, input, txversion): + tx = self.create_self_transfer_from_utxo(input) + tx.nVersion = txversion + tx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(tx.vin[0].scriptSig))) + return tx + + def send_generic_input_tx(self, coinbases): + input_txid = self.nodes[0].getblock(coinbases.pop(), 2)['tx'][0]['txid'] + utxo_to_spend = self.miniwallet.get_utxo(txid=input_txid) + return self.miniwallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_to_spend)['tx'] + + def create_bip68txs(self, bip68inputs, txversion, locktime_delta=0): + """Returns a list of bip68 transactions with different bits set.""" + txs = [] + assert len(bip68inputs) >= 16 + for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)): + locktime = relative_locktime(sdf, srhb, stf, srlb) + tx = self.create_self_transfer_from_utxo(bip68inputs[i]) + tx.nVersion = txversion + tx.vin[0].nSequence = locktime + locktime_delta + tx.rehash() + txs.append({'tx': tx, 'sdf': sdf, 'stf': stf}) + + return txs + + def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta=0): + """Returns a list of bip68 transactions with different bits set.""" + txs = [] + assert len(bip112inputs) >= 16 + for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)): + locktime = relative_locktime(sdf, srhb, stf, srlb) + tx = self.create_self_transfer_from_utxo(bip112inputs[i]) + if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed + tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta + else: # vary nSequence instead, OP_CSV is fixed + tx.vin[0].nSequence = locktime + locktime_delta + tx.nVersion = txversion + if (varyOP_CSV): + tx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) + else: + tx.vin[0].scriptSig = CScript([BASE_RELATIVE_LOCKTIME, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) + tx.rehash() + txs.append({'tx': tx, 'sdf': sdf, 'stf': stf}) + return txs def generate_blocks(self, number): test_blocks = [] @@ -189,16 +184,16 @@ def send_blocks(self, blocks, success=True, reject_reason=None): def run_test(self): self.helper_peer = self.nodes[0].add_p2p_connection(P2PDataStore()) + self.miniwallet = MiniWallet(self.nodes[0], raw_script=True) self.log.info("Generate blocks in the past for coinbase outputs.") - self.coinbase_blocks = self.nodes[0].generate(COINBASE_BLOCK_COUNT) # blocks generated for inputs + self.coinbase_blocks = self.miniwallet.generate(COINBASE_BLOCK_COUNT) # blocks generated for inputs # set time so that there was enough time to build up to 1000 blocks 10 minutes apart on top of the last one # without worrying about getting into the future self.nodes[0].setmocktime(TIME_GENESIS_BLOCK + 600 * 1000 + 100) self.tipheight = COINBASE_BLOCK_COUNT # height of the next block to build self.last_block_time = TIME_GENESIS_BLOCK self.tip = int(self.nodes[0].getbestblockhash(), 16) - self.nodeaddress = self.nodes[0].getnewaddress() # Activation height is hardcoded test_blocks = self.generate_blocks(CSV_ACTIVATION_HEIGHT-5 - COINBASE_BLOCK_COUNT) @@ -213,14 +208,14 @@ def run_test(self): # 16 normal inputs bip68inputs = [] for _ in range(16): - bip68inputs.append(send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)) + bip68inputs.append(self.send_generic_input_tx(self.coinbase_blocks)) # 2 sets of 16 inputs with 10 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) bip112basicinputs = [] for _ in range(2): inputs = [] for _ in range(16): - inputs.append(send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)) + inputs.append(self.send_generic_input_tx(self.coinbase_blocks)) bip112basicinputs.append(inputs) # 2 sets of 16 varied inputs with (relative_lock_time) OP_CSV OP_DROP (actually will be prepended to spending scriptSig) @@ -228,16 +223,16 @@ def run_test(self): for _ in range(2): inputs = [] for _ in range(16): - inputs.append(send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)) + inputs.append(self.send_generic_input_tx(self.coinbase_blocks)) bip112diverseinputs.append(inputs) # 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) - bip112specialinput = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress) + bip112specialinput = self.send_generic_input_tx(self.coinbase_blocks) # 1 special input with (empty stack) OP_CSV (actually will be prepended to spending scriptSig) - bip112emptystackinput = send_generic_input_tx(self.nodes[0],self.coinbase_blocks, self.nodeaddress) + bip112emptystackinput = self.send_generic_input_tx(self.coinbase_blocks) # 1 normal input - bip113input = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress) + bip113input = self.send_generic_input_tx(self.coinbase_blocks) self.nodes[0].setmocktime(self.last_block_time + 600) inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 431 @@ -257,36 +252,36 @@ def run_test(self): # Test both version 1 and version 2 transactions for all tests # BIP113 test transaction will be modified before each use to put in appropriate block time - bip113tx_v1 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, amount=Decimal("499.98")) + bip113tx_v1 = self.create_self_transfer_from_utxo(bip113input) bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE bip113tx_v1.nVersion = 1 - bip113tx_v2 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, amount=Decimal("499.98")) + bip113tx_v2 = self.create_self_transfer_from_utxo(bip113input) bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE bip113tx_v2.nVersion = 2 # For BIP68 test all 16 relative sequence locktimes - bip68txs_v1 = create_bip68txs(self.nodes[0], bip68inputs, 1, self.nodeaddress) - bip68txs_v2 = create_bip68txs(self.nodes[0], bip68inputs, 2, self.nodeaddress) + bip68txs_v1 = self.create_bip68txs(bip68inputs, 1) + bip68txs_v2 = self.create_bip68txs(bip68inputs, 2) # For BIP112 test: # 16 relative sequence locktimes of 10 against 10 OP_CSV OP_DROP inputs - bip112txs_vary_nSequence_v1 = create_bip112txs(self.nodes[0], bip112basicinputs[0], False, 1, self.nodeaddress) - bip112txs_vary_nSequence_v2 = create_bip112txs(self.nodes[0], bip112basicinputs[0], False, 2, self.nodeaddress) + bip112txs_vary_nSequence_v1 = self.create_bip112txs(bip112basicinputs[0], False, 1) + bip112txs_vary_nSequence_v2 = self.create_bip112txs(bip112basicinputs[0], False, 2) # 16 relative sequence locktimes of 9 against 10 OP_CSV OP_DROP inputs - bip112txs_vary_nSequence_9_v1 = create_bip112txs(self.nodes[0], bip112basicinputs[1], False, 1, self.nodeaddress, -1) - bip112txs_vary_nSequence_9_v2 = create_bip112txs(self.nodes[0], bip112basicinputs[1], False, 2, self.nodeaddress, -1) + bip112txs_vary_nSequence_9_v1 = self.create_bip112txs(bip112basicinputs[1], False, 1, -1) + bip112txs_vary_nSequence_9_v2 = self.create_bip112txs(bip112basicinputs[1], False, 2, -1) # sequence lock time of 10 against 16 (relative_lock_time) OP_CSV OP_DROP inputs - bip112txs_vary_OP_CSV_v1 = create_bip112txs(self.nodes[0], bip112diverseinputs[0], True, 1, self.nodeaddress) - bip112txs_vary_OP_CSV_v2 = create_bip112txs(self.nodes[0], bip112diverseinputs[0], True, 2, self.nodeaddress) + bip112txs_vary_OP_CSV_v1 = self.create_bip112txs(bip112diverseinputs[0], True, 1) + bip112txs_vary_OP_CSV_v2 = self.create_bip112txs(bip112diverseinputs[0], True, 2) # sequence lock time of 9 against 16 (relative_lock_time) OP_CSV OP_DROP inputs - bip112txs_vary_OP_CSV_9_v1 = create_bip112txs(self.nodes[0], bip112diverseinputs[1], True, 1, self.nodeaddress, -1) - bip112txs_vary_OP_CSV_9_v2 = create_bip112txs(self.nodes[0], bip112diverseinputs[1], True, 2, self.nodeaddress, -1) + bip112txs_vary_OP_CSV_9_v1 = self.create_bip112txs(bip112diverseinputs[1], True, 1, -1) + bip112txs_vary_OP_CSV_9_v2 = self.create_bip112txs(bip112diverseinputs[1], True, 2, -1) # -1 OP_CSV OP_DROP input - bip112tx_special_v1 = create_bip112special(self.nodes[0], bip112specialinput, 1, self.nodeaddress) - bip112tx_special_v2 = create_bip112special(self.nodes[0], bip112specialinput, 2, self.nodeaddress) + bip112tx_special_v1 = self.create_bip112special(bip112specialinput, 1) + bip112tx_special_v2 = self.create_bip112special(bip112specialinput, 2) # (empty stack) OP_CSV input - bip112tx_emptystack_v1 = create_bip112emptystack(self.nodes[0], bip112emptystackinput, 1, self.nodeaddress) - bip112tx_emptystack_v2 = create_bip112emptystack(self.nodes[0], bip112emptystackinput, 2, self.nodeaddress) + bip112tx_emptystack_v1 = self.create_bip112emptystack(bip112emptystackinput, 1) + bip112tx_emptystack_v2 = self.create_bip112emptystack(bip112emptystackinput, 2) self.log.info("TESTING") @@ -296,8 +291,8 @@ def run_test(self): success_txs = [] # BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block - bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1) - success_txs.append(bip113signed1) + bip113tx_v1.rehash() + success_txs.append(bip113tx_v1) success_txs.append(bip112tx_special_v1) success_txs.append(bip112tx_emptystack_v1) # add BIP 68 txs @@ -316,8 +311,8 @@ def run_test(self): success_txs = [] # BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block - bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2) - success_txs.append(bip113signed2) + bip113tx_v2.rehash() + success_txs.append(bip113tx_v2) success_txs.append(bip112tx_special_v2) success_txs.append(bip112tx_emptystack_v2) # add BIP 68 txs @@ -342,17 +337,18 @@ def run_test(self): self.log.info("BIP 113 tests") # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block - bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1) + bip113tx_v1.rehash() bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block - bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2) - for bip113tx in [bip113signed1, bip113signed2]: + bip113tx_v2.rehash() + for bip113tx in [bip113tx_v1, bip113tx_v2]: self.send_blocks([self.create_test_block([bip113tx])], success=False, reject_reason='bad-txns-nonfinal') + # BIP 113 tests should now pass if the locktime is < MTP bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block - bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1) + bip113tx_v1.rehash() bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block - bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2) - for bip113tx in [bip113signed1, bip113signed2]: + bip113tx_v2.rehash() + for bip113tx in [bip113tx_v1, bip113tx_v2]: self.send_blocks([self.create_test_block([bip113tx])]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) @@ -475,8 +471,8 @@ def run_test(self): time_txs = [] for tx in [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]: tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG - signtx = sign_transaction(self.nodes[0], tx) - time_txs.append(signtx) + tx.rehash() + time_txs.append(tx) self.send_blocks([self.create_test_block(time_txs)]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 1c09c61eefd5c..547e399fa5520 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -61,7 +61,7 @@ def generate(self, num_blocks): def get_address(self): return self._address - def get_utxo(self, *, txid: Optional[str]=''): + def get_utxo(self, *, txid: Optional[str]='', mark_as_spent=True): """ Returns a utxo and marks it as spent (pops it from the internal list) @@ -74,7 +74,10 @@ def get_utxo(self, *, txid: Optional[str]=''): if txid: utxo = next(filter(lambda utxo: txid == utxo['txid'], self._utxos)) index = self._utxos.index(utxo) - return self._utxos.pop(index) + if mark_as_spent: + return self._utxos.pop(index) + else: + return self._utxos[index] def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None): """Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" From 5d10b41302fdcee7addb6cddebbbb205a9515270 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 4 May 2021 06:49:17 +0200 Subject: [PATCH 07/11] Merge bitcoin/bitcoin#21840: test: Misc refactor to get rid of &foo[0] raw pointers fa8a88849c08c810a82338bf0e70738eb6748906 bench: Remove duplicate constants (MarcoFalke) 000098f9647cd2e21660603b7d7a8f623f70f673 test: Use throwing variant accessor (MarcoFalke) fa2197c8b3178787d99e2acb5c3c717df14ddabf test: Use loop to register RPCs (MarcoFalke) Pull request description: Simplify test code ACKs for top commit: Empact: Code Review ACK fa8a88849c08c810a82338bf0e70738eb6748906 practicalswift: cr ACK fa8a88849c08c810a82338bf0e70738eb6748906 promag: Code review ACK fa8a88849c08c810a82338bf0e70738eb6748906. Tree-SHA512: 6a5bebaa9a3f43e9c332f4fbff606e9ece6dc8b95a769980082cc022f8e9bde6083c1e4a0145dcbf3741f514d6e97b4198f201a1bf1370ebf43bd3a5c0f85981 --- src/bench/block_assemble.cpp | 5 +++-- src/qt/test/rpcnestedtests.cpp | 8 ++++---- src/test/script_standard_tests.cpp | 24 ++++++++---------------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 322bc5ec62f33..a23b9e8ac6433 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -7,6 +7,7 @@ #include #include