From 7774c314fb3c342eb5d48015b1c1b8b66d3d87db Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Thu, 9 May 2024 18:52:27 +0200 Subject: [PATCH 01/91] test: refactor: return TaprootInfo from P2TR address creation routine Rather than only returning the internal key from the P2TR anyone-can-spend address creation routine, provide the whole TaprootInfo object, which in turn contains a dictionary of TaprootLeafInfo object for named leaves. This data is used in MiniWallet for the default ADDRESS_OP_TRUE mode, in order to deduplicate the witness script and leaf version of the control block. --- test/functional/test_framework/address.py | 7 ++++--- test/functional/test_framework/wallet.py | 10 +++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index bcb38b21cd..968069ff18 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -53,13 +53,14 @@ def create_deterministic_address_bcrt1_p2tr_op_true(explicit_internal_key=None): can be spent with a witness stack of OP_TRUE and the control block with internal public key (script-path spending). - Returns a tuple with the generated address and the internal key. + Returns a tuple with the generated address and the TaprootInfo object. """ internal_key = explicit_internal_key or (1).to_bytes(32, 'big') - address = output_key_to_p2tr(taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).output_pubkey) + taproot_info = taproot_construct(internal_key, [("only-path", CScript([OP_TRUE]))]) + address = output_key_to_p2tr(taproot_info.output_pubkey) if explicit_internal_key is None: assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka') - return (address, internal_key) + return (address, taproot_info) def byte_to_base58(b, version): diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 7d4f4a3392..82553c6fc4 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -39,7 +39,6 @@ ) from test_framework.script import ( CScript, - LEAF_VERSION_TAPSCRIPT, OP_1, OP_NOP, OP_RETURN, @@ -107,7 +106,7 @@ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE, tag_name=N self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes()) elif mode == MiniWalletMode.ADDRESS_OP_TRUE: internal_key = None if tag_name is None else hash256(tag_name.encode()) - self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true(internal_key) + self._address, self._taproot_info = create_deterministic_address_bcrt1_p2tr_op_true(internal_key) self._scriptPubKey = address_to_scriptpubkey(self._address) # When the pre-mined test framework chain is used, it contains coinbase @@ -195,7 +194,12 @@ def sign_tx(self, tx, fixed_length=True): elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE: tx.wit.vtxinwit = [CTxInWitness()] * len(tx.vin) for i in tx.wit.vtxinwit: - i.scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key] + assert_equal(len(self._taproot_info.leaves), 1) + leaf_info = list(self._taproot_info.leaves.values())[0] + i.scriptWitness.stack = [ + leaf_info.script, + bytes([leaf_info.version]) + self._taproot_info.internal_pubkey, + ] else: assert False From c9f7364ab2bccad56a4473dbd18d9c80eaf651d4 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Thu, 9 May 2024 19:17:57 +0200 Subject: [PATCH 02/91] test: fix MiniWallet script-path spend (missing parity bit in leaf version) This commit fixes a dormant bug in MiniWallet that exists since support for P2TR was initially added in #23371 (see commit 041abfebe49ae5e3e882c00cc5caea1365a27a49). In the course of spending the output, the leaf version byte of the control block in the witness stack doesn't set the parity bit, i.e. we were so far just lucky that the used combinations of relevant data (internal pubkey, leaf script / version) didn't result in a tweaked pubkey with odd y-parity. If that was the case, we'd get the following validation error: `mandatory-script-verify-flag-failed (Witness program hash mismatch) (-26)` Since MiniWallets can now optionally be tagged (#29939), resulting in different internal pubkeys, the issue is more prevalent now. Fix it by passing the parity bit, as specified in BIP341. --- test/functional/test_framework/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 82553c6fc4..e816f6fedd 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -198,7 +198,7 @@ def sign_tx(self, tx, fixed_length=True): leaf_info = list(self._taproot_info.leaves.values())[0] i.scriptWitness.stack = [ leaf_info.script, - bytes([leaf_info.version]) + self._taproot_info.internal_pubkey, + bytes([leaf_info.version | self._taproot_info.negflag]) + self._taproot_info.internal_pubkey, ] else: assert False From 3162c917e93fde4bea6e4627bb0c3c7cdc37386c Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Tue, 11 Jun 2024 02:13:18 +0200 Subject: [PATCH 03/91] test: fix MiniWallet internal key derivation for tagged instances Not every pseudorandom hash result is a valid x-only public key, so the pubkey tweaking in the course of creating the output public key would fail about every second time. Fix this by treating the hash result as private key and calculate the x-only public key out of that, to be used then as internal key. --- test/functional/test_framework/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index e816f6fedd..0d37b7ffb5 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -105,7 +105,7 @@ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE, tag_name=N pub_key = self._priv_key.get_pubkey() self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes()) elif mode == MiniWalletMode.ADDRESS_OP_TRUE: - internal_key = None if tag_name is None else hash256(tag_name.encode()) + internal_key = None if tag_name is None else compute_xonly_pubkey(hash256(tag_name.encode()))[0] self._address, self._taproot_info = create_deterministic_address_bcrt1_p2tr_op_true(internal_key) self._scriptPubKey = address_to_scriptpubkey(self._address) From e4b0dabb2115dc74e9c5794ddca3822cd8301c72 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Tue, 11 Jun 2024 02:19:54 +0200 Subject: [PATCH 04/91] test: add functional test for tagged MiniWallet instances --- .../functional/feature_framework_miniwallet.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/functional/feature_framework_miniwallet.py b/test/functional/feature_framework_miniwallet.py index f108289018..55c837a1b7 100755 --- a/test/functional/feature_framework_miniwallet.py +++ b/test/functional/feature_framework_miniwallet.py @@ -3,6 +3,9 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test MiniWallet.""" +import random +import string + from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -31,6 +34,20 @@ def test_tx_padding(self): assert_greater_than_or_equal(tx.get_weight(), target_weight) assert_greater_than_or_equal(target_weight + 3, tx.get_weight()) + def test_wallet_tagging(self): + """Verify that tagged wallet instances are able to send funds.""" + self.log.info(f"Test tagged wallet instances...") + node = self.nodes[0] + untagged_wallet = self.wallets[0][1] + for i in range(10): + tag = ''.join(random.choice(string.ascii_letters) for _ in range(20)) + self.log.debug(f"-> ({i}) tag name: {tag}") + tagged_wallet = MiniWallet(node, tag_name=tag) + untagged_wallet.send_to(from_node=node, scriptPubKey=tagged_wallet.get_scriptPubKey(), amount=100000) + tagged_wallet.rescan_utxos() + tagged_wallet.send_self_transfer(from_node=node) + self.generate(node, 1) # clear mempool + def run_test(self): node = self.nodes[0] self.wallets = [ @@ -43,6 +60,7 @@ def run_test(self): self.generate(wallet, COINBASE_MATURITY) self.test_tx_padding() + self.test_wallet_tagging() if __name__ == '__main__': From 6bbc2dd6c50f09ff1e70423dc29a404b570f5b69 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 3 Jul 2024 23:46:32 +1000 Subject: [PATCH 05/91] logging: Add thread safety annotations --- src/logging.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/logging.h b/src/logging.h index fe6b7051ba..2f24f32886 100644 --- a/src/logging.h +++ b/src/logging.h @@ -127,17 +127,18 @@ namespace BCLog { std::string GetLogPrefix(LogFlags category, Level level) const; /** Send a string to the log output */ - void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level); + void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Returns whether logs will be written to any output */ - bool Enabled() const + bool Enabled() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); return m_buffering || m_print_to_console || m_print_to_file || !m_print_callbacks.empty(); } /** Connect a slot to the print signal and return the connection */ - std::list>::iterator PushBackCallback(std::function fun) + std::list>::iterator PushBackCallback(std::function fun) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); m_print_callbacks.push_back(std::move(fun)); @@ -145,30 +146,30 @@ namespace BCLog { } /** Delete a connection */ - void DeleteCallback(std::list>::iterator it) + void DeleteCallback(std::list>::iterator it) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); m_print_callbacks.erase(it); } /** Start logging (and flush all buffered messages) */ - bool StartLogging(); + bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Only for testing */ - void DisconnectTestLogger(); + void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); void ShrinkDebugFile(); - std::unordered_map CategoryLevels() const + std::unordered_map CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); return m_category_log_levels; } - void SetCategoryLogLevel(const std::unordered_map& levels) + void SetCategoryLogLevel(const std::unordered_map& levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); m_category_log_levels = levels; } - bool SetCategoryLogLevel(const std::string& category_str, const std::string& level_str); + bool SetCategoryLogLevel(const std::string& category_str, const std::string& level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); Level LogLevel() const { return m_log_level.load(); } void SetLogLevel(Level level) { m_log_level = level; } @@ -182,7 +183,7 @@ namespace BCLog { bool DisableCategory(const std::string& str); bool WillLogCategory(LogFlags category) const; - bool WillLogCategoryLevel(LogFlags category, Level level) const; + bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Returns a vector of the log categories in alphabetical order. */ std::vector LogCategoriesList() const; From 29eafd5733d77b3e8f3f3ab6cd65c61ac0e8536b Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Mon, 8 Jul 2024 17:12:26 +0200 Subject: [PATCH 06/91] rpc: doc: use "output script" terminology consistently in "asm"/"hex" results The wording "public key script" was likely chosen as a human-readable form of the technical term `scriptPubKey`, but it doesn't seem to be really widespread. Replace it by the more common term "output script" instead. Note that the argument for the `decodescript` RPC is not necessarily an output script (it could e.g. be also a redeem script), so in this case we just stay generic and use "script". See also the draft BIP "Terminology for Transaction Components" (https://github.com/murchandamus/bips/blob/2022-04-tx-terminology/bip-tx-terminology.mediawiki) which suggests to use "output script" as well. Affects the help text of the following RPCs: - decodepsbt - decoderawtransaction - decodescript - getblock (if verbosity=3) - getrawtransaction (if verbosity=2,3) - gettxout --- src/rpc/blockchain.cpp | 8 ++++---- src/rpc/rawtransaction.cpp | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 9b5c3ab5ff..73999f6f84 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -654,9 +654,9 @@ const RPCResult getblock_vin{ {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, + {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"}, }}, @@ -1056,9 +1056,9 @@ static RPCHelpMan gettxout() {RPCResult::Type::NUM, "confirmations", "The number of confirmations"}, {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, + {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, }}, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 75b538061d..d407cfc081 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -85,9 +85,9 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& static std::vector ScriptPubKeyDoc() { return { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, + {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"}, }; @@ -506,18 +506,18 @@ static RPCHelpMan decodescript() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::STR, "asm", "Script public key"}, + {RPCResult::Type::STR, "asm", "Disassembly of the script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, {RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "p2sh", /*optional=*/true, "address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped)"}, {RPCResult::Type::OBJ, "segwit", /*optional=*/true, - "Result of a witness script public key wrapping this redeem script (not returned for types that should not be wrapped)", + "Result of a witness output script wrapping this redeem script (not returned for types that should not be wrapped)", { - {RPCResult::Type::STR, "asm", "String representation of the script public key"}, - {RPCResult::Type::STR_HEX, "hex", "Hex string of the script public key"}, - {RPCResult::Type::STR, "type", "The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash)"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, + {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, + {RPCResult::Type::STR, "type", "The type of the output script (e.g. witness_v0_keyhash or witness_v0_scripthash)"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, {RPCResult::Type::STR, "p2sh-segwit", "address of the P2SH script wrapping this witness redeem script"}, @@ -833,9 +833,9 @@ const RPCResult decodepsbt_inputs{ {RPCResult::Type::NUM, "amount", "The value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, + {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, }}, From 0b1960f1b29cfe5209ac68102c8643fc9553f247 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Thu, 4 Jul 2024 00:52:29 +1000 Subject: [PATCH 07/91] logging: Add DisableLogging() --- src/bitcoin-chainstate.cpp | 7 +++++++ src/logging.cpp | 12 ++++++++++++ src/logging.h | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index ecbdcd48bb..697096586e 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,12 @@ int main(int argc, char* argv[]) { + // We do not enable logging for this app, so explicitly disable it. + // To enable logging instead, replace with: + // LogInstance().m_print_to_console = true; + // LogInstance().StartLogging(); + LogInstance().DisableLogging(); + // SETUP: Argument parsing and handling if (argc != 2) { std::cerr diff --git a/src/logging.cpp b/src/logging.cpp index a9fea433be..53af7d5ca7 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -96,6 +96,18 @@ void BCLog::Logger::DisconnectTestLogger() m_print_callbacks.clear(); } +void BCLog::Logger::DisableLogging() +{ + { + StdLockGuard scoped_lock(m_cs); + assert(m_buffering); + assert(m_print_callbacks.empty()); + } + m_print_to_file = false; + m_print_to_console = false; + StartLogging(); +} + void BCLog::Logger::EnableCategory(BCLog::LogFlags flag) { m_categories |= flag; diff --git a/src/logging.h b/src/logging.h index 2f24f32886..70539f03b0 100644 --- a/src/logging.h +++ b/src/logging.h @@ -157,6 +157,14 @@ namespace BCLog { /** Only for testing */ void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); + /** Disable logging + * This offers a slight speedup and slightly smaller memory usage + * compared to leaving the logging system in its default state. + * Mostly intended for libbitcoin-kernel apps that don't want any logging. + * Should be used instead of StartLogging(). + */ + void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); + void ShrinkDebugFile(); std::unordered_map CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) From 3eb1307df0a38ac4ea52995fbb03ead37387b41e Mon Sep 17 00:00:00 2001 From: glozow Date: Tue, 25 Jul 2023 14:21:20 +0100 Subject: [PATCH 08/91] guard TxRequest and rejection caches with new mutex We need to synchronize between various tx download structures. TxRequest does not inherently need cs_main for synchronization, and it's not appropriate to lock all of the tx download logic under cs_main. --- src/net_processing.cpp | 89 +++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d674758abd..95ef67b160 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -490,9 +490,9 @@ class PeerManagerImpl final : public PeerManager /** Overridden from CValidationInterface. */ void BlockConnected(ChainstateRole role, const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); void BlockDisconnected(const std::shared_ptr &block, const CBlockIndex* pindex) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void BlockChecked(const CBlock& block, const BlockValidationState& state) override @@ -501,13 +501,13 @@ class PeerManagerImpl final : public PeerManager EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex); /** Implement NetEventsInterface */ - void InitializeNode(const CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex); + void InitializeNode(const CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_tx_download_mutex); + void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, !m_tx_download_mutex); bool HasAllDesirableServiceFlags(ServiceFlags services) const override; bool ProcessMessages(CNode* pfrom, std::atomic& interrupt) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); bool SendMessages(CNode* pto) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex); /** Implement PeerManager */ void StartScheduledTasks(CScheduler& scheduler) override; @@ -526,7 +526,7 @@ class PeerManagerImpl final : public PeerManager void UnitTestMisbehaving(NodeId peer_id) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), ""); }; void ProcessMessage(CNode& pfrom, const std::string& msg_type, DataStream& vRecv, const std::chrono::microseconds time_received, const std::atomic& interruptMsgProc) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override; @@ -585,12 +585,12 @@ class PeerManagerImpl final : public PeerManager * Updates m_txrequest, m_recent_rejects, m_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact. */ void ProcessInvalidTx(NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result, bool maybe_add_extra_compact_tx) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); /** Handle a transaction whose result was MempoolAcceptResult::ResultType::VALID. * Updates m_txrequest, m_orphanage, and vExtraTxnForCompact. Also queues the tx for relay. */ void ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list& replaced_transactions) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); struct PackageToValidate { const Package m_txns; @@ -620,13 +620,13 @@ class PeerManagerImpl final : public PeerManager * individual transactions, and caches rejection for the package as a group. */ void ProcessPackageResult(const PackageToValidate& package_to_validate, const PackageMempoolAcceptResult& package_result) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); /** Look for a child of this transaction in the orphanage to form a 1-parent-1-child package, * skipping any combinations that have already been tried. Return the resulting package along with * the senders of its respective transactions, or std::nullopt if no package is found. */ std::optional Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); /** * Reconsider orphan transactions after a parent has been accepted to the mempool. @@ -640,7 +640,7 @@ class PeerManagerImpl final : public PeerManager * will be empty. */ bool ProcessOrphanTx(Peer& peer) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, !m_tx_download_mutex); /** Process a single headers message from a peer. * @@ -722,7 +722,7 @@ class PeerManagerImpl final : public PeerManager * peer. The announcement parameters are decided in PeerManager and then * passed to TxRequestTracker. */ void AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time) - EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_tx_download_mutex); /** Send a message to a peer */ void PushMessage(CNode& node, CSerializedNetMsg&& msg) const { m_connman.PushMessage(&node, std::move(msg)); } @@ -770,7 +770,19 @@ class PeerManagerImpl final : public PeerManager BanMan* const m_banman; ChainstateManager& m_chainman; CTxMemPool& m_mempool; - TxRequestTracker m_txrequest GUARDED_BY(::cs_main); + + /** Synchronizes tx download including TxRequestTracker, rejection filters, and TxOrphanage. + * Lock invariants: + * - A txhash (txid or wtxid) in m_txrequest is not also in m_orphanage. + * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects. + * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects_reconsiderable. + * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_confirmed_transactions. + * - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc). + * + * m_tx_download_mutex must be acquired before mempool.cs + */ + Mutex m_tx_download_mutex; + TxRequestTracker m_txrequest GUARDED_BY(m_tx_download_mutex); std::unique_ptr m_txreconciliation; /** The height of the best chain */ @@ -851,7 +863,7 @@ class PeerManagerImpl final : public PeerManager * chain tip has changed. * */ bool AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex); + EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex, m_tx_download_mutex); /** * Filter for transactions that were recently rejected by the mempool. @@ -887,10 +899,10 @@ class PeerManagerImpl final : public PeerManager * * Memory used: 1.3 MB */ - CRollingBloomFilter m_recent_rejects GUARDED_BY(::cs_main){120'000, 0.000'001}; + CRollingBloomFilter m_recent_rejects GUARDED_BY(m_tx_download_mutex){120'000, 0.000'001}; /** Block hash of chain tip the last time we reset m_recent_rejects and * m_recent_rejects_reconsiderable. */ - uint256 hashRecentRejectsChainTip GUARDED_BY(cs_main); + uint256 hashRecentRejectsChainTip GUARDED_BY(m_tx_download_mutex); /** * Filter for: @@ -912,7 +924,7 @@ class PeerManagerImpl final : public PeerManager * * Parameters are picked to be the same as m_recent_rejects, with the same rationale. */ - CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY(::cs_main){120'000, 0.000'001}; + CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY(m_tx_download_mutex){120'000, 0.000'001}; /* * Filter for transactions that have been recently confirmed. @@ -1067,7 +1079,7 @@ class PeerManagerImpl final : public PeerManager int m_peers_downloading_from GUARDED_BY(cs_main) = 0; /** Storage for orphan information */ - TxOrphanage m_orphanage; + TxOrphanage m_orphanage GUARDED_BY(m_tx_download_mutex); void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); @@ -1630,7 +1642,8 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer) void PeerManagerImpl::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time) { - AssertLockHeld(::cs_main); // For m_txrequest + AssertLockHeld(::cs_main); // for State + AssertLockHeld(m_tx_download_mutex); // For m_txrequest NodeId nodeid = node.GetId(); if (!node.HasPermission(NetPermissionFlags::Relay) && m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) { // Too many queued announcements from this peer @@ -1666,8 +1679,11 @@ void PeerManagerImpl::InitializeNode(const CNode& node, ServiceFlags our_service { NodeId nodeid = node.GetId(); { - LOCK(cs_main); + LOCK(cs_main); // For m_node_states m_node_states.emplace_hint(m_node_states.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(node.IsInboundConn())); + } + { + LOCK(m_tx_download_mutex); assert(m_txrequest.Count(nodeid) == 0); } @@ -1735,8 +1751,11 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) } } } - m_orphanage.EraseForPeer(nodeid); - m_txrequest.DisconnectedPeer(nodeid); + { + LOCK(m_tx_download_mutex); + m_orphanage.EraseForPeer(nodeid); + m_txrequest.DisconnectedPeer(nodeid); + } if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid); m_num_preferred_download_peers -= state->fPreferredDownload; m_peers_downloading_from -= (!state->vBlocksInFlight.empty()); @@ -1753,6 +1772,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) assert(m_peers_downloading_from == 0); assert(m_outbound_peers_with_protect_from_disconnect == 0); assert(m_wtxid_relay_peers == 0); + LOCK(m_tx_download_mutex); assert(m_txrequest.Size() == 0); assert(m_orphanage.Size() == 0); } @@ -2084,6 +2104,7 @@ void PeerManagerImpl::BlockConnected( if (role == ChainstateRole::BACKGROUND) { return; } + LOCK(m_tx_download_mutex); m_orphanage.EraseForBlock(*pblock); { @@ -2096,7 +2117,6 @@ void PeerManagerImpl::BlockConnected( } } { - LOCK(cs_main); for (const auto& ptx : pblock->vtx) { m_txrequest.ForgetTxHash(ptx->GetHash()); m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); @@ -2254,6 +2274,9 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) { + AssertLockHeld(::cs_main); + AssertLockHeld(m_tx_download_mutex); + if (m_chainman.ActiveChain().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { // If the chain tip has changed previously rejected transactions // might be now valid, e.g. due to a nLockTime'd tx becoming valid, @@ -3154,7 +3177,7 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); LogDebug(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n", ptx->GetHash().ToString(), @@ -3219,7 +3242,7 @@ void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, c { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); // As this version of the transaction was acceptable, we can forget about any requests for it. // No-op if the tx is not in txrequest. @@ -3247,7 +3270,7 @@ void PeerManagerImpl::ProcessPackageResult(const PackageToValidate& package_to_v { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); const auto& package = package_to_validate.m_txns; const auto& senders = package_to_validate.m_senders; @@ -3303,7 +3326,7 @@ std::optional PeerManagerImpl::Find1P1CPacka { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); const auto& parent_wtxid{ptx->GetWitnessHash()}; @@ -3356,7 +3379,7 @@ std::optional PeerManagerImpl::Find1P1CPacka bool PeerManagerImpl::ProcessOrphanTx(Peer& peer) { AssertLockHeld(g_msgproc_mutex); - LOCK(cs_main); + LOCK2(::cs_main, m_tx_download_mutex); CTransactionRef porphanTx = nullptr; @@ -4173,7 +4196,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const bool reject_tx_invs{RejectIncomingTxs(pfrom)}; - LOCK(cs_main); + LOCK2(cs_main, m_tx_download_mutex); const auto current_time{GetTime()}; uint256* best_block{nullptr}; @@ -4506,7 +4529,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const uint256& hash = peer->m_wtxid_relay ? wtxid : txid; AddKnownTx(*peer, hash); - LOCK(cs_main); + LOCK2(cs_main, m_tx_download_mutex); m_txrequest.ReceivedResponse(pfrom.GetId(), txid); if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid); @@ -5263,7 +5286,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, std::vector vInv; vRecv >> vInv; if (vInv.size() <= MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - LOCK(::cs_main); + LOCK(m_tx_download_mutex); for (CInv &inv : vInv) { if (inv.IsGenTxMsg()) { // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as @@ -5388,6 +5411,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic& interrupt // by another peer that was already processed; in that case, // the extra work may not be noticed, possibly resulting in an // unnecessary 100ms delay) + LOCK(m_tx_download_mutex); if (m_orphanage.HaveTxToReconsider(peer->m_id)) fMoreWork = true; } catch (const std::exception& e) { LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size, e.what(), typeid(e).name()); @@ -6281,6 +6305,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // // Message: getdata (transactions) // + LOCK(m_tx_download_mutex); std::vector> expired; auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired); for (const auto& entry : expired) { From 36f170d87924e50d0ff9be2a1b0f2a8f13950a9b Mon Sep 17 00:00:00 2001 From: glozow Date: Fri, 29 Sep 2023 13:58:16 +0100 Subject: [PATCH 09/91] add ValidationInterface::ActiveTipChange This is a synchronous callback notifying clients of all tip changes. It allows clients to respond to a new block immediately after it is connected. The synchronicity is important for things like m_recent_rejects, in which a transaction's validity can change (rejected vs accepted) when this event is processed. For example, the transaction might have a timelock condition that has just been met. This is distinct from something like m_recent_confirmed_transactions, in which the validation outcome is the same (valid vs already-have), so it does not need to be reset immediately. --- src/validation.cpp | 14 +++++++++++++- src/validationinterface.cpp | 6 ++++++ src/validationinterface.h | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 988df3802a..52bff9bac2 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3488,6 +3488,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< { LOCK(cs_main); + { // Lock transaction pool for at least as long as it takes for connectTrace to be consumed LOCK(MempoolMutex()); const bool was_in_ibd = m_chainman.IsInitialBlockDownload(); @@ -3564,7 +3565,12 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< break; } } - } + } // release MempoolMutex + // Notify external listeners about the new tip, even if pindexFork == pindexNewTip. + if (m_chainman.m_options.signals && this == &m_chainman.ActiveChainstate()) { + m_chainman.m_options.signals->ActiveTipChange(pindexNewTip, m_chainman.IsInitialBlockDownload()); + } + } // release cs_main // When we reach this point, we switched to a new tip (stored in pindexNewTip). if (exited_ibd) { @@ -3783,6 +3789,12 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde // distinguish user-initiated invalidateblock changes from other // changes. (void)m_chainman.GetNotifications().blockTip(GetSynchronizationState(m_chainman.IsInitialBlockDownload(), m_chainman.m_blockman.m_blockfiles_indexed), *to_mark_failed->pprev); + + // Fire ActiveTipChange now for the current chain tip to make sure clients are notified. + // ActivateBestChain may call this as well, but not necessarily. + if (m_chainman.m_options.signals) { + m_chainman.m_options.signals->ActiveTipChange(m_chain.Tip(), m_chainman.IsInitialBlockDownload()); + } } return true; } diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 579444a065..f5baa16c99 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -183,6 +183,12 @@ void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlo fInitialDownload); } +void ValidationSignals::ActiveTipChange(const CBlockIndex *new_tip, bool is_ibd) +{ + LOG_EVENT("%s: new block hash=%s block height=%d", __func__, new_tip->GetBlockHash().ToString(), new_tip->nHeight); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ActiveTipChange(new_tip, is_ibd); }); +} + void ValidationSignals::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t mempool_sequence) { auto event = [tx, mempool_sequence, this] { diff --git a/src/validationinterface.h b/src/validationinterface.h index 6f49a73c93..3cc3566a60 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -61,6 +61,10 @@ class CValidationInterface { * Called on a background thread. Only called for the active chainstate. */ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {} + /** + * Notifies listeners any time the block chain tip changes, synchronously. + */ + virtual void ActiveTipChange(const CBlockIndex* new_tip, bool is_ibd) {}; /** * Notifies listeners of a transaction having been added to mempool. * @@ -214,6 +218,7 @@ class ValidationSignals { void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main); void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); + void ActiveTipChange(const CBlockIndex*, bool); void TransactionAddedToMempool(const NewMempoolTransactionInfo&, uint64_t mempool_sequence); void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence); void MempoolTransactionsRemovedForBlock(const std::vector&, unsigned int nBlockHeight); From 18a43552509603ddf83b752fd7b4b973ba1dcf82 Mon Sep 17 00:00:00 2001 From: glozow Date: Thu, 16 May 2024 12:27:40 +0100 Subject: [PATCH 10/91] update recent_rejects filters on ActiveTipChange Resetting m_recent_rejects once per block is more efficient than comparing hashRecentRejectsChainTip with the chain tip every time we call AlreadyHaveTx. We keep hashRecentRejectsChainTip for now to assert that updates happen correctly; it is removed in the next commit. --- src/net_processing.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 95ef67b160..62c4df91a5 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -489,6 +489,8 @@ class PeerManagerImpl final : public PeerManager CTxMemPool& pool, node::Warnings& warnings, Options opts); /** Overridden from CValidationInterface. */ + void ActiveTipChange(const CBlockIndex* new_tip, bool) override + EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); void BlockConnected(ChainstateRole role, const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) override EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); void BlockDisconnected(const std::shared_ptr &block, const CBlockIndex* pindex) override @@ -2074,6 +2076,22 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } +void PeerManagerImpl::ActiveTipChange(const CBlockIndex* new_tip, bool is_ibd) +{ + AssertLockNotHeld(m_mempool.cs); + AssertLockNotHeld(m_tx_download_mutex); + + if (!is_ibd) { + LOCK(m_tx_download_mutex); + // If the chain tip has changed, previously rejected transactions might now be valid, e.g. due + // to a timelock. Reset the rejection filters to give those transactions another chance if we + // see them again. + m_recent_rejects.reset(); + m_recent_rejects_reconsiderable.reset(); + hashRecentRejectsChainTip = new_tip->GetBlockHash(); + } +} + /** * Evict orphan txn pool entries based on a newly connected * block, remember the recently confirmed transactions, and delete tracked @@ -2277,7 +2295,11 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconside AssertLockHeld(::cs_main); AssertLockHeld(m_tx_download_mutex); - if (m_chainman.ActiveChain().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { + // Since recent_rejects is updated whenever the tip changes, and hashRecentRejectsChainTip is + // not set until the first time it is called outside of IBD, hashRecentRejectsChainTip should + // always be up to date with the current chain tip. + if (!Assume(hashRecentRejectsChainTip == uint256::ZERO || + hashRecentRejectsChainTip == m_chainman.ActiveChain().Tip()->GetBlockHash())) { // If the chain tip has changed previously rejected transactions // might be now valid, e.g. due to a nLockTime'd tx becoming valid, // or a double-spend. Reset the rejects filter and give those From 723ea0f9a5b5e3f3f58ea049a98299ff0ebde468 Mon Sep 17 00:00:00 2001 From: glozow Date: Fri, 29 Sep 2023 14:03:51 +0100 Subject: [PATCH 11/91] remove obsoleted hashRecentRejectsChainTip This also means AlreadyHaveTx no longer needs cs_main held. --- src/net_processing.cpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 62c4df91a5..e701265016 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -861,11 +861,9 @@ class PeerManagerImpl final : public PeerManager * - m_recent_rejects * - m_recent_rejects_reconsiderable (if include_reconsiderable = true) * - m_recent_confirmed_transactions - * Also responsible for resetting m_recent_rejects and m_recent_rejects_reconsiderable if the - * chain tip has changed. * */ bool AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex, m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, m_tx_download_mutex); /** * Filter for transactions that were recently rejected by the mempool. @@ -902,9 +900,6 @@ class PeerManagerImpl final : public PeerManager * Memory used: 1.3 MB */ CRollingBloomFilter m_recent_rejects GUARDED_BY(m_tx_download_mutex){120'000, 0.000'001}; - /** Block hash of chain tip the last time we reset m_recent_rejects and - * m_recent_rejects_reconsiderable. */ - uint256 hashRecentRejectsChainTip GUARDED_BY(m_tx_download_mutex); /** * Filter for: @@ -2088,7 +2083,6 @@ void PeerManagerImpl::ActiveTipChange(const CBlockIndex* new_tip, bool is_ibd) // see them again. m_recent_rejects.reset(); m_recent_rejects_reconsiderable.reset(); - hashRecentRejectsChainTip = new_tip->GetBlockHash(); } } @@ -2292,23 +2286,8 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) { - AssertLockHeld(::cs_main); AssertLockHeld(m_tx_download_mutex); - // Since recent_rejects is updated whenever the tip changes, and hashRecentRejectsChainTip is - // not set until the first time it is called outside of IBD, hashRecentRejectsChainTip should - // always be up to date with the current chain tip. - if (!Assume(hashRecentRejectsChainTip == uint256::ZERO || - hashRecentRejectsChainTip == m_chainman.ActiveChain().Tip()->GetBlockHash())) { - // If the chain tip has changed previously rejected transactions - // might be now valid, e.g. due to a nLockTime'd tx becoming valid, - // or a double-spend. Reset the rejects filter and give those - // txs a second chance. - hashRecentRejectsChainTip = m_chainman.ActiveChain().Tip()->GetBlockHash(); - m_recent_rejects.reset(); - m_recent_rejects_reconsiderable.reset(); - } - const uint256& hash = gtxid.GetHash(); if (gtxid.IsWtxid()) { From 61745c7451ec64b26c74f672c688e82efb3b96aa Mon Sep 17 00:00:00 2001 From: glozow Date: Tue, 16 Apr 2024 14:58:42 +0100 Subject: [PATCH 12/91] lock m_recent_confirmed_transactions using m_tx_download_mutex --- src/net_processing.cpp | 43 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index e701265016..c241994763 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -490,11 +490,11 @@ class PeerManagerImpl final : public PeerManager /** Overridden from CValidationInterface. */ void ActiveTipChange(const CBlockIndex* new_tip, bool) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void BlockConnected(ChainstateRole role, const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void BlockDisconnected(const std::shared_ptr &block, const CBlockIndex* pindex) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void BlockChecked(const CBlock& block, const BlockValidationState& state) override @@ -507,9 +507,9 @@ class PeerManagerImpl final : public PeerManager void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, !m_tx_download_mutex); bool HasAllDesirableServiceFlags(ServiceFlags services) const override; bool ProcessMessages(CNode* pfrom, std::atomic& interrupt) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); bool SendMessages(CNode* pto) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex); /** Implement PeerManager */ void StartScheduledTasks(CScheduler& scheduler) override; @@ -528,7 +528,7 @@ class PeerManagerImpl final : public PeerManager void UnitTestMisbehaving(NodeId peer_id) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), ""); }; void ProcessMessage(CNode& pfrom, const std::string& msg_type, DataStream& vRecv, const std::chrono::microseconds time_received, const std::atomic& interruptMsgProc) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override; @@ -863,7 +863,7 @@ class PeerManagerImpl final : public PeerManager * - m_recent_confirmed_transactions * */ bool AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, m_tx_download_mutex); + EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex); /** * Filter for transactions that were recently rejected by the mempool. @@ -938,8 +938,7 @@ class PeerManagerImpl final : public PeerManager * transaction per day that would be inadvertently ignored (which is the * same probability that we have in the reject filter). */ - Mutex m_recent_confirmed_transactions_mutex; - CRollingBloomFilter m_recent_confirmed_transactions GUARDED_BY(m_recent_confirmed_transactions_mutex){48'000, 0.000'001}; + CRollingBloomFilter m_recent_confirmed_transactions GUARDED_BY(m_tx_download_mutex){48'000, 0.000'001}; /** * For sending `inv`s to inbound peers, we use a single (exponentially @@ -2119,20 +2118,15 @@ void PeerManagerImpl::BlockConnected( LOCK(m_tx_download_mutex); m_orphanage.EraseForBlock(*pblock); - { - LOCK(m_recent_confirmed_transactions_mutex); - for (const auto& ptx : pblock->vtx) { - m_recent_confirmed_transactions.insert(ptx->GetHash().ToUint256()); - if (ptx->HasWitness()) { - m_recent_confirmed_transactions.insert(ptx->GetWitnessHash().ToUint256()); - } + for (const auto& ptx : pblock->vtx) { + m_recent_confirmed_transactions.insert(ptx->GetHash().ToUint256()); + if (ptx->HasWitness()) { + m_recent_confirmed_transactions.insert(ptx->GetWitnessHash().ToUint256()); } } - { - for (const auto& ptx : pblock->vtx) { - m_txrequest.ForgetTxHash(ptx->GetHash()); - m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); - } + for (const auto& ptx : pblock->vtx) { + m_txrequest.ForgetTxHash(ptx->GetHash()); + m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); } } @@ -2146,7 +2140,7 @@ void PeerManagerImpl::BlockDisconnected(const std::shared_ptr &blo // block's worth of transactions in it, but that should be fine, since // presumably the most common case of relaying a confirmed transaction // should be just after a new block containing it is found. - LOCK(m_recent_confirmed_transactions_mutex); + LOCK(m_tx_download_mutex); m_recent_confirmed_transactions.reset(); } @@ -2310,10 +2304,7 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconside if (include_reconsiderable && m_recent_rejects_reconsiderable.contains(hash)) return true; - { - LOCK(m_recent_confirmed_transactions_mutex); - if (m_recent_confirmed_transactions.contains(hash)) return true; - } + if (m_recent_confirmed_transactions.contains(hash)) return true; return m_recent_rejects.contains(hash) || m_mempool.exists(gtxid); } From 6ff84069a5dd92303ed2ec28f0ec7c96bbda3938 Mon Sep 17 00:00:00 2001 From: glozow Date: Thu, 16 May 2024 10:32:51 +0100 Subject: [PATCH 13/91] remove obsoleted TxOrphanage::m_mutex The TxOrphanage is now guarded externally by m_tx_download_mutex. --- src/test/orphanage_tests.cpp | 6 ++---- src/txorphanage.cpp | 22 -------------------- src/txorphanage.h | 40 ++++++++++++++++-------------------- 3 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp index 3459aa9f0e..082d090d7c 100644 --- a/src/test/orphanage_tests.cpp +++ b/src/test/orphanage_tests.cpp @@ -21,15 +21,13 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup) class TxOrphanageTest : public TxOrphanage { public: - inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + inline size_t CountOrphans() const { - LOCK(m_mutex); return m_orphans.size(); } - CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + CTransactionRef RandomOrphan() { - LOCK(m_mutex); std::map::iterator it; it = m_orphans.lower_bound(Wtxid::FromUint256(InsecureRand256())); if (it == m_orphans.end()) diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp index 3eaf53939d..29f1c19c17 100644 --- a/src/txorphanage.cpp +++ b/src/txorphanage.cpp @@ -20,8 +20,6 @@ static constexpr auto ORPHAN_TX_EXPIRE_INTERVAL{5min}; bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) { - LOCK(m_mutex); - const Txid& hash = tx->GetHash(); const Wtxid& wtxid = tx->GetWitnessHash(); if (m_orphans.count(wtxid)) @@ -55,13 +53,11 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) int TxOrphanage::EraseTx(const Wtxid& wtxid) { - LOCK(m_mutex); return EraseTxNoLock(wtxid); } int TxOrphanage::EraseTxNoLock(const Wtxid& wtxid) { - AssertLockHeld(m_mutex); std::map::iterator it = m_orphans.find(wtxid); if (it == m_orphans.end()) return 0; @@ -97,8 +93,6 @@ int TxOrphanage::EraseTxNoLock(const Wtxid& wtxid) void TxOrphanage::EraseForPeer(NodeId peer) { - LOCK(m_mutex); - m_peer_work_set.erase(peer); int nErased = 0; @@ -116,8 +110,6 @@ void TxOrphanage::EraseForPeer(NodeId peer) void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) { - LOCK(m_mutex); - unsigned int nEvicted = 0; auto nNow{Now()}; if (m_next_sweep <= nNow) { @@ -150,9 +142,6 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx) { - LOCK(m_mutex); - - for (unsigned int i = 0; i < tx.vout.size(); i++) { const auto it_by_prev = m_outpoint_to_orphan_it.find(COutPoint(tx.GetHash(), i)); if (it_by_prev != m_outpoint_to_orphan_it.end()) { @@ -171,14 +160,11 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx) bool TxOrphanage::HaveTx(const Wtxid& wtxid) const { - LOCK(m_mutex); return m_orphans.count(wtxid); } CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer) { - LOCK(m_mutex); - auto work_set_it = m_peer_work_set.find(peer); if (work_set_it != m_peer_work_set.end()) { auto& work_set = work_set_it->second; @@ -197,8 +183,6 @@ CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer) bool TxOrphanage::HaveTxToReconsider(NodeId peer) { - LOCK(m_mutex); - auto work_set_it = m_peer_work_set.find(peer); if (work_set_it != m_peer_work_set.end()) { auto& work_set = work_set_it->second; @@ -209,8 +193,6 @@ bool TxOrphanage::HaveTxToReconsider(NodeId peer) void TxOrphanage::EraseForBlock(const CBlock& block) { - LOCK(m_mutex); - std::vector vOrphanErase; for (const CTransactionRef& ptx : block.vtx) { @@ -239,8 +221,6 @@ void TxOrphanage::EraseForBlock(const CBlock& block) std::vector TxOrphanage::GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const { - LOCK(m_mutex); - // First construct a vector of iterators to ensure we do not return duplicates of the same tx // and so we can sort by nTimeExpire. std::vector iters; @@ -281,8 +261,6 @@ std::vector TxOrphanage::GetChildrenFromSamePeer(const CTransac std::vector> TxOrphanage::GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const { - LOCK(m_mutex); - // First construct vector of iterators to ensure we do not return duplicates of the same tx. std::vector iters; diff --git a/src/txorphanage.h b/src/txorphanage.h index 3083c8467f..9917266749 100644 --- a/src/txorphanage.h +++ b/src/txorphanage.h @@ -22,55 +22,51 @@ class TxOrphanage { public: /** Add a new orphan transaction */ - bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + bool AddTx(const CTransactionRef& tx, NodeId peer); /** Check if we already have an orphan transaction (by wtxid only) */ - bool HaveTx(const Wtxid& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + bool HaveTx(const Wtxid& wtxid) const; /** Extract a transaction from a peer's work set * Returns nullptr if there are no transactions to work on. * Otherwise returns the transaction reference, and removes * it from the work set. */ - CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + CTransactionRef GetTxToReconsider(NodeId peer); /** Erase an orphan by wtxid */ - int EraseTx(const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + int EraseTx(const Wtxid& wtxid); /** Erase all orphans announced by a peer (eg, after that peer disconnects) */ - void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void EraseForPeer(NodeId peer); /** Erase all orphans included in or invalidated by a new block */ - void EraseForBlock(const CBlock& block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void EraseForBlock(const CBlock& block); /** Limit the orphanage to the given maximum */ - void LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void LimitOrphans(unsigned int max_orphans, FastRandomContext& rng); /** Add any orphans that list a particular tx as a parent into the from peer's work set */ - void AddChildrenToWorkSet(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);; + void AddChildrenToWorkSet(const CTransaction& tx); /** Does this peer have any work to do? */ - bool HaveTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);; + bool HaveTxToReconsider(NodeId peer); /** Get all children that spend from this tx and were received from nodeid. Sorted from most * recent to least recent. */ - std::vector GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + std::vector GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const; /** Get all children that spend from this tx but were not received from nodeid. Also return * which peer provided each tx. */ - std::vector> GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + std::vector> GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const; /** Return how many entries exist in the orphange */ - size_t Size() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + size_t Size() { - LOCK(m_mutex); return m_orphans.size(); } protected: - /** Guards orphan transactions */ - mutable Mutex m_mutex; - struct OrphanTx { CTransactionRef tx; NodeId fromPeer; @@ -80,10 +76,10 @@ class TxOrphanage { /** Map from wtxid to orphan transaction record. Limited by * -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */ - std::map m_orphans GUARDED_BY(m_mutex); + std::map m_orphans; /** Which peer provided the orphans that need to be reconsidered */ - std::map> m_peer_work_set GUARDED_BY(m_mutex); + std::map> m_peer_work_set; using OrphanMap = decltype(m_orphans); @@ -98,16 +94,16 @@ class TxOrphanage { /** Index from the parents' COutPoint into the m_orphans. Used * to remove orphan transactions from the m_orphans */ - std::map> m_outpoint_to_orphan_it GUARDED_BY(m_mutex); + std::map> m_outpoint_to_orphan_it; /** Orphan transactions in vector for quick random eviction */ - std::vector m_orphan_list GUARDED_BY(m_mutex); + std::vector m_orphan_list; /** Erase an orphan by wtxid */ - int EraseTxNoLock(const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex); + int EraseTxNoLock(const Wtxid& wtxid); /** Timestamp for the next scheduled sweep of expired orphans */ - NodeSeconds m_next_sweep GUARDED_BY(m_mutex){0s}; + NodeSeconds m_next_sweep{0s}; }; #endif // BITCOIN_TXORPHANAGE_H From c85accecafc20f6a6ae94bdf6cdd3ba9747218fd Mon Sep 17 00:00:00 2001 From: glozow Date: Thu, 23 May 2024 13:25:41 +0100 Subject: [PATCH 14/91] [refactor] delete EraseTxNoLock, just use EraseTx --- src/txorphanage.cpp | 13 ++++--------- src/txorphanage.h | 3 --- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp index 29f1c19c17..df9b96e64d 100644 --- a/src/txorphanage.cpp +++ b/src/txorphanage.cpp @@ -52,11 +52,6 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) } int TxOrphanage::EraseTx(const Wtxid& wtxid) -{ - return EraseTxNoLock(wtxid); -} - -int TxOrphanage::EraseTxNoLock(const Wtxid& wtxid) { std::map::iterator it = m_orphans.find(wtxid); if (it == m_orphans.end()) @@ -102,7 +97,7 @@ void TxOrphanage::EraseForPeer(NodeId peer) // increment to avoid iterator becoming invalid after erasure const auto& [wtxid, orphan] = *iter++; if (orphan.fromPeer == peer) { - nErased += EraseTxNoLock(wtxid); + nErased += EraseTx(wtxid); } } if (nErased > 0) LogPrint(BCLog::TXPACKAGES, "Erased %d orphan transaction(s) from peer=%d\n", nErased, peer); @@ -121,7 +116,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) { std::map::iterator maybeErase = iter++; if (maybeErase->second.nTimeExpire <= nNow) { - nErased += EraseTxNoLock(maybeErase->second.tx->GetWitnessHash()); + nErased += EraseTx(maybeErase->second.tx->GetWitnessHash()); } else { nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); } @@ -134,7 +129,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) { // Evict a random orphan: size_t randompos = rng.randrange(m_orphan_list.size()); - EraseTxNoLock(m_orphan_list[randompos]->second.tx->GetWitnessHash()); + EraseTx(m_orphan_list[randompos]->second.tx->GetWitnessHash()); ++nEvicted; } if (nEvicted > 0) LogPrint(BCLog::TXPACKAGES, "orphanage overflow, removed %u tx\n", nEvicted); @@ -213,7 +208,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block) if (vOrphanErase.size()) { int nErased = 0; for (const auto& orphanHash : vOrphanErase) { - nErased += EraseTxNoLock(orphanHash); + nErased += EraseTx(orphanHash); } LogPrint(BCLog::TXPACKAGES, "Erased %d orphan transaction(s) included or conflicted by block\n", nErased); } diff --git a/src/txorphanage.h b/src/txorphanage.h index 9917266749..207b79e009 100644 --- a/src/txorphanage.h +++ b/src/txorphanage.h @@ -99,9 +99,6 @@ class TxOrphanage { /** Orphan transactions in vector for quick random eviction */ std::vector m_orphan_list; - /** Erase an orphan by wtxid */ - int EraseTxNoLock(const Wtxid& wtxid); - /** Timestamp for the next scheduled sweep of expired orphans */ NodeSeconds m_next_sweep{0s}; }; From a0473442d1c22043f5a288bd9255c006fd85d947 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 16 Jul 2024 22:05:14 +0100 Subject: [PATCH 15/91] scripted-diff: Add `__file__` argument to `BitcoinTestFramework.init()` -BEGIN VERIFY SCRIPT- sed -i -e 's/\s*().main\s*()/(__file__).main()/' $(git ls-files test/functional/*.py) sed -i -e 's/def __init__(self)/def __init__(self, test_file)/' test/functional/test_framework/test_framework.py -END VERIFY SCRIPT- --- test/functional/create_cache.py | 2 +- test/functional/example_test.py | 2 +- test/functional/feature_abortnode.py | 2 +- test/functional/feature_addrman.py | 2 +- test/functional/feature_anchors.py | 2 +- test/functional/feature_asmap.py | 2 +- test/functional/feature_assumeutxo.py | 2 +- test/functional/feature_assumevalid.py | 2 +- test/functional/feature_bind_extra.py | 2 +- test/functional/feature_bind_port_discover.py | 2 +- test/functional/feature_bind_port_externalip.py | 2 +- test/functional/feature_bip68_sequence.py | 2 +- test/functional/feature_block.py | 2 +- test/functional/feature_blocksdir.py | 2 +- test/functional/feature_cltv.py | 2 +- test/functional/feature_coinstatsindex.py | 2 +- test/functional/feature_config_args.py | 2 +- test/functional/feature_csv_activation.py | 2 +- test/functional/feature_dbcrash.py | 2 +- test/functional/feature_dersig.py | 2 +- test/functional/feature_dirsymlinks.py | 2 +- test/functional/feature_discover.py | 2 +- test/functional/feature_fastprune.py | 2 +- test/functional/feature_fee_estimation.py | 2 +- test/functional/feature_filelock.py | 2 +- test/functional/feature_framework_miniwallet.py | 2 +- test/functional/feature_help.py | 2 +- test/functional/feature_includeconf.py | 2 +- test/functional/feature_index_prune.py | 2 +- test/functional/feature_init.py | 2 +- test/functional/feature_loadblock.py | 2 +- test/functional/feature_logging.py | 2 +- test/functional/feature_maxtipage.py | 2 +- test/functional/feature_maxuploadtarget.py | 2 +- test/functional/feature_minchainwork.py | 2 +- test/functional/feature_notifications.py | 2 +- test/functional/feature_nulldummy.py | 2 +- test/functional/feature_posix_fs_permissions.py | 2 +- test/functional/feature_presegwit_node_upgrade.py | 2 +- test/functional/feature_proxy.py | 2 +- test/functional/feature_pruning.py | 2 +- test/functional/feature_rbf.py | 2 +- test/functional/feature_reindex.py | 2 +- test/functional/feature_reindex_readonly.py | 2 +- test/functional/feature_remove_pruned_files_on_startup.py | 2 +- test/functional/feature_segwit.py | 2 +- test/functional/feature_settings.py | 2 +- test/functional/feature_shutdown.py | 2 +- test/functional/feature_signet.py | 2 +- test/functional/feature_startupnotify.py | 2 +- test/functional/feature_taproot.py | 2 +- test/functional/feature_uacomment.py | 2 +- test/functional/feature_unsupported_utxo_db.py | 2 +- test/functional/feature_utxo_set_hash.py | 2 +- test/functional/feature_versionbits_warning.py | 2 +- test/functional/interface_bitcoin_cli.py | 2 +- test/functional/interface_http.py | 2 +- test/functional/interface_rest.py | 2 +- test/functional/interface_rpc.py | 2 +- test/functional/interface_usdt_coinselection.py | 2 +- test/functional/interface_usdt_mempool.py | 2 +- test/functional/interface_usdt_net.py | 2 +- test/functional/interface_usdt_utxocache.py | 2 +- test/functional/interface_usdt_validation.py | 2 +- test/functional/interface_zmq.py | 2 +- test/functional/mempool_accept.py | 2 +- test/functional/mempool_accept_wtxid.py | 2 +- test/functional/mempool_compatibility.py | 2 +- test/functional/mempool_datacarrier.py | 2 +- test/functional/mempool_dust.py | 2 +- test/functional/mempool_expiry.py | 2 +- test/functional/mempool_limit.py | 2 +- test/functional/mempool_package_limits.py | 2 +- test/functional/mempool_package_onemore.py | 2 +- test/functional/mempool_package_rbf.py | 2 +- test/functional/mempool_packages.py | 2 +- test/functional/mempool_persist.py | 2 +- test/functional/mempool_reorg.py | 2 +- test/functional/mempool_resurrect.py | 2 +- test/functional/mempool_sigoplimit.py | 2 +- test/functional/mempool_spend_coinbase.py | 2 +- test/functional/mempool_truc.py | 2 +- test/functional/mempool_unbroadcast.py | 2 +- test/functional/mempool_updatefromblock.py | 2 +- test/functional/mining_basic.py | 2 +- test/functional/mining_getblocktemplate_longpoll.py | 2 +- test/functional/mining_prioritisetransaction.py | 2 +- test/functional/p2p_1p1c_network.py | 2 +- test/functional/p2p_add_connections.py | 2 +- test/functional/p2p_addr_relay.py | 2 +- test/functional/p2p_addrfetch.py | 2 +- test/functional/p2p_addrv2_relay.py | 2 +- test/functional/p2p_block_sync.py | 2 +- test/functional/p2p_blockfilters.py | 2 +- test/functional/p2p_blocksonly.py | 2 +- test/functional/p2p_compactblocks.py | 2 +- test/functional/p2p_compactblocks_blocksonly.py | 2 +- test/functional/p2p_compactblocks_hb.py | 2 +- test/functional/p2p_disconnect_ban.py | 2 +- test/functional/p2p_dns_seeds.py | 2 +- test/functional/p2p_dos_header_tree.py | 2 +- test/functional/p2p_eviction.py | 2 +- test/functional/p2p_feefilter.py | 2 +- test/functional/p2p_filter.py | 2 +- test/functional/p2p_fingerprint.py | 2 +- test/functional/p2p_getaddr_caching.py | 2 +- test/functional/p2p_getdata.py | 2 +- test/functional/p2p_handshake.py | 2 +- test/functional/p2p_headers_sync_with_minchainwork.py | 2 +- test/functional/p2p_i2p_ports.py | 2 +- test/functional/p2p_i2p_sessions.py | 2 +- test/functional/p2p_ibd_stalling.py | 2 +- test/functional/p2p_ibd_txrelay.py | 2 +- test/functional/p2p_initial_headers_sync.py | 2 +- test/functional/p2p_invalid_block.py | 2 +- test/functional/p2p_invalid_locator.py | 2 +- test/functional/p2p_invalid_messages.py | 2 +- test/functional/p2p_invalid_tx.py | 2 +- test/functional/p2p_leak.py | 2 +- test/functional/p2p_leak_tx.py | 2 +- test/functional/p2p_message_capture.py | 2 +- test/functional/p2p_mutated_blocks.py | 2 +- test/functional/p2p_net_deadlock.py | 2 +- test/functional/p2p_nobloomfilter_messages.py | 2 +- test/functional/p2p_node_network_limited.py | 2 +- test/functional/p2p_opportunistic_1p1c.py | 2 +- test/functional/p2p_orphan_handling.py | 2 +- test/functional/p2p_outbound_eviction.py | 2 +- test/functional/p2p_permissions.py | 2 +- test/functional/p2p_ping.py | 2 +- test/functional/p2p_segwit.py | 2 +- test/functional/p2p_sendheaders.py | 2 +- test/functional/p2p_sendtxrcncl.py | 2 +- test/functional/p2p_timeouts.py | 2 +- test/functional/p2p_tx_download.py | 2 +- test/functional/p2p_tx_privacy.py | 2 +- test/functional/p2p_unrequested_blocks.py | 2 +- test/functional/p2p_v2_encrypted.py | 2 +- test/functional/p2p_v2_misbehaving.py | 2 +- test/functional/p2p_v2_transport.py | 2 +- test/functional/rpc_bind.py | 2 +- test/functional/rpc_blockchain.py | 2 +- test/functional/rpc_createmultisig.py | 2 +- test/functional/rpc_decodescript.py | 2 +- test/functional/rpc_deprecated.py | 2 +- test/functional/rpc_deriveaddresses.py | 2 +- test/functional/rpc_dumptxoutset.py | 2 +- test/functional/rpc_estimatefee.py | 2 +- test/functional/rpc_generate.py | 2 +- test/functional/rpc_getblockfilter.py | 2 +- test/functional/rpc_getblockfrompeer.py | 2 +- test/functional/rpc_getblockstats.py | 2 +- test/functional/rpc_getchaintips.py | 2 +- test/functional/rpc_getdescriptorinfo.py | 2 +- test/functional/rpc_help.py | 2 +- test/functional/rpc_invalid_address_message.py | 2 +- test/functional/rpc_invalidateblock.py | 2 +- test/functional/rpc_mempool_info.py | 2 +- test/functional/rpc_misc.py | 2 +- test/functional/rpc_named_arguments.py | 2 +- test/functional/rpc_net.py | 2 +- test/functional/rpc_packages.py | 2 +- test/functional/rpc_preciousblock.py | 2 +- test/functional/rpc_psbt.py | 2 +- test/functional/rpc_rawtransaction.py | 2 +- test/functional/rpc_scanblocks.py | 2 +- test/functional/rpc_scantxoutset.py | 2 +- test/functional/rpc_setban.py | 2 +- test/functional/rpc_signer.py | 2 +- test/functional/rpc_signmessagewithprivkey.py | 2 +- test/functional/rpc_signrawtransactionwithkey.py | 2 +- test/functional/rpc_txoutproof.py | 2 +- test/functional/rpc_uptime.py | 2 +- test/functional/rpc_users.py | 2 +- test/functional/rpc_validateaddress.py | 2 +- test/functional/rpc_whitelist.py | 2 +- test/functional/test_framework/test_framework.py | 2 +- test/functional/tool_signet_miner.py | 2 +- test/functional/tool_wallet.py | 2 +- test/functional/wallet_abandonconflict.py | 2 +- test/functional/wallet_address_types.py | 2 +- test/functional/wallet_assumeutxo.py | 2 +- test/functional/wallet_avoid_mixing_output_types.py | 2 +- test/functional/wallet_avoidreuse.py | 2 +- test/functional/wallet_backup.py | 2 +- test/functional/wallet_backwards_compatibility.py | 2 +- test/functional/wallet_balance.py | 2 +- test/functional/wallet_basic.py | 2 +- test/functional/wallet_blank.py | 2 +- test/functional/wallet_bumpfee.py | 2 +- test/functional/wallet_change_address.py | 2 +- test/functional/wallet_coinbase_category.py | 2 +- test/functional/wallet_conflicts.py | 2 +- test/functional/wallet_create_tx.py | 2 +- test/functional/wallet_createwallet.py | 2 +- test/functional/wallet_createwalletdescriptor.py | 2 +- test/functional/wallet_crosschain.py | 2 +- test/functional/wallet_descriptor.py | 2 +- test/functional/wallet_disable.py | 2 +- test/functional/wallet_dump.py | 2 +- test/functional/wallet_encryption.py | 2 +- test/functional/wallet_fallbackfee.py | 2 +- test/functional/wallet_fast_rescan.py | 2 +- test/functional/wallet_fundrawtransaction.py | 2 +- test/functional/wallet_gethdkeys.py | 2 +- test/functional/wallet_groups.py | 2 +- test/functional/wallet_hd.py | 2 +- test/functional/wallet_implicitsegwit.py | 2 +- test/functional/wallet_import_rescan.py | 2 +- test/functional/wallet_import_with_label.py | 2 +- test/functional/wallet_importdescriptors.py | 2 +- test/functional/wallet_importmulti.py | 2 +- test/functional/wallet_importprunedfunds.py | 2 +- test/functional/wallet_inactive_hdchains.py | 2 +- test/functional/wallet_keypool.py | 2 +- test/functional/wallet_keypool_topup.py | 2 +- test/functional/wallet_labels.py | 2 +- test/functional/wallet_listdescriptors.py | 2 +- test/functional/wallet_listreceivedby.py | 2 +- test/functional/wallet_listsinceblock.py | 2 +- test/functional/wallet_listtransactions.py | 2 +- test/functional/wallet_migration.py | 2 +- test/functional/wallet_miniscript.py | 2 +- test/functional/wallet_multisig_descriptor_psbt.py | 2 +- test/functional/wallet_multiwallet.py | 2 +- test/functional/wallet_orphanedreward.py | 2 +- test/functional/wallet_pruning.py | 2 +- test/functional/wallet_reindex.py | 2 +- test/functional/wallet_reorgsrestore.py | 2 +- test/functional/wallet_rescan_unconfirmed.py | 2 +- test/functional/wallet_resendwallettransactions.py | 2 +- test/functional/wallet_send.py | 2 +- test/functional/wallet_sendall.py | 2 +- test/functional/wallet_sendmany.py | 2 +- test/functional/wallet_signer.py | 2 +- test/functional/wallet_signmessagewithaddress.py | 2 +- test/functional/wallet_signrawtransactionwithwallet.py | 2 +- test/functional/wallet_simulaterawtx.py | 2 +- test/functional/wallet_spend_unconfirmed.py | 2 +- test/functional/wallet_startup.py | 2 +- test/functional/wallet_taproot.py | 2 +- test/functional/wallet_timelock.py | 2 +- test/functional/wallet_transactiontime_rescan.py | 2 +- test/functional/wallet_txn_clone.py | 2 +- test/functional/wallet_txn_doublespend.py | 2 +- test/functional/wallet_upgradewallet.py | 2 +- test/functional/wallet_watchonly.py | 2 +- 247 files changed, 247 insertions(+), 247 deletions(-) diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 1108a8e354..0702ea7666 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -24,4 +24,4 @@ def run_test(self): pass if __name__ == '__main__': - CreateCache().main() + CreateCache(__file__).main() diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 7f7aa065ad..39cea2962f 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -225,4 +225,4 @@ def run_test(self): if __name__ == '__main__': - ExampleTest().main() + ExampleTest(__file__).main() diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py index 01ba2834c4..a5c8aa163a 100755 --- a/test/functional/feature_abortnode.py +++ b/test/functional/feature_abortnode.py @@ -42,4 +42,4 @@ def run_test(self): if __name__ == '__main__': - AbortNodeTest().main() + AbortNodeTest(__file__).main() diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py index 2efad70900..c4e60fba12 100755 --- a/test/functional/feature_addrman.py +++ b/test/functional/feature_addrman.py @@ -160,4 +160,4 @@ def run_test(self): if __name__ == "__main__": - AddrmanTest().main() + AddrmanTest(__file__).main() diff --git a/test/functional/feature_anchors.py b/test/functional/feature_anchors.py index 5d68f50f58..5ca46c1366 100755 --- a/test/functional/feature_anchors.py +++ b/test/functional/feature_anchors.py @@ -141,4 +141,4 @@ def run_test(self): if __name__ == "__main__": - AnchorsTest().main() + AnchorsTest(__file__).main() diff --git a/test/functional/feature_asmap.py b/test/functional/feature_asmap.py index e469deef49..cbff028bcc 100755 --- a/test/functional/feature_asmap.py +++ b/test/functional/feature_asmap.py @@ -146,4 +146,4 @@ def run_test(self): if __name__ == '__main__': - AsmapTest().main() + AsmapTest(__file__).main() diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index 688e2866b2..f4d7c47d13 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -555,4 +555,4 @@ class Block: chain_tx: int if __name__ == '__main__': - AssumeutxoTest().main() + AssumeutxoTest(__file__).main() diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 982fa79915..03a9f666b2 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -172,4 +172,4 @@ def run_test(self): if __name__ == '__main__': - AssumeValidTest().main() + AssumeValidTest(__file__).main() diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py index ed2328b76f..6b53de188f 100755 --- a/test/functional/feature_bind_extra.py +++ b/test/functional/feature_bind_extra.py @@ -88,4 +88,4 @@ def run_test(self): assert_equal(binds, set(expected_services)) if __name__ == '__main__': - BindExtraTest().main() + BindExtraTest(__file__).main() diff --git a/test/functional/feature_bind_port_discover.py b/test/functional/feature_bind_port_discover.py index 6e07f2f16c..568c88bcbe 100755 --- a/test/functional/feature_bind_port_discover.py +++ b/test/functional/feature_bind_port_discover.py @@ -75,4 +75,4 @@ def run_test(self): assert found_addr1 if __name__ == '__main__': - BindPortDiscoverTest().main() + BindPortDiscoverTest(__file__).main() diff --git a/test/functional/feature_bind_port_externalip.py b/test/functional/feature_bind_port_externalip.py index 6a74ce5738..8e2ac02470 100755 --- a/test/functional/feature_bind_port_externalip.py +++ b/test/functional/feature_bind_port_externalip.py @@ -72,4 +72,4 @@ def run_test(self): assert found if __name__ == '__main__': - BindPortExternalIPTest().main() + BindPortExternalIPTest(__file__).main() diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index 14b92d6733..2d61987e94 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -412,4 +412,4 @@ def test_version2_relay(self): if __name__ == '__main__': - BIP68Test().main() + BIP68Test(__file__).main() diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 932f37a083..172af27848 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -1434,4 +1434,4 @@ def send_blocks(self, blocks, success=True, reject_reason=None, force_send=False if __name__ == '__main__': - FullBlockTest().main() + FullBlockTest(__file__).main() diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py index 1a60c13c2c..4a43632855 100755 --- a/test/functional/feature_blocksdir.py +++ b/test/functional/feature_blocksdir.py @@ -35,4 +35,4 @@ def run_test(self): if __name__ == '__main__': - BlocksdirTest().main() + BlocksdirTest(__file__).main() diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index fb3f662271..dc01f8fa8f 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -195,4 +195,4 @@ def run_test(self): if __name__ == '__main__': - BIP65Test().main() + BIP65Test(__file__).main() diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py index 691163d053..b4392e6002 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -324,4 +324,4 @@ def _test_init_index_after_reorg(self): if __name__ == '__main__': - CoinStatsIndexTest().main() + CoinStatsIndexTest(__file__).main() diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 9e13a3deef..dc812d224f 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -431,4 +431,4 @@ def run_test(self): if __name__ == '__main__': - ConfArgsTest().main() + ConfArgsTest(__file__).main() diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 2db9682931..df02bcc6ad 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -482,4 +482,4 @@ def run_test(self): if __name__ == '__main__': - BIP68_112_113Test().main() + BIP68_112_113Test(__file__).main() diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py index afd0246209..f1aa3961e3 100755 --- a/test/functional/feature_dbcrash.py +++ b/test/functional/feature_dbcrash.py @@ -286,4 +286,4 @@ def run_test(self): if __name__ == "__main__": - ChainstateWriteCrashTest().main() + ChainstateWriteCrashTest(__file__).main() diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 035e7151ca..48b0b745c6 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -148,4 +148,4 @@ def run_test(self): if __name__ == '__main__': - BIP66Test().main() + BIP66Test(__file__).main() diff --git a/test/functional/feature_dirsymlinks.py b/test/functional/feature_dirsymlinks.py index 96f4aed08a..9fed99cbe5 100755 --- a/test/functional/feature_dirsymlinks.py +++ b/test/functional/feature_dirsymlinks.py @@ -38,4 +38,4 @@ def run_test(self): if __name__ == "__main__": - SymlinkTest().main() + SymlinkTest(__file__).main() diff --git a/test/functional/feature_discover.py b/test/functional/feature_discover.py index 7f4b81114e..9eaaea3652 100755 --- a/test/functional/feature_discover.py +++ b/test/functional/feature_discover.py @@ -72,4 +72,4 @@ def run_test(self): if __name__ == '__main__': - DiscoverTest().main() + DiscoverTest(__file__).main() diff --git a/test/functional/feature_fastprune.py b/test/functional/feature_fastprune.py index c913c4f93a..ca6877b901 100755 --- a/test/functional/feature_fastprune.py +++ b/test/functional/feature_fastprune.py @@ -26,4 +26,4 @@ def run_test(self): if __name__ == '__main__': - FeatureFastpruneTest().main() + FeatureFastpruneTest(__file__).main() diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index ffc87f8b8b..34fb3c5573 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -439,4 +439,4 @@ def run_test(self): if __name__ == "__main__": - EstimateFeeTest().main() + EstimateFeeTest(__file__).main() diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py index 567207915e..e71871114d 100755 --- a/test/functional/feature_filelock.py +++ b/test/functional/feature_filelock.py @@ -54,4 +54,4 @@ def check_wallet_filelock(descriptors): check_wallet_filelock(True) if __name__ == '__main__': - FilelockTest().main() + FilelockTest(__file__).main() diff --git a/test/functional/feature_framework_miniwallet.py b/test/functional/feature_framework_miniwallet.py index f108289018..1f381df236 100755 --- a/test/functional/feature_framework_miniwallet.py +++ b/test/functional/feature_framework_miniwallet.py @@ -46,4 +46,4 @@ def run_test(self): if __name__ == '__main__': - FeatureFrameworkMiniWalletTest().main() + FeatureFrameworkMiniWalletTest(__file__).main() diff --git a/test/functional/feature_help.py b/test/functional/feature_help.py index 4b66030b47..6d8a742d89 100755 --- a/test/functional/feature_help.py +++ b/test/functional/feature_help.py @@ -59,4 +59,4 @@ def run_test(self): if __name__ == '__main__': - HelpTest().main() + HelpTest(__file__).main() diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py index 58ab063e71..ee484e7ec5 100755 --- a/test/functional/feature_includeconf.py +++ b/test/functional/feature_includeconf.py @@ -83,4 +83,4 @@ def run_test(self): assert subversion.endswith("main; relative; relative2)/") if __name__ == '__main__': - IncludeConfTest().main() + IncludeConfTest(__file__).main() diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 66c0a4f615..030bf51ed8 100755 --- a/test/functional/feature_index_prune.py +++ b/test/functional/feature_index_prune.py @@ -155,4 +155,4 @@ def run_test(self): if __name__ == '__main__': - FeatureIndexPruneTest().main() + FeatureIndexPruneTest(__file__).main() diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index 22ae0c307b..659d33684e 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -149,4 +149,4 @@ def check_clean_start(): if __name__ == '__main__': - InitStressTest().main() + InitStressTest(__file__).main() diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py index 5129e0d328..1519c132b9 100755 --- a/test/functional/feature_loadblock.py +++ b/test/functional/feature_loadblock.py @@ -80,4 +80,4 @@ def run_test(self): if __name__ == '__main__': - LoadblockTest().main() + LoadblockTest(__file__).main() diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py index 0e9aca358d..ab817fd12d 100755 --- a/test/functional/feature_logging.py +++ b/test/functional/feature_logging.py @@ -101,4 +101,4 @@ def run_test(self): if __name__ == '__main__': - LoggingTest().main() + LoggingTest(__file__).main() diff --git a/test/functional/feature_maxtipage.py b/test/functional/feature_maxtipage.py index a1774a5395..4ce9bb949c 100755 --- a/test/functional/feature_maxtipage.py +++ b/test/functional/feature_maxtipage.py @@ -62,4 +62,4 @@ def run_test(self): if __name__ == '__main__': - MaxTipAgeTest().main() + MaxTipAgeTest(__file__).main() diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index 39cff7b738..136cdd024d 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -206,4 +206,4 @@ def run_test(self): self.nodes[0].assert_start_raises_init_error(extra_args=["-maxuploadtarget=abc"], expected_msg="Error: Unable to parse -maxuploadtarget: 'abc'") if __name__ == '__main__': - MaxUploadTest().main() + MaxUploadTest(__file__).main() diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py index 078d2ef63c..8327a0477b 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -115,4 +115,4 @@ def run_test(self): if __name__ == '__main__': - MinimumChainWorkTest().main() + MinimumChainWorkTest(__file__).main() diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index d2b5315d31..79e8df4b5e 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -194,4 +194,4 @@ def expect_wallet_notify(self, tx_details): if __name__ == '__main__': - NotificationsTest().main() + NotificationsTest(__file__).main() diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index f896cb6f43..a53f78c13d 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -154,4 +154,4 @@ def block_submit(self, node, txs, *, with_witness=False, accept): if __name__ == '__main__': - NULLDUMMYTest().main() + NULLDUMMYTest(__file__).main() diff --git a/test/functional/feature_posix_fs_permissions.py b/test/functional/feature_posix_fs_permissions.py index 40528779e6..28b1803891 100755 --- a/test/functional/feature_posix_fs_permissions.py +++ b/test/functional/feature_posix_fs_permissions.py @@ -40,4 +40,4 @@ def run_test(self): if __name__ == '__main__': - PosixFsPermissionsTest().main() + PosixFsPermissionsTest(__file__).main() diff --git a/test/functional/feature_presegwit_node_upgrade.py b/test/functional/feature_presegwit_node_upgrade.py index 3d762c8197..8c1bd90083 100755 --- a/test/functional/feature_presegwit_node_upgrade.py +++ b/test/functional/feature_presegwit_node_upgrade.py @@ -54,4 +54,4 @@ def run_test(self): if __name__ == '__main__': - SegwitUpgradeTest().main() + SegwitUpgradeTest(__file__).main() diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py index 7a6f639021..2201821fda 100755 --- a/test/functional/feature_proxy.py +++ b/test/functional/feature_proxy.py @@ -457,4 +457,4 @@ def networks_dict(d): os.unlink(socket_path) if __name__ == '__main__': - ProxyTest().main() + ProxyTest(__file__).main() diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index 5f99b8dee8..8d924282cf 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -513,4 +513,4 @@ def test_pruneheight_undo_presence(self): assert_equal(pruneheight, new_pruneheight) if __name__ == '__main__': - PruneTest().main() + PruneTest(__file__).main() diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 739b9b9bb9..cd5f5734c9 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -727,4 +727,4 @@ def test_fullrbf(self): assert conflicting_tx['txid'] in self.nodes[0].getrawmempool() if __name__ == '__main__': - ReplaceByFeeTest().main() + ReplaceByFeeTest(__file__).main() diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py index 835cd0c5cf..50a9ae1c06 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -103,4 +103,4 @@ def run_test(self): if __name__ == '__main__': - ReindexTest().main() + ReindexTest(__file__).main() diff --git a/test/functional/feature_reindex_readonly.py b/test/functional/feature_reindex_readonly.py index 52c0bb26a6..858a67566f 100755 --- a/test/functional/feature_reindex_readonly.py +++ b/test/functional/feature_reindex_readonly.py @@ -87,4 +87,4 @@ def run_test(self): if __name__ == '__main__': - BlockstoreReindexTest().main() + BlockstoreReindexTest(__file__).main() diff --git a/test/functional/feature_remove_pruned_files_on_startup.py b/test/functional/feature_remove_pruned_files_on_startup.py index 4ee653142a..2e689f2920 100755 --- a/test/functional/feature_remove_pruned_files_on_startup.py +++ b/test/functional/feature_remove_pruned_files_on_startup.py @@ -52,4 +52,4 @@ def run_test(self): assert not os.path.exists(rev1) if __name__ == '__main__': - FeatureRemovePrunedFilesOnStartupTest().main() + FeatureRemovePrunedFilesOnStartupTest(__file__).main() diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 4dc19222c4..f98f326e8f 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -657,4 +657,4 @@ def create_and_mine_tx_from_txids(self, txids, success=True): if __name__ == '__main__': - SegWitTest().main() + SegWitTest(__file__).main() diff --git a/test/functional/feature_settings.py b/test/functional/feature_settings.py index 1cd0aeabd3..2189eac7dd 100755 --- a/test/functional/feature_settings.py +++ b/test/functional/feature_settings.py @@ -88,4 +88,4 @@ def run_test(self): if __name__ == '__main__': - SettingsTest().main() + SettingsTest(__file__).main() diff --git a/test/functional/feature_shutdown.py b/test/functional/feature_shutdown.py index 291df4c518..a7277be39d 100755 --- a/test/functional/feature_shutdown.py +++ b/test/functional/feature_shutdown.py @@ -32,4 +32,4 @@ def run_test(self): self.stop_node(0, wait=1000) if __name__ == '__main__': - ShutdownTest().main() + ShutdownTest(__file__).main() diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py index a90a2a8e5e..b648266cae 100755 --- a/test/functional/feature_signet.py +++ b/test/functional/feature_signet.py @@ -82,4 +82,4 @@ def run_test(self): if __name__ == '__main__': - SignetBasicTest().main() + SignetBasicTest(__file__).main() diff --git a/test/functional/feature_startupnotify.py b/test/functional/feature_startupnotify.py index a8e62c6244..1e07103725 100755 --- a/test/functional/feature_startupnotify.py +++ b/test/functional/feature_startupnotify.py @@ -39,4 +39,4 @@ def get_count(): if __name__ == '__main__': - StartupNotifyTest().main() + StartupNotifyTest(__file__).main() diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index 1a0844d240..b2e030adc7 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -1766,4 +1766,4 @@ def run_test(self): if __name__ == '__main__': - TaprootTest().main() + TaprootTest(__file__).main() diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py index 4720f6dea3..fc372f543d 100755 --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -37,4 +37,4 @@ def run_test(self): if __name__ == '__main__': - UacommentTest().main() + UacommentTest(__file__).main() diff --git a/test/functional/feature_unsupported_utxo_db.py b/test/functional/feature_unsupported_utxo_db.py index 6acf551216..694a8e0623 100755 --- a/test/functional/feature_unsupported_utxo_db.py +++ b/test/functional/feature_unsupported_utxo_db.py @@ -58,4 +58,4 @@ def run_test(self): if __name__ == "__main__": - UnsupportedUtxoDbTest().main() + UnsupportedUtxoDbTest(__file__).main() diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py index 0bdcc6d83d..3ab779b87d 100755 --- a/test/functional/feature_utxo_set_hash.py +++ b/test/functional/feature_utxo_set_hash.py @@ -75,4 +75,4 @@ def run_test(self): if __name__ == '__main__': - UTXOSetHashTest().main() + UTXOSetHashTest(__file__).main() diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 2c330eb681..dc25ce6c83 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -100,4 +100,4 @@ def run_test(self): self.wait_until(lambda: self.versionbits_in_alert_file()) if __name__ == '__main__': - VersionBitsWarningTest().main() + VersionBitsWarningTest(__file__).main() diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index a6628dcbf3..e7113f8335 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -383,4 +383,4 @@ def run_test(self): if __name__ == '__main__': - TestBitcoinCli().main() + TestBitcoinCli(__file__).main() diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py index 6e32009e05..dbdceb52d1 100755 --- a/test/functional/interface_http.py +++ b/test/functional/interface_http.py @@ -106,4 +106,4 @@ def run_test(self): if __name__ == '__main__': - HTTPBasicsTest ().main () + HTTPBasicsTest(__file__).main() diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index ae8d6b226d..5706b1427b 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -436,4 +436,4 @@ def run_test(self): assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid hash: {INVALID_PARAM}") if __name__ == '__main__': - RESTTest().main() + RESTTest(__file__).main() diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py index 6c1855c400..9074f0a2d9 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -246,4 +246,4 @@ def run_test(self): if __name__ == '__main__': - RPCInterfaceTest().main() + RPCInterfaceTest(__file__).main() diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py index 30931a41cd..dc40986a75 100755 --- a/test/functional/interface_usdt_coinselection.py +++ b/test/functional/interface_usdt_coinselection.py @@ -231,4 +231,4 @@ def run_test(self): if __name__ == '__main__': - CoinSelectionTracepointTest().main() + CoinSelectionTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py index 0168d9f916..a088278665 100755 --- a/test/functional/interface_usdt_mempool.py +++ b/test/functional/interface_usdt_mempool.py @@ -322,4 +322,4 @@ def run_test(self): if __name__ == "__main__": - MempoolTracepointTest().main() + MempoolTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py index 5d7c8c2304..7b55259b63 100755 --- a/test/functional/interface_usdt_net.py +++ b/test/functional/interface_usdt_net.py @@ -168,4 +168,4 @@ def handle_outbound(_, data, __): if __name__ == '__main__': - NetTracepointTest().main() + NetTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py index 06cdcd10a0..ad98a3a162 100755 --- a/test/functional/interface_usdt_utxocache.py +++ b/test/functional/interface_usdt_utxocache.py @@ -407,4 +407,4 @@ def handle_utxocache_flush(_, data, __): if __name__ == '__main__': - UTXOCacheTracepointTest().main() + UTXOCacheTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py index 30982393d8..9a37b96ada 100755 --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -131,4 +131,4 @@ def handle_blockconnected(_, data, __): if __name__ == '__main__': - ValidationTracepointTest().main() + ValidationTracepointTest(__file__).main() diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 9f6f8919de..b960f40ccc 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -597,4 +597,4 @@ def test_ipv6(self): if __name__ == '__main__': - ZMQTest().main() + ZMQTest(__file__).main() diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index e1cee46839..2b841f3791 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -409,4 +409,4 @@ def run_test(self): ) if __name__ == '__main__': - MempoolAcceptanceTest().main() + MempoolAcceptanceTest(__file__).main() diff --git a/test/functional/mempool_accept_wtxid.py b/test/functional/mempool_accept_wtxid.py index 4767d6db22..e00e7b1ae4 100755 --- a/test/functional/mempool_accept_wtxid.py +++ b/test/functional/mempool_accept_wtxid.py @@ -125,4 +125,4 @@ def run_test(self): assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0) if __name__ == '__main__': - MempoolWtxidTest().main() + MempoolWtxidTest(__file__).main() diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index a126f164aa..7c72aaae77 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -78,4 +78,4 @@ def run_test(self): if __name__ == "__main__": - MempoolCompatibilityTest().main() + MempoolCompatibilityTest(__file__).main() diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py index 2e27aa988e..ed6ad8461a 100755 --- a/test/functional/mempool_datacarrier.py +++ b/test/functional/mempool_datacarrier.py @@ -88,4 +88,4 @@ def run_test(self): if __name__ == '__main__': - DataCarrierTest().main() + DataCarrierTest(__file__).main() diff --git a/test/functional/mempool_dust.py b/test/functional/mempool_dust.py index e0c026207a..1ea03a8a9e 100755 --- a/test/functional/mempool_dust.py +++ b/test/functional/mempool_dust.py @@ -110,4 +110,4 @@ def run_test(self): if __name__ == '__main__': - DustRelayFeeTest().main() + DustRelayFeeTest(__file__).main() diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py index 5eebe43488..2bd88f9825 100755 --- a/test/functional/mempool_expiry.py +++ b/test/functional/mempool_expiry.py @@ -114,4 +114,4 @@ def run_test(self): if __name__ == '__main__': - MempoolExpiryTest().main() + MempoolExpiryTest(__file__).main() diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 49a0a32c45..626928a49a 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -342,4 +342,4 @@ def run_test(self): if __name__ == '__main__': - MempoolLimitTest().main() + MempoolLimitTest(__file__).main() diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py index 2a64597511..6e26a684e2 100755 --- a/test/functional/mempool_package_limits.py +++ b/test/functional/mempool_package_limits.py @@ -343,4 +343,4 @@ def test_desc_size_limits(self): if __name__ == "__main__": - MempoolPackageLimitsTest().main() + MempoolPackageLimitsTest(__file__).main() diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py index 632425814a..fd54a8c3e1 100755 --- a/test/functional/mempool_package_onemore.py +++ b/test/functional/mempool_package_onemore.py @@ -77,4 +77,4 @@ def run_test(self): if __name__ == '__main__': - MempoolPackagesTest().main() + MempoolPackagesTest(__file__).main() diff --git a/test/functional/mempool_package_rbf.py b/test/functional/mempool_package_rbf.py index e9658aa8d0..9b4269f0a0 100755 --- a/test/functional/mempool_package_rbf.py +++ b/test/functional/mempool_package_rbf.py @@ -596,4 +596,4 @@ def test_child_conflicts_parent_mempool_ancestor(self): assert child_result["txid"] not in mempool_info if __name__ == "__main__": - PackageRBFTest().main() + PackageRBFTest(__file__).main() diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index 4be6594de6..a844a2a1d8 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -298,4 +298,4 @@ def run_test(self): self.sync_blocks() if __name__ == '__main__': - MempoolPackagesTest().main() + MempoolPackagesTest(__file__).main() diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 32a927084a..c64c203e50 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -263,4 +263,4 @@ def test_importmempool_union(self): if __name__ == "__main__": - MempoolPersistTest().main() + MempoolPersistTest(__file__).main() diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 691518ea09..e27942760c 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -194,4 +194,4 @@ def run_test(self): if __name__ == '__main__': - MempoolCoinbaseTest().main() + MempoolCoinbaseTest(__file__).main() diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py index c10052372d..720255b9e3 100755 --- a/test/functional/mempool_resurrect.py +++ b/test/functional/mempool_resurrect.py @@ -55,4 +55,4 @@ def run_test(self): if __name__ == '__main__': - MempoolCoinbaseTest().main() + MempoolCoinbaseTest(__file__).main() diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py index d3fb5f9119..4656176a75 100755 --- a/test/functional/mempool_sigoplimit.py +++ b/test/functional/mempool_sigoplimit.py @@ -196,4 +196,4 @@ def run_test(self): if __name__ == '__main__': - BytesPerSigOpTest().main() + BytesPerSigOpTest(__file__).main() diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py index a7cb2ba602..64ab33d3ff 100755 --- a/test/functional/mempool_spend_coinbase.py +++ b/test/functional/mempool_spend_coinbase.py @@ -57,4 +57,4 @@ def run_test(self): if __name__ == '__main__': - MempoolSpendCoinbaseTest().main() + MempoolSpendCoinbaseTest(__file__).main() diff --git a/test/functional/mempool_truc.py b/test/functional/mempool_truc.py index e1f3d77201..3f57b3e356 100755 --- a/test/functional/mempool_truc.py +++ b/test/functional/mempool_truc.py @@ -644,4 +644,4 @@ def run_test(self): if __name__ == "__main__": - MempoolTRUC().main() + MempoolTRUC(__file__).main() diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py index 12de750731..7c96b4b570 100755 --- a/test/functional/mempool_unbroadcast.py +++ b/test/functional/mempool_unbroadcast.py @@ -109,4 +109,4 @@ def test_txn_removal(self): if __name__ == "__main__": - MempoolUnbroadcastTest().main() + MempoolUnbroadcastTest(__file__).main() diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py index 8350e9c91e..1754991756 100755 --- a/test/functional/mempool_updatefromblock.py +++ b/test/functional/mempool_updatefromblock.py @@ -103,4 +103,4 @@ def run_test(self): if __name__ == '__main__': - MempoolUpdateFromBlockTest().main() + MempoolUpdateFromBlockTest(__file__).main() diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 5f2dde8eac..6a364a4815 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -325,4 +325,4 @@ def chain_tip(b_hash, *, status='headers-only', branchlen=1): if __name__ == '__main__': - MiningTest().main() + MiningTest(__file__).main() diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py index c0e7195c82..2d15151e65 100755 --- a/test/functional/mining_getblocktemplate_longpoll.py +++ b/test/functional/mining_getblocktemplate_longpoll.py @@ -73,4 +73,4 @@ def run_test(self): assert not thr.is_alive() if __name__ == '__main__': - GetBlockTemplateLPTest().main() + GetBlockTemplateLPTest(__file__).main() diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index c5f34e3ecb..eb55202e16 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -305,4 +305,4 @@ def run_test(self): assert template != new_template if __name__ == '__main__': - PrioritiseTransactionTest().main() + PrioritiseTransactionTest(__file__).main() diff --git a/test/functional/p2p_1p1c_network.py b/test/functional/p2p_1p1c_network.py index ea59248506..c3cdb3e0b3 100755 --- a/test/functional/p2p_1p1c_network.py +++ b/test/functional/p2p_1p1c_network.py @@ -163,4 +163,4 @@ def run_test(self): if __name__ == '__main__': - PackageRelayTest().main() + PackageRelayTest(__file__).main() diff --git a/test/functional/p2p_add_connections.py b/test/functional/p2p_add_connections.py index bd766a279e..886de36fcc 100755 --- a/test/functional/p2p_add_connections.py +++ b/test/functional/p2p_add_connections.py @@ -107,4 +107,4 @@ def run_test(self): assert_equal(feeler_conn.last_message["version"].relay, 0) if __name__ == '__main__': - P2PAddConnections().main() + P2PAddConnections(__file__).main() diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index d10e47e036..56a9e6a84e 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -441,4 +441,4 @@ def destination_rotates_more_than_once_over_several_days_test(self): if __name__ == '__main__': - AddrTest().main() + AddrTest(__file__).main() diff --git a/test/functional/p2p_addrfetch.py b/test/functional/p2p_addrfetch.py index 3ead653ba6..69cc106341 100755 --- a/test/functional/p2p_addrfetch.py +++ b/test/functional/p2p_addrfetch.py @@ -83,4 +83,4 @@ def run_test(self): if __name__ == '__main__': - P2PAddrFetch().main() + P2PAddrFetch(__file__).main() diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py index 4ec8e0bc04..d5ded926d3 100755 --- a/test/functional/p2p_addrv2_relay.py +++ b/test/functional/p2p_addrv2_relay.py @@ -110,4 +110,4 @@ def run_test(self): if __name__ == '__main__': - AddrTest().main() + AddrTest(__file__).main() diff --git a/test/functional/p2p_block_sync.py b/test/functional/p2p_block_sync.py index 6c7f08364e..51bbac1738 100755 --- a/test/functional/p2p_block_sync.py +++ b/test/functional/p2p_block_sync.py @@ -34,4 +34,4 @@ def run_test(self): if __name__ == '__main__': - BlockSyncTest().main() + BlockSyncTest(__file__).main() diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index 680fa9c7fa..88d5aa1408 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -282,4 +282,4 @@ def compute_last_header(prev_header, hashes): if __name__ == '__main__': - CompactFiltersTest().main() + CompactFiltersTest(__file__).main() diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 637644e6e4..b9e6dc9056 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -125,4 +125,4 @@ def check_p2p_tx_violation(self): if __name__ == '__main__': - P2PBlocksOnly().main() + P2PBlocksOnly(__file__).main() diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 9e314db110..49cf26d425 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -965,4 +965,4 @@ def run_test(self): if __name__ == '__main__': - CompactBlocksTest().main() + CompactBlocksTest(__file__).main() diff --git a/test/functional/p2p_compactblocks_blocksonly.py b/test/functional/p2p_compactblocks_blocksonly.py index 761cd3a218..b92efc875c 100755 --- a/test/functional/p2p_compactblocks_blocksonly.py +++ b/test/functional/p2p_compactblocks_blocksonly.py @@ -127,4 +127,4 @@ def test_for_cmpctblock(block): p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block2)) if __name__ == '__main__': - P2PCompactBlocksBlocksOnly().main() + P2PCompactBlocksBlocksOnly(__file__).main() diff --git a/test/functional/p2p_compactblocks_hb.py b/test/functional/p2p_compactblocks_hb.py index 023b33ff6d..e4f58e9cf7 100755 --- a/test/functional/p2p_compactblocks_hb.py +++ b/test/functional/p2p_compactblocks_hb.py @@ -97,4 +97,4 @@ def run_test(self): if __name__ == '__main__': - CompactBlocksConnectionTest().main() + CompactBlocksConnectionTest(__file__).main() diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py index e47f9c732b..94be86475e 100755 --- a/test/functional/p2p_disconnect_ban.py +++ b/test/functional/p2p_disconnect_ban.py @@ -147,4 +147,4 @@ def run_test(self): assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1] if __name__ == '__main__': - DisconnectBanTest().main() + DisconnectBanTest(__file__).main() diff --git a/test/functional/p2p_dns_seeds.py b/test/functional/p2p_dns_seeds.py index e58ad8e0fc..a2d4ea110f 100755 --- a/test/functional/p2p_dns_seeds.py +++ b/test/functional/p2p_dns_seeds.py @@ -126,4 +126,4 @@ def wait_time_tests(self): if __name__ == '__main__': - P2PDNSSeeds().main() + P2PDNSSeeds(__file__).main() diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py index 4b4346af49..fbb5d716f5 100755 --- a/test/functional/p2p_dos_header_tree.py +++ b/test/functional/p2p_dos_header_tree.py @@ -85,4 +85,4 @@ def run_test(self): if __name__ == '__main__': - RejectLowDifficultyHeadersTest().main() + RejectLowDifficultyHeadersTest(__file__).main() diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py index 8b31dfa549..0d2bdcc429 100755 --- a/test/functional/p2p_eviction.py +++ b/test/functional/p2p_eviction.py @@ -124,4 +124,4 @@ def run_test(self): if __name__ == '__main__': - P2PEvict().main() + P2PEvict(__file__).main() diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py index bcba534f9a..6b44118467 100755 --- a/test/functional/p2p_feefilter.py +++ b/test/functional/p2p_feefilter.py @@ -132,4 +132,4 @@ def test_feefilter_blocksonly(self): if __name__ == '__main__': - FeeFilterTest().main() + FeeFilterTest(__file__).main() diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index 7c8ed58e51..e4aaf507cf 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -252,4 +252,4 @@ def run_test(self): if __name__ == '__main__': - FilterTest().main() + FilterTest(__file__).main() diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index e8bba8555f..f49be62056 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -130,4 +130,4 @@ def run_test(self): if __name__ == '__main__': - P2PFingerprintTest().main() + P2PFingerprintTest(__file__).main() diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py index 60b43c32ae..6626b14ee0 100755 --- a/test/functional/p2p_getaddr_caching.py +++ b/test/functional/p2p_getaddr_caching.py @@ -119,4 +119,4 @@ def run_test(self): if __name__ == '__main__': - AddrTest().main() + AddrTest(__file__).main() diff --git a/test/functional/p2p_getdata.py b/test/functional/p2p_getdata.py index 89d68d5ba0..6153d08d9b 100755 --- a/test/functional/p2p_getdata.py +++ b/test/functional/p2p_getdata.py @@ -46,4 +46,4 @@ def run_test(self): if __name__ == '__main__': - GetdataTest().main() + GetdataTest(__file__).main() diff --git a/test/functional/p2p_handshake.py b/test/functional/p2p_handshake.py index 9536e74893..18307a2824 100755 --- a/test/functional/p2p_handshake.py +++ b/test/functional/p2p_handshake.py @@ -97,4 +97,4 @@ def run_test(self): if __name__ == '__main__': - P2PHandshakeTest().main() + P2PHandshakeTest(__file__).main() diff --git a/test/functional/p2p_headers_sync_with_minchainwork.py b/test/functional/p2p_headers_sync_with_minchainwork.py index 832fd7e0e9..9055232cf3 100755 --- a/test/functional/p2p_headers_sync_with_minchainwork.py +++ b/test/functional/p2p_headers_sync_with_minchainwork.py @@ -162,4 +162,4 @@ def run_test(self): if __name__ == '__main__': - RejectLowDifficultyHeadersTest().main() + RejectLowDifficultyHeadersTest(__file__).main() diff --git a/test/functional/p2p_i2p_ports.py b/test/functional/p2p_i2p_ports.py index 20dcb50a57..b1a3c61c7a 100755 --- a/test/functional/p2p_i2p_ports.py +++ b/test/functional/p2p_i2p_ports.py @@ -32,4 +32,4 @@ def run_test(self): if __name__ == '__main__': - I2PPorts().main() + I2PPorts(__file__).main() diff --git a/test/functional/p2p_i2p_sessions.py b/test/functional/p2p_i2p_sessions.py index 9e7fdc6e14..67474f6c0e 100755 --- a/test/functional/p2p_i2p_sessions.py +++ b/test/functional/p2p_i2p_sessions.py @@ -33,4 +33,4 @@ def run_test(self): if __name__ == '__main__': - I2PSessions().main() + I2PSessions(__file__).main() diff --git a/test/functional/p2p_ibd_stalling.py b/test/functional/p2p_ibd_stalling.py index 830f374d63..11cd8837f4 100755 --- a/test/functional/p2p_ibd_stalling.py +++ b/test/functional/p2p_ibd_stalling.py @@ -162,4 +162,4 @@ def is_block_requested(self, peers, hash): if __name__ == '__main__': - P2PIBDStallingTest().main() + P2PIBDStallingTest(__file__).main() diff --git a/test/functional/p2p_ibd_txrelay.py b/test/functional/p2p_ibd_txrelay.py index b93e39a925..882f5b5c13 100755 --- a/test/functional/p2p_ibd_txrelay.py +++ b/test/functional/p2p_ibd_txrelay.py @@ -86,4 +86,4 @@ def run_test(self): peer_txer.send_and_ping(msg_tx(tx)) if __name__ == '__main__': - P2PIBDTxRelayTest().main() + P2PIBDTxRelayTest(__file__).main() diff --git a/test/functional/p2p_initial_headers_sync.py b/test/functional/p2p_initial_headers_sync.py index bc6e0fb355..5c17b75677 100755 --- a/test/functional/p2p_initial_headers_sync.py +++ b/test/functional/p2p_initial_headers_sync.py @@ -96,5 +96,5 @@ def run_test(self): self.log.info("Success!") if __name__ == '__main__': - HeadersSyncTest().main() + HeadersSyncTest(__file__).main() diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index 8ec62ae5ee..c4c79dcbb8 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -138,4 +138,4 @@ def run_test(self): if __name__ == '__main__': - InvalidBlockRequestTest().main() + InvalidBlockRequestTest(__file__).main() diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index 32a23532a2..bde01d5c95 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -39,4 +39,4 @@ def run_test(self): if __name__ == '__main__': - InvalidLocatorTest().main() + InvalidLocatorTest(__file__).main() diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index 8e459ba676..507393fb70 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -356,4 +356,4 @@ def test_resource_exhaustion(self): if __name__ == '__main__': - InvalidMessagesTest().main() + InvalidMessagesTest(__file__).main() diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index 0ae05d4b0b..241aefab24 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -224,4 +224,4 @@ def run_test(self): if __name__ == '__main__': - InvalidTxRequestTest().main() + InvalidTxRequestTest(__file__).main() diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 645488f24d..f800e815d8 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -178,4 +178,4 @@ def run_test(self): if __name__ == '__main__': - P2PLeakTest().main() + P2PLeakTest(__file__).main() diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py index f53f98e06d..a2eec49b72 100755 --- a/test/functional/p2p_leak_tx.py +++ b/test/functional/p2p_leak_tx.py @@ -104,4 +104,4 @@ def test_notfound_on_unannounced_tx(self): if __name__ == '__main__': - P2PLeakTxTest().main() + P2PLeakTxTest(__file__).main() diff --git a/test/functional/p2p_message_capture.py b/test/functional/p2p_message_capture.py index 691a0b6409..4c82adc58c 100755 --- a/test/functional/p2p_message_capture.py +++ b/test/functional/p2p_message_capture.py @@ -69,4 +69,4 @@ def run_test(self): if __name__ == '__main__': - MessageCaptureTest().main() + MessageCaptureTest(__file__).main() diff --git a/test/functional/p2p_mutated_blocks.py b/test/functional/p2p_mutated_blocks.py index 708b19b1e5..4a790168da 100755 --- a/test/functional/p2p_mutated_blocks.py +++ b/test/functional/p2p_mutated_blocks.py @@ -112,4 +112,4 @@ def self_transfer_requested(): if __name__ == '__main__': - MutatedBlocksTest().main() + MutatedBlocksTest(__file__).main() diff --git a/test/functional/p2p_net_deadlock.py b/test/functional/p2p_net_deadlock.py index 1a357b944b..4f1b731e21 100755 --- a/test/functional/p2p_net_deadlock.py +++ b/test/functional/p2p_net_deadlock.py @@ -34,4 +34,4 @@ def run_test(self): if __name__ == '__main__': - NetDeadlockTest().main() + NetDeadlockTest(__file__).main() diff --git a/test/functional/p2p_nobloomfilter_messages.py b/test/functional/p2p_nobloomfilter_messages.py index 507a71b2a9..dd2dc9ae69 100755 --- a/test/functional/p2p_nobloomfilter_messages.py +++ b/test/functional/p2p_nobloomfilter_messages.py @@ -45,4 +45,4 @@ def run_test(self): if __name__ == '__main__': - P2PNoBloomFilterMessages().main() + P2PNoBloomFilterMessages(__file__).main() diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index 8b63d8ee26..df6e6a2e28 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -172,4 +172,4 @@ def run_test(self): self.test_avoid_requesting_historical_blocks() if __name__ == '__main__': - NodeNetworkLimitedTest().main() + NodeNetworkLimitedTest(__file__).main() diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index aec6e95fbc..4477046c8d 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -412,4 +412,4 @@ def run_test(self): if __name__ == '__main__': - PackageRelayTest().main() + PackageRelayTest(__file__).main() diff --git a/test/functional/p2p_orphan_handling.py b/test/functional/p2p_orphan_handling.py index f525d87cca..22600bf8a4 100755 --- a/test/functional/p2p_orphan_handling.py +++ b/test/functional/p2p_orphan_handling.py @@ -585,4 +585,4 @@ def run_test(self): if __name__ == '__main__': - OrphanHandlingTest().main() + OrphanHandlingTest(__file__).main() diff --git a/test/functional/p2p_outbound_eviction.py b/test/functional/p2p_outbound_eviction.py index 8d89688999..30ac85e32f 100755 --- a/test/functional/p2p_outbound_eviction.py +++ b/test/functional/p2p_outbound_eviction.py @@ -250,4 +250,4 @@ def run_test(self): if __name__ == '__main__': - P2POutEvict().main() + P2POutEvict(__file__).main() diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index 80a27943fd..5ca5101613 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -147,4 +147,4 @@ def checkpermission(self, args, expectedPermissions): if __name__ == '__main__': - P2PPermissionsTests().main() + P2PPermissionsTests(__file__).main() diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py index 3ba30a42b1..5c10ac2a4b 100755 --- a/test/functional/p2p_ping.py +++ b/test/functional/p2p_ping.py @@ -117,4 +117,4 @@ def run_test(self): if __name__ == '__main__': - PingPongTest().main() + PingPongTest(__file__).main() diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index d20cf41a72..9be53d2ab8 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -2067,4 +2067,4 @@ def received_wtxidrelay(): if __name__ == '__main__': - SegWitTest().main() + SegWitTest(__file__).main() diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index 5c463267a1..db706556d8 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -568,4 +568,4 @@ def test_nonnull_locators(self, test_node, inv_node): assert "getdata" not in inv_node.last_message if __name__ == '__main__': - SendHeadersTest().main() + SendHeadersTest(__file__).main() diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py index 8f5e6c0387..2c7216b5ca 100755 --- a/test/functional/p2p_sendtxrcncl.py +++ b/test/functional/p2p_sendtxrcncl.py @@ -232,4 +232,4 @@ def run_test(self): if __name__ == '__main__': - SendTxRcnclTest().main() + SendTxRcnclTest(__file__).main() diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py index 80d7b6e9ae..1fd78e163b 100755 --- a/test/functional/p2p_timeouts.py +++ b/test/functional/p2p_timeouts.py @@ -109,4 +109,4 @@ def run_test(self): if __name__ == '__main__': - TimeoutsTest().main() + TimeoutsTest(__file__).main() diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py index 0af6b1d2c9..11b4d9cc3b 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -306,4 +306,4 @@ def run_test(self): if __name__ == '__main__': - TxDownloadTest().main() + TxDownloadTest(__file__).main() diff --git a/test/functional/p2p_tx_privacy.py b/test/functional/p2p_tx_privacy.py index e674f6c3eb..afe9df8a0f 100755 --- a/test/functional/p2p_tx_privacy.py +++ b/test/functional/p2p_tx_privacy.py @@ -74,4 +74,4 @@ def run_test(self): spy.wait_for_inv_match(CInv(MSG_WTX, tx2.calc_sha256(True))) if __name__ == '__main__': - TxPrivacyTest().main() + TxPrivacyTest(__file__).main() diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 776eaf5255..835ecbf184 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -296,4 +296,4 @@ def run_test(self): self.log.info("Successfully synced nodes 1 and 0") if __name__ == '__main__': - AcceptBlockTest().main() + AcceptBlockTest(__file__).main() diff --git a/test/functional/p2p_v2_encrypted.py b/test/functional/p2p_v2_encrypted.py index 05755dece0..3e8ce09d24 100755 --- a/test/functional/p2p_v2_encrypted.py +++ b/test/functional/p2p_v2_encrypted.py @@ -131,4 +131,4 @@ def run_test(self): if __name__ == '__main__': - P2PEncrypted().main() + P2PEncrypted(__file__).main() diff --git a/test/functional/p2p_v2_misbehaving.py b/test/functional/p2p_v2_misbehaving.py index 9017ee9455..b66d0289ff 100755 --- a/test/functional/p2p_v2_misbehaving.py +++ b/test/functional/p2p_v2_misbehaving.py @@ -185,4 +185,4 @@ def test_v2disconnection(self): if __name__ == '__main__': - EncryptedP2PMisbehaving().main() + EncryptedP2PMisbehaving(__file__).main() diff --git a/test/functional/p2p_v2_transport.py b/test/functional/p2p_v2_transport.py index fe2449124d..94c91906e6 100755 --- a/test/functional/p2p_v2_transport.py +++ b/test/functional/p2p_v2_transport.py @@ -168,4 +168,4 @@ def run_test(self): if __name__ == '__main__': - V2TransportTest().main() + V2TransportTest(__file__).main() diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py index 3106419e5c..8c76c1f5f5 100755 --- a/test/functional/rpc_bind.py +++ b/test/functional/rpc_bind.py @@ -124,4 +124,4 @@ def _run_nonloopback_tests(self): assert_raises_rpc_error(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], self.non_loopback_ip, self.defaultport) if __name__ == '__main__': - RPCBindTest().main() + RPCBindTest(__file__).main() diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 9b7743cafa..e5aca7f138 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -635,4 +635,4 @@ def move_block_file(old, new): if __name__ == '__main__': - BlockchainTest().main() + BlockchainTest(__file__).main() diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 37656341d2..9f4e17a328 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -257,4 +257,4 @@ def test_sortedmulti_descriptors_bip67(self): if __name__ == '__main__': - RpcCreateMultiSigTest().main() + RpcCreateMultiSigTest(__file__).main() diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py index f37e61ab50..66dbd78573 100755 --- a/test/functional/rpc_decodescript.py +++ b/test/functional/rpc_decodescript.py @@ -289,4 +289,4 @@ def run_test(self): self.decodescript_miniscript() if __name__ == '__main__': - DecodeScriptTest().main() + DecodeScriptTest(__file__).main() diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py index 15c77ed856..4a415d57f5 100755 --- a/test/functional/rpc_deprecated.py +++ b/test/functional/rpc_deprecated.py @@ -26,4 +26,4 @@ def run_test(self): self.log.info("No tested deprecated RPC methods") if __name__ == '__main__': - DeprecatedRpcTest().main() + DeprecatedRpcTest(__file__).main() diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py index 64994d6bb3..c66d91713f 100755 --- a/test/functional/rpc_deriveaddresses.py +++ b/test/functional/rpc_deriveaddresses.py @@ -61,4 +61,4 @@ def run_test(self): assert_raises_rpc_error(-5, "Descriptor does not have a corresponding address", self.nodes[0].deriveaddresses, bare_multisig_descriptor) if __name__ == '__main__': - DeriveaddressesTest().main() + DeriveaddressesTest(__file__).main() diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py index c92c8da357..0b7c468846 100755 --- a/test/functional/rpc_dumptxoutset.py +++ b/test/functional/rpc_dumptxoutset.py @@ -58,4 +58,4 @@ def run_test(self): if __name__ == '__main__': - DumptxoutsetTest().main() + DumptxoutsetTest(__file__).main() diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py index 6643799a76..05ceafbe4e 100755 --- a/test/functional/rpc_estimatefee.py +++ b/test/functional/rpc_estimatefee.py @@ -52,4 +52,4 @@ def run_test(self): if __name__ == '__main__': - EstimateFeeTest().main() + EstimateFeeTest(__file__).main() diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 3e250925e7..68de900664 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -126,4 +126,4 @@ def test_generate(self): if __name__ == "__main__": - RPCGenerateTest().main() + RPCGenerateTest(__file__).main() diff --git a/test/functional/rpc_getblockfilter.py b/test/functional/rpc_getblockfilter.py index b09af9e078..245bcec8e8 100755 --- a/test/functional/rpc_getblockfilter.py +++ b/test/functional/rpc_getblockfilter.py @@ -61,4 +61,4 @@ def run_test(self): self.nodes[0].getblockfilter, genesis_hash, filter_type) if __name__ == '__main__': - GetBlockFilterTest().main() + GetBlockFilterTest(__file__).main() diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py index 1ab1023cf1..e309018516 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -154,4 +154,4 @@ def run_test(self): if __name__ == '__main__': - GetBlockFromPeerTest().main() + GetBlockFromPeerTest(__file__).main() diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index bf261befcc..d1e4895eb6 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -183,4 +183,4 @@ def run_test(self): assert_equal(tip_stats["utxo_size_inc_actual"], 300) if __name__ == '__main__': - GetblockstatsTest().main() + GetblockstatsTest(__file__).main() diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py index 7efa306c8c..1bd4413ce1 100755 --- a/test/functional/rpc_getchaintips.py +++ b/test/functional/rpc_getchaintips.py @@ -58,4 +58,4 @@ def run_test(self): assert_equal (tips[1], shortTip) if __name__ == '__main__': - GetChainTipsTest ().main () + GetChainTipsTest(__file__).main() diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py index 2eb36f260c..c84928462d 100755 --- a/test/functional/rpc_getdescriptorinfo.py +++ b/test/functional/rpc_getdescriptorinfo.py @@ -63,4 +63,4 @@ def run_test(self): if __name__ == '__main__': - DescriptorTest().main() + DescriptorTest(__file__).main() diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py index 53c5aa05e5..4ce24ecb67 100755 --- a/test/functional/rpc_help.py +++ b/test/functional/rpc_help.py @@ -132,4 +132,4 @@ def wallet_help(self): if __name__ == '__main__': - HelpRpcTest().main() + HelpRpcTest(__file__).main() diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py index 6759b69dd1..f712530c3b 100755 --- a/test/functional/rpc_invalid_address_message.py +++ b/test/functional/rpc_invalid_address_message.py @@ -119,4 +119,4 @@ def run_test(self): if __name__ == '__main__': - InvalidAddressErrorMessageTest().main() + InvalidAddressErrorMessageTest(__file__).main() diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index 69c5397ce2..db79d55259 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -90,4 +90,4 @@ def run_test(self): if __name__ == '__main__': - InvalidateTest().main() + InvalidateTest(__file__).main() diff --git a/test/functional/rpc_mempool_info.py b/test/functional/rpc_mempool_info.py index 246af22e50..231d93a7b1 100755 --- a/test/functional/rpc_mempool_info.py +++ b/test/functional/rpc_mempool_info.py @@ -96,4 +96,4 @@ def create_tx(**kwargs): if __name__ == '__main__': - RPCMempoolInfoTest().main() + RPCMempoolInfoTest(__file__).main() diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index 20485c01d3..b5c12b28c1 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -102,4 +102,4 @@ def run_test(self): if __name__ == '__main__': - RpcMiscTest().main() + RpcMiscTest(__file__).main() diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py index 46d9ffceae..0385c33267 100755 --- a/test/functional/rpc_named_arguments.py +++ b/test/functional/rpc_named_arguments.py @@ -35,4 +35,4 @@ def run_test(self): assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", node.echo, 0, None, 2, arg1=1) if __name__ == '__main__': - NamedArgumentTest().main() + NamedArgumentTest(__file__).main() diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 37e2c1fb71..b63059b1ee 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -574,4 +574,4 @@ def check_getrawaddrman_entries(expected): if __name__ == '__main__': - NetTest().main() + NetTest(__file__).main() diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index 1acd586d2c..ef2f66b3a0 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -489,4 +489,4 @@ def test_maxburn_submitpackage(self): assert_equal(node.getrawmempool(), [chained_txns_burn[0]["txid"]]) if __name__ == "__main__": - RPCPackagesTest().main() + RPCPackagesTest(__file__).main() diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py index 3062a86565..224bba6f9b 100755 --- a/test/functional/rpc_preciousblock.py +++ b/test/functional/rpc_preciousblock.py @@ -109,4 +109,4 @@ def run_test(self): assert_equal(self.nodes[2].getbestblockhash(), hashH) if __name__ == '__main__': - PreciousTest().main() + PreciousTest(__file__).main() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index a56960adff..8c5f98286a 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -985,4 +985,4 @@ def test_psbt_input_keys(psbt_input, keys): if __name__ == '__main__': - PSBTTest().main() + PSBTTest(__file__).main() diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index f974a05f7b..aa179e009d 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -612,4 +612,4 @@ def raw_multisig_transaction_legacy_tests(self): if __name__ == '__main__': - RawTransactionsTest().main() + RawTransactionsTest(__file__).main() diff --git a/test/functional/rpc_scanblocks.py b/test/functional/rpc_scanblocks.py index 8b4aebc77a..d05ba09ba5 100755 --- a/test/functional/rpc_scanblocks.py +++ b/test/functional/rpc_scanblocks.py @@ -136,4 +136,4 @@ def run_test(self): if __name__ == '__main__': - ScanblocksTest().main() + ScanblocksTest(__file__).main() diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py index 9f77f209ef..078a24d577 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -131,4 +131,4 @@ def run_test(self): if __name__ == "__main__": - ScantxoutsetTest().main() + ScantxoutsetTest(__file__).main() diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py index ba86b278bd..c4e5ebccca 100755 --- a/test/functional/rpc_setban.py +++ b/test/functional/rpc_setban.py @@ -75,4 +75,4 @@ def run_test(self): assert_equal(banned['ban_duration'], 1234) if __name__ == '__main__': - SetBanTests().main() + SetBanTests(__file__).main() diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py index 488682e959..7dd16ea8fe 100755 --- a/test/functional/rpc_signer.py +++ b/test/functional/rpc_signer.py @@ -77,4 +77,4 @@ def run_test(self): assert_equal({'fingerprint': '00000001', 'name': 'trezor_t'} in self.nodes[1].enumeratesigners()['signers'], True) if __name__ == '__main__': - RPCSignerTest().main() + RPCSignerTest(__file__).main() diff --git a/test/functional/rpc_signmessagewithprivkey.py b/test/functional/rpc_signmessagewithprivkey.py index c5df22157d..8e86698781 100755 --- a/test/functional/rpc_signmessagewithprivkey.py +++ b/test/functional/rpc_signmessagewithprivkey.py @@ -60,4 +60,4 @@ def run_test(self): if __name__ == '__main__': - SignMessagesWithPrivTest().main() + SignMessagesWithPrivTest(__file__).main() diff --git a/test/functional/rpc_signrawtransactionwithkey.py b/test/functional/rpc_signrawtransactionwithkey.py index f4fec13495..9dae0ba994 100755 --- a/test/functional/rpc_signrawtransactionwithkey.py +++ b/test/functional/rpc_signrawtransactionwithkey.py @@ -143,4 +143,4 @@ def run_test(self): if __name__ == '__main__': - SignRawTransactionWithKeyTest().main() + SignRawTransactionWithKeyTest(__file__).main() diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index 60b7ce8d20..387132b680 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -104,4 +104,4 @@ def run_test(self): # verify that the proofs are invalid if __name__ == '__main__': - MerkleBlockTest().main() + MerkleBlockTest(__file__).main() diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py index f8df59d02a..fdf459953c 100755 --- a/test/functional/rpc_uptime.py +++ b/test/functional/rpc_uptime.py @@ -32,4 +32,4 @@ def _test_uptime(self): if __name__ == '__main__': - UptimeTest().main() + UptimeTest(__file__).main() diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py index 153493fbab..44187ce790 100755 --- a/test/functional/rpc_users.py +++ b/test/functional/rpc_users.py @@ -156,4 +156,4 @@ def run_test(self): if __name__ == '__main__': - HTTPBasicsTest().main() + HTTPBasicsTest(__file__).main() diff --git a/test/functional/rpc_validateaddress.py b/test/functional/rpc_validateaddress.py index d87ba098c3..dde07e7ead 100755 --- a/test/functional/rpc_validateaddress.py +++ b/test/functional/rpc_validateaddress.py @@ -200,4 +200,4 @@ def run_test(self): if __name__ == "__main__": - ValidateAddressMainTest().main() + ValidateAddressMainTest(__file__).main() diff --git a/test/functional/rpc_whitelist.py b/test/functional/rpc_whitelist.py index fb404fb479..5f74fe8274 100755 --- a/test/functional/rpc_whitelist.py +++ b/test/functional/rpc_whitelist.py @@ -93,4 +93,4 @@ def run_test(self): assert_equal(200, rpccall(self.nodes[0], self.strange_users[4], "getblockcount").status) if __name__ == "__main__": - RPCWhitelistTest().main() + RPCWhitelistTest(__file__).main() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 9e44a11143..3887cc8545 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -92,7 +92,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): This class also contains various public and private helper methods.""" - def __init__(self) -> None: + def __init__(self, test_file) -> None: """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" self.chain: str = 'regtest' self.setup_clean_chain: bool = False diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py index 1ad2a579bf..bdefb92ae6 100755 --- a/test/functional/tool_signet_miner.py +++ b/test/functional/tool_signet_miner.py @@ -62,4 +62,4 @@ def run_test(self): if __name__ == "__main__": - SignetMinerTest().main() + SignetMinerTest(__file__).main() diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index dcf74f6075..784a769882 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -563,4 +563,4 @@ def run_test(self): self.test_dump_very_large_records() if __name__ == '__main__': - ToolWalletTest().main() + ToolWalletTest(__file__).main() diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index dda48aae1b..ce0f4d099b 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -241,4 +241,4 @@ def run_test(self): assert_equal(newbalance, balance - Decimal("20")) if __name__ == '__main__': - AbandonConflictTest().main() + AbandonConflictTest(__file__).main() diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index 6b27b32dea..e326d3e89e 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -387,4 +387,4 @@ def run_test(self): assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getrawchangeaddress, "bech32m") if __name__ == '__main__': - AddressTypeTest().main() + AddressTypeTest(__file__).main() diff --git a/test/functional/wallet_assumeutxo.py b/test/functional/wallet_assumeutxo.py index 30396da015..0bce2f137c 100755 --- a/test/functional/wallet_assumeutxo.py +++ b/test/functional/wallet_assumeutxo.py @@ -164,4 +164,4 @@ def run_test(self): if __name__ == '__main__': - AssumeutxoTest().main() + AssumeutxoTest(__file__).main() diff --git a/test/functional/wallet_avoid_mixing_output_types.py b/test/functional/wallet_avoid_mixing_output_types.py index 66fbf780e5..146b3df3f4 100755 --- a/test/functional/wallet_avoid_mixing_output_types.py +++ b/test/functional/wallet_avoid_mixing_output_types.py @@ -177,4 +177,4 @@ def run_test(self): if __name__ == '__main__': - AddressInputTypeGrouping().main() + AddressInputTypeGrouping(__file__).main() diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py index 4983bfda7f..bba79d0a25 100755 --- a/test/functional/wallet_avoidreuse.py +++ b/test/functional/wallet_avoidreuse.py @@ -381,4 +381,4 @@ def test_all_destination_groups_are_used(self): if __name__ == '__main__': - AvoidReuseTest().main() + AvoidReuseTest(__file__).main() diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index d03b08bcc4..a639c34377 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -244,4 +244,4 @@ def run_test(self): if __name__ == '__main__': - WalletBackupTest().main() + WalletBackupTest(__file__).main() diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py index ab008a40cd..e71283b928 100755 --- a/test/functional/wallet_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -400,4 +400,4 @@ def run_test(self): assert_equal(info, addr_info) if __name__ == '__main__': - BackwardsCompatibilityTest().main() + BackwardsCompatibilityTest(__file__).main() diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index 2c85773bf3..9da53402a4 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -339,4 +339,4 @@ def test_balances(*, fee_node_1=0): assert_equal(tx_info['lastprocessedblock']['hash'], prev_hash) if __name__ == '__main__': - WalletTest().main() + WalletTest(__file__).main() diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 1b2b8ec1f3..c968e4333a 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -818,4 +818,4 @@ def test_chain_listunspent(self): if __name__ == '__main__': - WalletTest().main() + WalletTest(__file__).main() diff --git a/test/functional/wallet_blank.py b/test/functional/wallet_blank.py index e646d27005..76f9cb05ee 100755 --- a/test/functional/wallet_blank.py +++ b/test/functional/wallet_blank.py @@ -160,4 +160,4 @@ def run_test(self): if __name__ == '__main__': - WalletBlankTest().main() + WalletBlankTest(__file__).main() diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 6d45adc823..81c1c8c1b3 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -854,4 +854,4 @@ def test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, if __name__ == "__main__": - BumpFeeTest().main() + BumpFeeTest(__file__).main() diff --git a/test/functional/wallet_change_address.py b/test/functional/wallet_change_address.py index f8bfe9eebf..07bab82697 100755 --- a/test/functional/wallet_change_address.py +++ b/test/functional/wallet_change_address.py @@ -105,4 +105,4 @@ def run_test(self): self.assert_change_pos(w1, tx, 0) if __name__ == '__main__': - WalletChangeAddressTest().main() + WalletChangeAddressTest(__file__).main() diff --git a/test/functional/wallet_coinbase_category.py b/test/functional/wallet_coinbase_category.py index c2cb0bf3b0..f09ed4913a 100755 --- a/test/functional/wallet_coinbase_category.py +++ b/test/functional/wallet_coinbase_category.py @@ -60,4 +60,4 @@ def run_test(self): self.assert_category("orphan", address, txid, 100) if __name__ == '__main__': - CoinbaseCategoryTest().main() + CoinbaseCategoryTest(__file__).main() diff --git a/test/functional/wallet_conflicts.py b/test/functional/wallet_conflicts.py index 25a95aa954..7a950ffae6 100755 --- a/test/functional/wallet_conflicts.py +++ b/test/functional/wallet_conflicts.py @@ -423,4 +423,4 @@ def test_descendants_with_mempool_conflicts(self): carol.unloadwallet() if __name__ == '__main__': - TxConflicts().main() + TxConflicts(__file__).main() diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py index 41ddb2bc69..6deb262c9a 100755 --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.py @@ -129,4 +129,4 @@ def test_version3(self): if __name__ == '__main__': - CreateTxWalletTest().main() + CreateTxWalletTest(__file__).main() diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index 8e07021e03..0232af1658 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -190,4 +190,4 @@ def run_test(self): if __name__ == '__main__': - CreateWalletTest().main() + CreateWalletTest(__file__).main() diff --git a/test/functional/wallet_createwalletdescriptor.py b/test/functional/wallet_createwalletdescriptor.py index 18e1703da3..e8cd914769 100755 --- a/test/functional/wallet_createwalletdescriptor.py +++ b/test/functional/wallet_createwalletdescriptor.py @@ -120,4 +120,4 @@ def test_encrypted(self): if __name__ == '__main__': - WalletCreateDescriptorTest().main() + WalletCreateDescriptorTest(__file__).main() diff --git a/test/functional/wallet_crosschain.py b/test/functional/wallet_crosschain.py index 4c5d7192ae..3505d33e51 100755 --- a/test/functional/wallet_crosschain.py +++ b/test/functional/wallet_crosschain.py @@ -62,4 +62,4 @@ def run_test(self): if __name__ == '__main__': - WalletCrossChain().main() + WalletCrossChain(__file__).main() diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index cbd3898f92..5e0ee97892 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -282,4 +282,4 @@ def run_test(self): if __name__ == '__main__': - WalletDescriptorTest().main () + WalletDescriptorTest(__file__).main() diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py index 9c73f7dead..da6e5d408f 100755 --- a/test/functional/wallet_disable.py +++ b/test/functional/wallet_disable.py @@ -28,4 +28,4 @@ def run_test (self): if __name__ == '__main__': - DisableWalletTest().main() + DisableWalletTest(__file__).main() diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index f50aae0c53..3a4f23a124 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -223,4 +223,4 @@ def run_test(self): w3.dumpwallet(self.nodes[0].datadir_path / "w3.dump") if __name__ == '__main__': - WalletDumpTest().main() + WalletDumpTest(__file__).main() diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index b30634010d..5a5fb3e5be 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -102,4 +102,4 @@ def run_test(self): if __name__ == '__main__': - WalletEncryptionTest().main() + WalletEncryptionTest(__file__).main() diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py index f0740b72fd..1849a602ab 100755 --- a/test/functional/wallet_fallbackfee.py +++ b/test/functional/wallet_fallbackfee.py @@ -32,4 +32,4 @@ def run_test(self): assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1})) if __name__ == '__main__': - WalletRBFTest().main() + WalletRBFTest(__file__).main() diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py index 1315bccafd..4ac441516e 100755 --- a/test/functional/wallet_fast_rescan.py +++ b/test/functional/wallet_fast_rescan.py @@ -99,4 +99,4 @@ def run_test(self): if __name__ == '__main__': - WalletFastRescanTest().main() + WalletFastRescanTest(__file__).main() diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index 07737c273d..827f27b431 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -1523,4 +1523,4 @@ def test_input_confs_control(self): wallet.unloadwallet() if __name__ == '__main__': - RawTransactionsTest().main() + RawTransactionsTest(__file__).main() diff --git a/test/functional/wallet_gethdkeys.py b/test/functional/wallet_gethdkeys.py index f09b8c875a..b6edc29fe6 100755 --- a/test/functional/wallet_gethdkeys.py +++ b/test/functional/wallet_gethdkeys.py @@ -182,4 +182,4 @@ def test_mixed_multisig(self): if __name__ == '__main__': - WalletGetHDKeyTest().main() + WalletGetHDKeyTest(__file__).main() diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index 26477131cf..8d6c96c0e0 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -182,4 +182,4 @@ def run_test(self): if __name__ == '__main__': - WalletGroupTest().main() + WalletGroupTest(__file__).main() diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 52161043ea..8f2a5fc78b 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -280,4 +280,4 @@ def run_test(self): if __name__ == '__main__': - WalletHDTest().main() + WalletHDTest(__file__).main() diff --git a/test/functional/wallet_implicitsegwit.py b/test/functional/wallet_implicitsegwit.py index baa9bafb00..e5787c0304 100755 --- a/test/functional/wallet_implicitsegwit.py +++ b/test/functional/wallet_implicitsegwit.py @@ -65,4 +65,4 @@ def run_test(self): check_implicit_transactions(implicit_keys, self.nodes[0]) if __name__ == '__main__': - ImplicitSegwitTest().main() + ImplicitSegwitTest(__file__).main() diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 2a9435b370..c5834c15d2 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -338,4 +338,4 @@ def run_test(self): if __name__ == "__main__": - ImportRescanTest().main() + ImportRescanTest(__file__).main() diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py index 0a1fc31ebc..9d01dfa5b7 100755 --- a/test/functional/wallet_import_with_label.py +++ b/test/functional/wallet_import_with_label.py @@ -125,4 +125,4 @@ def run_test(self): if __name__ == "__main__": - ImportWithLabel().main() + ImportWithLabel(__file__).main() diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py index f9d05a2fe4..6a69377c63 100755 --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -709,4 +709,4 @@ def run_test(self): assert_equal(temp_wallet.getbalance(), encrypted_wallet.getbalance()) if __name__ == '__main__': - ImportDescriptorsTest().main() + ImportDescriptorsTest(__file__).main() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 31013f6323..42b470bb97 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -898,4 +898,4 @@ def run_test(self): if __name__ == '__main__': - ImportMultiTest().main() + ImportMultiTest(__file__).main() diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py index b3ae22cc44..467fddeb59 100755 --- a/test/functional/wallet_importprunedfunds.py +++ b/test/functional/wallet_importprunedfunds.py @@ -143,4 +143,4 @@ def run_test(self): if __name__ == '__main__': - ImportPrunedFundsTest().main() + ImportPrunedFundsTest(__file__).main() diff --git a/test/functional/wallet_inactive_hdchains.py b/test/functional/wallet_inactive_hdchains.py index c6d22ab90b..3b0c09c02b 100755 --- a/test/functional/wallet_inactive_hdchains.py +++ b/test/functional/wallet_inactive_hdchains.py @@ -146,4 +146,4 @@ def run_test(self): if __name__ == '__main__': - InactiveHDChainsTest().main() + InactiveHDChainsTest(__file__).main() diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index 6ed8572347..d3b6ca1ed1 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -223,4 +223,4 @@ def run_test(self): assert_raises_rpc_error(-4, msg, w2.keypoolrefill, 100) if __name__ == '__main__': - KeyPoolTest().main() + KeyPoolTest(__file__).main() diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index e1bd85d8a9..25028d87bf 100755 --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -98,4 +98,4 @@ def run_test(self): if __name__ == '__main__': - KeypoolRestoreTest().main() + KeypoolRestoreTest(__file__).main() diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py index f074339a2b..307e10ae34 100755 --- a/test/functional/wallet_labels.py +++ b/test/functional/wallet_labels.py @@ -256,4 +256,4 @@ def change_label(node, address, old_label, new_label): new_label.verify(node) if __name__ == '__main__': - WalletLabelsTest().main() + WalletLabelsTest(__file__).main() diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py index 712b881322..c9d6c1f190 100755 --- a/test/functional/wallet_listdescriptors.py +++ b/test/functional/wallet_listdescriptors.py @@ -136,4 +136,4 @@ def run_test(self): if __name__ == '__main__': - ListDescriptorsTest().main() + ListDescriptorsTest(__file__).main() diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py index d0f1336a5e..522c7732fe 100755 --- a/test/functional/wallet_listreceivedby.py +++ b/test/functional/wallet_listreceivedby.py @@ -263,4 +263,4 @@ def run_test(self): if __name__ == '__main__': - ReceivedByTest().main() + ReceivedByTest(__file__).main() diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index 15214539a9..d777212f96 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -505,4 +505,4 @@ def test_label(self): if __name__ == '__main__': - ListSinceBlockTest().main() + ListSinceBlockTest(__file__).main() diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py index c820eaa6f6..a9f2066dd1 100755 --- a/test/functional/wallet_listtransactions.py +++ b/test/functional/wallet_listtransactions.py @@ -330,4 +330,4 @@ def test_op_return(self): if __name__ == '__main__': - ListTransactionsTest().main() + ListTransactionsTest(__file__).main() diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index 8fdc284d24..b4dc163e34 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -1032,4 +1032,4 @@ def run_test(self): self.test_blank() if __name__ == '__main__': - WalletMigrationTest().main() + WalletMigrationTest(__file__).main() diff --git a/test/functional/wallet_miniscript.py b/test/functional/wallet_miniscript.py index 67e1283902..064eac499b 100755 --- a/test/functional/wallet_miniscript.py +++ b/test/functional/wallet_miniscript.py @@ -401,4 +401,4 @@ def run_test(self): if __name__ == "__main__": - WalletMiniscriptTest().main() + WalletMiniscriptTest(__file__).main() diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py index 145912025f..2e0b0d1a41 100755 --- a/test/functional/wallet_multisig_descriptor_psbt.py +++ b/test/functional/wallet_multisig_descriptor_psbt.py @@ -154,4 +154,4 @@ def run_test(self): if __name__ == "__main__": - WalletMultisigDescriptorPSBTTest().main() + WalletMultisigDescriptorPSBTTest(__file__).main() diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index ee866ee59b..156f4279b4 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -423,4 +423,4 @@ def wallet_file(name): if __name__ == '__main__': - MultiWalletTest().main() + MultiWalletTest(__file__).main() diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py index 451f8abb0a..8a02781f26 100755 --- a/test/functional/wallet_orphanedreward.py +++ b/test/functional/wallet_orphanedreward.py @@ -73,4 +73,4 @@ def run_test(self): if __name__ == '__main__': - OrphanedBlockRewardTest().main() + OrphanedBlockRewardTest(__file__).main() diff --git a/test/functional/wallet_pruning.py b/test/functional/wallet_pruning.py index 6e252b5406..9c34a24be9 100755 --- a/test/functional/wallet_pruning.py +++ b/test/functional/wallet_pruning.py @@ -155,4 +155,4 @@ def run_test(self): self.test_wallet_import_pruned_with_missing_blocks(wallet_birthheight_1) if __name__ == '__main__': - WalletPruningTest().main() + WalletPruningTest(__file__).main() diff --git a/test/functional/wallet_reindex.py b/test/functional/wallet_reindex.py index 5388de4b71..6778f76efc 100755 --- a/test/functional/wallet_reindex.py +++ b/test/functional/wallet_reindex.py @@ -105,4 +105,4 @@ def run_test(self): if __name__ == '__main__': - WalletReindexTest().main() + WalletReindexTest(__file__).main() diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py index 4271f3e481..77cf34898b 100755 --- a/test/functional/wallet_reorgsrestore.py +++ b/test/functional/wallet_reorgsrestore.py @@ -101,4 +101,4 @@ def run_test(self): assert conflicting["blockhash"] != conflicted_after_reorg["blockhash"] if __name__ == '__main__': - ReorgsRestoreTest().main() + ReorgsRestoreTest(__file__).main() diff --git a/test/functional/wallet_rescan_unconfirmed.py b/test/functional/wallet_rescan_unconfirmed.py index ad9fa081c2..69ad522b5d 100755 --- a/test/functional/wallet_rescan_unconfirmed.py +++ b/test/functional/wallet_rescan_unconfirmed.py @@ -80,4 +80,4 @@ def run_test(self): assert_equal(w1.gettransaction(tx_child_unconfirmed_sweep["txid"])["confirmations"], 0) if __name__ == '__main__': - WalletRescanUnconfirmed().main() + WalletRescanUnconfirmed(__file__).main() diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index f61e1edc1d..49c8ef1c5f 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -149,4 +149,4 @@ def run_test(self): if __name__ == '__main__': - ResendWalletTransactionsTest().main() + ResendWalletTransactionsTest(__file__).main() diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index bbb0d658d9..2d0aad3b5d 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -612,4 +612,4 @@ def test_weight_limits(self): if __name__ == '__main__': - WalletSendTest().main() + WalletSendTest(__file__).main() diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py index 1d308c225d..b256b53b38 100755 --- a/test/functional/wallet_sendall.py +++ b/test/functional/wallet_sendall.py @@ -531,4 +531,4 @@ def run_test(self): self.sendall_fails_with_transaction_too_large() if __name__ == '__main__': - SendallTest().main() + SendallTest(__file__).main() diff --git a/test/functional/wallet_sendmany.py b/test/functional/wallet_sendmany.py index 5751993143..ad99100590 100755 --- a/test/functional/wallet_sendmany.py +++ b/test/functional/wallet_sendmany.py @@ -40,4 +40,4 @@ def run_test(self): if __name__ == '__main__': - SendmanyTest().main() + SendmanyTest(__file__).main() diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py index abfc3c1ba1..52b4c390b8 100755 --- a/test/functional/wallet_signer.py +++ b/test/functional/wallet_signer.py @@ -263,4 +263,4 @@ def test_multiple_signers(self): assert_raises_rpc_error(-1, "GetExternalSigner: More than one external signer found", self.nodes[1].createwallet, wallet_name='multi_hww', disable_private_keys=True, descriptors=True, external_signer=True) if __name__ == '__main__': - WalletSignerTest().main() + WalletSignerTest(__file__).main() diff --git a/test/functional/wallet_signmessagewithaddress.py b/test/functional/wallet_signmessagewithaddress.py index 4a4b818bd1..170c883ca4 100755 --- a/test/functional/wallet_signmessagewithaddress.py +++ b/test/functional/wallet_signmessagewithaddress.py @@ -45,4 +45,4 @@ def run_test(self): if __name__ == '__main__': - SignMessagesWithAddressTest().main() + SignMessagesWithAddressTest(__file__).main() diff --git a/test/functional/wallet_signrawtransactionwithwallet.py b/test/functional/wallet_signrawtransactionwithwallet.py index 612a2542e7..eb0e4097fe 100755 --- a/test/functional/wallet_signrawtransactionwithwallet.py +++ b/test/functional/wallet_signrawtransactionwithwallet.py @@ -310,4 +310,4 @@ def run_test(self): if __name__ == '__main__': - SignRawTransactionWithWalletTest().main() + SignRawTransactionWithWalletTest(__file__).main() diff --git a/test/functional/wallet_simulaterawtx.py b/test/functional/wallet_simulaterawtx.py index 545aad892c..11b7a4c76e 100755 --- a/test/functional/wallet_simulaterawtx.py +++ b/test/functional/wallet_simulaterawtx.py @@ -129,4 +129,4 @@ def run_test(self): assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w2.simulaterawtransaction, [tx1, tx2]) if __name__ == '__main__': - SimulateTxTest().main() + SimulateTxTest(__file__).main() diff --git a/test/functional/wallet_spend_unconfirmed.py b/test/functional/wallet_spend_unconfirmed.py index bfcdeaeaa8..4c73e0970b 100755 --- a/test/functional/wallet_spend_unconfirmed.py +++ b/test/functional/wallet_spend_unconfirmed.py @@ -505,4 +505,4 @@ def run_test(self): self.test_external_input_unconfirmed_low() if __name__ == '__main__': - UnconfirmedInputTest().main() + UnconfirmedInputTest(__file__).main() diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py index 2cc4e312af..6feb00af8e 100755 --- a/test/functional/wallet_startup.py +++ b/test/functional/wallet_startup.py @@ -58,4 +58,4 @@ def run_test(self): assert_equal(set(self.nodes[0].listwallets()), set(('w2', 'w3'))) if __name__ == '__main__': - WalletStartupTest().main() + WalletStartupTest(__file__).main() diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py index a5d7445ce8..a88d84f4c6 100755 --- a/test/functional/wallet_taproot.py +++ b/test/functional/wallet_taproot.py @@ -507,4 +507,4 @@ def run_test(self): ) if __name__ == '__main__': - WalletTaprootTest().main() + WalletTaprootTest(__file__).main() diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py index 0a622979a4..6c88438330 100755 --- a/test/functional/wallet_timelock.py +++ b/test/functional/wallet_timelock.py @@ -50,4 +50,4 @@ def run_test(self): if __name__ == "__main__": - WalletLocktimeTest().main() + WalletLocktimeTest(__file__).main() diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py index ea99992084..fb6dc74dc5 100755 --- a/test/functional/wallet_transactiontime_rescan.py +++ b/test/functional/wallet_transactiontime_rescan.py @@ -223,4 +223,4 @@ def run_test(self): assert_equal(encrypted_wallet.getbalance(), temp_wallet.getbalance()) if __name__ == '__main__': - TransactionTimeRescanTest().main() + TransactionTimeRescanTest(__file__).main() diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 1f3b6f2ce9..a2dd223aed 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -149,4 +149,4 @@ def run_test(self): if __name__ == '__main__': - TxnMallTest().main() + TxnMallTest(__file__).main() diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index 3cd0cd3207..3d6830f1f3 100755 --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -138,4 +138,4 @@ def run_test(self): if __name__ == '__main__': - TxnMallTest().main() + TxnMallTest(__file__).main() diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index a4f2a9b74d..7d1d244dff 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -360,4 +360,4 @@ def copy_split_hd(): self.test_upgradewallet(disabled_wallet, previous_version=169900, expected_version=169900) if __name__ == '__main__': - UpgradeWalletTest().main() + UpgradeWalletTest(__file__).main() diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py index b473f5d65c..298d50d452 100755 --- a/test/functional/wallet_watchonly.py +++ b/test/functional/wallet_watchonly.py @@ -111,4 +111,4 @@ def run_test(self): if __name__ == '__main__': - CreateWalletWatchonlyTest().main() + CreateWalletWatchonlyTest(__file__).main() From 9bf7ca6cad888d460f57d249264dc0062025bb3f Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 13 Jul 2024 12:31:19 +0100 Subject: [PATCH 16/91] qa: Consider `cache` and `config.ini` relative to invocation directory In CMake-based build system (1) `config.ini` is created in the build directory, and (2) `cache` must also be created in the same directory. This change enables running individual functional tests from the build directory. --- test/functional/test_framework/test_framework.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 3887cc8545..49212eb019 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -103,7 +103,7 @@ def __init__(self, test_file) -> None: self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond self.supports_cli = True self.bind_to_localhost_only = True - self.parse_args() + self.parse_args(test_file) self.default_wallet_name = "default_wallet" if self.options.descriptors else "" self.wallet_data_filename = "wallet.dat" # Optional list of wallet names that can be set in set_test_params to @@ -155,14 +155,14 @@ def main(self): exit_code = self.shutdown() sys.exit(exit_code) - def parse_args(self): + def parse_args(self, test_file): previous_releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases" parser = argparse.ArgumentParser(usage="%(prog)s [options]") parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") parser.add_argument("--noshutdown", dest="noshutdown", default=False, action="store_true", help="Don't stop bitcoinds after the test execution") - parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../cache"), + parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(test_file) + "/../cache"), help="Directory for caching pregenerated datadirs (default: %(default)s)") parser.add_argument("--tmpdir", dest="tmpdir", help="Root directory for datadirs (must not exist)") parser.add_argument("-l", "--loglevel", dest="loglevel", default="INFO", @@ -177,7 +177,7 @@ def parse_args(self): parser.add_argument("--coveragedir", dest="coveragedir", help="Write tested RPC commands into this directory") parser.add_argument("--configfile", dest="configfile", - default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../config.ini"), + default=os.path.abspath(os.path.dirname(test_file) + "/../config.ini"), help="Location of the test framework config file (default: %(default)s)") parser.add_argument("--pdbonfailure", dest="pdbonfailure", default=False, action="store_true", help="Attach a python debugger if test fails") From a8e3af1a82dd584a1cc3ffbe587e66889f72e3c7 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:58:40 +0100 Subject: [PATCH 17/91] qa: Do not assume running `feature_asmap.py` from source directory --- test/functional/feature_asmap.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/functional/feature_asmap.py b/test/functional/feature_asmap.py index cbff028bcc..53e94bf4df 100755 --- a/test/functional/feature_asmap.py +++ b/test/functional/feature_asmap.py @@ -30,7 +30,7 @@ from test_framework.util import assert_equal DEFAULT_ASMAP_FILENAME = 'ip_asn.map' # defined in src/init.cpp -ASMAP = '../../src/test/data/asmap.raw' # path to unit test skeleton asmap +ASMAP = 'src/test/data/asmap.raw' # path to unit test skeleton asmap VERSION = 'fec61fa21a9f46f3b17bdcd660d7f4cd90b966aad3aec593c99b35f0aca15853' def expected_messages(filename): @@ -133,7 +133,8 @@ def run_test(self): self.node = self.nodes[0] self.datadir = self.node.chain_path self.default_asmap = os.path.join(self.datadir, DEFAULT_ASMAP_FILENAME) - self.asmap_raw = os.path.join(os.path.dirname(os.path.realpath(__file__)), ASMAP) + base_dir = self.config["environment"]["SRCDIR"] + self.asmap_raw = os.path.join(base_dir, ASMAP) self.test_without_asmap_arg() self.test_asmap_with_absolute_path() From 6c9746ff9248e4f3c931a9bfd4dcc5f8bec7d412 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 10 Jul 2024 15:46:55 +0100 Subject: [PATCH 18/91] contrib: simplify MACHO test-security-check --- contrib/devtools/security-check.py | 12 ++++----- contrib/devtools/test-security-check.py | 34 ++++++++++--------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index f57e9abfec..bc79aad264 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -163,7 +163,7 @@ def check_MACHO_FIXUP_CHAINS(binary) -> bool: ''' return binary.has_dyld_chained_fixups -def check_MACHO_Canary(binary) -> bool: +def check_MACHO_CANARY(binary) -> bool: ''' Check for use of stack canary ''' @@ -182,7 +182,7 @@ def check_NX(binary) -> bool: ''' return binary.has_nx -def check_MACHO_control_flow(binary) -> bool: +def check_MACHO_CONTROL_FLOW(binary) -> bool: ''' Check for control flow instrumentation ''' @@ -192,7 +192,7 @@ def check_MACHO_control_flow(binary) -> bool: return True return False -def check_MACHO_branch_protection(binary) -> bool: +def check_MACHO_BRANCH_PROTECTION(binary) -> bool: ''' Check for branch protection instrumentation ''' @@ -222,7 +222,7 @@ def check_MACHO_branch_protection(binary) -> bool: BASE_MACHO = [ ('NOUNDEFS', check_MACHO_NOUNDEFS), - ('Canary', check_MACHO_Canary), + ('CANARY', check_MACHO_CANARY), ('FIXUP_CHAINS', check_MACHO_FIXUP_CHAINS), ] @@ -240,8 +240,8 @@ def check_MACHO_branch_protection(binary) -> bool: lief.EXE_FORMATS.MACHO: { lief.ARCHITECTURES.X86: BASE_MACHO + [('PIE', check_PIE), ('NX', check_NX), - ('CONTROL_FLOW', check_MACHO_control_flow)], - lief.ARCHITECTURES.ARM64: BASE_MACHO + [('BRANCH_PROTECTION', check_MACHO_branch_protection)], + ('CONTROL_FLOW', check_MACHO_CONTROL_FLOW)], + lief.ARCHITECTURES.ARM64: BASE_MACHO + [('BRANCH_PROTECTION', check_MACHO_BRANCH_PROTECTION)], } } diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index de372cbd39..5e49bee4f3 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -120,27 +120,21 @@ def test_MACHO(self): arch = get_arch(cxx, source, executable) if arch == lief.ARCHITECTURES.X86: - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-no_fixup_chains']), - (1, executable+': failed NOUNDEFS Canary FIXUP_CHAINS PIE CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-fixup_chains']), - (1, executable+': failed NOUNDEFS Canary CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all', '-Wl,-fixup_chains']), - (1, executable+': failed NOUNDEFS CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains']), - (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains']), - (0, '')) + pass_flags = ['-Wl,-pie', '-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_pie', '-Wl,-no_fixup_chains']), (1, executable+': failed FIXUP_CHAINS PIE')) # -fixup_chains is incompatible with -no_pie + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_fixup_chains']), (1, executable + ': failed FIXUP_CHAINS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-flat_namespace']), (1, executable + ': failed NOUNDEFS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) else: - # arm64 darwin doesn't support non-PIE binaries, control flow or executable stacks - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-no_fixup_chains']), - (1, executable+': failed NOUNDEFS Canary FIXUP_CHAINS BRANCH_PROTECTION')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-fixup_chains', '-mbranch-protection=bti']), - (1, executable+': failed NOUNDEFS Canary')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']), - (1, executable+': failed NOUNDEFS')) - self.assertEqual(call_security_check(cxx, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']), - (0, '')) - + # arm64 darwin doesn't support non-PIE binaries or executable stacks + pass_flags = ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-mbranch-protection=none']), (1, executable + ': failed BRANCH_PROTECTION')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_fixup_chains']), (1, executable + ': failed FIXUP_CHAINS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-flat_namespace']), (1, executable + ': failed NOUNDEFS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) clean_files(source, executable) From 1810e20677fff974827ec433a4614d6fdad462b0 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 10 Jul 2024 16:17:21 +0100 Subject: [PATCH 19/91] contrib: simplify PE test-security-check --- contrib/devtools/security-check.py | 8 ++++---- contrib/devtools/test-security-check.py | 24 ++++++++++-------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index bc79aad264..04c92654e8 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -130,7 +130,7 @@ def check_PE_RELOC_SECTION(binary) -> bool: '''Check for a reloc section. This is required for functional ASLR.''' return binary.has_relocations -def check_PE_control_flow(binary) -> bool: +def check_PE_CONTROL_FLOW(binary) -> bool: ''' Check for control flow instrumentation ''' @@ -145,7 +145,7 @@ def check_PE_control_flow(binary) -> bool: return True return False -def check_PE_Canary(binary) -> bool: +def check_PE_CANARY(binary) -> bool: ''' Check for use of stack canary ''' @@ -216,8 +216,8 @@ def check_MACHO_BRANCH_PROTECTION(binary) -> bool: ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('NX', check_NX), ('RELOC_SECTION', check_PE_RELOC_SECTION), - ('CONTROL_FLOW', check_PE_control_flow), - ('Canary', check_PE_Canary), + ('CONTROL_FLOW', check_PE_CONTROL_FLOW), + ('CANARY', check_PE_CANARY), ] BASE_MACHO = [ diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 5e49bee4f3..f63e79e998 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -95,20 +95,16 @@ def test_PE(self): cxx = determine_wellknown_cmd('CXX', 'x86_64-w64-mingw32-g++') write_testcode(source) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--disable-nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fno-stack-protector']), - (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW Canary')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']), - (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']), - (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']), - (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) # -pie -fPIE does nothing unless --dynamicbase is also supplied - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']), - (1, executable+': failed HIGH_ENTROPY_VA CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']), - (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full','-fstack-protector-all', '-lssp']), - (0, '')) + pass_flags = ['-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--dynamicbase', '-Wl,--high-entropy-va', '-pie', '-fPIE', '-fcf-protection=full', '-fstack-protector-all', '-lssp'] + + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY')) + # https://github.com/lief-project/LIEF/issues/1076 - in future, we could test this individually. + # self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-reloc-section']), (1, executable + ': failed RELOC_SECTION')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-nxcompat']), (1, executable + ': failed NX')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-dynamicbase']), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA')) # -pie -fPIE does nothing without --dynamicbase + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-high-entropy-va']), (1, executable + ': failed HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) clean_files(source, executable) From 51d8f435c9ce8af0460380e52026b6d65b1de398 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 10 Jul 2024 16:37:14 +0100 Subject: [PATCH 20/91] contrib: simplify ELF test-security-check --- contrib/devtools/security-check.py | 12 ++++---- contrib/devtools/test-security-check.py | 39 +++++++++---------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 04c92654e8..94810501be 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -38,13 +38,13 @@ def check_ELF_RELRO(binary) -> bool: return have_gnu_relro and have_bindnow -def check_ELF_Canary(binary) -> bool: +def check_ELF_CANARY(binary) -> bool: ''' Check for use of stack canary ''' return binary.has_symbol('__stack_chk_fail') -def check_ELF_separate_code(binary): +def check_ELF_SEPARATE_CODE(binary): ''' Check that sections are appropriately separated in virtual memory, based on their permissions. This checks for missing -Wl,-z,separate-code @@ -105,7 +105,7 @@ def check_ELF_separate_code(binary): return False return True -def check_ELF_control_flow(binary) -> bool: +def check_ELF_CONTROL_FLOW(binary) -> bool: ''' Check for control flow instrumentation ''' @@ -206,8 +206,8 @@ def check_MACHO_BRANCH_PROTECTION(binary) -> bool: ('PIE', check_PIE), ('NX', check_NX), ('RELRO', check_ELF_RELRO), - ('Canary', check_ELF_Canary), - ('separate_code', check_ELF_separate_code), + ('CANARY', check_ELF_CANARY), + ('SEPARATE_CODE', check_ELF_SEPARATE_CODE), ] BASE_PE = [ @@ -228,7 +228,7 @@ def check_MACHO_BRANCH_PROTECTION(binary) -> bool: CHECKS = { lief.EXE_FORMATS.ELF: { - lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_control_flow)], + lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_CONTROL_FLOW)], lief.ARCHITECTURES.ARM: BASE_ELF, lief.ARCHITECTURES.ARM64: BASE_ELF, lief.ARCHITECTURES.PPC: BASE_ELF, diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index f63e79e998..4bec6bfe7c 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -59,33 +59,20 @@ def test_ELF(self): arch = get_arch(cxx, source, executable) if arch == lief.ARCHITECTURES.X86: - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE NX RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), - (1, executable+': failed separate_code CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']), - (0, '')) + pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) else: - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE NX RELRO')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed RELRO')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), - (1, executable+': failed separate_code')) - self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), - (0, '')) + pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) clean_files(source, executable) From 41a2545046bce315af697a3c6baf6e3fb2e824c2 Mon Sep 17 00:00:00 2001 From: ismaelsadeeq Date: Wed, 12 Jun 2024 14:08:18 +0100 Subject: [PATCH 21/91] [fees]: change `estimatesmartfee` default mode to `economical` --- src/rpc/fees.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index aefe78162b..662d24ef81 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -36,7 +36,7 @@ static RPCHelpMan estimatesmartfee() "in BIP 141 (witness data is discounted).\n", { {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, - {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"conservative"}, "The fee estimate mode.\n" + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n" "Whether to return a more conservative estimate which also satisfies\n" "a longer history. A conservative estimate potentially returns a\n" "higher feerate and is more likely to be sufficient for the desired\n" @@ -71,13 +71,13 @@ static RPCHelpMan estimatesmartfee() CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue(); unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); - bool conservative = true; + bool conservative = false; if (!request.params[1].isNull()) { FeeEstimateMode fee_mode; if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) { throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); } - if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false; + if (fee_mode == FeeEstimateMode::CONSERVATIVE) conservative = true; } UniValue result(UniValue::VOBJ); From 1bc9f64bee919bc46eb061ef8c66f936eb6a8918 Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 20 Jun 2024 10:40:14 +0100 Subject: [PATCH 22/91] contrib: assume binary existence in sec/sym checks If the binaries don't exist, the Guix build has failed for some other reason. There's no need to check for unknown architectures, or executable formats, as the only ones that could be built are those that we've configured toolchains for in Guix. We've also been doing this inconsistently across the two scripts. --- contrib/devtools/security-check.py | 37 +++++++++--------------------- contrib/devtools/symbol-check.py | 26 ++++++++------------- 2 files changed, 20 insertions(+), 43 deletions(-) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 94810501be..46f9ee915f 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -248,31 +248,16 @@ def check_MACHO_BRANCH_PROTECTION(binary) -> bool: if __name__ == '__main__': retval: int = 0 for filename in sys.argv[1:]: - try: - binary = lief.parse(filename) - etype = binary.format - arch = binary.abstract.header.architecture - binary.concrete - - if etype == lief.EXE_FORMATS.UNKNOWN: - print(f'{filename}: unknown executable format') - retval = 1 - continue - - if arch == lief.ARCHITECTURES.NONE: - print(f'{filename}: unknown architecture') - retval = 1 - continue - - failed: list[str] = [] - for (name, func) in CHECKS[etype][arch]: - if not func(binary): - failed.append(name) - if failed: - print(f'{filename}: failed {" ".join(failed)}') - retval = 1 - except IOError: - print(f'{filename}: cannot open') + binary = lief.parse(filename) + etype = binary.format + arch = binary.abstract.header.architecture + binary.concrete + + failed: list[str] = [] + for (name, func) in CHECKS[etype][arch]: + if not func(binary): + failed.append(name) + if failed: + print(f'{filename}: failed {" ".join(failed)}') retval = 1 sys.exit(retval) - diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index c4e6bc81e1..cff5a9b480 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -299,22 +299,14 @@ def check_ELF_ABI(binary) -> bool: if __name__ == '__main__': retval: int = 0 for filename in sys.argv[1:]: - try: - binary = lief.parse(filename) - etype = binary.format - if etype == lief.EXE_FORMATS.UNKNOWN: - print(f'{filename}: unknown executable format') - retval = 1 - continue - - failed: list[str] = [] - for (name, func) in CHECKS[etype]: - if not func(binary): - failed.append(name) - if failed: - print(f'{filename}: failed {" ".join(failed)}') - retval = 1 - except IOError: - print(f'{filename}: cannot open') + binary = lief.parse(filename) + etype = binary.format + + failed: list[str] = [] + for (name, func) in CHECKS[etype]: + if not func(binary): + failed.append(name) + if failed: + print(f'{filename}: failed {" ".join(failed)}') retval = 1 sys.exit(retval) From c2f86d4bcba290c33ed99383cc76380bb15ba384 Mon Sep 17 00:00:00 2001 From: Fabian Jahr Date: Sat, 6 Jul 2024 18:09:37 +0200 Subject: [PATCH 23/91] test: Remove already resolved assumeutxo todo comments - "Valid snapshot file, but referencing a snapshot block that turns out to be invalid, or has an invalid parent" has been addressed in #30267 - "An ancestor of snapshot block" - If chain tip refers to blocks in this context then any successful load is addressing this because if we have synced past the snapshot base block we fail because we don't need assumeutxo anymore. And if this is about headers then this is the `test_headers_not_synced()` case. - "A descendant of the snapshot block" - If this refers to blocks the `test_snapshot_with_less_work()` addressed this and if it is just headers in this case again it would be represented in all of the successful loads in the test. Co-authored-by: Alfonso Roman Zubeldia --- test/functional/feature_assumeutxo.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index 17c1554cde..8ef92b9b6f 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -11,16 +11,9 @@ ## Possible test improvements -Interesting test cases could be loading an assumeutxo snapshot file with: - -- TODO: Valid snapshot file, but referencing a snapshot block that turns out to be - invalid, or has an invalid parent - Interesting starting states could be loading a snapshot when the current chain tip is: -- TODO: An ancestor of snapshot block - TODO: The snapshot block -- TODO: A descendant of the snapshot block """ from shutil import rmtree @@ -358,6 +351,8 @@ def run_test(self): self.test_snapshot_not_on_most_work_chain(dump_output['path']) self.log.info(f"Loading snapshot into second node from {dump_output['path']}") + # This node's tip is on an ancestor block of the snapshot, which should + # be the normal case loaded = n1.loadtxoutset(dump_output['path']) assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT) assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT) From d63ef738001fb69ce04134cc8645dcd1e1cbccd1 Mon Sep 17 00:00:00 2001 From: Fabian Jahr Date: Mon, 8 Jul 2024 12:12:33 +0100 Subject: [PATCH 24/91] test: Add loadtxoutset test with tip on snapshot block Also pulls out the guarding assert and calls it explicitly before the test function is called. This is already done before the existing call of the test function so it was not needed there. --- test/functional/feature_assumeutxo.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index 8ef92b9b6f..868017ab85 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -8,13 +8,6 @@ The assumeutxo value generated and used here is committed to in `CRegTestParams::m_assumeutxo_data` in `src/kernel/chainparams.cpp`. - -## Possible test improvements - -Interesting starting states could be loading a snapshot when the current chain tip is: - -- TODO: The snapshot block - """ from shutil import rmtree @@ -195,7 +188,6 @@ def test_invalid_file_path(self): def test_snapshot_with_less_work(self, dump_output_path): self.log.info("Test bitcoind should fail when snapshot has less accumulated work than this node.") node = self.nodes[0] - assert_equal(node.getblockcount(), FINAL_HEIGHT) with node.assert_debug_log(expected_msgs=["[snapshot] activation failed - work does not exceed active chainstate"]): assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", node.loadtxoutset, dump_output_path) @@ -309,6 +301,11 @@ def run_test(self): self.log.info(f"Creating a UTXO snapshot at height {SNAPSHOT_BASE_HEIGHT}") dump_output = n0.dumptxoutset('utxos.dat') + self.log.info("Test loading snapshot when the node tip is on the same block as the snapshot") + assert_equal(n0.getblockcount(), SNAPSHOT_BASE_HEIGHT) + assert_equal(n0.getblockchaininfo()["blocks"], SNAPSHOT_BASE_HEIGHT) + self.test_snapshot_with_less_work(dump_output['path']) + self.log.info("Test loading snapshot when headers are not synced") self.test_headers_not_synced(dump_output['path']) From 6cf9b344409efcc41a2b34f87100d25e1d2486af Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 3 Jul 2024 23:51:32 +1000 Subject: [PATCH 25/91] logging: Limit early logging buffer Log messages created prior to StartLogging() being called go into a buffer. Enforce a limit on the size of this buffer. --- src/logging.cpp | 31 +++++++++++++++++++++++++++++++ src/logging.h | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/src/logging.cpp b/src/logging.cpp index 53af7d5ca7..9dafa72054 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -71,6 +72,9 @@ bool BCLog::Logger::StartLogging() // dump buffered messages from before we opened the log m_buffering = false; + if (m_buffer_lines_discarded > 0) { + LogPrintStr_(strprintf("Early logging buffer overflowed, %d log lines discarded.\n", m_buffer_lines_discarded), __func__, __FILE__, __LINE__, BCLog::ALL, Level::Info); + } while (!m_msgs_before_open.empty()) { const std::string& s = m_msgs_before_open.front(); @@ -82,6 +86,7 @@ bool BCLog::Logger::StartLogging() m_msgs_before_open.pop_front(); } + m_cur_buffer_memusage = 0; if (m_print_to_console) fflush(stdout); return true; @@ -94,6 +99,11 @@ void BCLog::Logger::DisconnectTestLogger() if (m_fileout != nullptr) fclose(m_fileout); m_fileout = nullptr; m_print_callbacks.clear(); + m_max_buffer_memusage = DEFAULT_MAX_LOG_BUFFER; + m_cur_buffer_memusage = 0; + m_buffer_lines_discarded = 0; + m_msgs_before_open.clear(); + } void BCLog::Logger::DisableLogging() @@ -362,9 +372,19 @@ std::string BCLog::Logger::GetLogPrefix(BCLog::LogFlags category, BCLog::Level l return s; } +static size_t MemUsage(const std::string& str) +{ + return str.size() + memusage::MallocUsage(sizeof(memusage::list_node)); +} + void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) { StdLockGuard scoped_lock(m_cs); + return LogPrintStr_(str, logging_function, source_file, source_line, category, level); +} + +void BCLog::Logger::LogPrintStr_(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +{ std::string str_prefixed = LogEscapeMessage(str); if (m_started_new_line) { @@ -387,6 +407,17 @@ void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& loggi if (m_buffering) { // buffer if we haven't started logging yet m_msgs_before_open.push_back(str_prefixed); + + m_cur_buffer_memusage += MemUsage(str_prefixed); + while (m_cur_buffer_memusage > m_max_buffer_memusage) { + if (m_msgs_before_open.empty()) { + m_cur_buffer_memusage = 0; + break; + } + m_cur_buffer_memusage -= MemUsage(m_msgs_before_open.front()); + m_msgs_before_open.pop_front(); + ++m_buffer_lines_discarded; + } return; } diff --git a/src/logging.h b/src/logging.h index 70539f03b0..b3fe70cca7 100644 --- a/src/logging.h +++ b/src/logging.h @@ -79,6 +79,7 @@ namespace BCLog { Error, }; constexpr auto DEFAULT_LOG_LEVEL{Level::Debug}; + constexpr size_t DEFAULT_MAX_LOG_BUFFER{1'000'000}; // buffer up to 1MB of log data prior to StartLogging class Logger { @@ -88,6 +89,9 @@ namespace BCLog { FILE* m_fileout GUARDED_BY(m_cs) = nullptr; std::list m_msgs_before_open GUARDED_BY(m_cs); bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. + size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER}; + size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0}; + size_t m_buffer_lines_discarded GUARDED_BY(m_cs){0}; /** * m_started_new_line is a state variable that will suppress printing of @@ -111,6 +115,10 @@ namespace BCLog { /** Slots that connect to the print signal */ std::list> m_print_callbacks GUARDED_BY(m_cs) {}; + /** Send a string to the log output (internal) */ + void LogPrintStr_(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + EXCLUSIVE_LOCKS_REQUIRED(m_cs); + public: bool m_print_to_console = false; bool m_print_to_file = false; From 558df5c733d31456faf856d44f7037f41981d797 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Fri, 12 Jul 2024 10:19:55 +1000 Subject: [PATCH 26/91] logging: Apply formatting to early log messages The formatting of log messages isn't defined until StartLogging() is called; so can't be correctly applied to early log messages from prior to that call. Instead of saving the output log message, save the inputs to the logging invocation (including time, mocktime and thread name), and format those inputs into a log message when StartLogging() is called. --- src/logging.cpp | 107 +++++++++++++++++++++++++++++------------------- src/logging.h | 17 +++++++- 2 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/logging.cpp b/src/logging.cpp index 9dafa72054..4b3b58a0b7 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -76,15 +76,16 @@ bool BCLog::Logger::StartLogging() LogPrintStr_(strprintf("Early logging buffer overflowed, %d log lines discarded.\n", m_buffer_lines_discarded), __func__, __FILE__, __LINE__, BCLog::ALL, Level::Info); } while (!m_msgs_before_open.empty()) { - const std::string& s = m_msgs_before_open.front(); + const auto& buflog = m_msgs_before_open.front(); + std::string s{buflog.str}; + FormatLogStrInPlace(s, buflog.category, buflog.level, buflog.source_file, buflog.source_line, buflog.logging_function, buflog.threadname, buflog.now, buflog.mocktime); + m_msgs_before_open.pop_front(); if (m_print_to_file) FileWriteStr(s, m_fileout); if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout); for (const auto& cb : m_print_callbacks) { cb(s); } - - m_msgs_before_open.pop_front(); } m_cur_buffer_memusage = 0; if (m_print_to_console) fflush(stdout); @@ -298,28 +299,23 @@ std::string BCLog::Logger::LogLevelsString() const return Join(std::vector{levels.begin(), levels.end()}, ", ", [](BCLog::Level level) { return LogLevelToStr(level); }); } -std::string BCLog::Logger::LogTimestampStr(const std::string& str) +std::string BCLog::Logger::LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const { std::string strStamped; if (!m_log_timestamps) - return str; - - if (m_started_new_line) { - const auto now{SystemClock::now()}; - const auto now_seconds{std::chrono::time_point_cast(now)}; - strStamped = FormatISO8601DateTime(TicksSinceEpoch(now_seconds)); - if (m_log_time_micros && !strStamped.empty()) { - strStamped.pop_back(); - strStamped += strprintf(".%06dZ", Ticks(now - now_seconds)); - } - std::chrono::seconds mocktime = GetMockTime(); - if (mocktime > 0s) { - strStamped += " (mocktime: " + FormatISO8601DateTime(count_seconds(mocktime)) + ")"; - } - strStamped += ' ' + str; - } else - strStamped = str; + return strStamped; + + const auto now_seconds{std::chrono::time_point_cast(now)}; + strStamped = FormatISO8601DateTime(TicksSinceEpoch(now_seconds)); + if (m_log_time_micros && !strStamped.empty()) { + strStamped.pop_back(); + strStamped += strprintf(".%06dZ", Ticks(now - now_seconds)); + } + if (mocktime > 0s) { + strStamped += " (mocktime: " + FormatISO8601DateTime(count_seconds(mocktime)) + ")"; + } + strStamped += ' '; return strStamped; } @@ -372,9 +368,24 @@ std::string BCLog::Logger::GetLogPrefix(BCLog::LogFlags category, BCLog::Level l return s; } -static size_t MemUsage(const std::string& str) +static size_t MemUsage(const BCLog::Logger::BufferedLog& buflog) { - return str.size() + memusage::MallocUsage(sizeof(memusage::list_node)); + return buflog.str.size() + buflog.logging_function.size() + buflog.source_file.size() + buflog.threadname.size() + memusage::MallocUsage(sizeof(memusage::list_node)); +} + +void BCLog::Logger::FormatLogStrInPlace(std::string& str, BCLog::LogFlags category, BCLog::Level level, const std::string& source_file, int source_line, const std::string& logging_function, const std::string& threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const +{ + str.insert(0, GetLogPrefix(category, level)); + + if (m_log_sourcelocations) { + str.insert(0, "[" + RemovePrefix(source_file, "./") + ":" + ToString(source_line) + "] [" + logging_function + "] "); + } + + if (m_log_threadnames) { + str.insert(0, "[" + (threadname.empty() ? "unknown" : threadname) + "] "); + } + + str.insert(0, LogTimestampStr(now, mocktime)); } void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) @@ -387,28 +398,37 @@ void BCLog::Logger::LogPrintStr_(const std::string& str, const std::string& logg { std::string str_prefixed = LogEscapeMessage(str); - if (m_started_new_line) { - str_prefixed.insert(0, GetLogPrefix(category, level)); - } - - if (m_log_sourcelocations && m_started_new_line) { - str_prefixed.insert(0, "[" + RemovePrefix(source_file, "./") + ":" + ToString(source_line) + "] [" + logging_function + "] "); - } - - if (m_log_threadnames && m_started_new_line) { - const auto& threadname = util::ThreadGetInternalName(); - str_prefixed.insert(0, "[" + (threadname.empty() ? "unknown" : threadname) + "] "); - } - - str_prefixed = LogTimestampStr(str_prefixed); - + const bool starts_new_line = m_started_new_line; m_started_new_line = !str.empty() && str[str.size()-1] == '\n'; if (m_buffering) { - // buffer if we haven't started logging yet - m_msgs_before_open.push_back(str_prefixed); + if (!starts_new_line) { + if (!m_msgs_before_open.empty()) { + m_msgs_before_open.back().str += str_prefixed; + m_cur_buffer_memusage += str_prefixed.size(); + return; + } else { + // unlikely edge case; add a marker that something was trimmed + str_prefixed.insert(0, "[...] "); + } + } + + { + BufferedLog buf{ + .now=SystemClock::now(), + .mocktime=GetMockTime(), + .str=str_prefixed, + .logging_function=logging_function, + .source_file=source_file, + .threadname=util::ThreadGetInternalName(), + .source_line=source_line, + .category=category, + .level=level, + }; + m_cur_buffer_memusage += MemUsage(buf); + m_msgs_before_open.push_back(std::move(buf)); + } - m_cur_buffer_memusage += MemUsage(str_prefixed); while (m_cur_buffer_memusage > m_max_buffer_memusage) { if (m_msgs_before_open.empty()) { m_cur_buffer_memusage = 0; @@ -418,9 +438,14 @@ void BCLog::Logger::LogPrintStr_(const std::string& str, const std::string& logg m_msgs_before_open.pop_front(); ++m_buffer_lines_discarded; } + return; } + if (starts_new_line) { + FormatLogStrInPlace(str_prefixed, category, level, source_file, source_line, logging_function, util::ThreadGetInternalName(), SystemClock::now(), GetMockTime()); + } + if (m_print_to_console) { // print to console fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout); diff --git a/src/logging.h b/src/logging.h index b3fe70cca7..5c64c9e447 100644 --- a/src/logging.h +++ b/src/logging.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -83,11 +84,21 @@ namespace BCLog { class Logger { + public: + struct BufferedLog { + SystemClock::time_point now; + std::chrono::seconds mocktime; + std::string str, logging_function, source_file, threadname; + int source_line; + LogFlags category; + Level level; + }; + private: mutable StdMutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected FILE* m_fileout GUARDED_BY(m_cs) = nullptr; - std::list m_msgs_before_open GUARDED_BY(m_cs); + std::list m_msgs_before_open GUARDED_BY(m_cs); bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER}; size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0}; @@ -110,7 +121,9 @@ namespace BCLog { /** Log categories bitfield. */ std::atomic m_categories{0}; - std::string LogTimestampStr(const std::string& str); + void FormatLogStrInPlace(std::string& str, LogFlags category, Level level, const std::string& source_file, int source_line, const std::string& logging_function, const std::string& threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const; + + std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const; /** Slots that connect to the print signal */ std::list> m_print_callbacks GUARDED_BY(m_cs) {}; From b4dd7ab43e8cfc2c171f67588e4e1ec2705393c2 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Fri, 12 Jul 2024 12:40:05 +1000 Subject: [PATCH 27/91] logging: use std::string_view --- src/logging.cpp | 37 ++++++++++++++++++------------------- src/logging.h | 18 +++++++++--------- src/test/util_tests.cpp | 2 +- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/logging.cpp b/src/logging.cpp index 4b3b58a0b7..9c87cfd2b7 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -15,8 +15,7 @@ #include using util::Join; -using util::RemovePrefix; -using util::ToString; +using util::RemovePrefixView; const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL{BCLog::Level::Info}; @@ -44,7 +43,7 @@ BCLog::Logger& LogInstance() bool fLogIPs = DEFAULT_LOGIPS; -static int FileWriteStr(const std::string &str, FILE *fp) +static int FileWriteStr(std::string_view str, FILE *fp) { return fwrite(str.data(), 1, str.size(), fp); } @@ -124,7 +123,7 @@ void BCLog::Logger::EnableCategory(BCLog::LogFlags flag) m_categories |= flag; } -bool BCLog::Logger::EnableCategory(const std::string& str) +bool BCLog::Logger::EnableCategory(std::string_view str) { BCLog::LogFlags flag; if (!GetLogCategory(flag, str)) return false; @@ -137,7 +136,7 @@ void BCLog::Logger::DisableCategory(BCLog::LogFlags flag) m_categories &= ~flag; } -bool BCLog::Logger::DisableCategory(const std::string& str) +bool BCLog::Logger::DisableCategory(std::string_view str) { BCLog::LogFlags flag; if (!GetLogCategory(flag, str)) return false; @@ -168,7 +167,7 @@ bool BCLog::Logger::DefaultShrinkDebugFile() const return m_categories == BCLog::NONE; } -static const std::map LOG_CATEGORIES_BY_STR{ +static const std::map> LOG_CATEGORIES_BY_STR{ {"0", BCLog::NONE}, {"", BCLog::NONE}, {"net", BCLog::NET}, @@ -208,7 +207,7 @@ static const std::map LOG_CATEGORIES_BY_STR{ static const std::unordered_map LOG_CATEGORIES_BY_FLAG{ // Swap keys and values from LOG_CATEGORIES_BY_STR. - [](const std::map& in) { + [](const auto& in) { std::unordered_map out; for (const auto& [k, v] : in) { switch (v) { @@ -221,7 +220,7 @@ static const std::unordered_map LOG_CATEGORIES_BY_ }(LOG_CATEGORIES_BY_STR) }; -bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str) +bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str) { if (str.empty()) { flag = BCLog::ALL; @@ -259,7 +258,7 @@ std::string LogCategoryToStr(BCLog::LogFlags category) return it->second; } -static std::optional GetLogLevel(const std::string& level_str) +static std::optional GetLogLevel(std::string_view level_str) { if (level_str == "trace") { return BCLog::Level::Trace; @@ -328,7 +327,7 @@ namespace BCLog { * It escapes instead of removes them to still allow for troubleshooting * issues where they accidentally end up in strings. */ - std::string LogEscapeMessage(const std::string& str) { + std::string LogEscapeMessage(std::string_view str) { std::string ret; for (char ch_in : str) { uint8_t ch = (uint8_t)ch_in; @@ -373,28 +372,28 @@ static size_t MemUsage(const BCLog::Logger::BufferedLog& buflog) return buflog.str.size() + buflog.logging_function.size() + buflog.source_file.size() + buflog.threadname.size() + memusage::MallocUsage(sizeof(memusage::list_node)); } -void BCLog::Logger::FormatLogStrInPlace(std::string& str, BCLog::LogFlags category, BCLog::Level level, const std::string& source_file, int source_line, const std::string& logging_function, const std::string& threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const +void BCLog::Logger::FormatLogStrInPlace(std::string& str, BCLog::LogFlags category, BCLog::Level level, std::string_view source_file, int source_line, std::string_view logging_function, std::string_view threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const { str.insert(0, GetLogPrefix(category, level)); if (m_log_sourcelocations) { - str.insert(0, "[" + RemovePrefix(source_file, "./") + ":" + ToString(source_line) + "] [" + logging_function + "] "); + str.insert(0, strprintf("[%s:%d] [%s] ", RemovePrefixView(source_file, "./"), source_line, logging_function)); } if (m_log_threadnames) { - str.insert(0, "[" + (threadname.empty() ? "unknown" : threadname) + "] "); + str.insert(0, strprintf("[%s] ", (threadname.empty() ? "unknown" : threadname))); } str.insert(0, LogTimestampStr(now, mocktime)); } -void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +void BCLog::Logger::LogPrintStr(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) { StdLockGuard scoped_lock(m_cs); return LogPrintStr_(str, logging_function, source_file, source_line, category, level); } -void BCLog::Logger::LogPrintStr_(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +void BCLog::Logger::LogPrintStr_(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) { std::string str_prefixed = LogEscapeMessage(str); @@ -418,8 +417,8 @@ void BCLog::Logger::LogPrintStr_(const std::string& str, const std::string& logg .now=SystemClock::now(), .mocktime=GetMockTime(), .str=str_prefixed, - .logging_function=logging_function, - .source_file=source_file, + .logging_function=std::string(logging_function), + .source_file=std::string(source_file), .threadname=util::ThreadGetInternalName(), .source_line=source_line, .category=category, @@ -512,7 +511,7 @@ void BCLog::Logger::ShrinkDebugFile() fclose(file); } -bool BCLog::Logger::SetLogLevel(const std::string& level_str) +bool BCLog::Logger::SetLogLevel(std::string_view level_str) { const auto level = GetLogLevel(level_str); if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false; @@ -520,7 +519,7 @@ bool BCLog::Logger::SetLogLevel(const std::string& level_str) return true; } -bool BCLog::Logger::SetCategoryLogLevel(const std::string& category_str, const std::string& level_str) +bool BCLog::Logger::SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) { BCLog::LogFlags flag; if (!GetLogCategory(flag, category_str)) return false; diff --git a/src/logging.h b/src/logging.h index 5c64c9e447..91f919e822 100644 --- a/src/logging.h +++ b/src/logging.h @@ -121,7 +121,7 @@ namespace BCLog { /** Log categories bitfield. */ std::atomic m_categories{0}; - void FormatLogStrInPlace(std::string& str, LogFlags category, Level level, const std::string& source_file, int source_line, const std::string& logging_function, const std::string& threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const; + void FormatLogStrInPlace(std::string& str, LogFlags category, Level level, std::string_view source_file, int source_line, std::string_view logging_function, std::string_view threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const; std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const; @@ -129,7 +129,7 @@ namespace BCLog { std::list> m_print_callbacks GUARDED_BY(m_cs) {}; /** Send a string to the log output (internal) */ - void LogPrintStr_(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + void LogPrintStr_(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) EXCLUSIVE_LOCKS_REQUIRED(m_cs); public: @@ -148,7 +148,7 @@ namespace BCLog { std::string GetLogPrefix(LogFlags category, Level level) const; /** Send a string to the log output */ - void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + void LogPrintStr(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Returns whether logs will be written to any output */ @@ -198,18 +198,18 @@ namespace BCLog { StdLockGuard scoped_lock(m_cs); m_category_log_levels = levels; } - bool SetCategoryLogLevel(const std::string& category_str, const std::string& level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); + bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); Level LogLevel() const { return m_log_level.load(); } void SetLogLevel(Level level) { m_log_level = level; } - bool SetLogLevel(const std::string& level); + bool SetLogLevel(std::string_view level); uint32_t GetCategoryMask() const { return m_categories.load(); } void EnableCategory(LogFlags flag); - bool EnableCategory(const std::string& str); + bool EnableCategory(std::string_view str); void DisableCategory(LogFlags flag); - bool DisableCategory(const std::string& str); + bool DisableCategory(std::string_view str); bool WillLogCategory(LogFlags category) const; bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs); @@ -242,14 +242,14 @@ static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level leve } /** Return true if str parses as a log category and set the flag */ -bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str); +bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str); // Be conservative when using functions that // unconditionally log to debug.log! It should not be the case that an inbound // peer can fill up a user's disk with debug.log entries. template -static inline void LogPrintf_(const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, const char* fmt, const Args&... args) +static inline void LogPrintf_(std::string_view logging_function, std::string_view source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, const char* fmt, const Args&... args) { if (LogInstance().Enabled()) { std::string log_msg; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index a371753adf..4113b22be8 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -58,7 +58,7 @@ static const std::string STRING_WITH_EMBEDDED_NULL_CHAR{"1"s "\0" "1"s}; /* defined in logging.cpp */ namespace BCLog { - std::string LogEscapeMessage(const std::string& str); + std::string LogEscapeMessage(std::string_view str); } BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) From 0c8605253ae887dac316264cb969b752027d277a Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 15 Jul 2024 16:32:27 +0100 Subject: [PATCH 28/91] depends: add zeromq mktemp macos patch --- depends/packages/zeromq.mk | 6 ++++-- depends/patches/zeromq/macos_mktemp_check.patch | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 depends/patches/zeromq/macos_mktemp_check.patch diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index bfa5e97c60..d3bd3da6c7 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -3,7 +3,8 @@ $(package)_version=4.3.5 $(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43 -$(package)_patches=remove_libstd_link.patch +$(package)_patches = remove_libstd_link.patch +$(package)_patches += macos_mktemp_check.patch define $(package)_set_vars $(package)_config_opts = --without-docs --disable-shared --disable-valgrind @@ -14,7 +15,8 @@ define $(package)_set_vars endef define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch + patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \ + patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch endef define $(package)_config_cmds diff --git a/depends/patches/zeromq/macos_mktemp_check.patch b/depends/patches/zeromq/macos_mktemp_check.patch new file mode 100644 index 0000000000..c703abcd71 --- /dev/null +++ b/depends/patches/zeromq/macos_mktemp_check.patch @@ -0,0 +1,16 @@ +build: fix mkdtemp check on macOS + +On macOS, mkdtemp is in unistd.h. Fix the CMake check so that is works. +Upstreamed in https://github.com/zeromq/libzmq/pull/4668. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -599,7 +599,7 @@ if(NOT MSVC) + + check_cxx_symbol_exists(fork unistd.h HAVE_FORK) + check_cxx_symbol_exists(gethrtime sys/time.h HAVE_GETHRTIME) +- check_cxx_symbol_exists(mkdtemp stdlib.h HAVE_MKDTEMP) ++ check_cxx_symbol_exists(mkdtemp "stdlib.h;unistd.h" HAVE_MKDTEMP) + check_cxx_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4) + check_cxx_symbol_exists(strnlen string.h HAVE_STRNLEN) + else() From 2de68d6d388b9a33c57234d3161f6ffc4c2a0246 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 15 Jul 2024 16:34:44 +0100 Subject: [PATCH 29/91] depends: add zeromq builtin sha1 patch --- depends/packages/zeromq.mk | 4 +++- depends/patches/zeromq/builtin_sha1.patch | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 depends/patches/zeromq/builtin_sha1.patch diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index d3bd3da6c7..d71351e62c 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -5,6 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43 $(package)_patches = remove_libstd_link.patch $(package)_patches += macos_mktemp_check.patch +$(package)_patches += builtin_sha1.patch define $(package)_set_vars $(package)_config_opts = --without-docs --disable-shared --disable-valgrind @@ -16,7 +17,8 @@ endef define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \ - patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch + patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch && \ + patch -p1 < $($(package)_patch_dir)/builtin_sha1.patch endef define $(package)_config_cmds diff --git a/depends/patches/zeromq/builtin_sha1.patch b/depends/patches/zeromq/builtin_sha1.patch new file mode 100644 index 0000000000..5481c9dbdd --- /dev/null +++ b/depends/patches/zeromq/builtin_sha1.patch @@ -0,0 +1,17 @@ +Don't use builtin sha1 if not using ws + +The builtin SHA1 (ZMQ_USE_BUILTIN_SHA1) is only used in the websocket +engine (ws_engine.cpp). +Upstreamed in https://github.com/zeromq/libzmq/pull/4670. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -234,7 +234,7 @@ if(NOT ZMQ_USE_GNUTLS) + endif() + endif() + endif() +- if(NOT ZMQ_USE_NSS) ++ if(ENABLE_WS AND NOT ZMQ_USE_NSS) + list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/external/sha1/sha1.c + ${CMAKE_CURRENT_SOURCE_DIR}/external/sha1/sha1.h) + message(STATUS "Using builtin sha1") From cbbc229adf4c12ad4bd7edde71425b8ef217edfc Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 15 Jul 2024 16:36:42 +0100 Subject: [PATCH 30/91] depends: add zeromq windows usage patch --- depends/packages/zeromq.mk | 4 +- depends/patches/zeromq/fix_have_windows.patch | 54 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 depends/patches/zeromq/fix_have_windows.patch diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index d71351e62c..0f8ede8699 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -6,6 +6,7 @@ $(package)_sha256_hash=6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a91 $(package)_patches = remove_libstd_link.patch $(package)_patches += macos_mktemp_check.patch $(package)_patches += builtin_sha1.patch +$(package)_patches += fix_have_windows.patch define $(package)_set_vars $(package)_config_opts = --without-docs --disable-shared --disable-valgrind @@ -18,7 +19,8 @@ endef define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \ patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch && \ - patch -p1 < $($(package)_patch_dir)/builtin_sha1.patch + patch -p1 < $($(package)_patch_dir)/builtin_sha1.patch && \ + patch -p1 < $($(package)_patch_dir)/fix_have_windows.patch endef define $(package)_config_cmds diff --git a/depends/patches/zeromq/fix_have_windows.patch b/depends/patches/zeromq/fix_have_windows.patch new file mode 100644 index 0000000000..e77ef31adf --- /dev/null +++ b/depends/patches/zeromq/fix_have_windows.patch @@ -0,0 +1,54 @@ +This fixes several instances where _MSC_VER was +used to determine whether to use afunix.h or not. + +See https://github.com/zeromq/libzmq/pull/4678. +--- a/src/ipc_address.hpp ++++ b/src/ipc_address.hpp +@@ -7,7 +7,7 @@ + + #include + +-#if defined _MSC_VER ++#if defined ZMQ_HAVE_WINDOWS + #include + #else + #include +diff --git a/src/ipc_connecter.cpp b/src/ipc_connecter.cpp +index 3f988745..ed2a0645 100644 +--- a/src/ipc_connecter.cpp ++++ b/src/ipc_connecter.cpp +@@ -16,7 +16,7 @@ + #include "ipc_address.hpp" + #include "session_base.hpp" + +-#ifdef _MSC_VER ++#if defined ZMQ_HAVE_WINDOWS + #include + #else + #include +diff --git a/src/ipc_listener.cpp b/src/ipc_listener.cpp +index 50126040..5428579b 100644 +--- a/src/ipc_listener.cpp ++++ b/src/ipc_listener.cpp +@@ -17,7 +17,7 @@ + #include "socket_base.hpp" + #include "address.hpp" + +-#ifdef _MSC_VER ++#ifdef ZMQ_HAVE_WINDOWS + #ifdef ZMQ_IOTHREAD_POLLER_USE_SELECT + #error On Windows, IPC does not work with POLLER=select, use POLLER=epoll instead, or disable IPC transport + #endif +diff --git a/tests/testutil.cpp b/tests/testutil.cpp +index bdc80283..6f21e8f6 100644 +--- a/tests/testutil.cpp ++++ b/tests/testutil.cpp +@@ -7,7 +7,7 @@ + + #if defined _WIN32 + #include "../src/windows.hpp" +-#if defined _MSC_VER ++#if defined ZMQ_HAVE_WINDOWS + #if defined ZMQ_HAVE_IPC + #include + #include From a522ef15424110f76172b3c0603fa08f7291c9fc Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 15 Jul 2024 16:38:15 +0100 Subject: [PATCH 31/91] depends: add zeromq cmake minimum patch --- depends/packages/zeromq.mk | 4 +++- depends/patches/zeromq/cmake_minimum.patch | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 depends/patches/zeromq/cmake_minimum.patch diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 0f8ede8699..ef2ff0b6d7 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -7,6 +7,7 @@ $(package)_patches = remove_libstd_link.patch $(package)_patches += macos_mktemp_check.patch $(package)_patches += builtin_sha1.patch $(package)_patches += fix_have_windows.patch +$(package)_patches += cmake_minimum.patch define $(package)_set_vars $(package)_config_opts = --without-docs --disable-shared --disable-valgrind @@ -20,7 +21,8 @@ define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \ patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch && \ patch -p1 < $($(package)_patch_dir)/builtin_sha1.patch && \ - patch -p1 < $($(package)_patch_dir)/fix_have_windows.patch + patch -p1 < $($(package)_patch_dir)/fix_have_windows.patch && \ + patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch endef define $(package)_config_cmds diff --git a/depends/patches/zeromq/cmake_minimum.patch b/depends/patches/zeromq/cmake_minimum.patch new file mode 100644 index 0000000000..d6b6b5fae7 --- /dev/null +++ b/depends/patches/zeromq/cmake_minimum.patch @@ -0,0 +1,18 @@ +Set a more sane cmake_minimum_required. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,12 +1,7 @@ + # CMake build script for ZeroMQ ++cmake_minimum_required(VERSION 3.16) + project(ZeroMQ) + +-if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) +- cmake_minimum_required(VERSION 3.0.2) +-else() +- cmake_minimum_required(VERSION 2.8.12) +-endif() +- + include(CheckIncludeFiles) + include(CheckCCompilerFlag) + include(CheckCXXCompilerFlag) From fefb3bbe5b538f8faa59de191914ad0c22c3ade6 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 15 Jul 2024 16:43:18 +0100 Subject: [PATCH 32/91] depends: add zeromq no librt patch --- depends/packages/zeromq.mk | 4 +- depends/patches/zeromq/no_librt.patch | 54 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 depends/patches/zeromq/no_librt.patch diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index ef2ff0b6d7..534f4ced34 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -8,6 +8,7 @@ $(package)_patches += macos_mktemp_check.patch $(package)_patches += builtin_sha1.patch $(package)_patches += fix_have_windows.patch $(package)_patches += cmake_minimum.patch +$(package)_patches += no_librt.patch define $(package)_set_vars $(package)_config_opts = --without-docs --disable-shared --disable-valgrind @@ -22,7 +23,8 @@ define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch && \ patch -p1 < $($(package)_patch_dir)/builtin_sha1.patch && \ patch -p1 < $($(package)_patch_dir)/fix_have_windows.patch && \ - patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch + patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch && \ + patch -p1 < $($(package)_patch_dir)/no_librt.patch endef define $(package)_config_cmds diff --git a/depends/patches/zeromq/no_librt.patch b/depends/patches/zeromq/no_librt.patch new file mode 100644 index 0000000000..b63854c95b --- /dev/null +++ b/depends/patches/zeromq/no_librt.patch @@ -0,0 +1,54 @@ +We don't use librt, so don't try and link against it. + +Related to: https://github.com/zeromq/libzmq/pull/4702. + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 03462271..87ceab3c 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -564,13 +564,6 @@ else() + check_cxx_symbol_exists(SO_BUSY_POLL sys/socket.h ZMQ_HAVE_BUSY_POLL) + endif() + +-if(NOT MINGW) +- find_library(RT_LIBRARY rt) +- if(RT_LIBRARY) +- set(pkg_config_libs_private "${pkg_config_libs_private} -lrt") +- endif() +-endif() +- + find_package(Threads) + + if(WIN32 AND NOT CYGWIN) +@@ -588,9 +581,7 @@ if(WIN32 AND NOT CYGWIN) + endif() + + if(NOT MSVC) +- set(CMAKE_REQUIRED_LIBRARIES rt) + check_cxx_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME) +- set(CMAKE_REQUIRED_LIBRARIES) + + check_cxx_symbol_exists(fork unistd.h HAVE_FORK) + check_cxx_symbol_exists(gethrtime sys/time.h HAVE_GETHRTIME) +@@ -1503,10 +1494,6 @@ if(BUILD_SHARED) + target_link_libraries(libzmq iphlpapi) + endif() + +- if(RT_LIBRARY) +- target_link_libraries(libzmq -lrt) +- endif() +- + if(norm_FOUND) + target_link_libraries(libzmq norm::norm) + endif() +@@ -1553,10 +1540,6 @@ if(BUILD_STATIC) + target_link_libraries(libzmq-static iphlpapi) + endif() + +- if(RT_LIBRARY) +- target_link_libraries(libzmq-static -lrt) +- endif() +- + if(CMAKE_SYSTEM_NAME MATCHES "QNX") + add_definitions(-DUNITY_EXCLUDE_MATH_H) + endif() From 9e2a723d5da4fc277a42fed37424f578e348ebf8 Mon Sep 17 00:00:00 2001 From: TheCharlatan Date: Thu, 4 Jul 2024 21:43:16 +0200 Subject: [PATCH 33/91] test: Add arguments for creating a slimmer setup Adds more testing options for creating an environment without networking and a validation interface. This is useful for improving the performance of the utxo snapshot fuzz test, which constructs a new TestingSetup on each iteration. --- src/test/fuzz/utxo_snapshot.cpp | 8 +++++++- src/test/util/setup_common.cpp | 12 ++++++++---- src/test/util/setup_common.h | 2 ++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 522c9c54ee..60d9d39b73 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -31,7 +31,13 @@ void initialize_chain() FUZZ_TARGET(utxo_snapshot, .init = initialize_chain) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - std::unique_ptr setup{MakeNoLogFileContext()}; + std::unique_ptr setup{ + MakeNoLogFileContext( + ChainType::REGTEST, + TestOpts{ + .setup_net = false, + .setup_validation_interface = false, + })}; const auto& node = setup->m_node; auto& chainman{*node.chainman}; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 60f9261e7e..b4dd07f257 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -218,9 +218,11 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts) // We have to run a scheduler thread to prevent ActivateBestChain // from blocking due to queue overrun. - m_node.scheduler = std::make_unique(); - m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); }); - m_node.validation_signals = std::make_unique(std::make_unique(*m_node.scheduler)); + if (opts.setup_validation_interface) { + m_node.scheduler = std::make_unique(); + m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); }); + m_node.validation_signals = std::make_unique(std::make_unique(*m_node.scheduler)); + } m_node.fee_estimator = std::make_unique(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES); bilingual_str error{}; @@ -255,7 +257,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts) ChainTestingSetup::~ChainTestingSetup() { if (m_node.scheduler) m_node.scheduler->stop(); - m_node.validation_signals->FlushBackgroundCallbacks(); + if (m_node.validation_signals) m_node.validation_signals->FlushBackgroundCallbacks(); m_node.connman.reset(); m_node.banman.reset(); m_node.addrman.reset(); @@ -306,6 +308,8 @@ TestingSetup::TestingSetup( LoadVerifyActivateChainstate(); + if (!opts.setup_net) return; + m_node.netgroupman = std::make_unique(/*asmap=*/std::vector()); m_node.addrman = std::make_unique(*m_node.netgroupman, /*deterministic=*/false, diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index e8b630af94..220bf6e422 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -52,6 +52,8 @@ struct TestOpts { std::vector extra_args{}; bool coins_db_in_memory{true}; bool block_tree_db_in_memory{true}; + bool setup_net{true}; + bool setup_validation_interface{true}; }; /** Basic testing setup. From f46b2202560a76b473e229b77303b8f877c16cac Mon Sep 17 00:00:00 2001 From: TheCharlatan Date: Fri, 5 Jul 2024 15:33:45 +0200 Subject: [PATCH 34/91] fuzz: Use BasicTestingSetup for coins_view target --- src/test/fuzz/coins_view.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 8f3e357a84..41c971c237 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -27,7 +27,6 @@ #include namespace { -const TestingSetup* g_setup; const Coin EMPTY_COIN{}; bool operator==(const Coin& a, const Coin& b) @@ -39,8 +38,7 @@ bool operator==(const Coin& a, const Coin& b) void initialize_coins_view() { - static const auto testing_setup = MakeNoLogFileContext(); - g_setup = testing_setup.get(); + static const auto testing_setup = MakeNoLogFileContext<>(); } FUZZ_TARGET(coins_view, .init = initialize_coins_view) From 0388ad0d65b6c9ee802ca641eb01d69fcdd5605d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 19 Apr 2023 15:44:46 -0400 Subject: [PATCH 35/91] depends: switch zmq to CMake The CMake WIN32_WINNT autodetection is broken, and must be set manually. We may want to set is explicitly in any case, but the brokenness should also be fixed upstream. Also patch out depends paths, that would cause non-determinism. Co-authored-by: fanquake --- depends/packages/zeromq.mk | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 534f4ced34..23bd58bf53 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -3,6 +3,7 @@ $(package)_version=4.3.5 $(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43 +$(package)_build_subdir=build $(package)_patches = remove_libstd_link.patch $(package)_patches += macos_mktemp_check.patch $(package)_patches += builtin_sha1.patch @@ -11,11 +12,12 @@ $(package)_patches += cmake_minimum.patch $(package)_patches += no_librt.patch define $(package)_set_vars - $(package)_config_opts = --without-docs --disable-shared --disable-valgrind - $(package)_config_opts += --disable-perf --disable-curve-keygen --disable-curve --disable-libbsd - $(package)_config_opts += --without-libsodium --without-libgssapi_krb5 --without-pgm --without-norm --without-vmci - $(package)_config_opts += --disable-libunwind --disable-radix-tree --without-gcov --disable-dependency-tracking - $(package)_config_opts += --disable-Werror --disable-drafts --enable-option-checking + $(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DWITH_DOCS=OFF -DWITH_LIBSODIUM=OFF + $(package)_config_opts += -DWITH_LIBBSD=OFF -DENABLE_CURVE=OFF -DENABLE_CPACK=OFF + $(package)_config_opts += -DBUILD_SHARED=OFF -DBUILD_TESTS=OFF -DZMQ_BUILD_TESTS=OFF + $(package)_config_opts += -DENABLE_DRAFTS=OFF -DZMQ_BUILD_TESTS=OFF + $(package)_cxxflags += -ffile-prefix-map=$($(package)_extract_dir)=/usr + $(package)_config_opts_mingw32 += -DZMQ_WIN32_WINNT=0x0601 -DZMQ_HAVE_IPC=OFF endef define $(package)_preprocess_cmds @@ -28,17 +30,15 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds - ./autogen.sh && \ - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config && \ - $($(package)_autoconf) + $($(package)_cmake) -S .. -B . endef define $(package)_build_cmds - $(MAKE) src/libzmq.la + $(MAKE) endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-includeHEADERS install-pkgconfigDATA + $(MAKE) DESTDIR=$($(package)_staging_dir) install endef define $(package)_postprocess_cmds From fa80b16b20dffcb85b80f75fee64ed333f2062f9 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Wed, 17 Jul 2024 16:21:23 +0200 Subject: [PATCH 36/91] fuzz: Limit parse_univalue input length --- src/test/fuzz/parse_univalue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index a3d6ab6375..cb39b3be83 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2022 The Bitcoin Core developers +// Copyright (c) 2009-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -77,7 +77,7 @@ FUZZ_TARGET(parse_univalue, .init = initialize_parse_univalue) } try { FlatSigningProvider provider; - (void)EvalDescriptorStringOrObject(univalue, provider); + if (buffer.size() < 10'000) (void)EvalDescriptorStringOrObject(univalue, provider); } catch (const UniValue&) { } catch (const std::runtime_error&) { } From fae0db0360466aed536f4ce96d357cf579100080 Mon Sep 17 00:00:00 2001 From: TheCharlatan Date: Sat, 13 Jul 2024 11:02:42 +0200 Subject: [PATCH 37/91] fuzz: Deglobalize signature cache in sigcache test The body of the fuzz test should ideally be a pure function. If data is persisted in the cache over many iterations, and there is a crash, reproducing it from the input might be difficult. --- src/test/fuzz/script_sigcache.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp index 3248ebc4af..7f73c3706c 100644 --- a/src/test/fuzz/script_sigcache.cpp +++ b/src/test/fuzz/script_sigcache.cpp @@ -2,44 +2,41 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include +#include +#include #include +#include