@@ -633,9 +633,9 @@ class MemPoolAccept
633633 CTxMemPool::setEntries m_iters_conflicting;
634634 /* * All mempool ancestors of this transaction. */
635635 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 ;
639639 /* * Whether RBF-related data structures (m_conflicts, m_iters_conflicting, m_all_conflicting,
640640 * m_replaced_transactions) include a sibling in addition to txns with conflicting inputs. */
641641 bool m_sibling_eviction{false };
@@ -780,7 +780,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
780780
781781 // Alias what we need out of ws
782782 TxValidationState& state = ws.m_state ;
783- std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry ;
784783
785784 if (!CheckTransaction (tx, state)) {
786785 return false ; // state filled in by CheckTransaction
@@ -909,9 +908,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
909908 // Set entry_sequence to 0 when bypass_limits is used; this allows txs from a block
910909 // reorg to be marked earlier than any child txs that were already in the mempool.
911910 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 ();
915915
916916 // Enforces 0-fee for dust transactions, no incentive to be mined alone
917917 if (m_pool.m_opts .require_standard ) {
@@ -983,7 +983,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
983983 maybe_rbf_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants ();
984984 }
985985
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)}) {
987987 ws.m_ancestors = std::move (*ancestors);
988988 } else {
989989 // If CalculateMemPoolAncestors fails second time, we want the original error string.
@@ -1015,7 +1015,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
10151015 if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx ->version == TRUC_VERSION) {
10161016 return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " too-long-mempool-chain" , error_message);
10171017 }
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)}) {
10191019 ws.m_ancestors = std::move (*ancestors_retry);
10201020 } else {
10211021 return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " too-long-mempool-chain" , error_message);
@@ -1114,6 +1114,11 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
11141114 return state.Invalid (TxValidationResult::TX_RECONSIDERABLE,
11151115 strprintf (" insufficient fee%s" , ws.m_sibling_eviction ? " (including sibling eviction)" : " " ), *err_string);
11161116 }
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+ }
11171122 return true ;
11181123}
11191124
@@ -1173,7 +1178,9 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
11731178 " package RBF failed: too many potential replacements" , *err_string);
11741179 }
11751180
1181+
11761182 for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts ) {
1183+ parent_ws.m_changeset ->StageRemoval (it);
11771184 m_subpackage.m_conflicting_fees += it->GetModifiedFee ();
11781185 m_subpackage.m_conflicting_size += it->GetTxSize ();
11791186 }
@@ -1283,7 +1290,6 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
12831290 const uint256& hash = ws.m_hash ;
12841291 TxValidationState& state = ws.m_state ;
12851292 const bool bypass_limits = args.m_bypass_limits ;
1286- std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry ;
12871293
12881294 if (!m_subpackage.m_all_conflicts .empty ()) Assume (args.m_allow_replacement );
12891295 // Remove conflicting transactions from the mempool
@@ -1296,25 +1302,23 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
12961302 it->GetTxSize (),
12971303 hash.ToString (),
12981304 tx.GetWitnessHash ().ToString (),
1299- entry ->GetFee (),
1300- entry ->GetTxSize ());
1305+ ws. m_tx_handle ->GetFee (),
1306+ ws. m_tx_handle ->GetTxSize ());
13011307 TRACEPOINT (mempool, replaced,
13021308 it->GetTx ().GetHash ().data (),
13031309 it->GetTxSize (),
13041310 it->GetFee (),
13051311 std::chrono::duration_cast<std::chrono::duration<std::uint64_t >>(it->GetTime ()).count (),
13061312 hash.data (),
1307- entry ->GetTxSize (),
1308- entry ->GetFee ()
1313+ ws. m_tx_handle ->GetTxSize (),
1314+ ws. m_tx_handle ->GetFee ()
13091315 );
13101316 m_subpackage.m_replaced_transactions .push_back (it->GetSharedTx ());
13111317 }
1312- m_pool. RemoveStaged (m_subpackage. m_all_conflicts , false , MemPoolRemovalReason::REPLACED );
1318+ ws. m_changeset -> Apply ( );
13131319 // 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()
13151321 m_subpackage.m_all_conflicts .clear ();
1316- // Store transaction in memory
1317- m_pool.addUnchecked (*entry, ws.m_ancestors );
13181322
13191323 // trim mempool and check if tx was trimmed
13201324 // 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>&
13591363 // Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the
13601364 // last calculation done in PreChecks, since package ancestors have already been submitted.
13611365 {
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 )};
13631367 if (!ancestors) {
13641368 results.emplace (ws.m_ptx ->GetWitnessHash (), MempoolAcceptResult::Failure (ws.m_state ));
13651369 // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
@@ -1400,6 +1404,8 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
14001404
14011405 // Add successful results. The returned results may change later if LimitMempoolSize() evicts them.
14021406 for (Workspace& ws : workspaces) {
1407+ auto iter = m_pool.GetIter (ws.m_ptx ->GetHash ());
1408+ Assume (iter.has_value ());
14031409 const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
14041410 CFeeRate{ws.m_modified_fees , static_cast <uint32_t >(ws.m_vsize )};
14051411 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>&
14101416 if (!m_pool.m_opts .signals ) continue ;
14111417 const CTransaction& tx = *ws.m_ptx ;
14121418 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 (),
14141420 args.m_bypass_limits , args.m_package_submission ,
14151421 IsCurrentForFeeEstimation (m_active_chainstate),
14161422 m_pool.HasNoInputsOf (tx));
@@ -1481,8 +1487,10 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
14811487
14821488 if (m_pool.m_opts .signals ) {
14831489 const CTransaction& tx = *ws.m_ptx ;
1490+ auto iter = m_pool.GetIter (tx.GetHash ());
1491+ Assume (iter.has_value ());
14841492 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 (),
14861494 args.m_bypass_limits , args.m_package_submission ,
14871495 IsCurrentForFeeEstimation (m_active_chainstate),
14881496 m_pool.HasNoInputsOf (tx));
0 commit comments