From 170306728aa23a4d5fcc383ddabd97f66fed5119 Mon Sep 17 00:00:00 2001 From: glozow Date: Wed, 14 Feb 2024 14:15:48 +0000 Subject: [policy] sibling eviction for v3 transactions --- src/policy/v3_policy.cpp | 21 ++++++++++++++++----- src/policy/v3_policy.h | 8 +++++++- 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'src/policy') diff --git a/src/policy/v3_policy.cpp b/src/policy/v3_policy.cpp index c98262c364..3c3942d707 100644 --- a/src/policy/v3_policy.cpp +++ b/src/policy/v3_policy.cpp @@ -130,10 +130,11 @@ std::optional PackageV3Checks(const CTransactionRef& ptx, int64_t v } // It shouldn't be possible to have any mempool siblings at this point. SingleV3Checks - // catches mempool siblings. Also, if the package consists of connected transactions, + // catches mempool siblings and sibling eviction is not extended to packages. Also, if the package consists of connected transactions, // any tx having a mempool ancestor would mean the package exceeds ancestor limits. if (!Assume(!parent_info.m_has_mempool_descendant)) { - return strprintf("tx %u would exceed descendant count limit", parent_info.m_wtxid.ToString()); + return strprintf("tx %s (wtxid=%s) would exceed descendant count limit", + parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString()); } } } else { @@ -214,10 +215,20 @@ std::optional> SingleV3Checks(const CTra std::any_of(children.cbegin(), children.cend(), [&direct_conflicts](const CTxMemPoolEntry& child){return direct_conflicts.count(child.GetTx().GetHash()) > 0;}); if (parent_entry->GetCountWithDescendants() + 1 > V3_DESCENDANT_LIMIT && !child_will_be_replaced) { + // Allow sibling eviction for v3 transaction: if another child already exists, even if + // we don't conflict inputs with it, consider evicting it under RBF rules. We rely on v3 rules + // only permitting 1 descendant, as otherwise we would need to have logic for deciding + // which descendant to evict. Skip if this isn't true, e.g. if the transaction has + // multiple children or the sibling also has descendants due to a reorg. + const bool consider_sibling_eviction{parent_entry->GetCountWithDescendants() == 2 && + children.begin()->get().GetCountWithAncestors() == 2}; + + // Return the sibling if its eviction can be considered. Provide the "descendant count + // limit" string either way, as the caller may decide not to do sibling eviction. return std::make_pair(strprintf("tx %u (wtxid=%s) would exceed descendant count limit", - parent_entry->GetSharedTx()->GetHash().ToString(), - parent_entry->GetSharedTx()->GetWitnessHash().ToString()), - nullptr); + parent_entry->GetSharedTx()->GetHash().ToString(), + parent_entry->GetSharedTx()->GetWitnessHash().ToString()), + consider_sibling_eviction ? children.begin()->get().GetSharedTx() : nullptr); } } return std::nullopt; diff --git a/src/policy/v3_policy.h b/src/policy/v3_policy.h index c61d8ac4cc..2e56f8822b 100644 --- a/src/policy/v3_policy.h +++ b/src/policy/v3_policy.h @@ -48,7 +48,13 @@ static_assert(V3_CHILD_MAX_VSIZE + MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR * count of in-mempool ancestors. * @param[in] vsize The sigop-adjusted virtual size of ptx. * - * @returns debug string if an error occurs, std::nullopt otherwise. + * @returns 3 possibilities: + * - std::nullopt if all v3 checks were applied successfully + * - debug string + pointer to a mempool sibling if this transaction would be the second child in a + * 1-parent-1-child cluster; the caller may consider evicting the specified sibling or return an + * error with the debug string. + * - debug string + nullptr if this transaction violates some v3 rule and sibling eviction is not + * applicable. */ std::optional> SingleV3Checks(const CTransactionRef& ptx, const CTxMemPool::setEntries& mempool_ancestors, -- cgit v1.2.3