Merge bitcoin/bitcoin#33226: [29.x] 33106 backport and final changes for rc2

0034dcfba9 [doc] man pages for 29.1rc2 (glozow)
eb1574af0c [build] bump version to 29.1rc2 (glozow)
f9f1ca5445 [doc] update release notes (glozow)
9dd7efc8c3 [policy] lower default minrelaytxfee and incrementalrelayfee to 100sat/kvB (glozow)
bbdab3ef7b [prep/test] make wallet_fundrawtransaction's minrelaytxfee assumption explicit (glozow)
da30ca0efa [prep/util] help MockMempoolMinFee handle more precise feerates (glozow)
a0ae3fc8a7 [prep/test] replace magic number 1000 with respective feerate vars (glozow)
1c1970fb45 [miner] lower default -blockmintxfee to 1sat/kvB (glozow)
3a7e093f94 [doc] assert that default min relay feerate and incremental are the same (glozow)
567c3ee3cb [test] explicitly check default -minrelaytxfee and -incrementalrelayfee (glozow)
6b5396c4b1 [test] RBF rule 4 for various incrementalrelayfee settings (glozow)
03da7aff99 [test] check bypass of minrelay for various minrelaytxfee settings (glozow)
4e3cfa660d [test] check miner doesn't select 0fee transactions (glozow)

Pull request description:

  Backports #33106 and includes final changes for 29.1rc2. Based on current network conditions (in which nodes rejecting 0.1-1sat/vB are missing many transactions), it is recommended to change these policy settings.

  I did not include #32750 because it causes #33177 and I don't foresee any problems; it was just a nice to have.
  For reviewers: the backport is unclean but fairly straightforward. I just had to adapt a test that is no longer in master (#32973) and include `-datacarriersize` in order to pad transaction size (#32406).

ACKs for top commit:
  dergoegge:
    utACK 0034dcfba9
  marcofleon:
    ACK  0034dcfba9
  murchandamus:
    crACK 0034dcfba9
  brunoerg:
    crACK 0034dcfba9

Tree-SHA512: 1b7540ac3fec5b15cf36926dbf633054f14549d76aa445a2bf042b5667e8637db4f9c21c869af25a0c3f8c7cca6c585d17896d2f7e95a6264c1ff59817446694
This commit is contained in:
merge-script 2025-08-21 12:18:36 +01:00
commit 89fe999cda
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1
27 changed files with 237 additions and 106 deletions

View File

@ -30,7 +30,7 @@ set(CLIENT_NAME "Bitcoin Core")
set(CLIENT_VERSION_MAJOR 29)
set(CLIENT_VERSION_MINOR 1)
set(CLIENT_VERSION_BUILD 0)
set(CLIENT_VERSION_RC 1)
set(CLIENT_VERSION_RC 2)
set(CLIENT_VERSION_IS_RELEASE "true")
set(COPYRIGHT_YEAR "2025")

View File

@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-CLI "1" "July 2025" "bitcoin-cli v29.1.0rc1" "User Commands"
.TH BITCOIN-CLI "1" "August 2025" "bitcoin-cli v29.1.0rc2" "User Commands"
.SH NAME
bitcoin-cli \- manual page for bitcoin-cli v29.1.0rc1
bitcoin-cli \- manual page for bitcoin-cli v29.1.0rc2
.SH SYNOPSIS
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR]
@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v29.1.0rc1
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,help <command>\/\fR
.SH DESCRIPTION
Bitcoin Core RPC client version v29.1.0rc1
Bitcoin Core RPC client version v29.1.0rc2
.PP
The bitcoin\-cli utility provides a command line interface to interact with a Bitcoin Core RPC server.
.PP

