wallet: Automatically abandon orphaned coinbases and their children
This commit is contained in:
1 parent
48174c0f28
commit
9addbd7890
3 files changed
+34
-12
No files matched your search
@@ -293,6 +293,7 @@ public:
|
|||||||
|
|
||||||
bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
|
bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
|
||||||
bool isConflicted() const { return state<TxStateConflicted>(); }
|
bool isConflicted() const { return state<TxStateConflicted>(); }
|
||||||
|
bool isInactive() const { return state<TxStateInactive>(); }
|
||||||
bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
|
bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
|
||||||
bool isConfirmed() const { return state<TxStateConfirmed>(); }
|
bool isConfirmed() const { return state<TxStateConfirmed>(); }
|
||||||
const uint256& GetHash() const { return tx->GetHash(); }
|
const uint256& GetHash() const { return tx->GetHash(); }
|
||||||
|
|||||||
+32
-1
@@ -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
|
//// debug print
|
||||||
WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
|
WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
|
||||||
|
|
||||||
@@ -1276,7 +1303,11 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
|
|||||||
wtx.MarkDirty();
|
wtx.MarkDirty();
|
||||||
batch.WriteTx(wtx);
|
batch.WriteTx(wtx);
|
||||||
NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
|
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) {
|
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));
|
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) {
|
for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
|
||||||
|
|||||||
@@ -37,17 +37,7 @@ class OrphanedBlockRewardTest(BitcoinTestFramework):
|
|||||||
# from the wallet can still be spent.
|
# from the wallet can still be spent.
|
||||||
self.nodes[0].invalidateblock(blk)
|
self.nodes[0].invalidateblock(blk)
|
||||||
self.generate(self.nodes[0], 152)
|
self.generate(self.nodes[0], 152)
|
||||||
# Without the following abandontransaction call, the coins are
|
# We expect the descendants of orphaned rewards to no longer be considered
|
||||||
# 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)
|
|
||||||
assert_equal(self.nodes[1].getbalances()["mine"], {
|
assert_equal(self.nodes[1].getbalances()["mine"], {
|
||||||
"trusted": 10,
|
"trusted": 10,
|
||||||
"untrusted_pending": 0,
|
"untrusted_pending": 0,
|
||||||
|
|||||||
Reference in new issue
Block a user