@@ -477,6 +477,17 @@ class MemPoolAccept
477477 };
478478 }
479479
480+ /* * Parameters for child-with-unconfirmed-parents package validation. */
481+ static ATMPArgs PackageChildWithParents (const CChainParams& chainparams, int64_t accept_time,
482+ std::vector<COutPoint>& coins_to_uncache) {
483+ return ATMPArgs{/* m_chainparams */ chainparams,
484+ /* m_accept_time */ accept_time,
485+ /* m_bypass_limits */ false ,
486+ /* m_coins_to_uncache */ coins_to_uncache,
487+ /* m_test_accept */ false ,
488+ /* m_allow_bip125_replacement */ false ,
489+ };
490+ }
480491 // No default ctor to avoid exposing details to clients and allowing the possibility of
481492 // mixing up the order of the arguments. Use static functions above instead.
482493 ATMPArgs () = delete ;
@@ -492,6 +503,12 @@ class MemPoolAccept
492503 */
493504 PackageMempoolAcceptResult AcceptMultipleTransactions (const std::vector<CTransactionRef>& txns, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
494505
506+ /* *
507+ * Package (more specific than just multiple transactions) acceptance. Package must be a child
508+ * with all of its unconfirmed parents, and topologically sorted.
509+ */
510+ PackageMempoolAcceptResult AcceptPackage (const Package& package, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
511+
495512private:
496513 // All the intermediate state that gets passed between the various levels
497514 // of checking a given transaction.
@@ -1077,6 +1094,62 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
10771094 return PackageMempoolAcceptResult (package_state, std::move (results));
10781095}
10791096
1097+ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage (const Package& package, ATMPArgs& args)
1098+ {
1099+ AssertLockHeld (cs_main);
1100+ PackageValidationState package_state;
1101+
1102+ // Check that the package is well-formed. If it isn't, we won't try to validate any of the
1103+ // transactions and thus won't return any MempoolAcceptResults, just a package-wide error.
1104+
1105+ // Context-free package checks.
1106+ if (!CheckPackage (package, package_state)) return PackageMempoolAcceptResult (package_state, {});
1107+
1108+ // All transactions in the package must be a parent of the last transaction. This is just an
1109+ // opportunity for us to fail fast on a context-free check without taking the mempool lock.
1110+ if (!IsChildWithParents (package)) {
1111+ package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-child-with-parents" );
1112+ return PackageMempoolAcceptResult (package_state, {});
1113+ }
1114+
1115+ const auto & child = package[package.size () - 1 ];
1116+ // The package must be 1 child with all of its unconfirmed parents. The package is expected to
1117+ // be sorted, so the last transaction is the child.
1118+ std::unordered_set<uint256, SaltedTxidHasher> unconfirmed_parent_txids;
1119+ std::transform (package.cbegin (), package.end () - 1 ,
1120+ std::inserter (unconfirmed_parent_txids, unconfirmed_parent_txids.end ()),
1121+ [](const auto & tx) { return tx->GetHash (); });
1122+
1123+ // All child inputs must refer to a preceding package transaction or a confirmed UTXO. The only
1124+ // way to verify this is to look up the child's inputs in our current coins view (not including
1125+ // mempool), and enforce that all parents not present in the package be available at chain tip.
1126+ // Since this check can bring new coins into the coins cache, keep track of these coins and
1127+ // uncache them if we don't end up submitting this package to the mempool.
1128+ const CCoinsViewCache& coins_tip_cache = m_active_chainstate.CoinsTip ();
1129+ for (const auto & input : child->vin ) {
1130+ if (!coins_tip_cache.HaveCoinInCache (input.prevout )) {
1131+ args.m_coins_to_uncache .push_back (input.prevout );
1132+ }
1133+ }
1134+ // Using the MemPoolAccept m_view cache allows us to look up these same coins faster later.
1135+ // This should be connecting directly to CoinsTip, not to m_viewmempool, because we specifically
1136+ // require inputs to be confirmed if they aren't in the package.
1137+ m_view.SetBackend (m_active_chainstate.CoinsTip ());
1138+ const auto package_or_confirmed = [this , &unconfirmed_parent_txids](const auto & input) {
1139+ return unconfirmed_parent_txids.count (input.prevout .hash ) > 0 || m_view.HaveCoin (input.prevout );
1140+ };
1141+ if (!std::all_of (child->vin .cbegin (), child->vin .cend (), package_or_confirmed)) {
1142+ package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-child-with-unconfirmed-parents" );
1143+ return PackageMempoolAcceptResult (package_state, {});
1144+ }
1145+ // Protect against bugs where we pull more inputs from disk that miss being added to
1146+ // coins_to_uncache. The backend will be connected again when needed in PreChecks.
1147+ m_view.SetBackend (m_dummy);
1148+
1149+ LOCK (m_pool.cs );
1150+ return AcceptMultipleTransactions (package, args);
1151+ }
1152+
10801153} // anon namespace
10811154
10821155/* * (try to) add transaction to memory pool with a specified acceptance time **/
@@ -1120,8 +1193,16 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx
11201193
11211194 std::vector<COutPoint> coins_to_uncache;
11221195 const CChainParams& chainparams = Params ();
1123- auto args = MemPoolAccept::ATMPArgs::PackageTestAccept (chainparams, GetTime (), coins_to_uncache);
1124- const PackageMempoolAcceptResult result = MemPoolAccept (pool, active_chainstate).AcceptMultipleTransactions (package, args);
1196+ const auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED (cs_main) {
1197+ AssertLockHeld (cs_main);
1198+ if (test_accept) {
1199+ auto args = MemPoolAccept::ATMPArgs::PackageTestAccept (chainparams, GetTime (), coins_to_uncache);
1200+ return MemPoolAccept (pool, active_chainstate).AcceptMultipleTransactions (package, args);
1201+ } else {
1202+ auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents (chainparams, GetTime (), coins_to_uncache);
1203+ return MemPoolAccept (pool, active_chainstate).AcceptPackage (package, args);
1204+ }
1205+ }();
11251206
11261207 // Uncache coins pertaining to transactions that were not submitted to the mempool.
11271208 for (const COutPoint& hashTx : coins_to_uncache) {
0 commit comments