wallet: abandon inactive coinbase tx and their descendants during startup

This commit is contained in:
furszy 2025-02-04 10:34:48 -05:00
parent 0a931a9787
commit 474139aa9b
No known key found for this signature in database
GPG key ID: 5DD23CCC686AA623
3 changed files with 17 additions and 5 deletions

View file

@ -1315,12 +1315,15 @@ void CWallet::MarkInputsDirty(const CTransactionRef& tx)
bool CWallet::AbandonTransaction(const uint256& hashTx)
{
LOCK(cs_wallet);
// Can't mark abandoned if confirmed or in mempool
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
const CWalletTx& origtx = it->second;
if (GetTxDepthInMainChain(origtx) != 0 || origtx.InMempool()) {
return AbandonTransaction(it->second);
}
bool CWallet::AbandonTransaction(CWalletTx& tx)
{
// Can't mark abandoned if confirmed or in mempool
if (GetTxDepthInMainChain(tx) != 0 || tx.InMempool()) {
return false;
}
@ -1342,7 +1345,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
// Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
// states change will remain abandoned and will require manual broadcast if the user wants them.
RecursiveUpdateTxState(hashTx, try_updating_state);
RecursiveUpdateTxState(tx.GetHash(), try_updating_state);
return true;
}

View file

@ -871,6 +871,7 @@ public:
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);
bool AbandonTransaction(CWalletTx& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Mark a transaction as replaced by another transaction. */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);

View file

@ -1115,6 +1115,14 @@ static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, std::vecto
});
result = std::max(result, order_pos_res.m_result);
// After loading all tx records, abandon any coinbase that is no longer in the active chain.
// This could happen during an external wallet load, or if the user replaced the chain data.
for (auto& [id, wtx] : pwallet->mapWallet) {
if (wtx.IsCoinBase() && wtx.isInactive()) {
pwallet->AbandonTransaction(wtx);
}
}
return result;
}