diff --git a/lib/electrumx_rpc/subscribable_electrumx_client.dart b/lib/electrumx_rpc/subscribable_electrumx_client.dart index 67e57f5b8..35f20ad09 100644 --- a/lib/electrumx_rpc/subscribable_electrumx_client.dart +++ b/lib/electrumx_rpc/subscribable_electrumx_client.dart @@ -13,6 +13,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; +import 'package:stackwallet/electrumx_rpc/electrumx_client.dart'; import 'package:stackwallet/utilities/logger.dart'; class ElectrumXSubscription with ChangeNotifier { @@ -60,6 +61,29 @@ class SubscribableElectrumXClient { _keepAlive = keepAlive; } + factory SubscribableElectrumXClient.from({ + required ElectrumXNode node, + // TorService? torService, + }) { + return SubscribableElectrumXClient( + useSSL: node.useSSL, + ); + } + + // Example for returning a future which completes upon connection. + // static Future from({ + // required ElectrumXNode node, + // TorService? torService, + // }) async { + // final client = SubscribableElectrumXClient( + // useSSL: node.useSSL, + // ); + // + // await client.connect(host: node.address, port: node.port); + // + // return client; + // } + Future connect({required String host, required int port}) async { try { await _socket?.close(); @@ -75,7 +99,10 @@ class SubscribableElectrumXClient { true, // TODO do not automatically trust bad certificates. ); } catch (e, s) { - print(s); + Logging.instance.log( + "Error connecting in SubscribableElectrumXClient" + "\nError: $e\nStack trace: $s", + level: LogLevel.Error); } } else { _socket = await Socket.connect( diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart index 0b74f4ed6..d13a90080 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart @@ -7,6 +7,7 @@ import 'package:coinlib_flutter/coinlib_flutter.dart' as coinlib; import 'package:isar/isar.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx_client.dart'; import 'package:stackwallet/electrumx_rpc/electrumx_client.dart'; +import 'package:stackwallet/electrumx_rpc/subscribable_electrumx_client.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/v2/input_v2.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart'; @@ -30,6 +31,7 @@ import 'package:uuid/uuid.dart'; mixin ElectrumXInterface on Bip39HDWallet { late ElectrumXClient electrumXClient; late CachedElectrumXClient electrumXCachedClient; + late SubscribableElectrumXClient subscribableElectrumXClient; int? get maximumFeerate => null; @@ -793,10 +795,47 @@ mixin ElectrumXInterface on Bip39HDWallet { } Future fetchChainHeight() async { + final Completer completer = Completer(); + try { - final result = await electrumXClient.getBlockHeadTip(); - return result["height"] as int; - } catch (e) { + // Subscribe to block headers. + final subscription = + subscribableElectrumXClient.subscribeToBlockHeaders(); + + // Make sure we only complete once. + bool isFirstResponse = true; + + // Add listener. + subscription.addListener(() { + final response = subscription.response; + if (response != null && + response is Map && + response.containsKey('height')) { + final int chainHeight = response['height'] as int; + // print("Current chain height: $chainHeight"); + + if (isFirstResponse) { + isFirstResponse = false; + + // Return the chain height. + completer.complete(chainHeight); + } + } else { + Logging.instance.log( + "blockchain.headers.subscribe returned malformed response\n" + "Response: $response", + level: LogLevel.Error); + } + }); + + // Wait for first response. + return completer.future; + } catch (e, s) { + Logging.instance.log( + "Exception rethrown in fetchChainHeight\nError: $e\nStack trace: $s", + level: LogLevel.Error); + // completer.completeError(e, s); + // return Future.error(e, s); rethrow; } } @@ -865,6 +904,10 @@ mixin ElectrumXInterface on Bip39HDWallet { electrumXCachedClient = CachedElectrumXClient.from( electrumXClient: electrumXClient, ); + subscribableElectrumXClient = SubscribableElectrumXClient.from( + node: newNode, + // torService: torService, + ); } //============================================================================