25
25
# Assert functions
26
26
##################
27
27
28
+
28
29
def assert_approx (v , vexp , vspan = 0.00001 ):
29
30
"""Assert that `v` is within `vspan` of `vexp`"""
30
31
if v < vexp - vspan :
31
32
raise AssertionError ("%s < [%s..%s]" % (str (v ), str (vexp - vspan ), str (vexp + vspan )))
32
33
if v > vexp + vspan :
33
34
raise AssertionError ("%s > [%s..%s]" % (str (v ), str (vexp - vspan ), str (vexp + vspan )))
34
35
36
+
35
37
def assert_fee_amount (fee , tx_size , fee_per_kB ):
36
38
"""Assert the fee was in range"""
37
39
target_fee = round (tx_size * fee_per_kB / 1000 , 8 )
@@ -41,21 +43,26 @@ def assert_fee_amount(fee, tx_size, fee_per_kB):
41
43
if fee > (tx_size + 2 ) * fee_per_kB / 1000 :
42
44
raise AssertionError ("Fee of %s BTC too high! (Should be %s BTC)" % (str (fee ), str (target_fee )))
43
45
46
+
44
47
def assert_equal (thing1 , thing2 , * args ):
45
48
if thing1 != thing2 or any (thing1 != arg for arg in args ):
46
49
raise AssertionError ("not(%s)" % " == " .join (str (arg ) for arg in (thing1 , thing2 ) + args ))
47
50
51
+
48
52
def assert_greater_than (thing1 , thing2 ):
49
53
if thing1 <= thing2 :
50
54
raise AssertionError ("%s <= %s" % (str (thing1 ), str (thing2 )))
51
55
56
+
52
57
def assert_greater_than_or_equal (thing1 , thing2 ):
53
58
if thing1 < thing2 :
54
59
raise AssertionError ("%s < %s" % (str (thing1 ), str (thing2 )))
55
60
61
+
56
62
def assert_raises (exc , fun , * args , ** kwds ):
57
63
assert_raises_message (exc , None , fun , * args , ** kwds )
58
64
65
+
59
66
def assert_raises_message (exc , message , fun , * args , ** kwds ):
60
67
try :
61
68
fun (* args , ** kwds )
@@ -71,6 +78,7 @@ def assert_raises_message(exc, message, fun, *args, **kwds):
71
78
else :
72
79
raise AssertionError ("No exception raised" )
73
80
81
+
74
82
def assert_raises_process_error (returncode , output , fun , * args , ** kwds ):
75
83
"""Execute a process and asserts the process return code and output.
76
84
@@ -95,6 +103,7 @@ def assert_raises_process_error(returncode, output, fun, *args, **kwds):
95
103
else :
96
104
raise AssertionError ("No exception raised" )
97
105
106
+
98
107
def assert_raises_rpc_error (code , message , fun , * args , ** kwds ):
99
108
"""Run an RPC and verify that a specific JSONRPC exception code and message is raised.
100
109
@@ -113,6 +122,7 @@ def assert_raises_rpc_error(code, message, fun, *args, **kwds):
113
122
"""
114
123
assert try_rpc (code , message , fun , * args , ** kwds ), "No exception raised"
115
124
125
+
116
126
def try_rpc (code , message , fun , * args , ** kwds ):
117
127
"""Tries to run an rpc command.
118
128
@@ -134,22 +144,22 @@ def try_rpc(code, message, fun, *args, **kwds):
134
144
else :
135
145
return False
136
146
147
+
137
148
def assert_is_hex_string (string ):
138
149
try :
139
150
int (string , 16 )
140
151
except Exception as e :
141
- raise AssertionError (
142
- "Couldn't interpret %r as hexadecimal; raised: %s" % ( string , e ))
152
+ raise AssertionError ("Couldn't interpret %r as hexadecimal; raised: %s" % ( string , e ))
153
+
143
154
144
155
def assert_is_hash_string (string , length = 64 ):
145
156
if not isinstance (string , str ):
146
157
raise AssertionError ("Expected a string, got type %r" % type (string ))
147
158
elif length and len (string ) != length :
148
- raise AssertionError (
149
- "String of length %d expected; got %d" % (length , len (string )))
159
+ raise AssertionError ("String of length %d expected; got %d" % (length , len (string )))
150
160
elif not re .match ('[abcdef0-9]+$' , string ):
151
- raise AssertionError (
152
- "String %r contains invalid characters for a hash." % string )
161
+ raise AssertionError ("String %r contains invalid characters for a hash." % string )
162
+
153
163
154
164
def assert_array_result (object_array , to_match , expected , should_not_find = False ):
155
165
"""
@@ -180,34 +190,41 @@ def assert_array_result(object_array, to_match, expected, should_not_find=False)
180
190
if num_matched > 0 and should_not_find :
181
191
raise AssertionError ("Objects were found %s" % (str (to_match )))
182
192
193
+
183
194
# Utility functions
184
195
###################
185
196
197
+
186
198
def check_json_precision ():
187
199
"""Make sure json library being used does not lose precision converting BTC values"""
188
200
n = Decimal ("20000000.00000003" )
189
201
satoshis = int (json .loads (json .dumps (float (n ))) * 1.0e8 )
190
202
if satoshis != 2000000000000003 :
191
203
raise RuntimeError ("JSON encode/decode loses precision" )
192
204
205
+
193
206
def EncodeDecimal (o ):
194
207
if isinstance (o , Decimal ):
195
208
return str (o )
196
209
raise TypeError (repr (o ) + " is not JSON serializable" )
197
210
211
+
198
212
def count_bytes (hex_string ):
199
213
return len (bytearray .fromhex (hex_string ))
200
214
201
215
202
216
def hex_str_to_bytes (hex_str ):
203
217
return unhexlify (hex_str .encode ('ascii' ))
204
218
219
+
205
220
def str_to_b64str (string ):
206
221
return b64encode (string .encode ('utf-8' )).decode ('ascii' )
207
222
223
+
208
224
def satoshi_round (amount ):
209
225
return Decimal (amount ).quantize (Decimal ('0.00000001' ), rounding = ROUND_DOWN )
210
226
227
+
211
228
def wait_until (predicate , * , attempts = float ('inf' ), timeout = float ('inf' ), lock = None , timeout_factor = 1.0 ):
212
229
if attempts == float ('inf' ) and timeout == float ('inf' ):
213
230
timeout = 60
@@ -235,6 +252,7 @@ def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=N
235
252
raise AssertionError ("Predicate {} not true after {} seconds" .format (predicate_source , timeout ))
236
253
raise RuntimeError ('Unreachable' )
237
254
255
+
238
256
# RPC/P2P connection constants and functions
239
257
############################################
240
258
@@ -250,6 +268,7 @@ class PortSeed:
250
268
# Must be initialized with a unique integer for each process
251
269
n = None
252
270
271
+
253
272
def get_rpc_proxy (url , node_number , * , timeout = None , coveragedir = None ):
254
273
"""
255
274
Args:
@@ -271,18 +290,20 @@ def get_rpc_proxy(url, node_number, *, timeout=None, coveragedir=None):
271
290
proxy = AuthServiceProxy (url , ** proxy_kwargs )
272
291
proxy .url = url # store URL on proxy for info
273
292
274
- coverage_logfile = coverage .get_filename (
275
- coveragedir , node_number ) if coveragedir else None
293
+ coverage_logfile = coverage .get_filename (coveragedir , node_number ) if coveragedir else None
276
294
277
295
return coverage .AuthServiceProxyWrapper (proxy , coverage_logfile )
278
296
297
+
279
298
def p2p_port (n ):
280
299
assert n <= MAX_NODES
281
300
return PORT_MIN + n + (MAX_NODES * PortSeed .n ) % (PORT_RANGE - 1 - MAX_NODES )
282
301
302
+
283
303
def rpc_port (n ):
284
304
return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed .n ) % (PORT_RANGE - 1 - MAX_NODES )
285
305
306
+
286
307
def rpc_url (datadir , i , chain , rpchost ):
287
308
rpc_u , rpc_p = get_auth_cookie (datadir , chain )
288
309
host = '127.0.0.1'
@@ -295,9 +316,11 @@ def rpc_url(datadir, i, chain, rpchost):
295
316
host = rpchost
296
317
return "http://%s:%s@%s:%d" % (rpc_u , rpc_p , host , int (port ))
297
318
319
+
298
320
# Node functions
299
321
################
300
322
323
+
301
324
def initialize_datadir (dirname , n , chain ):
302
325
datadir = get_datadir_path (dirname , n )
303
326
if not os .path .isdir (datadir ):
@@ -327,21 +350,17 @@ def initialize_datadir(dirname, n, chain):
327
350
os .makedirs (os .path .join (datadir , 'stdout' ), exist_ok = True )
328
351
return datadir
329
352
330
- def adjust_bitcoin_conf_for_pre_17 (conf_file ):
331
- with open (conf_file ,'r' , encoding = 'utf8' ) as conf :
332
- conf_data = conf .read ()
333
- with open (conf_file , 'w' , encoding = 'utf8' ) as conf :
334
- conf_data_changed = conf_data .replace ('[regtest]' , '' )
335
- conf .write (conf_data_changed )
336
353
337
354
def get_datadir_path (dirname , n ):
338
355
return os .path .join (dirname , "node" + str (n ))
339
356
357
+
340
358
def append_config (datadir , options ):
341
359
with open (os .path .join (datadir , "bitcoin.conf" ), 'a' , encoding = 'utf8' ) as f :
342
360
for option in options :
343
361
f .write (option + "\n " )
344
362
363
+
345
364
def get_auth_cookie (datadir , chain ):
346
365
user = None
347
366
password = None
@@ -366,20 +385,24 @@ def get_auth_cookie(datadir, chain):
366
385
raise ValueError ("No RPC credentials" )
367
386
return user , password
368
387
388
+
369
389
# If a cookie file exists in the given datadir, delete it.
370
390
def delete_cookie_file (datadir , chain ):
371
391
if os .path .isfile (os .path .join (datadir , chain , ".cookie" )):
372
392
logger .debug ("Deleting leftover cookie file" )
373
393
os .remove (os .path .join (datadir , chain , ".cookie" ))
374
394
395
+
375
396
def softfork_active (node , key ):
376
397
"""Return whether a softfork is active."""
377
398
return node .getblockchaininfo ()['softforks' ][key ]['active' ]
378
399
400
+
379
401
def set_node_times (nodes , t ):
380
402
for node in nodes :
381
403
node .setmocktime (t )
382
404
405
+
383
406
def disconnect_nodes (from_connection , node_num ):
384
407
def get_peer_ids ():
385
408
result = []
@@ -392,7 +415,7 @@ def get_peer_ids():
392
415
if not peer_ids :
393
416
logger .warning ("disconnect_nodes: {} and {} were not connected" .format (
394
417
from_connection .index ,
395
- node_num
418
+ node_num ,
396
419
))
397
420
return
398
421
for peer_id in peer_ids :
@@ -402,12 +425,13 @@ def get_peer_ids():
402
425
# If this node is disconnected between calculating the peer id
403
426
# and issuing the disconnect, don't worry about it.
404
427
# This avoids a race condition if we're mass-disconnecting peers.
405
- if e .error ['code' ] != - 29 : # RPC_CLIENT_NODE_NOT_CONNECTED
428
+ if e .error ['code' ] != - 29 : # RPC_CLIENT_NODE_NOT_CONNECTED
406
429
raise
407
430
408
431
# wait to disconnect
409
432
wait_until (lambda : not get_peer_ids (), timeout = 5 )
410
433
434
+
411
435
def connect_nodes (from_connection , node_num ):
412
436
ip_port = "127.0.0.1:" + str (p2p_port (node_num ))
413
437
from_connection .addnode (ip_port , "onetry" )
@@ -479,6 +503,7 @@ def find_output(node, txid, amount, *, blockhash=None):
479
503
return i
480
504
raise RuntimeError ("find_output txid %s : %s not found" % (txid , str (amount )))
481
505
506
+
482
507
def gather_inputs (from_node , amount_needed , confirmations_required = 1 ):
483
508
"""
484
509
Return a random set of unspent txouts that are enough to pay amount_needed
@@ -496,6 +521,7 @@ def gather_inputs(from_node, amount_needed, confirmations_required=1):
496
521
raise RuntimeError ("Insufficient funds: need %d, have %d" % (amount_needed , total_in ))
497
522
return (total_in , inputs )
498
523
524
+
499
525
def make_change (from_node , amount_in , amount_out , fee ):
500
526
"""
501
527
Create change output(s), return them
@@ -513,6 +539,7 @@ def make_change(from_node, amount_in, amount_out, fee):
513
539
outputs [from_node .getnewaddress ()] = change
514
540
return outputs
515
541
542
+
516
543
def random_transaction (nodes , amount , min_fee , fee_increment , fee_variants ):
517
544
"""
518
545
Create a random transaction.
@@ -532,6 +559,7 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
532
559
533
560
return (txid , signresult ["hex" ], fee )
534
561
562
+
535
563
# Helper to create at least "count" utxos
536
564
# Pass in a fee that is sufficient for relay and mining new transactions.
537
565
def create_confirmed_utxos (fee , node , count ):
@@ -564,6 +592,7 @@ def create_confirmed_utxos(fee, node, count):
564
592
assert len (utxos ) >= count
565
593
return utxos
566
594
595
+
567
596
# Create large OP_RETURN txouts that can be appended to a transaction
568
597
# to make it large (helper for constructing large transactions).
569
598
def gen_return_txouts ():
@@ -583,6 +612,7 @@ def gen_return_txouts():
583
612
txouts .append (txout )
584
613
return txouts
585
614
615
+
586
616
# Create a spend of each passed-in utxo, splicing in "txouts" to each raw
587
617
# transaction to make it large. See gen_return_txouts() above.
588
618
def create_lots_of_big_transactions (node , txouts , utxos , num , fee ):
@@ -606,6 +636,7 @@ def create_lots_of_big_transactions(node, txouts, utxos, num, fee):
606
636
txids .append (txid )
607
637
return txids
608
638
639
+
609
640
def mine_large_block (node , utxos = None ):
610
641
# generate a 66k transaction,
611
642
# and 14 of them is close to the 1MB block limit
@@ -619,6 +650,7 @@ def mine_large_block(node, utxos=None):
619
650
create_lots_of_big_transactions (node , txouts , utxos , num , fee = fee )
620
651
node .generate (1 )
621
652
653
+
622
654
def find_vout_for_address (node , txid , addr ):
623
655
"""
624
656
Locate the vout index of the given transaction sending to the
0 commit comments