0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-02 09:46:52 -05:00

wallet: Automatically abandon orphaned coinbases and their children

This commit is contained in:
Andrew Chow 2022-11-14 15:14:12 -05:00
parent 48174c0f28
commit 9addbd7890
3 changed files with 34 additions and 12 deletions

View file

@ -293,6 +293,7 @@ public:
bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
bool isConflicted() const { return state<TxStateConflicted>(); }
bool isInactive() const { return state<TxStateInactive>(); }
bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
bool isConfirmed() const { return state<TxStateConfirmed>(); }
const uint256& GetHash() const { return tx->GetHash(); }

View file

@ -1067,6 +1067,33 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
}
}
// Mark inactive coinbase transactions and their descendants as abandoned
if (wtx.IsCoinBase() && wtx.isInactive()) {
std::vector<CWalletTx*> txs{&wtx};
TxStateInactive inactive_state = TxStateInactive{/*abandoned=*/true};
while (!txs.empty()) {
CWalletTx* desc_tx = txs.back();
txs.pop_back();
desc_tx->m_state = inactive_state;
// Break caches since we have changed the state
desc_tx->MarkDirty();
batch.WriteTx(*desc_tx);
MarkInputsDirty(desc_tx->tx);
for (unsigned int i = 0; i < desc_tx->tx->vout.size(); ++i) {
COutPoint outpoint(desc_tx->GetHash(), i);
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
const auto wit = mapWallet.find(it->second);
if (wit != mapWallet.end()) {
txs.push_back(&wit->second);
}
}
}
}
}
//// debug print
WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
@ -1276,7 +1303,11 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
wtx.MarkDirty();
batch.WriteTx(wtx);
NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
// States are not permanent, so these transactions can become unabandoned if they are re-added to the
// mempool, or confirmed in a block, or conflicted.
// 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.
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {

View file

@ -37,17 +37,7 @@ class OrphanedBlockRewardTest(BitcoinTestFramework):
# from the wallet can still be spent.
self.nodes[0].invalidateblock(blk)
self.generate(self.nodes[0], 152)
# Without the following abandontransaction call, the coins are
# not considered available yet.
assert_equal(self.nodes[1].getbalances()["mine"], {
"trusted": 0,
"untrusted_pending": 0,
"immature": 0,
})
# The following abandontransaction is necessary to make the later
# lines succeed, and probably should not be needed; see
# https://github.com/bitcoin/bitcoin/issues/14148.
self.nodes[1].abandontransaction(txid)
# We expect the descendants of orphaned rewards to no longer be considered
assert_equal(self.nodes[1].getbalances()["mine"], {
"trusted": 10,
"untrusted_pending": 0,