mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-23 19:16:09 +00:00
Fixes for LTC electrum nodes available.
This commit is contained in:
parent
9f9ec91eba
commit
1cb27d9da3
7 changed files with 64 additions and 53 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: () =>
|
||||||
|
|
Loading…
Reference in a new issue