View File

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-QT "1" "July 2025" "bitcoin-qt v29.1.0rc1" "User Commands"
.TH BITCOIN-QT "1" "August 2025" "bitcoin-qt v29.1.0rc2" "User Commands"
.SH NAME
bitcoin-qt \- manual page for bitcoin-qt v29.1.0rc1
bitcoin-qt \- manual page for bitcoin-qt v29.1.0rc2
.SH SYNOPSIS
.B bitcoin-qt
[\fI\,options\/\fR] [\fI\,URI\/\fR]
.SH DESCRIPTION
Bitcoin Core version v29.1.0rc1
Bitcoin Core version v29.1.0rc2
.PP
The bitcoin\-qt application provides a graphical interface for interacting with Bitcoin Core.
.PP
@ -702,7 +702,7 @@ this size or less (default: 83)
\fB\-minrelaytxfee=\fR<amt>
.IP
Fees (in BTC/kvB) smaller than this are considered zero fee for
relaying, mining and transaction creation (default: 0.00001)
relaying, mining and transaction creation (default: 0.000001)
.HP
\fB\-permitbaremultisig\fR
.IP
@ -729,7 +729,7 @@ Set maximum BIP141 block weight (default: 4000000)
\fB\-blockmintxfee=\fR<amt>
.IP
Set lowest fee rate (in BTC/kvB) for transactions to be included in
block creation. (default: 0.00001)
block creation. (default: 0.00000001)
.HP
\fB\-blockreservedweight=\fR<n>
.IP

View File

@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-TX "1" "July 2025" "bitcoin-tx v29.1.0rc1" "User Commands"
.TH BITCOIN-TX "1" "August 2025" "bitcoin-tx v29.1.0rc2" "User Commands"
.SH NAME
bitcoin-tx \- manual page for bitcoin-tx v29.1.0rc1
bitcoin-tx \- manual page for bitcoin-tx v29.1.0rc2
.SH SYNOPSIS
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR]
@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v29.1.0rc1
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR]
.SH DESCRIPTION
Bitcoin Core bitcoin\-tx utility version v29.1.0rc1
Bitcoin Core bitcoin\-tx utility version v29.1.0rc2
.PP
The bitcoin\-tx tool is used for creating and modifying bitcoin transactions.
.PP

View File

@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-UTIL "1" "July 2025" "bitcoin-util v29.1.0rc1" "User Commands"
.TH BITCOIN-UTIL "1" "August 2025" "bitcoin-util v29.1.0rc2" "User Commands"
.SH NAME
bitcoin-util \- manual page for bitcoin-util v29.1.0rc1
bitcoin-util \- manual page for bitcoin-util v29.1.0rc2
.SH SYNOPSIS
.B bitcoin-util
[\fI\,options\/\fR] [\fI\,command\/\fR]
@ -9,7 +9,7 @@ bitcoin-util \- manual page for bitcoin-util v29.1.0rc1
.B bitcoin-util
[\fI\,options\/\fR] \fI\,grind <hex-block-header>\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-util utility version v29.1.0rc1
Bitcoin Core bitcoin\-util utility version v29.1.0rc2
.PP
The bitcoin\-util tool provides bitcoin related functionality that does not rely on the ability to access a running node. Available [commands] are listed below.
.SH OPTIONS

View File

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-WALLET "1" "July 2025" "bitcoin-wallet v29.1.0rc1" "User Commands"
.TH BITCOIN-WALLET "1" "August 2025" "bitcoin-wallet v29.1.0rc2" "User Commands"
.SH NAME
bitcoin-wallet \- manual page for bitcoin-wallet v29.1.0rc1
bitcoin-wallet \- manual page for bitcoin-wallet v29.1.0rc2
.SH SYNOPSIS
.B bitcoin-wallet
[\fI\,options\/\fR] \fI\,<command>\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-wallet utility version v29.1.0rc1
Bitcoin Core bitcoin\-wallet utility version v29.1.0rc2
.PP
bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files.
.PP

