wallet: don't include unconfirmed v3 txs with children in available coins

This commit is contained in:
ishaanam
2025-07-08 15:09:16 -04:00
parent ec2676becd
commit 2e9617664e
3 changed files with 40 additions and 0 deletions

View File

@@ -390,8 +390,11 @@ CoinsResult AvailableCoins(const CWallet& wallet,
if (nDepth == 0 && params.check_version_trucness) {
if (coinControl->m_version == TRUC_VERSION) {
if (wtx.tx->version != TRUC_VERSION) continue;
// this unconfirmed v3 transaction already has a child
if (wtx.truc_child_in_mempool.has_value()) continue;
} else {
if (wtx.tx->version == TRUC_VERSION) continue;
Assume(!wtx.truc_child_in_mempool.has_value());
}
}

View File

@@ -258,6 +258,10 @@ public:
// BlockConflicted.
std::set<Txid> mempool_conflicts;
// Track v3 mempool tx that spends from this tx
// so that we don't try to create another unconfirmed child
std::optional<Txid> truc_child_in_mempool;
template<typename Stream>
void Serialize(Stream& s) const
{

View File

@@ -30,6 +30,7 @@
#include <node/types.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <policy/truc_policy.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <psbt.h>
@@ -1388,6 +1389,22 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
return wtx.mempool_conflicts.insert(txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED;
});
}
}
if (tx->version == TRUC_VERSION) {
// Unconfirmed TRUC transactions are only allowed a 1-parent-1-child topology.
// For any unconfirmed v3 parents (there should be a maximum of 1 except in reorgs),
// record this child so the wallet doesn't try to spend any other outputs
for (const CTxIn& tx_in : tx->vin) {
auto parent_it = mapWallet.find(tx_in.prevout.hash);
if (parent_it != mapWallet.end()) {
CWalletTx& parent_wtx = parent_it->second;
if (parent_wtx.isUnconfirmed()) {
parent_wtx.truc_child_in_mempool = tx->GetHash();
}
}
}
}
}
@@ -1441,6 +1458,22 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
});
}
}
if (tx->version == TRUC_VERSION) {
// If this tx has a parent, unset its truc_child_in_mempool to make it possible
// to spend from the parent again. If this tx was replaced by another
// child of the same parent, transactionAddedToMempool
// will update truc_child_in_mempool
for (const CTxIn& tx_in : tx->vin) {
auto parent_it = mapWallet.find(tx_in.prevout.hash);
if (parent_it != mapWallet.end()) {
CWalletTx& parent_wtx = parent_it->second;
if (parent_wtx.truc_child_in_mempool == tx->GetHash()) {
parent_wtx.truc_child_in_mempool = std::nullopt;
}
}
}
}
}
void CWallet::blockConnected(ChainstateRole role, const interfaces::BlockInfo& block)