11import logging
22import os
3+ import sys
34import pathlib
4- import shutil
55import threading
66import traceback
77from typing import Dict
88
99from flask_babel import lazy_gettext as _
1010from cryptoadvance .specter .rpc import BitcoinRPC
11-
1211from cryptoadvance .specter .key import Key
1312
1413from ..helpers import add_dicts , alias , is_liquid , load_jsons
@@ -37,7 +36,7 @@ def __init__(
3736 chain ,
3837 device_manager ,
3938 path = "specter" ,
40- allow_threading = True ,
39+ allow_threading_for_testing = False ,
4140 ):
4241 self .data_folder = data_folder
4342 self .chain = chain
@@ -52,7 +51,7 @@ def __init__(
5251 self .wallets = {}
5352 # A way to communicate failed wallets to the outside
5453 self .bitcoin_core_version_raw = bitcoin_core_version_raw
55- self .allow_threading = allow_threading
54+ self .allow_threading_for_testing = allow_threading_for_testing
5655 # define different wallet classes for liquid and bitcoin
5756 self .WalletClass = LWallet if is_liquid (chain ) else Wallet
5857 self .update (data_folder , rpc , chain )
@@ -108,15 +107,29 @@ def update(
108107 and self .rpc is not None
109108 and self .chain is not None
110109 ):
111- if self .allow_threading and use_threading :
112- t = threading .Thread (
113- target = self ._update ,
114- args = (wallets_update_list ,),
115- )
116-
117- t .start ()
110+ if "pytest" in sys .modules :
111+ if self .allow_threading_for_testing :
112+ logger .info ("Using threads in updating the wallet manager." )
113+ t = threading .Thread (
114+ target = self ._update ,
115+ args = (wallets_update_list ,),
116+ )
117+ t .start ()
118+ else :
119+ logger .info ("Not using threads in updating the wallet manager." )
120+ self ._update (wallets_update_list )
118121 else :
119- self ._update (wallets_update_list )
122+ if use_threading :
123+ logger .info ("Using threads in updating the wallet manager." )
124+ t = threading .Thread (
125+ target = self ._update ,
126+ args = (wallets_update_list ,),
127+ )
128+
129+ t .start ()
130+ else :
131+ logger .info ("Not using threads in updating the wallet manager." )
132+ self ._update (wallets_update_list )
120133 else :
121134 self .is_loading = False
122135 logger .warning (
@@ -134,7 +147,7 @@ def _update(self, wallets_update_list: Dict):
134147 * and, on the Specter side, the wallet objects of those unloaded wallets are reinitialised
135148 """
136149 logger .info (
137- f"Started Updating Wallets with { len (wallets_update_list .values ())} wallets"
150+ f"Started updating wallets with { len (wallets_update_list .values ())} wallets"
138151 )
139152 # list of wallets in the dict
140153 existing_names = list (self .wallets .keys ())
@@ -147,7 +160,7 @@ def _update(self, wallets_update_list: Dict):
147160
148161 wallet_alias = wallets_update_list [wallet ]["alias" ]
149162 wallet_name = wallets_update_list [wallet ]["name" ]
150- logger .info (f" Updating wallet { wallet_name } " )
163+ logger .info (f"Updating wallet { wallet_name } " )
151164 # wallet from json not yet loaded in Bitcoin Core?!
152165 if os .path .join (self .rpc_path , wallet_alias ) not in loaded_wallets :
153166 try :
@@ -348,27 +361,43 @@ def create_wallet(self, name, sigs_required, key_type, keys, devices, **kwargs):
348361 else :
349362 raise ("Failed to create new wallet" )
350363
351- def delete_wallet (
352- self , wallet , bitcoin_datadir = get_default_datadir (), chain = "main"
353- ):
354- logger .info ("Deleting {}" .format (wallet .alias ))
355- wallet_rpc_path = os .path .join (self .rpc_path , wallet .alias )
356- self .rpc .unloadwallet (wallet_rpc_path )
357- # Try deleting wallet folder
358- if bitcoin_datadir :
359- if chain != "main" :
360- bitcoin_datadir = os .path .join (bitcoin_datadir , chain )
361- candidates = [
362- os .path .join (bitcoin_datadir , wallet_rpc_path ),
363- os .path .join (bitcoin_datadir , "wallets" , wallet_rpc_path ),
364- ]
365- for path in candidates :
366- shutil .rmtree (path , ignore_errors = True )
367-
368- # Delete files
369- wallet .delete_files ()
370- del self .wallets [wallet .name ]
371- self .update ()
364+ def delete_wallet (self , wallet , node = None ) -> tuple :
365+ """Returns a tuple with two Booleans, indicating whether the wallet was deleted on the Specter side and/or on the node side."""
366+ logger .info (f"Deleting { wallet .alias } " )
367+ specter_wallet_deleted = False
368+ node_wallet_file_deleted = False
369+ # Make first sure that we can unload the wallet in Bitcoin Core
370+ try :
371+ wallet_rpc_path = os .path .join (
372+ self .rpc_path , wallet .alias
373+ ) # e.g. specter/jade_wallet
374+ logger .debug (f"The wallet_rpc_path is: { wallet_rpc_path } " )
375+ self .rpc .unloadwallet (wallet_rpc_path )
376+ # Delete the wallet.json and backups
377+ try :
378+ wallet .delete_files ()
379+ # Remove the wallet instance
380+ del self .wallets [wallet .name ]
381+ self .update ()
382+ specter_wallet_deleted = True
383+ except KeyError :
384+ raise SpecterError (
385+ f"The wallet { wallet .name } has already been deleted."
386+ )
387+ except SpecterInternalException as sie :
388+ logger .exception (
389+ f"Could not delete the wallet { wallet .name } in Specter due to { sie } "
390+ )
391+ # Also delete the wallet file on the node if possible
392+ if node :
393+ if node .delete_wallet_file (wallet ):
394+ node_wallet_file_deleted = True
395+ except RpcError :
396+ raise SpecterError (
397+ "Unable to unload the wallet on the node. Aborting the deletion of the wallet ..."
398+ )
399+ deleted = (specter_wallet_deleted , node_wallet_file_deleted )
400+ return deleted
372401
373402 def rename_wallet (self , wallet , name ):
374403 logger .info ("Renaming {}" .format (wallet .alias ))
@@ -469,7 +498,7 @@ def delete(self, specter):
469498 """Deletes all the wallets"""
470499 for w in list (self .wallets .keys ()):
471500 wallet = self .wallets [w ]
472- self .delete_wallet (wallet , specter . bitcoin_datadir , specter . chain )
501+ self .delete_wallet (wallet )
473502 delete_folder (self .data_folder )
474503
475504 @classmethod
0 commit comments