View File

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIND "1" "July 2025" "bitcoind v29.1.0rc1" "User Commands"
.TH BITCOIND "1" "August 2025" "bitcoind v29.1.0rc2" "User Commands"
.SH NAME
bitcoind \- manual page for bitcoind v29.1.0rc1
bitcoind \- manual page for bitcoind v29.1.0rc2
.SH SYNOPSIS
.B bitcoind
[\fI\,options\/\fR]
.SH DESCRIPTION
Bitcoin Core daemon version v29.1.0rc1
Bitcoin Core daemon version v29.1.0rc2
.PP
The Bitcoin Core daemon (bitcoind) is a headless program that connects to the Bitcoin network to validate and relay transactions and blocks, as well as relaying addresses.
.PP
@ -702,7 +702,7 @@ this size or less (default: 83)
\fB\-minrelaytxfee=\fR<amt>
.IP
Fees (in BTC/kvB) smaller than this are considered zero fee for
relaying, mining and transaction creation (default: 0.00001)
relaying, mining and transaction creation (default: 0.000001)
.HP
\fB\-permitbaremultisig\fR
.IP
@ -729,7 +729,7 @@ Set maximum BIP141 block weight (default: 4000000)
\fB\-blockmintxfee=\fR<amt>
.IP
Set lowest fee rate (in BTC/kvB) for transactions to be included in
block creation. (default: 0.00001)
block creation. (default: 0.00000001)
.HP
\fB\-blockreservedweight=\fR<n>
.IP

View File

@ -1,6 +1,6 @@
Bitcoin Core version 29.1rc1 is now available from:
Bitcoin Core version 29.1rc2 is now available from:
<https://bitcoincore.org/bin/bitcoin-core-29.1/test.rc1/>
<https://bitcoincore.org/bin/bitcoin-core-29.1/test.rc2/>
This release includes various bug fixes and performance
improvements, as well as updated translations.
@ -48,6 +48,20 @@ Notable changes
- #32521 policy: make pathological transactions packed with legacy sigops non-standard
- 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.
- 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.
- #33106 policy: lower the default blockmintxfee, incrementalrelayfee, minrelaytxfee
### Logging
Unconditional logging to disk is now rate limited by giving each source location
@ -181,6 +195,7 @@ Thanks to everyone who directly contributed to this release:
- enirox001
- fanquake
- furszy
- glozow
- instagibbs
- Hennadii Stepanov
- hodlinator

View File

