diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 8e24bb95fc5..a44cc409136 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -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()); } } diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index b44f0c7d059..83c3c660135 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -258,6 +258,10 @@ public: // BlockConflicted. std::set mempool_conflicts; + // Track v3 mempool tx that spends from this tx + // so that we don't try to create another unconfirmed child + std::optional truc_child_in_mempool; + template void Serialize(Stream& s) const { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0b265e41ee2..0814d672863 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -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)