diff --git a/doc/policy/mempool-replacements.md b/doc/policy/mempool-replacements.md index eb370672e40..73682e2ffb3 100644 --- a/doc/policy/mempool-replacements.md +++ b/doc/policy/mempool-replacements.md @@ -32,8 +32,8 @@ other consensus and policy rules, each of the following conditions are met: 4. The additional fees (difference between absolute fee paid by the replacement transaction and the sum paid by the original transactions) pays for the replacement transaction's bandwidth at or above the rate set by the node's incremental relay feerate. For example, if the incremental relay - feerate is 1 satoshi/vB and the replacement transaction is 500 virtual bytes total, then the - replacement pays a fee at least 500 satoshis higher than the sum of the original transactions. + feerate is 0.1 satoshi/vB and the replacement transaction is 500 virtual bytes total, then the + replacement pays a fee at least 50 satoshis higher than the sum of the original transactions. *Rationale*: Try to prevent DoS attacks where an attacker causes the network to repeatedly relay transactions each paying a tiny additional amount in fees, e.g. just 1 satoshi. @@ -77,3 +77,5 @@ This set of rules is similar but distinct from BIP125. * Full replace-by-fee is the default policy as of **v28.0** ([PR #30493](https://github.com/bitcoin/bitcoin/pull/30493)). * Signaling for replace-by-fee is no longer required as of [PR 30592](https://github.com/bitcoin/bitcoin/pull/30592). + +* The incremental relay feerate default is 0.1sat/vB ([PR #33106](https://github.com/bitcoin/bitcoin/pull/33106)). diff --git a/doc/release-notes-33106.md b/doc/release-notes-33106.md new file mode 100644 index 00000000000..95750cedff9 --- /dev/null +++ b/doc/release-notes-33106.md @@ -0,0 +1,17 @@ +Mining and Transaction Relay Policy +========================= + +The minimum block feerate (`-blockmintxfee`) has been changed to 1 satoshi per kvB. It can still be changed using the +configuration option. + +The default minimum relay feerate (`-minrelaytxfee`) and incremental relay feerate (`-incrementalrelayfee`) have been +changed to 100 satoshis per kvB. They can still be changed using their respective configuration options, but it is +recommended to change both together if you decide to do so. + +Other minimum feerates (e.g. the dust feerate, the minimum returned by the fee estimator, and all feerates used by the +wallet) remain unchanged. The mempool minimum feerate still changes in response to high volume but more gradually, as a +result of the change to the incremental relay feerate. + +Note that unless these lower defaults are widely adopted across the network, transactions created with lower fee rates +are not guaranteed to propagate or confirm. The wallet feerates remain unchanged; `-mintxfee` must be changed before +attempting to create transactions with lower feerates using the wallet. diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index 11c77ff5610..abbe97d9221 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -65,6 +65,7 @@ util::Result ApplyArgsManOptions(const ArgsManager& argsman, const CChainP } } + static_assert(DEFAULT_MIN_RELAY_TX_FEE == DEFAULT_INCREMENTAL_RELAY_FEE); if (const auto arg{argsman.GetArg("-minrelaytxfee")}) { if (std::optional min_relay_feerate = ParseMoney(*arg)) { // High fee check is done afterward in CWallet::Create() diff --git a/src/policy/policy.h b/src/policy/policy.h index ad787630a45..ce8bfc6aef9 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -29,7 +29,7 @@ static constexpr unsigned int DEFAULT_BLOCK_RESERVED_WEIGHT{8000}; * Setting a lower value is prevented at startup. */ static constexpr unsigned int MINIMUM_BLOCK_RESERVED_WEIGHT{2000}; /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ -static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000}; +static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1}; /** The maximum weight for transactions we're willing to relay/mine */ static constexpr int32_t MAX_STANDARD_TX_WEIGHT{400000}; /** The minimum non-witness size for transactions we're willing to relay/mine: one larger than 64 */ @@ -41,7 +41,7 @@ static constexpr unsigned int MAX_STANDARD_TX_SIGOPS_COST{MAX_BLOCK_SIGOPS_COST/ /** The maximum number of potentially executed legacy signature operations in a single standard tx */ static constexpr unsigned int MAX_TX_LEGACY_SIGOPS{2'500}; /** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or replacement **/ -static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000}; +static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{100}; /** Default for -bytespersigop */ static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20}; /** Default for -permitbaremultisig */ @@ -63,7 +63,7 @@ static constexpr unsigned int MAX_STANDARD_SCRIPTSIG_SIZE{1650}; * outputs below the new threshold */ static constexpr unsigned int DUST_RELAY_TX_FEE{3000}; /** Default for -minrelaytxfee, minimum relay fee for transactions */ -static constexpr unsigned int DEFAULT_MIN_RELAY_TX_FEE{1000}; +static constexpr unsigned int DEFAULT_MIN_RELAY_TX_FEE{100}; /** Default for -limitancestorcount, max number of in-mempool ancestors */ static constexpr unsigned int DEFAULT_ANCESTOR_LIMIT{25}; /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 5992d2a41eb..5f8b63dbdd7 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -443,7 +443,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - AddToMempool(pool, entry.Fee(10000LL).FromTx(tx1)); + AddToMempool(pool, entry.Fee(1000LL).FromTx(tx1)); CMutableTransaction tx2 = CMutableTransaction(); tx2.vin.resize(1); @@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; tx2.vout[0].nValue = 10 * COIN; - AddToMempool(pool, entry.Fee(5000LL).FromTx(tx2)); + AddToMempool(pool, entry.Fee(500LL).FromTx(tx2)); pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing BOOST_CHECK(pool.exists(tx1.GetHash())); @@ -469,7 +469,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; tx3.vout[0].nValue = 10 * COIN; - AddToMempool(pool, entry.Fee(20000LL).FromTx(tx3)); + AddToMempool(pool, entry.Fee(2000LL).FromTx(tx3)); pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) BOOST_CHECK(!pool.exists(tx1.GetHash())); @@ -481,8 +481,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(!pool.exists(tx2.GetHash())); BOOST_CHECK(!pool.exists(tx3.GetHash())); - CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2))); - BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); + CFeeRate maxFeeRateRemoved(2500, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2))); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE); CMutableTransaction tx4 = CMutableTransaction(); tx4.vin.resize(2); @@ -532,10 +532,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[1].nValue = 10 * COIN; - AddToMempool(pool, entry.Fee(7000LL).FromTx(tx4)); - AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5)); - AddToMempool(pool, entry.Fee(1100LL).FromTx(tx6)); - AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7)); + AddToMempool(pool, entry.Fee(700LL).FromTx(tx4)); + AddToMempool(pool, entry.Fee(100LL).FromTx(tx5)); + AddToMempool(pool, entry.Fee(110LL).FromTx(tx6)); + AddToMempool(pool, entry.Fee(900LL).FromTx(tx7)); // we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that pool.TrimToSize(pool.DynamicMemoryUsage() - 1); @@ -544,8 +544,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(!pool.exists(tx7.GetHash())); if (!pool.exists(tx5.GetHash())) - AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5)); - AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7)); + AddToMempool(pool, entry.Fee(100LL).FromTx(tx5)); + AddToMempool(pool, entry.Fee(900LL).FromTx(tx7)); pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 BOOST_CHECK(pool.exists(tx4.GetHash())); @@ -553,34 +553,34 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx6.GetHash())); BOOST_CHECK(!pool.exists(tx7.GetHash())); - AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5)); - AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7)); + AddToMempool(pool, entry.Fee(100LL).FromTx(tx5)); + AddToMempool(pool, entry.Fee(900LL).FromTx(tx7)); std::vector vtx; SetMockTime(42); SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE); - BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE); // ... we should keep the same min fee until we get a block pool.removeForBlock(vtx, 1); SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE); - BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0)); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/2.0)); // ... then feerate should drop 1/2 each halflife SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2); - BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0)); + BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/4.0)); // ... with a 1/2 halflife when mempool is < 1/2 its target size SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); - BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0)); + BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/8.0)); // ... with a 1/4 halflife when mempool is < 1/4 its target size SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); - BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000); - // ... but feerate should never drop below 1000 + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), DEFAULT_INCREMENTAL_RELAY_FEE); + // ... but feerate should never drop below DEFAULT_INCREMENTAL_RELAY_FEE SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0); - // ... unless it has gone all the way to 0 (after getting past 1000/2) + // ... unless it has gone all the way to 0 (after getting past DEFAULT_INCREMENTAL_RELAY_FEE/2) } inline CTransactionRef make_tx(std::vector&& output_values, std::vector&& inputs=std::vector(), std::vector&& input_indices=std::vector()) diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index ffdf7a4de62..9fab16fba70 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -216,6 +217,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vout.resize(2); tx.vout[0].nValue = 5000000000LL - 100000000; tx.vout[1].nValue = 100000000; // 1BTC output + // Increase size to avoid rounding errors: when the feerate is extremely small (i.e. 1sat/kvB), evaluating the fee + // at a smaller transaction size gives us a rounded value of 0. + BulkTransaction(tx, 4000); Txid hashFreeTx2 = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp index cbbea61a53c..31cf994c875 100644 --- a/src/test/rbf_tests.cpp +++ b/src/test/rbf_tests.cpp @@ -238,10 +238,10 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup) BOOST_CHECK(PaysForRBF(high_fee, high_fee - 1, 1, CFeeRate(0), unused_txid).has_value()); BOOST_CHECK(PaysForRBF(high_fee + 1, high_fee, 1, CFeeRate(0), unused_txid).has_value()); // Additional fees must cover the replacement's vsize at incremental relay fee - BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 2, incremental_relay_feerate, unused_txid).has_value()); - BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, incremental_relay_feerate, unused_txid) == std::nullopt); - BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, higher_relay_feerate, unused_txid).has_value()); - BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 2, higher_relay_feerate, unused_txid) == std::nullopt); + BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 11, incremental_relay_feerate, unused_txid).has_value()); + BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 10, incremental_relay_feerate, unused_txid) == std::nullopt); + BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 11, higher_relay_feerate, unused_txid).has_value()); + BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 20, higher_relay_feerate, unused_txid) == std::nullopt); BOOST_CHECK(PaysForRBF(low_fee, high_fee, 99999999, incremental_relay_feerate, unused_txid).has_value()); BOOST_CHECK(PaysForRBF(low_fee, high_fee + 99999999, 99999999, incremental_relay_feerate, unused_txid) == std::nullopt); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 0fc7991e570..8ce0a0dbe83 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -586,6 +587,9 @@ void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate) CMutableTransaction mtx = CMutableTransaction(); mtx.vin.emplace_back(COutPoint{Txid::FromUint256(m_rng.rand256()), 0}); mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE))); + // Set a large size so that the fee evaluated at target_feerate (which is usually in sats/kvB) is an integer. + // Otherwise, GetMinFee() may end up slightly different from target_feerate. + BulkTransaction(mtx, 4000); const auto tx{MakeTransactionRef(mtx)}; LockPoints lp; // The new mempool min feerate is equal to the removed package's feerate + incremental feerate. diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 3c9b21ddcac..4117326b883 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -13,7 +13,10 @@ from test_framework.messages import ( from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + assert_greater_than, + assert_greater_than_or_equal, assert_raises_rpc_error, + get_fee, ) from test_framework.wallet import MiniWallet from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE @@ -74,6 +77,9 @@ class ReplaceByFeeTest(BitcoinTestFramework): self.log.info("Running test full replace by fee...") self.test_fullrbf() + self.log.info("Running test incremental relay feerates...") + self.test_incremental_relay_feerates() + self.log.info("Passed") def make_utxo(self, node, amount, *, confirmed=True, scriptPubKey=None): @@ -579,10 +585,42 @@ class ReplaceByFeeTest(BitcoinTestFramework): # Higher fee, higher feerate, different txid, but the replacement does not provide a relay # fee conforming to node's `incrementalrelayfee` policy of 1000 sat per KB. - assert_equal(self.nodes[0].getmempoolinfo()["incrementalrelayfee"], Decimal("0.00001")) + assert_equal(self.nodes[0].getmempoolinfo()["incrementalrelayfee"], Decimal("0.000001")) tx.vout[0].nValue -= 1 assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx.serialize().hex()) + def test_incremental_relay_feerates(self): + self.log.info("Test that incremental relay fee is applied correctly in RBF for various settings...") + node = self.nodes[0] + for incremental_setting in (0, 5, 10, 50, 100, 234, 1000, 5000, 21000): + incremental_setting_decimal = incremental_setting / Decimal(COIN) + self.log.info(f"-> Test -incrementalrelayfee={incremental_setting_decimal:.8f}sat/kvB...") + self.restart_node(0, extra_args=[f"-incrementalrelayfee={incremental_setting_decimal:.8f}", "-persistmempool=0"]) + + # When incremental relay feerate is higher than min relay feerate, min relay feerate is automatically increased. + min_relay_feerate = node.getmempoolinfo()["minrelaytxfee"] + assert_greater_than_or_equal(min_relay_feerate, incremental_setting_decimal) + + low_feerate = min_relay_feerate * 2 + confirmed_utxo = self.wallet.get_utxo(confirmed_only=True) + replacee_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee_rate=low_feerate, target_vsize=5000) + node.sendrawtransaction(replacee_tx['hex']) + + replacement_placeholder_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo) + replacement_expected_size = replacement_placeholder_tx['tx'].get_vsize() + replacement_required_fee = get_fee(replacement_expected_size, incremental_setting_decimal) + replacee_tx['fee'] + + # Should always be required to pay additional fees + if incremental_setting > 0: + assert_greater_than(replacement_required_fee, replacee_tx['fee']) + + # 1 satoshi shy of the required fee + failed_replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee=replacement_required_fee - Decimal("0.00000001")) + assert_raises_rpc_error(-26, "insufficient fee", node.sendrawtransaction, failed_replacement_tx['hex']) + + replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee=replacement_required_fee) + node.sendrawtransaction(replacement_tx['hex']) + def test_fullrbf(self): # BIP125 signaling is not respected diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 867c9312208..7dbd7ba1e2e 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -10,6 +10,10 @@ import math from test_framework.test_framework import BitcoinTestFramework from test_framework.blocktools import MAX_STANDARD_TX_WEIGHT +from test_framework.mempool_util import ( + DEFAULT_MIN_RELAY_TX_FEE, + DEFAULT_INCREMENTAL_RELAY_FEE, +) from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, COIN, @@ -85,6 +89,11 @@ class MempoolAcceptanceTest(BitcoinTestFramework): assert_equal(node.getblockcount(), 200) assert_equal(node.getmempoolinfo()['size'], self.mempool_size) + self.log.info("Check default settings") + # Settings are listed in BTC/kvB + assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN) + assert_equal(node.getmempoolinfo()['incrementalrelayfee'], Decimal(DEFAULT_INCREMENTAL_RELAY_FEE) / COIN) + self.log.info('Should not accept garbage to testmempoolaccept') assert_raises_rpc_error(-3, 'JSON value of type string is not of expected type array', lambda: node.testmempoolaccept(rawtxs='ff00baar')) assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=['ff22']*26)) diff --git a/test/functional/mempool_ephemeral_dust.py b/test/functional/mempool_ephemeral_dust.py index fd77eac3e2b..a0308da72ac 100755 --- a/test/functional/mempool_ephemeral_dust.py +++ b/test/functional/mempool_ephemeral_dust.py @@ -216,7 +216,7 @@ class EphemeralDustTest(BitcoinTestFramework): res = self.nodes[0].submitpackage([dusty_tx["hex"], sweep_tx["hex"]]) assert_equal(res["package_msg"], "transaction failed") - assert_equal(res["tx-results"][dusty_tx["wtxid"]]["error"], "min relay fee not met, 0 < 147") + assert_equal(res["tx-results"][dusty_tx["wtxid"]]["error"], "min relay fee not met, 0 < 15") assert_equal(self.nodes[0].getrawmempool(), []) diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index c9a200cfd9b..72696062457 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -92,8 +92,7 @@ class MempoolLimitTest(BitcoinTestFramework): assert_equal(node.getrawmempool(), []) # Restarting the node resets mempool minimum feerate - assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000')) - assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000')) + assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"]) fill_mempool(self, node) current_info = node.getmempoolinfo() @@ -184,8 +183,7 @@ class MempoolLimitTest(BitcoinTestFramework): self.restart_node(0, extra_args=self.extra_args[0]) # Restarting the node resets mempool minimum feerate - assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000')) - assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000')) + assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"]) fill_mempool(self, node) current_info = node.getmempoolinfo() @@ -208,7 +206,7 @@ class MempoolLimitTest(BitcoinTestFramework): # coin is no longer available, but the cache could still contain the tx. cpfp_parent = self.wallet.create_self_transfer( utxo_to_spend=replaced_tx["new_utxo"], - fee_rate=mempoolmin_feerate - Decimal('0.00001'), + fee_rate=mempoolmin_feerate - Decimal('0.000001'), confirmed_only=True) self.wallet.rescan_utxos() @@ -256,8 +254,7 @@ class MempoolLimitTest(BitcoinTestFramework): relayfee = node.getnetworkinfo()['relayfee'] self.log.info('Check that mempoolminfee is minrelaytxfee') - assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000')) - assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000')) + assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"]) fill_mempool(self, node) @@ -315,9 +312,9 @@ class MempoolLimitTest(BitcoinTestFramework): target_vsize_each = 50000 assert_greater_than(target_vsize_each * 2 * 3, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"]) # Should be a true CPFP: parent's feerate is just below mempool min feerate - parent_feerate = mempoolmin_feerate - Decimal("0.000001") # 0.1 sats/vbyte below min feerate + parent_feerate = mempoolmin_feerate - Decimal("0.0000001") # 0.01 sats/vbyte below min feerate # Parent + child is above mempool minimum feerate - child_feerate = (worst_feerate_btcvb * 1000) - Decimal("0.000001") # 0.1 sats/vbyte below worst feerate + child_feerate = (worst_feerate_btcvb * 1000) - Decimal("0.0000001") # 0.01 sats/vbyte below worst feerate # However, when eviction is triggered, these transactions should be at the bottom. # This assertion assumes parent and child are the same size. miniwallet.rescan_utxos() diff --git a/test/functional/mempool_package_rbf.py b/test/functional/mempool_package_rbf.py index ca56bdf8c5f..54f3a90c0ac 100755 --- a/test/functional/mempool_package_rbf.py +++ b/test/functional/mempool_package_rbf.py @@ -162,13 +162,13 @@ class PackageRBFTest(BitcoinTestFramework): self.log.info("Check replacement pays for incremental bandwidth") _, placeholder_txns3 = self.create_simple_package(coin) package_3_size = sum([tx.get_vsize() for tx in placeholder_txns3]) - incremental_sats_required = Decimal(package_3_size) / COIN - incremental_sats_short = incremental_sats_required - Decimal("0.00000001") + incremental_sats_required = (Decimal(package_3_size * 0.1) / COIN).quantize(Decimal("0.00000001")) + incremental_sats_short = incremental_sats_required - Decimal("0.00000005") # Recreate the package with slightly higher fee once we know the size of the new package, but still short of required fee failure_package_hex3, failure_package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + incremental_sats_short) assert_equal(package_3_size, sum([tx.get_vsize() for tx in failure_package_txns3])) pkg_results3 = node.submitpackage(failure_package_hex3) - assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {failure_package_txns3[1].txid_hex}, not enough additional fees to relay; {incremental_sats_short} < {incremental_sats_required}", pkg_results3["package_msg"]) + assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {failure_package_txns3[1].txid_hex}, not enough additional fees to relay; {incremental_sats_short:8f} < {incremental_sats_required:8f}", pkg_results3["package_msg"]) self.assert_mempool_contents(expected=package_txns1) success_package_hex3, success_package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + incremental_sats_required) @@ -562,12 +562,13 @@ class PackageRBFTest(BitcoinTestFramework): ) node.sendrawtransaction(grandparent_result["hex"]) + minrelayfeerate = node.getnetworkinfo()["relayfee"] # Now make package of two descendants that looks # like a cpfp where the parent can't get in on its own self.ctr += 1 parent_result = self.wallet.create_self_transfer( - fee_rate=Decimal('0.00001000'), + fee_rate=minrelayfeerate, utxo_to_spend=grandparent_result["new_utxo"], sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr, ) diff --git a/test/functional/mempool_truc.py b/test/functional/mempool_truc.py index 8a4f34e3669..428bfb0b807 100755 --- a/test/functional/mempool_truc.py +++ b/test/functional/mempool_truc.py @@ -11,6 +11,7 @@ from test_framework.util import ( assert_greater_than, assert_greater_than_or_equal, assert_raises_rpc_error, + get_fee, ) from test_framework.wallet import ( COIN, @@ -595,12 +596,57 @@ class MempoolTRUC(BitcoinTestFramework): ) self.check_mempool([tx_with_multi_children["txid"], tx_with_sibling3_rbf["txid"], tx_with_sibling2["txid"]]) + @cleanup(extra_args=None) + def test_minrelay_in_package_combos(self): + node = self.nodes[0] + self.log.info("Test that only TRUC transactions can be under minrelaytxfee for various settings...") + + for minrelay_setting in (0, 5, 10, 100, 500, 1000, 5000, 333333, 2500000): + self.log.info(f"-> Test -minrelaytxfee={minrelay_setting}sat/kvB...") + setting_decimal = minrelay_setting / Decimal(COIN) + self.restart_node(0, extra_args=[f"-minrelaytxfee={setting_decimal:.8f}", "-persistmempool=0"]) + minrelayfeerate = node.getmempoolinfo()["minrelaytxfee"] + high_feerate = minrelayfeerate * 50 + + tx_v3_0fee_parent = self.wallet.create_self_transfer(fee=0, fee_rate=0, confirmed_only=True, version=3) + tx_v3_child = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_0fee_parent["new_utxo"], fee_rate=high_feerate, version=3) + total_v3_fee = tx_v3_child["fee"] + tx_v3_0fee_parent["fee"] + total_v3_size = tx_v3_child["tx"].get_vsize() + tx_v3_0fee_parent["tx"].get_vsize() + assert_greater_than_or_equal(total_v3_fee, get_fee(total_v3_size, minrelayfeerate)) + if minrelayfeerate > 0: + assert_greater_than(get_fee(tx_v3_0fee_parent["tx"].get_vsize(), minrelayfeerate), 0) + # Always need to pay at least 1 satoshi for entry, even if minimum feerate is very low + assert_greater_than(total_v3_fee, 0) + + tx_v2_0fee_parent = self.wallet.create_self_transfer(fee=0, fee_rate=0, confirmed_only=True, version=2) + tx_v2_child = self.wallet.create_self_transfer(utxo_to_spend=tx_v2_0fee_parent["new_utxo"], fee_rate=high_feerate, version=2) + total_v2_fee = tx_v2_child["fee"] + tx_v2_0fee_parent["fee"] + total_v2_size = tx_v2_child["tx"].get_vsize() + tx_v2_0fee_parent["tx"].get_vsize() + assert_greater_than_or_equal(total_v2_fee, get_fee(total_v2_size, minrelayfeerate)) + if minrelayfeerate > 0: + assert_greater_than(get_fee(tx_v2_0fee_parent["tx"].get_vsize(), minrelayfeerate), 0) + # Always need to pay at least 1 satoshi for entry, even if minimum feerate is very low + assert_greater_than(total_v2_fee, 0) + + result_truc = node.submitpackage([tx_v3_0fee_parent["hex"], tx_v3_child["hex"]], maxfeerate=0) + assert_equal(result_truc["package_msg"], "success") + + result_non_truc = node.submitpackage([tx_v2_0fee_parent["hex"], tx_v2_child["hex"]], maxfeerate=0) + if minrelayfeerate > 0: + assert_equal(result_non_truc["package_msg"], "transaction failed") + min_fee_parent = int(get_fee(tx_v2_0fee_parent["tx"].get_vsize(), minrelayfeerate) * COIN) + assert_equal(result_non_truc["tx-results"][tx_v2_0fee_parent["wtxid"]]["error"], f"min relay fee not met, 0 < {min_fee_parent}") + self.check_mempool([tx_v3_0fee_parent["txid"], tx_v3_child["txid"]]) + else: + assert_equal(result_non_truc["package_msg"], "success") + self.check_mempool([tx_v2_0fee_parent["txid"], tx_v2_child["txid"], tx_v3_0fee_parent["txid"], tx_v3_child["txid"]]) + def run_test(self): self.log.info("Generate blocks to create UTXOs") node = self.nodes[0] self.wallet = MiniWallet(node) - self.generate(self.wallet, 120) + self.generate(self.wallet, 200) self.test_truc_max_vsize() self.test_truc_acceptance() self.test_truc_replacement() @@ -614,6 +660,7 @@ class MempoolTRUC(BitcoinTestFramework): self.test_reorg_2child_rbf() self.test_truc_sibling_eviction() self.test_reorg_sibling_eviction_1p2c() + self.test_minrelay_in_package_combos() if __name__ == "__main__": diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index a4e482f6a01..4683919d1cc 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -39,6 +39,7 @@ from test_framework.p2p import P2PDataStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + assert_greater_than, assert_greater_than_or_equal, assert_raises_rpc_error, get_fee, @@ -54,7 +55,7 @@ MAX_FUTURE_BLOCK_TIME = 2 * 3600 MAX_TIMEWARP = 600 VERSIONBITS_TOP_BITS = 0x20000000 VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28 -DEFAULT_BLOCK_MIN_TX_FEE = 1000 # default `-blockmintxfee` setting [sat/kvB] +DEFAULT_BLOCK_MIN_TX_FEE = 1 # default `-blockmintxfee` setting [sat/kvB] class MiningTest(BitcoinTestFramework): def set_test_params(self): @@ -143,7 +144,7 @@ class MiningTest(BitcoinTestFramework): node = self.nodes[0] # test default (no parameter), zero and a bunch of arbitrary blockmintxfee rates [sat/kvB] - for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 50, 100, 500, 2500, 5000, 21000, 333333, 2500000): + for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 5, 10, 50, 100, 500, 1000, 2500, 5000, 21000, 333333, 2500000): blockmintxfee_btc_kvb = blockmintxfee_sat_kvb / Decimal(COIN) if blockmintxfee_sat_kvb == DEFAULT_BLOCK_MIN_TX_FEE: self.log.info(f"-> Default -blockmintxfee setting ({blockmintxfee_sat_kvb} sat/kvB)...") @@ -154,19 +155,27 @@ class MiningTest(BitcoinTestFramework): self.wallet.rescan_utxos() # to avoid spending outputs of txs that are not in mempool anymore after restart # submit one tx with exactly the blockmintxfee rate, and one slightly below - tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb) + tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True) assert_equal(tx_with_min_feerate["fee"], get_fee(tx_with_min_feerate["tx"].get_vsize(), blockmintxfee_btc_kvb)) - if blockmintxfee_btc_kvb > 0: + if blockmintxfee_sat_kvb > 5: lowerfee_btc_kvb = blockmintxfee_btc_kvb - Decimal(10)/COIN # 0.01 sat/vbyte lower - tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb) + tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb, confirmed_only=True) assert_equal(tx_below_min_feerate["fee"], get_fee(tx_below_min_feerate["tx"].get_vsize(), lowerfee_btc_kvb)) else: # go below zero fee by using modified fees - tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb) + tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True) node.prioritisetransaction(tx_below_min_feerate["txid"], 0, -1) # check that tx below specified fee-rate is neither in template nor in the actual block block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS) block_template_txids = [tx['txid'] for tx in block_template['transactions']] + + # Unless blockmintxfee is 0, the template shouldn't contain free transactions. + # Note that the real block assembler uses package feerates, but we didn't create dependent transactions so it's ok to use base feerate. + if blockmintxfee_btc_kvb > 0: + for txid in block_template_txids: + tx = node.getmempoolentry(txid) + assert_greater_than(tx['fees']['base'], 0) + self.generate(self.wallet, 1, sync_fun=self.no_op) block = node.getblock(node.getbestblockhash(), verbosity=2) block_txids = [tx['txid'] for tx in block['tx']] diff --git a/test/functional/p2p_1p1c_network.py b/test/functional/p2p_1p1c_network.py index 4d0f11ea99b..e4d3b738c19 100755 --- a/test/functional/p2p_1p1c_network.py +++ b/test/functional/p2p_1p1c_network.py @@ -13,9 +13,11 @@ from decimal import Decimal from math import ceil from test_framework.mempool_util import ( + DEFAULT_MIN_RELAY_TX_FEE, fill_mempool, ) from test_framework.messages import ( + COIN, msg_tx, ) from test_framework.p2p import ( @@ -31,9 +33,6 @@ from test_framework.wallet import ( MiniWalletMode, ) -# 1sat/vB feerate denominated in BTC/KvB -FEERATE_1SAT_VB = Decimal("0.00001000") - class PackageRelayTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True @@ -49,12 +48,12 @@ class PackageRelayTest(BitcoinTestFramework): self.log.debug("Check that all nodes' mempool minimum feerates are above min relay feerate") for node in self.nodes: - assert_equal(node.getmempoolinfo()['minrelaytxfee'], FEERATE_1SAT_VB) - assert_greater_than(node.getmempoolinfo()['mempoolminfee'], FEERATE_1SAT_VB) + assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN) + assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN) def create_basic_1p1c(self, wallet): - low_fee_parent = wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB, confirmed_only=True) - high_fee_child = wallet.create_self_transfer(utxo_to_spend=low_fee_parent["new_utxo"], fee_rate=999*FEERATE_1SAT_VB) + low_fee_parent = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN, confirmed_only=True) + high_fee_child = wallet.create_self_transfer(utxo_to_spend=low_fee_parent["new_utxo"], fee_rate=999*Decimal(DEFAULT_MIN_RELAY_TX_FEE)/ COIN) package_hex_basic = [low_fee_parent["hex"], high_fee_child["hex"]] return package_hex_basic, low_fee_parent["tx"], high_fee_child["tx"] @@ -85,8 +84,8 @@ class PackageRelayTest(BitcoinTestFramework): return [low_fee_parent_2outs["hex"], high_fee_child_2outs["hex"]], low_fee_parent_2outs["tx"], high_fee_child_2outs["tx"] def create_package_2p1c(self, wallet): - parent1 = wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB*10, confirmed_only=True) - parent2 = wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB*20, confirmed_only=True) + parent1 = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN * 10, confirmed_only=True) + parent2 = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN * 20, confirmed_only=True) child = wallet.create_self_transfer_multi( utxos_to_spend=[parent1["new_utxo"], parent2["new_utxo"]], fee_per_output=999*parent1["tx"].get_vsize(), diff --git a/test/functional/p2p_ibd_txrelay.py b/test/functional/p2p_ibd_txrelay.py index 870324d76c3..0cd0ac05b2c 100755 --- a/test/functional/p2p_ibd_txrelay.py +++ b/test/functional/p2p_ibd_txrelay.py @@ -28,8 +28,8 @@ from test_framework.p2p import ( ) from test_framework.test_framework import BitcoinTestFramework -MAX_FEE_FILTER = Decimal(9170997) / COIN -NORMAL_FEE_FILTER = Decimal(100) / COIN +MAX_FEE_FILTER = Decimal(9936506) / COIN +NORMAL_FEE_FILTER = Decimal(10) / COIN class P2PIBDTxRelayTest(BitcoinTestFramework): @@ -37,8 +37,8 @@ class P2PIBDTxRelayTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [ - ["-minrelaytxfee={}".format(NORMAL_FEE_FILTER)], - ["-minrelaytxfee={}".format(NORMAL_FEE_FILTER)], + ["-minrelaytxfee={:.8f}".format(NORMAL_FEE_FILTER)], + ["-minrelaytxfee={:.8f}".format(NORMAL_FEE_FILTER)], ] def run_test(self): diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index d75d6b40e20..ef4440b9ecb 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -13,10 +13,12 @@ import time from test_framework.blocktools import MAX_STANDARD_TX_WEIGHT from test_framework.mempool_util import ( create_large_orphan, + DEFAULT_MIN_RELAY_TX_FEE, fill_mempool, ) from test_framework.messages import ( CInv, + COIN, COutPoint, CTransaction, CTxIn, @@ -79,13 +81,13 @@ class PackageRelayTest(BitcoinTestFramework): ]] def create_tx_below_mempoolminfee(self, wallet, utxo_to_spend=None): - """Create a 1-input 1sat/vB transaction using a confirmed UTXO. Decrement and use + """Create a 1-input 0.1sat/vB transaction using a confirmed UTXO. Decrement and use self.sequence so that subsequent calls to this function result in unique transactions.""" self.sequence -= 1 - assert_greater_than(self.nodes[0].getmempoolinfo()["mempoolminfee"], FEERATE_1SAT_VB) + assert_greater_than(self.nodes[0].getmempoolinfo()["mempoolminfee"], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN) - return wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB, sequence=self.sequence, utxo_to_spend=utxo_to_spend, confirmed_only=True) + return wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN, sequence=self.sequence, utxo_to_spend=utxo_to_spend, confirmed_only=True) @cleanup def test_basic_child_then_parent(self): diff --git a/test/functional/test_framework/mempool_util.py b/test/functional/test_framework/mempool_util.py index b60c14cf7c1..901a4ed62e6 100644 --- a/test/functional/test_framework/mempool_util.py +++ b/test/functional/test_framework/mempool_util.py @@ -3,7 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Helpful routines for mempool testing.""" -from decimal import Decimal import random from .blocktools import ( @@ -30,6 +29,11 @@ from .wallet import ( MiniWallet, ) +# Default for -minrelaytxfee in sat/kvB +DEFAULT_MIN_RELAY_TX_FEE = 100 +# Default for -incrementalrelayfee in sat/kvB +DEFAULT_INCREMENTAL_RELAY_FEE = 100 + def assert_mempool_contents(test_framework, node, expected=None, sync=True): """Assert that all transactions in expected are in the mempool, and no additional ones exist. 'expected' is an array of @@ -57,9 +61,7 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None): """ test_framework.log.info("Fill the mempool until eviction is triggered and the mempoolminfee rises") txouts = gen_return_txouts() - relayfee = node.getnetworkinfo()['relayfee'] - - assert_equal(relayfee, Decimal('0.00001000')) + minrelayfee = node.getnetworkinfo()['relayfee'] tx_batch_size = 1 num_of_batches = 75 @@ -79,7 +81,7 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None): test_framework.log.debug("Create a mempool tx that will be evicted") tx_to_be_evicted_id = ephemeral_miniwallet.send_self_transfer( - from_node=node, utxo_to_spend=confirmed_utxos.pop(0), fee_rate=relayfee)["txid"] + from_node=node, utxo_to_spend=confirmed_utxos.pop(0), fee_rate=minrelayfee)["txid"] def send_batch(fee): utxos = confirmed_utxos[:tx_batch_size] @@ -89,14 +91,14 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None): # Increase the tx fee rate to give the subsequent transactions a higher priority in the mempool # The tx has an approx. vsize of 65k, i.e. multiplying the previous fee rate (in sats/kvB) # by 130 should result in a fee that corresponds to 2x of that fee rate - base_fee = relayfee * 130 + base_fee = minrelayfee * 130 batch_fees = [(i + 1) * base_fee for i in range(num_of_batches)] test_framework.log.debug("Fill up the mempool with txs with higher fee rate") for fee in batch_fees[:-3]: send_batch(fee) tx_sync_fun() if tx_sync_fun else test_framework.sync_mempools() # sync before any eviction - assert_equal(node.getmempoolinfo()["mempoolminfee"], Decimal("0.00001000")) + assert_equal(node.getmempoolinfo()["mempoolminfee"], minrelayfee) for fee in batch_fees[-3:]: send_batch(fee) tx_sync_fun() if tx_sync_fun else test_framework.sync_mempools() # sync after all evictions @@ -108,8 +110,8 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None): assert tx_to_be_evicted_id not in node.getrawmempool() test_framework.log.debug("Check that mempoolminfee is larger than minrelaytxfee") - assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000')) - assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000')) + assert_equal(node.getmempoolinfo()['minrelaytxfee'], minrelayfee) + assert_greater_than(node.getmempoolinfo()['mempoolminfee'], minrelayfee) def tx_in_orphanage(node, tx: CTransaction) -> bool: """Returns true if the transaction is in the orphanage.""" diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 05965caacd3..097c39575a3 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -535,7 +535,7 @@ def test_dust_to_fee(self, rbf_node, dest_address): def test_settxfee(self, rbf_node, dest_address): self.log.info('Test settxfee') - assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.000005')) + assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.0000005')) assert_raises_rpc_error(-8, "txfee cannot be less than wallet min fee", rbf_node.settxfee, Decimal('0.000015')) # check that bumpfee reacts correctly to the use of settxfee (paytxfee) rbfid = spend_one_input(rbf_node, dest_address) @@ -850,7 +850,7 @@ def test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, # Ensure you can not fee bump if the fee_rate is more than original fee_rate but the total fee from new fee_rate is # less than (original fee + incrementalrelayfee) - assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2.8}) + assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2.05}) # You can fee bump as long as the new fee set from fee_rate is at least (original fee + incrementalrelayfee) rbf_node.bumpfee(tx["txid"], {"fee_rate": 3}) diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index 2d5c5a2d993..7cf92876b3f 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -43,7 +43,8 @@ class RawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 self.extra_args = [[ - "-deprecatedrpc=settxfee" + "-deprecatedrpc=settxfee", + "-minrelaytxfee=0.00001000", ] for i in range(self.num_nodes)] self.setup_clean_chain = True # whitelist peers to speed up tx relay / mempool sync