This commit is contained in:
M 2020-08-29 13:19:27 +03:00
parent 6aaac93fa8
commit 24d139e540
11 changed files with 114 additions and 31 deletions

View file

@ -373,7 +373,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 9; CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = 32J6BB6VUS; DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -509,7 +509,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 9; CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = 32J6BB6VUS; DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -540,7 +540,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 9; CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = 32J6BB6VUS; DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (

View file

@ -16,12 +16,13 @@ class BitcoinTransactionInfo extends TransactionInfo {
@required TransactionDirection direction, @required TransactionDirection direction,
@required bool isPending, @required bool isPending,
@required DateTime date, @required DateTime date,
@required this.confirmations}) { @required int confirmations}) {
this.height = height; this.height = height;
this.amount = amount; this.amount = amount;
this.direction = direction; this.direction = direction;
this.date = date; this.date = date;
this.isPending = isPending; this.isPending = isPending;
this.confirmations = confirmations;
} }
factory BitcoinTransactionInfo.fromElectrumVerbose(Map<String, Object> obj, factory BitcoinTransactionInfo.fromElectrumVerbose(Map<String, Object> obj,
@ -119,7 +120,6 @@ class BitcoinTransactionInfo extends TransactionInfo {
} }
final String id; final String id;
int confirmations;
String _fiatAmount; String _fiatAmount;

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:convert'; import 'dart:convert';
import 'package:cake_wallet/bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_credentials.dart';
@ -31,9 +32,12 @@ import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/core/wallet_base.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
import 'package:cake_wallet/di.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'bitcoin_wallet.g.dart'; part 'bitcoin_wallet.g.dart';
class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet; class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet;
abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store { abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
@ -217,6 +221,11 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
try { try {
syncStatus = ConnectingSyncStatus(); syncStatus = ConnectingSyncStatus();
await eclient.connectToUri(node.uri); await eclient.connectToUri(node.uri);
eclient.onConnectionStatusChange = (bool isConnected) {
if (!isConnected) {
syncStatus = LostConnectionSyncStatus();
}
};
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
@ -331,7 +340,6 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
await _scripthashesUpdateSubject[sh]?.close(); await _scripthashesUpdateSubject[sh]?.close();
_scripthashesUpdateSubject[sh] = eclient.scripthashUpdate(sh); _scripthashesUpdateSubject[sh] = eclient.scripthashUpdate(sh);
_scripthashesUpdateSubject[sh].listen((event) async { _scripthashesUpdateSubject[sh].listen((event) async {
print('event $event');
transactionHistory.updateAsync(); transactionHistory.updateAsync();
await _updateBalance(); await _updateBalance();
}); });

View file

@ -32,6 +32,7 @@ class ElectrumClient {
bool get isConnected => _isConnected; bool get isConnected => _isConnected;
Socket socket; Socket socket;
void Function(bool) onConnectionStatusChange;
int _id; int _id;
final Map<String, SocketTask> _tasks; final Map<String, SocketTask> _tasks;
bool _isConnected; bool _isConnected;
@ -45,50 +46,49 @@ class ElectrumClient {
} }
Future<void> connect({@required String host, @required int port}) async { Future<void> connect({@required String host, @required int port}) async {
await socket?.close(); try {
final start = DateTime.now(); await socket?.close();
} catch (_) {}
socket = await SecureSocket.connect(host, port, timeout: connectionTimeout); socket = await SecureSocket.connect(host, port, timeout: connectionTimeout);
_setIsConnected(true);
_isConnected = true;
socket.listen((List<int> event) { socket.listen((List<int> event) {
try { try {
final jsoned = json.decode(utf8.decode(event)) as Map<String, Object>; final jsoned = json.decode(utf8.decode(event)) as Map<String, Object>;
// print(jsoned); print(jsoned);
final method = jsoned['method']; final method = jsoned['method'];
final id = jsoned['id'] as String;
final params = jsoned['result'];
if (method is String) { if (method is String) {
_methodHandler(method: method, request: jsoned); _methodHandler(method: method, request: jsoned);
return; return;
} }
final id = jsoned['id'] as String;
final params = jsoned['result'];
_finish(id, params); _finish(id, params);
} catch (e) { } catch (e) {
print(e); print(e);
} }
}, onError: (Object error) { },
print('ElectrumClient error: ${error.toString()}'); onError: (_) => _setIsConnected(false),
}, onDone: () { onDone: () => _setIsConnected(false));
final end = DateTime.now();
final diff = end.millisecondsSinceEpoch - start.millisecondsSinceEpoch;
print('On done: $diff');
});
print('Connected to ${socket.remoteAddress}');
keepAlive(); keepAlive();
} }
void keepAlive() { void keepAlive() {
_aliveTimer?.cancel(); _aliveTimer?.cancel();
// FIXME: Unnamed constant. // FIXME: Unnamed constant.
_aliveTimer = Timer.periodic(Duration(seconds: 30), (_) async => ping()); _aliveTimer = Timer.periodic(Duration(seconds: 2), (_) async => ping());
} }
Future<void> ping() => call(method: 'server.ping'); Future<void> ping() async {
try {
await callWithTimeout(method: 'server.ping');
_setIsConnected(true);
} on RequestFailedTimeoutException catch (_) {
_setIsConnected(false);
}
}
Future<List<String>> version() => Future<List<String>> version() =>
call(method: 'server.version').then((dynamic result) { call(method: 'server.version').then((dynamic result) {
@ -205,7 +205,6 @@ class ElectrumClient {
{@required String transactionRaw}) async => {@required String transactionRaw}) async =>
call(method: 'blockchain.transaction.broadcast', params: [transactionRaw]) call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
.then((dynamic result) { .then((dynamic result) {
print('result $result');
if (result is String) { if (result is String) {
return result; return result;
} }
@ -264,6 +263,25 @@ class ElectrumClient {
return completer.future; return completer.future;
} }
Future<dynamic> callWithTimeout(
{String method,
List<Object> params = const [],
int timeout = 2000}) async {
final completer = Completer<dynamic>();
_id += 1;
final id = _id;
_regisryTask(id, completer);
socket.write(jsonrpc(method: method, id: _id, params: params));
Timer(Duration(milliseconds: timeout), () {
if (!completer.isCompleted) {
completer.completeError(RequestFailedTimeoutException(method, _id));
}
});
return completer.future;
}
void request({String method, List<Object> params = const []}) { void request({String method, List<Object> params = const []}) {
_id += 1; _id += 1;
socket.write(jsonrpc(method: method, id: _id, params: params)); socket.write(jsonrpc(method: method, id: _id, params: params));
@ -280,7 +298,9 @@ class ElectrumClient {
return; return;
} }
_tasks[id]?.completer?.complete(data); if (!(_tasks[id]?.completer?.isCompleted ?? false)) {
_tasks[id]?.completer?.complete(data);
}
if (!(_tasks[id]?.isSubscription ?? false)) { if (!(_tasks[id]?.isSubscription ?? false)) {
_tasks[id] = null; _tasks[id] = null;
@ -303,4 +323,19 @@ class ElectrumClient {
break; break;
} }
} }
void _setIsConnected(bool isConnected) {
if (_isConnected != isConnected) {
onConnectionStatusChange?.call(isConnected);
}
_isConnected = isConnected;
}
}
class RequestFailedTimeoutException implements Exception {
RequestFailedTimeoutException(this.method, this.id);
final String method;
final int id;
} }

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart'; import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -49,6 +51,7 @@ ReactionDisposer _initialAuthReaction;
ReactionDisposer _onCurrentWalletChangeReaction; ReactionDisposer _onCurrentWalletChangeReaction;
ReactionDisposer _onWalletSyncStatusChangeReaction; ReactionDisposer _onWalletSyncStatusChangeReaction;
ReactionDisposer _onCurrentFiatCurrencyChangeDisposer; ReactionDisposer _onCurrentFiatCurrencyChangeDisposer;
Timer _reconnectionTimer;
Future<void> bootstrap( Future<void> bootstrap(
{FiatConvertationService fiatConvertationService}) async { {FiatConvertationService fiatConvertationService}) async {
@ -74,10 +77,21 @@ Future<void> bootstrap(
_onCurrentWalletChangeReaction ??= _onCurrentWalletChangeReaction ??=
reaction((_) => getIt.get<AppStore>().wallet, (WalletBase wallet) async { reaction((_) => getIt.get<AppStore>().wallet, (WalletBase wallet) async {
_onWalletSyncStatusChangeReaction?.reaction?.dispose(); _onWalletSyncStatusChangeReaction?.reaction?.dispose();
_reconnectionTimer?.cancel();
_onWalletSyncStatusChangeReaction = reaction( _onWalletSyncStatusChangeReaction = reaction(
(_) => wallet.syncStatus is ConnectedSyncStatus, (_) => wallet.syncStatus is ConnectedSyncStatus,
(_) async => await wallet.startSync()); (_) async => await wallet.startSync());
_reconnectionTimer = Timer.periodic(Duration(seconds: 5), (_) async {
if (wallet.syncStatus is LostConnectionSyncStatus ||
wallet.syncStatus is FailedSyncStatus) {
try {
await wallet.connectToNode(
node: settingsStore.getCurrentNode(wallet.type));
} catch (_) {}
}
});
await getIt await getIt
.get<SharedPreferences>() .get<SharedPreferences>()
.setString('current_wallet_name', wallet.name); .setString('current_wallet_name', wallet.name);

View file

@ -73,3 +73,11 @@ class ConnectedSyncStatus extends SyncStatus {
@override @override
String title() => S.current.sync_status_connected; String title() => S.current.sync_status_connected;
} }
class LostConnectionSyncStatus extends SyncStatus {
@override
double progress() => 1.0;
@override
String title() => S.current.sync_status_failed_connect;
}

View file

@ -7,6 +7,7 @@ abstract class TransactionInfo extends Object {
bool isPending; bool isPending;
DateTime date; DateTime date;
int height; int height;
int confirmations;
String amountFormatted(); String amountFormatted();
String fiatAmount(); String fiatAmount();
void changeFiatAmount(String amount); void changeFiatAmount(String amount);

View file

@ -159,7 +159,8 @@ class SendFormState extends State<SendForm> {
decoration: InputDecoration( decoration: InputDecoration(
prefixIcon: Padding( prefixIcon: Padding(
padding: EdgeInsets.only(top: 12), padding: EdgeInsets.only(top: 12),
child: Text('${widget.sendViewModel.currency.toString()}:', child: Text(
'${widget.sendViewModel.currency.toString()}:',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -213,7 +214,14 @@ class SendFormState extends State<SendForm> {
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).dividerColor, color: Theme.of(context).dividerColor,
width: 1.0))), width: 1.0))),
validator: widget.sendViewModel.amountValidator), validator: (String value) {
if (widget.sendViewModel.all) {
return null;
}
return widget.sendViewModel.amountValidator
.call(value);
}),
), ),
Padding( Padding(
padding: const EdgeInsets.only(top: 20), padding: const EdgeInsets.only(top: 20),

View file

@ -1,3 +1,4 @@
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -48,6 +49,9 @@ class TransactionDetailsPage extends BasePage {
StandartListItem( StandartListItem(
title: S.current.transaction_details_date, title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)), value: dateFormat.format(tx.date)),
StandartListItem(
title: 'Confirmations',
value: tx.confirmations?.toString()),
StandartListItem( StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'), title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem( StandartListItem(

View file

@ -86,7 +86,7 @@ abstract class DashboardViewModelBase with Store {
statusText = S.current.Blocks_remaining(status.toString()); statusText = S.current.Blocks_remaining(status.toString());
} }
if (status is FailedSyncStatus) { if (status is FailedSyncStatus || status is LostConnectionSyncStatus) {
statusText = S.current.please_try_to_connect_to_another_node; statusText = S.current.please_try_to_connect_to_another_node;
} }

View file

@ -116,6 +116,11 @@ abstract class SendViewModelBase with Store {
@action @action
void setCryptoAmount(String amount) { void setCryptoAmount(String amount) {
// FIXME: hardcoded value.
if (amount.toUpperCase() != 'ALL') {
all = false;
}
cryptoAmount = amount; cryptoAmount = amount;
_updateFiatAmount(); _updateFiatAmount();
} }