Skip to content

Commit dced203

Browse files
ishaanamariard
andcommitted
wallet, tests: mark unconflicted txs as inactive
In `blockDisconnected`, for each transaction in the block, look for any wallet transactions spending the same inputs. If any of these transactions were marked conflicted, they are now marked as inactive. Co-authored-by: ariard <[email protected]>
1 parent 096487c commit dced203

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

src/wallet/wallet.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,8 +1446,36 @@ void CWallet::blockDisconnected(const interfaces::BlockInfo& block)
14461446
// future with a stickier abandoned state or even removing abandontransaction call.
14471447
m_last_block_processed_height = block.height - 1;
14481448
m_last_block_processed = *Assert(block.prev_hash);
1449+
1450+
int disconnect_height = block.height;
1451+
14491452
for (const CTransactionRef& ptx : Assert(block.data)->vtx) {
14501453
SyncTransaction(ptx, TxStateInactive{});
1454+
1455+
for (const CTxIn& tx_in : ptx->vin) {
1456+
// No other wallet transactions conflicted with this transaction
1457+
if (mapTxSpends.count(tx_in.prevout) < 1) continue;
1458+
1459+
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.prevout);
1460+
1461+
// For all of the spends that conflict with this transaction
1462+
for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1463+
CWalletTx& wtx = mapWallet.find(_it->second)->second;
1464+
1465+
if (!wtx.isConflicted()) continue;
1466+
1467+
auto try_updating_state = [&](CWalletTx& tx) {
1468+
if (!tx.isConflicted()) return TxUpdate::UNCHANGED;
1469+
if (tx.state<TxStateConflicted>()->conflicting_block_height >= disconnect_height) {
1470+
tx.m_state = TxStateInactive{};
1471+
return TxUpdate::CHANGED;
1472+
}
1473+
return TxUpdate::UNCHANGED;
1474+
};
1475+
1476+
RecursiveUpdateTxState(wtx.tx->GetHash(), try_updating_state);
1477+
}
1478+
}
14511479
}
14521480
}
14531481

test/functional/wallet_abandonconflict.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -226,20 +226,16 @@ def run_test(self):
226226
assert_equal(double_spend["walletconflicts"], [txAB1])
227227

228228
# Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
229+
assert_equal(alice.gettransaction(txAB1)["confirmations"], -1)
229230
newbalance = alice.getbalance()
230231
assert_equal(newbalance, balance + Decimal("20"))
231232
balance = newbalance
232233

233-
# There is currently a minor bug around this and so this test doesn't work. See Issue #7315
234-
# Invalidate the block with the double spend and B's 10 BTC output should no longer be available
235-
# Don't think C's should either
234+
# Invalidate the block with the double spend. B & C's 10 BTC outputs should no longer be available
236235
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
236+
assert_equal(alice.gettransaction(txAB1)["confirmations"], 0)
237237
newbalance = alice.getbalance()
238-
#assert_equal(newbalance, balance - Decimal("10"))
239-
self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
240-
self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
241-
assert_equal(balance, newbalance)
242-
238+
assert_equal(newbalance, balance - Decimal("20"))
243239

244240
if __name__ == '__main__':
245241
AbandonConflictTest().main()

0 commit comments

Comments
 (0)