44# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55"""Test mempool acceptance of raw transactions."""
66
7+ from copy import deepcopy
78from decimal import Decimal
89import math
910
3435 assert_equal ,
3536 assert_raises_rpc_error ,
3637)
38+ from test_framework .wallet import MiniWallet
3739
3840
3941class MempoolAcceptanceTest (BitcoinTestFramework ):
@@ -44,9 +46,6 @@ def set_test_params(self):
4446 ]] * self .num_nodes
4547 self .supports_cli = False
4648
47- def skip_test_if_missing_module (self ):
48- self .skip_if_no_wallet ()
49-
5049 def check_mempool_result (self , result_expected , * args , ** kwargs ):
5150 """Wrapper to check result of testmempoolaccept on node_0's mempool"""
5251 result_test = self .nodes [0 ].testmempoolaccept (* args , ** kwargs )
@@ -57,12 +56,13 @@ def check_mempool_result(self, result_expected, *args, **kwargs):
5756
5857 def run_test (self ):
5958 node = self .nodes [0 ]
59+ self .wallet = MiniWallet (node )
60+ self .wallet .rescan_utxos ()
6061
6162 self .log .info ('Start with empty mempool, and 200 blocks' )
6263 self .mempool_size = 0
6364 assert_equal (node .getblockcount (), 200 )
6465 assert_equal (node .getmempoolinfo ()['size' ], self .mempool_size )
65- coins = node .listunspent ()
6666
6767 self .log .info ('Should not accept garbage to testmempoolaccept' )
6868 assert_raises_rpc_error (- 3 , 'Expected type array, got string' , lambda : node .testmempoolaccept (rawtxs = 'ff00baar' ))
@@ -71,12 +71,12 @@ def run_test(self):
7171 assert_raises_rpc_error (- 22 , 'TX decode failed' , lambda : node .testmempoolaccept (rawtxs = ['ff00baar' ]))
7272
7373 self .log .info ('A transaction already in the blockchain' )
74- coin = coins . pop () # Pick a random coin(base) to spend
75- raw_tx_in_block = node . signrawtransactionwithwallet ( node . createrawtransaction (
76- inputs = [{ 'txid' : coin [ 'txid' ], 'vout' : coin [ 'vout' ]}],
77- outputs = [{ node . getnewaddress (): 0.3 }, { node . getnewaddress (): 49 }],
78- ))[ ' hex' ]
79- txid_in_block = node . sendrawtransaction (hexstring = raw_tx_in_block , maxfeerate = 0 )
74+ tx = self . wallet . create_self_transfer ()[ 'tx' ] # Pick a random coin(base) to spend
75+ tx . vout . append ( deepcopy ( tx . vout [ 0 ]))
76+ tx . vout [ 0 ]. nValue = int ( 0.3 * COIN )
77+ tx . vout [ 1 ]. nValue = int ( 49 * COIN )
78+ raw_tx_in_block = tx . serialize (). hex ()
79+ txid_in_block = self . wallet . sendrawtransaction (from_node = node , tx_hex = raw_tx_in_block , maxfeerate = 0 )
8080 self .generate (node , 1 )
8181 self .mempool_size = 0
8282 self .check_mempool_result (
@@ -86,27 +86,26 @@ def run_test(self):
8686
8787 self .log .info ('A transaction not in the mempool' )
8888 fee = Decimal ('0.000007' )
89- raw_tx_0 = node .signrawtransactionwithwallet (node .createrawtransaction (
90- inputs = [{"txid" : txid_in_block , "vout" : 0 , "sequence" : BIP125_SEQUENCE_NUMBER }], # RBF is used later
91- outputs = [{node .getnewaddress (): Decimal ('0.3' ) - fee }],
92- ))['hex' ]
93- tx = tx_from_hex (raw_tx_0 )
89+ utxo_to_spend = self .wallet .get_utxo (txid = txid_in_block ) # use 0.3 BTC UTXO
90+ tx = self .wallet .create_self_transfer (utxo_to_spend = utxo_to_spend , sequence = BIP125_SEQUENCE_NUMBER )['tx' ]
91+ tx .vout [0 ].nValue = int ((Decimal ('0.3' ) - fee ) * COIN )
92+ raw_tx_0 = tx .serialize ().hex ()
9493 txid_0 = tx .rehash ()
9594 self .check_mempool_result (
9695 result_expected = [{'txid' : txid_0 , 'allowed' : True , 'vsize' : tx .get_vsize (), 'fees' : {'base' : fee }}],
9796 rawtxs = [raw_tx_0 ],
9897 )
9998
10099 self .log .info ('A final transaction not in the mempool' )
101- coin = coins .pop () # Pick a random coin(base) to spend
102100 output_amount = Decimal ('0.025' )
103- raw_tx_final = node .signrawtransactionwithwallet (node .createrawtransaction (
104- inputs = [{'txid' : coin ['txid' ], 'vout' : coin ['vout' ], "sequence" : SEQUENCE_FINAL }],
105- outputs = [{node .getnewaddress (): output_amount }],
101+ tx = self .wallet .create_self_transfer (
102+ sequence = SEQUENCE_FINAL ,
106103 locktime = node .getblockcount () + 2000 , # Can be anything
107- ))['hex' ]
104+ )['tx' ]
105+ tx .vout [0 ].nValue = int (output_amount * COIN )
106+ raw_tx_final = tx .serialize ().hex ()
108107 tx = tx_from_hex (raw_tx_final )
109- fee_expected = coin [ 'amount' ] - output_amount
108+ fee_expected = Decimal ( '50.0' ) - output_amount
110109 self .check_mempool_result (
111110 result_expected = [{'txid' : tx .rehash (), 'allowed' : True , 'vsize' : tx .get_vsize (), 'fees' : {'base' : fee_expected }}],
112111 rawtxs = [tx .serialize ().hex ()],
@@ -127,8 +126,7 @@ def run_test(self):
127126 tx = tx_from_hex (raw_tx_0 )
128127 tx .vout [0 ].nValue -= int (fee * COIN ) # Double the fee
129128 tx .vin [0 ].nSequence = BIP125_SEQUENCE_NUMBER + 1 # Now, opt out of RBF
130- raw_tx_0 = node .signrawtransactionwithwallet (tx .serialize ().hex ())['hex' ]
131- tx = tx_from_hex (raw_tx_0 )
129+ raw_tx_0 = tx .serialize ().hex ()
132130 txid_0 = tx .rehash ()
133131 self .check_mempool_result (
134132 result_expected = [{'txid' : txid_0 , 'allowed' : True , 'vsize' : tx .get_vsize (), 'fees' : {'base' : (2 * fee )}}],
@@ -141,7 +139,6 @@ def run_test(self):
141139 # take original raw_tx_0
142140 tx = tx_from_hex (raw_tx_0 )
143141 tx .vout [0 ].nValue -= int (4 * fee * COIN ) # Set more fee
144- # skip re-signing the tx
145142 self .check_mempool_result (
146143 result_expected = [{'txid' : tx .rehash (), 'allowed' : False , 'reject-reason' : 'txn-mempool-conflict' }],
147144 rawtxs = [tx .serialize ().hex ()],
@@ -151,7 +148,6 @@ def run_test(self):
151148 self .log .info ('A transaction with missing inputs, that never existed' )
152149 tx = tx_from_hex (raw_tx_0 )
153150 tx .vin [0 ].prevout = COutPoint (hash = int ('ff' * 32 , 16 ), n = 14 )
154- # skip re-signing the tx
155151 self .check_mempool_result (
156152 result_expected = [{'txid' : tx .rehash (), 'allowed' : False , 'reject-reason' : 'missing-inputs' }],
157153 rawtxs = [tx .serialize ().hex ()],
@@ -160,17 +156,17 @@ def run_test(self):
160156 self .log .info ('A transaction with missing inputs, that existed once in the past' )
161157 tx = tx_from_hex (raw_tx_0 )
162158 tx .vin [0 ].prevout .n = 1 # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
163- raw_tx_1 = node . signrawtransactionwithwallet ( tx .serialize ().hex ())[ 'hex' ]
159+ raw_tx_1 = tx .serialize ().hex ()
164160 txid_1 = node .sendrawtransaction (hexstring = raw_tx_1 , maxfeerate = 0 )
165161 # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
166- raw_tx_spend_both = node . signrawtransactionwithwallet ( node . createrawtransaction (
167- inputs = [
168- { 'txid' : txid_0 , 'vout' : 0 },
169- { 'txid' : txid_1 , 'vout' : 0 },
170- ],
171- outputs = [{ node . getnewaddress (): 0.1 }]
172- ))[ ' hex' ]
173- txid_spend_both = node . sendrawtransaction (hexstring = raw_tx_spend_both , maxfeerate = 0 )
162+ tx = self . wallet . create_self_transfer ()[ 'tx' ]
163+ tx . vin . append ( deepcopy ( tx . vin [ 0 ]))
164+ tx . wit . vtxinwit . append ( deepcopy ( tx . wit . vtxinwit [ 0 ]))
165+ tx . vin [ 0 ]. prevout = COutPoint ( hash = int ( txid_0 , 16 ), n = 0 )
166+ tx . vin [ 1 ]. prevout = COutPoint ( hash = int ( txid_1 , 16 ), n = 0 )
167+ tx . vout [ 0 ]. nValue = int ( 0.1 * COIN )
168+ raw_tx_spend_both = tx . serialize (). hex ()
169+ txid_spend_both = self . wallet . sendrawtransaction (from_node = node , tx_hex = raw_tx_spend_both , maxfeerate = 0 )
174170 self .generate (node , 1 )
175171 self .mempool_size = 0
176172 # Now see if we can add the coins back to the utxo set by sending the exact txs again
@@ -183,12 +179,11 @@ def run_test(self):
183179 rawtxs = [raw_tx_1 ],
184180 )
185181
186- self .log .info ('Create a signed "reference" tx for later use' )
187- raw_tx_reference = node .signrawtransactionwithwallet (node .createrawtransaction (
188- inputs = [{'txid' : txid_spend_both , 'vout' : 0 }],
189- outputs = [{node .getnewaddress (): 0.05 }],
190- ))['hex' ]
191- tx = tx_from_hex (raw_tx_reference )
182+ self .log .info ('Create a "reference" tx for later use' )
183+ utxo_to_spend = self .wallet .get_utxo (txid = txid_spend_both )
184+ tx = self .wallet .create_self_transfer (utxo_to_spend = utxo_to_spend , sequence = SEQUENCE_FINAL )['tx' ]
185+ tx .vout [0 ].nValue = int (0.05 * COIN )
186+ raw_tx_reference = tx .serialize ().hex ()
192187 # Reference tx should be valid on itself
193188 self .check_mempool_result (
194189 result_expected = [{'txid' : tx .rehash (), 'allowed' : True , 'vsize' : tx .get_vsize (), 'fees' : { 'base' : Decimal ('0.1' ) - Decimal ('0.05' )}}],
@@ -199,8 +194,6 @@ def run_test(self):
199194 self .log .info ('A transaction with no outputs' )
200195 tx = tx_from_hex (raw_tx_reference )
201196 tx .vout = []
202- # Skip re-signing the transaction for context independent checks from now on
203- # tx = tx_from_hex(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])
204197 self .check_mempool_result (
205198 result_expected = [{'txid' : tx .rehash (), 'allowed' : False , 'reject-reason' : 'bad-txns-vout-empty' }],
206199 rawtxs = [tx .serialize ().hex ()],
@@ -257,7 +250,7 @@ def run_test(self):
257250 )
258251
259252 self .log .info ('A coinbase transaction' )
260- # Pick the input of the first tx we signed , so it has to be a coinbase tx
253+ # Pick the input of the first tx we created , so it has to be a coinbase tx
261254 raw_tx_coinbase_spent = node .getrawtransaction (txid = node .decoderawtransaction (hexstring = raw_tx_in_block )['vin' ][0 ]['txid' ])
262255 tx = tx_from_hex (raw_tx_coinbase_spent )
263256 self .check_mempool_result (
@@ -334,7 +327,6 @@ def run_test(self):
334327 self .log .info ('A transaction that is locked by BIP68 sequence logic' )
335328 tx = tx_from_hex (raw_tx_reference )
336329 tx .vin [0 ].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
337- # Can skip re-signing the tx because of early rejection
338330 self .check_mempool_result (
339331 result_expected = [{'txid' : tx .rehash (), 'allowed' : False , 'reject-reason' : 'non-BIP68-final' }],
340332 rawtxs = [tx .serialize ().hex ()],
0 commit comments