@@ -411,6 +411,7 @@ def __init__(self, bitcoin_dir="/tmp/bitcoind-test", rpcport=None):
411411 self .bitcoin_dir = bitcoin_dir
412412 self .rpcport = rpcport
413413 self .prefix = 'bitcoind'
414+ self .canned_blocks = None
414415
415416 regtestdir = os .path .join (bitcoin_dir , 'regtest' )
416417 if not os .path .exists (regtestdir ):
@@ -446,15 +447,18 @@ def __del__(self):
446447 if self .reserved_rpcport is not None :
447448 drop_unused_port (self .reserved_rpcport )
448449
449- def start (self ):
450+ def start (self , wallet_file = None ):
450451 TailableProc .start (self )
451452 self .wait_for_log ("Done loading" , timeout = TIMEOUT )
452453
453454 logging .info ("BitcoinD started" )
454- try :
455- self .rpc .createwallet ("lightningd-tests" )
456- except JSONRPCError :
457- self .rpc .loadwallet ("lightningd-tests" )
455+ if wallet_file :
456+ self .rpc .restorewallet ("lightningd-tests" , wallet_file )
457+ else :
458+ try :
459+ self .rpc .createwallet ("lightningd-tests" )
460+ except JSONRPCError :
461+ self .rpc .loadwallet ("lightningd-tests" )
458462
459463 def stop (self ):
460464 for p in self .proxies :
@@ -468,6 +472,10 @@ def get_proxy(self):
468472 proxy .start ()
469473 return proxy
470474
475+ def set_canned_blocks (self , blocks ):
476+ """Set blocks as an array of blocks to "generate", or None to reset"""
477+ self .canned_blocks = blocks
478+
471479 # wait_for_mempool can be used to wait for the mempool before generating blocks:
472480 # True := wait for at least 1 transation
473481 # int > 0 := wait for at least N transactions
@@ -482,6 +490,16 @@ def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None, needfeer
482490 else :
483491 wait_for (lambda : len (self .rpc .getrawmempool ()) >= wait_for_mempool )
484492
493+ # Use canned blocks if we have them (fails if we run out!).
494+ if self .canned_blocks is not None :
495+ ret = []
496+ while numblocks > 0 :
497+ self .rpc .submitblock (self .canned_blocks [0 ])
498+ ret .append (self .rpc .getbestblockhash ())
499+ numblocks -= 1
500+ del self .canned_blocks [0 ]
501+ return ret
502+
485503 mempool = self .rpc .getrawmempool (True )
486504 logging .debug ("Generating {numblocks}, confirming {lenmempool} transactions: {mempool}" .format (
487505 numblocks = numblocks ,
@@ -509,6 +527,21 @@ def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None, needfeer
509527
510528 return self .rpc .generatetoaddress (numblocks , to_addr )
511529
530+ def send_and_mine_block (self , addr , sats ):
531+ """Sometimes we want the txid. We assume it's the first tx for canned blocks"""
532+ if self .canned_blocks :
533+ self .generate_block (1 )
534+ # Find which non-coinbase txs sent to this address: return txid
535+ for txid in self .rpc .getblock (self .rpc .getbestblockhash ())['tx' ][1 :]:
536+ for out in self .rpc .getrawtransaction (txid , 1 )['vout' ]:
537+ if out ['scriptPubKey' ].get ('address' ) == addr :
538+ return txid
539+ assert False , f"No address { addr } in block { self .rpc .getblock (self .rpc .getbestblockhash ())} "
540+
541+ txid = self .rpc .sendtoaddress (addr , sats / 10 ** 8 )
542+ self .generate_block (1 )
543+ return txid
544+
512545 def simple_reorg (self , height , shift = 0 ):
513546 """
514547 Reorganize chain by creating a fork at height=[height] and re-mine all mempool
@@ -526,6 +559,7 @@ def simple_reorg(self, height, shift=0):
526559 forward to h1.
527560 2. Set [height]=h2 and [shift]= h1-h2
528561 """
562+ assert self .canned_blocks is None
529563 hashes = []
530564 fee_delta = 1000000
531565 orig_len = self .rpc .getblockcount ()
@@ -559,7 +593,7 @@ def save_blocks(self):
559593 """Bundle up blocks into an array, for restore_blocks"""
560594 blocks = []
561595 numblocks = self .rpc .getblockcount ()
562- for bnum in range (1 , numblocks ):
596+ for bnum in range (1 , numblocks + 1 ):
563597 bhash = self .rpc .getblockhash (bnum )
564598 blocks .append (self .rpc .getblock (bhash , False ))
565599 return blocks
@@ -892,6 +926,10 @@ def __init__(self, node_id, lightning_dir, bitcoind, executor, valgrind, may_fai
892926 self .daemon .opts ['grpc-port' ] = grpc_port
893927 self .grpc_port = grpc_port or 9736
894928
929+ # If bitcoind is serving canned blocks, it will keep initialblockdownload on true!
930+ if self .bitcoin .canned_blocks is not None :
931+ self .daemon .opts ['dev-ignore-ibd' ] = True
932+
895933 def _create_rpc (self , jsonschemas ):
896934 """Prepares anything related to the RPC.
897935 """
@@ -987,10 +1025,12 @@ def openchannel(self, remote_node, capacity=FUNDAMOUNT, addrtype="bech32", confi
9871025
9881026 def fundwallet (self , sats , addrtype = "bech32" , mine_block = True ):
9891027 addr = self .rpc .newaddr (addrtype )[addrtype ]
990- txid = self .bitcoin .rpc .sendtoaddress (addr , sats / 10 ** 8 )
9911028 if mine_block :
992- self .bitcoin .generate_block ( 1 )
1029+ txid = self .bitcoin .send_and_mine_block ( addr , sats )
9931030 self .daemon .wait_for_log ('Owning output .* txid {} CONFIRMED' .format (txid ))
1031+ else :
1032+ txid = self .bitcoin .rpc .sendtoaddress (addr , sats / 10 ** 8 )
1033+
9941034 return addr , txid
9951035
9961036 def fundbalancedchannel (self , remote_node , total_capacity = FUNDAMOUNT , announce = True ):
@@ -1118,8 +1158,7 @@ def has_funds_on_addr(addr):
11181158 # We should not have funds on that address yet, we just generated it.
11191159 assert not has_funds_on_addr (addr )
11201160
1121- self .bitcoin .rpc .sendtoaddress (addr , (amount + 1000000 ) / 10 ** 8 )
1122- self .bitcoin .generate_block (1 )
1161+ self .bitcoin .send_and_mine_block (addr , amount + 1000000 )
11231162
11241163 # Now we should.
11251164 wait_for (lambda : has_funds_on_addr (addr ))
@@ -1134,10 +1173,18 @@ def has_funds_on_addr(addr):
11341173 ** kwargs )
11351174 blockid = self .bitcoin .generate_block (1 , wait_for_mempool = res ['txid' ])[0 ]
11361175
1176+ txnum = None
11371177 for i , txid in enumerate (self .bitcoin .rpc .getblock (blockid )['tx' ]):
11381178 if txid == res ['txid' ]:
11391179 txnum = i
11401180
1181+ if txnum is None :
1182+ print (f"mempool = { self .bitcoin .rpc .getrawmempool ()} " )
1183+ print ("txs:" )
1184+ for txid in self .bitcoin .rpc .getblock (blockid )['tx' ][1 :]:
1185+ print (f"txid { txid } : { self .bitcoin .rpc .getrawtransaction (txid )} { self .bitcoin .rpc .getrawtransaction (txid , 1 )} " )
1186+ assert False , f"txid { res ['txid' ]} not found"
1187+
11411188 scid = "{}x{}x{}" .format (self .bitcoin .rpc .getblockcount (),
11421189 txnum , res ['outnum' ])
11431190
0 commit comments