diff --git a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart index 6c0c49884..627c54fa0 100644 --- a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart @@ -53,6 +53,13 @@ abstract class LibMoneroWallet int get isarTransactionVersion => 2; LibMoneroWallet(super.currency, this.compatType) { + _attachTorListeners(); + + // Potentially dangerous hack. See comments in _startInit() + _startInit(); + } + + void _attachTorListeners() { final bus = GlobalEventBus.instance; // Listen for tor status changes. @@ -83,10 +90,8 @@ abstract class LibMoneroWallet ) async { await updateNode(); }); - - // Potentially dangerous hack. See comments in _startInit() - _startInit(); } + // cw based wallet listener to handle synchronization of utxo frozen states late final StreamSubscription> _streamSub; Future _startInit() async { @@ -193,6 +198,10 @@ abstract class LibMoneroWallet @override Future open() async { + if (_torStatusListener == null || _torPreferenceListener == null) { + _attachTorListeners(); + } + bool wasNull = false; if (wallet == null) { @@ -441,7 +450,7 @@ abstract class LibMoneroWallet ); if (this.wallet != null) { - await exit(); + await _exitNative(); } this.wallet = wallet; @@ -504,24 +513,50 @@ abstract class LibMoneroWallet @override Future updateNode() async { - final node = getCurrentNode(); - - if (await _torNodeMismatchGuard(node)) { - throw Exception("TOR – clearnet mismatch"); + if (wallet == null) { + return; } - final host = node.host.endsWith(".onion") - ? node.host - : Uri.parse(node.host).host; - final ({InternetAddress host, int port})? proxy = - AppConfig.hasFeature(AppFeature.tor) && prefs.useTor && !node.forceNoTor - ? TorService.sharedInstance.getProxyInfo() - : null; + await _updateNodeMutex.protect(() async { + if (wallet == null) { + return; + } - _setSyncStatus(lib_monero_compat.ConnectingSyncStatus()); - try { - if (_requireMutex) { - await _torConnectingLock.protect(() async { + final node = getCurrentNode(); + + if (await _torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); + } + + final host = node.host.endsWith(".onion") + ? node.host + : Uri.parse(node.host).host; + final ({InternetAddress host, int port})? proxy = + AppConfig.hasFeature(AppFeature.tor) && + prefs.useTor && + !node.forceNoTor + ? TorService.sharedInstance.getProxyInfo() + : null; + + _setSyncStatus(lib_monero_compat.ConnectingSyncStatus()); + try { + if (_requireMutex) { + await _torConnectingLock.protect(() async { + await csMonero.connect( + wallet!, + daemonAddress: "$host:${node.port}", + daemonUsername: node.loginName, + daemonPassword: await node.getPassword(secureStorageInterface), + trusted: node.trusted ?? false, + useSSL: node.useSSL, + socksProxyAddress: node.forceNoTor + ? null + : proxy == null + ? null + : "${proxy.host.address}:${proxy.port}", + ); + }); + } else { await csMonero.connect( wallet!, daemonAddress: "$host:${node.port}", @@ -535,37 +570,21 @@ abstract class LibMoneroWallet ? null : "${proxy.host.address}:${proxy.port}", ); - }); - } else { - await csMonero.connect( - wallet!, - daemonAddress: "$host:${node.port}", - daemonUsername: node.loginName, - daemonPassword: await node.getPassword(secureStorageInterface), - trusted: node.trusted ?? false, - useSSL: node.useSSL, - socksProxyAddress: node.forceNoTor - ? null - : proxy == null - ? null - : "${proxy.host.address}:${proxy.port}", + } + await csMonero.startSyncing(wallet!); + await csMonero.startListeners(wallet!); + csMonero.startAutoSaving(wallet!); + + _setSyncStatus(lib_monero_compat.ConnectedSyncStatus()); + } catch (e, s) { + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + Logging.instance.e( + "Exception caught in $runtimeType.updateNode(): ", + error: e, + stackTrace: s, ); } - await csMonero.startSyncing(wallet!); - await csMonero.startListeners(wallet!); - csMonero.startAutoSaving(wallet!); - - _setSyncStatus(lib_monero_compat.ConnectedSyncStatus()); - } catch (e, s) { - _setSyncStatus(lib_monero_compat.FailedSyncStatus()); - Logging.instance.e( - "Exception caught in $runtimeType.updateNode(): ", - error: e, - stackTrace: s, - ); - } - - return; + }); } @override @@ -732,13 +751,21 @@ abstract class LibMoneroWallet @override Future exit() async { Logging.instance.i("exit called on monero $walletId!"); + await _exitNative(); + await _torStatusListener?.cancel(); + await _torPreferenceListener?.cancel(); + _torStatusListener = null; + _torPreferenceListener = null; + Logging.instance.i("exit call completed monero $walletId!"); + } + + Future _exitNative() async { if (wallet != null) { csMonero.stopAutoSaving(wallet!); await csMonero.stopListeners(wallet!); await csMonero.stopSyncing(wallet!); await csMonero.save(wallet!); } - Logging.instance.i("exit call completed monero $walletId!"); } Future pathForWalletDir({ @@ -1578,7 +1605,7 @@ abstract class LibMoneroWallet ); if (this.wallet == null) { - await exit(); + await _exitNative(); } this.wallet = wallet; @@ -1629,4 +1656,6 @@ abstract class LibMoneroWallet final Mutex _torConnectingLock = Mutex(); bool _requireMutex = false; + + final Mutex _updateNodeMutex = Mutex(); } diff --git a/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart b/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart index 4517f1498..89096e87c 100644 --- a/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_salvium_wallet.dart @@ -51,6 +51,13 @@ abstract class LibSalviumWallet int get isarTransactionVersion => 2; LibSalviumWallet(super.currency) { + _attachTorListeners(); + + // Potentially dangerous hack. See comments in _startInit() + _startInit(); + } + + void _attachTorListeners() { final bus = GlobalEventBus.instance; // Listen for tor status changes. @@ -81,10 +88,8 @@ abstract class LibSalviumWallet ) async { await updateNode(); }); - - // Potentially dangerous hack. See comments in _startInit() - _startInit(); } + // cw based wallet listener to handle synchronization of utxo frozen states late final StreamSubscription> _streamSub; Future _startInit() async { @@ -189,6 +194,10 @@ abstract class LibSalviumWallet @override Future open() async { + if (_torStatusListener == null || _torPreferenceListener == null) { + _attachTorListeners(); + } + bool wasNull = false; if (wallet == null) { @@ -419,7 +428,7 @@ abstract class LibSalviumWallet ); if (this.wallet != null) { - await exit(); + await _exitNative(); } this.wallet = wallet; @@ -481,24 +490,50 @@ abstract class LibSalviumWallet @override Future updateNode() async { - final node = getCurrentNode(); - - if (_torNodeMismatchGuard(node)) { - throw Exception("TOR – clearnet mismatch"); + if (wallet == null) { + return; } - final host = node.host.endsWith(".onion") - ? node.host - : Uri.parse(node.host).host; - final ({InternetAddress host, int port})? proxy = - AppConfig.hasFeature(AppFeature.tor) && prefs.useTor && !node.forceNoTor - ? TorService.sharedInstance.getProxyInfo() - : null; + await _updateNodeMutex.protect(() async { + if (wallet == null) { + return; + } + + final node = getCurrentNode(); - _setSyncStatus(ConnectingSyncStatus()); - try { - if (_requireMutex) { - await _torConnectingLock.protect(() async { + if (_torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); + } + + final host = node.host.endsWith(".onion") + ? node.host + : Uri.parse(node.host).host; + final ({InternetAddress host, int port})? proxy = + AppConfig.hasFeature(AppFeature.tor) && + prefs.useTor && + !node.forceNoTor + ? TorService.sharedInstance.getProxyInfo() + : null; + + _setSyncStatus(ConnectingSyncStatus()); + try { + if (_requireMutex) { + await _torConnectingLock.protect(() async { + await csSalvium.connect( + wallet!, + daemonAddress: "$host:${node.port}", + daemonUsername: node.loginName, + daemonPassword: await node.getPassword(secureStorageInterface), + trusted: node.trusted ?? false, + useSSL: node.useSSL, + socksProxyAddress: node.forceNoTor + ? null + : proxy == null + ? null + : "${proxy.host.address}:${proxy.port}", + ); + }); + } else { await csSalvium.connect( wallet!, daemonAddress: "$host:${node.port}", @@ -512,37 +547,21 @@ abstract class LibSalviumWallet ? null : "${proxy.host.address}:${proxy.port}", ); - }); - } else { - await csSalvium.connect( - wallet!, - daemonAddress: "$host:${node.port}", - daemonUsername: node.loginName, - daemonPassword: await node.getPassword(secureStorageInterface), - trusted: node.trusted ?? false, - useSSL: node.useSSL, - socksProxyAddress: node.forceNoTor - ? null - : proxy == null - ? null - : "${proxy.host.address}:${proxy.port}", + } + csSalvium.startSyncing(wallet!); + csSalvium.startListeners(wallet!); + csSalvium.startAutoSaving(wallet!); + + // _setSyncStatus(ConnectedSyncStatus()); + } catch (e, s) { + // _setSyncStatus(FailedSyncStatus()); + Logging.instance.e( + "Exception caught in $runtimeType.updateNode(): ", + error: e, + stackTrace: s, ); } - csSalvium.startSyncing(wallet!); - csSalvium.startListeners(wallet!); - csSalvium.startAutoSaving(wallet!); - - // _setSyncStatus(ConnectedSyncStatus()); - } catch (e, s) { - // _setSyncStatus(FailedSyncStatus()); - Logging.instance.e( - "Exception caught in $runtimeType.updateNode(): ", - error: e, - stackTrace: s, - ); - } - - return; + }); } @override @@ -727,6 +746,14 @@ abstract class LibSalviumWallet @override Future exit() async { Logging.instance.i("exit called on $walletId"); + await _exitNative(); + await _torStatusListener?.cancel(); + await _torPreferenceListener?.cancel(); + _torStatusListener = null; + _torPreferenceListener = null; + } + + Future _exitNative() async { if (wallet != null) { csSalvium.stopAutoSaving(wallet!); csSalvium.stopListeners(wallet!); @@ -1544,7 +1571,7 @@ abstract class LibSalviumWallet ); if (this.wallet != null) { - await exit(); + await _exitNative(); } this.wallet = wallet; @@ -1596,6 +1623,8 @@ abstract class LibSalviumWallet final Mutex _torConnectingLock = Mutex(); bool _requireMutex = false; + + final Mutex _updateNodeMutex = Mutex(); } String _libSalviumWalletPasswordKey(String walletName) => diff --git a/lib/wallets/wallet/intermediate/lib_wownero_wallet.dart b/lib/wallets/wallet/intermediate/lib_wownero_wallet.dart index 5ebd2191a..78cf8acc3 100644 --- a/lib/wallets/wallet/intermediate/lib_wownero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_wownero_wallet.dart @@ -55,6 +55,13 @@ abstract class LibWowneroWallet int get isarTransactionVersion => 2; LibWowneroWallet(super.currency, this.compatType) { + _attachTorListeners(); + + // Potentially dangerous hack. See comments in _startInit() + _startInit(); + } + + void _attachTorListeners() { final bus = GlobalEventBus.instance; // Listen for tor status changes. @@ -85,10 +92,8 @@ abstract class LibWowneroWallet ) async { await updateNode(); }); - - // Potentially dangerous hack. See comments in _startInit() - _startInit(); } + // cw based wallet listener to handle synchronization of utxo frozen states late final StreamSubscription> _streamSub; Future _startInit() async { @@ -195,6 +200,10 @@ abstract class LibWowneroWallet @override Future open() async { + if (_torStatusListener == null || _torPreferenceListener == null) { + _attachTorListeners(); + } + bool wasNull = false; if (wallet == null) { @@ -443,7 +452,7 @@ abstract class LibWowneroWallet ); if (this.wallet != null) { - await exit(); + await _exitNative(); } this.wallet = wallet; @@ -506,24 +515,50 @@ abstract class LibWowneroWallet @override Future updateNode() async { - final node = getCurrentNode(); - - if (_torNodeMismatchGuard(node)) { - throw Exception("TOR – clearnet mismatch"); + if (wallet == null) { + return; } - final host = node.host.endsWith(".onion") - ? node.host - : Uri.parse(node.host).host; - final ({InternetAddress host, int port})? proxy = - AppConfig.hasFeature(AppFeature.tor) && prefs.useTor && !node.forceNoTor - ? TorService.sharedInstance.getProxyInfo() - : null; + await _updateNodeMutex.protect(() async { + if (wallet == null) { + return; + } - _setSyncStatus(lib_monero_compat.ConnectingSyncStatus()); - try { - if (_requireMutex) { - await _torConnectingLock.protect(() async { + final node = getCurrentNode(); + + if (_torNodeMismatchGuard(node)) { + throw Exception("TOR – clearnet mismatch"); + } + + final host = node.host.endsWith(".onion") + ? node.host + : Uri.parse(node.host).host; + final ({InternetAddress host, int port})? proxy = + AppConfig.hasFeature(AppFeature.tor) && + prefs.useTor && + !node.forceNoTor + ? TorService.sharedInstance.getProxyInfo() + : null; + + _setSyncStatus(lib_monero_compat.ConnectingSyncStatus()); + try { + if (_requireMutex) { + await _torConnectingLock.protect(() async { + await csWownero.connect( + wallet!, + daemonAddress: "$host:${node.port}", + daemonUsername: node.loginName, + daemonPassword: await node.getPassword(secureStorageInterface), + trusted: node.trusted ?? false, + useSSL: node.useSSL, + socksProxyAddress: node.forceNoTor + ? null + : proxy == null + ? null + : "${proxy.host.address}:${proxy.port}", + ); + }); + } else { await csWownero.connect( wallet!, daemonAddress: "$host:${node.port}", @@ -537,37 +572,21 @@ abstract class LibWowneroWallet ? null : "${proxy.host.address}:${proxy.port}", ); - }); - } else { - await csWownero.connect( - wallet!, - daemonAddress: "$host:${node.port}", - daemonUsername: node.loginName, - daemonPassword: await node.getPassword(secureStorageInterface), - trusted: node.trusted ?? false, - useSSL: node.useSSL, - socksProxyAddress: node.forceNoTor - ? null - : proxy == null - ? null - : "${proxy.host.address}:${proxy.port}", + } + csWownero.startSyncing(wallet!); + csWownero.startListeners(wallet!); + csWownero.startAutoSaving(wallet!); + + _setSyncStatus(lib_monero_compat.ConnectedSyncStatus()); + } catch (e, s) { + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + Logging.instance.e( + "Exception caught in $runtimeType.updateNode(): ", + error: e, + stackTrace: s, ); } - csWownero.startSyncing(wallet!); - csWownero.startListeners(wallet!); - csWownero.startAutoSaving(wallet!); - - _setSyncStatus(lib_monero_compat.ConnectedSyncStatus()); - } catch (e, s) { - _setSyncStatus(lib_monero_compat.FailedSyncStatus()); - Logging.instance.e( - "Exception caught in $runtimeType.updateNode(): ", - error: e, - stackTrace: s, - ); - } - - return; + }); } @override @@ -750,6 +769,14 @@ abstract class LibWowneroWallet @override Future exit() async { Logging.instance.i("exit called on $wallet!"); + await _exitNative(); + await _torStatusListener?.cancel(); + await _torPreferenceListener?.cancel(); + _torStatusListener = null; + _torPreferenceListener = null; + } + + Future _exitNative() async { if (wallet != null) { csWownero.stopAutoSaving(wallet!); csWownero.stopListeners(wallet!); @@ -1556,7 +1583,7 @@ abstract class LibWowneroWallet ); if (this.wallet == null) { - await exit(); + await _exitNative(); } this.wallet = wallet; @@ -1607,4 +1634,6 @@ abstract class LibWowneroWallet final Mutex _torConnectingLock = Mutex(); bool _requireMutex = false; + + final Mutex _updateNodeMutex = Mutex(); }