@ -53,7 +53,7 @@ from .simple_config import SimpleConfig
from . exchange_rate import FxThread
from . logging import get_logger , Logger
from . import GuiImportError
from . plugin import run_hook
from . plugin import run_hook , Plugins
if TYPE_CHECKING :
from electrum import gui
@ -376,11 +376,19 @@ class WatchTowerServer(AuthenticatedServer):
class Daemon ( Logger ) :
network : Optional [ Network ]
gui_object : Optional [ ' gui.BaseElectrumGui ' ]
network : Optional [ Network ] = None
gui_object : Optional [ ' gui.BaseElectrumGui ' ] = None
watchtower : Optional [ ' WatchTowerServer ' ] = None
@profiler
def __init__ ( self , config : SimpleConfig , fd = None , * , listen_jsonrpc = True ) :
def __init__ (
self ,
config : SimpleConfig ,
fd = None ,
* ,
listen_jsonrpc : bool = True ,
start_network : bool = True , # setting to False allows customising network settings before starting it
) :
Logger . __init__ ( self )
self . config = config
self . listen_jsonrpc = listen_jsonrpc
@ -392,11 +400,9 @@ class Daemon(Logger):
self . logger . warning ( " Ignoring parameter ' wallet_path ' for daemon. "
" Use the load_wallet command instead. " )
self . asyncio_loop = util . get_asyncio_loop ( )
self . network = None
if not config . get ( ' offline ' ) :
self . network = Network ( config , daemon = self )
self . fx = FxThread ( config = config )
self . gui_object = None
# path -> wallet; make sure path is standardized.
self . _wallets = { } # type: Dict[str, Abstract_Wallet]
self . _wallet_lock = threading . RLock ( )
@ -406,23 +412,14 @@ class Daemon(Logger):
if listen_jsonrpc :
self . commands_server = CommandsServer ( self , fd )
daemon_jobs . append ( self . commands_server . run ( ) )
# server-side watchtower
self . watchtower = None
watchtower_address = self . config . get_netaddress ( ' watchtower_address ' )
if not config . get ( ' offline ' ) and watchtower_address :
self . watchtower = WatchTowerServer ( self . network , watchtower_address )
daemon_jobs . append ( self . watchtower . run )
if self . network :
self . network . start ( jobs = [ self . fx . run ] )
# prepare lightning functionality, also load channel db early
if self . config . get ( ' use_gossip ' , False ) :
self . network . start_gossip ( )
self . _stop_entered = False
self . _stopping_soon_or_errored = threading . Event ( )
self . _stopped_event = threading . Event ( )
self . taskgroup = OldTaskGroup ( )
asyncio . run_coroutine_threadsafe ( self . _run ( jobs = daemon_jobs ) , self . asyncio_loop )
if start_network and self . network :
self . start_network ( )
@log_exceptions
async def _run ( self , jobs : Iterable = None ) :
@ -442,6 +439,20 @@ class Daemon(Logger):
# not see the exception (especially if the GUI did not start yet).
self . _stopping_soon_or_errored . set ( )
def start_network ( self ) :
self . logger . info ( f " starting network. " )
assert not self . config . get ( ' offline ' )
assert self . network
# server-side watchtower
if watchtower_address := self . config . get_netaddress ( ' watchtower_address ' ) :
self . watchtower = WatchTowerServer ( self . network , watchtower_address )
asyncio . run_coroutine_threadsafe ( self . taskgroup . spawn ( self . watchtower . run ) , self . asyncio_loop )
self . network . start ( jobs = [ self . fx . run ] )
# prepare lightning functionality, also load channel db early
if self . config . get ( ' use_gossip ' , False ) :
self . network . start_gossip ( )
def with_wallet_lock ( func ) :
def func_wrapper ( self : ' Daemon ' , * args , * * kwargs ) :
with self . _wallet_lock :
@ -566,7 +577,7 @@ class Daemon(Logger):
self . logger . info ( " stopped " )
self . _stopped_event . set ( )
def run_gui ( self , config , plugins ) :
def run_gui ( self , config : ' SimpleConfig ' , plugins : ' Plugins ' ) :
threading . current_thread ( ) . name = ' GUI '
gui_name = config . get ( ' gui ' , ' qt ' )
if gui_name in [ ' lite ' , ' classic ' ] :