fallback for UTXO fetch failures

This commit is contained in:
Serhii 2024-12-19 13:01:47 +02:00
parent c160884dfa
commit 0bb022ac30
2 changed files with 60 additions and 11 deletions

View file

@ -235,7 +235,7 @@ class ElectrumClient {
return [];
});
Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) async {
Future<List<Map<String, dynamic>>?> getListUnspent(String scriptHash) async {
final result = await call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]);
if (result is List) {
@ -248,7 +248,7 @@ class ElectrumClient {
}).toList();
}
return [];
return null;
}
Future<List<Map<String, dynamic>>> getMempool(String scriptHash) =>

View file

@ -1359,6 +1359,7 @@ abstract class ElectrumWalletBase
@action
Future<void> updateAllUnspents() async {
List<BitcoinUnspent> updatedUnspentCoins = [];
final previousUnspentCoins = List<BitcoinUnspent>.from(unspentCoins);
if (hasSilentPaymentsScanning) {
// Update unspents stored from scanned silent payment transactions
@ -1376,13 +1377,27 @@ abstract class ElectrumWalletBase
if (addr is! BitcoinSilentPaymentAddressRecord) addr.balance = 0;
});
await Future.wait(walletAddresses.allAddresses
final addressFutures = walletAddresses.allAddresses
.where((element) => element.type != SegwitAddresType.mweb)
.map((address) async {
updatedUnspentCoins.addAll(await fetchUnspent(address));
}));
.map((address) => fetchUnspent(address))
.toList();
unspentCoins = updatedUnspentCoins;
final results = await Future.wait(addressFutures);
final failedCount = results.where((result) => result == null).length;
if (failedCount == 0) {
for (final result in results) {
updatedUnspentCoins.addAll(result!);
}
unspentCoins = updatedUnspentCoins;
} else {
unspentCoins = handleFailedUtxoFetch(
failedCount: failedCount,
previousUnspentCoins: previousUnspentCoins,
updatedUnspentCoins: updatedUnspentCoins,
results: results,
);
}
final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId == id);
@ -1395,6 +1410,38 @@ abstract class ElectrumWalletBase
await _refreshUnspentCoinsInfo();
}
List<BitcoinUnspent> handleFailedUtxoFetch({
required int failedCount,
required List<BitcoinUnspent> previousUnspentCoins,
required List<BitcoinUnspent> updatedUnspentCoins,
required List<List<BitcoinUnspent>?> results,
}) {
if (failedCount == results.length) {
printV("All UTXOs failed to fetch, falling back to previous UTXOs");
return previousUnspentCoins;
}
final successfulUtxos = <BitcoinUnspent>[];
for (final result in results) {
if (result != null) {
successfulUtxos.addAll(result);
}
}
if (failedCount > 0 && successfulUtxos.isEmpty) {
printV("Some UTXOs failed, but no successful UTXOs, falling back to previous UTXOs");
return previousUnspentCoins;
}
if (failedCount > 0) {
printV("Some UTXOs failed, updating with successful UTXOs");
updatedUnspentCoins.addAll(successfulUtxos);
}
return updatedUnspentCoins;
}
Future<void> updateCoins(List<BitcoinUnspent> newUnspentCoins) async {
if (newUnspentCoins.isEmpty) {
return;
@ -1426,15 +1473,17 @@ abstract class ElectrumWalletBase
@action
Future<void> updateUnspentsForAddress(BitcoinAddressRecord address) async {
final newUnspentCoins = await fetchUnspent(address);
await updateCoins(newUnspentCoins);
await updateCoins(newUnspentCoins ?? []);
}
@action
Future<List<BitcoinUnspent>> fetchUnspent(BitcoinAddressRecord address) async {
List<Map<String, dynamic>> unspents = [];
Future<List<BitcoinUnspent>?> fetchUnspent(BitcoinAddressRecord address) async {
List<BitcoinUnspent> updatedUnspentCoins = [];
unspents = await electrumClient.getListUnspent(address.getScriptHash(network));
final unspents = await electrumClient.getListUnspent(address.getScriptHash(network));
// Failed to fetch unspents
if (unspents == null) return null;
await Future.wait(unspents.map((unspent) async {
try {