From 6cfe9e9c0f58c339ba66148ceed3202be1c4551b Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 25 Nov 2024 13:33:58 -0600 Subject: [PATCH 01/14] add plain/tor network flags to node data --- lib/models/node_model.dart | 13 +++++++++++++ lib/models/type_adaptors/node_model.g.dart | 10 ++++++++-- .../helpers/restore_create_backup.dart | 2 ++ lib/services/node_service.dart | 3 +++ lib/wallets/crypto_currency/coins/banano.dart | 2 ++ lib/wallets/crypto_currency/coins/bitcoin.dart | 6 ++++++ .../crypto_currency/coins/bitcoin_frost.dart | 6 ++++++ lib/wallets/crypto_currency/coins/bitcoincash.dart | 4 ++++ lib/wallets/crypto_currency/coins/cardano.dart | 5 ++++- lib/wallets/crypto_currency/coins/dash.dart | 2 ++ lib/wallets/crypto_currency/coins/dogecoin.dart | 4 ++++ lib/wallets/crypto_currency/coins/ecash.dart | 2 ++ lib/wallets/crypto_currency/coins/epiccash.dart | 2 ++ lib/wallets/crypto_currency/coins/ethereum.dart | 2 ++ lib/wallets/crypto_currency/coins/firo.dart | 4 ++++ lib/wallets/crypto_currency/coins/litecoin.dart | 4 ++++ lib/wallets/crypto_currency/coins/monero.dart | 2 ++ lib/wallets/crypto_currency/coins/namecoin.dart | 2 ++ lib/wallets/crypto_currency/coins/nano.dart | 2 ++ lib/wallets/crypto_currency/coins/particl.dart | 2 ++ lib/wallets/crypto_currency/coins/peercoin.dart | 4 ++++ lib/wallets/crypto_currency/coins/solana.dart | 2 ++ lib/wallets/crypto_currency/coins/stellar.dart | 4 ++++ lib/wallets/crypto_currency/coins/tezos.dart | 2 ++ lib/wallets/crypto_currency/coins/wownero.dart | 2 ++ 25 files changed, 90 insertions(+), 3 deletions(-) diff --git a/lib/models/node_model.dart b/lib/models/node_model.dart index a07c9a2dd..a945a5eb7 100644 --- a/lib/models/node_model.dart +++ b/lib/models/node_model.dart @@ -9,6 +9,7 @@ */ import 'package:hive/hive.dart'; + import '../utilities/default_nodes.dart'; import '../utilities/flutter_secure_storage_interface.dart'; @@ -38,6 +39,10 @@ class NodeModel { final bool isDown; // @HiveField(10) final bool? trusted; + // @HiveField(11) + final bool torEnabled; + // @HiveField(12) + final bool plainEnabled; NodeModel({ required this.host, @@ -49,6 +54,8 @@ class NodeModel { required this.coinName, required this.isFailover, required this.isDown, + required this.torEnabled, + required this.plainEnabled, this.loginName, this.trusted, }); @@ -64,6 +71,8 @@ class NodeModel { bool? isFailover, bool? isDown, bool? trusted, + bool? torEnabled, + bool? plainEnabled, }) { return NodeModel( host: host ?? this.host, @@ -77,6 +86,8 @@ class NodeModel { isFailover: isFailover ?? this.isFailover, isDown: isDown ?? this.isDown, trusted: trusted ?? this.trusted, + torEnabled: torEnabled ?? this.torEnabled, + plainEnabled: plainEnabled ?? this.plainEnabled, ); } @@ -98,6 +109,8 @@ class NodeModel { map['isFailover'] = isFailover; map['isDown'] = isDown; map['trusted'] = trusted; + map['torEnabled'] = torEnabled; + map['plainEnabled'] = plainEnabled; return map; } diff --git a/lib/models/type_adaptors/node_model.g.dart b/lib/models/type_adaptors/node_model.g.dart index 597468c56..cc771ba09 100644 --- a/lib/models/type_adaptors/node_model.g.dart +++ b/lib/models/type_adaptors/node_model.g.dart @@ -28,13 +28,15 @@ class NodeModelAdapter extends TypeAdapter { isFailover: fields[8] as bool, isDown: fields[9] as bool, trusted: fields[10] as bool?, + torEnabled: fields[11] as bool? ?? true, + plainEnabled: fields[12] as bool? ?? true, ); } @override void write(BinaryWriter writer, NodeModel obj) { writer - ..writeByte(11) + ..writeByte(13) ..writeByte(0) ..write(obj.id) ..writeByte(1) @@ -56,7 +58,11 @@ class NodeModelAdapter extends TypeAdapter { ..writeByte(9) ..write(obj.isDown) ..writeByte(10) - ..write(obj.trusted); + ..write(obj.trusted) + ..writeByte(11) + ..write(obj.torEnabled) + ..writeByte(12) + ..write(obj.plainEnabled); } @override diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index 6d99938b3..6846686ab 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -1272,6 +1272,8 @@ abstract class SWB { loginName: node['loginName'] as String?, isFailover: node['isFailover'] as bool, isDown: node['isDown'] as bool, + torEnabled: node['torEnabled'] as bool? ?? true, + plainEnabled: node['plainEnabled'] as bool? ?? true, ), node["password"] as String?, true, diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index f2e640a67..306cb5d6a 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -12,6 +12,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; + import '../app_config.dart'; import '../db/hive/db.dart'; import '../models/node_model.dart'; @@ -253,7 +254,9 @@ class NodeService extends ChangeNotifier { enabled: true, coinName: coin.identifier, isFailover: true, + torEnabled: nodeMap["torEnabled"] == "true", isDown: nodeMap["isDown"] == "true", + plainEnabled: nodeMap["plainEnabled"] == "true", ); final currentNode = getNodeById(id: nodeMap["id"] as String); if (currentNode != null) { diff --git a/lib/wallets/crypto_currency/coins/banano.dart b/lib/wallets/crypto_currency/coins/banano.dart index 4bb5184d2..c32adb8f4 100644 --- a/lib/wallets/crypto_currency/coins/banano.dart +++ b/lib/wallets/crypto_currency/coins/banano.dart @@ -77,6 +77,8 @@ class Banano extends NanoCurrency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoin.dart b/lib/wallets/crypto_currency/coins/bitcoin.dart index 3b75e2186..c3dfa4bb8 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin.dart @@ -239,6 +239,8 @@ class Bitcoin extends Bip39HDCurrency coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -252,6 +254,8 @@ class Bitcoin extends Bip39HDCurrency coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test4: @@ -265,6 +269,8 @@ class Bitcoin extends Bip39HDCurrency coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart index 64c90a719..4c75a17b6 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart @@ -73,6 +73,8 @@ class BitcoinFrost extends FrostCurrency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -86,6 +88,8 @@ class BitcoinFrost extends FrostCurrency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test4: @@ -99,6 +103,8 @@ class BitcoinFrost extends FrostCurrency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoincash.dart b/lib/wallets/crypto_currency/coins/bitcoincash.dart index 9d9a291a8..0d60de787 100644 --- a/lib/wallets/crypto_currency/coins/bitcoincash.dart +++ b/lib/wallets/crypto_currency/coins/bitcoincash.dart @@ -298,6 +298,8 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -311,6 +313,8 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/cardano.dart b/lib/wallets/crypto_currency/coins/cardano.dart index e9cf17c65..1f8fac465 100644 --- a/lib/wallets/crypto_currency/coins/cardano.dart +++ b/lib/wallets/crypto_currency/coins/cardano.dart @@ -77,6 +77,8 @@ class Cardano extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: @@ -91,7 +93,8 @@ class Cardano extends Bip39Currency { int get fractionDigits => 6; @override - String get genesisHash => "f0f7892b5c333cffc4b3c4344de48af4cc63f55e44936196f365a9ef2244134f"; + String get genesisHash => + "f0f7892b5c333cffc4b3c4344de48af4cc63f55e44936196f365a9ef2244134f"; @override bool get hasBuySupport => false; diff --git a/lib/wallets/crypto_currency/coins/dash.dart b/lib/wallets/crypto_currency/coins/dash.dart index 366bbbcc8..dc508c4cc 100644 --- a/lib/wallets/crypto_currency/coins/dash.dart +++ b/lib/wallets/crypto_currency/coins/dash.dart @@ -189,6 +189,8 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/dogecoin.dart b/lib/wallets/crypto_currency/coins/dogecoin.dart index 1de949edc..ad1899fb6 100644 --- a/lib/wallets/crypto_currency/coins/dogecoin.dart +++ b/lib/wallets/crypto_currency/coins/dogecoin.dart @@ -189,6 +189,8 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -202,6 +204,8 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/ecash.dart b/lib/wallets/crypto_currency/coins/ecash.dart index ad1ec4f6c..84ae7bfb8 100644 --- a/lib/wallets/crypto_currency/coins/ecash.dart +++ b/lib/wallets/crypto_currency/coins/ecash.dart @@ -289,6 +289,8 @@ class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 6e47eb411..2c3dbd437 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -80,6 +80,8 @@ class Epiccash extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/ethereum.dart b/lib/wallets/crypto_currency/coins/ethereum.dart index 5c0f5b06d..32eb754e6 100644 --- a/lib/wallets/crypto_currency/coins/ethereum.dart +++ b/lib/wallets/crypto_currency/coins/ethereum.dart @@ -57,6 +57,8 @@ class Ethereum extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); @override diff --git a/lib/wallets/crypto_currency/coins/firo.dart b/lib/wallets/crypto_currency/coins/firo.dart index d8a6381b2..bbe83e526 100644 --- a/lib/wallets/crypto_currency/coins/firo.dart +++ b/lib/wallets/crypto_currency/coins/firo.dart @@ -231,6 +231,8 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -257,6 +259,8 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/litecoin.dart b/lib/wallets/crypto_currency/coins/litecoin.dart index 1c09a0c2a..46cd1d3ee 100644 --- a/lib/wallets/crypto_currency/coins/litecoin.dart +++ b/lib/wallets/crypto_currency/coins/litecoin.dart @@ -220,6 +220,8 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -233,6 +235,8 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/monero.dart b/lib/wallets/crypto_currency/coins/monero.dart index fba0e1701..ec3d9bae1 100644 --- a/lib/wallets/crypto_currency/coins/monero.dart +++ b/lib/wallets/crypto_currency/coins/monero.dart @@ -72,6 +72,8 @@ class Monero extends CryptonoteCurrency { isFailover: true, isDown: false, trusted: true, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/namecoin.dart b/lib/wallets/crypto_currency/coins/namecoin.dart index 9f0134b9a..aab17df11 100644 --- a/lib/wallets/crypto_currency/coins/namecoin.dart +++ b/lib/wallets/crypto_currency/coins/namecoin.dart @@ -102,6 +102,8 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); // case CryptoCurrencyNetwork.test: // TODO: [prio=low] Add testnet support. diff --git a/lib/wallets/crypto_currency/coins/nano.dart b/lib/wallets/crypto_currency/coins/nano.dart index 32f49cbec..c5d9c9446 100644 --- a/lib/wallets/crypto_currency/coins/nano.dart +++ b/lib/wallets/crypto_currency/coins/nano.dart @@ -77,6 +77,8 @@ class Nano extends NanoCurrency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/particl.dart b/lib/wallets/crypto_currency/coins/particl.dart index e83eaf4ed..80d6104c3 100644 --- a/lib/wallets/crypto_currency/coins/particl.dart +++ b/lib/wallets/crypto_currency/coins/particl.dart @@ -97,6 +97,8 @@ class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); // case CryptoCurrencyNetwork.test: // TODO: [prio=low] Add testnet. diff --git a/lib/wallets/crypto_currency/coins/peercoin.dart b/lib/wallets/crypto_currency/coins/peercoin.dart index ba291cc14..6074d093c 100644 --- a/lib/wallets/crypto_currency/coins/peercoin.dart +++ b/lib/wallets/crypto_currency/coins/peercoin.dart @@ -103,6 +103,8 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -116,6 +118,8 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/solana.dart b/lib/wallets/crypto_currency/coins/solana.dart index 6cfc185e1..3bf00c358 100644 --- a/lib/wallets/crypto_currency/coins/solana.dart +++ b/lib/wallets/crypto_currency/coins/solana.dart @@ -55,6 +55,8 @@ class Solana extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: throw Exception("Unsupported network: $network"); diff --git a/lib/wallets/crypto_currency/coins/stellar.dart b/lib/wallets/crypto_currency/coins/stellar.dart index f0606f1f0..75fceb211 100644 --- a/lib/wallets/crypto_currency/coins/stellar.dart +++ b/lib/wallets/crypto_currency/coins/stellar.dart @@ -68,6 +68,8 @@ class Stellar extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -81,6 +83,8 @@ class Stellar extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/tezos.dart b/lib/wallets/crypto_currency/coins/tezos.dart index e99831ca5..ff9b167c9 100644 --- a/lib/wallets/crypto_currency/coins/tezos.dart +++ b/lib/wallets/crypto_currency/coins/tezos.dart @@ -118,6 +118,8 @@ class Tezos extends Bip39Currency { coinName: identifier, isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/wownero.dart b/lib/wallets/crypto_currency/coins/wownero.dart index ed3f18c3d..595966db4 100644 --- a/lib/wallets/crypto_currency/coins/wownero.dart +++ b/lib/wallets/crypto_currency/coins/wownero.dart @@ -72,6 +72,8 @@ class Wownero extends CryptonoteCurrency { isFailover: true, isDown: false, trusted: true, + torEnabled: true, + plainEnabled: true, ); default: From d6d4df78221e403f571982d223e166bc2f1ae786 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 25 Nov 2024 18:29:58 -0600 Subject: [PATCH 02/14] quick (quite quick) and dirty (very dirty) tor/clearnet/both config option for coin network/node connections --- lib/db/db_version_migration.dart | 4 + lib/electrumx_rpc/client_manager.dart | 51 ++++- lib/electrumx_rpc/electrumx_client.dart | 46 ++++- .../node_tor_mismatch_config_exception.dart | 1 + .../add_edit_node_view.dart | 194 +++++++++++++++++- .../manage_nodes_views/node_details_view.dart | 65 +++++- lib/services/node_service.dart | 4 + lib/services/notifications_service.dart | 28 ++- lib/utilities/test_node_connection.dart | 35 ++-- lib/utilities/tor_plain_net_option_enum.dart | 23 +++ .../wallet/impl/bitcoin_frost_wallet.dart | 4 + .../intermediate/lib_monero_wallet.dart | 38 ++++ .../electrumx_interface.dart | 4 + lib/widgets/node_card.dart | 14 +- lib/widgets/node_options_sheet.dart | 11 + test/cached_electrumx_test.dart | 2 + test/services/node_service_test.dart | 10 +- test/widget_tests/node_card_test.dart | 12 ++ .../widget_tests/node_options_sheet_test.dart | 35 +++- 19 files changed, 536 insertions(+), 45 deletions(-) create mode 100644 lib/exceptions/wallet/node_tor_mismatch_config_exception.dart create mode 100644 lib/utilities/tor_plain_net_option_enum.dart diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart index 1415803e4..606996a7f 100644 --- a/lib/db/db_version_migration.dart +++ b/lib/db/db_version_migration.dart @@ -77,6 +77,8 @@ class DbVersionMigrator with WalletDB { name: e.name, id: e.id, useSSL: e.useSSL, + torEnabled: e.torEnabled, + clearEnabled: e.plainEnabled, ), ) .toList(); @@ -88,6 +90,8 @@ class DbVersionMigrator with WalletDB { name: node.name, id: node.id, useSSL: node.useSSL, + torEnabled: node.torEnabled, + clearEnabled: node.plainEnabled, ), prefs: prefs, failovers: failovers, diff --git a/lib/electrumx_rpc/client_manager.dart b/lib/electrumx_rpc/client_manager.dart index fb8b920cc..aea7e34e6 100644 --- a/lib/electrumx_rpc/client_manager.dart +++ b/lib/electrumx_rpc/client_manager.dart @@ -3,6 +3,8 @@ import 'dart:async'; import 'package:electrum_adapter/electrum_adapter.dart'; import '../utilities/logger.dart'; +import '../utilities/prefs.dart'; +import '../utilities/tor_plain_net_option_enum.dart'; import '../wallets/crypto_currency/crypto_currency.dart'; class ClientManager { @@ -10,6 +12,7 @@ class ClientManager { static final ClientManager sharedInstance = ClientManager._(); final Map _map = {}; + final Map _mapNet = {}; final Map _heights = {}; final Map> _subscriptions = {}; final Map> _heightCompleters = {}; @@ -24,18 +27,37 @@ class ClientManager { ElectrumClient? getClient({ required CryptoCurrency cryptoCurrency, - }) => - _map[_keyHelper(cryptoCurrency)]; + required TorPlainNetworkOption netType, + }) { + final _key = _keyHelper(cryptoCurrency); - void addClient( + if (netType == _mapNet[_key]) { + return _map[_key]; + } else { + return null; + } + } + + Future addClient( ElectrumClient client, { required CryptoCurrency cryptoCurrency, - }) { + required TorPlainNetworkOption netType, + }) async { final key = _keyHelper(cryptoCurrency); if (_map[key] != null) { - throw Exception("ElectrumX Client for $key already exists."); + if (_mapNet[key] == netType) { + throw Exception( + "ElectrumX Client for $key and $netType already exists.", + ); + } + + await remove(cryptoCurrency: cryptoCurrency); + + _map[key] = client; + _mapNet[key] = netType; } else { _map[key] = client; + _mapNet[key] = netType; } _heightCompleters[key] = Completer(); @@ -68,10 +90,24 @@ class ClientManager { ); } + if (Prefs.instance.useTor) { + if (_mapNet[key]! == TorPlainNetworkOption.clear) { + throw Exception( + "Non-TOR only client for $key found.", + ); + } + } else { + if (_mapNet[key]! == TorPlainNetworkOption.tor) { + throw Exception( + "TOR only client for $key found.", + ); + } + } + return _heights[key] ?? await _heightCompleters[key]!.future; } - Future remove({ + Future<(ElectrumClient?, TorPlainNetworkOption?)> remove({ required CryptoCurrency cryptoCurrency, }) async { final key = _keyHelper(cryptoCurrency); @@ -80,7 +116,7 @@ class ClientManager { _heights.remove(key); _heightCompleters.remove(key); - return _map.remove(key); + return (_map.remove(key), _mapNet.remove(key)); } Future closeAll() async { @@ -99,6 +135,7 @@ class ClientManager { _heightCompleters.clear(); _heights.clear(); _subscriptions.clear(); + _mapNet.clear(); _map.clear(); } } diff --git a/lib/electrumx_rpc/electrumx_client.dart b/lib/electrumx_rpc/electrumx_client.dart index bceb03fac..986fad95c 100644 --- a/lib/electrumx_rpc/electrumx_client.dart +++ b/lib/electrumx_rpc/electrumx_client.dart @@ -29,6 +29,7 @@ import '../utilities/amount/amount.dart'; import '../utilities/extensions/impl/string.dart'; import '../utilities/logger.dart'; import '../utilities/prefs.dart'; +import '../utilities/tor_plain_net_option_enum.dart'; import '../wallets/crypto_currency/crypto_currency.dart'; import '../wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'client_manager.dart'; @@ -42,6 +43,10 @@ typedef SparkMempoolData = ({ class WifiOnlyException implements Exception {} +class TorOnlyException implements Exception {} + +class ClearnetOnlyException implements Exception {} + class ElectrumXNode { ElectrumXNode({ required this.address, @@ -49,12 +54,16 @@ class ElectrumXNode { required this.name, required this.id, required this.useSSL, + required this.torEnabled, + required this.clearEnabled, }); final String address; final int port; final String name; final String id; final bool useSSL; + final bool torEnabled; + final bool clearEnabled; factory ElectrumXNode.from(ElectrumXNode node) { return ElectrumXNode( @@ -63,6 +72,8 @@ class ElectrumXNode { name: node.name, id: node.id, useSSL: node.useSSL, + torEnabled: node.torEnabled, + clearEnabled: node.clearEnabled, ); } @@ -74,6 +85,7 @@ class ElectrumXNode { class ElectrumXClient { final CryptoCurrency cryptoCurrency; + final TorPlainNetworkOption netType; String get host => _host; late String _host; @@ -90,6 +102,7 @@ class ElectrumXClient { ElectrumClient? getElectrumAdapter() => ClientManager.sharedInstance.getClient( cryptoCurrency: cryptoCurrency, + netType: netType, ); late Prefs _prefs; @@ -119,6 +132,7 @@ class ElectrumXClient { required int port, required bool useSSL, required Prefs prefs, + required this.netType, required List failovers, required this.cryptoCurrency, this.connectionTimeoutForSpecialCaseJsonRPCClients = @@ -168,6 +182,7 @@ class ElectrumXClient { _electrumAdapterChannel = null; await (await ClientManager.sharedInstance .remove(cryptoCurrency: cryptoCurrency)) + .$1 ?.close(); // Also close any chain height services that are currently open. @@ -193,6 +208,10 @@ class ElectrumXClient { failovers: failovers, globalEventBusForTesting: globalEventBusForTesting, cryptoCurrency: cryptoCurrency, + netType: TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearEnabled, + ), ); } @@ -236,6 +255,18 @@ class ElectrumXClient { // Get the proxy info from the TorService. proxyInfo = _torService.getProxyInfo(); } + + if (netType == TorPlainNetworkOption.clear) { + _electrumAdapterChannel = null; + await ClientManager.sharedInstance + .remove(cryptoCurrency: cryptoCurrency); + } + } else { + if (netType == TorPlainNetworkOption.tor) { + _electrumAdapterChannel = null; + await ClientManager.sharedInstance + .remove(cryptoCurrency: cryptoCurrency); + } } // If the current ElectrumAdapterClient is closed, create a new one. @@ -288,9 +319,10 @@ class ElectrumXClient { ); } - ClientManager.sharedInstance.addClient( + await ClientManager.sharedInstance.addClient( newClient, cryptoCurrency: cryptoCurrency, + netType: netType, ); } @@ -352,6 +384,10 @@ class ElectrumXClient { return response; } on WifiOnlyException { rethrow; + } on ClearnetOnlyException { + rethrow; + } on TorOnlyException { + rethrow; } on SocketException { // likely timed out so then retry if (retries > 0) { @@ -442,6 +478,10 @@ class ElectrumXClient { return response; } on WifiOnlyException { rethrow; + } on ClearnetOnlyException { + rethrow; + } on TorOnlyException { + rethrow; } on SocketException { // likely timed out so then retry if (retries > 0) { @@ -488,10 +528,10 @@ class ElectrumXClient { return await request( requestID: requestID, command: 'server.ping', - requestTimeout: const Duration(seconds: 2), + requestTimeout: const Duration(seconds: 3), retries: retryCount, ).timeout( - const Duration(seconds: 2), + const Duration(seconds: 3), onTimeout: () { Logging.instance.log( "ElectrumxClient.ping timed out with retryCount=$retryCount, host=$_host", diff --git a/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart b/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart new file mode 100644 index 000000000..38fe0638b --- /dev/null +++ b/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart @@ -0,0 +1 @@ +class NodeTorMismatchConfigException implements Exception {} diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 7888635b7..6480c52f0 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -18,14 +18,17 @@ import 'package:uuid/uuid.dart'; import '../../../../models/node_model.dart'; import '../../../../notifications/show_flush_bar.dart'; +import '../../../../providers/global/active_wallet_provider.dart'; import '../../../../providers/global/secure_store_provider.dart'; import '../../../../providers/providers.dart'; import '../../../../themes/stack_colors.dart'; import '../../../../utilities/assets.dart'; import '../../../../utilities/constants.dart'; +import '../../../../utilities/enums/sync_type_enum.dart'; import '../../../../utilities/flutter_secure_storage_interface.dart'; import '../../../../utilities/test_node_connection.dart'; import '../../../../utilities/text_styles.dart'; +import '../../../../utilities/tor_plain_net_option_enum.dart'; import '../../../../utilities/util.dart'; import '../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../wallets/crypto_currency/intermediate/cryptonote_currency.dart'; @@ -229,6 +232,11 @@ class _AddEditNodeViewState extends ConsumerState { } } + final torEnabled = formData.netOption == TorPlainNetworkOption.tor || + formData.netOption == TorPlainNetworkOption.both; + final plainEnabled = formData.netOption == TorPlainNetworkOption.clear || + formData.netOption == TorPlainNetworkOption.both; + switch (viewType) { case AddEditNodeViewType.add: final NodeModel node = NodeModel( @@ -243,6 +251,8 @@ class _AddEditNodeViewState extends ConsumerState { isFailover: formData.isFailover!, trusted: formData.trusted!, isDown: false, + torEnabled: torEnabled, + plainEnabled: plainEnabled, ); await ref.read(nodeServiceChangeNotifierProvider).add( @@ -250,6 +260,7 @@ class _AddEditNodeViewState extends ConsumerState { formData.password, true, ); + await _notifyWalletsOfUpdatedNode(); if (mounted) { Navigator.of(context) .popUntil(ModalRoute.withName(widget.routeOnSuccessOrDelete)); @@ -268,6 +279,8 @@ class _AddEditNodeViewState extends ConsumerState { isFailover: formData.isFailover!, trusted: formData.trusted!, isDown: false, + torEnabled: torEnabled, + plainEnabled: plainEnabled, ); await ref.read(nodeServiceChangeNotifierProvider).add( @@ -275,6 +288,7 @@ class _AddEditNodeViewState extends ConsumerState { formData.password, true, ); + await _notifyWalletsOfUpdatedNode(); if (mounted) { Navigator.of(context) .popUntil(ModalRoute.withName(widget.routeOnSuccessOrDelete)); @@ -283,6 +297,39 @@ class _AddEditNodeViewState extends ConsumerState { } } + Future _notifyWalletsOfUpdatedNode() async { + final wallets = + ref.read(pWallets).wallets.where((e) => e.info.coin == widget.coin); + final prefs = ref.read(prefsChangeNotifierProvider); + + switch (prefs.syncType) { + case SyncingType.currentWalletOnly: + for (final wallet in wallets) { + if (ref.read(currentWalletIdProvider) == wallet.walletId) { + unawaited(wallet.updateNode().then((value) => wallet.refresh())); + } else { + unawaited(wallet.updateNode()); + } + } + break; + case SyncingType.selectedWalletsAtStartup: + final List walletIdsToSync = prefs.walletIdsSyncOnStartup; + for (final wallet in wallets) { + if (walletIdsToSync.contains(wallet.walletId)) { + unawaited(wallet.updateNode().then((value) => wallet.refresh())); + } else { + unawaited(wallet.updateNode()); + } + } + break; + case SyncingType.allWalletsOnStartup: + for (final wallet in wallets) { + unawaited(wallet.updateNode().then((value) => wallet.refresh())); + } + break; + } + } + @override void initState() { isDesktop = Util.isDesktop; @@ -568,10 +615,11 @@ class NodeFormData { String? name, host, login, password; int? port; bool? useSSL, isFailover, trusted; + TorPlainNetworkOption? netOption; @override String toString() { - return "{ name: $name, host: $host, port: $port, useSSL: $useSSL, trusted: $trusted }"; + return "{ name: $name, host: $host, port: $port, useSSL: $useSSL, trusted: $trusted, netOption: $netOption }"; } } @@ -615,6 +663,7 @@ class _NodeFormState extends ConsumerState { bool _trusted = false; int? port; late bool enableSSLCheckbox; + late TorPlainNetworkOption netOption; late final bool enableAuthFields; @@ -672,6 +721,7 @@ class _NodeFormState extends ConsumerState { ref.read(nodeFormDataProvider).useSSL = _useSSL; ref.read(nodeFormDataProvider).isFailover = _isFailover; ref.read(nodeFormDataProvider).trusted = _trusted; + ref.read(nodeFormDataProvider).netOption = netOption; } @override @@ -704,6 +754,15 @@ class _NodeFormState extends ConsumerState { _useSSL = node.useSSL; _isFailover = node.isFailover; _trusted = node.trusted ?? false; + + if (node.torEnabled && !node.plainEnabled) { + netOption = TorPlainNetworkOption.tor; + } else if (node.plainEnabled && !node.torEnabled) { + netOption = TorPlainNetworkOption.clear; + } else { + netOption = TorPlainNetworkOption.both; + } + if (widget.coin is Epiccash) { enableSSLCheckbox = !node.host.startsWith("http"); } else { @@ -716,6 +775,7 @@ class _NodeFormState extends ConsumerState { }); } else { enableSSLCheckbox = true; + netOption = TorPlainNetworkOption.both; // default to port 3413 // _portController.text = "3413"; } @@ -1168,7 +1228,139 @@ class _NodeFormState extends ConsumerState { ), ], ), + const SizedBox( + height: 16, + ), + Row( + children: [ + RadioTextButton( + label: "Only TOR traffic", + enabled: !widget.readOnly, + value: TorPlainNetworkOption.tor, + groupValue: netOption, + onChanged: (value) { + if (!widget.readOnly) { + setState( + () => netOption = TorPlainNetworkOption.tor, + ); + _updateState(); + } + }, + ), + ], + ), + const SizedBox( + height: 8, + ), + Row( + children: [ + RadioTextButton( + label: "Only non-TOR traffic", + enabled: !widget.readOnly, + value: TorPlainNetworkOption.clear, + groupValue: netOption, + onChanged: (value) { + if (!widget.readOnly) { + setState( + () => netOption = TorPlainNetworkOption.clear, + ); + _updateState(); + } + }, + ), + ], + ), + const SizedBox( + height: 8, + ), + Row( + children: [ + RadioTextButton( + label: "Allow both", + enabled: !widget.readOnly, + value: TorPlainNetworkOption.both, + groupValue: netOption, + onChanged: (value) { + if (!widget.readOnly) { + setState( + () => netOption = TorPlainNetworkOption.both, + ); + _updateState(); + } + }, + ), + ], + ), ], ); } } + +class RadioTextButton extends StatelessWidget { + const RadioTextButton({ + super.key, + required this.value, + required this.label, + required this.groupValue, + required this.onChanged, + this.enabled = true, + }); + + final T value; + final String label; + final T groupValue; + final bool enabled; + final void Function(T) onChanged; + + @override + Widget build(BuildContext context) { + return ConditionalParent( + condition: Util.isDesktop, + builder: (child) => MouseRegion( + cursor: SystemMouseCursors.click, + child: child, + ), + child: GestureDetector( + onTap: () { + if (value != groupValue) { + onChanged.call(value); + } + }, + child: Container( + color: Colors.transparent, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 20, + height: 20, + child: Radio( + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, + value: value, + groupValue: groupValue, + onChanged: !enabled + ? null + : (_) { + if (value != groupValue) { + onChanged.call(value); + } + }, + ), + ), + const SizedBox( + width: 14, + ), + Text( + label, + style: STextStyles.w500_14(context), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart index da7f0cfcc..3b83d5690 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart @@ -13,15 +13,19 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:tuple/tuple.dart'; + import '../../../../notifications/show_flush_bar.dart'; -import 'add_edit_node_view.dart'; +import '../../../../providers/global/active_wallet_provider.dart'; import '../../../../providers/global/secure_store_provider.dart'; import '../../../../providers/providers.dart'; import '../../../../themes/stack_colors.dart'; import '../../../../utilities/assets.dart'; +import '../../../../utilities/enums/sync_type_enum.dart'; import '../../../../utilities/flutter_secure_storage_interface.dart'; import '../../../../utilities/test_node_connection.dart'; import '../../../../utilities/text_styles.dart'; +import '../../../../utilities/tor_plain_net_option_enum.dart'; import '../../../../utilities/util.dart'; import '../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../widgets/background.dart'; @@ -31,7 +35,7 @@ import '../../../../widgets/desktop/delete_button.dart'; import '../../../../widgets/desktop/desktop_dialog.dart'; import '../../../../widgets/desktop/primary_button.dart'; import '../../../../widgets/desktop/secondary_button.dart'; -import 'package:tuple/tuple.dart'; +import 'add_edit_node_view.dart'; class NodeDetailsView extends ConsumerStatefulWidget { const NodeDetailsView({ @@ -59,6 +63,39 @@ class _NodeDetailsViewState extends ConsumerState { bool _desktopReadOnly = true; + Future _notifyWalletsOfUpdatedNode() async { + final wallets = + ref.read(pWallets).wallets.where((e) => e.info.coin == widget.coin); + final prefs = ref.read(prefsChangeNotifierProvider); + + switch (prefs.syncType) { + case SyncingType.currentWalletOnly: + for (final wallet in wallets) { + if (ref.read(currentWalletIdProvider) == wallet.walletId) { + unawaited(wallet.updateNode().then((value) => wallet.refresh())); + } else { + unawaited(wallet.updateNode()); + } + } + break; + case SyncingType.selectedWalletsAtStartup: + final List walletIdsToSync = prefs.walletIdsSyncOnStartup; + for (final wallet in wallets) { + if (walletIdsToSync.contains(wallet.walletId)) { + unawaited(wallet.updateNode().then((value) => wallet.refresh())); + } else { + unawaited(wallet.updateNode()); + } + } + break; + case SyncingType.allWalletsOnStartup: + for (final wallet in wallets) { + unawaited(wallet.updateNode().then((value) => wallet.refresh())); + } + break; + } + } + @override initState() { secureStore = ref.read(secureStoreProvider); @@ -265,6 +302,16 @@ class _NodeDetailsViewState extends ConsumerState { .read(nodeServiceChangeNotifierProvider) .getNodeById(id: nodeId)!; + final TorPlainNetworkOption netOption; + if (ref.read(nodeFormDataProvider).netOption != null) { + netOption = ref.read(nodeFormDataProvider).netOption!; + } else { + netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.plainEnabled, + ); + } + final nodeFormData = NodeFormData() ..useSSL = node.useSSL ..trusted = node.trusted @@ -272,7 +319,8 @@ class _NodeDetailsViewState extends ConsumerState { ..host = node.host ..login = node.loginName ..port = node.port - ..isFailover = node.isFailover; + ..isFailover = node.isFailover + ..netOption = netOption; nodeFormData.password = await node.getPassword( ref.read(secureStoreProvider), ); @@ -338,6 +386,16 @@ class _NodeDetailsViewState extends ConsumerState { loginName: ref.read(nodeFormDataProvider).login, isFailover: ref.read(nodeFormDataProvider).isFailover, + torEnabled: + ref.read(nodeFormDataProvider).netOption == + TorPlainNetworkOption.tor || + ref.read(nodeFormDataProvider).netOption == + TorPlainNetworkOption.both, + plainEnabled: + ref.read(nodeFormDataProvider).netOption == + TorPlainNetworkOption.clear || + ref.read(nodeFormDataProvider).netOption == + TorPlainNetworkOption.both, ); await ref @@ -347,6 +405,7 @@ class _NodeDetailsViewState extends ConsumerState { ref.read(nodeFormDataProvider).password, true, ); + await _notifyWalletsOfUpdatedNode(); } }, ) diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index 306cb5d6a..a0f5c8065 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -59,6 +59,8 @@ class NodeService extends ChangeNotifier { enabled: savedNode.enabled, isFailover: savedNode.isFailover, trusted: savedNode.trusted, + torEnabled: savedNode.torEnabled, + plainEnabled: savedNode.plainEnabled, ), ); } @@ -75,6 +77,8 @@ class NodeService extends ChangeNotifier { enabled: primaryNode.enabled, isFailover: primaryNode.isFailover, trusted: primaryNode.trusted, + torEnabled: primaryNode.torEnabled, + plainEnabled: primaryNode.plainEnabled, ), ); } diff --git a/lib/services/notifications_service.dart b/lib/services/notifications_service.dart index 5df8cad4d..3748791d9 100644 --- a/lib/services/notifications_service.dart +++ b/lib/services/notifications_service.dart @@ -11,23 +11,23 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; + import '../app_config.dart'; import '../db/hive/db.dart'; import '../electrumx_rpc/electrumx_client.dart'; import '../exceptions/electrumx/no_such_transaction.dart'; import '../models/exchange/response_objects/trade.dart'; import '../models/notification_model.dart'; +import '../utilities/logger.dart'; +import '../utilities/prefs.dart'; +import '../wallets/crypto_currency/crypto_currency.dart'; +import '../wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; +import 'exchange/exchange.dart'; import 'exchange/exchange_response.dart'; import 'node_service.dart'; import 'notifications_api.dart'; import 'trade_service.dart'; import 'wallets.dart'; -import '../utilities/logger.dart'; -import '../utilities/prefs.dart'; -import '../wallets/crypto_currency/crypto_currency.dart'; -import '../wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; - -import 'exchange/exchange.dart'; class NotificationsService extends ChangeNotifier { late NodeService nodeService; @@ -136,12 +136,26 @@ class NotificationsService extends ChangeNotifier { final node = nodeService.getPrimaryNodeFor(currency: coin); if (node != null) { if (wallet is ElectrumXInterface) { + if (prefs.useTor) { + if (node.plainEnabled && !node.torEnabled) { + // just ignore I guess?? + return; + } + } else { + if (node.torEnabled && !node.plainEnabled) { + // just ignore I guess?? + return; + } + } + final eNode = ElectrumXNode( address: node.host, port: node.port, name: node.name, id: node.id, useSSL: node.useSSL, + torEnabled: node.torEnabled, + clearEnabled: node.plainEnabled, ); final failovers = nodeService .failoverNodesFor(currency: coin) @@ -152,6 +166,8 @@ class NotificationsService extends ChangeNotifier { name: e.name, id: e.id, useSSL: e.useSSL, + torEnabled: node.torEnabled, + clearEnabled: node.plainEnabled, ), ) .toList(); diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart index 458e04e4d..127702b14 100644 --- a/lib/utilities/test_node_connection.dart +++ b/lib/utilities/test_node_connection.dart @@ -5,7 +5,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:on_chain/ada/ada.dart'; -import 'package:on_chain/ada/src/provider/provider/provider.dart'; import 'package:socks5_proxy/socks.dart'; import '../networking/http.dart'; @@ -25,6 +24,7 @@ import 'test_epic_box_connection.dart'; import 'test_eth_node_connection.dart'; import 'test_monero_node_connection.dart'; import 'test_stellar_node_connection.dart'; +import 'tor_plain_net_option_enum.dart'; Future _xmrHelper( NodeFormData nodeFormData, @@ -45,7 +45,6 @@ Future _xmrHelper( final uriString = "${uri.scheme}://${uri.host}:${port ?? 0}$path"; - if (proxyInfo == null && uri.host.endsWith(".onion")) { return false; } @@ -93,6 +92,24 @@ Future testNodeConnection({ }) async { final formData = nodeFormData; + if (ref.read(prefsChangeNotifierProvider).useTor) { + if (formData.netOption! == TorPlainNetworkOption.clear) { + Logging.instance.log( + "This node is configured for non-TOR only but TOR is enabled", + level: LogLevel.Warning, + ); + return false; + } + } else { + if (formData.netOption! == TorPlainNetworkOption.tor) { + Logging.instance.log( + "This node is configured for TOR only but TOR is disabled", + level: LogLevel.Warning, + ); + return false; + } + } + bool testPassed = false; switch (cryptoCurrency) { @@ -111,9 +128,7 @@ Future testNodeConnection({ case CryptonoteCurrency(): try { - final proxyInfo = ref - .read(prefsChangeNotifierProvider) - .useTor + final proxyInfo = ref.read(prefsChangeNotifierProvider).useTor ? ref.read(pTorService).getProxyInfo() : null; @@ -186,7 +201,7 @@ Future testNodeConnection({ case Stellar(): try { testPassed = - await testStellarNodeConnection(formData.host!, formData.port!); + await testStellarNodeConnection(formData.host!, formData.port!); } catch (_) {} break; @@ -202,9 +217,7 @@ Future testNodeConnection({ "action": "version", }, ), - proxyInfo: ref - .read(prefsChangeNotifierProvider) - .useTor + proxyInfo: ref.read(prefsChangeNotifierProvider).useTor ? ref.read(pTorService).getProxyInfo() : null, ); @@ -245,9 +258,7 @@ Future testNodeConnection({ case Cardano(): try { final client = HttpClient(); - if (ref - .read(prefsChangeNotifierProvider) - .useTor) { + if (ref.read(prefsChangeNotifierProvider).useTor) { final proxyInfo = TorService.sharedInstance.getProxyInfo(); final proxySettings = ProxySettings( proxyInfo.host, diff --git a/lib/utilities/tor_plain_net_option_enum.dart b/lib/utilities/tor_plain_net_option_enum.dart new file mode 100644 index 000000000..26b5604d9 --- /dev/null +++ b/lib/utilities/tor_plain_net_option_enum.dart @@ -0,0 +1,23 @@ +enum TorPlainNetworkOption { + tor, + clear, + both; + + bool allowsTor() => this == tor || this == both; + bool allowsClear() => this == clear || this == both; + + static TorPlainNetworkOption fromNodeData( + bool torEnabled, + bool clearEnabled, + ) { + if (clearEnabled && torEnabled) { + return TorPlainNetworkOption.both; + } else if (torEnabled) { + return TorPlainNetworkOption.tor; + } else if (clearEnabled) { + return TorPlainNetworkOption.clear; + } else { + return TorPlainNetworkOption.both; + } + } +} diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart index 9d4a4b739..aa1bab4e7 100644 --- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart +++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart @@ -1338,6 +1338,8 @@ class BitcoinFrostWallet extends Wallet name: node.name, useSSL: node.useSSL, id: node.id, + torEnabled: node.torEnabled, + clearEnabled: node.plainEnabled, ); } @@ -1352,6 +1354,8 @@ class BitcoinFrostWallet extends Wallet name: e.name, id: e.id, useSSL: e.useSSL, + torEnabled: e.torEnabled, + clearEnabled: e.plainEnabled, ), ) .toList(); diff --git a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart index f1ac98c80..e83ba744b 100644 --- a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart @@ -467,7 +467,22 @@ abstract class LibMoneroWallet final host = Uri.parse(node.host).host; ({InternetAddress host, int port})? proxy; if (prefs.useTor) { + if (node.plainEnabled && !node.torEnabled) { + libMoneroWallet?.stopAutoSaving(); + libMoneroWallet?.stopListeners(); + libMoneroWallet?.stopSyncing(); + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + throw Exception("TOR - clearnet mismatch"); + } proxy = TorService.sharedInstance.getProxyInfo(); + } else { + if (!node.plainEnabled && node.torEnabled) { + libMoneroWallet?.stopAutoSaving(); + libMoneroWallet?.stopListeners(); + libMoneroWallet?.stopSyncing(); + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + throw Exception("TOR - clearnet mismatch"); + } } _setSyncStatus(lib_monero_compat.ConnectingSyncStatus()); @@ -495,6 +510,9 @@ abstract class LibMoneroWallet proxy == null ? null : "${proxy.host.address}:${proxy.port}", ); } + libMoneroWallet?.startSyncing(); + libMoneroWallet?.startListeners(); + libMoneroWallet?.startAutoSaving(); _setSyncStatus(lib_monero_compat.ConnectedSyncStatus()); } catch (e, s) { @@ -1020,6 +1038,26 @@ abstract class LibMoneroWallet return; } + final node = getCurrentNode(); + + if (prefs.useTor) { + if (node.plainEnabled && !node.torEnabled) { + libMoneroWallet?.stopAutoSaving(); + libMoneroWallet?.stopListeners(); + libMoneroWallet?.stopSyncing(); + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + throw Exception("TOR - clearnet mismatch"); + } + } else { + if (!node.plainEnabled && node.torEnabled) { + libMoneroWallet?.stopAutoSaving(); + libMoneroWallet?.stopListeners(); + libMoneroWallet?.stopSyncing(); + _setSyncStatus(lib_monero_compat.FailedSyncStatus()); + throw Exception("TOR - clearnet mismatch"); + } + } + // this acquire should be almost instant due to above check. // Slight possibility of race but should be irrelevant await refreshMutex.acquire(); diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart index 62f0e2255..e764dee54 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart @@ -906,6 +906,8 @@ mixin ElectrumXInterface name: node.name, useSSL: node.useSSL, id: node.id, + torEnabled: node.torEnabled, + clearEnabled: node.plainEnabled, ); } @@ -919,6 +921,8 @@ mixin ElectrumXInterface name: e.name, id: e.id, useSSL: e.useSSL, + torEnabled: e.torEnabled, + clearEnabled: e.plainEnabled, ), ) .toList(); diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart index b8a6f9cad..6099ff242 100644 --- a/lib/widgets/node_card.dart +++ b/lib/widgets/node_card.dart @@ -13,6 +13,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:tuple/tuple.dart'; + import '../notifications/show_flush_bar.dart'; import '../pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart'; import '../pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart'; @@ -26,6 +28,7 @@ import '../utilities/default_nodes.dart'; import '../utilities/enums/sync_type_enum.dart'; import '../utilities/test_node_connection.dart'; import '../utilities/text_styles.dart'; +import '../utilities/tor_plain_net_option_enum.dart'; import '../utilities/util.dart'; import '../wallets/crypto_currency/crypto_currency.dart'; import 'conditional_parent.dart'; @@ -33,7 +36,6 @@ import 'custom_buttons/blue_text_button.dart'; import 'expandable.dart'; import 'node_options_sheet.dart'; import 'rounded_white_container.dart'; -import 'package:tuple/tuple.dart'; class NodeCard extends ConsumerStatefulWidget { const NodeCard({ @@ -165,6 +167,15 @@ class _NodeCardState extends ConsumerState { text: "Connect", enabled: _status == "Disconnected", onTap: () async { + final TorPlainNetworkOption netOption; + if (_node.torEnabled && !_node.plainEnabled) { + netOption = TorPlainNetworkOption.tor; + } else if (_node.plainEnabled && !_node.torEnabled) { + netOption = TorPlainNetworkOption.clear; + } else { + netOption = TorPlainNetworkOption.both; + } + final nodeFormData = NodeFormData() ..useSSL = _node.useSSL ..trusted = _node.trusted @@ -172,6 +183,7 @@ class _NodeCardState extends ConsumerState { ..host = _node.host ..login = _node.loginName ..port = _node.port + ..netOption = netOption ..isFailover = _node.isFailover; nodeFormData.password = await _node.getPassword( ref.read(secureStoreProvider), diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart index 553f60c05..8273401b1 100644 --- a/lib/widgets/node_options_sheet.dart +++ b/lib/widgets/node_options_sheet.dart @@ -27,6 +27,7 @@ import '../utilities/default_nodes.dart'; import '../utilities/enums/sync_type_enum.dart'; import '../utilities/test_node_connection.dart'; import '../utilities/text_styles.dart'; +import '../utilities/tor_plain_net_option_enum.dart'; import '../wallets/crypto_currency/crypto_currency.dart'; import 'rounded_white_container.dart'; @@ -256,6 +257,15 @@ class NodeOptionsSheet extends ConsumerWidget { ref.read(secureStoreProvider), ); if (context.mounted) { + final TorPlainNetworkOption netOption; + if (node.torEnabled && !node.plainEnabled) { + netOption = TorPlainNetworkOption.tor; + } else if (node.plainEnabled && + !node.torEnabled) { + netOption = TorPlainNetworkOption.clear; + } else { + netOption = TorPlainNetworkOption.both; + } final canConnect = await testNodeConnection( context: context, nodeFormData: NodeFormData() @@ -266,6 +276,7 @@ class NodeOptionsSheet extends ConsumerWidget { ..port = node.port ..useSSL = node.useSSL ..isFailover = node.isFailover + ..netOption = netOption ..trusted = node.trusted, cryptoCurrency: coin, ref: ref, diff --git a/test/cached_electrumx_test.dart b/test/cached_electrumx_test.dart index 26213175f..2d5b9b418 100644 --- a/test/cached_electrumx_test.dart +++ b/test/cached_electrumx_test.dart @@ -168,6 +168,8 @@ void main() { name: "some name", id: "some ID", useSSL: true, + torEnabled: true, + clearEnabled: true, ); final client = diff --git a/test/services/node_service_test.dart b/test/services/node_service_test.dart index 5b4f1e635..d5ce1b84c 100644 --- a/test/services/node_service_test.dart +++ b/test/services/node_service_test.dart @@ -1,10 +1,10 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:hive/hive.dart'; import 'package:hive_test/hive_test.dart'; +import 'package:stackwallet/app_config.dart'; import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/app_config.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; @@ -48,6 +48,8 @@ void main() { coinName: "bitcoin", isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); await service.setPrimaryNodeFor( coin: Bitcoin(CryptoCurrencyNetwork.main), @@ -129,6 +131,8 @@ void main() { coinName: "bitcoin", isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); final nodeB = NodeModel( host: "host2", @@ -140,6 +144,8 @@ void main() { coinName: "monero", isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); final nodeC = NodeModel( host: "host3", @@ -151,6 +157,8 @@ void main() { coinName: "epicCash", isFailover: true, isDown: false, + torEnabled: true, + plainEnabled: true, ); setUp(() async { diff --git a/test/widget_tests/node_card_test.dart b/test/widget_tests/node_card_test.dart index 45c0dbe12..374991fab 100644 --- a/test/widget_tests/node_card_test.dart +++ b/test/widget_tests/node_card_test.dart @@ -37,6 +37,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -51,6 +53,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -112,6 +116,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -126,6 +132,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -188,6 +196,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -202,6 +212,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); diff --git a/test/widget_tests/node_options_sheet_test.dart b/test/widget_tests/node_options_sheet_test.dart index c289b29b5..6070e2473 100644 --- a/test/widget_tests/node_options_sheet_test.dart +++ b/test/widget_tests/node_options_sheet_test.dart @@ -25,17 +25,20 @@ void main() { final mockPrefs = MockPrefs(); final mockNodeService = MockNodeService(); - when(mockNodeService.getNodeById(id: "node id")).thenAnswer( - (realInvocation) => NodeModel( - host: "127.0.0.1", - port: 2000, - name: "Some other name", - id: "node id", - useSSL: true, - enabled: true, - coinName: "Bitcoin", - isFailover: false, - isDown: false)); + when(mockNodeService.getNodeById(id: "node id")) + .thenAnswer((realInvocation) => NodeModel( + host: "127.0.0.1", + port: 2000, + name: "Some other name", + id: "node id", + useSSL: true, + enabled: true, + coinName: "Bitcoin", + isFailover: false, + isDown: false, + torEnabled: true, + plainEnabled: true, + )); when(mockNodeService.getPrimaryNodeFor( currency: Bitcoin(CryptoCurrencyNetwork.main))) @@ -48,6 +51,8 @@ void main() { enabled: true, coinName: "Bitcoin", isFailover: false, + torEnabled: true, + plainEnabled: true, isDown: false)); await tester.pumpWidget( @@ -109,6 +114,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -125,6 +132,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -186,6 +195,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); @@ -202,6 +213,8 @@ void main() { coinName: "Bitcoin", isFailover: false, isDown: false, + torEnabled: true, + plainEnabled: true, ), ); From 4197ff40f45a96c6b9bbe590ab5fc7e7d3310bc0 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 09:18:35 -0600 Subject: [PATCH 03/14] consistent variable naming --- lib/db/db_version_migration.dart | 4 ++-- lib/electrumx_rpc/electrumx_client.dart | 8 ++++---- lib/models/node_model.dart | 10 +++++----- lib/models/type_adaptors/node_model.g.dart | 4 ++-- .../manage_nodes_views/add_edit_node_view.dart | 8 ++++---- .../manage_nodes_views/node_details_view.dart | 4 ++-- .../helpers/restore_create_backup.dart | 2 +- lib/services/node_service.dart | 6 +++--- lib/services/notifications_service.dart | 8 ++++---- lib/wallets/crypto_currency/coins/banano.dart | 2 +- lib/wallets/crypto_currency/coins/bitcoin.dart | 6 +++--- lib/wallets/crypto_currency/coins/bitcoin_frost.dart | 6 +++--- lib/wallets/crypto_currency/coins/bitcoincash.dart | 4 ++-- lib/wallets/crypto_currency/coins/cardano.dart | 2 +- lib/wallets/crypto_currency/coins/dash.dart | 2 +- lib/wallets/crypto_currency/coins/dogecoin.dart | 4 ++-- lib/wallets/crypto_currency/coins/ecash.dart | 2 +- lib/wallets/crypto_currency/coins/epiccash.dart | 2 +- lib/wallets/crypto_currency/coins/ethereum.dart | 2 +- lib/wallets/crypto_currency/coins/firo.dart | 4 ++-- lib/wallets/crypto_currency/coins/litecoin.dart | 4 ++-- lib/wallets/crypto_currency/coins/monero.dart | 2 +- lib/wallets/crypto_currency/coins/namecoin.dart | 2 +- lib/wallets/crypto_currency/coins/nano.dart | 2 +- lib/wallets/crypto_currency/coins/particl.dart | 2 +- lib/wallets/crypto_currency/coins/peercoin.dart | 4 ++-- lib/wallets/crypto_currency/coins/solana.dart | 2 +- lib/wallets/crypto_currency/coins/stellar.dart | 4 ++-- lib/wallets/crypto_currency/coins/tezos.dart | 2 +- lib/wallets/crypto_currency/coins/wownero.dart | 2 +- lib/wallets/wallet/impl/bitcoin_frost_wallet.dart | 4 ++-- .../wallet/intermediate/lib_monero_wallet.dart | 8 ++++---- .../wallet_mixin_interfaces/electrumx_interface.dart | 4 ++-- lib/widgets/node_card.dart | 4 ++-- lib/widgets/node_options_sheet.dart | 5 +++-- test/cached_electrumx_test.dart | 2 +- test/services/node_service_test.dart | 8 ++++---- test/widget_tests/node_card_test.dart | 12 ++++++------ test/widget_tests/node_options_sheet_test.dart | 12 ++++++------ 39 files changed, 88 insertions(+), 87 deletions(-) diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart index 606996a7f..fcf632669 100644 --- a/lib/db/db_version_migration.dart +++ b/lib/db/db_version_migration.dart @@ -78,7 +78,7 @@ class DbVersionMigrator with WalletDB { id: e.id, useSSL: e.useSSL, torEnabled: e.torEnabled, - clearEnabled: e.plainEnabled, + clearnetEnabled: e.clearnetEnabled, ), ) .toList(); @@ -91,7 +91,7 @@ class DbVersionMigrator with WalletDB { id: node.id, useSSL: node.useSSL, torEnabled: node.torEnabled, - clearEnabled: node.plainEnabled, + clearnetEnabled: node.clearnetEnabled, ), prefs: prefs, failovers: failovers, diff --git a/lib/electrumx_rpc/electrumx_client.dart b/lib/electrumx_rpc/electrumx_client.dart index 986fad95c..dff2b68fd 100644 --- a/lib/electrumx_rpc/electrumx_client.dart +++ b/lib/electrumx_rpc/electrumx_client.dart @@ -55,7 +55,7 @@ class ElectrumXNode { required this.id, required this.useSSL, required this.torEnabled, - required this.clearEnabled, + required this.clearnetEnabled, }); final String address; final int port; @@ -63,7 +63,7 @@ class ElectrumXNode { final String id; final bool useSSL; final bool torEnabled; - final bool clearEnabled; + final bool clearnetEnabled; factory ElectrumXNode.from(ElectrumXNode node) { return ElectrumXNode( @@ -73,7 +73,7 @@ class ElectrumXNode { id: node.id, useSSL: node.useSSL, torEnabled: node.torEnabled, - clearEnabled: node.clearEnabled, + clearnetEnabled: node.clearnetEnabled, ); } @@ -210,7 +210,7 @@ class ElectrumXClient { cryptoCurrency: cryptoCurrency, netType: TorPlainNetworkOption.fromNodeData( node.torEnabled, - node.clearEnabled, + node.clearnetEnabled, ), ); } diff --git a/lib/models/node_model.dart b/lib/models/node_model.dart index a945a5eb7..e4d3f66b6 100644 --- a/lib/models/node_model.dart +++ b/lib/models/node_model.dart @@ -42,7 +42,7 @@ class NodeModel { // @HiveField(11) final bool torEnabled; // @HiveField(12) - final bool plainEnabled; + final bool clearnetEnabled; NodeModel({ required this.host, @@ -55,7 +55,7 @@ class NodeModel { required this.isFailover, required this.isDown, required this.torEnabled, - required this.plainEnabled, + required this.clearnetEnabled, this.loginName, this.trusted, }); @@ -72,7 +72,7 @@ class NodeModel { bool? isDown, bool? trusted, bool? torEnabled, - bool? plainEnabled, + bool? clearnetEnabled, }) { return NodeModel( host: host ?? this.host, @@ -87,7 +87,7 @@ class NodeModel { isDown: isDown ?? this.isDown, trusted: trusted ?? this.trusted, torEnabled: torEnabled ?? this.torEnabled, - plainEnabled: plainEnabled ?? this.plainEnabled, + clearnetEnabled: clearnetEnabled ?? this.clearnetEnabled, ); } @@ -110,7 +110,7 @@ class NodeModel { map['isDown'] = isDown; map['trusted'] = trusted; map['torEnabled'] = torEnabled; - map['plainEnabled'] = plainEnabled; + map['clearEnabled'] = clearnetEnabled; return map; } diff --git a/lib/models/type_adaptors/node_model.g.dart b/lib/models/type_adaptors/node_model.g.dart index cc771ba09..32490fd50 100644 --- a/lib/models/type_adaptors/node_model.g.dart +++ b/lib/models/type_adaptors/node_model.g.dart @@ -29,7 +29,7 @@ class NodeModelAdapter extends TypeAdapter { isDown: fields[9] as bool, trusted: fields[10] as bool?, torEnabled: fields[11] as bool? ?? true, - plainEnabled: fields[12] as bool? ?? true, + clearnetEnabled: fields[12] as bool? ?? true, ); } @@ -62,7 +62,7 @@ class NodeModelAdapter extends TypeAdapter { ..writeByte(11) ..write(obj.torEnabled) ..writeByte(12) - ..write(obj.plainEnabled); + ..write(obj.clearnetEnabled); } @override diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 6480c52f0..8695f1ea3 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -252,7 +252,7 @@ class _AddEditNodeViewState extends ConsumerState { trusted: formData.trusted!, isDown: false, torEnabled: torEnabled, - plainEnabled: plainEnabled, + clearnetEnabled: plainEnabled, ); await ref.read(nodeServiceChangeNotifierProvider).add( @@ -280,7 +280,7 @@ class _AddEditNodeViewState extends ConsumerState { trusted: formData.trusted!, isDown: false, torEnabled: torEnabled, - plainEnabled: plainEnabled, + clearnetEnabled: plainEnabled, ); await ref.read(nodeServiceChangeNotifierProvider).add( @@ -755,9 +755,9 @@ class _NodeFormState extends ConsumerState { _isFailover = node.isFailover; _trusted = node.trusted ?? false; - if (node.torEnabled && !node.plainEnabled) { + if (node.torEnabled && !node.clearnetEnabled) { netOption = TorPlainNetworkOption.tor; - } else if (node.plainEnabled && !node.torEnabled) { + } else if (node.clearnetEnabled && !node.torEnabled) { netOption = TorPlainNetworkOption.clear; } else { netOption = TorPlainNetworkOption.both; diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart index 3b83d5690..56c87e5c4 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart @@ -308,7 +308,7 @@ class _NodeDetailsViewState extends ConsumerState { } else { netOption = TorPlainNetworkOption.fromNodeData( node.torEnabled, - node.plainEnabled, + node.clearnetEnabled, ); } @@ -391,7 +391,7 @@ class _NodeDetailsViewState extends ConsumerState { TorPlainNetworkOption.tor || ref.read(nodeFormDataProvider).netOption == TorPlainNetworkOption.both, - plainEnabled: + clearnetEnabled: ref.read(nodeFormDataProvider).netOption == TorPlainNetworkOption.clear || ref.read(nodeFormDataProvider).netOption == diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index 6846686ab..3d06d713d 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -1273,7 +1273,7 @@ abstract class SWB { isFailover: node['isFailover'] as bool, isDown: node['isDown'] as bool, torEnabled: node['torEnabled'] as bool? ?? true, - plainEnabled: node['plainEnabled'] as bool? ?? true, + clearnetEnabled: node['plainEnabled'] as bool? ?? true, ), node["password"] as String?, true, diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index a0f5c8065..e55e2218b 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -60,7 +60,7 @@ class NodeService extends ChangeNotifier { isFailover: savedNode.isFailover, trusted: savedNode.trusted, torEnabled: savedNode.torEnabled, - plainEnabled: savedNode.plainEnabled, + clearnetEnabled: savedNode.clearnetEnabled, ), ); } @@ -78,7 +78,7 @@ class NodeService extends ChangeNotifier { isFailover: primaryNode.isFailover, trusted: primaryNode.trusted, torEnabled: primaryNode.torEnabled, - plainEnabled: primaryNode.plainEnabled, + clearnetEnabled: primaryNode.clearnetEnabled, ), ); } @@ -260,7 +260,7 @@ class NodeService extends ChangeNotifier { isFailover: true, torEnabled: nodeMap["torEnabled"] == "true", isDown: nodeMap["isDown"] == "true", - plainEnabled: nodeMap["plainEnabled"] == "true", + clearnetEnabled: nodeMap["plainEnabled"] == "true", ); final currentNode = getNodeById(id: nodeMap["id"] as String); if (currentNode != null) { diff --git a/lib/services/notifications_service.dart b/lib/services/notifications_service.dart index 3748791d9..065285257 100644 --- a/lib/services/notifications_service.dart +++ b/lib/services/notifications_service.dart @@ -137,12 +137,12 @@ class NotificationsService extends ChangeNotifier { if (node != null) { if (wallet is ElectrumXInterface) { if (prefs.useTor) { - if (node.plainEnabled && !node.torEnabled) { + if (node.clearnetEnabled && !node.torEnabled) { // just ignore I guess?? return; } } else { - if (node.torEnabled && !node.plainEnabled) { + if (node.torEnabled && !node.clearnetEnabled) { // just ignore I guess?? return; } @@ -155,7 +155,7 @@ class NotificationsService extends ChangeNotifier { id: node.id, useSSL: node.useSSL, torEnabled: node.torEnabled, - clearEnabled: node.plainEnabled, + clearnetEnabled: node.clearnetEnabled, ); final failovers = nodeService .failoverNodesFor(currency: coin) @@ -167,7 +167,7 @@ class NotificationsService extends ChangeNotifier { id: e.id, useSSL: e.useSSL, torEnabled: node.torEnabled, - clearEnabled: node.plainEnabled, + clearnetEnabled: node.clearnetEnabled, ), ) .toList(); diff --git a/lib/wallets/crypto_currency/coins/banano.dart b/lib/wallets/crypto_currency/coins/banano.dart index c32adb8f4..8b1e1114b 100644 --- a/lib/wallets/crypto_currency/coins/banano.dart +++ b/lib/wallets/crypto_currency/coins/banano.dart @@ -78,7 +78,7 @@ class Banano extends NanoCurrency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoin.dart b/lib/wallets/crypto_currency/coins/bitcoin.dart index c3dfa4bb8..35a9cf8f0 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin.dart @@ -240,7 +240,7 @@ class Bitcoin extends Bip39HDCurrency isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -255,7 +255,7 @@ class Bitcoin extends Bip39HDCurrency isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test4: @@ -270,7 +270,7 @@ class Bitcoin extends Bip39HDCurrency isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart index 4c75a17b6..d1f22227e 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart @@ -74,7 +74,7 @@ class BitcoinFrost extends FrostCurrency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -89,7 +89,7 @@ class BitcoinFrost extends FrostCurrency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test4: @@ -104,7 +104,7 @@ class BitcoinFrost extends FrostCurrency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/bitcoincash.dart b/lib/wallets/crypto_currency/coins/bitcoincash.dart index 0d60de787..6f6d5e4b5 100644 --- a/lib/wallets/crypto_currency/coins/bitcoincash.dart +++ b/lib/wallets/crypto_currency/coins/bitcoincash.dart @@ -299,7 +299,7 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -314,7 +314,7 @@ class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/cardano.dart b/lib/wallets/crypto_currency/coins/cardano.dart index 1f8fac465..71ea2c372 100644 --- a/lib/wallets/crypto_currency/coins/cardano.dart +++ b/lib/wallets/crypto_currency/coins/cardano.dart @@ -78,7 +78,7 @@ class Cardano extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/dash.dart b/lib/wallets/crypto_currency/coins/dash.dart index dc508c4cc..1a63f1811 100644 --- a/lib/wallets/crypto_currency/coins/dash.dart +++ b/lib/wallets/crypto_currency/coins/dash.dart @@ -190,7 +190,7 @@ class Dash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/dogecoin.dart b/lib/wallets/crypto_currency/coins/dogecoin.dart index ad1899fb6..ce10bc0d7 100644 --- a/lib/wallets/crypto_currency/coins/dogecoin.dart +++ b/lib/wallets/crypto_currency/coins/dogecoin.dart @@ -190,7 +190,7 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -205,7 +205,7 @@ class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/ecash.dart b/lib/wallets/crypto_currency/coins/ecash.dart index 84ae7bfb8..4074b249d 100644 --- a/lib/wallets/crypto_currency/coins/ecash.dart +++ b/lib/wallets/crypto_currency/coins/ecash.dart @@ -290,7 +290,7 @@ class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 2c3dbd437..25fdd6c9c 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -81,7 +81,7 @@ class Epiccash extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/ethereum.dart b/lib/wallets/crypto_currency/coins/ethereum.dart index 32eb754e6..1d7bb53ed 100644 --- a/lib/wallets/crypto_currency/coins/ethereum.dart +++ b/lib/wallets/crypto_currency/coins/ethereum.dart @@ -58,7 +58,7 @@ class Ethereum extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); @override diff --git a/lib/wallets/crypto_currency/coins/firo.dart b/lib/wallets/crypto_currency/coins/firo.dart index bbe83e526..26957600d 100644 --- a/lib/wallets/crypto_currency/coins/firo.dart +++ b/lib/wallets/crypto_currency/coins/firo.dart @@ -232,7 +232,7 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -260,7 +260,7 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/litecoin.dart b/lib/wallets/crypto_currency/coins/litecoin.dart index 46cd1d3ee..91b444f73 100644 --- a/lib/wallets/crypto_currency/coins/litecoin.dart +++ b/lib/wallets/crypto_currency/coins/litecoin.dart @@ -221,7 +221,7 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -236,7 +236,7 @@ class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/monero.dart b/lib/wallets/crypto_currency/coins/monero.dart index ec3d9bae1..7e0347775 100644 --- a/lib/wallets/crypto_currency/coins/monero.dart +++ b/lib/wallets/crypto_currency/coins/monero.dart @@ -73,7 +73,7 @@ class Monero extends CryptonoteCurrency { isDown: false, trusted: true, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/namecoin.dart b/lib/wallets/crypto_currency/coins/namecoin.dart index aab17df11..e390d599e 100644 --- a/lib/wallets/crypto_currency/coins/namecoin.dart +++ b/lib/wallets/crypto_currency/coins/namecoin.dart @@ -103,7 +103,7 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); // case CryptoCurrencyNetwork.test: // TODO: [prio=low] Add testnet support. diff --git a/lib/wallets/crypto_currency/coins/nano.dart b/lib/wallets/crypto_currency/coins/nano.dart index c5d9c9446..0909b8aa8 100644 --- a/lib/wallets/crypto_currency/coins/nano.dart +++ b/lib/wallets/crypto_currency/coins/nano.dart @@ -78,7 +78,7 @@ class Nano extends NanoCurrency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/particl.dart b/lib/wallets/crypto_currency/coins/particl.dart index 80d6104c3..067aae72d 100644 --- a/lib/wallets/crypto_currency/coins/particl.dart +++ b/lib/wallets/crypto_currency/coins/particl.dart @@ -98,7 +98,7 @@ class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); // case CryptoCurrencyNetwork.test: // TODO: [prio=low] Add testnet. diff --git a/lib/wallets/crypto_currency/coins/peercoin.dart b/lib/wallets/crypto_currency/coins/peercoin.dart index 6074d093c..b67b0e1ab 100644 --- a/lib/wallets/crypto_currency/coins/peercoin.dart +++ b/lib/wallets/crypto_currency/coins/peercoin.dart @@ -104,7 +104,7 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -119,7 +119,7 @@ class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/solana.dart b/lib/wallets/crypto_currency/coins/solana.dart index 3bf00c358..1db985c76 100644 --- a/lib/wallets/crypto_currency/coins/solana.dart +++ b/lib/wallets/crypto_currency/coins/solana.dart @@ -56,7 +56,7 @@ class Solana extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: throw Exception("Unsupported network: $network"); diff --git a/lib/wallets/crypto_currency/coins/stellar.dart b/lib/wallets/crypto_currency/coins/stellar.dart index 75fceb211..d799de31b 100644 --- a/lib/wallets/crypto_currency/coins/stellar.dart +++ b/lib/wallets/crypto_currency/coins/stellar.dart @@ -69,7 +69,7 @@ class Stellar extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); case CryptoCurrencyNetwork.test: @@ -84,7 +84,7 @@ class Stellar extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/tezos.dart b/lib/wallets/crypto_currency/coins/tezos.dart index ff9b167c9..0cb8cca0c 100644 --- a/lib/wallets/crypto_currency/coins/tezos.dart +++ b/lib/wallets/crypto_currency/coins/tezos.dart @@ -119,7 +119,7 @@ class Tezos extends Bip39Currency { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/crypto_currency/coins/wownero.dart b/lib/wallets/crypto_currency/coins/wownero.dart index 595966db4..e043fdd7b 100644 --- a/lib/wallets/crypto_currency/coins/wownero.dart +++ b/lib/wallets/crypto_currency/coins/wownero.dart @@ -73,7 +73,7 @@ class Wownero extends CryptonoteCurrency { isDown: false, trusted: true, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); default: diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart index aa1bab4e7..313f1afb6 100644 --- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart +++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart @@ -1339,7 +1339,7 @@ class BitcoinFrostWallet extends Wallet useSSL: node.useSSL, id: node.id, torEnabled: node.torEnabled, - clearEnabled: node.plainEnabled, + clearnetEnabled: node.clearnetEnabled, ); } @@ -1355,7 +1355,7 @@ class BitcoinFrostWallet extends Wallet id: e.id, useSSL: e.useSSL, torEnabled: e.torEnabled, - clearEnabled: e.plainEnabled, + clearnetEnabled: e.clearnetEnabled, ), ) .toList(); diff --git a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart index e83ba744b..597853a62 100644 --- a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart @@ -467,7 +467,7 @@ abstract class LibMoneroWallet final host = Uri.parse(node.host).host; ({InternetAddress host, int port})? proxy; if (prefs.useTor) { - if (node.plainEnabled && !node.torEnabled) { + if (node.clearnetEnabled && !node.torEnabled) { libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); @@ -476,7 +476,7 @@ abstract class LibMoneroWallet } proxy = TorService.sharedInstance.getProxyInfo(); } else { - if (!node.plainEnabled && node.torEnabled) { + if (!node.clearnetEnabled && node.torEnabled) { libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); @@ -1041,7 +1041,7 @@ abstract class LibMoneroWallet final node = getCurrentNode(); if (prefs.useTor) { - if (node.plainEnabled && !node.torEnabled) { + if (node.clearnetEnabled && !node.torEnabled) { libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); @@ -1049,7 +1049,7 @@ abstract class LibMoneroWallet throw Exception("TOR - clearnet mismatch"); } } else { - if (!node.plainEnabled && node.torEnabled) { + if (!node.clearnetEnabled && node.torEnabled) { libMoneroWallet?.stopAutoSaving(); libMoneroWallet?.stopListeners(); libMoneroWallet?.stopSyncing(); diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart index e764dee54..cc49149d9 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart @@ -907,7 +907,7 @@ mixin ElectrumXInterface useSSL: node.useSSL, id: node.id, torEnabled: node.torEnabled, - clearEnabled: node.plainEnabled, + clearnetEnabled: node.clearnetEnabled, ); } @@ -922,7 +922,7 @@ mixin ElectrumXInterface id: e.id, useSSL: e.useSSL, torEnabled: e.torEnabled, - clearEnabled: e.plainEnabled, + clearnetEnabled: e.clearnetEnabled, ), ) .toList(); diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart index 6099ff242..85f16a135 100644 --- a/lib/widgets/node_card.dart +++ b/lib/widgets/node_card.dart @@ -168,9 +168,9 @@ class _NodeCardState extends ConsumerState { enabled: _status == "Disconnected", onTap: () async { final TorPlainNetworkOption netOption; - if (_node.torEnabled && !_node.plainEnabled) { + if (_node.torEnabled && !_node.clearnetEnabled) { netOption = TorPlainNetworkOption.tor; - } else if (_node.plainEnabled && !_node.torEnabled) { + } else if (_node.clearnetEnabled && !_node.torEnabled) { netOption = TorPlainNetworkOption.clear; } else { netOption = TorPlainNetworkOption.both; diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart index 8273401b1..511be2395 100644 --- a/lib/widgets/node_options_sheet.dart +++ b/lib/widgets/node_options_sheet.dart @@ -258,9 +258,10 @@ class NodeOptionsSheet extends ConsumerWidget { ); if (context.mounted) { final TorPlainNetworkOption netOption; - if (node.torEnabled && !node.plainEnabled) { + if (node.torEnabled && + !node.clearnetEnabled) { netOption = TorPlainNetworkOption.tor; - } else if (node.plainEnabled && + } else if (node.clearnetEnabled && !node.torEnabled) { netOption = TorPlainNetworkOption.clear; } else { diff --git a/test/cached_electrumx_test.dart b/test/cached_electrumx_test.dart index 2d5b9b418..370e02972 100644 --- a/test/cached_electrumx_test.dart +++ b/test/cached_electrumx_test.dart @@ -169,7 +169,7 @@ void main() { id: "some ID", useSSL: true, torEnabled: true, - clearEnabled: true, + clearnetEnabled: true, ); final client = diff --git a/test/services/node_service_test.dart b/test/services/node_service_test.dart index d5ce1b84c..cb402deed 100644 --- a/test/services/node_service_test.dart +++ b/test/services/node_service_test.dart @@ -49,7 +49,7 @@ void main() { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); await service.setPrimaryNodeFor( coin: Bitcoin(CryptoCurrencyNetwork.main), @@ -132,7 +132,7 @@ void main() { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); final nodeB = NodeModel( host: "host2", @@ -145,7 +145,7 @@ void main() { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); final nodeC = NodeModel( host: "host3", @@ -158,7 +158,7 @@ void main() { isFailover: true, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ); setUp(() async { diff --git a/test/widget_tests/node_card_test.dart b/test/widget_tests/node_card_test.dart index 374991fab..cc706824c 100644 --- a/test/widget_tests/node_card_test.dart +++ b/test/widget_tests/node_card_test.dart @@ -38,7 +38,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -54,7 +54,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -117,7 +117,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -133,7 +133,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -197,7 +197,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -213,7 +213,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); diff --git a/test/widget_tests/node_options_sheet_test.dart b/test/widget_tests/node_options_sheet_test.dart index 6070e2473..998f6322a 100644 --- a/test/widget_tests/node_options_sheet_test.dart +++ b/test/widget_tests/node_options_sheet_test.dart @@ -37,7 +37,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, )); when(mockNodeService.getPrimaryNodeFor( @@ -52,7 +52,7 @@ void main() { coinName: "Bitcoin", isFailover: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, isDown: false)); await tester.pumpWidget( @@ -115,7 +115,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -133,7 +133,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -196,7 +196,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); @@ -214,7 +214,7 @@ void main() { isFailover: false, isDown: false, torEnabled: true, - plainEnabled: true, + clearnetEnabled: true, ), ); From 7b603cd7f90766a2080497ccc50eede851ab74a0 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 09:44:52 -0600 Subject: [PATCH 04/14] make cardano aware of tor node settings --- .../node_tor_mismatch_config_exception.dart | 9 +- lib/wallets/wallet/impl/cardano_wallet.dart | 187 +++++++++++++----- 2 files changed, 143 insertions(+), 53 deletions(-) diff --git a/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart b/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart index 38fe0638b..d262ac532 100644 --- a/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart +++ b/lib/exceptions/wallet/node_tor_mismatch_config_exception.dart @@ -1 +1,8 @@ -class NodeTorMismatchConfigException implements Exception {} +class NodeTorMismatchConfigException implements Exception { + final String message; + + NodeTorMismatchConfigException({required this.message}); + + @override + String toString() => message; +} diff --git a/lib/wallets/wallet/impl/cardano_wallet.dart b/lib/wallets/wallet/impl/cardano_wallet.dart index bf3abfd31..2b9a8b9bb 100644 --- a/lib/wallets/wallet/impl/cardano_wallet.dart +++ b/lib/wallets/wallet/impl/cardano_wallet.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:io'; import 'package:blockchain_utils/bip/bip/bip44/base/bip44_base.dart'; @@ -7,19 +6,21 @@ import 'package:blockchain_utils/bip/cardano/cip1852/cip1852.dart'; import 'package:blockchain_utils/bip/cardano/cip1852/conf/cip1852_coins.dart'; import 'package:blockchain_utils/bip/cardano/mnemonic/cardano_icarus_seed_generator.dart'; import 'package:blockchain_utils/bip/cardano/shelley/cardano_shelley.dart'; +import 'package:isar/isar.dart'; import 'package:on_chain/ada/ada.dart'; import 'package:socks5_proxy/socks.dart'; +import 'package:tuple/tuple.dart'; + +import '../../../exceptions/wallet/node_tor_mismatch_config_exception.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; -import 'package:tuple/tuple.dart'; import '../../../models/isar/models/blockchain_data/transaction.dart' as isar; import '../../../models/paymint/fee_object_model.dart'; -import '../../../networking/http.dart'; import '../../../services/tor_service.dart'; import '../../../utilities/amount/amount.dart'; -import 'package:isar/isar.dart'; import '../../../utilities/logger.dart'; import '../../../utilities/prefs.dart'; +import '../../../utilities/tor_plain_net_option_enum.dart'; import '../../api/cardano/blockfrost_http_provider.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; @@ -30,7 +31,6 @@ class CardanoWallet extends Bip39Wallet { // Source: https://cips.cardano.org/cip/CIP-1852 static const String _addressDerivationPath = "m/1852'/1815'/0'/0/0"; - static final HTTP _httpClient = HTTP(); BlockforestProvider? blockfrostProvider; @@ -138,12 +138,12 @@ class CardanoWallet extends Bip39Wallet { final fee = params.calculateFee(284).toInt(); return FeeObject( - numberOfBlocksFast: 2, - numberOfBlocksAverage: 2, - numberOfBlocksSlow: 2, - fast: fee, - medium: fee, - slow: fee, + numberOfBlocksFast: 2, + numberOfBlocksAverage: 2, + numberOfBlocksSlow: 2, + fast: fee, + medium: fee, + slow: fee, ); } catch (e, s) { Logging.instance.log( @@ -184,41 +184,59 @@ class CardanoWallet extends Bip39Wallet { totalBalance += BigInt.parse(utxo.amount.first.quantity); } - if (leftAmountForUtxos > BigInt.parse("0") || totalBalance < txData.amount!.raw) { + if (leftAmountForUtxos > BigInt.parse("0") || + totalBalance < txData.amount!.raw) { throw Exception("Insufficient balance"); } - final bip32 = CardanoIcarusBip32.fromSeed(CardanoIcarusSeedGenerator(await getMnemonic()).generate()); + final bip32 = CardanoIcarusBip32.fromSeed( + CardanoIcarusSeedGenerator(await getMnemonic()).generate()); final spend = bip32.derivePath("1852'/1815'/0'/0/0"); final privateKey = AdaPrivateKey.fromBytes(spend.privateKey.raw); // Calculate fees with example tx final exampleFee = ADAHelper.toLovelaces("0.10"); - final change = TransactionOutput(address: ADABaseAddress((await getCurrentReceivingAddress())!.value), amount: Value(coin: totalBalance - (txData.amount!.raw))); + final change = TransactionOutput( + address: ADABaseAddress((await getCurrentReceivingAddress())!.value), + amount: Value(coin: totalBalance - (txData.amount!.raw))); final body = TransactionBody( - inputs: listOfUtxosToBeUsed.map((e) => TransactionInput(transactionId: TransactionHash.fromHex(e.txHash), index: e.outputIndex)).toList(), - outputs: [change, TransactionOutput(address: ADABaseAddress(txData.recipients!.first.address), amount: Value(coin: txData.amount!.raw - exampleFee))], + inputs: listOfUtxosToBeUsed + .map((e) => TransactionInput( + transactionId: TransactionHash.fromHex(e.txHash), + index: e.outputIndex)) + .toList(), + outputs: [ + change, + TransactionOutput( + address: ADABaseAddress(txData.recipients!.first.address), + amount: Value(coin: txData.amount!.raw - exampleFee)) + ], fee: exampleFee, ); final exampleTx = ADATransaction( - body: body, - witnessSet: TransactionWitnessSet(vKeys: [ + body: body, + witnessSet: TransactionWitnessSet( + vKeys: [ privateKey.createSignatureWitness(body.toHash().data), - ],) - ,); - final params = await blockfrostProvider!.request(BlockfrostRequestLatestEpochProtocolParameters()); + ], + ), + ); + final params = await blockfrostProvider! + .request(BlockfrostRequestLatestEpochProtocolParameters()); final fee = params.calculateFee(exampleTx.size); // Check if we are sending all balance, which means no change and only one output for recipient. if (totalBalance == txData.amount!.raw) { - final List newRecipients = [( - address: txData.recipients!.first.address, - amount: Amount( - rawValue: txData.amount!.raw - fee, - fractionDigits: cryptoCurrency.fractionDigits, - ), - isChange: txData.recipients!.first.isChange, - ),]; + final List newRecipients = [ + ( + address: txData.recipients!.first.address, + amount: Amount( + rawValue: txData.amount!.raw - fee, + fractionDigits: cryptoCurrency.fractionDigits, + ), + isChange: txData.recipients!.first.isChange, + ), + ]; return txData.copyWith( fee: Amount( rawValue: fee, @@ -232,8 +250,10 @@ class CardanoWallet extends Bip39Wallet { } // Minimum change in Cardano is 1 ADA and we need to have enough balance for that - if (totalBalance - (txData.amount!.raw + fee) < ADAHelper.toLovelaces("1")) { - throw Exception("Not enough balance for change. By network rules, please either send all balance or leave at least 1 ADA change."); + if (totalBalance - (txData.amount!.raw + fee) < + ADAHelper.toLovelaces("1")) { + throw Exception( + "Not enough balance for change. By network rules, please either send all balance or leave at least 1 ADA change."); } return txData.copyWith( @@ -266,7 +286,6 @@ class CardanoWallet extends Bip39Wallet { ), ); - var leftAmountForUtxos = txData.amount!.raw + txData.fee!.raw; final listOfUtxosToBeUsed = []; var totalBalance = BigInt.zero; @@ -285,31 +304,53 @@ class CardanoWallet extends Bip39Wallet { totalUtxoAmount += BigInt.parse(utxo.amount.first.quantity); } - final bip32 = CardanoIcarusBip32.fromSeed(CardanoIcarusSeedGenerator(await getMnemonic()).generate()); + final bip32 = CardanoIcarusBip32.fromSeed( + CardanoIcarusSeedGenerator(await getMnemonic()).generate()); final spend = bip32.derivePath("1852'/1815'/0'/0/0"); final privateKey = AdaPrivateKey.fromBytes(spend.privateKey.raw); - final change = TransactionOutput(address: ADABaseAddress((await getCurrentReceivingAddress())!.value), amount: Value(coin: totalUtxoAmount - (txData.amount!.raw + txData.fee!.raw))); + final change = TransactionOutput( + address: ADABaseAddress((await getCurrentReceivingAddress())!.value), + amount: Value( + coin: totalUtxoAmount - (txData.amount!.raw + txData.fee!.raw))); List outputs = []; if (totalBalance == (txData.amount!.raw + txData.fee!.raw)) { - outputs = [TransactionOutput(address: ADABaseAddress(txData.recipients!.first.address), amount: Value(coin: txData.amount!.raw))]; + outputs = [ + TransactionOutput( + address: ADABaseAddress(txData.recipients!.first.address), + amount: Value(coin: txData.amount!.raw)) + ]; } else { - outputs = [change, TransactionOutput(address: ADABaseAddress(txData.recipients!.first.address), amount: Value(coin: txData.amount!.raw))]; + outputs = [ + change, + TransactionOutput( + address: ADABaseAddress(txData.recipients!.first.address), + amount: Value(coin: txData.amount!.raw)) + ]; } final body = TransactionBody( - inputs: listOfUtxosToBeUsed.map((e) => TransactionInput(transactionId: TransactionHash.fromHex(e.txHash), index: e.outputIndex)).toList(), + inputs: listOfUtxosToBeUsed + .map((e) => TransactionInput( + transactionId: TransactionHash.fromHex(e.txHash), + index: e.outputIndex)) + .toList(), outputs: outputs, fee: txData.fee!.raw, ); final tx = ADATransaction( - body: body, - witnessSet: TransactionWitnessSet(vKeys: [ + body: body, + witnessSet: TransactionWitnessSet( + vKeys: [ privateKey.createSignatureWitness(body.toHash().data), - ],) - ,); + ], + ), + ); - final sentTx = await blockfrostProvider!.request(BlockfrostRequestSubmitTransaction( - transactionCborBytes: tx.serialize(),),); + final sentTx = await blockfrostProvider!.request( + BlockfrostRequestSubmitTransaction( + transactionCborBytes: tx.serialize(), + ), + ); return txData.copyWith( txid: sentTx, ); @@ -365,11 +406,13 @@ class CardanoWallet extends Bip39Wallet { final balance = Balance( total: Amount( - rawValue: totalBalanceInLovelace, - fractionDigits: cryptoCurrency.fractionDigits,), + rawValue: totalBalanceInLovelace, + fractionDigits: cryptoCurrency.fractionDigits, + ), spendable: Amount( - rawValue: totalBalanceInLovelace, - fractionDigits: cryptoCurrency.fractionDigits,), + rawValue: totalBalanceInLovelace, + fractionDigits: cryptoCurrency.fractionDigits, + ), blockedTotal: Amount( rawValue: BigInt.zero, fractionDigits: cryptoCurrency.fractionDigits, @@ -399,8 +442,9 @@ class CardanoWallet extends Bip39Wallet { ); await info.updateCachedChainHeight( - newHeight: latestBlock.height == null ? 0 : latestBlock.height!, - isar: mainDB.isar,); + newHeight: latestBlock.height == null ? 0 : latestBlock.height!, + isar: mainDB.isar, + ); } catch (e, s) { Logging.instance.log( "Error updating transactions in cardano_wallet.dart: $e\n$s", @@ -473,13 +517,15 @@ class CardanoWallet extends Bip39Wallet { if (txType == isar.TransactionType.incoming) { receiverAddr = currentAddr; for (final output in utxoInfo.outputs) { - if (output.address == currentAddr && output.amount.first.unit == "lovelace") { + if (output.address == currentAddr && + output.amount.first.unit == "lovelace") { amount += int.parse(output.amount.first.quantity); } } } else if (txType == isar.TransactionType.outgoing) { for (final output in utxoInfo.outputs) { - if (output.address != currentAddr && output.amount.first.unit == "lovelace") { + if (output.address != currentAddr && + output.amount.first.unit == "lovelace") { receiverAddr = output.address; amount += int.parse(output.amount.first.quantity); } @@ -532,6 +578,8 @@ class CardanoWallet extends Bip39Wallet { } await mainDB.addNewTransactionData(parsedTxsList, walletId); + } on NodeTorMismatchConfigException { + rethrow; } catch (e, s) { Logging.instance.log( "Error updating transactions in cardano_wallet.dart: $e\n$s", @@ -548,6 +596,7 @@ class CardanoWallet extends Bip39Wallet { Future updateProvider() async { final currentNode = getCurrentNode(); + final client = HttpClient(); if (prefs.useTor) { final proxyInfo = TorService.sharedInstance.getProxyInfo(); @@ -557,11 +606,45 @@ class CardanoWallet extends Bip39Wallet { ); SocksTCPClient.assignToHttpClient(client, [proxySettings]); } - blockfrostProvider = BlockforestProvider( + blockfrostProvider = CustomBlockForestProvider( BlockfrostHttpProvider( url: "${currentNode.host}:${currentNode.port}/", client: client, ), + prefs, + TorPlainNetworkOption.fromNodeData( + currentNode.torEnabled, + currentNode.clearnetEnabled, + ), ); } } + +class CustomBlockForestProvider extends BlockforestProvider { + CustomBlockForestProvider(super.rpc, this.prefs, this.netOption); + + final Prefs prefs; + final TorPlainNetworkOption netOption; + + @override + Future request( + BlockforestRequestParam request, [ + Duration? timeout, + ]) async { + if (prefs.useTor) { + if (netOption == TorPlainNetworkOption.clear) { + throw NodeTorMismatchConfigException( + message: "TOR enabled but node set to clearnet only", + ); + } + } else { + if (netOption == TorPlainNetworkOption.tor) { + throw NodeTorMismatchConfigException( + message: "TOR off but node set to TOR only", + ); + } + } + + return super.request(request, timeout); + } +} From 8a63c42582bde20012bea4c67e4fa48db2637eaf Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:00:56 -0600 Subject: [PATCH 05/14] badly hack tor node settings into epic wallets --- lib/utilities/test_epic_box_connection.dart | 12 ++++++ lib/wallets/wallet/impl/epiccash_wallet.dart | 43 +++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/utilities/test_epic_box_connection.dart b/lib/utilities/test_epic_box_connection.dart index 039fa7ec8..7fff18369 100644 --- a/lib/utilities/test_epic_box_connection.dart +++ b/lib/utilities/test_epic_box_connection.dart @@ -15,6 +15,7 @@ import '../pages/settings_views/global_settings_view/manage_nodes_views/add_edit import '../services/tor_service.dart'; import 'logger.dart'; import 'prefs.dart'; +import 'tor_plain_net_option_enum.dart'; Future _testEpicBoxNodeConnection(Uri uri) async { final HTTP client = HTTP(); @@ -50,6 +51,17 @@ Future testEpicNodeConnection(NodeFormData data) async { if (data.host == null || data.port == null || data.useSSL == null) { return null; } + + if (Prefs.instance.useTor) { + if (data.netOption == TorPlainNetworkOption.clear) { + return null; + } + } else { + if (data.netOption == TorPlainNetworkOption.tor) { + return null; + } + } + const String path_postfix = "/v1/version"; if (data.host!.startsWith("https://")) { diff --git a/lib/wallets/wallet/impl/epiccash_wallet.dart b/lib/wallets/wallet/impl/epiccash_wallet.dart index 73955c8cb..96d6b112e 100644 --- a/lib/wallets/wallet/impl/epiccash_wallet.dart +++ b/lib/wallets/wallet/impl/epiccash_wallet.dart @@ -11,6 +11,7 @@ import 'package:mutex/mutex.dart'; import 'package:stack_wallet_backup/generate_password.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; +import '../../../exceptions/wallet/node_tor_mismatch_config_exception.dart'; import '../../../models/balance.dart'; import '../../../models/epicbox_config_model.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; @@ -32,6 +33,7 @@ import '../../../utilities/flutter_secure_storage_interface.dart'; import '../../../utilities/logger.dart'; import '../../../utilities/stack_file_system.dart'; import '../../../utilities/test_epic_box_connection.dart'; +import '../../../utilities/tor_plain_net_option_enum.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/bip39_wallet.dart'; @@ -82,6 +84,7 @@ class EpiccashWallet extends Bip39Wallet { /// returns an empty String on success, error message on failure Future cancelPendingTransactionAndPost(String txSlateId) async { try { + _hackedCheckTorNodePrefs(); final String wallet = (await secureStorageInterface.read( key: '${walletId}_wallet', ))!; @@ -173,6 +176,7 @@ class EpiccashWallet extends Bip39Wallet { }) async { final wallet = await secureStorageInterface.read(key: '${walletId}_wallet'); try { + _hackedCheckTorNodePrefs(); final available = info.cachedBalance.spendable.raw.toInt(); final transactionFees = await epiccash.LibEpiccash.getTransactionFees( @@ -198,6 +202,7 @@ class EpiccashWallet extends Bip39Wallet { } Future _startSync() async { + _hackedCheckTorNodePrefs(); Logging.instance.log("request start sync", level: LogLevel.Info); final wallet = await secureStorageInterface.read(key: '${walletId}_wallet'); const int refreshFromNode = 1; @@ -222,6 +227,7 @@ class EpiccashWallet extends Bip39Wallet { double spendable, double total })> _allWalletBalances() async { + _hackedCheckTorNodePrefs(); final wallet = await secureStorageInterface.read(key: '${walletId}_wallet'); const refreshFromNode = 0; return await epiccash.LibEpiccash.getWalletBalances( @@ -232,6 +238,7 @@ class EpiccashWallet extends Bip39Wallet { } Future _testEpicboxServer(EpicBoxConfigModel epicboxConfig) async { + _hackedCheckTorNodePrefs(); final host = epicboxConfig.host; final port = epicboxConfig.port ?? 443; WebSocketChannel? channel; @@ -576,6 +583,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future confirmSend({required TxData txData}) async { try { + _hackedCheckTorNodePrefs(); final wallet = await secureStorageInterface.read(key: '${walletId}_wallet'); final EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); @@ -638,6 +646,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future prepareSend({required TxData txData}) async { try { + _hackedCheckTorNodePrefs(); if (txData.recipients?.length != 1) { throw Exception("Epic cash prepare send requires a single recipient!"); } @@ -679,6 +688,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future recover({required bool isRescan}) async { try { + _hackedCheckTorNodePrefs(); await refreshMutex.protect(() async { if (isRescan) { // clear blockchain info @@ -782,6 +792,7 @@ class EpiccashWallet extends Bip39Wallet { cryptoCurrency, ), ); + _hackedCheckTorNodePrefs(); // if (info.epicData?.creationHeight == null) { // await info.updateExtraEpiccashWalletInfo(epicData: inf, isar: isar) @@ -880,6 +891,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future updateBalance() async { try { + _hackedCheckTorNodePrefs(); final balances = await _allWalletBalances(); final balance = Balance( total: Amount.fromDecimal( @@ -915,6 +927,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future updateTransactions() async { try { + _hackedCheckTorNodePrefs(); final wallet = await secureStorageInterface.read(key: '${walletId}_wallet'); const refreshFromNode = 1; @@ -1083,7 +1096,11 @@ class EpiccashWallet extends Bip39Wallet { NodeFormData() ..host = node!.host ..useSSL = node.useSSL - ..port = node.port, + ..port = node.port + ..netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearnetEnabled, + ), ) != null; } catch (e, s) { @@ -1094,6 +1111,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future updateChainHeight() async { + _hackedCheckTorNodePrefs(); final config = await _getRealConfig(); final latestHeight = await epiccash.LibEpiccash.getChainHeight(config: config); @@ -1105,6 +1123,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future estimateFeeFor(Amount amount, int feeRate) async { + _hackedCheckTorNodePrefs(); // setting ifErrorEstimateFee doesn't do anything as its not used in the nativeFee function????? final int currentFee = await _nativeFee( amount.raw.toInt(), @@ -1143,6 +1162,28 @@ class EpiccashWallet extends Bip39Wallet { await super.exit(); Logging.instance.log("EpicCash_wallet exit finished", level: LogLevel.Info); } + + void _hackedCheckTorNodePrefs() { + final node = nodeService.getPrimaryNodeFor(currency: cryptoCurrency)!; + final netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearnetEnabled, + ); + + if (prefs.useTor) { + if (netOption == TorPlainNetworkOption.clear) { + throw NodeTorMismatchConfigException( + message: "TOR enabled but node set to clearnet only", + ); + } + } else { + if (netOption == TorPlainNetworkOption.tor) { + throw NodeTorMismatchConfigException( + message: "TOR off but node set to TOR only", + ); + } + } + } } Future deleteEpicWallet({ From 25c6c7590bef635932fac616c716726f43f3ea86 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:06:47 -0600 Subject: [PATCH 06/14] fix layout overflow on desktop --- .../manage_nodes_views/add_edit_node_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 8695f1ea3..9c51cfb5e 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -469,7 +469,7 @@ class _AddEditNodeViewState extends ConsumerState { condition: isDesktop, builder: (child) => DesktopDialog( maxWidth: 580, - maxHeight: 500, + maxHeight: double.infinity, child: Column( mainAxisSize: MainAxisSize.min, children: [ From d87af969d62c0abe17ce6a18914c13dff843a6b8 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:07:14 -0600 Subject: [PATCH 07/14] eth doesn't do tor due to underlying lib limitation. --- .../add_edit_node_view.dart | 132 +++++++++--------- 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 9c51cfb5e..ccf4bf2ba 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -1228,69 +1228,75 @@ class _NodeFormState extends ConsumerState { ), ], ), - const SizedBox( - height: 16, - ), - Row( - children: [ - RadioTextButton( - label: "Only TOR traffic", - enabled: !widget.readOnly, - value: TorPlainNetworkOption.tor, - groupValue: netOption, - onChanged: (value) { - if (!widget.readOnly) { - setState( - () => netOption = TorPlainNetworkOption.tor, - ); - _updateState(); - } - }, - ), - ], - ), - const SizedBox( - height: 8, - ), - Row( - children: [ - RadioTextButton( - label: "Only non-TOR traffic", - enabled: !widget.readOnly, - value: TorPlainNetworkOption.clear, - groupValue: netOption, - onChanged: (value) { - if (!widget.readOnly) { - setState( - () => netOption = TorPlainNetworkOption.clear, - ); - _updateState(); - } - }, - ), - ], - ), - const SizedBox( - height: 8, - ), - Row( - children: [ - RadioTextButton( - label: "Allow both", - enabled: !widget.readOnly, - value: TorPlainNetworkOption.both, - groupValue: netOption, - onChanged: (value) { - if (!widget.readOnly) { - setState( - () => netOption = TorPlainNetworkOption.both, - ); - _updateState(); - } - }, - ), - ], - ), + if (widget.coin is! Ethereum) + const SizedBox( + height: 16, + ), + if (widget.coin is! Ethereum) + Row( + children: [ + RadioTextButton( + label: "Only TOR traffic", + enabled: !widget.readOnly, + value: TorPlainNetworkOption.tor, + groupValue: netOption, + onChanged: (value) { + if (!widget.readOnly) { + setState( + () => netOption = TorPlainNetworkOption.tor, + ); + _updateState(); + } + }, + ), + ], + ), + if (widget.coin is! Ethereum) + const SizedBox( + height: 8, + ), + if (widget.coin is! Ethereum) + Row( + children: [ + RadioTextButton( + label: "Only non-TOR traffic", + enabled: !widget.readOnly, + value: TorPlainNetworkOption.clear, + groupValue: netOption, + onChanged: (value) { + if (!widget.readOnly) { + setState( + () => netOption = TorPlainNetworkOption.clear, + ); + _updateState(); + } + }, + ), + ], + ), + if (widget.coin is! Ethereum) + const SizedBox( + height: 8, + ), + if (widget.coin is! Ethereum) + Row( + children: [ + RadioTextButton( + label: "Allow both", + enabled: !widget.readOnly, + value: TorPlainNetworkOption.both, + groupValue: netOption, + onChanged: (value) { + if (!widget.readOnly) { + setState( + () => netOption = TorPlainNetworkOption.both, + ); + _updateState(); + } + }, + ), + ], + ), ], ); } From 31fe9a538b9c8aceed23fe358b06a131b9e5642f Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:14:02 -0600 Subject: [PATCH 08/14] hack in a tor check to nano and banano --- .../nano_interface.dart | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart index 39d16497e..e08bc3b45 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart @@ -5,6 +5,7 @@ import 'package:isar/isar.dart'; import 'package:nanodart/nanodart.dart'; import 'package:tuple/tuple.dart'; +import '../../../exceptions/wallet/node_tor_mismatch_config_exception.dart'; import '../../../external_api_keys.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; @@ -18,6 +19,7 @@ import '../../../services/tor_service.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/extensions/impl/string.dart'; import '../../../utilities/logger.dart'; +import '../../../utilities/tor_plain_net_option_enum.dart'; import '../../crypto_currency/intermediate/nano_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/bip39_wallet.dart'; @@ -47,6 +49,7 @@ mixin NanoInterface on Bip39Wallet { final _httpClient = HTTP(); Future _requestWork(String hash) async { + _hackedCheckTorNodePrefs(); return _httpClient .post( url: Uri.parse(_kWorkServer), // this should be a @@ -104,6 +107,7 @@ mixin NanoInterface on Bip39Wallet { String amountRaw, String publicAddress, ) async { + _hackedCheckTorNodePrefs(); // TODO: the opening block of an account is a special case bool openBlock = false; @@ -223,6 +227,7 @@ mixin NanoInterface on Bip39Wallet { } Future _confirmAllReceivable(String accountAddress) async { + _hackedCheckTorNodePrefs(); final node = getCurrentNode(); final receivableResponse = await _httpClient.post( url: Uri.parse(node.host), @@ -254,6 +259,7 @@ mixin NanoInterface on Bip39Wallet { //========= public =========================================================== Future getCurrentRepresentative() async { + _hackedCheckTorNodePrefs(); final serverURI = Uri.parse(getCurrentNode().host); final address = (_cachedAddress ?? await getCurrentReceivingAddress())!.value; @@ -272,6 +278,7 @@ mixin NanoInterface on Bip39Wallet { Future changeRepresentative(String newRepresentative) async { try { + _hackedCheckTorNodePrefs(); final node = getCurrentNode(); final serverURI = Uri.parse(node.host); await updateBalance(); @@ -347,6 +354,11 @@ mixin NanoInterface on Bip39Wallet { @override Future pingCheck() async { + try { + _hackedCheckTorNodePrefs(); + } catch (_) { + return false; + } final node = getCurrentNode(); final uri = Uri.parse(node.host); final response = await _httpClient.post( @@ -365,6 +377,7 @@ mixin NanoInterface on Bip39Wallet { @override Future prepareSend({required TxData txData}) async { + _hackedCheckTorNodePrefs(); if (txData.recipients!.length != 1) { throw ArgumentError( "${cryptoCurrency.runtimeType} currently only " @@ -383,6 +396,7 @@ mixin NanoInterface on Bip39Wallet { @override Future confirmSend({required TxData txData}) async { try { + _hackedCheckTorNodePrefs(); // our address: final String publicAddress = (_cachedAddress ?? await getCurrentReceivingAddress())!.value; @@ -483,6 +497,7 @@ mixin NanoInterface on Bip39Wallet { @override Future recover({required bool isRescan}) async { try { + _hackedCheckTorNodePrefs(); await refreshMutex.protect(() async { if (isRescan) { await mainDB.deleteWalletBlockchainData(walletId); @@ -505,6 +520,7 @@ mixin NanoInterface on Bip39Wallet { String? previous, Map? data, ) async { + _hackedCheckTorNodePrefs(); final node = getCurrentNode(); final body = { "action": "account_history", @@ -543,6 +559,7 @@ mixin NanoInterface on Bip39Wallet { @override Future updateTransactions() async { + _hackedCheckTorNodePrefs(); await updateChainHeight(); final receivingAddress = (_cachedAddress ?? await getCurrentReceivingAddress())!; @@ -613,6 +630,7 @@ mixin NanoInterface on Bip39Wallet { @override Future updateBalance() async { try { + _hackedCheckTorNodePrefs(); final addressString = (_cachedAddress ??= (await getCurrentReceivingAddress())!).value; final body = jsonEncode({ @@ -661,6 +679,7 @@ mixin NanoInterface on Bip39Wallet { @override Future updateChainHeight() async { try { + _hackedCheckTorNodePrefs(); final String publicAddress = (_cachedAddress ??= (await getCurrentReceivingAddress())!).value; @@ -724,4 +743,26 @@ mixin NanoInterface on Bip39Wallet { medium: 0, slow: 0, ); + + void _hackedCheckTorNodePrefs() { + final node = getCurrentNode(); + final netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearnetEnabled, + ); + + if (prefs.useTor) { + if (netOption == TorPlainNetworkOption.clear) { + throw NodeTorMismatchConfigException( + message: "TOR enabled but node set to clearnet only", + ); + } + } else { + if (netOption == TorPlainNetworkOption.tor) { + throw NodeTorMismatchConfigException( + message: "TOR off but node set to TOR only", + ); + } + } + } } From 7d047e8d47d40457008173cdee0d06a808438aa5 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:30:49 -0600 Subject: [PATCH 09/14] fix solana node update logic --- lib/wallets/wallet/impl/solana_wallet.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/wallets/wallet/impl/solana_wallet.dart b/lib/wallets/wallet/impl/solana_wallet.dart index 5cbfda157..5d80063aa 100644 --- a/lib/wallets/wallet/impl/solana_wallet.dart +++ b/lib/wallets/wallet/impl/solana_wallet.dart @@ -357,16 +357,19 @@ class SolanaWallet extends Bip39Wallet { @override Future updateNode() async { - _solNode = getCurrentNode(); + _solNode = NodeService(secureStorageInterface: secureStorageInterface) + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; await refresh(); } @override NodeModel getCurrentNode() { - return _solNode ?? - NodeService(secureStorageInterface: secureStorageInterface) + _solNode ??= NodeService(secureStorageInterface: secureStorageInterface) .getPrimaryNodeFor(currency: info.coin) ?? info.coin.defaultNode; + + return _solNode!; } @override From cd003ba41229ce9362cca92c5e46824789f4ab5e Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:31:23 -0600 Subject: [PATCH 10/14] check solana node tor setting before making calls --- lib/wallets/wallet/impl/solana_wallet.dart | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/wallets/wallet/impl/solana_wallet.dart b/lib/wallets/wallet/impl/solana_wallet.dart index 5d80063aa..3c481ea39 100644 --- a/lib/wallets/wallet/impl/solana_wallet.dart +++ b/lib/wallets/wallet/impl/solana_wallet.dart @@ -9,6 +9,7 @@ import 'package:solana/dto.dart'; import 'package:solana/solana.dart'; import 'package:tuple/tuple.dart'; +import '../../../exceptions/wallet/node_tor_mismatch_config_exception.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/transaction.dart' as isar; import '../../../models/isar/models/isar_models.dart'; @@ -19,6 +20,7 @@ import '../../../services/tor_service.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/logger.dart'; import '../../../utilities/prefs.dart'; +import '../../../utilities/tor_plain_net_option_enum.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/bip39_wallet.dart'; @@ -60,6 +62,7 @@ class SolanaWallet extends Bip39Wallet { } Future _getEstimatedNetworkFee(Amount transferAmount) async { + _checkClient(); final latestBlockhash = await _rpcClient?.getLatestBlockhash(); final pubKey = (await _getKeyPair()).publicKey; @@ -254,7 +257,7 @@ class SolanaWallet extends Bip39Wallet { return health != null; } catch (e, s) { Logging.instance.log( - "$runtimeType Solana pingCheck failed \"health=$health\": $e\n$s", + "$runtimeType Solana pingCheck failed \"health response=$health\": $e\n$s", level: LogLevel.Error, ); return Future.value(false); @@ -289,9 +292,9 @@ class SolanaWallet extends Bip39Wallet { @override Future updateBalance() async { + _checkClient(); try { final address = await getCurrentReceivingAddress(); - _checkClient(); final balance = await _rpcClient?.getBalance(address!.value); @@ -448,6 +451,8 @@ class SolanaWallet extends Bip39Wallet { txsList.add(Tuple2(transaction, txAddress)); } await mainDB.addNewTransactionData(txsList, walletId); + } on NodeTorMismatchConfigException { + rethrow; } catch (e, s) { Logging.instance.log( "Error occurred in solana_wallet.dart while getting" @@ -467,6 +472,28 @@ class SolanaWallet extends Bip39Wallet { /// void _checkClient() { final node = getCurrentNode(); + + final netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearnetEnabled, + ); + + if (prefs.useTor) { + if (netOption == TorPlainNetworkOption.clear) { + _rpcClient = null; + throw NodeTorMismatchConfigException( + message: "TOR enabled but node set to clearnet only", + ); + } + } else { + if (netOption == TorPlainNetworkOption.tor) { + _rpcClient = null; + throw NodeTorMismatchConfigException( + message: "TOR off but node set to TOR only", + ); + } + } + _rpcClient = createRpcClient( node.host, node.port, From 800de8873dbf71fa64c9d0b299c128a1550ba351 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:37:39 -0600 Subject: [PATCH 11/14] check stellar node tor setting before making calls --- lib/wallets/wallet/impl/stellar_wallet.dart | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/wallets/wallet/impl/stellar_wallet.dart b/lib/wallets/wallet/impl/stellar_wallet.dart index 09d5d48fa..8932a30fb 100644 --- a/lib/wallets/wallet/impl/stellar_wallet.dart +++ b/lib/wallets/wallet/impl/stellar_wallet.dart @@ -7,6 +7,7 @@ import 'package:mutex/mutex.dart'; import 'package:socks5_proxy/socks.dart'; import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart' as stellar; +import '../../../exceptions/wallet/node_tor_mismatch_config_exception.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; import '../../../models/isar/models/blockchain_data/transaction.dart'; @@ -22,6 +23,7 @@ import '../../../utilities/amount/amount.dart'; import '../../../utilities/enums/fee_rate_type_enum.dart'; import '../../../utilities/logger.dart'; import '../../../utilities/test_stellar_node_connection.dart'; +import '../../../utilities/tor_plain_net_option_enum.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/bip39_wallet.dart'; @@ -61,12 +63,40 @@ class StellarWallet extends Bip39Wallet { ); } + void _hackedCheck() { + final node = getCurrentNode(); + final netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearnetEnabled, + ); + + if (prefs.useTor) { + if (netOption == TorPlainNetworkOption.clear) { + _stellarSdk?.httpClient.close(); + _stellarSdk = null; + throw NodeTorMismatchConfigException( + message: "TOR enabled but node set to clearnet only", + ); + } + } else { + if (netOption == TorPlainNetworkOption.tor) { + _stellarSdk?.httpClient.close(); + _stellarSdk = null; + throw NodeTorMismatchConfigException( + message: "TOR off but node set to TOR only", + ); + } + } + } + Future get stellarSdk async { if (_requireMutex) { await _torConnectingLock.protect(() async { + _hackedCheck(); _stellarSdk ??= _getFreshSdk(); }); } else { + _hackedCheck(); _stellarSdk ??= _getFreshSdk(); } return _stellarSdk!; From b548386097b5c7d06b01bafa1436937547f1d2ed Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 10:45:08 -0600 Subject: [PATCH 12/14] hack a check for node tor settings before making calls into tezos as well --- lib/wallets/wallet/impl/tezos_wallet.dart | 41 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/wallets/wallet/impl/tezos_wallet.dart b/lib/wallets/wallet/impl/tezos_wallet.dart index a1728c10a..ab1448319 100644 --- a/lib/wallets/wallet/impl/tezos_wallet.dart +++ b/lib/wallets/wallet/impl/tezos_wallet.dart @@ -4,6 +4,7 @@ import 'package:isar/isar.dart'; import 'package:tezart/tezart.dart' as tezart; import 'package:tuple/tuple.dart'; +import '../../../exceptions/wallet/node_tor_mismatch_config_exception.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; import '../../../models/isar/models/blockchain_data/transaction.dart'; @@ -14,6 +15,7 @@ import '../../../services/tor_service.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/extensions/impl/string.dart'; import '../../../utilities/logger.dart'; +import '../../../utilities/tor_plain_net_option_enum.dart'; import '../../api/tezos/tezos_account.dart'; import '../../api/tezos/tezos_api.dart'; import '../../api/tezos/tezos_rpc_api.dart'; @@ -42,6 +44,7 @@ class TezosWallet extends Bip39Wallet { String passphrase = "", }) async { try { + _hackedCheckTorNodePrefs(); for (final path in Tezos.possibleDerivationPaths) { final ks = await _getKeyStore(path: path.value); @@ -99,6 +102,7 @@ class TezosWallet extends Bip39Wallet { // Amount? customRevealFee, }) async { try { + _hackedCheckTorNodePrefs(); final sourceKeyStore = await _getKeyStore(); final server = (_xtzNode ?? getCurrentNode()).host; // if (kDebugMode) { @@ -178,6 +182,7 @@ class TezosWallet extends Bip39Wallet { @override Future prepareSend({required TxData txData}) async { try { + _hackedCheckTorNodePrefs(); if (txData.recipients == null || txData.recipients!.length != 1) { throw Exception("$runtimeType prepareSend requires 1 recipient"); } @@ -288,6 +293,7 @@ class TezosWallet extends Bip39Wallet { @override Future confirmSend({required TxData txData}) async { + _hackedCheckTorNodePrefs(); await txData.tezosOperationsList!.inject(); await txData.tezosOperationsList!.monitor(); return txData.copyWith( @@ -301,6 +307,7 @@ class TezosWallet extends Bip39Wallet { TezosAccount account, String recipientAddress, ) async { + _hackedCheckTorNodePrefs(); try { final opList = await _buildSendTransaction( amount: Amount( @@ -356,6 +363,7 @@ class TezosWallet extends Bip39Wallet { int feeRate, { String recipientAddress = "tz1MXvDCyXSqBqXPNDcsdmVZKfoxL9FTHmp2", }) async { + _hackedCheckTorNodePrefs(); if (info.cachedBalance.spendable.raw == BigInt.zero) { return Amount( rawValue: BigInt.zero, @@ -402,6 +410,7 @@ class TezosWallet extends Bip39Wallet { @override Future pingCheck() async { + _hackedCheckTorNodePrefs(); final currentNode = getCurrentNode(); return await TezosRpcAPI.testNetworkConnection( nodeInfo: ( @@ -413,6 +422,7 @@ class TezosWallet extends Bip39Wallet { @override Future recover({required bool isRescan}) async { + _hackedCheckTorNodePrefs(); await refreshMutex.protect(() async { if (isRescan) { await mainDB.deleteWalletBlockchainData(walletId); @@ -463,6 +473,7 @@ class TezosWallet extends Bip39Wallet { @override Future updateBalance() async { try { + _hackedCheckTorNodePrefs(); final currentNode = _xtzNode ?? getCurrentNode(); final balance = await TezosRpcAPI.getBalance( nodeInfo: (host: currentNode.host, port: currentNode.port), @@ -498,6 +509,7 @@ class TezosWallet extends Bip39Wallet { @override Future updateChainHeight() async { try { + _hackedCheckTorNodePrefs(); final currentNode = _xtzNode ?? getCurrentNode(); final height = await TezosRpcAPI.getChainHeight( nodeInfo: ( @@ -530,14 +542,15 @@ class TezosWallet extends Bip39Wallet { @override NodeModel getCurrentNode() { - return _xtzNode ?? + return _xtzNode ??= NodeService(secureStorageInterface: secureStorageInterface) - .getPrimaryNodeFor(currency: info.coin) ?? - info.coin.defaultNode; + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; } @override Future updateTransactions() async { + _hackedCheckTorNodePrefs(); // TODO: optimize updateTransactions and use V2 final myAddress = (await getCurrentReceivingAddress())!; @@ -615,4 +628,26 @@ class TezosWallet extends Bip39Wallet { // do nothing. Not used in tezos return false; } + + void _hackedCheckTorNodePrefs() { + final node = nodeService.getPrimaryNodeFor(currency: cryptoCurrency)!; + final netOption = TorPlainNetworkOption.fromNodeData( + node.torEnabled, + node.clearnetEnabled, + ); + + if (prefs.useTor) { + if (netOption == TorPlainNetworkOption.clear) { + throw NodeTorMismatchConfigException( + message: "TOR enabled but node set to clearnet only", + ); + } + } else { + if (netOption == TorPlainNetworkOption.tor) { + throw NodeTorMismatchConfigException( + message: "TOR off but node set to TOR only", + ); + } + } + } } From 3fb18bf2dbc1d59a15ade876a74c52a696b6cd46 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 12:46:18 -0600 Subject: [PATCH 13/14] info dialog if node settings and current TOR status will cause sync issues on wallet open --- lib/pages/pinpad_views/lock_screen_view.dart | 17 ++++ .../sub_widgets/favorite_card.dart | 14 +++ .../sub_widgets/wallet_list_item.dart | 15 +++ .../my_stack_view/coin_wallets_table.dart | 19 ++++ .../my_stack_view/wallet_summary_table.dart | 14 +++ .../show_node_tor_settings_mismatch.dart | 97 +++++++++++++++++++ lib/widgets/wallet_card.dart | 14 +++ 7 files changed, 190 insertions(+) create mode 100644 lib/utilities/show_node_tor_settings_mismatch.dart diff --git a/lib/pages/pinpad_views/lock_screen_view.dart b/lib/pages/pinpad_views/lock_screen_view.dart index 711a25a45..5d630ba4f 100644 --- a/lib/pages/pinpad_views/lock_screen_view.dart +++ b/lib/pages/pinpad_views/lock_screen_view.dart @@ -16,6 +16,7 @@ import 'package:mutex/mutex.dart'; import '../../notifications/show_flush_bar.dart'; // import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart'; +import '../../providers/global/node_service_provider.dart'; import '../../providers/global/prefs_provider.dart'; import '../../providers/global/secure_store_provider.dart'; import '../../providers/global/wallets_provider.dart'; @@ -25,7 +26,9 @@ import '../../utilities/assets.dart'; import '../../utilities/biometrics.dart'; import '../../utilities/flutter_secure_storage_interface.dart'; import '../../utilities/show_loading.dart'; +import '../../utilities/show_node_tor_settings_mismatch.dart'; import '../../utilities/text_styles.dart'; +import '../../utilities/util.dart'; import '../../wallets/wallet/intermediate/lib_monero_wallet.dart'; import '../../widgets/background.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; @@ -101,6 +104,20 @@ class _LockscreenViewState extends ConsumerState { final walletId = widget.routeOnSuccessArguments as String; final wallet = ref.read(pWallets).getWallet(walletId); + + final canContinue = await checkShowNodeTorSettingsMismatch( + context: context, + currency: wallet.cryptoCurrency, + prefs: ref.read(prefsChangeNotifierProvider), + nodeService: ref.read(nodeServiceChangeNotifierProvider), + allowCancel: false, + rootNavigator: Util.isDesktop, + ); + + if (!canContinue) { + return; + } + final Future loadFuture; if (wallet is LibMoneroWallet) { loadFuture = diff --git a/lib/pages/wallets_view/sub_widgets/favorite_card.dart b/lib/pages/wallets_view/sub_widgets/favorite_card.dart index 48d0d1257..26e11624a 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_card.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_card.dart @@ -22,6 +22,7 @@ import '../../../utilities/amount/amount.dart'; import '../../../utilities/amount/amount_formatter.dart'; import '../../../utilities/constants.dart'; import '../../../utilities/show_loading.dart'; +import '../../../utilities/show_node_tor_settings_mismatch.dart'; import '../../../utilities/text_styles.dart'; import '../../../utilities/util.dart'; import '../../../wallets/crypto_currency/coins/firo.dart'; @@ -117,6 +118,19 @@ class _FavoriteCardState extends ConsumerState { onTap: () async { final wallet = ref.read(pWallets).getWallet(walletId); + final canContinue = await checkShowNodeTorSettingsMismatch( + context: context, + currency: coin, + prefs: ref.read(prefsChangeNotifierProvider), + nodeService: ref.read(nodeServiceChangeNotifierProvider), + allowCancel: true, + rootNavigator: Util.isDesktop, + ); + + if (!canContinue) { + return; + } + final Future loadFuture; if (wallet is LibMoneroWallet) { loadFuture = diff --git a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart index 3ac87eb2e..767770ba9 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -21,6 +21,7 @@ import '../../../themes/stack_colors.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/constants.dart'; import '../../../utilities/show_loading.dart'; +import '../../../utilities/show_node_tor_settings_mismatch.dart'; import '../../../utilities/text_styles.dart'; import '../../../utilities/util.dart'; import '../../../wallets/crypto_currency/crypto_currency.dart'; @@ -83,6 +84,20 @@ class WalletListItem extends ConsumerWidget { .read(pWallets) .wallets .firstWhere((e) => e.info.coin == coin); + + final canContinue = await checkShowNodeTorSettingsMismatch( + context: context, + currency: coin, + prefs: ref.read(prefsChangeNotifierProvider), + nodeService: ref.read(nodeServiceChangeNotifierProvider), + allowCancel: true, + rootNavigator: Util.isDesktop, + ); + + if (!canContinue) { + return; + } + final Future loadFuture; if (wallet is LibMoneroWallet) { loadFuture = diff --git a/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart b/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart index 7771c33f5..8da907ca3 100644 --- a/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart @@ -12,10 +12,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../providers/global/active_wallet_provider.dart'; +import '../../providers/global/node_service_provider.dart'; +import '../../providers/global/prefs_provider.dart'; import '../../providers/global/wallets_provider.dart'; import '../../themes/stack_colors.dart'; import '../../utilities/constants.dart'; import '../../utilities/show_loading.dart'; +import '../../utilities/show_node_tor_settings_mismatch.dart'; import '../../utilities/util.dart'; import '../../wallets/crypto_currency/crypto_currency.dart'; import '../../wallets/wallet/intermediate/lib_monero_wallet.dart'; @@ -81,6 +84,22 @@ class CoinWalletsTable extends ConsumerWidget { final wallet = ref.read(pWallets).getWallet(walletIds[i]); + + final canContinue = + await checkShowNodeTorSettingsMismatch( + context: context, + currency: coin, + prefs: ref.read(prefsChangeNotifierProvider), + nodeService: + ref.read(nodeServiceChangeNotifierProvider), + allowCancel: true, + rootNavigator: Util.isDesktop, + ); + + if (!canContinue) { + return; + } + final Future loadFuture; if (wallet is LibMoneroWallet) { loadFuture = wallet diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart index b30ffb17a..5df82cc0f 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart @@ -20,6 +20,7 @@ import '../../themes/coin_icon_provider.dart'; import '../../themes/stack_colors.dart'; import '../../utilities/amount/amount.dart'; import '../../utilities/show_loading.dart'; +import '../../utilities/show_node_tor_settings_mismatch.dart'; import '../../utilities/text_styles.dart'; import '../../utilities/util.dart'; import '../../wallets/crypto_currency/crypto_currency.dart'; @@ -123,6 +124,19 @@ class _DesktopWalletSummaryRowState final wallet = ref.read(pWallets).wallets.firstWhere( (e) => e.cryptoCurrency.identifier == widget.coin.identifier); + final canContinue = await checkShowNodeTorSettingsMismatch( + context: context, + currency: wallet.cryptoCurrency, + prefs: ref.read(prefsChangeNotifierProvider), + nodeService: ref.read(nodeServiceChangeNotifierProvider), + allowCancel: true, + rootNavigator: Util.isDesktop, + ); + + if (!canContinue) { + return; + } + final Future loadFuture; if (wallet is LibMoneroWallet) { loadFuture = diff --git a/lib/utilities/show_node_tor_settings_mismatch.dart b/lib/utilities/show_node_tor_settings_mismatch.dart new file mode 100644 index 000000000..6c2490b51 --- /dev/null +++ b/lib/utilities/show_node_tor_settings_mismatch.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; + +import '../services/node_service.dart'; +import '../wallets/crypto_currency/crypto_currency.dart'; +import '../widgets/conditional_parent.dart'; +import '../widgets/desktop/desktop_dialog.dart'; +import '../widgets/desktop/primary_button.dart'; +import '../widgets/desktop/secondary_button.dart'; +import '../widgets/stack_dialog.dart'; +import 'prefs.dart'; +import 'text_styles.dart'; +import 'util.dart'; + +Future checkShowNodeTorSettingsMismatch({ + required BuildContext context, + required CryptoCurrency currency, + required Prefs prefs, + required NodeService nodeService, + required bool allowCancel, + bool rootNavigator = false, +}) async { + final node = + nodeService.getPrimaryNodeFor(currency: currency) ?? currency.defaultNode; + if (prefs.useTor) { + if (node.torEnabled) { + return true; + } + } else { + if (node.clearnetEnabled) { + return true; + } + } + + final result = await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => ConditionalParent( + condition: Util.isDesktop, + builder: (child) => DesktopDialog( + maxHeight: double.infinity, + child: Padding( + padding: const EdgeInsets.all(32), + child: child, + ), + ), + child: ConditionalParent( + condition: !Util.isDesktop, + builder: (child) => StackDialogBase( + child: child, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Attention! Node connection issue detected. " + "The current node will not sync due to its connectivity settings. " + "Please adjust the node settings or enable/disable TOR.", + style: STextStyles.w600_16(context), + ), + SizedBox( + height: Util.isDesktop ? 32 : 24, + ), + Row( + children: [ + allowCancel + ? Expanded( + child: SecondaryButton( + buttonHeight: Util.isDesktop ? ButtonHeight.l : null, + label: "Cancel", + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + ) + : const Spacer(), + SizedBox( + width: Util.isDesktop ? 24 : 16, + ), + Expanded( + child: PrimaryButton( + buttonHeight: Util.isDesktop ? ButtonHeight.l : null, + label: "Continue", + onPressed: () { + Navigator.of(context).pop(true); + }, + ), + ), + ], + ), + ], + ), + ), + ), + ); + + return result ?? true; +} diff --git a/lib/widgets/wallet_card.dart b/lib/widgets/wallet_card.dart index 79ab0d41d..814d4b321 100644 --- a/lib/widgets/wallet_card.dart +++ b/lib/widgets/wallet_card.dart @@ -23,6 +23,7 @@ import '../providers/providers.dart'; import '../utilities/constants.dart'; import '../utilities/logger.dart'; import '../utilities/show_loading.dart'; +import '../utilities/show_node_tor_settings_mismatch.dart'; import '../utilities/util.dart'; import '../wallets/isar/providers/eth/current_token_wallet_provider.dart'; import '../wallets/wallet/impl/ethereum_wallet.dart'; @@ -95,6 +96,19 @@ class SimpleWalletCard extends ConsumerWidget { final wallet = ref.read(pWallets).getWallet(walletId); + final canContinue = await checkShowNodeTorSettingsMismatch( + context: context, + currency: wallet.cryptoCurrency, + prefs: ref.read(prefsChangeNotifierProvider), + nodeService: ref.read(nodeServiceChangeNotifierProvider), + allowCancel: true, + rootNavigator: Util.isDesktop, + ); + + if (!canContinue) { + return; + } + if (context.mounted) { final Future loadFuture; if (wallet is LibMoneroWallet) { From d6abd7d658088370190a54a663c67fbca3b1df9e Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 26 Nov 2024 13:48:33 -0600 Subject: [PATCH 14/14] "handle" null account info according to https://solana.com/docs/rpc/http/getaccountinfo#result --- lib/wallets/wallet/impl/solana_wallet.dart | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/wallets/wallet/impl/solana_wallet.dart b/lib/wallets/wallet/impl/solana_wallet.dart index 3c481ea39..8c7f7e43b 100644 --- a/lib/wallets/wallet/impl/solana_wallet.dart +++ b/lib/wallets/wallet/impl/solana_wallet.dart @@ -132,11 +132,14 @@ class SolanaWallet extends Bip39Wallet { // Rent exemption of Solana final accInfo = await _rpcClient?.getAccountInfo(address!.value); + if (accInfo!.value == null) { + throw Exception("Account does not appear to exist"); + } + final int minimumRent = - await _rpcClient?.getMinimumBalanceForRentExemption( - accInfo!.value!.data.toString().length, - ) ?? - 0; // TODO revisit null condition. + await _rpcClient!.getMinimumBalanceForRentExemption( + accInfo.value!.data.toString().length, + ); if (minimumRent > ((await _getCurrentBalanceInLamports()) - txData.amount!.raw.toInt() - @@ -300,13 +303,14 @@ class SolanaWallet extends Bip39Wallet { // Rent exemption of Solana final accInfo = await _rpcClient?.getAccountInfo(address!.value); - // TODO [prio=low]: handle null account info. + if (accInfo!.value == null) { + throw Exception("Account does not appear to exist"); + } + final int minimumRent = - await _rpcClient?.getMinimumBalanceForRentExemption( - accInfo!.value!.data.toString().length, - ) ?? - 0; - // TODO [prio=low]: revisit null condition. + await _rpcClient!.getMinimumBalanceForRentExemption( + accInfo.value!.data.toString().length, + ); final spendableBalance = balance!.value - minimumRent; final newBalance = Balance(