@@ -508,6 +508,19 @@ class MemPoolAccept
508508 };
509509 }
510510
511+ /* * Parameters for a single transaction within a package. */
512+ static ATMPArgs SingleInPackageAccept (const ATMPArgs& package_args) {
513+ return ATMPArgs{/* m_chainparams */ package_args.m_chainparams ,
514+ /* m_accept_time */ package_args.m_accept_time ,
515+ /* m_bypass_limits */ false ,
516+ /* m_coins_to_uncache */ package_args.m_coins_to_uncache ,
517+ /* m_test_accept */ package_args.m_test_accept ,
518+ /* m_allow_bip125_replacement */ true ,
519+ /* m_package_submission */ false ,
520+ /* m_package_feerates */ false , // only 1 transaction
521+ };
522+ }
523+
511524 private:
512525 // Private ctor to avoid exposing details to clients and allowing the possibility of
513526 // mixing up the order of the arguments. Use static functions above instead.
@@ -1328,6 +1341,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
13281341 // transactions that are already in the mempool, and only call AcceptMultipleTransactions() with
13291342 // the new transactions. This ensures we don't double-count transaction counts and sizes when
13301343 // checking ancestor/descendant limits, or double-count transaction fees for fee-related policy.
1344+ ATMPArgs single_args = ATMPArgs::SingleInPackageAccept (args);
13311345 std::vector<CTransactionRef> txns_new;
13321346 for (const auto & tx : package) {
13331347 const auto & wtxid = tx->GetWitnessHash ();
@@ -1354,18 +1368,31 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
13541368 results.emplace (wtxid, MempoolAcceptResult::MempoolTxDifferentWitness (iter.value ()->GetTx ().GetWitnessHash ()));
13551369 } else {
13561370 // Transaction does not already exist in the mempool.
1357- txns_new.push_back (tx);
1371+ // Try submitting the transaction on its own.
1372+ const auto single_res = AcceptSingleTransaction (tx, single_args);
1373+ if (single_res.m_result_type == MempoolAcceptResult::ResultType::VALID) {
1374+ // The transaction succeeded on its own and is now in the mempool. Don't include it
1375+ // in package validation, because its fees should only be "used" once.
1376+ assert (m_pool.exists (GenTxid::Wtxid (wtxid)));
1377+ results.emplace (wtxid, single_res);
1378+ } else {
1379+ txns_new.push_back (tx);
1380+ }
13581381 }
13591382 }
13601383
13611384 // Nothing to do if the entire package has already been submitted.
1362- if (txns_new.empty ()) return PackageMempoolAcceptResult (package_state, std::move (results));
1385+ if (txns_new.empty ()) {
1386+ // No package feerate when no package validation was done.
1387+ return PackageMempoolAcceptResult (package_state, std::move (results));
1388+ }
13631389 // Validate the (deduplicated) transactions as a package.
13641390 auto submission_result = AcceptMultipleTransactions (txns_new, args);
13651391 // Include already-in-mempool transaction results in the final result.
13661392 for (const auto & [wtxid, mempoolaccept_res] : results) {
13671393 submission_result.m_tx_results .emplace (wtxid, mempoolaccept_res);
13681394 }
1395+ if (submission_result.m_state .IsValid ()) assert (submission_result.m_package_feerate .has_value ());
13691396 return submission_result;
13701397}
13711398
0 commit comments