@@ -460,6 +460,10 @@ class MemPoolAccept
460460 * partially submitted.
461461 */
462462 const bool m_package_submission;
463+ /* * When true, use package feerates instead of individual transaction feerates for fee-based
464+ * policies such as mempool min fee and min relay fee.
465+ */
466+ const bool m_package_feerates;
463467
464468 /* * Parameters for single transaction mempool validation. */
465469 static ATMPArgs SingleAccept (const CChainParams& chainparams, int64_t accept_time,
@@ -472,6 +476,7 @@ class MemPoolAccept
472476 /* m_test_accept */ test_accept,
473477 /* m_allow_bip125_replacement */ true ,
474478 /* m_package_submission */ false ,
479+ /* m_package_feerates */ false ,
475480 };
476481 }
477482
@@ -485,6 +490,7 @@ class MemPoolAccept
485490 /* m_test_accept */ true ,
486491 /* m_allow_bip125_replacement */ false ,
487492 /* m_package_submission */ false , // not submitting to mempool
493+ /* m_package_feerates */ false ,
488494 };
489495 }
490496
@@ -498,6 +504,7 @@ class MemPoolAccept
498504 /* m_test_accept */ false ,
499505 /* m_allow_bip125_replacement */ false ,
500506 /* m_package_submission */ true ,
507+ /* m_package_feerates */ true ,
501508 };
502509 }
503510
@@ -510,14 +517,16 @@ class MemPoolAccept
510517 std::vector<COutPoint>& coins_to_uncache,
511518 bool test_accept,
512519 bool allow_bip125_replacement,
513- bool package_submission)
520+ bool package_submission,
521+ bool package_feerates)
514522 : m_chainparams{chainparams},
515523 m_accept_time{accept_time},
516524 m_bypass_limits{bypass_limits},
517525 m_coins_to_uncache{coins_to_uncache},
518526 m_test_accept{test_accept},
519527 m_allow_bip125_replacement{allow_bip125_replacement},
520- m_package_submission{package_submission}
528+ m_package_submission{package_submission},
529+ m_package_feerates{package_feerates}
521530 {
522531 }
523532 };
@@ -819,9 +828,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
819828 return state.Invalid (TxValidationResult::TX_NOT_STANDARD, " bad-txns-too-many-sigops" ,
820829 strprintf (" %d" , nSigOpsCost));
821830
822- // No transactions are allowed below minRelayTxFee except from disconnected
823- // blocks
824- if (!bypass_limits && !CheckFeeRate (ws.m_vsize , ws.m_modified_fees , state)) return false ;
831+ // No individual transactions are allowed below minRelayTxFee and mempool min fee except from
832+ // disconnected blocks and transactions in a package. Package transactions will be checked using
833+ // package feerate later.
834+ if (!bypass_limits && !args.m_package_feerates && !CheckFeeRate (ws.m_vsize , ws.m_modified_fees , state)) return false ;
825835
826836 ws.m_iters_conflicting = m_pool.GetIterSet (ws.m_conflicts );
827837 // Calculate in-mempool ancestors, up to a limit.
@@ -1205,20 +1215,35 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
12051215 m_viewmempool.PackageAddTransaction (ws.m_ptx );
12061216 }
12071217
1218+ // Transactions must meet two minimum feerates: the mempool minimum fee and min relay fee.
1219+ // For transactions consisting of exactly one child and its parents, it suffices to use the
1220+ // package feerate (total modified fees / total virtual size) to check this requirement.
1221+ const auto m_total_vsize = std::accumulate (workspaces.cbegin (), workspaces.cend (), int64_t {0 },
1222+ [](int64_t sum, auto & ws) { return sum + ws.m_vsize ; });
1223+ const auto m_total_modified_fees = std::accumulate (workspaces.cbegin (), workspaces.cend (), CAmount{0 },
1224+ [](CAmount sum, auto & ws) { return sum + ws.m_modified_fees ; });
1225+ const CFeeRate package_feerate (m_total_modified_fees, m_total_vsize);
1226+ TxValidationState placeholder_state;
1227+ if (args.m_package_feerates &&
1228+ !CheckFeeRate (m_total_vsize, m_total_modified_fees, placeholder_state)) {
1229+ package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-fee-too-low" );
1230+ return PackageMempoolAcceptResult (package_state, package_feerate, {});
1231+ }
1232+
12081233 // Apply package mempool ancestor/descendant limits. Skip if there is only one transaction,
12091234 // because it's unnecessary. Also, CPFP carve out can increase the limit for individual
12101235 // transactions, but this exemption is not extended to packages in CheckPackageLimits().
12111236 std::string err_string;
12121237 if (txns.size () > 1 && !PackageMempoolChecks (txns, package_state)) {
1213- return PackageMempoolAcceptResult (package_state, std::move (results));
1238+ return PackageMempoolAcceptResult (package_state, package_feerate, std::move (results));
12141239 }
12151240
12161241 for (Workspace& ws : workspaces) {
12171242 if (!PolicyScriptChecks (args, ws)) {
12181243 // Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished.
12191244 package_state.Invalid (PackageValidationResult::PCKG_TX, " transaction failed" );
12201245 results.emplace (ws.m_ptx ->GetWitnessHash (), MempoolAcceptResult::Failure (ws.m_state ));
1221- return PackageMempoolAcceptResult (package_state, std::move (results));
1246+ return PackageMempoolAcceptResult (package_state, package_feerate, std::move (results));
12221247 }
12231248 if (args.m_test_accept ) {
12241249 // When test_accept=true, transactions that pass PolicyScriptChecks are valid because there are
@@ -1229,14 +1254,14 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
12291254 }
12301255 }
12311256
1232- if (args.m_test_accept ) return PackageMempoolAcceptResult (package_state, std::move (results));
1257+ if (args.m_test_accept ) return PackageMempoolAcceptResult (package_state, package_feerate, std::move (results));
12331258
12341259 if (!SubmitPackage (args, workspaces, package_state, results)) {
12351260 // PackageValidationState filled in by SubmitPackage().
1236- return PackageMempoolAcceptResult (package_state, std::move (results));
1261+ return PackageMempoolAcceptResult (package_state, package_feerate, std::move (results));
12371262 }
12381263
1239- return PackageMempoolAcceptResult (package_state, std::move (results));
1264+ return PackageMempoolAcceptResult (package_state, package_feerate, std::move (results));
12401265}
12411266
12421267PackageMempoolAcceptResult MemPoolAccept::AcceptPackage (const Package& package, ATMPArgs& args)
0 commit comments