From cd7872ca543d31d20f419fd2203138b8301c2e68 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Sun, 27 Apr 2025 20:41:59 +0000 Subject: [PATCH 1/5] Remove arbitrary limits on OP_Return (datacarrier) outputs Also removes the code to enforce those limits, including the `-datacarrier` and `-datacarriersize` config options. These limits are easily bypassed by both direct submission to miner mempools (e.g. MARA Slipstream), and forks of Bitcoin Core that do not enforce them (e.g. Libre Relay). Secondly, protocols are bypassing them by simply publishing data in other ways, such as unspendable outputs and scriptsigs. The *form* of datacarrier outputs remains standardized: a single OP_Return followed by zero or more data pushes; non-data opcodes remain non-standard. --- src/init.cpp | 6 -- src/kernel/mempool_options.h | 8 -- src/node/mempool_args.cpp | 6 -- src/policy/policy.cpp | 21 +---- src/policy/policy.h | 11 +-- src/test/fuzz/key.cpp | 4 +- src/test/fuzz/script.cpp | 2 +- src/test/fuzz/transaction.cpp | 4 +- src/test/multisig_tests.cpp | 2 +- src/test/script_p2sh_tests.cpp | 6 +- src/test/transaction_tests.cpp | 23 ++--- src/validation.cpp | 2 +- test/functional/feature_blocksxor.py | 1 - test/functional/feature_maxuploadtarget.py | 1 - test/functional/mempool_accept.py | 7 -- test/functional/mempool_datacarrier.py | 91 ------------------- test/functional/mempool_limit.py | 1 - test/functional/mempool_package_limits.py | 3 +- test/functional/mempool_package_rbf.py | 1 - test/functional/mempool_sigoplimit.py | 6 +- test/functional/mempool_truc.py | 14 +-- test/functional/mining_basic.py | 10 +- .../mining_prioritisetransaction.py | 1 - test/functional/p2p_1p1c_network.py | 1 - test/functional/p2p_opportunistic_1p1c.py | 1 - test/functional/p2p_tx_download.py | 2 +- test/functional/rpc_packages.py | 3 +- test/functional/test_framework/messages.py | 3 - test/functional/test_runner.py | 1 - 29 files changed, 42 insertions(+), 200 deletions(-) delete mode 100755 test/functional/mempool_datacarrier.py diff --git a/src/init.cpp b/src/init.cpp index a151c9d0a9e..bba781c95e3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -635,12 +635,6 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) argsman.AddArg("-dustrelayfee=", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-datacarriersize", - strprintf("Relay and mine transactions whose data-carrying raw scriptPubKey " - "is of this size or less (default: %u)", - MAX_OP_RETURN_RELAY), - ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index d57dbb393f3..4cb5df3a983 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -43,14 +43,6 @@ struct MemPoolOptions { /** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */ CFeeRate min_relay_feerate{DEFAULT_MIN_RELAY_TX_FEE}; CFeeRate dust_relay_feerate{DUST_RELAY_TX_FEE}; - /** - * A data carrying output is an unspendable output containing data. The script - * type is designated as TxoutType::NULL_DATA. - * - * Maximum size of TxoutType::NULL_DATA scripts that this node considers standard. - * If nullopt, any size is nonstandard. - */ - std::optional max_datacarrier_bytes{DEFAULT_ACCEPT_DATACARRIER ? std::optional{MAX_OP_RETURN_RELAY} : std::nullopt}; bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG}; bool require_standard{true}; bool persist_v1_dat{DEFAULT_PERSIST_V1_DAT}; diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index 6dbba783815..0f181231534 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -81,12 +81,6 @@ util::Result ApplyArgsManOptions(const ArgsManager& argsman, const CChainP mempool_opts.permit_bare_multisig = argsman.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); - if (argsman.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER)) { - mempool_opts.max_datacarrier_bytes = argsman.GetIntArg("-datacarriersize", MAX_OP_RETURN_RELAY); - } else { - mempool_opts.max_datacarrier_bytes = std::nullopt; - } - mempool_opts.require_standard = !argsman.GetBoolArg("-acceptnonstdtxn", DEFAULT_ACCEPT_NON_STD_TXN); if (!chainparams.IsTestChain() && !mempool_opts.require_standard) { return util::Error{Untranslated(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.GetChainTypeString()))}; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 32a31ea653c..22056c45b64 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -76,7 +76,7 @@ std::vector GetDust(const CTransaction& tx, CFeeRate dust_relay_rate) return dust_outputs; } -bool IsStandard(const CScript& scriptPubKey, const std::optional& max_datacarrier_bytes, TxoutType& whichType) +bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType) { std::vector > vSolutions; whichType = Solver(scriptPubKey, vSolutions); @@ -91,16 +91,12 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional& max_ return false; if (m < 1 || m > n) return false; - } else if (whichType == TxoutType::NULL_DATA) { - if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) { - return false; - } } return true; } -bool IsStandardTx(const CTransaction& tx, const std::optional& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) +bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) { if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1) { reason = "version"; @@ -137,17 +133,14 @@ bool IsStandardTx(const CTransaction& tx, const std::optional& max_dat } } - unsigned int nDataOut = 0; TxoutType whichType; for (const CTxOut& txout : tx.vout) { - if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) { + if (!::IsStandard(txout.scriptPubKey, whichType)) { reason = "scriptpubkey"; return false; } - if (whichType == TxoutType::NULL_DATA) - nDataOut++; - else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) { + if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) { reason = "bare-multisig"; return false; } @@ -159,12 +152,6 @@ bool IsStandardTx(const CTransaction& tx, const std::optional& max_dat return false; } - // only one OP_RETURN txout is permitted - if (nDataOut > 1) { - reason = "multi-op-return"; - return false; - } - return true; } diff --git a/src/policy/policy.h b/src/policy/policy.h index 2151ec13dd0..46310d01cd1 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -70,13 +70,6 @@ static constexpr unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT_KVB{101}; static constexpr unsigned int DEFAULT_DESCENDANT_LIMIT{25}; /** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT_KVB{101}; -/** Default for -datacarrier */ -static const bool DEFAULT_ACCEPT_DATACARRIER = true; -/** - * Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN, - * +2 for the pushdata opcodes. - */ -static const unsigned int MAX_OP_RETURN_RELAY = 83; /** * An extra transaction can be added to a package, as long as it only has one * ancestor and is no larger than this. Not really any reason to make this @@ -136,7 +129,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee); bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee); -bool IsStandard(const CScript& scriptPubKey, const std::optional& max_datacarrier_bytes, TxoutType& whichType); +bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType); /** Get the vout index numbers of all dust outputs */ std::vector GetDust(const CTransaction& tx, CFeeRate dust_relay_rate); @@ -150,7 +143,7 @@ static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3}; * Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, const std::optional& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason); +bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason); /** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp index c7ff2f3a28e..50001a1d820 100644 --- a/src/test/fuzz/key.cpp +++ b/src/test/fuzz/key.cpp @@ -151,12 +151,12 @@ FUZZ_TARGET(key, .init = initialize_key) assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID())); TxoutType which_type_tx_pubkey; - const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey); + const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey); assert(is_standard_tx_pubkey); assert(which_type_tx_pubkey == TxoutType::PUBKEY); TxoutType which_type_tx_multisig; - const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig); + const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig); assert(is_standard_tx_multisig); assert(which_type_tx_multisig == TxoutType::MULTISIG); diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 07a49e039fb..9aa50559cbd 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -53,7 +53,7 @@ FUZZ_TARGET(script, .init = initialize_script) } TxoutType which_type; - bool is_standard_ret = IsStandard(script, std::nullopt, which_type); + bool is_standard_ret = IsStandard(script, which_type); if (!is_standard_ret) { assert(which_type == TxoutType::NONSTANDARD || which_type == TxoutType::NULL_DATA || diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index c9eb11222fe..85c711cb98a 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -61,8 +61,8 @@ FUZZ_TARGET(transaction, .init = initialize_transaction) const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE}; std::string reason; - const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ true, dust_relay_fee, reason); - const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ false, dust_relay_fee, reason); + const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ true, dust_relay_fee, reason); + const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ false, dust_relay_fee, reason); if (is_standard_without_permit_bare_multisig) { assert(is_standard_with_permit_bare_multisig); } diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 29a73d03d25..b996f3cc061 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) const auto is_standard{[](const CScript& spk) { TxoutType type; - bool res{::IsStandard(spk, std::nullopt, type)}; + bool res{::IsStandard(spk, type)}; if (res) { BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG); } diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index bb408b7b0f5..9e5da2d1a88 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -21,13 +21,13 @@ // Helpers: static bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason) { - return IsStandardTx(tx, std::nullopt, permit_bare_multisig, CFeeRate{DUST_RELAY_TX_FEE}, reason); + return IsStandardTx(tx, permit_bare_multisig, CFeeRate{DUST_RELAY_TX_FEE}, reason); } static bool IsStandardTx(const CTransaction& tx, std::string& reason) { - return IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/true, CFeeRate{DUST_RELAY_TX_FEE}, reason) && - IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason); + return IsStandardTx(tx, /*permit_bare_multisig=*/true, CFeeRate{DUST_RELAY_TX_FEE}, reason) && + IsStandardTx(tx, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason); } static std::vector Serialize(const CScript& s) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 1375672a418..c5707bca72f 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -799,12 +799,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) constexpr auto CheckIsStandard = [](const auto& t) { std::string reason; - BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason)); + BOOST_CHECK(IsStandardTx(CTransaction{t}, g_bare_multi, g_dust, reason)); BOOST_CHECK(reason.empty()); }; constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) { std::string reason; - BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason)); + BOOST_CHECK(!IsStandardTx(CTransaction{t}, g_bare_multi, g_dust, reason)); BOOST_CHECK_EQUAL(reason_in, reason); }; @@ -858,15 +858,10 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].scriptPubKey = CScript() << OP_1; CheckIsNotStandard(t, "scriptpubkey"); - // MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; - BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); - CheckIsStandard(t); - - // MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard) + // TxoutType::NULL_DATA t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex; - BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); - CheckIsNotStandard(t, "scriptpubkey"); + BOOST_CHECK_EQUAL(84, t.vout[0].scriptPubKey.size()); + CheckIsStandard(t); // Data payload can be encoded in any way... t.vout[0].scriptPubKey = CScript() << OP_RETURN << ""_hex; @@ -888,21 +883,21 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].scriptPubKey = CScript() << OP_RETURN; CheckIsStandard(t); - // Only one TxoutType::NULL_DATA permitted in all cases + // Multiple TxoutType::NULL_DATA outputs are permitted t.vout.resize(2); t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; t.vout[0].nValue = 0; t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; t.vout[1].nValue = 0; - CheckIsNotStandard(t, "multi-op-return"); + CheckIsStandard(t); t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex; t.vout[1].scriptPubKey = CScript() << OP_RETURN; - CheckIsNotStandard(t, "multi-op-return"); + CheckIsStandard(t); t.vout[0].scriptPubKey = CScript() << OP_RETURN; t.vout[1].scriptPubKey = CScript() << OP_RETURN; - CheckIsNotStandard(t, "multi-op-return"); + CheckIsStandard(t); // Check large scriptSig (non-standard if size is >1650 bytes) t.vout.resize(1); diff --git a/src/validation.cpp b/src/validation.cpp index 1213d8be9f9..09515386e71 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -790,7 +790,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Rather not work on nonstandard transactions (unless -testnet/-regtest) std::string reason; - if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.max_datacarrier_bytes, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason)) { + if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason)) { return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); } diff --git a/test/functional/feature_blocksxor.py b/test/functional/feature_blocksxor.py index 9824bf97151..ab5b0071b86 100755 --- a/test/functional/feature_blocksxor.py +++ b/test/functional/feature_blocksxor.py @@ -23,7 +23,6 @@ class BlocksXORTest(BitcoinTestFramework): self.extra_args = [[ '-blocksxor=1', '-fastprune=1', # use smaller block files - '-datacarriersize=100000', # needed to pad transaction with MiniWallet ]] def run_test(self): diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index 1d7a7bfc55f..b72090b4363 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -51,7 +51,6 @@ class MaxUploadTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [[ f"-maxuploadtarget={UPLOAD_TARGET_MB}M", - "-datacarriersize=100000", ]] self.supports_cli = False diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 9014ab260e1..f4b21cd2044 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -326,13 +326,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework): result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}], rawtxs=[tx.serialize().hex()], ) - tx = tx_from_hex(raw_tx_reference) - tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) - tx.vout = [tx.vout[0]] * 2 - self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}], - rawtxs=[tx.serialize().hex()], - ) self.log.info('A timelocked transaction') tx = tx_from_hex(raw_tx_reference) diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py deleted file mode 100755 index 48e636caa22..00000000000 --- a/test/functional/mempool_datacarrier.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2020-2022 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test datacarrier functionality""" -from test_framework.messages import ( - CTxOut, - MAX_OP_RETURN_RELAY, -) -from test_framework.script import ( - CScript, - OP_RETURN, -) -from test_framework.test_framework import BitcoinTestFramework -from test_framework.test_node import TestNode -from test_framework.util import assert_raises_rpc_error -from test_framework.wallet import MiniWallet - -from random import randbytes - - -class DataCarrierTest(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 4 - self.extra_args = [ - [], - ["-datacarrier=0"], - ["-datacarrier=1", f"-datacarriersize={MAX_OP_RETURN_RELAY - 1}"], - ["-datacarrier=1", "-datacarriersize=2"], - ] - - def test_null_data_transaction(self, node: TestNode, data, success: bool) -> None: - tx = self.wallet.create_self_transfer(fee_rate=0)["tx"] - data = [] if data is None else [data] - tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN] + data))) - tx.vout[0].nValue -= tx.get_vsize() # simply pay 1sat/vbyte fee - - tx_hex = tx.serialize().hex() - - if success: - self.wallet.sendrawtransaction(from_node=node, tx_hex=tx_hex) - assert tx.rehash() in node.getrawmempool(True), f'{tx_hex} not in mempool' - else: - assert_raises_rpc_error(-26, "scriptpubkey", self.wallet.sendrawtransaction, from_node=node, tx_hex=tx_hex) - - def run_test(self): - self.wallet = MiniWallet(self.nodes[0]) - - # By default, only 80 bytes are used for data (+1 for OP_RETURN, +2 for the pushdata opcodes). - default_size_data = randbytes(MAX_OP_RETURN_RELAY - 3) - too_long_data = randbytes(MAX_OP_RETURN_RELAY - 2) - small_data = randbytes(MAX_OP_RETURN_RELAY - 4) - one_byte = randbytes(1) - zero_bytes = randbytes(0) - - self.log.info("Testing null data transaction with default -datacarrier and -datacarriersize values.") - self.test_null_data_transaction(node=self.nodes[0], data=default_size_data, success=True) - - self.log.info("Testing a null data transaction larger than allowed by the default -datacarriersize value.") - self.test_null_data_transaction(node=self.nodes[0], data=too_long_data, success=False) - - self.log.info("Testing a null data transaction with -datacarrier=false.") - self.test_null_data_transaction(node=self.nodes[1], data=default_size_data, success=False) - - self.log.info("Testing a null data transaction with a size larger than accepted by -datacarriersize.") - self.test_null_data_transaction(node=self.nodes[2], data=default_size_data, success=False) - - self.log.info("Testing a null data transaction with a size smaller than accepted by -datacarriersize.") - self.test_null_data_transaction(node=self.nodes[2], data=small_data, success=True) - - self.log.info("Testing a null data transaction with no data.") - self.test_null_data_transaction(node=self.nodes[0], data=None, success=True) - self.test_null_data_transaction(node=self.nodes[1], data=None, success=False) - self.test_null_data_transaction(node=self.nodes[2], data=None, success=True) - self.test_null_data_transaction(node=self.nodes[3], data=None, success=True) - - self.log.info("Testing a null data transaction with zero bytes of data.") - self.test_null_data_transaction(node=self.nodes[0], data=zero_bytes, success=True) - self.test_null_data_transaction(node=self.nodes[1], data=zero_bytes, success=False) - self.test_null_data_transaction(node=self.nodes[2], data=zero_bytes, success=True) - self.test_null_data_transaction(node=self.nodes[3], data=zero_bytes, success=True) - - self.log.info("Testing a null data transaction with one byte of data.") - self.test_null_data_transaction(node=self.nodes[0], data=one_byte, success=True) - self.test_null_data_transaction(node=self.nodes[1], data=one_byte, success=False) - self.test_null_data_transaction(node=self.nodes[2], data=one_byte, success=True) - self.test_null_data_transaction(node=self.nodes[3], data=one_byte, success=False) - - -if __name__ == '__main__': - DataCarrierTest(__file__).main() diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 85d158d6111..791654a8c04 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -29,7 +29,6 @@ class MempoolLimitTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [[ - "-datacarriersize=100000", "-maxmempool=5", ]] self.supports_cli = False diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py index 3290ff43c49..46d844e9fc7 100755 --- a/test/functional/mempool_package_limits.py +++ b/test/functional/mempool_package_limits.py @@ -52,8 +52,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): self.test_anc_count_limits_2() self.test_anc_count_limits_bushy() - # The node will accept (nonstandard) extra large OP_RETURN outputs - self.restart_node(0, extra_args=["-datacarriersize=100000"]) + self.restart_node(0) self.test_anc_size_limits() self.test_desc_size_limits() diff --git a/test/functional/mempool_package_rbf.py b/test/functional/mempool_package_rbf.py index 4dc6f8fe364..5be4fe55aee 100755 --- a/test/functional/mempool_package_rbf.py +++ b/test/functional/mempool_package_rbf.py @@ -33,7 +33,6 @@ class PackageRBFTest(BitcoinTestFramework): self.setup_clean_chain = True # Required for fill_mempool() self.extra_args = [[ - "-datacarriersize=100000", "-maxmempool=5", ]] * self.num_nodes diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py index 47df0c614ae..94c13f62a21 100755 --- a/test/functional/mempool_sigoplimit.py +++ b/test/functional/mempool_sigoplimit.py @@ -44,8 +44,6 @@ MAX_PUBKEYS_PER_MULTISIG = 20 class BytesPerSigOpTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - # allow large datacarrier output to pad transactions - self.extra_args = [['-datacarriersize=100000']] def create_p2wsh_spending_tx(self, witness_script, output_script): """Create a 1-input-1-output P2WSH spending transaction with only the @@ -139,7 +137,7 @@ class BytesPerSigOpTest(BitcoinTestFramework): self.log.info("Test a overly-large sigops-vbyte hits package limits") # Make a 2-transaction package which fails vbyte checks even though # separately they would work. - self.restart_node(0, extra_args=["-bytespersigop=5000","-permitbaremultisig=1"] + self.extra_args[0]) + self.restart_node(0, extra_args=["-bytespersigop=5000","-permitbaremultisig=1"]) def create_bare_multisig_tx(utxo_to_spend=None): _, pubkey = generate_keypair() @@ -185,7 +183,7 @@ class BytesPerSigOpTest(BitcoinTestFramework): else: bytespersigop_parameter = f"-bytespersigop={bytes_per_sigop}" self.log.info(f"Test sigops limit setting {bytespersigop_parameter}...") - self.restart_node(0, extra_args=[bytespersigop_parameter] + self.extra_args[0]) + self.restart_node(0, extra_args=[bytespersigop_parameter]) for num_sigops in (69, 101, 142, 183, 222): self.test_sigops_limit(bytes_per_sigop, num_sigops) diff --git a/test/functional/mempool_truc.py b/test/functional/mempool_truc.py index c2a65f9ade7..8a4f34e3669 100755 --- a/test/functional/mempool_truc.py +++ b/test/functional/mempool_truc.py @@ -49,7 +49,7 @@ class MempoolTRUC(BitcoinTestFramework): assert_equal(len(txids), len(mempool_contents)) assert all([txid in txids for txid in mempool_contents]) - @cleanup(extra_args=["-datacarriersize=20000"]) + @cleanup() def test_truc_max_vsize(self): node = self.nodes[0] self.log.info("Test TRUC-specific maximum transaction vsize") @@ -63,7 +63,7 @@ class MempoolTRUC(BitcoinTestFramework): tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_vsize=TRUC_MAX_VSIZE + 1, version=2) self.check_mempool([tx_v2_heavy["txid"]]) - @cleanup(extra_args=["-datacarriersize=1000"]) + @cleanup() def test_truc_acceptance(self): node = self.nodes[0] self.log.info("Test a child of a TRUC transaction cannot be more than 1000vB") @@ -160,7 +160,7 @@ class MempoolTRUC(BitcoinTestFramework): self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]]) - @cleanup(extra_args=["-datacarriersize=40000"]) + @cleanup() def test_truc_reorg(self): node = self.nodes[0] self.log.info("Test that, during a reorg, TRUC rules are not enforced") @@ -182,7 +182,7 @@ class MempoolTRUC(BitcoinTestFramework): node.reconsiderblock(block[0]) - @cleanup(extra_args=["-limitdescendantsize=10", "-datacarriersize=40000"]) + @cleanup(extra_args=["-limitdescendantsize=10"]) def test_nondefault_package_limits(self): """ Max standard tx size + TRUC rules imply the ancestor/descendant rules (at their default @@ -215,7 +215,7 @@ class MempoolTRUC(BitcoinTestFramework): self.generate(node, 1) self.log.info("Test that a decreased limitancestorsize also applies to v3 parent") - self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000"]) + self.restart_node(0, extra_args=["-limitancestorsize=10"]) tx_v3_parent_large2 = self.wallet.send_self_transfer( from_node=node, target_vsize=parent_target_vsize, @@ -235,7 +235,7 @@ class MempoolTRUC(BitcoinTestFramework): assert_raises_rpc_error(-26, "too-long-mempool-chain, exceeds ancestor size limit", node.sendrawtransaction, tx_v3_child_large2["hex"]) self.check_mempool([tx_v3_parent_large2["txid"]]) - @cleanup(extra_args=["-datacarriersize=1000"]) + @cleanup() def test_truc_ancestors_package(self): self.log.info("Test that TRUC ancestor limits are checked within the package") node = self.nodes[0] @@ -384,7 +384,7 @@ class MempoolTRUC(BitcoinTestFramework): assert_equal(result_package_cpfp["tx-results"][tx_sibling_3['wtxid']]['error'], expected_error_cpfp) - @cleanup(extra_args=["-datacarriersize=1000"]) + @cleanup() def test_truc_package_inheritance(self): self.log.info("Test that TRUC inheritance is checked within package") node = self.nodes[0] diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 63fb7002c17..cbb1cf789ef 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -279,11 +279,11 @@ class MiningTest(BitcoinTestFramework): def test_block_max_weight(self): self.log.info("Testing default and custom -blockmaxweight startup options.") - # Restart the node to allow large transactions + # Restart the node LARGE_TXS_COUNT = 10 LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT) HIGH_FEERATE = Decimal("0.0003") - self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}"]) + self.restart_node(0) # Ensure the mempool is empty assert_equal(len(self.nodes[0].getrawmempool()), 0) @@ -311,7 +311,7 @@ class MiningTest(BitcoinTestFramework): # Test block template creation with custom -blockmaxweight custom_block_weight = MAX_BLOCK_WEIGHT - 2000 # Reducing the weight by 2000 units will prevent 1 large transaction from fitting into the block. - self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", f"-blockmaxweight={custom_block_weight}"]) + self.restart_node(0, extra_args=[f"-blockmaxweight={custom_block_weight}"]) self.log.info("Testing the block template with custom -blockmaxweight to include 9 large and 2 normal transactions.") self.verify_block_template( @@ -321,7 +321,7 @@ class MiningTest(BitcoinTestFramework): # Ensure the block weight does not exceed the maximum self.log.info(f"Testing that the block weight will never exceed {MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT}.") - self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", f"-blockmaxweight={MAX_BLOCK_WEIGHT}"]) + self.restart_node(0, extra_args=[f"-blockmaxweight={MAX_BLOCK_WEIGHT}"]) self.log.info("Sending 2 additional normal transactions to fill the mempool to the maximum block weight.") self.send_transactions(utxos[LARGE_TXS_COUNT + 2:], NORMAL_FEERATE, NORMAL_VSIZE) self.log.info(f"Testing that the mempool's weight matches the maximum block weight: {MAX_BLOCK_WEIGHT}.") @@ -335,7 +335,7 @@ class MiningTest(BitcoinTestFramework): self.log.info("Test -blockreservedweight startup option.") # Lowering the -blockreservedweight by 4000 will allow for two more transactions. - self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", "-blockreservedweight=4000"]) + self.restart_node(0, extra_args=["-blockreservedweight=4000"]) self.verify_block_template( expected_tx_count=12, expected_weight=MAX_BLOCK_WEIGHT - 4000, diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index 2cb5d85b44f..a8646d49181 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -27,7 +27,6 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [[ "-printpriority=1", - "-datacarriersize=100000", ]] * self.num_nodes self.supports_cli = False diff --git a/test/functional/p2p_1p1c_network.py b/test/functional/p2p_1p1c_network.py index e48e5b88b67..b098e4cf436 100755 --- a/test/functional/p2p_1p1c_network.py +++ b/test/functional/p2p_1p1c_network.py @@ -41,7 +41,6 @@ class PackageRelayTest(BitcoinTestFramework): # hugely speeds up the test, as it involves multiple hops of tx relay. self.noban_tx_relay = True self.extra_args = [[ - "-datacarriersize=100000", "-maxmempool=5", ]] * self.num_nodes self.supports_cli = False diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index addb5027f37..0cdec4275fd 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -59,7 +59,6 @@ class PackageRelayTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [[ - "-datacarriersize=100000", "-maxmempool=5", ]] self.supports_cli = False diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py index 2b75c1193d1..3da781dee2e 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -68,7 +68,7 @@ class ConnectionType(Enum): class TxDownloadTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.extra_args= [['-datacarriersize=100000', '-maxmempool=5', '-persistmempool=0']] * self.num_nodes + self.extra_args= [['-maxmempool=5', '-persistmempool=0']] * self.num_nodes def test_tx_requests(self): self.log.info("Test that we request transactions from all our peers, eventually") diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index a2f9210f94d..119268213f4 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -438,7 +438,6 @@ class RPCPackagesTest(BitcoinTestFramework): # but child is too high fee # Lower mempool limit to make it easier to fill_mempool self.restart_node(0, extra_args=[ - "-datacarriersize=100000", "-maxmempool=5", "-persistmempool=0", ]) @@ -467,7 +466,7 @@ class RPCPackagesTest(BitcoinTestFramework): assert parent["txid"] not in node.getrawmempool() assert child["txid"] not in node.getrawmempool() - # Reset maxmempool, datacarriersize, reset dynamic mempool minimum feerate, and empty mempool. + # Reset maxmempool, reset dynamic mempool minimum feerate, and empty mempool. self.restart_node(0) self.wallet.rescan_utxos() diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index e6f72f43b54..007a8499c1a 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -73,9 +73,6 @@ WITNESS_SCALE_FACTOR = 4 DEFAULT_ANCESTOR_LIMIT = 25 # default max number of in-mempool ancestors DEFAULT_DESCENDANT_LIMIT = 25 # default max number of in-mempool descendants -# Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes. -MAX_OP_RETURN_RELAY = 83 - DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours MAGIC_BYTES = { diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 0d92317ca64..7039ad453be 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -338,7 +338,6 @@ BASE_SCRIPTS = [ 'feature_unsupported_utxo_db.py', 'feature_logging.py', 'feature_anchors.py', - 'mempool_datacarrier.py', 'feature_coinstatsindex.py', 'wallet_orphanedreward.py', 'wallet_timelock.py', From b420376aef7e6fbc8fe35dd909b6bac085c7b0c7 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 28 Apr 2025 20:15:08 +0000 Subject: [PATCH 2/5] Add comment to test noting when OP_RETURN limit was removed --- src/test/transaction_tests.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index c5707bca72f..988adbded9c 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -859,6 +859,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) CheckIsNotStandard(t, "scriptpubkey"); // TxoutType::NULL_DATA + // + // Until v30 OP_RETURN was limited to 83 bytes (80 bytes of data, +1 for + // OP_RETURN, +2 for the pushdata opcodes). Here we test with 84 bytes. t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex; BOOST_CHECK_EQUAL(84, t.vout[0].scriptPubKey.size()); CheckIsStandard(t); From 47f9565c15faec0ce35a17c68ade85af1dc41677 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 28 Apr 2025 20:16:50 +0000 Subject: [PATCH 3/5] Move node restart in test to better place. Needed because the previous test used -persistmempool=0 and we need to forget about the transaction it created. Credit: Sjors Provoost --- test/functional/mining_basic.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index cbb1cf789ef..49c80bfc943 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -186,6 +186,9 @@ class MiningTest(BitcoinTestFramework): assert tx_below_min_feerate['txid'] not in block_template_txids assert tx_below_min_feerate['txid'] not in block_txids + # Restart node to clear mempool for the next test + self.restart_node(0) + def test_timewarp(self): self.log.info("Test timewarp attack mitigation (BIP94)") node = self.nodes[0] @@ -279,11 +282,9 @@ class MiningTest(BitcoinTestFramework): def test_block_max_weight(self): self.log.info("Testing default and custom -blockmaxweight startup options.") - # Restart the node LARGE_TXS_COUNT = 10 LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT) HIGH_FEERATE = Decimal("0.0003") - self.restart_node(0) # Ensure the mempool is empty assert_equal(len(self.nodes[0].getrawmempool()), 0) From 8fd09d622d161eb554f080a52735832119cb35e5 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 28 Apr 2025 20:22:59 +0000 Subject: [PATCH 4/5] Add more OP_RETURN mempool acceptance functional tests Credit: Sjors Provoost and Antoine Poinsot --- test/functional/mempool_accept.py | 47 +++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index f4b21cd2044..a4dfda84438 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -9,6 +9,7 @@ from decimal import Decimal import math from test_framework.test_framework import BitcoinTestFramework +from test_framework.blocktools import MAX_STANDARD_TX_WEIGHT from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, COIN, @@ -327,6 +328,52 @@ class MempoolAcceptanceTest(BitcoinTestFramework): rawtxs=[tx.serialize().hex()], ) + # OP_RETURN followed by non-push + tx = tx_from_hex(raw_tx_reference) + tx.vout[0].scriptPubKey = CScript([OP_RETURN, OP_HASH160]) + tx.vout = [tx.vout[0]] * 2 + self.check_mempool_result( + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}], + rawtxs=[tx.serialize().hex()], + ) + + # Multiple OP_RETURN and more than 83 bytes are standard since v30 + tx = tx_from_hex(raw_tx_reference) + tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff']))) + tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff' * 90]))) + + self.check_mempool_result( + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal('0.05')}}], + rawtxs=[tx.serialize().hex()], + maxfeerate=0 + ) + + self.log.info("A transaction with several OP_RETURN outputs.") + tx = tx_from_hex(raw_tx_reference) + op_return_count = 42 + tx.vout[0].nValue = int(tx.vout[0].nValue / op_return_count) + tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) + tx.vout = [tx.vout[0]] * op_return_count + self.check_mempool_result( + result_expected=[{"txid": tx.rehash(), "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.05000026")}}], + rawtxs=[tx.serialize().hex()], + ) + + self.log.info("A transaction with an OP_RETUN output that bumps into the max standardness tx size.") + tx = tx_from_hex(raw_tx_reference) + tx.vout[0].scriptPubKey = CScript([OP_RETURN]) + data_len = int(MAX_STANDARD_TX_WEIGHT / 4) - tx.get_vsize() - 5 - 4 # -5 for PUSHDATA4 and -4 for script size + tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len)]) + self.check_mempool_result( + result_expected=[{"txid": tx.rehash(), "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.1") - Decimal("0.05")}}], + rawtxs=[tx.serialize().hex()], + ) + tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len + 1)]) + self.check_mempool_result( + result_expected=[{"txid": tx.rehash(), "allowed": False, "reject-reason": "tx-size"}], + rawtxs=[tx.serialize().hex()], + ) + self.log.info('A timelocked transaction') tx = tx_from_hex(raw_tx_reference) tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored From 47e713ea5a96d3bb2ddd64c8a87607e5ccea8c72 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 28 Apr 2025 20:26:20 +0000 Subject: [PATCH 5/5] Remove old comment to datacarriersize argument --- test/functional/test_framework/mempool_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/mempool_util.py b/test/functional/test_framework/mempool_util.py index 0e9c821e2ea..2991a88b54d 100644 --- a/test/functional/test_framework/mempool_util.py +++ b/test/functional/test_framework/mempool_util.py @@ -41,8 +41,8 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None): """Fill mempool until eviction. Allows for simpler testing of scenarios with floating mempoolminfee > minrelay - Requires -datacarriersize=100000 and -maxmempool=5 and assumes -minrelaytxfee - is 1 sat/vbyte. + Requires -maxmempool=5 and assumes -minrelaytxfee is 1 sat/vbyte. + To avoid unintentional tx dependencies, the mempool filling txs are created with a tagged ephemeral miniwallet instance. """