@@ -508,6 +508,19 @@ class MemPoolAccept
508
508
};
509
509
}
510
510
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
+
511
524
private:
512
525
// Private ctor to avoid exposing details to clients and allowing the possibility of
513
526
// mixing up the order of the arguments. Use static functions above instead.
@@ -1328,6 +1341,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1328
1341
// transactions that are already in the mempool, and only call AcceptMultipleTransactions() with
1329
1342
// the new transactions. This ensures we don't double-count transaction counts and sizes when
1330
1343
// checking ancestor/descendant limits, or double-count transaction fees for fee-related policy.
1344
+ ATMPArgs single_args = ATMPArgs::SingleInPackageAccept (args);
1331
1345
std::vector<CTransactionRef> txns_new;
1332
1346
for (const auto & tx : package) {
1333
1347
const auto & wtxid = tx->GetWitnessHash ();
@@ -1354,18 +1368,31 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1354
1368
results.emplace (wtxid, MempoolAcceptResult::MempoolTxDifferentWitness (iter.value ()->GetTx ().GetWitnessHash ()));
1355
1369
} else {
1356
1370
// 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
+ }
1358
1381
}
1359
1382
}
1360
1383
1361
1384
// 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
+ }
1363
1389
// Validate the (deduplicated) transactions as a package.
1364
1390
auto submission_result = AcceptMultipleTransactions (txns_new, args);
1365
1391
// Include already-in-mempool transaction results in the final result.
1366
1392
for (const auto & [wtxid, mempoolaccept_res] : results) {
1367
1393
submission_result.m_tx_results .emplace (wtxid, mempoolaccept_res);
1368
1394
}
1395
+ if (submission_result.m_state .IsValid ()) assert (submission_result.m_package_feerate .has_value ());
1369
1396
return submission_result;
1370
1397
}
1371
1398
0 commit comments