Resolves #34206
I’m not certain the test is worth keeping, but included it for now to show minimal example that crashes without fix. Can be removed.
Resolves #34206
I’m not certain the test is worth keeping, but included it for now to show minimal example that crashes without fix. Can be removed.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34238.
See the guideline for information on the review process.
| Type | Reviewers |
|---|---|
| ACK | bensig, dergoegge |
| Stale ACK | ismaelsadeeq |
If your review is incorrectly listed, please copy-paste <!–meta-tag:bot-skip–> into the comment that the bot should ignore.
Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):
2026-01-12
Code review ACK a591867c4100d349aa4b25328b609f983d7f8741
First commit removed erroneous assume, this is in line with my understanding of the solution here #34206 (comment)
The test also looks good to me. I ran the test with the assumption, and the assume got triggered; the test failed.
Without the assume the test passes.
701+ # Now try to create a v2 transaction - this triggers AvailableCoins with
702+ # check_version_trucness=true. The v2 parent has truc_child_in_mempool set
703+ # because the truc child is in mempool.
704+ new_v2_outputs = {self.bob.getnewaddress(): 0.1}
705+ raw_tx = self.alice.createrawtransaction(inputs=[], outputs=new_v2_outputs, version=2)
706+ self.alice.fundrawtransaction(raw_tx, {'include_unsafe': True})
Might be worth testing that you can also create + broadcast this transaction. But this doesn’t mean all TRUC rules are out the window:
0diff --git a/test/functional/wallet_v3_txs.py b/test/functional/wallet_v3_txs.py
1index 85865c3e54f..4728416099b 100755
2--- a/test/functional/wallet_v3_txs.py
3+++ b/test/functional/wallet_v3_txs.py
4@@ -676,8 +676,15 @@ class WalletV3Test(BitcoinTestFramework):
5 self.generate(self.nodes[0], 1)
6
7 # Verify both transactions are confirmed
8- assert_equal(self.alice.gettransaction(v2_txid)["confirmations"], 2)
9- assert_equal(self.alice.gettransaction(truc_txid)["confirmations"], 1)
10+ wallet_tx_v2 = self.alice.gettransaction(v2_txid)
11+ wallet_tx_truc = self.alice.gettransaction(truc_txid)
12+
13+ assert_equal(wallet_tx_v2["confirmations"], 2)
14+ assert_equal(wallet_tx_truc["confirmations"], 1)
15+
16+ # Check that their versions are correct
17+ assert_equal(self.alice.decoderawtransaction(wallet_tx_v2["hex"])["version"], 2)
18+ assert_equal(self.alice.decoderawtransaction(wallet_tx_truc["hex"])["version"], 3)
19
20 # Check listunspent before reorg - should have the truc output
21 unspent_before = self.alice.listunspent()
22@@ -686,6 +693,8 @@ class WalletV3Test(BitcoinTestFramework):
23
24 # Trigger the reorg
25 self.trigger_reorg(fork_blocks)
26+ # The TRUC transaction is now in a cluster of size 3, which is only permitted in a reorg.
27+ assert_equal(self.nodes[0].getmempoolcluster(truc_txid)["txcount"], 3)
28
29 # After reorg, both transactions should be back in mempool
30 mempool = self.nodes[0].getrawmempool()
31@@ -698,12 +707,34 @@ class WalletV3Test(BitcoinTestFramework):
32 unspent_txids_after = [u["txid"] for u in unspent_after]
33 assert truc_txid in unspent_txids_after
34
35+ total_unconfirmed_amount = sum([u["amount"] for u in self.alice.listunspent(minconf=0)])
36+ # We cannot create a transaction spending both outputs, regardless of version.
37+ output_too_high = {self.bob.getnewaddress(): total_unconfirmed_amount - Decimal("0.001")}
38+ for version in [2, 3]:
39+ raw_output_too_high = self.alice.createrawtransaction(inputs=[], outputs=output_too_high, version=version)
40+ assert_raises_rpc_error(
41+ -4,
42+ "Insufficient funds",
43+ self.alice.fundrawtransaction,
44+ raw_output_too_high,
45+ {'include_unsafe' : True}
46+ )
47+
48 # Now try to create a v2 transaction - this triggers AvailableCoins with
49 # check_version_trucness=true. The v2 parent has truc_child_in_mempool set
50 # because the truc child is in mempool.
51 new_v2_outputs = {self.bob.getnewaddress(): 0.1}
52- raw_tx = self.alice.createrawtransaction(inputs=[], outputs=new_v2_outputs, version=2)
53- self.alice.fundrawtransaction(raw_tx, {'include_unsafe': True})
54+ raw_v2_child = self.alice.createrawtransaction(inputs=[], outputs=new_v2_outputs, version=2)
55+ raw_v2_with_v3_sibling = self.alice.fundrawtransaction(raw_v2_child, {'include_unsafe': True})
56+
57+ # See that this transaction can be added to mempool
58+ signed_raw_v2_with_v3_sibling = self.alice.signrawtransactionwithwallet(raw_v2_with_v3_sibling["hex"])
59+ self.alice.sendrawtransaction(signed_raw_v2_with_v3_sibling["hex"])
60+
61+ # This TRUC transaction is in a cluster of size 4
62+ assert_equal(self.nodes[0].getmempoolcluster(truc_txid)["txcount"], 4)
63+
64+
65
66 if __name__ == '__main__':
67 WalletV3Test(__file__).main()