@@ -93,7 +93,7 @@ pub struct BitcoinRegtestController {
9393    burnchain_config :  Option < Burnchain > , 
9494    ongoing_block_commit :  Option < OngoingBlockCommit > , 
9595    should_keep_running :  Option < Arc < AtomicBool > > , 
96-     rpc_client :  BitcoinRpcClient , 
96+     rpc_client :  Option < BitcoinRpcClient > , 
9797} 
9898
9999#[ derive( Clone ) ]  
@@ -371,8 +371,7 @@ impl BitcoinRegtestController {
371371            should_keep_running :  should_keep_running. clone ( ) , 
372372        } ; 
373373
374-         let  rpc_client = BitcoinRpcClient :: from_stx_config ( & config) 
375-             . expect ( "unable to instantiate the RPC client!" ) ; 
374+         let  rpc_client = Self :: try_create_rpc_client ( & config) ; 
376375
377376        Self  { 
378377            use_coordinator :  coordinator_channel, 
@@ -421,8 +420,7 @@ impl BitcoinRegtestController {
421420            should_keep_running :  None , 
422421        } ; 
423422
424-         let  rpc_client = BitcoinRpcClient :: from_stx_config ( & config) 
425-             . expect ( "unable to instantiate the RPC client!" ) ; 
423+         let  rpc_client = Self :: try_create_rpc_client ( & config) ; 
426424
427425        Self  { 
428426            use_coordinator :  None , 
@@ -477,6 +475,36 @@ impl BitcoinRegtestController {
477475        } 
478476    } 
479477
478+     /// Attempt to create a new [`BitcoinRpcClient`] from the given [`Config`]. 
479+ /// 
480+ /// If the provided config indicates that the node is a **miner**, 
481+ /// tries to instantiate it or **panics** otherwise. 
482+ /// If the node is **not** a miner, returns None (e.g. follower node). 
483+ fn  try_create_rpc_client ( config :  & Config )  -> Option < BitcoinRpcClient >  { 
484+         if  config. node . miner  { 
485+             Some ( 
486+                 BitcoinRpcClient :: from_stx_config ( & config) 
487+                     . expect ( "unable to instantiate the RPC client!" ) , 
488+             ) 
489+         }  else  { 
490+             None 
491+         } 
492+     } 
493+ 
494+     /// Attempt to get a reference to the underlying [`BitcoinRpcClient`]. 
495+ /// 
496+ /// This function will panic if the RPC client has not been configured 
497+ /// (i.e. [`Self::try_create_rpc_client`] returned `None` during initialization), 
498+ /// but an attempt is made to use it anyway. 
499+ /// 
500+ /// In practice, this means the node is expected to act as a miner, 
501+ /// yet no [`BitcoinRpcClient`] was created or properly configured. 
502+ fn  try_get_rpc_client ( & self )  -> & BitcoinRpcClient  { 
503+         self . rpc_client 
504+             . as_ref ( ) 
505+             . expect ( "BUG: BitcoinRpcClient is required, but it has not been configured properly!" ) 
506+     } 
507+ 
480508    /// Helium (devnet) blocks receiver.  Returns the new burnchain tip. 
481509fn  receive_blocks_helium ( & mut  self )  -> BurnchainTip  { 
482510        let  mut  burnchain = self . get_burnchain ( ) ; 
@@ -686,7 +714,7 @@ impl BitcoinRegtestController {
686714
687715    /// Retrieve all loaded wallets. 
688716pub  fn  list_wallets ( & self )  -> BitcoinRegtestControllerResult < Vec < String > >  { 
689-         Ok ( self . rpc_client . list_wallets ( ) ?) 
717+         Ok ( self . try_get_rpc_client ( ) . list_wallets ( ) ?) 
690718    } 
691719
692720    /// Checks if the config-supplied wallet exists. 
@@ -695,7 +723,8 @@ impl BitcoinRegtestController {
695723        let  wallets = self . list_wallets ( ) ?; 
696724        let  wallet = self . get_wallet_name ( ) ; 
697725        if  !wallets. contains ( wallet)  { 
698-             self . rpc_client . create_wallet ( wallet,  Some ( true ) ) ?
726+             self . try_get_rpc_client ( ) 
727+                 . create_wallet ( wallet,  Some ( true ) ) ?
699728        } 
700729        Ok ( ( ) ) 
701730    } 
@@ -1861,7 +1890,7 @@ impl BitcoinRegtestController {
18611890
18621891        const  UNCAPPED_FEE :  f64  = 0.0 ; 
18631892        const  MAX_BURN_AMOUNT :  u64  = 1_000_000 ; 
1864-         self . rpc_client 
1893+         self . try_get_rpc_client ( ) 
18651894            . send_raw_transaction ( tx,  Some ( UNCAPPED_FEE ) ,  Some ( MAX_BURN_AMOUNT ) ) 
18661895            . map ( |txid| { 
18671896                debug ! ( "Transaction {txid} sent successfully" ) ; 
@@ -1933,7 +1962,9 @@ impl BitcoinRegtestController {
19331962            . expect ( "FATAL: invalid public key bytes" ) ; 
19341963        let  address = self . get_miner_address ( StacksEpochId :: Epoch21 ,  & public_key) ; 
19351964
1936-         let  result = self . rpc_client . generate_to_address ( num_blocks,  & address) ; 
1965+         let  result = self 
1966+             . try_get_rpc_client ( ) 
1967+             . generate_to_address ( num_blocks,  & address) ; 
19371968        /* 
19381969            Temporary: not using `BitcoinRpcClientResultExt::ok_or_log_panic` (test code related), 
19391970            because we need this logic available outside `#[cfg(test)]` due to Helium network. 
@@ -1966,7 +1997,7 @@ impl BitcoinRegtestController {
19661997            . expect ( "FATAL: invalid public key bytes" ) ; 
19671998        let  address = self . get_miner_address ( StacksEpochId :: Epoch21 ,  & public_key) ; 
19681999
1969-         self . rpc_client 
2000+         self . try_get_rpc_client ( ) 
19702001            . generate_block ( & address,  & [ ] ) 
19712002            . ok_or_log_panic ( "generating block" ) 
19722003    } 
@@ -1975,15 +2006,15 @@ impl BitcoinRegtestController {
19752006#[ cfg( test) ]  
19762007    pub  fn  invalidate_block ( & self ,  block :  & BurnchainHeaderHash )  { 
19772008        info ! ( "Invalidating block {block}" ) ; 
1978-         self . rpc_client 
2009+         self . try_get_rpc_client ( ) 
19792010            . invalidate_block ( block) 
19802011            . ok_or_log_panic ( "invalidate block" ) 
19812012    } 
19822013
19832014    /// Retrieve the hash (as a [`BurnchainHeaderHash`]) of the block at the given height. 
19842015#[ cfg( test) ]  
19852016    pub  fn  get_block_hash ( & self ,  height :  u64 )  -> BurnchainHeaderHash  { 
1986-         self . rpc_client 
2017+         self . try_get_rpc_client ( ) 
19872018            . get_block_hash ( height) 
19882019            . unwrap_or_log_panic ( "retrieve block" ) 
19892020    } 
@@ -2041,7 +2072,7 @@ impl BitcoinRegtestController {
20412072    /// Retrieves a raw [`Transaction`] by its [`Txid`] 
20422073#[ cfg( test) ]  
20432074    pub  fn  get_raw_transaction ( & self ,  txid :  & Txid )  -> Transaction  { 
2044-         self . rpc_client 
2075+         self . try_get_rpc_client ( ) 
20452076            . get_raw_transaction ( txid) 
20462077            . unwrap_or_log_panic ( "retrieve raw tx" ) 
20472078    } 
@@ -2069,7 +2100,7 @@ impl BitcoinRegtestController {
20692100                "Generate to address '{address}' for public key '{}'" , 
20702101                & pks[ 0 ] . to_hex( ) 
20712102            ) ; 
2072-             self . rpc_client 
2103+             self . try_get_rpc_client ( ) 
20732104                . generate_to_address ( num_blocks,  & address) 
20742105                . ok_or_log_panic ( "generating block" ) ; 
20752106            return ; 
@@ -2087,7 +2118,7 @@ impl BitcoinRegtestController {
20872118                    & pk. to_hex( ) , 
20882119                ) ; 
20892120            } 
2090-             self . rpc_client 
2121+             self . try_get_rpc_client ( ) 
20912122                . generate_to_address ( 1 ,  & address) 
20922123                . ok_or_log_panic ( "generating block" ) ; 
20932124        } 
@@ -2105,7 +2136,7 @@ impl BitcoinRegtestController {
21052136/// * `false` if the transaction is unconfirmed or could not be found. 
21062137pub  fn  is_transaction_confirmed ( & self ,  txid :  & Txid )  -> bool  { 
21072138        match  self 
2108-             . rpc_client 
2139+             . try_get_rpc_client ( ) 
21092140            . get_transaction ( self . get_wallet_name ( ) ,  txid) 
21102141        { 
21112142            Ok ( info)  => info. confirmations  > 0 , 
@@ -2158,15 +2189,15 @@ impl BitcoinRegtestController {
21582189            ) ; 
21592190
21602191            let  descriptor = format ! ( "addr({address})" ) ; 
2161-             let  info = self . rpc_client . get_descriptor_info ( & descriptor) ?; 
2192+             let  info = self . try_get_rpc_client ( ) . get_descriptor_info ( & descriptor) ?; 
21622193
21632194            let  descr_req = ImportDescriptorsRequest  { 
21642195                descriptor :  format ! ( "addr({address})#{}" ,  info. checksum) , 
21652196                timestamp :  Timestamp :: Time ( 0 ) , 
21662197                internal :  Some ( true ) , 
21672198            } ; 
21682199
2169-             self . rpc_client 
2200+             self . try_get_rpc_client ( ) 
21702201                . import_descriptors ( self . get_wallet_name ( ) ,  & [ & descr_req] ) ?; 
21712202        } 
21722203        Ok ( ( ) ) 
@@ -2227,11 +2258,11 @@ impl BitcoinRegtestController {
22272258        utxos_to_exclude :  & Option < UTXOSet > , 
22282259        block_height :  u64 , 
22292260    )  -> BitcoinRpcClientResult < UTXOSet >  { 
2230-         let  bhh = self . rpc_client . get_block_hash ( block_height) ?; 
2261+         let  bhh = self . try_get_rpc_client ( ) . get_block_hash ( block_height) ?; 
22312262
22322263        const  MIN_CONFIRMATIONS :  u64  = 0 ; 
22332264        const  MAX_CONFIRMATIONS :  u64  = 9_999_999 ; 
2234-         let  unspents = self . rpc_client . list_unspent ( 
2265+         let  unspents = self . try_get_rpc_client ( ) . list_unspent ( 
22352266            & self . get_wallet_name ( ) , 
22362267            Some ( MIN_CONFIRMATIONS ) , 
22372268            Some ( MAX_CONFIRMATIONS ) , 
@@ -2446,6 +2477,7 @@ mod tests {
24462477
24472478        pub  fn  create_config ( )  -> Config  { 
24482479            let  mut  config = Config :: default ( ) ; 
2480+             config. node . miner  = true ; 
24492481            config. burnchain . magic_bytes  = "T3" . as_bytes ( ) . into ( ) ; 
24502482            config. burnchain . username  = Some ( String :: from ( "user" ) ) ; 
24512483            config. burnchain . password  = Some ( String :: from ( "12345" ) ) ; 
@@ -2964,6 +2996,10 @@ mod tests {
29642996    #[ test]  
29652997    #[ ignore]  
29662998    fn  test_create_wallet_from_custom_name ( )  { 
2999+         if  env:: var ( "BITCOIND_TEST" )  != Ok ( "1" . into ( ) )  { 
3000+             return ; 
3001+         } 
3002+ 
29673003        let  mut  config = utils:: create_config ( ) ; 
29683004        config. burnchain . wallet_name  = String :: from ( "mywallet" ) ; 
29693005
0 commit comments