Skip to content

Commit 12dae63

Browse files
committed
Merge bitcoin#29306: policy: enable sibling eviction for v3 transactions
1342a31 [functional test] sibling eviction (glozow) 5fbab37 [unit test] sibling not returned from SingleV3Checks if 1p2c or 3gen (glozow) 1703067 [policy] sibling eviction for v3 transactions (glozow) b5d15f7 [refactor] return pair from SingleV3Checks (glozow) Pull request description: When we receive a v3 transaction that would bust a mempool transaction's descendant limit, instead of rejecting the new tx, consider replacing the other descendant if it is much higher feerate (using existing RBF criteria to assess that it's more incentive compatible and to avoid DoS). Delving post with more background and motivation: https://delvingbitcoin.org/t/sibling-eviction-for-v3-transactions/472 ACKs for top commit: sdaftuar: ACK 1342a31 achow101: ACK 1342a31 instagibbs: ACK bitcoin@1342a31 Tree-SHA512: dd957d49e51db78758f566c49bddc579b72478e371275c592d3d5ba097d20de47a6c81952045021b99d82a787f5b799baf16dd0ee0e6de90ba12e21e275352be
2 parents d14c728 + 1342a31 commit 12dae63

File tree

5 files changed

+314
-64
lines changed

5 files changed

+314
-64
lines changed

src/policy/v3_policy.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,11 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
130130
}
131131

132132
// It shouldn't be possible to have any mempool siblings at this point. SingleV3Checks
133-
// catches mempool siblings. Also, if the package consists of connected transactions,
133+
// catches mempool siblings and sibling eviction is not extended to packages. Also, if the package consists of connected transactions,
134134
// any tx having a mempool ancestor would mean the package exceeds ancestor limits.
135135
if (!Assume(!parent_info.m_has_mempool_descendant)) {
136-
return strprintf("tx %u would exceed descendant count limit", parent_info.m_wtxid.ToString());
136+
return strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
137+
parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString());
137138
}
138139
}
139140
} else {
@@ -158,21 +159,23 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
158159
return std::nullopt;
159160
}
160161

161-
std::optional<std::string> SingleV3Checks(const CTransactionRef& ptx,
162+
std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTransactionRef& ptx,
162163
const CTxMemPool::setEntries& mempool_ancestors,
163164
const std::set<Txid>& direct_conflicts,
164165
int64_t vsize)
165166
{
166167
// Check v3 and non-v3 inheritance.
167168
for (const auto& entry : mempool_ancestors) {
168169
if (ptx->nVersion != 3 && entry->GetTx().nVersion == 3) {
169-
return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
170+
return std::make_pair(strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
170171
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
171-
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString());
172+
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
173+
nullptr);
172174
} else if (ptx->nVersion == 3 && entry->GetTx().nVersion != 3) {
173-
return strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)",
175+
return std::make_pair(strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)",
174176
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
175-
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString());
177+
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
178+
nullptr);
176179
}
177180
}
178181

@@ -185,16 +188,18 @@ std::optional<std::string> SingleV3Checks(const CTransactionRef& ptx,
185188

186189
// Check that V3_ANCESTOR_LIMIT would not be violated.
187190
if (mempool_ancestors.size() + 1 > V3_ANCESTOR_LIMIT) {
188-
return strprintf("tx %s (wtxid=%s) would have too many ancestors",
189-
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
191+
return std::make_pair(strprintf("tx %s (wtxid=%s) would have too many ancestors",
192+
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()),
193+
nullptr);
190194
}
191195

192196
// Remaining checks only pertain to transactions with unconfirmed ancestors.
193197
if (mempool_ancestors.size() > 0) {
194198
// If this transaction spends V3 parents, it cannot be too large.
195199
if (vsize > V3_CHILD_MAX_VSIZE) {
196-
return strprintf("v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
197-
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, V3_CHILD_MAX_VSIZE);
200+
return std::make_pair(strprintf("v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
201+
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, V3_CHILD_MAX_VSIZE),
202+
nullptr);
198203
}
199204

200205
// Check the descendant counts of in-mempool ancestors.
@@ -210,9 +215,20 @@ std::optional<std::string> SingleV3Checks(const CTransactionRef& ptx,
210215
std::any_of(children.cbegin(), children.cend(),
211216
[&direct_conflicts](const CTxMemPoolEntry& child){return direct_conflicts.count(child.GetTx().GetHash()) > 0;});
212217
if (parent_entry->GetCountWithDescendants() + 1 > V3_DESCENDANT_LIMIT && !child_will_be_replaced) {
213-
return strprintf("tx %u (wtxid=%s) would exceed descendant count limit",
214-
parent_entry->GetSharedTx()->GetHash().ToString(),
215-
parent_entry->GetSharedTx()->GetWitnessHash().ToString());
218+
// Allow sibling eviction for v3 transaction: if another child already exists, even if
219+
// we don't conflict inputs with it, consider evicting it under RBF rules. We rely on v3 rules
220+
// only permitting 1 descendant, as otherwise we would need to have logic for deciding
221+
// which descendant to evict. Skip if this isn't true, e.g. if the transaction has
222+
// multiple children or the sibling also has descendants due to a reorg.
223+
const bool consider_sibling_eviction{parent_entry->GetCountWithDescendants() == 2 &&
224+
children.begin()->get().GetCountWithAncestors() == 2};
225+
226+
// Return the sibling if its eviction can be considered. Provide the "descendant count
227+
// limit" string either way, as the caller may decide not to do sibling eviction.
228+
return std::make_pair(strprintf("tx %u (wtxid=%s) would exceed descendant count limit",
229+
parent_entry->GetSharedTx()->GetHash().ToString(),
230+
parent_entry->GetSharedTx()->GetWitnessHash().ToString()),
231+
consider_sibling_eviction ? children.begin()->get().GetSharedTx() : nullptr);
216232
}
217233
}
218234
return std::nullopt;

src/policy/v3_policy.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ static_assert(V3_CHILD_MAX_VSIZE + MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR
4848
* count of in-mempool ancestors.
4949
* @param[in] vsize The sigop-adjusted virtual size of ptx.
5050
*
51-
* @returns debug string if an error occurs, std::nullopt otherwise.
51+
* @returns 3 possibilities:
52+
* - std::nullopt if all v3 checks were applied successfully
53+
* - debug string + pointer to a mempool sibling if this transaction would be the second child in a
54+
* 1-parent-1-child cluster; the caller may consider evicting the specified sibling or return an
55+
* error with the debug string.
56+
* - debug string + nullptr if this transaction violates some v3 rule and sibling eviction is not
57+
* applicable.
5258
*/
53-
std::optional<std::string> SingleV3Checks(const CTransactionRef& ptx,
59+
std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTransactionRef& ptx,
5460
const CTxMemPool::setEntries& mempool_ancestors,
5561
const std::set<Txid>& direct_conflicts,
5662
int64_t vsize);

0 commit comments

Comments
 (0)