Fixes for LTC electrum nodes available.

This commit is contained in:
M 2021-05-10 19:00:20 +03:00
parent 9f9ec91eba
commit 1cb27d9da3
7 changed files with 64 additions and 53 deletions

View file

@ -8,16 +8,6 @@ import 'package:cake_wallet/bitcoin/script_hash.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
class UriParseException implements Exception {
UriParseException(this.uri);
final String uri;
@override
String toString() =>
'Cannot parse host and port from uri. Invalid uri format. Uri: $uri';
}
String jsonrpcparams(List<Object> params) { String jsonrpcparams(List<Object> params) {
final _params = params?.map((val) => '"${val.toString()}"')?.join(','); final _params = params?.map((val) => '"${val.toString()}"')?.join(',');
return '[$_params]'; return '[$_params]';
@ -54,17 +44,8 @@ class ElectrumClient {
Timer _aliveTimer; Timer _aliveTimer;
String unterminatedString; String unterminatedString;
Future<void> connectToUri(String uri) async { Future<void> connectToUri(Uri uri) async =>
final splittedUri = uri.split(':'); await connect(host: uri.host, port: uri.port);
if (splittedUri.length != 2) {
throw UriParseException(uri);
}
final host = splittedUri.first;
final port = int.parse(splittedUri.last);
await connect(host: host, port: port);
}
Future<void> connect({@required String host, @required int port}) async { Future<void> connect({@required String host, @required int port}) async {
try { try {

View file

@ -149,7 +149,7 @@ Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
final nodeToReplace = replaceNodes[node.uri]; final nodeToReplace = replaceNodes[node.uri];
if (nodeToReplace != null) { if (nodeToReplace != null) {
node.uri = nodeToReplace.uri; node.uriRaw = nodeToReplace.uriRaw;
node.login = nodeToReplace.login; node.login = nodeToReplace.login;
node.password = nodeToReplace.password; node.password = nodeToReplace.password;
await node.save(); await node.save();
@ -319,11 +319,11 @@ Future<void> changeDefaultMoneroNode(
final currentMoneroNode = final currentMoneroNode =
nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId); nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId);
final needToReplaceCurrentMoneroNode = final needToReplaceCurrentMoneroNode =
currentMoneroNode.uri.contains(cakeWalletMoneroNodeUriPattern); currentMoneroNode.uri.toString().contains(cakeWalletMoneroNodeUriPattern);
nodeSource.values.forEach((node) async { nodeSource.values.forEach((node) async {
if (node.type == WalletType.monero && if (node.type == WalletType.monero &&
node.uri.contains(cakeWalletMoneroNodeUriPattern)) { node.uri.toString().contains(cakeWalletMoneroNodeUriPattern)) {
await node.delete(); await node.delete();
} }
}); });
@ -389,10 +389,10 @@ Future<void> resetBitcoinElectrumServer(
final currentElectrumSeverId = final currentElectrumSeverId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final oldElectrumServer = nodeSource.values.firstWhere( final oldElectrumServer = nodeSource.values.firstWhere(
(node) => node.uri.contains('electrumx.cakewallet.com'), (node) => node.uri.toString().contains('electrumx.cakewallet.com'),
orElse: () => null); orElse: () => null);
var cakeWalletNode = nodeSource.values.firstWhere( var cakeWalletNode = nodeSource.values.firstWhere(
(node) => node.uri == cakeWalletBitcoinElectrumUri, (node) => node.uri.toString() == cakeWalletBitcoinElectrumUri,
orElse: () => null); orElse: () => null);
if (cakeWalletNode == null) { if (cakeWalletNode == null) {

View file

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:cake_wallet/utils/mobx.dart'; import 'package:cake_wallet/utils/mobx.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'dart:convert'; import 'dart:convert';
@ -8,19 +10,23 @@ import 'package:cake_wallet/entities/digest_request.dart';
part 'node.g.dart'; part 'node.g.dart';
Uri createUriFromElectrumAddress(String address) =>
Uri.tryParse('tcp://$address');
@HiveType(typeId: Node.typeId) @HiveType(typeId: Node.typeId)
class Node extends HiveObject with Keyable { class Node extends HiveObject with Keyable {
Node( Node(
{@required this.uri, {@required String uri,
@required WalletType type, @required WalletType type,
this.login, this.login,
this.password, this.password,
this.useSSL}) { this.useSSL}) {
uriRaw = uri;
this.type = type; this.type = type;
} }
Node.fromMap(Map map) Node.fromMap(Map map)
: uri = map['uri'] as String ?? '', : uriRaw = map['uri'] as String ?? '',
login = map['login'] as String, login = map['login'] as String,
password = map['password'] as String, password = map['password'] as String,
typeRaw = map['typeRaw'] as int, typeRaw = map['typeRaw'] as int,
@ -30,7 +36,7 @@ class Node extends HiveObject with Keyable {
static const boxName = 'Nodes'; static const boxName = 'Nodes';
@HiveField(0) @HiveField(0)
String uri; String uriRaw;
@HiveField(1) @HiveField(1)
String login; String login;
@ -46,6 +52,19 @@ class Node extends HiveObject with Keyable {
bool get isSSL => useSSL ?? false; bool get isSSL => useSSL ?? false;
Uri get uri {
switch (type) {
case WalletType.monero:
return Uri.http(uriRaw, '');
case WalletType.bitcoin:
return createUriFromElectrumAddress(uriRaw);
case WalletType.litecoin:
return createUriFromElectrumAddress(uriRaw);
default:
return null;
}
}
@override @override
dynamic get keyIndex { dynamic get keyIndex {
_keyIndex ??= key; _keyIndex ??= key;
@ -64,7 +83,9 @@ class Node extends HiveObject with Keyable {
case WalletType.monero: case WalletType.monero:
return requestMoneroNode(); return requestMoneroNode();
case WalletType.bitcoin: case WalletType.bitcoin:
return requestBitcoinElectrumServer(); return requestElectrumServer();
case WalletType.litecoin:
return requestElectrumServer();
default: default:
return false; return false;
} }
@ -80,15 +101,15 @@ class Node extends HiveObject with Keyable {
if (login != null && password != null) { if (login != null && password != null) {
final digestRequest = DigestRequest(); final digestRequest = DigestRequest();
final response = await digestRequest.request( final response = await digestRequest.request(
uri: uri, login: login, password: password); uri: uri.toString(), login: login, password: password);
resBody = response.data as Map<String, dynamic>; resBody = response.data as Map<String, dynamic>;
} else { } else {
final url = Uri.http(uri, '/json_rpc'); final rpcUri = Uri.http(uri.toString(), '/json_rpc');
final headers = {'Content-type': 'application/json'}; final headers = {'Content-type': 'application/json'};
final body = final body =
json.encode({'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'}); json.encode({'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'});
final response = final response =
await http.post(url.toString(), headers: headers, body: body); await http.post(rpcUri.toString(), headers: headers, body: body);
resBody = json.decode(response.body) as Map<String, dynamic>; resBody = json.decode(response.body) as Map<String, dynamic>;
} }
@ -98,8 +119,13 @@ class Node extends HiveObject with Keyable {
} }
} }
Future<bool> requestBitcoinElectrumServer() async { Future<bool> requestElectrumServer() async {
// FIXME: IMPLEMENT ME try {
return true; await SecureSocket.connect(uri.host, uri.port,
timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
return true;
} catch (_) {
return false;
}
} }
} }

View file

@ -152,7 +152,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
try { try {
syncStatus = ConnectingSyncStatus(); syncStatus = ConnectingSyncStatus();
await monero_wallet.setupNode( await monero_wallet.setupNode(
address: node.uri, address: node.uri.toString(),
login: node.login, login: node.login,
password: node.password, password: node.password,
useSSL: node.isSSL, useSSL: node.isSSL,

View file

@ -7,19 +7,22 @@ import 'package:connectivity/connectivity.dart';
Timer _checkConnectionTimer; Timer _checkConnectionTimer;
void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore, {int timeInterval = 5}) { void startCheckConnectionReaction(
WalletBase wallet, SettingsStore settingsStore,
{int timeInterval = 5}) {
_checkConnectionTimer?.cancel(); _checkConnectionTimer?.cancel();
_checkConnectionTimer = Timer.periodic(Duration(seconds: timeInterval), (_) async { _checkConnectionTimer =
final connectivityResult = await (Connectivity().checkConnectivity()); Timer.periodic(Duration(seconds: timeInterval), (_) async {
try {
final connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) { if (connectivityResult == ConnectivityResult.none) {
wallet.syncStatus = FailedSyncStatus(); wallet.syncStatus = FailedSyncStatus();
return; return;
} }
if (wallet.syncStatus is LostConnectionSyncStatus || if (wallet.syncStatus is LostConnectionSyncStatus ||
wallet.syncStatus is FailedSyncStatus) { wallet.syncStatus is FailedSyncStatus) {
try {
final alive = final alive =
await settingsStore.getCurrentNode(wallet.type).requestNode(); await settingsStore.getCurrentNode(wallet.type).requestNode();
@ -27,9 +30,9 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore
await wallet.connectToNode( await wallet.connectToNode(
node: settingsStore.getCurrentNode(wallet.type)); node: settingsStore.getCurrentNode(wallet.type));
} }
} catch (_) {
// FIXME: empty catch clojure
} }
} catch (e) {
print(e.toString());
} }
}); });
} }

View file

@ -87,7 +87,7 @@ class NodeListPage extends BasePage {
final isSelected = final isSelected =
node.keyIndex == nodeListViewModel.currentNode?.keyIndex; node.keyIndex == nodeListViewModel.currentNode?.keyIndex;
final nodeListRow = NodeListRow( final nodeListRow = NodeListRow(
title: node.uri, title: node.uriRaw,
isSelected: isSelected, isSelected: isSelected,
isAlive: node.requestNode(), isAlive: node.requestNode(),
onTap: (_) async { onTap: (_) async {
@ -101,8 +101,9 @@ class NodeListPage extends BasePage {
return AlertWithTwoActions( return AlertWithTwoActions(
alertTitle: alertTitle:
S.of(context).change_current_node_title, S.of(context).change_current_node_title,
alertContent: alertContent: S
S.of(context).change_current_node(node.uri), .of(context)
.change_current_node(node.uriRaw),
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change, rightButtonText: S.of(context).change,
actionLeftButton: () => actionLeftButton: () =>