computeMissingUTXODetails function

Future<Iterable<UTXOTransaction>> computeMissingUTXODetails({
  1. required Iterable<ElectrumTransactionInfo> txList,
  2. required Iterable<NodeWithAddress> nodes,
  3. required Iterable<AddressType> addressTypes,
  4. required UTXONetworkType type,
  5. required List<(String, int)> endpoints,
})

Implementation

Future<Iterable<UTXOTransaction>> computeMissingUTXODetails({
  required Iterable<ElectrumTransactionInfo> txList,
  required Iterable<NodeWithAddress> nodes,
  required Iterable<AddressType> addressTypes,
  required UTXONetworkType type,
  required List<(String, int)> endpoints,
}) async {
  final coin = type.coin;
  if (txList.isEmpty) return [];

  final watch = Stopwatch()..start();
  final clients = await createClients(endpoints: endpoints, token: coin);

  final batchSize = clients.length;

  if (batchSize == 0) {
    throw Exception(
      "No clients available for fetching UTXO details. for token: ${coin.symbol}",
    );
  }

  final pool = List<ElectrumTransactionInfo>.from(txList);

  final nodeMap = <String, int>{};

  Future<Iterable<UTXOTransaction>> fetchFromPool(
    ElectrumXClient initalClient,
  ) async {
    final txs = <UTXOTransaction>[];
    var client = initalClient;
    while (pool.isNotEmpty) {
      final txInfo = pool.removeLast();

      final (tx, newClient, _) = await fetchFromRandomElectrumXNode(
        (client) {
          return client.getTransaction(
            txHash: txInfo.hash,
            addressTypes: addressTypes,
            nodes: nodes,
            type: type,
          );
        },
        client: client,
        endpoints: endpoints,
        token: coin,
        timeout: Duration(seconds: 5),
      );

      if (tx == null) {
        Logger.logWarning(
            "Failed to fetch TX ${txInfo.hash} from ${client.host}");
        txs.add(txInfo.getNotAvailableUTXOTransaction(type.coin));
        continue;
      }

      if (newClient != null) client = newClient;
      nodeMap[client.host] = (nodeMap[client.host] ?? 0) + 1;
      txs.add(tx);
    }

    return txs;
  }

  final futures = [
    for (final client in clients) fetchFromPool(client),
  ];

  final results = await Future.wait(futures);

  final txs = results.expand((e) => e).toList();

  watch.stop();
  Logger.logFetch(
    "Fetched ${txs.length} transactions in ${watch.elapsed}",
  );

  ///
  /// Disconnect Clients
  ///
  await Future.wait([
    for (final client in clients) client.disconnect(),
  ]);

  return txs;
}