mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-21 15:50:07 +01:00
test: add coverage for issue 34206
This commit is contained in:
@@ -19,6 +19,10 @@ from test_framework.script import (
|
||||
|
||||
from test_framework.script_util import bulk_vout
|
||||
|
||||
from test_framework.blocktools import (
|
||||
create_empty_fork,
|
||||
)
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
@@ -84,6 +88,12 @@ class WalletV3Test(BitcoinTestFramework):
|
||||
test_func(2, 3)
|
||||
test_func(3, 2)
|
||||
|
||||
def trigger_reorg(self, fork_blocks):
|
||||
"""Trigger reorg of the fork blocks."""
|
||||
for block in fork_blocks:
|
||||
self.nodes[0].submitblock(block.serialize().hex())
|
||||
assert_equal(self.nodes[0].getbestblockhash(), fork_blocks[-1].hash_hex)
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].createwallet("alice")
|
||||
self.alice = self.nodes[0].get_wallet_rpc("alice")
|
||||
@@ -120,6 +130,7 @@ class WalletV3Test(BitcoinTestFramework):
|
||||
self.mix_non_truc_versions()
|
||||
self.cant_spend_multiple_unconfirmed_truc_outputs()
|
||||
self.test_spend_third_generation()
|
||||
self.test_coins_availability_reorg()
|
||||
|
||||
@cleanup
|
||||
def tx_spends_unconfirmed_tx_with_wrong_version(self, version_a, version_b):
|
||||
@@ -630,5 +641,100 @@ class WalletV3Test(BitcoinTestFramework):
|
||||
version=3
|
||||
)
|
||||
|
||||
@cleanup
|
||||
def test_coins_availability_reorg(self):
|
||||
self.log.info("Test coin availability after reorg with v2 parent and truc child")
|
||||
|
||||
# Prep fork blocks
|
||||
fork_blocks = create_empty_fork(self.nodes[0])
|
||||
|
||||
# Send funds to alice so she can create transactions
|
||||
outputs = {self.alice.getnewaddress(): 5.0}
|
||||
self.send_tx(self.charlie, [], outputs, 2)
|
||||
self.generate(self.nodes[0], 1)
|
||||
|
||||
# Alice creates a v2 transaction with 2 outputs
|
||||
alice_unspent = self.alice.listunspent()[0]
|
||||
v2_outputs = [
|
||||
{self.alice.getnewaddress(): 2.5},
|
||||
{self.alice.getnewaddress(): 2.4999},
|
||||
]
|
||||
v2_txid = self.send_tx(self.alice, [alice_unspent], v2_outputs, 2)
|
||||
|
||||
# Mine the v2 transaction in one block
|
||||
self.generate(self.nodes[0], 1)
|
||||
|
||||
# Get the output from the v2 transaction for chaining
|
||||
v2_utxo = self.alice.listunspent(minconf=1)[0]
|
||||
assert_equal(v2_utxo["txid"], v2_txid)
|
||||
|
||||
# Alice creates a truc child chaining from the v2 utxo
|
||||
truc_outputs = {self.alice.getnewaddress(): v2_utxo["amount"] - Decimal("0.0001")}
|
||||
truc_txid = self.send_tx(self.alice, [v2_utxo], truc_outputs, 3)
|
||||
|
||||
# Mine the truc transaction in a second block
|
||||
self.generate(self.nodes[0], 1)
|
||||
|
||||
# Verify both transactions are confirmed
|
||||
wallet_tx_v2 = self.alice.gettransaction(v2_txid)
|
||||
wallet_tx_truc = self.alice.gettransaction(truc_txid)
|
||||
|
||||
assert_equal(wallet_tx_v2["confirmations"], 2)
|
||||
assert_equal(wallet_tx_truc["confirmations"], 1)
|
||||
|
||||
# Check that their versions are correct
|
||||
assert_equal(self.alice.decoderawtransaction(wallet_tx_v2["hex"])["version"], 2)
|
||||
assert_equal(self.alice.decoderawtransaction(wallet_tx_truc["hex"])["version"], 3)
|
||||
|
||||
# Check listunspent before reorg - should have the truc output
|
||||
unspent_before = self.alice.listunspent()
|
||||
truc_output_txids = [u["txid"] for u in unspent_before]
|
||||
assert truc_txid in truc_output_txids
|
||||
|
||||
# Trigger the reorg
|
||||
self.trigger_reorg(fork_blocks)
|
||||
# The TRUC transaction is now in a cluster of size 3, which is only permitted in a reorg.
|
||||
assert_equal(self.nodes[0].getmempoolcluster(truc_txid)["txcount"], 3)
|
||||
|
||||
# After reorg, both transactions should be back in mempool
|
||||
mempool = self.nodes[0].getrawmempool()
|
||||
assert v2_txid in mempool
|
||||
assert truc_txid in mempool
|
||||
|
||||
# Check listunspent after reorg - the truc output should still appear
|
||||
# as unconfirmed since the transaction is in the mempool
|
||||
unspent_after = self.alice.listunspent(minconf=0)
|
||||
unspent_txids_after = [u["txid"] for u in unspent_after]
|
||||
assert truc_txid in unspent_txids_after
|
||||
|
||||
total_unconfirmed_amount = sum([u["amount"] for u in self.alice.listunspent(minconf=0)])
|
||||
# We cannot create a transaction spending both outputs, regardless of version.
|
||||
output_too_high = {self.bob.getnewaddress(): total_unconfirmed_amount - Decimal("1")}
|
||||
for version in [2, 3]:
|
||||
raw_output_too_high = self.alice.createrawtransaction(inputs=[], outputs=output_too_high, version=version)
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"Insufficient funds",
|
||||
self.alice.fundrawtransaction,
|
||||
raw_output_too_high,
|
||||
{'include_unsafe' : True}
|
||||
)
|
||||
|
||||
# Now try to create a v2 transaction - this triggers AvailableCoins with
|
||||
# check_version_trucness=true. The v2 parent has truc_child_in_mempool set
|
||||
# because the truc child is in mempool.
|
||||
new_v2_outputs = {self.bob.getnewaddress(): 0.1}
|
||||
raw_v2_child = self.alice.createrawtransaction(inputs=[], outputs=new_v2_outputs, version=2)
|
||||
raw_v2_with_v3_sibling = self.alice.fundrawtransaction(raw_v2_child, {'include_unsafe': True})
|
||||
|
||||
# See that this transaction can be added to mempool
|
||||
signed_raw_v2_with_v3_sibling = self.alice.signrawtransactionwithwallet(raw_v2_with_v3_sibling["hex"])
|
||||
self.alice.sendrawtransaction(signed_raw_v2_with_v3_sibling["hex"])
|
||||
|
||||
# This TRUC transaction is in a cluster of size 4
|
||||
assert_equal(self.nodes[0].getmempoolcluster(truc_txid)["txcount"], 4)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
WalletV3Test(__file__).main()
|
||||
|
||||
Reference in New Issue
Block a user