1414 autodetect_rpc_confs ,
1515 get_default_datadir ,
1616)
17+ from .specter_error import BrokenCoreConnectionException
1718
1819logger = logging .getLogger (__name__ )
1920
@@ -74,7 +75,10 @@ def __init__(
7475 self .manager = manager
7576 self .proxy_url = manager .proxy_url
7677 self .only_tor = manager .only_tor
77- self .rpc = self .get_rpc ()
78+ try :
79+ self .rpc = self ._get_rpc ()
80+ except BrokenCoreConnectionException :
81+ self .rpc = None
7882 self ._asset_labels = None
7983 self .check_info ()
8084
@@ -128,26 +132,29 @@ def json(self):
128132 "node_type" : self .node_type ,
129133 }
130134
131- def get_rpc (self ):
132- """
133- Checks if config have changed, compares with old rpc
134- and returns new one if necessary
135- """
136- if hasattr (self , "rpc" ):
137- rpc = self .rpc
135+ def _get_rpc (self ):
136+ """Checks if configurations have changed, compares with old rpc
137+ and returns new one if necessary.
138+ Aims to be exception safe, returns None if rpc is not working"""
139+ if hasattr (self , "_rpc" ):
140+ rpc = self ._rpc
138141 else :
139142 rpc = None
140143 if self .autodetect :
141- if self .port :
142- rpc_conf_arr = autodetect_rpc_confs (
143- self .node_type ,
144- datadir = os .path .expanduser (self .datadir ),
145- port = self .port ,
146- )
147- else :
148- rpc_conf_arr = autodetect_rpc_confs (
149- self .node_type , datadir = os .path .expanduser (self .datadir )
150- )
144+ try :
145+ if self .port :
146+ # autodetect_rpc_confs is trying a RPC call
147+ rpc_conf_arr = autodetect_rpc_confs (
148+ self .node_type ,
149+ datadir = os .path .expanduser (self .datadir ),
150+ port = self .port ,
151+ )
152+ else :
153+ rpc_conf_arr = autodetect_rpc_confs (
154+ self .node_type , datadir = os .path .expanduser (self .datadir )
155+ )
156+ except BrokenCoreConnectionException :
157+ return None
151158 if len (rpc_conf_arr ) > 0 :
152159 rpc = BitcoinRPC (
153160 ** rpc_conf_arr [0 ], proxy_url = self .proxy_url , only_tor = self .only_tor
@@ -171,7 +178,7 @@ def get_rpc(self):
171178 )
172179
173180 if rpc == None :
174- logger .error (f"connection results to None in get_rpc" )
181+ logger .error (f"RPC connection is None in get_rpc. Returning None ... " )
175182 return None
176183 # check if it's liquid
177184 try :
@@ -184,8 +191,8 @@ def get_rpc(self):
184191 return rpc # The user is failing to configure correctly
185192 logger .error (rpce )
186193 return None
187- except ConnectionError as e :
188- logger .error (f"{ e } while get_rpc" )
194+ except BrokenCoreConnectionException as bcce :
195+ logger .error (f"{ bcce } while get_rpc" )
189196 return None
190197 except Exception as e :
191198 logger .exception (e )
@@ -194,7 +201,7 @@ def get_rpc(self):
194201 return rpc
195202 else :
196203 logger .debug (
197- f"connection { rpc } fails test_connection() returning None in get_rpc"
204+ f"Connection { rpc } fails test_connection() in get_rpc. Returning None ... "
198205 )
199206 return None
200207
@@ -239,10 +246,14 @@ def update_rpc(
239246 self .protocol = protocol
240247 update_rpc = True
241248 if update_rpc :
242- self .rpc = self .get_rpc ()
243- if self .rpc and self .rpc .test_connection ():
244- logger .debug (f"persisting { self } in update_rpc" )
245- write_node (self , self .fullpath )
249+ try :
250+ self .rpc = self ._get_rpc ()
251+ if self .rpc and self .rpc .test_connection ():
252+ logger .debug (f"persisting { self } in update_rpc" )
253+ write_node (self , self .fullpath )
254+ except BrokenCoreConnectionException :
255+ self ._mark_node_as_broken ()
256+ return False
246257 self .check_info ()
247258 return False if not self .rpc else self .rpc .test_connection ()
248259
@@ -255,7 +266,6 @@ def rename(self, new_name):
255266
256267 def check_info (self ):
257268 self ._is_configured = self .rpc is not None
258- self ._is_running = False
259269 if self .rpc is not None and self .rpc .test_connection ():
260270 try :
261271 res = [
@@ -289,12 +299,8 @@ def check_info(self):
289299 self .utxorescanwallet = None
290300 self ._network_parameters = get_network (self .chain )
291301 self ._is_running = True
292- except Exception as e :
293- self ._info = {"chain" : None }
294- self ._network_info = {"subversion" : "" , "version" : 999999 }
295- self ._network_parameters = get_network ("main" )
296- logger .error (f"connection { self .rpc } could not suceed check_info" )
297- logger .exception ("Exception %s while check_info()" % e )
302+ except BrokenCoreConnectionException :
303+ self ._mark_node_as_broken ()
298304 else :
299305 if self .rpc is None :
300306 logger .warning (f"connection of { self } is None in check_info" )
@@ -315,24 +321,20 @@ def check_info(self):
315321 )
316322 except Exception as e :
317323 logger .exception (e )
318- self ._info = {"chain" : None }
319- self ._network_info = {"subversion" : "" , "version" : 999999 }
320-
321- if not self ._is_running :
322- self ._info ["chain" ] = None
324+ self ._mark_node_as_broken ()
323325
324326 def test_rpc (self ):
325327 """tests the rpc-connection and returns a dict which helps
326328 to derive what might be wrong with the config
327329 ToDo: list an example here.
328330 """
329- rpc = self .get_rpc ()
331+ rpc = self ._get_rpc ()
330332 if rpc is None :
331333 return {
332334 "out" : "" ,
333335 "err" : _ ("Connection to node failed" ),
334336 "code" : - 1 ,
335- "tests" : {},
337+ "tests" : {"connectable" : False },
336338 }
337339 r = {}
338340 r ["tests" ] = {"connectable" : False }
@@ -356,15 +358,14 @@ def test_rpc(self):
356358 r ["err" ] = "Wallets disabled"
357359
358360 r ["out" ] = json .dumps (rpc .getblockchaininfo (), indent = 4 )
359- except ConnectionError as e :
360- logger .info ("Caught an ConnectionError while test_rpc: %s" , e )
361-
361+ except BrokenCoreConnectionException as bcce :
362+ logger .info (f"Caught { bcce } while test_rpc" )
362363 r ["tests" ]["connectable" ] = False
363364 r ["err" ] = _ ("Failed to connect!" )
364365 r ["code" ] = - 1
365366 except RpcError as rpce :
366367 logger .info (
367- f"Caught an RpcError while test_rpc status_code: { rpce .status_code } error_code:{ rpce .error_code } "
368+ f"Caught an RpcError while test_rpc status_code: { rpce .status_code } error_code: { rpce .error_code } "
368369 )
369370 r ["tests" ]["connectable" ] = True
370371 r ["code" ] = rpc .r .status_code
@@ -374,7 +375,7 @@ def test_rpc(self):
374375 else :
375376 r ["err" ] = str (rpce .status_code )
376377 except Exception as e :
377- logger .error (
378+ logger .exception (
378379 "Caught an exception of type {} while test_rpc: {}" .format (
379380 type (e ), str (e )
380381 )
@@ -388,6 +389,16 @@ def test_rpc(self):
388389 r ["code" ] = - 1
389390 return r
390391
392+ def _mark_node_as_broken (self ):
393+ self ._info = {"chain" : None }
394+ self ._network_info = {"subversion" : "" , "version" : 999999 }
395+ self ._network_parameters = get_network ("main" )
396+ logger .debug (
397+ f"Node is not running, no RPC connection, check_info didn't succeed, setting RPC attribute to None ..."
398+ )
399+ self ._info ["chain" ] = None
400+ self .rpc = None
401+
391402 def abortrescanutxo (self ):
392403 """use this to abort a rescan as it stores some state while rescanning"""
393404 self .rpc .scantxoutset ("abort" , [])
@@ -409,7 +420,11 @@ def is_liquid(self):
409420
410421 @property
411422 def is_running (self ):
412- return self ._is_running
423+ if self ._network_info ["version" ] == 999999 :
424+ logger .debug (f"Node is not running" )
425+ return False
426+ else :
427+ return True
413428
414429 @property
415430 def is_configured (self ):
@@ -478,10 +493,12 @@ def is_liquid(self):
478493
479494 @property
480495 def rpc (self ):
496+ """Returns None if rpc is broken"""
481497 if not hasattr (self , "_rpc" ):
482- return None
483- else :
484- return self ._rpc
498+ self ._rpc = self ._get_rpc ()
499+ elif self ._rpc is None :
500+ self ._rpc = self ._get_rpc ()
501+ return self ._rpc
485502
486503 @property
487504 def node_type (self ):
0 commit comments