8
8
that spend (directly or indirectly) coinbase transactions.
9
9
"""
10
10
11
- from test_framework .blocktools import (
12
- COINBASE_MATURITY ,
13
- create_raw_transaction ,
14
- )
15
11
from test_framework .test_framework import BitcoinTestFramework
16
12
from test_framework .util import assert_equal , assert_raises_rpc_error
17
-
13
+ from test_framework . wallet import MiniWallet
18
14
19
15
class MempoolCoinbaseTest (BitcoinTestFramework ):
20
16
def set_test_params (self ):
@@ -26,86 +22,90 @@ def set_test_params(self):
26
22
[]
27
23
]
28
24
29
- def skip_test_if_missing_module (self ):
30
- self .skip_if_no_wallet ()
31
-
32
25
def run_test (self ):
26
+ wallet = MiniWallet (self .nodes [0 ])
27
+
33
28
# Start with a 200 block chain
34
29
assert_equal (self .nodes [0 ].getblockcount (), 200 )
35
30
36
- # Mine four blocks. After this, nodes[0] blocks
37
- # 101, 102, and 103 are spend-able.
38
- new_blocks = self .nodes [1 ].generate (4 )
39
- self .sync_all ()
40
-
41
- node0_address = self .nodes [0 ].getnewaddress ()
42
- node1_address = self .nodes [1 ].getnewaddress ()
31
+ self .log .info ("Add 4 coinbase utxos to the miniwallet" )
32
+ # Block 76 contains the first spendable coinbase txs.
33
+ first_block = 76
34
+ wallet .scan_blocks (start = first_block , num = 4 )
43
35
44
36
# Three scenarios for re-orging coinbase spends in the memory pool:
45
- # 1. Direct coinbase spend : spend_101
46
- # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
47
- # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
48
- # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
37
+ # 1. Direct coinbase spend : spend_1
38
+ # 2. Indirect (coinbase spend in chain, child in mempool) : spend_2 and spend_2_1
39
+ # 3. Indirect (coinbase and child both in chain) : spend_3 and spend_3_1
40
+ # Use invalidateblock to make all of the above coinbase spends invalid (immature coinbase),
49
41
# and make sure the mempool code behaves correctly.
50
- b = [self .nodes [0 ].getblockhash (n ) for n in range (COINBASE_MATURITY + 1 , COINBASE_MATURITY + 5 )]
42
+ b = [self .nodes [0 ].getblockhash (n ) for n in range (first_block , first_block + 4 )]
51
43
coinbase_txids = [self .nodes [0 ].getblock (h )['tx' ][0 ] for h in b ]
52
- spend_101_raw = create_raw_transaction (self .nodes [0 ], coinbase_txids [1 ], node1_address , amount = 49.99 )
53
- spend_102_raw = create_raw_transaction (self .nodes [0 ], coinbase_txids [2 ], node0_address , amount = 49.99 )
54
- spend_103_raw = create_raw_transaction (self .nodes [0 ], coinbase_txids [3 ], node0_address , amount = 49.99 )
55
-
56
- # Create a transaction which is time-locked to two blocks in the future
57
- timelock_tx = self .nodes [0 ].createrawtransaction (
58
- inputs = [{
59
- "txid" : coinbase_txids [0 ],
60
- "vout" : 0 ,
61
- }],
62
- outputs = {node0_address : 49.99 },
63
- locktime = self .nodes [0 ].getblockcount () + 2 ,
64
- )
65
- timelock_tx = self .nodes [0 ].signrawtransactionwithwallet (timelock_tx )["hex" ]
66
- # This will raise an exception because the timelock transaction is too immature to spend
44
+ utxo_1 = wallet .get_utxo (txid = coinbase_txids [1 ])
45
+ utxo_2 = wallet .get_utxo (txid = coinbase_txids [2 ])
46
+ utxo_3 = wallet .get_utxo (txid = coinbase_txids [3 ])
47
+ self .log .info ("Create three transactions spending from coinbase utxos: spend_1, spend_2, spend_3" )
48
+ spend_1 = wallet .create_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = utxo_1 )
49
+ spend_2 = wallet .create_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = utxo_2 )
50
+ spend_3 = wallet .create_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = utxo_3 )
51
+
52
+ self .log .info ("Create another transaction which is time-locked to two blocks in the future" )
53
+ utxo = wallet .get_utxo (txid = coinbase_txids [0 ])
54
+ timelock_tx = wallet .create_self_transfer (
55
+ from_node = self .nodes [0 ],
56
+ utxo_to_spend = utxo ,
57
+ mempool_valid = False ,
58
+ locktime = self .nodes [0 ].getblockcount () + 2
59
+ )['hex' ]
60
+
61
+ self .log .info ("Check that the time-locked transaction is too immature to spend" )
67
62
assert_raises_rpc_error (- 26 , "non-final" , self .nodes [0 ].sendrawtransaction , timelock_tx )
68
63
69
- # Broadcast and mine spend_102 and 103:
70
- spend_102_id = self .nodes [0 ].sendrawtransaction (spend_102_raw )
71
- spend_103_id = self .nodes [0 ].sendrawtransaction (spend_103_raw )
64
+ self .log .info ("Broadcast and mine spend_2 and spend_3" )
65
+ wallet .sendrawtransaction (from_node = self .nodes [0 ], tx_hex = spend_2 ['hex' ])
66
+ wallet .sendrawtransaction (from_node = self .nodes [0 ], tx_hex = spend_3 ['hex' ])
67
+ self .log .info ("Generate a block" )
72
68
self .nodes [0 ].generate (1 )
73
- # Time -locked transaction is still too immature to spend
69
+ self . log . info ( "Check that time -locked transaction is still too immature to spend" )
74
70
assert_raises_rpc_error (- 26 , 'non-final' , self .nodes [0 ].sendrawtransaction , timelock_tx )
75
71
76
- # Create 102_1 and 103_1:
77
- spend_102_1_raw = create_raw_transaction (self .nodes [0 ], spend_102_id , node1_address , amount = 49.98 )
78
- spend_103_1_raw = create_raw_transaction (self .nodes [0 ], spend_103_id , node1_address , amount = 49.98 )
72
+ self .log .info ("Create spend_2_1 and spend_3_1" )
73
+ spend_2_utxo = wallet .get_utxo (txid = spend_2 ['txid' ])
74
+ spend_2_1 = wallet .create_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = spend_2_utxo )
75
+ spend_3_utxo = wallet .get_utxo (txid = spend_3 ['txid' ])
76
+ spend_3_1 = wallet .create_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = spend_3_utxo )
79
77
80
- # Broadcast and mine 103_1:
81
- spend_103_1_id = self .nodes [0 ].sendrawtransaction (spend_103_1_raw )
78
+ self .log .info ("Broadcast and mine spend_3_1" )
79
+ spend_3_1_id = self .nodes [0 ].sendrawtransaction (spend_3_1 ['hex' ])
80
+ self .log .info ("Generate a block" )
82
81
last_block = self .nodes [0 ].generate (1 )
83
82
# Sync blocks, so that peer 1 gets the block before timelock_tx
84
83
# Otherwise, peer 1 would put the timelock_tx in recentRejects
85
84
self .sync_all ()
86
85
87
- # Time -locked transaction can now be spent
86
+ self . log . info ( "The time -locked transaction can now be spent" )
88
87
timelock_tx_id = self .nodes [0 ].sendrawtransaction (timelock_tx )
89
88
90
- # ... now put spend_101 and spend_102_1 in memory pools:
91
- spend_101_id = self .nodes [0 ].sendrawtransaction (spend_101_raw )
92
- spend_102_1_id = self .nodes [0 ].sendrawtransaction (spend_102_1_raw )
89
+ self . log . info ( "Add spend_1 and spend_2_1 to the mempool" )
90
+ spend_1_id = self .nodes [0 ].sendrawtransaction (spend_1 [ 'hex' ] )
91
+ spend_2_1_id = self .nodes [0 ].sendrawtransaction (spend_2_1 [ 'hex' ] )
93
92
94
- assert_equal (set (self .nodes [0 ].getrawmempool ()), {spend_101_id , spend_102_1_id , timelock_tx_id })
93
+ assert_equal (set (self .nodes [0 ].getrawmempool ()), {spend_1_id , spend_2_1_id , timelock_tx_id })
95
94
self .sync_all ()
96
95
96
+ self .log .info ("invalidate the last block" )
97
97
for node in self .nodes :
98
98
node .invalidateblock (last_block [0 ])
99
- # Time -locked transaction is now too immature and has been removed from the mempool
100
- # spend_103_1 has been re-orged out of the chain and is back in the mempool
101
- assert_equal (set (self .nodes [0 ].getrawmempool ()), {spend_101_id , spend_102_1_id , spend_103_1_id })
99
+ self . log . info ( "The time -locked transaction is now too immature and has been removed from the mempool" )
100
+ self . log . info ( "spend_3_1 has been re-orged out of the chain and is back in the mempool" )
101
+ assert_equal (set (self .nodes [0 ].getrawmempool ()), {spend_1_id , spend_2_1_id , spend_3_1_id })
102
102
103
- # Use invalidateblock to re-org back and make all those coinbase spends
104
- # immature/invalid:
103
+ self . log . info ( " Use invalidateblock to re-org back and make all those coinbase spends immature/invalid" )
104
+ b = self . nodes [ 0 ]. getblockhash ( first_block + 100 )
105
105
for node in self .nodes :
106
- node .invalidateblock (new_blocks [ 0 ] )
106
+ node .invalidateblock (b )
107
107
108
- # mempool should be empty.
108
+ self . log . info ( "Check that the mempool is empty" )
109
109
assert_equal (set (self .nodes [0 ].getrawmempool ()), set ())
110
110
self .sync_all ()
111
111
0 commit comments