mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 07:09:15 +01:00
Merge bitcoin/bitcoin#31385: package validation: relax the package-not-child-with-unconfirmed-parents rule
ea17a9423f[doc] release note for relaxing requirement of all unconfirmed parents present (glozow)12f48d5ed3test: add chained 1p1c propagation test (Greg Sanders)525be56741[unit test] package submission 2p1c with 1 parent missing (glozow)f24771af05relax child-with-unconfirmed-parents rule (glozow) Pull request description: Broadens the package validation interface, see #27463 for wider context. On master, package rules include that (1) the package topology must be child-wth-parents (2) all of the child's unconfirmed parents must be present. This PR relaxes the second rule, leaving the first rule untouched (there are plans to change that as well, but not here). Original motivation for this rule was based on the idea that we would have a child-with-unconfirmed-parents package relay protocol, and this would verify that the peer provided the "correct" package. For various reasons, we're not planning on doing this. We could potentially do this for ancestor packages (with a similar definition that all UTXOs to make the tx valid are available in this package), but it's also questionable whether it's useful to enforce this. This rule gets in the way of certain usage of 1p1c package relay currently. If a transaction has multiple parents, of which only 1 requires a package CPFP, this rule blocks the package from relaying. Even if all the non-low-feerate parents are already in mempool, when the p2p logic submits the 1p1c package, it gets rejected for not meeting this rule. ACKs for top commit: ishaanam: re-utACKea17a9423finstagibbs: ACKea17a9423fTree-SHA512: c2231761ae7b2acea10a96735e7a36c646f517964d0acb59bacbae1c5a1950e0223458b84c6d5ce008f0c1d53c1605df0fb3cd0064ee535ead006eb7c0fa625b
This commit is contained in:
@@ -520,7 +520,7 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
/** Parameters for child-with-unconfirmed-parents package validation. */
|
||||
/** Parameters for child-with-parents package validation. */
|
||||
static ATMPArgs PackageChildWithParents(const CChainParams& chainparams, int64_t accept_time,
|
||||
std::vector<COutPoint>& coins_to_uncache, const std::optional<CFeeRate>& client_maxfeerate) {
|
||||
return ATMPArgs{/* m_chainparams */ chainparams,
|
||||
@@ -1716,7 +1716,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
|
||||
|
||||
// There are two topologies we are able to handle through this function:
|
||||
// (1) A single transaction
|
||||
// (2) A child-with-unconfirmed-parents package.
|
||||
// (2) A child-with-parents package.
|
||||
// Check that the package is well-formed. If it isn't, we won't try to validate any of the
|
||||
// transactions and thus won't return any MempoolAcceptResults, just a package-wide error.
|
||||
|
||||
@@ -1725,49 +1725,11 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
|
||||
return PackageMempoolAcceptResult(package_state_quit_early, {});
|
||||
}
|
||||
|
||||
if (package.size() > 1) {
|
||||
if (package.size() > 1 && !IsChildWithParents(package)) {
|
||||
// All transactions in the package must be a parent of the last transaction. This is just an
|
||||
// opportunity for us to fail fast on a context-free check without taking the mempool lock.
|
||||
if (!IsChildWithParents(package)) {
|
||||
package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents");
|
||||
return PackageMempoolAcceptResult(package_state_quit_early, {});
|
||||
}
|
||||
|
||||
// IsChildWithParents() guarantees the package is > 1 transactions.
|
||||
assert(package.size() > 1);
|
||||
// The package must be 1 child with all of its unconfirmed parents. The package is expected to
|
||||
// be sorted, so the last transaction is the child.
|
||||
const auto& child = package.back();
|
||||
std::unordered_set<uint256, SaltedTxidHasher> unconfirmed_parent_txids;
|
||||
std::transform(package.cbegin(), package.cend() - 1,
|
||||
std::inserter(unconfirmed_parent_txids, unconfirmed_parent_txids.end()),
|
||||
[](const auto& tx) { return tx->GetHash(); });
|
||||
|
||||
// All child inputs must refer to a preceding package transaction or a confirmed UTXO. The only
|
||||
// way to verify this is to look up the child's inputs in our current coins view (not including
|
||||
// mempool), and enforce that all parents not present in the package be available at chain tip.
|
||||
// Since this check can bring new coins into the coins cache, keep track of these coins and
|
||||
// uncache them if we don't end up submitting this package to the mempool.
|
||||
const CCoinsViewCache& coins_tip_cache = m_active_chainstate.CoinsTip();
|
||||
for (const auto& input : child->vin) {
|
||||
if (!coins_tip_cache.HaveCoinInCache(input.prevout)) {
|
||||
args.m_coins_to_uncache.push_back(input.prevout);
|
||||
}
|
||||
}
|
||||
// Using the MemPoolAccept m_view cache allows us to look up these same coins faster later.
|
||||
// This should be connecting directly to CoinsTip, not to m_viewmempool, because we specifically
|
||||
// require inputs to be confirmed if they aren't in the package.
|
||||
m_view.SetBackend(m_active_chainstate.CoinsTip());
|
||||
const auto package_or_confirmed = [this, &unconfirmed_parent_txids](const auto& input) {
|
||||
return unconfirmed_parent_txids.count(input.prevout.hash) > 0 || m_view.HaveCoin(input.prevout);
|
||||
};
|
||||
if (!std::all_of(child->vin.cbegin(), child->vin.cend(), package_or_confirmed)) {
|
||||
package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-unconfirmed-parents");
|
||||
return PackageMempoolAcceptResult(package_state_quit_early, {});
|
||||
}
|
||||
// Protect against bugs where we pull more inputs from disk that miss being added to
|
||||
// coins_to_uncache. The backend will be connected again when needed in PreChecks.
|
||||
m_view.SetBackend(m_dummy);
|
||||
package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents");
|
||||
return PackageMempoolAcceptResult(package_state_quit_early, {});
|
||||
}
|
||||
|
||||
LOCK(m_pool.cs);
|
||||
|
||||
Reference in New Issue
Block a user