fix: tweak sync percent feature and track progress during spark anon set download

This commit is contained in:
julian 2024-12-15 20:22:39 -06:00 committed by julian-CStack
parent c1ef98833a
commit 1884bfbaf7
4 changed files with 100 additions and 37 deletions

View file

@ -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;
}

View file

@ -564,6 +564,11 @@ abstract class Wallet<T extends CryptoCurrency> {
return future;
}
void _fireRefreshPercentChange(double percent) {
(this as ElectrumXInterface?)?.refreshingPercent = percent;
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(percent, walletId));
}
// Should fire events
Future<void> _refresh(Completer<void> completer) async {
// Awaiting this lock could be dangerous.
@ -612,15 +617,14 @@ abstract class Wallet<T extends CryptoCurrency> {
}
}
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<T extends CryptoCurrency> {
}
}
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<T extends CryptoCurrency> {
.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<T extends CryptoCurrency> {
// 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<T extends CryptoCurrency> {
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) {

View file

@ -42,6 +42,8 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
int? get maximumFeerate => null;
double? refreshingPercent;
static const _kServerBatchCutoffVersion = [1, 6];
List<int>? _serverVersion;
Future<bool> get serverCanBatch async {

View file

@ -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<T extends ElectrumXCurrencyInterface>
}
}
// 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<void> 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<T extends ElectrumXCurrencyInterface>
}
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<T extends ElectrumXCurrencyInterface>
);
}
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<T extends ElectrumXCurrencyInterface>
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<T extends ElectrumXCurrencyInterface>
});
}
if (percentIncrement != null) {
currentPercent = _triggerEventHelper(currentPercent, percentIncrement);
}
// used to check if balance is spendable or total
final currentHeight = await chainHeight;