@ -65,6 +65,7 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP
}
}
static_assert(DEFAULT_MIN_RELAY_TX_FEE == DEFAULT_INCREMENTAL_RELAY_FEE);
if (argsman.IsArgSet("-minrelaytxfee")) {
if (std::optional<CAmount> min_relay_feerate = ParseMoney(argsman.GetArg("-minrelaytxfee", ""))) {
// High fee check is done afterward in CWallet::Create()

View File

@ -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 */

View File

@ -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(GenTxid::Txid(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(GenTxid::Txid(tx1.GetHash())));
@ -481,8 +481,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
BOOST_CHECK(!pool.exists(GenTxid::Txid(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(GenTxid::Txid(tx7.GetHash())));
if (!pool.exists(GenTxid::Txid(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(GenTxid::Txid(tx4.GetHash())));
@ -553,34 +553,34 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
BOOST_CHECK(!pool.exists(GenTxid::Txid(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<CTransactionRef> 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<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>())

View File

@ -12,6 +12,7 @@
#include <node/miner.h>
#include <policy/policy.h>
#include <test/util/random.h>
#include <test/util/transaction_utils.h>
#include <test/util/txmempool.h>
#include <txmempool.h>
#include <uint256.h>
@ -210,6 +211,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));

View File

@ -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);

View File

@ -39,6 +39,7 @@
#include <streams.h>
#include <test/util/net.h>
#include <test/util/random.h>
#include <test/util/transaction_utils.h>
#include <test/util/txmempool.h>
#include <txdb.h>
#include <txmempool.h>
@ -571,6 +572,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.

View File

@ -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
@ -77,6 +80,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):
@ -583,10 +589,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}", "-datacarriersize=5000", "-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

View File

@ -9,6 +9,10 @@ from decimal import Decimal
import math
from test_framework.test_framework import BitcoinTestFramework
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,
@ -81,6 +85,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))

View File

@ -215,7 +215,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(), [])

View File

@ -94,8 +94,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()
@ -186,8 +185,8 @@ 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'], Decimal('0.00000100'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00000100'))
fill_mempool(self, node)
current_info = node.getmempoolinfo()
@ -216,7 +215,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# coin is no longer available, but the cache could still contains the tx.
cpfp_parent = self.wallet.create_self_transfer(
utxo_to_spend=mempool_evicted_tx["new_utxo"],
fee_rate=mempoolmin_feerate - Decimal('0.00001'),
fee_rate=mempoolmin_feerate / 2,
confirmed_only=True)
package_hex.append(cpfp_parent["hex"])
parent_utxos.append(cpfp_parent["new_utxo"])
@ -231,7 +230,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# Need to be large enough to trigger eviction
# (note that the mempool usage of a tx is about three times its vsize)
assert_greater_than(parent_vsize * num_big_parents * 3, current_info["maxmempool"] - current_info["bytes"])
parent_feerate = 100 * mempoolmin_feerate
parent_feerate = 10 * mempoolmin_feerate
big_parent_txids = []
for i in range(num_big_parents):
@ -250,7 +249,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# Specific number of satoshis to fit within a small window. The parent_cpfp + child package needs to be
# - When there is mid-package eviction, high enough feerate to meet the new mempoolminfee
# - When there is no mid-package eviction, low enough feerate to be evicted immediately after submission.
magic_satoshis = 1200
magic_satoshis = 120
cpfp_satoshis = int(cpfp_fee * COIN) + magic_satoshis
child = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=cpfp_satoshis)
@ -278,8 +277,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()
@ -304,7 +302,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()
@ -352,8 +350,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)
@ -411,9 +408,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()

View File

@ -163,13 +163,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].rehash()}, 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].rehash()}, 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)
@ -563,12 +563,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,
)

View File

@ -10,6 +10,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,
@ -594,12 +595,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()
@ -613,6 +659,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__":

View File

@ -36,6 +36,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,
@ -48,7 +49,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]
def assert_template(node, block, expect, rehash=True):
@ -99,7 +100,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)...")
@ -110,19 +111,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']]

View File

@ -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
@ -51,12 +50,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"]
@ -87,8 +86,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(),

View File

@ -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):

View File

@ -9,10 +9,12 @@ Test opportunistic 1p1c package submission logic.
from decimal import Decimal
import time
from test_framework.mempool_util import (
DEFAULT_MIN_RELAY_TX_FEE,
fill_mempool,
)
from test_framework.messages import (
CInv,
COIN,
CTxInWitness,
MAX_BIP125_RBF_SEQUENCE,
MSG_WTX,
@ -65,13 +67,13 @@ class PackageRelayTest(BitcoinTestFramework):
self.supports_cli = False
def create_tx_below_mempoolminfee(self, wallet):
"""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, confirmed_only=True)
return wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN, sequence=self.sequence, confirmed_only=True)
@cleanup
def test_basic_child_then_parent(self):

View File

@ -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
from .blocktools import (
COINBASE_MATURITY,
@ -20,6 +19,10 @@ from .wallet import (
)
ORPHAN_TX_EXPIRE_TIME = 1200
# 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,
@ -48,9 +51,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
@ -70,7 +71,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]
@ -80,14 +81,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
@ -99,8 +100,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."""

View File

@ -534,7 +534,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)
@ -846,7 +846,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})

View File

@ -44,6 +44,10 @@ class RawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.extra_args = [[
"-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
self.noban_tx_relay = True