Skip to content

Commit f34fe08

Browse files
committed
Merge bitcoin/bitcoin#31122: cluster mempool: Implement changeset interface for mempool
5736d1d tracing: pass if replaced by tx/pkg to tracepoint (0xb10c) a4ec07f doc: add comments for CTxMemPool::ChangeSet (Suhas Daftuar) 83f814b Remove m_all_conflicts from SubPackageState (Suhas Daftuar) d3c8e7d Ensure that we don't add duplicate transactions in rbf fuzz tests (Suhas Daftuar) d7dc9fd Move CalculateChunksForRBF() to the mempool changeset (Suhas Daftuar) 284a1d3 Move prioritisation into changeset (Suhas Daftuar) 446b08b Don't distinguish between direct conflicts and all conflicts when doing cluster-size-2-rbf checks (Suhas Daftuar) b530410 Duplicate transactions are not permitted within a changeset (Suhas Daftuar) b447416 Public mempool removal methods Assume() no changeset is outstanding (Suhas Daftuar) 2b30f4d Make RemoveStaged() private (Suhas Daftuar) 1882919 Enforce that there is only one changeset at a time (Suhas Daftuar) 7fb62f7 Apply mempool changeset transactions directly into the mempool (Suhas Daftuar) 34b6c58 Clean up FinalizeSubpackage to avoid workspace-specific information (Suhas Daftuar) 57983b8 Move LimitMempoolSize to take place outside FinalizeSubpackage (Suhas Daftuar) 01e145b Move changeset from workspace to subpackage (Suhas Daftuar) 802214c Introduce mempool changesets (Suhas Daftuar) 87d92fa test: Add unit test coverage of package rbf + prioritisetransaction (Suhas Daftuar) 15d982f Add package hash to package-rbf log message (Suhas Daftuar) Pull request description: part of cluster mempool: #30289 It became clear while working on cluster mempool that it would be helpful for transaction validation if we could consider a full set of proposed changes to the mempool -- consisting of a set of transactions to add, and a set of transactions (ie conflicts) to simultaneously remove -- and perform calculations on what the mempool would look like if the proposed changes were to be applied. Two specific examples of where we'd like to do this: - Determining if ancestor/descendant/TRUC limits would be violated (in the future, cluster limits) if either a single transaction or a package of transactions were to be accepted - Determining if an RBF would make the mempool "better", however that idea is defined, both in the single transaction and package of transaction cases In preparation for cluster mempool, I have pulled this reworking of the mempool interface out of #28676 so it can be reviewed on its own. I have not re-implemented ancestor/descendant limits to be run through the changeset, since with cluster mempool those limits will be going away, so this seems like wasted effort. However, I have rebased #28676 on top of this branch so reviewers can see what the new mempool interface could look like in the cluster mempool setting. There are some minor behavior changes here, which I believe are inconsequential: - In the package validation setting, transactions would be added to the mempool before the `ConsensusScriptChecks()` are run. In theory, `ConsensusScriptChecks()` should always pass if the `PolicyScriptChecks()` have passed and it's just a belt-and-suspenders for us, but if somehow they were to diverge then there could be some small behavior change from adding transactions and then removing them, versus never adding them at all. - The error reporting on `CheckConflictTopology()` has slightly changed due to no longer distinguishing between direct conflicts and indirect conflicts. I believe this should be entirely inconsequential because there shouldn't be a logical difference between those two ideas from the perspective of this function, but I did have to update some error strings in some tests. - Because, in a package setting, RBFs now happen as part of the entire package being accepted, the logging has changed slightly because we do not know which transaction specifically evicted a given removed transaction. - Specifically, the "package hash" is now used to reference the set of transactions that are being accepted, rather than any single txid. The log message relating to package RBF that happen in the `TXPACKAGES` category has been updated as well to include the package hash, so that it's possible to see which specific set of transactions are being referenced by that package hash. - Relatedly, the tracepoint logging in the package rbf case has been updated as well to reference the package hash, rather than a transaction hash. ACKs for top commit: naumenkogs: ACK bitcoin/bitcoin@5736d1d instagibbs: ACK 5736d1d ismaelsadeeq: reACK 5736d1d glozow: ACK 5736d1d Tree-SHA512: 21810872e082920d337c89ac406085aa71c5f8e5151ab07aedf41e6601f60a909b22fbf462ef3b735d5d5881e9b76142c53957158e674dd5dfe6f6aabbdf630b
2 parents b2d952c + 5736d1d commit f34fe08

