diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart index 1be577f1d..f8eb344a8 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart @@ -39,6 +39,7 @@ import '../../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../../wallets/wallet/impl/monero_wallet.dart'; import '../../../../wallets/wallet/impl/wownero_wallet.dart'; +import '../../../../wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; import '../../../../widgets/animated_text.dart'; import '../../../../widgets/background.dart'; import '../../../../widgets/conditional_parent.dart'; @@ -233,7 +234,10 @@ class _WalletNetworkSettingsViewState _percent = 1; _blocksRemaining = 0; } else { - _percent = 0; + _percent = + (ref.read(pWallets).getWallet(widget.walletId) as ElectrumXInterface?) + ?.refreshingPercent ?? + 0; _blocksRemaining = -1; } diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 5b8eba8a6..b0516b74e 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -564,6 +564,11 @@ abstract class Wallet { return future; } + void _fireRefreshPercentChange(double percent) { + (this as ElectrumXInterface?)?.refreshingPercent = percent; + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(percent, walletId)); + } + // Should fire events Future _refresh(Completer completer) async { // Awaiting this lock could be dangerous. @@ -612,15 +617,14 @@ abstract class Wallet { } } - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.0, walletId)); - _checkAlive(); + _fireRefreshPercentChange(0); await updateChainHeight(); if (this is BitcoinFrostWallet) { await (this as BitcoinFrostWallet).lookAhead(); } - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.1, walletId)); + _fireRefreshPercentChange(0.1); // TODO: [prio=low] handle this differently. Extra modification of this file for coin specific functionality should be avoided. if (this is MultiAddressInterface) { @@ -630,8 +634,7 @@ abstract class Wallet { } } - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); - _checkAlive(); + _fireRefreshPercentChange(0.2); // TODO: [prio=low] handle this differently. Extra modification of this file for coin specific functionality should be avoided. if (this is MultiAddressInterface) { @@ -640,21 +643,21 @@ abstract class Wallet { .checkChangeAddressForTransactions(); } } - _checkAlive(); - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.3, walletId)); + _fireRefreshPercentChange(0.3); if (this is SparkInterface && !viewOnly) { // this should be called before updateTransactions() - await (this as SparkInterface).refreshSparkData(null); + await (this as SparkInterface).refreshSparkData((0.3, 0.6)); } final fetchFuture = updateTransactions(); - _checkAlive(); + + _fireRefreshPercentChange(0.6); final utxosRefreshFuture = updateUTXOs(); // if (currentHeight != storedHeight) { - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.60, walletId)); + _fireRefreshPercentChange(0.65); await utxosRefreshFuture; - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.70, walletId)); + _fireRefreshPercentChange(0.70); await fetchFuture; @@ -665,8 +668,7 @@ abstract class Wallet { // check utxos again for notification outputs await updateUTXOs(); } - _checkAlive(); - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.80, walletId)); + _fireRefreshPercentChange(0.80); // await getAllTxsToWatch(); @@ -677,16 +679,11 @@ abstract class Wallet { await (this as LelantusInterface).refreshLelantusData(); } } - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.90, walletId)); + _fireRefreshPercentChange(0.90); await updateBalance(); - _checkAlive(); - GlobalEventBus.instance.fire(RefreshPercentChangedEvent(1.0, walletId)); - - if (this is! SparkInterface) { - tAlive = false; // interrupt timer as its not needed anymore - } + _fireRefreshPercentChange(1.0); completer.complete(); } catch (error, strace) { diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart index cc49149d9..b59041ef8 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart @@ -42,6 +42,8 @@ mixin ElectrumXInterface int? get maximumFeerate => null; + double? refreshingPercent; + static const _kServerBatchCutoffVersion = [1, 6]; List? _serverVersion; Future get serverCanBatch async { diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart index 8460ce319..fbc294e7c 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart @@ -14,6 +14,8 @@ import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; import '../../../models/isar/models/isar_models.dart'; import '../../../models/signing_data.dart'; +import '../../../services/event_bus/events/global/refresh_percent_changed_event.dart'; +import '../../../services/event_bus/global_event_bus.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/enums/derive_path_type_enum.dart'; import '../../../utilities/extensions/extensions.dart'; @@ -795,8 +797,24 @@ mixin SparkInterface } } + // returns next percent + double _triggerEventHelper(double current, double increment) { + refreshingPercent = current; + GlobalEventBus.instance.fire( + RefreshPercentChangedEvent( + current, + walletId, + ), + ); + return current + increment; + } + + // Linearly make calls so there is less chance of timing out or otherwise breaking Future refreshSparkData( - void Function(int countFetched, int totalCount)? progressUpdated, + ( + double startingPercent, + double endingPercent, + )? refreshProgressRange, ) async { final start = DateTime.now(); try { @@ -818,25 +836,55 @@ mixin SparkInterface } groupIds.add(latestGroupId); - // start fetch and update process for each set groupId as required - final possibleFutures = groupIds.map( - (e) => - FiroCacheCoordinator.runFetchAndUpdateSparkAnonSetCacheForGroupId( - e, + final steps = groupIds.length + + 1 // get used tags step + + + 1 // check updated cache step + + + 1 // identify coins step + + + 1 // cross ref coins and txns + + + 1; // update balance + + final percentIncrement = refreshProgressRange == null + ? null + : (refreshProgressRange.$2 - refreshProgressRange.$1) / steps; + double currentPercent = refreshProgressRange?.$1 ?? 0; + + // fetch and update process for each set groupId as required + for (final gId in groupIds) { + await FiroCacheCoordinator.runFetchAndUpdateSparkAnonSetCacheForGroupId( + gId, electrumXClient, cryptoCurrency.network, - null, - ), + // null, + (a, b) { + if (percentIncrement != null) { + _triggerEventHelper( + currentPercent + (percentIncrement * (a / b)), + 0, + ); + } + }, + ); + if (percentIncrement != null) { + currentPercent += percentIncrement; + } + } + + if (percentIncrement != null) { + currentPercent = _triggerEventHelper(currentPercent, percentIncrement); + } + + await FiroCacheCoordinator.runFetchAndUpdateSparkUsedCoinTags( + electrumXClient, + cryptoCurrency.network, ); - // wait for each fetch and update to complete - await Future.wait([ - ...possibleFutures, - FiroCacheCoordinator.runFetchAndUpdateSparkUsedCoinTags( - electrumXClient, - cryptoCurrency.network, - ), - ]); + if (percentIncrement != null) { + currentPercent = _triggerEventHelper(currentPercent, percentIncrement); + } // Get cached timestamps per groupId. These timestamps are used to check // and try to id coins that were added to the spark anon set cache @@ -883,6 +931,10 @@ mixin SparkInterface ); } + if (percentIncrement != null) { + currentPercent = _triggerEventHelper(currentPercent, percentIncrement); + } + // get address(es) to get the private key hex strings required for // identifying spark coins final sparkAddresses = await mainDB.isar.addresses @@ -930,6 +982,10 @@ mixin SparkInterface isar: mainDB.isar, ); + if (percentIncrement != null) { + currentPercent = _triggerEventHelper(currentPercent, percentIncrement); + } + // check for spark coins in mempool final mempoolMyCoins = await _refreshSparkCoinsMempoolCheck( privateKeyHexSet: privateKeyHexSet, @@ -991,6 +1047,10 @@ mixin SparkInterface }); } + if (percentIncrement != null) { + currentPercent = _triggerEventHelper(currentPercent, percentIncrement); + } + // used to check if balance is spendable or total final currentHeight = await chainHeight;