@@ -1685,10 +1685,14 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptSubPackage(const std::vector<CTr
1685
1685
1686
1686
PackageMempoolAcceptResult MemPoolAccept::AcceptPackage (const Package& package, ATMPArgs& args)
1687
1687
{
1688
+ Assert (!package.empty ());
1688
1689
AssertLockHeld (cs_main);
1689
1690
// Used if returning a PackageMempoolAcceptResult directly from this function.
1690
1691
PackageValidationState package_state_quit_early;
1691
1692
1693
+ // There are two topologies we are able to handle through this function:
1694
+ // (1) A single transaction
1695
+ // (2) A child-with-unconfirmed-parents package.
1692
1696
// Check that the package is well-formed. If it isn't, we won't try to validate any of the
1693
1697
// transactions and thus won't return any MempoolAcceptResults, just a package-wide error.
1694
1698
@@ -1697,48 +1701,50 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1697
1701
return PackageMempoolAcceptResult (package_state_quit_early, {});
1698
1702
}
1699
1703
1700
- // All transactions in the package must be a parent of the last transaction. This is just an
1701
- // opportunity for us to fail fast on a context-free check without taking the mempool lock.
1702
- if (!IsChildWithParents (package)) {
1703
- package_state_quit_early.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-child-with-parents" );
1704
- return PackageMempoolAcceptResult (package_state_quit_early, {});
1705
- }
1706
-
1707
- // IsChildWithParents() guarantees the package is > 1 transactions.
1708
- assert (package.size () > 1 );
1709
- // The package must be 1 child with all of its unconfirmed parents. The package is expected to
1710
- // be sorted, so the last transaction is the child.
1711
- const auto & child = package.back ();
1712
- std::unordered_set<uint256, SaltedTxidHasher> unconfirmed_parent_txids;
1713
- std::transform (package.cbegin (), package.cend () - 1 ,
1714
- std::inserter (unconfirmed_parent_txids, unconfirmed_parent_txids.end ()),
1715
- [](const auto & tx) { return tx->GetHash (); });
1716
-
1717
- // All child inputs must refer to a preceding package transaction or a confirmed UTXO. The only
1718
- // way to verify this is to look up the child's inputs in our current coins view (not including
1719
- // mempool), and enforce that all parents not present in the package be available at chain tip.
1720
- // Since this check can bring new coins into the coins cache, keep track of these coins and
1721
- // uncache them if we don't end up submitting this package to the mempool.
1722
- const CCoinsViewCache& coins_tip_cache = m_active_chainstate.CoinsTip ();
1723
- for (const auto & input : child->vin ) {
1724
- if (!coins_tip_cache.HaveCoinInCache (input.prevout )) {
1725
- args.m_coins_to_uncache .push_back (input.prevout );
1726
- }
1727
- }
1728
- // Using the MemPoolAccept m_view cache allows us to look up these same coins faster later.
1729
- // This should be connecting directly to CoinsTip, not to m_viewmempool, because we specifically
1730
- // require inputs to be confirmed if they aren't in the package.
1731
- m_view.SetBackend (m_active_chainstate.CoinsTip ());
1732
- const auto package_or_confirmed = [this , &unconfirmed_parent_txids](const auto & input) {
1733
- return unconfirmed_parent_txids.count (input.prevout .hash ) > 0 || m_view.HaveCoin (input.prevout );
1734
- };
1735
- if (!std::all_of (child->vin .cbegin (), child->vin .cend (), package_or_confirmed)) {
1736
- package_state_quit_early.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-child-with-unconfirmed-parents" );
1737
- return PackageMempoolAcceptResult (package_state_quit_early, {});
1704
+ if (package.size () > 1 ) {
1705
+ // All transactions in the package must be a parent of the last transaction. This is just an
1706
+ // opportunity for us to fail fast on a context-free check without taking the mempool lock.
1707
+ if (!IsChildWithParents (package)) {
1708
+ package_state_quit_early.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-child-with-parents" );
1709
+ return PackageMempoolAcceptResult (package_state_quit_early, {});
1710
+ }
1711
+
1712
+ // IsChildWithParents() guarantees the package is > 1 transactions.
1713
+ assert (package.size () > 1 );
1714
+ // The package must be 1 child with all of its unconfirmed parents. The package is expected to
1715
+ // be sorted, so the last transaction is the child.
1716
+ const auto & child = package.back ();
1717
+ std::unordered_set<uint256, SaltedTxidHasher> unconfirmed_parent_txids;
1718
+ std::transform (package.cbegin (), package.cend () - 1 ,
1719
+ std::inserter (unconfirmed_parent_txids, unconfirmed_parent_txids.end ()),
1720
+ [](const auto & tx) { return tx->GetHash (); });
1721
+
1722
+ // All child inputs must refer to a preceding package transaction or a confirmed UTXO. The only
1723
+ // way to verify this is to look up the child's inputs in our current coins view (not including
1724
+ // mempool), and enforce that all parents not present in the package be available at chain tip.
1725
+ // Since this check can bring new coins into the coins cache, keep track of these coins and
1726
+ // uncache them if we don't end up submitting this package to the mempool.
1727
+ const CCoinsViewCache& coins_tip_cache = m_active_chainstate.CoinsTip ();
1728
+ for (const auto & input : child->vin ) {
1729
+ if (!coins_tip_cache.HaveCoinInCache (input.prevout )) {
1730
+ args.m_coins_to_uncache .push_back (input.prevout );
1731
+ }
1732
+ }
1733
+ // Using the MemPoolAccept m_view cache allows us to look up these same coins faster later.
1734
+ // This should be connecting directly to CoinsTip, not to m_viewmempool, because we specifically
1735
+ // require inputs to be confirmed if they aren't in the package.
1736
+ m_view.SetBackend (m_active_chainstate.CoinsTip ());
1737
+ const auto package_or_confirmed = [this , &unconfirmed_parent_txids](const auto & input) {
1738
+ return unconfirmed_parent_txids.count (input.prevout .hash ) > 0 || m_view.HaveCoin (input.prevout );
1739
+ };
1740
+ if (!std::all_of (child->vin .cbegin (), child->vin .cend (), package_or_confirmed)) {
1741
+ package_state_quit_early.Invalid (PackageValidationResult::PCKG_POLICY, " package-not-child-with-unconfirmed-parents" );
1742
+ return PackageMempoolAcceptResult (package_state_quit_early, {});
1743
+ }
1744
+ // Protect against bugs where we pull more inputs from disk that miss being added to
1745
+ // coins_to_uncache. The backend will be connected again when needed in PreChecks.
1746
+ m_view.SetBackend (m_dummy);
1738
1747
}
1739
- // Protect against bugs where we pull more inputs from disk that miss being added to
1740
- // coins_to_uncache. The backend will be connected again when needed in PreChecks.
1741
- m_view.SetBackend (m_dummy);
1742
1748
1743
1749
LOCK (m_pool.cs );
1744
1750
// Stores results from which we will create the returned PackageMempoolAcceptResult.
@@ -1748,6 +1754,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1748
1754
// this transaction. "Nonfinal" because if a transaction fails by itself but succeeds later
1749
1755
// (i.e. when evaluated with a fee-bumping child), the result in this map may be discarded.
1750
1756
std::map<uint256, MempoolAcceptResult> individual_results_nonfinal;
1757
+ // Tracks whether we think package submission could result in successful entry to the mempool
1751
1758
bool quit_early{false };
1752
1759
std::vector<CTransactionRef> txns_package_eval;
1753
1760
for (const auto & tx : package) {
@@ -1789,8 +1796,9 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1789
1796
// in package validation, because its fees should only be "used" once.
1790
1797
assert (m_pool.exists (GenTxid::Wtxid (wtxid)));
1791
1798
results_final.emplace (wtxid, single_res);
1792
- } else if (single_res.m_state .GetResult () != TxValidationResult::TX_RECONSIDERABLE &&
1793
- single_res.m_state .GetResult () != TxValidationResult::TX_MISSING_INPUTS) {
1799
+ } else if (package.size () == 1 || // If there is only one transaction, no need to retry it "as a package"
1800
+ (single_res.m_state .GetResult () != TxValidationResult::TX_RECONSIDERABLE &&
1801
+ single_res.m_state .GetResult () != TxValidationResult::TX_MISSING_INPUTS)) {
1794
1802
// Package validation policy only differs from individual policy in its evaluation
1795
1803
// of feerate. For example, if a transaction fails here due to violation of a
1796
1804
// consensus rule, the result will not change when it is submitted as part of a
0 commit comments