[wallet] never try to spend from unconfirmed TRUC that already has ancestors
What changed, and why it matters
This Bitcoin Core wallet patch prevents users from accidentally creating invalid or poorly structured transactions. Specifically, it stops the wallet from spending coins that come from an unconfirmed 'TRUC' (version 3) transaction which already has parent transactions in the mempool. Without this check, the wallet could build a transaction chain that violates Bitcoin's new TRUC rules, causing the new transaction to be rejected by the network instead of confirmed.
Treat as a low-to-moderate reliability/correctness fix. Backport to maintained branches that include TRUC (v3 transaction) support so wallets do not produce invalid chains. No immediate emergency response is warranted; no independent exploit or active abuse has been demonstrated in the supplied materials.
Security signals we found
Denial-of-service / fund-locking risk: creating a transaction that violates TRUC topology rules would be rejected by the mempool, potentially leaving user funds stuck or dependent on a parent that may never confirm.
Protocol-rule violation: TRUC transactions have stricter ancestor/descendant limits than standard transactions; the wallet was not enforcing them for coin selection.
Defensive correctness fix in coin-selection logic.
Evidence from the diff
The change adds an ancestry check in AvailableCoins() for unconfirmed TRUC (BIP-431 v3) transaction outputs. Before selecting a v3 unconfirmed UTXO for spending, the wallet now queries getTransactionAncestry() and skips the coin if ancestors > 1. This prevents the wallet from constructing a third-generation descendant (parent -> child -> grandchild) of an unconfirmed TRUC transaction, which would violate TRUC topology constraints and result in mempool rejection. The patch is narrow and defensive.
Changed components
src/wallet/spend.cppCWallet::AvailableCoins()TRUC / v3 transaction handlingInspect captured patch +5 / −0
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 146fb49e..5654c8f3 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -403,6 +403,11 @@ CoinsResult AvailableCoins(const CWallet& wallet,
if (wtx.tx->version != TRUC_VERSION) continue;
// this unconfirmed v3 transaction already has a child
if (wtx.truc_child_in_mempool.has_value()) continue;
+
+ // this unconfirmed v3 transaction has a parent: spending would create a third generation
+ size_t ancestors, descendants;
+ wallet.chain().getTransactionAncestry(wtx.tx->GetHash(), ancestors, descendants);
+ if (ancestors > 1) continue;
} else {
if (wtx.tx->version == TRUC_VERSION) continue;
Assume(!wtx.truc_child_in_mempool.has_value());
Why this scored 43/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.