Fixes for LTC electrum nodes available.

M committed May 10, 2021 at 19:00 UTC 1cb27d9da3edb507c8b42d0e6fb0997846d9a09f
7 files changed +64 -53
lib/bitcoin/electrum.dart
+2 -21
@@ -8,16 +8,6 @@ import 'package:cake_wallet/bitcoin/script_hash.dart';
8 import 'package:flutter/foundation.dart';
9 import 'package:rxdart/rxdart.dart';
10
11 -class UriParseException implements Exception {
12 - UriParseException(this.uri);
13 -
14 - final String uri;
15 -
16 - @override
17 - String toString() =>
18 - 'Cannot parse host and port from uri. Invalid uri format. Uri: $uri';
19 -}
20 -
11 String jsonrpcparams(List<Object> params) {
12 final _params = params?.map((val) => '"${val.toString()}"')?.join(',');
13 return '[$_params]';
@@ -54,17 +44,8 @@ class ElectrumClient {
44 Timer _aliveTimer;
45 String unterminatedString;
46
57 - Future<void> connectToUri(String uri) async {
58 - final splittedUri = uri.split(':');
59 -
60 - if (splittedUri.length != 2) {
61 - throw UriParseException(uri);
62 - }
63 -
64 - final host = splittedUri.first;
65 - final port = int.parse(splittedUri.last);
66 - await connect(host: host, port: port);
67 - }
47 + Future<void> connectToUri(Uri uri) async =>
48 + await connect(host: uri.host, port: uri.port);
49
50 Future<void> connect({@required String host, @required int port}) async {
51 try {
lib/entities/default_settings_migration.dart
+5 -5
@@ -149,7 +149,7 @@ Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
149 final nodeToReplace = replaceNodes[node.uri];
150
151 if (nodeToReplace != null) {
152 - node.uri = nodeToReplace.uri;
152 + node.uriRaw = nodeToReplace.uriRaw;
153 node.login = nodeToReplace.login;
154 node.password = nodeToReplace.password;
155 await node.save();
@@ -319,11 +319,11 @@ Future<void> changeDefaultMoneroNode(
319 final currentMoneroNode =
320 nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId);
321 final needToReplaceCurrentMoneroNode =
322 - currentMoneroNode.uri.contains(cakeWalletMoneroNodeUriPattern);
322 + currentMoneroNode.uri.toString().contains(cakeWalletMoneroNodeUriPattern);
323
324 nodeSource.values.forEach((node) async {
325 if (node.type == WalletType.monero &&
326 - node.uri.contains(cakeWalletMoneroNodeUriPattern)) {
326 + node.uri.toString().contains(cakeWalletMoneroNodeUriPattern)) {
327 await node.delete();
328 }
329 });
@@ -389,10 +389,10 @@ Future<void> resetBitcoinElectrumServer(
389 final currentElectrumSeverId =
390 sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
391 final oldElectrumServer = nodeSource.values.firstWhere(
392 - (node) => node.uri.contains('electrumx.cakewallet.com'),
392 + (node) => node.uri.toString().contains('electrumx.cakewallet.com'),
393 orElse: () => null);
394 var cakeWalletNode = nodeSource.values.firstWhere(
395 - (node) => node.uri == cakeWalletBitcoinElectrumUri,
395 + (node) => node.uri.toString() == cakeWalletBitcoinElectrumUri,
396 orElse: () => null);
397
398 if (cakeWalletNode == null) {
lib/entities/node.dart
+36 -10
@@ -1,3 +1,5 @@
1 +import 'dart:io';
2 +
3 import 'package:cake_wallet/utils/mobx.dart';
4 import 'package:flutter/foundation.dart';
5 import 'dart:convert';
@@ -8,19 +10,23 @@ import 'package:cake_wallet/entities/digest_request.dart';
10
11 part 'node.g.dart';
12
13 +Uri createUriFromElectrumAddress(String address) =>
14 + Uri.tryParse('tcp://$address');
15 +
16 @HiveType(typeId: Node.typeId)
17 class Node extends HiveObject with Keyable {
18 Node(
14 - {@required this.uri,
19 + {@required String uri,
20 @required WalletType type,
21 this.login,
22 this.password,
23 this.useSSL}) {
24 + uriRaw = uri;
25 this.type = type;
26 }
27
28 Node.fromMap(Map map)
23 - : uri = map['uri'] as String ?? '',
29 + : uriRaw = map['uri'] as String ?? '',
30 login = map['login'] as String,
31 password = map['password'] as String,
32 typeRaw = map['typeRaw'] as int,
@@ -30,7 +36,7 @@ class Node extends HiveObject with Keyable {
36 static const boxName = 'Nodes';
37
38 @HiveField(0)
33 - String uri;
39 + String uriRaw;
40
41 @HiveField(1)
42 String login;
@@ -46,6 +52,19 @@ class Node extends HiveObject with Keyable {
52
53 bool get isSSL => useSSL ?? false;
54
55 + Uri get uri {
56 + switch (type) {
57 + case WalletType.monero:
58 + return Uri.http(uriRaw, '');
59 + case WalletType.bitcoin:
60 + return createUriFromElectrumAddress(uriRaw);
61 + case WalletType.litecoin:
62 + return createUriFromElectrumAddress(uriRaw);
63 + default:
64 + return null;
65 + }
66 + }
67 +
68 @override
69 dynamic get keyIndex {
70 _keyIndex ??= key;
@@ -64,7 +83,9 @@ class Node extends HiveObject with Keyable {
83 case WalletType.monero:
84 return requestMoneroNode();
85 case WalletType.bitcoin:
67 - return requestBitcoinElectrumServer();
86 + return requestElectrumServer();
87 + case WalletType.litecoin:
88 + return requestElectrumServer();
89 default:
90 return false;
91 }
@@ -80,15 +101,15 @@ class Node extends HiveObject with Keyable {
101 if (login != null && password != null) {
102 final digestRequest = DigestRequest();
103 final response = await digestRequest.request(
83 - uri: uri, login: login, password: password);
104 + uri: uri.toString(), login: login, password: password);
105 resBody = response.data as Map<String, dynamic>;
106 } else {
86 - final url = Uri.http(uri, '/json_rpc');
107 + final rpcUri = Uri.http(uri.toString(), '/json_rpc');
108 final headers = {'Content-type': 'application/json'};
109 final body =
110 json.encode({'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'});
111 final response =
91 - await http.post(url.toString(), headers: headers, body: body);
112 + await http.post(rpcUri.toString(), headers: headers, body: body);
113 resBody = json.decode(response.body) as Map<String, dynamic>;
114 }
115
@@ -98,8 +119,13 @@ class Node extends HiveObject with Keyable {
119 }
120 }
121
101 - Future<bool> requestBitcoinElectrumServer() async {
102 - // FIXME: IMPLEMENT ME
103 - return true;
122 + Future<bool> requestElectrumServer() async {
123 + try {
124 + await SecureSocket.connect(uri.host, uri.port,
125 + timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
126 + return true;
127 + } catch (_) {
128 + return false;
129 + }
130 }
131 }
lib/main.dart
+1 -1
@@ -74,7 +74,7 @@ Future<void> main() async {
74 if (!Hive.isAdapterRegistered(Order.typeId)) {
75 Hive.registerAdapter(OrderAdapter());
76 }
77 -
77 +
78 final secureStorage = FlutterSecureStorage();
79 final transactionDescriptionsBoxKey = await getEncryptionKey(
80 secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
lib/monero/monero_wallet.dart
+1 -1
@@ -152,7 +152,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
152 try {
153 syncStatus = ConnectingSyncStatus();
154 await monero_wallet.setupNode(
155 - address: node.uri,
155 + address: node.uri.toString(),
156 login: node.login,
157 password: node.password,
158 useSSL: node.isSSL,
lib/reactions/check_connection.dart
+15 -12
@@ -7,19 +7,22 @@ import 'package:connectivity/connectivity.dart';
7
8 Timer _checkConnectionTimer;
9
10 -void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore, {int timeInterval = 5}) {
10 +void startCheckConnectionReaction(
11 + WalletBase wallet, SettingsStore settingsStore,
12 + {int timeInterval = 5}) {
13 _checkConnectionTimer?.cancel();
12 - _checkConnectionTimer = Timer.periodic(Duration(seconds: timeInterval), (_) async {
13 - final connectivityResult = await (Connectivity().checkConnectivity());
14 + _checkConnectionTimer =
15 + Timer.periodic(Duration(seconds: timeInterval), (_) async {
16 + try {
17 + final connectivityResult = await (Connectivity().checkConnectivity());
18
15 - if (connectivityResult == ConnectivityResult.none) {
16 - wallet.syncStatus = FailedSyncStatus();
17 - return;
18 - }
19 + if (connectivityResult == ConnectivityResult.none) {
20 + wallet.syncStatus = FailedSyncStatus();
21 + return;
22 + }
23
20 - if (wallet.syncStatus is LostConnectionSyncStatus ||
21 - wallet.syncStatus is FailedSyncStatus) {
22 - try {
24 + if (wallet.syncStatus is LostConnectionSyncStatus ||
25 + wallet.syncStatus is FailedSyncStatus) {
26 final alive =
27 await settingsStore.getCurrentNode(wallet.type).requestNode();
28
@@ -27,9 +30,9 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore
30 await wallet.connectToNode(
31 node: settingsStore.getCurrentNode(wallet.type));
32 }
30 - } catch (_) {
31 - // FIXME: empty catch clojure
33 }
34 + } catch (e) {
35 + print(e.toString());
36 }
37 });
38 }
lib/src/screens/nodes/nodes_list_page.dart
+4 -3
@@ -87,7 +87,7 @@ class NodeListPage extends BasePage {
87 final isSelected =
88 node.keyIndex == nodeListViewModel.currentNode?.keyIndex;
89 final nodeListRow = NodeListRow(
90 - title: node.uri,
90 + title: node.uriRaw,
91 isSelected: isSelected,
92 isAlive: node.requestNode(),
93 onTap: (_) async {
@@ -101,8 +101,9 @@ class NodeListPage extends BasePage {
101 return AlertWithTwoActions(
102 alertTitle:
103 S.of(context).change_current_node_title,
104 - alertContent:
105 - S.of(context).change_current_node(node.uri),
104 + alertContent: S
105 + .of(context)
106 + .change_current_node(node.uriRaw),
107 leftButtonText: S.of(context).cancel,
108 rightButtonText: S.of(context).change,
109 actionLeftButton: () =>