mirror of https://github.com/bitcoin/bitcoin.git
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: utACK0034dcfba9
marcofleon: ACK0034dcfba9
murchandamus: crACK0034dcfba9
brunoerg: crACK0034dcfba9
Tree-SHA512: 1b7540ac3fec5b15cf36926dbf633054f14549d76aa445a2bf042b5667e8637db4f9c21c869af25a0c3f8c7cca6c585d17896d2f7e95a6264c1ff59817446694
This commit is contained in:
commit
89fe999cda
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>())
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(), [])
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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__":
|
||||
|
|
|
@ -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']]
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue