diff options
author | ishaanam <ishaana.misra@gmail.com> | 2023-03-04 19:35:41 -0500 |
---|---|---|
committer | ishaanam <ishaana.misra@gmail.com> | 2023-05-14 10:45:21 -0400 |
commit | dced203162d45e542f187f8d0d07dab85c52cf28 (patch) | |
tree | 51bb5bb8ba2da0e4ad8639eaf8beb127e738c22c | |
parent | 096487c4dcfadebe5ca959927f5426cae1c304d5 (diff) | |
download | bitcoin-dced203162d45e542f187f8d0d07dab85c52cf28.tar.xz |
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 <antoine.riard@gmail.com>
-rw-r--r-- | src/wallet/wallet.cpp | 28 | ||||
-rwxr-xr-x | test/functional/wallet_abandonconflict.py | 12 |
2 files changed, 32 insertions, 8 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 86cea876c2..671e4e4c6f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1446,8 +1446,36 @@ void CWallet::blockDisconnected(const interfaces::BlockInfo& block) // future with a stickier abandoned state or even removing abandontransaction call. m_last_block_processed_height = block.height - 1; m_last_block_processed = *Assert(block.prev_hash); + + int disconnect_height = block.height; + for (const CTransactionRef& ptx : Assert(block.data)->vtx) { SyncTransaction(ptx, TxStateInactive{}); + + for (const CTxIn& tx_in : ptx->vin) { + // No other wallet transactions conflicted with this transaction + if (mapTxSpends.count(tx_in.prevout) < 1) continue; + + std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.prevout); + + // For all of the spends that conflict with this transaction + for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) { + CWalletTx& wtx = mapWallet.find(_it->second)->second; + + if (!wtx.isConflicted()) continue; + + auto try_updating_state = [&](CWalletTx& tx) { + if (!tx.isConflicted()) return TxUpdate::UNCHANGED; + if (tx.state<TxStateConflicted>()->conflicting_block_height >= disconnect_height) { + tx.m_state = TxStateInactive{}; + return TxUpdate::CHANGED; + } + return TxUpdate::UNCHANGED; + }; + + RecursiveUpdateTxState(wtx.tx->GetHash(), try_updating_state); + } + } } } diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index 934f44588d..2691507773 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -226,20 +226,16 @@ class AbandonConflictTest(BitcoinTestFramework): assert_equal(double_spend["walletconflicts"], [txAB1]) # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted + assert_equal(alice.gettransaction(txAB1)["confirmations"], -1) newbalance = alice.getbalance() assert_equal(newbalance, balance + Decimal("20")) balance = newbalance - # There is currently a minor bug around this and so this test doesn't work. See Issue #7315 - # Invalidate the block with the double spend and B's 10 BTC output should no longer be available - # Don't think C's should either + # Invalidate the block with the double spend. B & C's 10 BTC outputs should no longer be available self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + assert_equal(alice.gettransaction(txAB1)["confirmations"], 0) newbalance = alice.getbalance() - #assert_equal(newbalance, balance - Decimal("10")) - self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer") - self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") - assert_equal(balance, newbalance) - + assert_equal(newbalance, balance - Decimal("20")) if __name__ == '__main__': AbandonConflictTest().main() |