Skip to content

Conversation

@furszy
Copy link
Member

@furszy furszy commented Feb 4, 2025

Since #26499, we mark coinbase transactions and their descendants as abandoned when a reorg arises through the "block disconnection" signal handler. However, this does not cover all scenarios; external wallets could contain coinbase transactions from blocks the node has not seen yet, or the user could have replaced the chain with an earlier or different version (one without the coinbase chain).

This affects balance calculation as well as mempool rebroadcast (descendants shouldn't be relayed).
Fix this by marking orphaned coinbase transactions and their descendants as abandoned during wallet startup.

@DrahtBot
Copy link
Contributor

DrahtBot commented Feb 4, 2025

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31794.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK rkrux, mzumsande, achow101
Stale ACK Eunovo

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

@furszy
Copy link
Member Author

furszy commented Feb 4, 2025

Test failure is unrelated.

@DrahtBot DrahtBot removed the CI failed label Feb 4, 2025
Copy link
Contributor

@Eunovo Eunovo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 0331060

While testing, I noticed that trying to abandon a tx in mempool wasn't covered in the functional tests.
Here's a diff for that.

diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index ce0f4d099b..2bbfaee3db 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -45,6 +45,10 @@ class AbandonConflictTest(BitcoinTestFramework):
         txB = alice.sendtoaddress(alice.getnewaddress(), Decimal("10"))
         txC = alice.sendtoaddress(alice.getnewaddress(), Decimal("10"))
         self.sync_mempools()
+
+        # Can not abandon transaction in mempool
+        assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: alice.abandontransaction(txid=txA))
+
         self.generate(self.nodes[1], 1)
 
         # Can not abandon non-wallet transaction

@furszy furszy force-pushed the 2025_wallet_abandon_coinbase_during_startup branch from 0331060 to 409241d Compare February 10, 2025 18:30
@furszy
Copy link
Member Author

furszy commented Feb 10, 2025

Thanks for the review Eunovo. Feedback tackled.

While testing, I noticed that trying to abandon a tx in mempool wasn't covered in the functional tests

That seems to be material for a different PR (a quick one). Happy to ACK it if you push it.

@Eunovo
Copy link
Contributor

Eunovo commented Feb 10, 2025

That seems to be material for a different PR (a quick one). Happy to ACK it if you push it.

It'd be a really tiny PR. I think you can just add it but I'm happy to open a new one if needed.

@Eunovo
Copy link
Contributor

Eunovo commented Feb 10, 2025

ReACK 409241d

Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursory review, will look again soon

// states change will remain abandoned and will require manual broadcast if the user wants them.

RecursiveUpdateTxState(hashTx, try_updating_state);
RecursiveUpdateTxState(tx.GetHash(), try_updating_state);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RecursiveUpdateTxState() accepts a const uint256& tx_hash as the first argument but tx.GetHash() returns a Txid&, which is Txid = transaction_identifier<false>.
IIUC, this works because of this conversion function: https://github.com/bitcoin/bitcoin/blob/master/src/util/transaction_identifier.h#L67
A comment suggests for the new code to use ToUint256 instead: https://github.com/bitcoin/bitcoin/blob/master/src/util/transaction_identifier.h#L62

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't started following this pattern in the wallet sources yet. Might be better to do it all at once in a single PR and verify that nothing breaks (which should be the case because we don't use the witness id).

Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 409241db5dca0b23f5c7714f99be52411fc5541e

Build and tests successful.

Seems to be an edge case that's fixed but I'm in favour because it ensures data correctness.

Re: this comment #31794 (review)
I agree with @furszy that this should be in a separate PR because of the separate context.

@furszy furszy force-pushed the 2025_wallet_abandon_coinbase_during_startup branch from 409241d to 3c89cab Compare February 14, 2025 20:00
@achow101
Copy link
Member

ACK 3c89cab06a6259fa70eaf3a78c01ee42780c4e27

@DrahtBot DrahtBot requested review from Eunovo and rkrux February 14, 2025 22:09
Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git range-diff 409241db5dca0b23f5c7714f99be52411fc5541e...3c89cab06a6259fa70eaf3a78c01ee42780c4e27

Newer changes are updating the functional tests based on the comments suggested earlier. I will ACK once a small bug is corrected.

@furszy furszy force-pushed the 2025_wallet_abandon_coinbase_during_startup branch from 3c89cab to e4dd5a3 Compare February 15, 2025 15:49
Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK e4dd5a3

@DrahtBot DrahtBot requested a review from achow101 February 15, 2025 17:51
Copy link
Contributor

@mzumsande mzumsande left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review ACK e4dd5a3

Another scenario that wasn't explicitly mentioned in the OP is a simple reorg: Wallet has a coinbase tx, then it's unloaded, then the node undergoes a reorg, then the wallet is loaded again, and the coinbase tx should be abandoned. That would also make for a simpler test (no need to copy datadirs).

@achow101
Copy link
Member

ACK e4dd5a3

@achow101 achow101 merged commit dc3a714 into bitcoin:master Feb 19, 2025
18 checks passed
sedited added a commit to sedited/rust-bitcoinkernel that referenced this pull request Feb 22, 2025