3
3
# Distributed under the MIT software license, see the accompanying
4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
"""Test fee estimation code."""
6
+ from copy import deepcopy
6
7
from decimal import Decimal
7
8
import os
8
9
import random
9
10
10
11
from test_framework .messages import (
11
12
COIN ,
12
- COutPoint ,
13
- CTransaction ,
14
- CTxIn ,
15
- CTxOut ,
16
- )
17
- from test_framework .script import (
18
- CScript ,
19
- OP_1 ,
20
- OP_DROP ,
21
- OP_TRUE ,
22
- )
23
- from test_framework .script_util import (
24
- script_to_p2sh_script ,
25
13
)
26
14
from test_framework .test_framework import BitcoinTestFramework
27
15
from test_framework .util import (
31
19
assert_raises_rpc_error ,
32
20
satoshi_round ,
33
21
)
34
-
35
- # Construct 2 trivial P2SH's and the ScriptSigs that spend them
36
- # So we can create many transactions without needing to spend
37
- # time signing.
38
- SCRIPT = CScript ([OP_1 , OP_DROP ])
39
- P2SH = script_to_p2sh_script (SCRIPT )
40
- REDEEM_SCRIPT = CScript ([OP_TRUE , SCRIPT ])
22
+ from test_framework .wallet import MiniWallet
41
23
42
24
43
25
def small_txpuzzle_randfee (
44
- from_node , conflist , unconflist , amount , min_fee , fee_increment
26
+ wallet , from_node , conflist , unconflist , amount , min_fee , fee_increment
45
27
):
46
- """Create and send a transaction with a random fee.
28
+ """Create and send a transaction with a random fee using MiniWallet .
47
29
48
- The transaction pays to a trivial P2SH script, and assumes that its inputs
49
- are of the same form.
50
30
The function takes a list of confirmed outputs and unconfirmed outputs
51
31
and attempts to use the confirmed list first for its inputs.
52
32
It adds the newly created outputs to the unconfirmed list.
@@ -58,23 +38,29 @@ def small_txpuzzle_randfee(
58
38
rand_fee = float (fee_increment ) * (1.1892 ** random .randint (0 , 28 ))
59
39
# Total fee ranges from min_fee to min_fee + 127*fee_increment
60
40
fee = min_fee - fee_increment + satoshi_round (rand_fee )
61
- tx = CTransaction ()
41
+ utxos_to_spend = []
62
42
total_in = Decimal ("0.00000000" )
63
43
while total_in <= (amount + fee ) and len (conflist ) > 0 :
64
44
t = conflist .pop (0 )
65
- total_in += t ["amount " ]
66
- tx . vin . append (CTxIn ( COutPoint ( int ( t [ "txid" ], 16 ), t [ "vout" ]), REDEEM_SCRIPT ) )
45
+ total_in += t ["value " ]
46
+ utxos_to_spend . append (t )
67
47
while total_in <= (amount + fee ) and len (unconflist ) > 0 :
68
48
t = unconflist .pop (0 )
69
- total_in += t ["amount " ]
70
- tx . vin . append (CTxIn ( COutPoint ( int ( t [ "txid" ], 16 ), t [ "vout" ]), REDEEM_SCRIPT ) )
49
+ total_in += t ["value " ]
50
+ utxos_to_spend . append (t )
71
51
if total_in <= amount + fee :
72
52
raise RuntimeError (f"Insufficient funds: need { amount + fee } , have { total_in } " )
73
- tx .vout .append (CTxOut (int ((total_in - amount - fee ) * COIN ), P2SH ))
74
- tx .vout .append (CTxOut (int (amount * COIN ), P2SH ))
53
+ tx = wallet .create_self_transfer_multi (
54
+ from_node = from_node ,
55
+ utxos_to_spend = utxos_to_spend ,
56
+ fee_per_output = 0 )
57
+ tx .vout [0 ].nValue = int ((total_in - amount - fee ) * COIN )
58
+ tx .vout .append (deepcopy (tx .vout [0 ]))
59
+ tx .vout [1 ].nValue = int (amount * COIN )
60
+
75
61
txid = from_node .sendrawtransaction (hexstring = tx .serialize ().hex (), maxfeerate = 0 )
76
- unconflist .append ({"txid" : txid , "vout" : 0 , "amount " : total_in - amount - fee })
77
- unconflist .append ({"txid" : txid , "vout" : 1 , "amount " : amount })
62
+ unconflist .append ({"txid" : txid , "vout" : 0 , "value " : total_in - amount - fee })
63
+ unconflist .append ({"txid" : txid , "vout" : 1 , "value " : amount })
78
64
79
65
return (tx .serialize ().hex (), fee )
80
66
@@ -129,17 +115,13 @@ def check_estimates(node, fees_seen):
129
115
check_smart_estimates (node , fees_seen )
130
116
131
117
132
- def send_tx (node , utxo , feerate ):
118
+ def send_tx (wallet , node , utxo , feerate ):
133
119
"""Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb)."""
134
- tx = CTransaction ()
135
- tx .vin = [CTxIn (COutPoint (int (utxo ["txid" ], 16 ), utxo ["vout" ]), REDEEM_SCRIPT )]
136
- tx .vout = [CTxOut (int (utxo ["amount" ] * COIN ), P2SH )]
137
-
138
- # vbytes == bytes as we are using legacy transactions
139
- fee = tx .get_vsize () * feerate
140
- tx .vout [0 ].nValue -= fee
141
-
142
- return node .sendrawtransaction (tx .serialize ().hex ())
120
+ return wallet .send_self_transfer (
121
+ from_node = node ,
122
+ utxo_to_spend = utxo ,
123
+ fee_rate = Decimal (feerate * 1000 ) / COIN ,
124
+ )['txid' ]
143
125
144
126
145
127
class EstimateFeeTest (BitcoinTestFramework ):
@@ -152,9 +134,6 @@ def set_test_params(self):
152
134
[
"[email protected] " ,
"-blockmaxweight=32000" ],
153
135
]
154
136
155
- def skip_test_if_missing_module (self ):
156
- self .skip_if_no_wallet ()
157
-
158
137
def setup_network (self ):
159
138
"""
160
139
We'll setup the network to have 3 nodes that all mine with different parameters.
@@ -168,9 +147,6 @@ def setup_network(self):
168
147
# (68k weight is room enough for 120 or so transactions)
169
148
# Node2 is a stingy miner, that
170
149
# produces too small blocks (room for only 55 or so transactions)
171
- self .start_nodes ()
172
- self .import_deterministic_coinbase_privkeys ()
173
- self .stop_nodes ()
174
150
175
151
def transact_and_mine (self , numblocks , mining_node ):
176
152
min_fee = Decimal ("0.00001" )
@@ -183,6 +159,7 @@ def transact_and_mine(self, numblocks, mining_node):
183
159
for _ in range (random .randrange (100 - 50 , 100 + 50 )):
184
160
from_index = random .randint (1 , 2 )
185
161
(txhex , fee ) = small_txpuzzle_randfee (
162
+ self .wallet ,
186
163
self .nodes [from_index ],
187
164
self .confutxo ,
188
165
self .memutxo ,
@@ -205,24 +182,10 @@ def transact_and_mine(self, numblocks, mining_node):
205
182
206
183
def initial_split (self , node ):
207
184
"""Split two coinbase UTxOs into many small coins"""
208
- utxo_count = 2048
209
- self .confutxo = []
210
- splitted_amount = Decimal ("0.04" )
211
- fee = Decimal ("0.1" )
212
- change = Decimal ("100" ) - splitted_amount * utxo_count - fee
213
- tx = CTransaction ()
214
- tx .vin = [
215
- CTxIn (COutPoint (int (cb ["txid" ], 16 ), cb ["vout" ]))
216
- for cb in node .listunspent ()[:2 ]
217
- ]
218
- tx .vout = [CTxOut (int (splitted_amount * COIN ), P2SH ) for _ in range (utxo_count )]
219
- tx .vout .append (CTxOut (int (change * COIN ), P2SH ))
220
- txhex = node .signrawtransactionwithwallet (tx .serialize ().hex ())["hex" ]
221
- txid = node .sendrawtransaction (txhex )
222
- self .confutxo = [
223
- {"txid" : txid , "vout" : i , "amount" : splitted_amount }
224
- for i in range (utxo_count )
225
- ]
185
+ self .confutxo = self .wallet .send_self_transfer_multi (
186
+ from_node = node ,
187
+ utxos_to_spend = [self .wallet .get_utxo () for _ in range (2 )],
188
+ num_outputs = 2048 )['new_utxos' ]
226
189
while len (node .getrawmempool ()) > 0 :
227
190
self .generate (node , 1 , sync_fun = self .no_op )
228
191
@@ -284,12 +247,12 @@ def sanity_check_rbf_estimates(self, utxos):
284
247
# Broadcast 45 low fee transactions that will need to be RBF'd
285
248
for _ in range (45 ):
286
249
u = utxos .pop (0 )
287
- txid = send_tx (node , u , low_feerate )
250
+ txid = send_tx (self . wallet , node , u , low_feerate )
288
251
utxos_to_respend .append (u )
289
252
txids_to_replace .append (txid )
290
253
# Broadcast 5 low fee transaction which don't need to
291
254
for _ in range (5 ):
292
- send_tx (node , utxos .pop (0 ), low_feerate )
255
+ send_tx (self . wallet , node , utxos .pop (0 ), low_feerate )
293
256
# Mine the transactions on another node
294
257
self .sync_mempools (wait = 0.1 , nodes = [node , miner ])
295
258
for txid in txids_to_replace :
@@ -298,7 +261,7 @@ def sanity_check_rbf_estimates(self, utxos):
298
261
# RBF the low-fee transactions
299
262
while len (utxos_to_respend ) > 0 :
300
263
u = utxos_to_respend .pop (0 )
301
- send_tx (node , u , high_feerate )
264
+ send_tx (self . wallet , node , u , high_feerate )
302
265
303
266
# Mine the last replacement txs
304
267
self .sync_mempools (wait = 0.1 , nodes = [node , miner ])
@@ -316,6 +279,8 @@ def run_test(self):
316
279
317
280
# Split two coinbases into many small utxos
318
281
self .start_node (0 )
282
+ self .wallet = MiniWallet (self .nodes [0 ])
283
+ self .wallet .rescan_utxos ()
319
284
self .initial_split (self .nodes [0 ])
320
285
self .log .info ("Finished splitting" )
321
286
0 commit comments