Skip to content

Commit

Permalink
Merge pull request #1036 from cypherstack/node-settings
Browse files Browse the repository at this point in the history
Node settings
  • Loading branch information
rehrar authored Nov 26, 2024
2 parents f38efd3 + d6abd7d commit 1ce4bee
Show file tree
Hide file tree
Showing 57 changed files with 1,178 additions and 120 deletions.
4 changes: 4 additions & 0 deletions lib/db/db_version_migration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class DbVersionMigrator with WalletDB {
name: e.name,
id: e.id,
useSSL: e.useSSL,
torEnabled: e.torEnabled,
clearnetEnabled: e.clearnetEnabled,
),
)
.toList();
Expand All @@ -88,6 +90,8 @@ class DbVersionMigrator with WalletDB {
name: node.name,
id: node.id,
useSSL: node.useSSL,
torEnabled: node.torEnabled,
clearnetEnabled: node.clearnetEnabled,
),
prefs: prefs,
failovers: failovers,
Expand Down
51 changes: 44 additions & 7 deletions lib/electrumx_rpc/client_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ 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 {
ClientManager._();
static final ClientManager sharedInstance = ClientManager._();

final Map<String, ElectrumClient> _map = {};
final Map<String, TorPlainNetworkOption> _mapNet = {};
final Map<String, int> _heights = {};
final Map<String, StreamSubscription<BlockHeader>> _subscriptions = {};
final Map<String, Completer<int>> _heightCompleters = {};
Expand All @@ -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<void> 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<int>();
Expand Down Expand Up @@ -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<ElectrumClient?> remove({
Future<(ElectrumClient?, TorPlainNetworkOption?)> remove({
required CryptoCurrency cryptoCurrency,
}) async {
final key = _keyHelper(cryptoCurrency);
Expand All @@ -80,7 +116,7 @@ class ClientManager {
_heights.remove(key);
_heightCompleters.remove(key);

return _map.remove(key);
return (_map.remove(key), _mapNet.remove(key));
}

Future<void> closeAll() async {
Expand All @@ -99,6 +135,7 @@ class ClientManager {
_heightCompleters.clear();
_heights.clear();
_subscriptions.clear();
_mapNet.clear();
_map.clear();
}
}
46 changes: 43 additions & 3 deletions lib/electrumx_rpc/electrumx_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -42,19 +43,27 @@ typedef SparkMempoolData = ({

class WifiOnlyException implements Exception {}

class TorOnlyException implements Exception {}

class ClearnetOnlyException implements Exception {}

class ElectrumXNode {
ElectrumXNode({
required this.address,
required this.port,
required this.name,
required this.id,
required this.useSSL,
required this.torEnabled,
required this.clearnetEnabled,
});
final String address;
final int port;
final String name;
final String id;
final bool useSSL;
final bool torEnabled;
final bool clearnetEnabled;

factory ElectrumXNode.from(ElectrumXNode node) {
return ElectrumXNode(
Expand All @@ -63,6 +72,8 @@ class ElectrumXNode {
name: node.name,
id: node.id,
useSSL: node.useSSL,
torEnabled: node.torEnabled,
clearnetEnabled: node.clearnetEnabled,
);
}

Expand All @@ -74,6 +85,7 @@ class ElectrumXNode {

class ElectrumXClient {
final CryptoCurrency cryptoCurrency;
final TorPlainNetworkOption netType;

String get host => _host;
late String _host;
Expand All @@ -90,6 +102,7 @@ class ElectrumXClient {
ElectrumClient? getElectrumAdapter() =>
ClientManager.sharedInstance.getClient(
cryptoCurrency: cryptoCurrency,
netType: netType,
);

late Prefs _prefs;
Expand Down Expand Up @@ -119,6 +132,7 @@ class ElectrumXClient {
required int port,
required bool useSSL,
required Prefs prefs,
required this.netType,
required List<ElectrumXNode> failovers,
required this.cryptoCurrency,
this.connectionTimeoutForSpecialCaseJsonRPCClients =
Expand Down Expand Up @@ -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.
Expand All @@ -193,6 +208,10 @@ class ElectrumXClient {
failovers: failovers,
globalEventBusForTesting: globalEventBusForTesting,
cryptoCurrency: cryptoCurrency,
netType: TorPlainNetworkOption.fromNodeData(
node.torEnabled,
node.clearnetEnabled,
),
);
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -288,9 +319,10 @@ class ElectrumXClient {
);
}

ClientManager.sharedInstance.addClient(
await ClientManager.sharedInstance.addClient(
newClient,
cryptoCurrency: cryptoCurrency,
netType: netType,
);
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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",
Expand Down
8 changes: 8 additions & 0 deletions lib/exceptions/wallet/node_tor_mismatch_config_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class NodeTorMismatchConfigException implements Exception {
final String message;

NodeTorMismatchConfigException({required this.message});

@override
String toString() => message;
}
13 changes: 13 additions & 0 deletions lib/models/node_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import 'package:hive/hive.dart';

import '../utilities/default_nodes.dart';
import '../utilities/flutter_secure_storage_interface.dart';

Expand Down Expand Up @@ -38,6 +39,10 @@ class NodeModel {
final bool isDown;
// @HiveField(10)
final bool? trusted;
// @HiveField(11)
final bool torEnabled;
// @HiveField(12)
final bool clearnetEnabled;

NodeModel({
required this.host,
Expand All @@ -49,6 +54,8 @@ class NodeModel {
required this.coinName,
required this.isFailover,
required this.isDown,
required this.torEnabled,
required this.clearnetEnabled,
this.loginName,
this.trusted,
});
Expand All @@ -64,6 +71,8 @@ class NodeModel {
bool? isFailover,
bool? isDown,
bool? trusted,
bool? torEnabled,
bool? clearnetEnabled,
}) {
return NodeModel(
host: host ?? this.host,
Expand All @@ -77,6 +86,8 @@ class NodeModel {
isFailover: isFailover ?? this.isFailover,
isDown: isDown ?? this.isDown,
trusted: trusted ?? this.trusted,
torEnabled: torEnabled ?? this.torEnabled,
clearnetEnabled: clearnetEnabled ?? this.clearnetEnabled,
);
}

Expand All @@ -98,6 +109,8 @@ class NodeModel {
map['isFailover'] = isFailover;
map['isDown'] = isDown;
map['trusted'] = trusted;
map['torEnabled'] = torEnabled;
map['clearEnabled'] = clearnetEnabled;
return map;
}

Expand Down
10 changes: 8 additions & 2 deletions lib/models/type_adaptors/node_model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1ce4bee

Please sign in to comment.