@@ -633,9 +633,9 @@ class MemPoolAccept
633
633
CTxMemPool::setEntries m_iters_conflicting;
634
634
/* * All mempool ancestors of this transaction. */
635
635
CTxMemPool::setEntries m_ancestors;
636
- /* * Mempool entry constructed for this transaction. Constructed in PreChecks() but not
637
- * inserted into the mempool until Finalize(). */
638
- std::unique_ptr<CTxMemPoolEntry> m_entry ;
636
+ /* Changeset representing adding a transaction and removing its conflicts. */
637
+ std::unique_ptr<CTxMemPool::ChangeSet> m_changeset;
638
+ CTxMemPool::ChangeSet::TxHandle m_tx_handle ;
639
639
/* * Whether RBF-related data structures (m_conflicts, m_iters_conflicting, m_all_conflicting,
640
640
* m_replaced_transactions) include a sibling in addition to txns with conflicting inputs. */
641
641
bool m_sibling_eviction{false };
@@ -780,7 +780,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
780
780
781
781
// Alias what we need out of ws
782
782
TxValidationState& state = ws.m_state ;
783
- std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry ;
784
783
785
784
if (!CheckTransaction (tx, state)) {
786
785
return false ; // state filled in by CheckTransaction
@@ -909,9 +908,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
909
908
// Set entry_sequence to 0 when bypass_limits is used; this allows txs from a block
910
909
// reorg to be marked earlier than any child txs that were already in the mempool.
911
910
const uint64_t entry_sequence = bypass_limits ? 0 : m_pool.GetSequence ();
912
- entry.reset (new CTxMemPoolEntry (ptx, ws.m_base_fees , nAcceptTime, m_active_chainstate.m_chain .Height (), entry_sequence,
913
- fSpendsCoinbase , nSigOpsCost, lock_points.value ()));
914
- ws.m_vsize = entry->GetTxSize ();
911
+ ws.m_changeset = m_pool.GetChangeSet ();
912
+ ws.m_tx_handle = ws.m_changeset ->StageAddition (ptx, ws.m_base_fees , nAcceptTime, m_active_chainstate.m_chain .Height (), entry_sequence, fSpendsCoinbase , nSigOpsCost, lock_points.value ());
913
+
914
+ ws.m_vsize = ws.m_tx_handle ->GetTxSize ();
915
915
916
916
// Enforces 0-fee for dust transactions, no incentive to be mined alone
917
917
if (m_pool.m_opts .require_standard ) {
@@ -983,7 +983,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
983
983
maybe_rbf_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants ();
984
984
}
985
985
986
- if (auto ancestors{m_pool. CalculateMemPoolAncestors (*entry , maybe_rbf_limits)}) {
986
+ if (auto ancestors{ws. m_changeset -> CalculateMemPoolAncestors (ws. m_tx_handle , maybe_rbf_limits)}) {
987
987
ws.m_ancestors = std::move (*ancestors);
988
988
} else {
989
989
// If CalculateMemPoolAncestors fails second time, we want the original error string.
@@ -1015,7 +1015,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
1015
1015
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx ->version == TRUC_VERSION) {
1016
1016
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " too-long-mempool-chain" , error_message);
1017
1017
}
1018
- if (auto ancestors_retry{m_pool. CalculateMemPoolAncestors (*entry , cpfp_carve_out_limits)}) {
1018
+ if (auto ancestors_retry{ws. m_changeset -> CalculateMemPoolAncestors (ws. m_tx_handle , cpfp_carve_out_limits)}) {
1019
1019
ws.m_ancestors = std::move (*ancestors_retry);
1020
1020
} else {
1021
1021
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " too-long-mempool-chain" , error_message);
@@ -1114,6 +1114,11 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1114
1114
return state.Invalid (TxValidationResult::TX_RECONSIDERABLE,
1115
1115
strprintf (" insufficient fee%s" , ws.m_sibling_eviction ? " (including sibling eviction)" : " " ), *err_string);
1116
1116
}
1117
+
1118
+ // Add all the to-be-removed transactions to the changeset.
1119
+ for (auto it : m_subpackage.m_all_conflicts ) {
1120
+ ws.m_changeset ->StageRemoval (it);
1121
+ }
1117
1122
return true ;
1118
1123
}
1119
1124
@@ -1173,7 +1178,9 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
1173
1178
" package RBF failed: too many potential replacements" , *err_string);
1174
1179
}
1175
1180
1181
+
1176
1182
for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts ) {
1183
+ parent_ws.m_changeset ->StageRemoval (it);
1177
1184
m_subpackage.m_conflicting_fees += it->GetModifiedFee ();
1178
1185
m_subpackage.m_conflicting_size += it->GetTxSize ();
1179
1186
}
@@ -1283,7 +1290,6 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
1283
1290
const uint256& hash = ws.m_hash ;
1284
1291
TxValidationState& state = ws.m_state ;
1285
1292
const bool bypass_limits = args.m_bypass_limits ;
1286
- std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry ;
1287
1293
1288
1294
if (!m_subpackage.m_all_conflicts .empty ()) Assume (args.m_allow_replacement );
1289
1295
// Remove conflicting transactions from the mempool
@@ -1296,25 +1302,23 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
1296
1302
it->GetTxSize (),
1297
1303
hash.ToString (),
1298
1304
tx.GetWitnessHash ().ToString (),
1299
- entry ->GetFee (),
1300
- entry ->GetTxSize ());
1305
+ ws. m_tx_handle ->GetFee (),
1306
+ ws. m_tx_handle ->GetTxSize ());
1301
1307
TRACEPOINT (mempool, replaced,
1302
1308
it->GetTx ().GetHash ().data (),
1303
1309
it->GetTxSize (),
1304
1310
it->GetFee (),
1305
1311
std::chrono::duration_cast<std::chrono::duration<std::uint64_t >>(it->GetTime ()).count (),
1306
1312
hash.data (),
1307
- entry ->GetTxSize (),
1308
- entry ->GetFee ()
1313
+ ws. m_tx_handle ->GetTxSize (),
1314
+ ws. m_tx_handle ->GetFee ()
1309
1315
);
1310
1316
m_subpackage.m_replaced_transactions .push_back (it->GetSharedTx ());
1311
1317
}
1312
- m_pool. RemoveStaged (m_subpackage. m_all_conflicts , false , MemPoolRemovalReason::REPLACED );
1318
+ ws. m_changeset -> Apply ( );
1313
1319
// Don't attempt to process the same conflicts repeatedly during subpackage evaluation:
1314
- // they no longer exist on subsequent calls to Finalize() post-RemoveStaged
1320
+ // they no longer exist on subsequent calls to Finalize() post-Apply()
1315
1321
m_subpackage.m_all_conflicts .clear ();
1316
- // Store transaction in memory
1317
- m_pool.addUnchecked (*entry, ws.m_ancestors );
1318
1322
1319
1323
// trim mempool and check if tx was trimmed
1320
1324
// If we are validating a package, don't trim here because we could evict a previous transaction
@@ -1359,7 +1363,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
1359
1363
// Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the
1360
1364
// last calculation done in PreChecks, since package ancestors have already been submitted.
1361
1365
{
1362
- auto ancestors{m_pool. CalculateMemPoolAncestors (* ws.m_entry , m_pool.m_opts .limits )};
1366
+ auto ancestors{ws. m_changeset -> CalculateMemPoolAncestors (ws.m_tx_handle , m_pool.m_opts .limits )};
1363
1367
if (!ancestors) {
1364
1368
results.emplace (ws.m_ptx ->GetWitnessHash (), MempoolAcceptResult::Failure (ws.m_state ));
1365
1369
// Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
@@ -1400,6 +1404,8 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
1400
1404
1401
1405
// Add successful results. The returned results may change later if LimitMempoolSize() evicts them.
1402
1406
for (Workspace& ws : workspaces) {
1407
+ auto iter = m_pool.GetIter (ws.m_ptx ->GetHash ());
1408
+ Assume (iter.has_value ());
1403
1409
const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
1404
1410
CFeeRate{ws.m_modified_fees , static_cast <uint32_t >(ws.m_vsize )};
1405
1411
const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
@@ -1410,7 +1416,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
1410
1416
if (!m_pool.m_opts .signals ) continue ;
1411
1417
const CTransaction& tx = *ws.m_ptx ;
1412
1418
const auto tx_info = NewMempoolTransactionInfo (ws.m_ptx , ws.m_base_fees ,
1413
- ws.m_vsize , ws. m_entry ->GetHeight (),
1419
+ ws.m_vsize , (*iter) ->GetHeight (),
1414
1420
args.m_bypass_limits , args.m_package_submission ,
1415
1421
IsCurrentForFeeEstimation (m_active_chainstate),
1416
1422
m_pool.HasNoInputsOf (tx));
@@ -1481,8 +1487,10 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1481
1487
1482
1488
if (m_pool.m_opts .signals ) {
1483
1489
const CTransaction& tx = *ws.m_ptx ;
1490
+ auto iter = m_pool.GetIter (tx.GetHash ());
1491
+ Assume (iter.has_value ());
1484
1492
const auto tx_info = NewMempoolTransactionInfo (ws.m_ptx , ws.m_base_fees ,
1485
- ws.m_vsize , ws. m_entry ->GetHeight (),
1493
+ ws.m_vsize , (*iter) ->GetHeight (),
1486
1494
args.m_bypass_limits , args.m_package_submission ,
1487
1495
IsCurrentForFeeEstimation (m_active_chainstate),
1488
1496
m_pool.HasNoInputsOf (tx));
0 commit comments