@@ -472,8 +472,10 @@ class MemPoolAccept
472472 */
473473 std::vector<COutPoint>& m_coins_to_uncache;
474474 const bool m_test_accept;
475- /* * Disable BIP125 RBFing; disallow all conflicts with mempool transactions. */
476- const bool disallow_mempool_conflicts;
475+ /* * Whether we allow transactions to replace mempool transactions by BIP125 rules. If false,
476+ * any transaction spending the same inputs as a transaction in the mempool is considered
477+ * a conflict. */
478+ const bool m_allow_bip125_replacement{true };
477479 };
478480
479481 // Single transaction acceptance
@@ -482,7 +484,7 @@ class MemPoolAccept
482484 /* *
483485 * Multiple transaction acceptance. Transactions may or may not be interdependent,
484486 * but must not conflict with each other. Parents must come before children if any
485- * dependencies exist, otherwise a TX_MISSING_INPUTS error will be returned .
487+ * dependencies exist.
486488 */
487489 PackageMempoolAcceptResult AcceptMultipleTransactions (const std::vector<CTransactionRef>& txns, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
488490
@@ -619,6 +621,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
619621 {
620622 const CTransaction* ptxConflicting = m_pool.GetConflictTx (txin.prevout );
621623 if (ptxConflicting) {
624+ if (!args.m_allow_bip125_replacement ) {
625+ // Transaction conflicts with a mempool tx, but we're not allowing replacements.
626+ return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " bip125-replacement-disallowed" );
627+ }
622628 if (!setConflicts.count (ptxConflicting->GetHash ()))
623629 {
624630 // Allow opt-out of transaction replacement by setting
@@ -645,7 +651,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
645651 break ;
646652 }
647653 }
648- if (fReplacementOptOut || args. disallow_mempool_conflicts ) {
654+ if (fReplacementOptOut ) {
649655 return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " txn-mempool-conflict" );
650656 }
651657
@@ -1080,65 +1086,15 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
10801086{
10811087 AssertLockHeld (cs_main);
10821088
1089+ // These context-free package limits can be done before taking the mempool lock.
10831090 PackageValidationState package_state;
1084- const unsigned int package_count = txns.size ();
1085-
1086- // These context-free package limits can be checked before taking the mempool lock.
1087- if (package_count > MAX_PACKAGE_COUNT) {
1088- package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-too-many-transactions" );
1089- return PackageMempoolAcceptResult (package_state, {});
1090- }
1091-
1092- const int64_t total_size = std::accumulate (txns.cbegin (), txns.cend (), 0 ,
1093- [](int64_t sum, const auto & tx) { return sum + GetVirtualTransactionSize (*tx); });
1094- // If the package only contains 1 tx, it's better to report the policy violation on individual tx size.
1095- if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000 ) {
1096- package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-too-large" );
1097- return PackageMempoolAcceptResult (package_state, {});
1098- }
1091+ if (!CheckPackage (txns, package_state)) return PackageMempoolAcceptResult (package_state, {});
10991092
1100- // Construct workspaces and check package policies.
11011093 std::vector<Workspace> workspaces{};
1102- workspaces.reserve (package_count);
1103- {
1104- std::unordered_set<uint256, SaltedTxidHasher> later_txids;
1105- std::transform (txns.cbegin (), txns.cend (), std::inserter (later_txids, later_txids.end ()),
1106- [](const auto & tx) { return tx->GetHash (); });
1107- // Require the package to be sorted in order of dependency, i.e. parents appear before children.
1108- // An unsorted package will fail anyway on missing-inputs, but it's better to quit earlier and
1109- // fail on something less ambiguous (missing-inputs could also be an orphan or trying to
1110- // spend nonexistent coins).
1111- for (const auto & tx : txns) {
1112- for (const auto & input : tx->vin ) {
1113- if (later_txids.find (input.prevout .hash ) != later_txids.end ()) {
1114- // The parent is a subsequent transaction in the package.
1115- package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-sorted" );
1116- return PackageMempoolAcceptResult (package_state, {});
1117- }
1118- }
1119- later_txids.erase (tx->GetHash ());
1120- workspaces.emplace_back (Workspace (tx));
1121- }
1122- }
1094+ workspaces.reserve (txns.size ());
1095+ std::transform (txns.cbegin (), txns.cend (), std::back_inserter (workspaces),
1096+ [](const auto & tx) { return Workspace (tx); });
11231097 std::map<const uint256, const MempoolAcceptResult> results;
1124- {
1125- // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package.
1126- std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen;
1127- for (const auto & tx : txns) {
1128- for (const auto & input : tx->vin ) {
1129- if (inputs_seen.find (input.prevout ) != inputs_seen.end ()) {
1130- // This input is also present in another tx in the package.
1131- package_state.Invalid (PackageValidationResult::PCKG_POLICY, " conflict-in-package" );
1132- return PackageMempoolAcceptResult (package_state, {});
1133- }
1134- }
1135- // Batch-add all the inputs for a tx at a time. If we added them 1 at a time, we could
1136- // catch duplicate inputs within a single tx. This is a more severe, consensus error,
1137- // and we want to report that from CheckTransaction instead.
1138- std::transform (tx->vin .cbegin (), tx->vin .cend (), std::inserter (inputs_seen, inputs_seen.end ()),
1139- [](const auto & input) { return input.prevout ; });
1140- }
1141- }
11421098
11431099 LOCK (m_pool.cs );
11441100
@@ -1151,10 +1107,10 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
11511107 return PackageMempoolAcceptResult (package_state, std::move (results));
11521108 }
11531109 // Make the coins created by this transaction available for subsequent transactions in the
1154- // package to spend. Since we already checked conflicts in the package and RBFs are
1155- // impossible , we don't need to track the coins spent. Note that this logic will need to be
1156- // updated if RBFs in packages are allowed in the future.
1157- assert (args.disallow_mempool_conflicts );
1110+ // package to spend. Since we already checked conflicts in the package and we don't allow
1111+ // replacements , we don't need to track the coins spent. Note that this logic will need to be
1112+ // updated if package replace-by-fee is allowed in the future.
1113+ assert (! args.m_allow_bip125_replacement );
11581114 m_viewmempool.PackageAddTransaction (ws.m_ptx );
11591115 }
11601116
@@ -1188,7 +1144,7 @@ static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainp
11881144{
11891145 std::vector<COutPoint> coins_to_uncache;
11901146 MemPoolAccept::ATMPArgs args { chainparams, nAcceptTime, bypass_limits, coins_to_uncache,
1191- test_accept, /* disallow_mempool_conflicts */ false };
1147+ test_accept, /* m_allow_bip125_replacement */ true };
11921148
11931149 assert (std::addressof (::ChainstateActive ()) == std::addressof (active_chainstate));
11941150 const MempoolAcceptResult result = MemPoolAccept (pool, active_chainstate).AcceptSingleTransaction (tx, args);
@@ -1225,12 +1181,11 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx
12251181 std::vector<COutPoint> coins_to_uncache;
12261182 const CChainParams& chainparams = Params ();
12271183 MemPoolAccept::ATMPArgs args { chainparams, GetTime (), /* bypass_limits */ false , coins_to_uncache,
1228- test_accept, /* disallow_mempool_conflicts */ true };
1184+ test_accept, /* m_allow_bip125_replacement */ false };
12291185 assert (std::addressof (::ChainstateActive ()) == std::addressof (active_chainstate));
12301186 const PackageMempoolAcceptResult result = MemPoolAccept (pool, active_chainstate).AcceptMultipleTransactions (package, args);
12311187
12321188 // Uncache coins pertaining to transactions that were not submitted to the mempool.
1233- // Ensure the cache is still within its size limits.
12341189 for (const COutPoint& hashTx : coins_to_uncache) {
12351190 active_chainstate.CoinsTip ().Uncache (hashTx);
12361191 }
0 commit comments