Merge #13652: rpc: Fix that CWallet::AbandonTransaction would leave the grandchildren, etc. active

89e70f9d7f Fix that CWallet::AbandonTransaction would only traverse one level (Ben Woosley)

Pull request description:

  Prior to this change, it would mark only the first layer of
  child transactions abandoned, due to always following the input `hashTx`
  rather than the current `now` tx.

Tree-SHA512: df068b49637d299ad73237c7244005fe5aa966d6beae57aff12e6948f173d9381e1b5d08533f7e3a1416991ed57f9f1f7b834057141d85c07dc60bb1f0872cea
This commit is contained in:
Wladimir J. van der Laan 2018-07-16 14:52:16 +02:00
commit 17943f77bd
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
2 changed files with 11 additions and 3 deletions

View file

@ -1143,7 +1143,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
batch.WriteTx(wtx); batch.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); NotifyTransactionChanged(this, 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
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0)); TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) { while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) { if (!done.count(iter->second)) {
todo.insert(iter->second); todo.insert(iter->second);

View file

@ -70,9 +70,17 @@ class AbandonConflictTest(BitcoinTestFramework):
signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs)) signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])
# Create a child tx spending ABC2
signed3_change = Decimal("24.999")
inputs = [ {"txid":txABC2, "vout":0} ]
outputs = { self.nodes[0].getnewaddress(): signed3_change }
signed3 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
# note tx is never directly referenced, only abandoned as a child of the above
self.nodes[0].sendrawtransaction(signed3["hex"])
# In mempool txs from self should increase balance from change # In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance() newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("30") + Decimal("24.9996")) assert_equal(newbalance, balance - Decimal("30") + signed3_change)
balance = newbalance balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool # Restart the node with a higher min relay fee so the parent tx is no longer in mempool
@ -87,7 +95,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Not in mempool txs from self should only reduce balance # Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received # inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance() newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("24.9996")) assert_equal(newbalance, balance - signed3_change)
# Unconfirmed received funds that are not in mempool, also shouldn't show # Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance # up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance() unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()