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: () =>