26 files changed

+699
-396
lines changed

doc/tracing.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,14 +245,15 @@ Arguments passed:
245245
2. Replaced transaction virtual size as `int32`
246246
3. Replaced transaction fee as `int64`
247247
4. Replaced transaction mempool entry time (epoch) as `uint64`
248-
5. Replacement transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
248+
5. Replacement transaction ID or package hash as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
249249
6. Replacement transaction virtual size as `int32`
250250
7. Replacement transaction fee as `int64`
251+
8. `bool` indicating if the argument 5. is a transaction ID or package hash (true if it's a transaction ID)
251252

252-
Note: In cases where a single replacement transaction replaces multiple
253+
Note: In cases where a replacement transaction or package replaces multiple
253254
existing transactions in the mempool, the tracepoint is called once for each
254-
replaced transaction, with data of the replacement transaction being the same
255-
in each call.
255+
replaced transaction, with data of the replacement transaction or package
256+
being the same in each call.
256257

257258
#### Tracepoint `mempool:rejected`
258259

src/bench/mempool_ephemeral_spends.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <script/script.h>
1212
#include <sync.h>
1313
#include <test/util/setup_common.h>
14+
#include <test/util/txmempool.h>
1415
#include <txmempool.h>
1516
#include <util/check.h>
1617

@@ -28,7 +29,7 @@ static void AddTx(const CTransactionRef& tx, CTxMemPool& pool) EXCLUSIVE_LOCKS_R
2829
unsigned int sigOpCost{4};
2930
uint64_t fee{0};
3031
LockPoints lp;
31-
pool.addUnchecked(CTxMemPoolEntry(
32+
AddToMempool(pool, CTxMemPoolEntry(
3233
tx, fee, nTime, nHeight, sequence,
3334
spendsCoinbase, sigOpCost, lp));
3435
}

src/bench/mempool_eviction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <script/script.h>
1111
#include <sync.h>
1212
#include <test/util/setup_common.h>
13+
#include <test/util/txmempool.h>
1314
#include <txmempool.h>
1415
#include <util/check.h>
1516

@@ -26,7 +27,7 @@ static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& po
2627
bool spendsCoinbase = false;
2728
unsigned int sigOpCost = 4;
2829
LockPoints lp;
29-
pool.addUnchecked(CTxMemPoolEntry(
30+
AddToMempool(pool, CTxMemPoolEntry(
3031
tx, nFee, nTime, nHeight, sequence,
3132
spendsCoinbase, sigOpCost, lp));
3233
}

src/bench/mempool_stress.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <script/script.h>
1111
#include <sync.h>
1212
#include <test/util/setup_common.h>
13+
#include <test/util/txmempool.h>
1314
#include <txmempool.h>
1415
#include <validation.h>
1516

@@ -28,7 +29,7 @@ static void AddTx(const CTransactionRef& tx, CTxMemPool& pool) EXCLUSIVE_LOCKS_R
2829
bool spendsCoinbase = false;
2930
unsigned int sigOpCost = 4;
3031
LockPoints lp;
31-
pool.addUnchecked(CTxMemPoolEntry(tx, 1000, nTime, nHeight, sequence, spendsCoinbase, sigOpCost, lp));
32+
AddToMempool(pool, CTxMemPoolEntry(tx, 1000, nTime, nHeight, sequence, spendsCoinbase, sigOpCost, lp));
3233
}
3334

3435
struct Available {

src/bench/rpc_mempool.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <script/script.h>
1111
#include <sync.h>
1212
#include <test/util/setup_common.h>
13+
#include <test/util/txmempool.h>
1314
#include <txmempool.h>
1415
#include <univalue.h>
1516
#include <util/check.h>
@@ -21,7 +22,7 @@
2122
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
2223
{
2324
LockPoints lp;
24-
pool.addUnchecked(CTxMemPoolEntry(tx, fee, /*time=*/0, /*entry_height=*/1, /*entry_sequence=*/0, /*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
25+
AddToMempool(pool, CTxMemPoolEntry(tx, fee, /*time=*/0, /*entry_height=*/1, /*entry_sequence=*/0, /*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
2526
}
2627

2728
static void RpcMempool(benchmark::Bench& bench)

src/policy/rbf.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,10 @@ std::optional<std::string> PaysForRBF(CAmount original_fees,
184184
return std::nullopt;
185185
}
186186

187-
std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool& pool,
188-
const CTxMemPool::setEntries& direct_conflicts,
189-
const CTxMemPool::setEntries& all_conflicts,
190-
CAmount replacement_fees,
191-
int64_t replacement_vsize)
187+
std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool::ChangeSet& changeset)
192188
{
193189
// Require that the replacement strictly improves the mempool's feerate diagram.
194-
const auto chunk_results{pool.CalculateChunksForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};
190+
const auto chunk_results{changeset.CalculateChunksForRBF()};
195191

196192
if (!chunk_results.has_value()) {
197193
return std::make_pair(DiagramCheckError::UNCALCULABLE, util::ErrorString(chunk_results).original);

src/policy/rbf.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,9 @@ std::optional<std::string> PaysForRBF(CAmount original_fees,
117117

118118
/**
119119
* The replacement transaction must improve the feerate diagram of the mempool.
120-
* @param[in] pool The mempool.
121-
* @param[in] direct_conflicts Set of in-mempool txids corresponding to the direct conflicts i.e.
122-
* input double-spends with the proposed transaction
123-
* @param[in] all_conflicts Set of mempool entries corresponding to all transactions to be evicted
124-
* @param[in] replacement_fees Fees of proposed replacement package
125-
* @param[in] replacement_vsize Size of proposed replacement package
120+
* @param[in] changeset The changeset containing proposed additions/removals
126121
* @returns error type and string if mempool diagram doesn't improve, otherwise std::nullopt.
127122
*/
128-
std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool& pool,
129-
const CTxMemPool::setEntries& direct_conflicts,
130-
const CTxMemPool::setEntries& all_conflicts,
131-
CAmount replacement_fees,
132-
int64_t replacement_vsize)
133-
EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
123+
std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool::ChangeSet& changeset);
134124

135125
#endif // BITCOIN_POLICY_RBF_H

src/test/blockencodings_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
6767
CBlock block(BuildBlockTestCase(rand_ctx));
6868

6969
LOCK2(cs_main, pool.cs);
70-
pool.addUnchecked(entry.FromTx(block.vtx[2]));
70+
AddToMempool(pool, entry.FromTx(block.vtx[2]));
7171
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
7272

7373
// Do a simple ShortTxIDs RT
@@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
151151
CBlock block(BuildBlockTestCase(rand_ctx));
152152

153153
LOCK2(cs_main, pool.cs);
154-
pool.addUnchecked(entry.FromTx(block.vtx[2]));
154+
AddToMempool(pool, entry.FromTx(block.vtx[2]));
155155
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
156156

157157
uint256 txhash;
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
222222
CBlock block(BuildBlockTestCase(rand_ctx));
223223

224224
LOCK2(cs_main, pool.cs);
225-
pool.addUnchecked(entry.FromTx(block.vtx[1]));
225+
AddToMempool(pool, entry.FromTx(block.vtx[1]));
226226
BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
227227

228228
uint256 txhash;
@@ -322,7 +322,7 @@ BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) {
322322
extra_txn.resize(10);
323323

324324
LOCK2(cs_main, pool.cs);
325-
pool.addUnchecked(entry.FromTx(block.vtx[2]));
325+
AddToMempool(pool, entry.FromTx(block.vtx[2]));
326326
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
327327
// Ensure the non_block_tx is actually not in the block
328328
for (const auto &block_tx : block.vtx) {

src/test/fuzz/mini_miner.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner)
5959
TestMemPoolEntryHelper entry;
6060
const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/100000)};
6161
assert(MoneyRange(fee));
62-
pool.addUnchecked(entry.Fee(fee).FromTx(tx));
62+
AddToMempool(pool, entry.Fee(fee).FromTx(tx));
6363

6464
// All outputs are available to spend
6565
for (uint32_t n{0}; n < num_outputs; ++n) {
@@ -154,7 +154,7 @@ FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
154154
TestMemPoolEntryHelper entry;
155155
const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/100000)};
156156
assert(MoneyRange(fee));
157-
pool.addUnchecked(entry.Fee(fee).FromTx(tx));
157+
AddToMempool(pool, entry.Fee(fee).FromTx(tx));
158158
transactions.push_back(tx);
159159
}
160160
std::vector<COutPoint> outpoints;

src/test/fuzz/partially_downloaded_block.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
7878

7979
if (add_to_mempool && !pool.exists(GenTxid::Txid(tx->GetHash()))) {
8080
LOCK2(cs_main, pool.cs);
81-
pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx));
81+
AddToMempool(pool, ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx));
8282
available.insert(i);
8383
}
8484
}

0 commit comments

Comments
 (0)