public async Task <IActionResult> GetTransactionsAsync([FromQuery, Required] IEnumerable <string> transactionIds) { if (!ModelState.IsValid) { return(BadRequest("Invalid transaction Ids.")); } var maxTxToRequest = 10; if (transactionIds.Count() > maxTxToRequest) { return(BadRequest($"Maximum {maxTxToRequest} transactions can be requested.")); } var parsedIds = new List <uint256>(); try { // Remove duplicates, do not use Distinct(), order is not guaranteed. foreach (var txid in transactionIds.Select(x => new uint256(x))) { if (!parsedIds.Contains(txid)) { parsedIds.Add(txid); } } } catch { return(BadRequest("Invalid transaction Ids.")); } try { var hexes = new Dictionary <uint256, string>(); var queryRpc = false; IRPCClient batchingRpc = null; List <Task <Transaction> > tasks = null; lock (TransactionHexCacheLock) { foreach (var txid in parsedIds) { if (TransactionHexCache.TryGetValue(txid, out string hex)) { hexes.Add(txid, hex); } else { if (!queryRpc) { queryRpc = true; batchingRpc = RpcClient.PrepareBatch(); tasks = new List <Task <Transaction> >(); } tasks.Add(batchingRpc.GetRawTransactionAsync(txid)); } } } if (queryRpc) { await batchingRpc.SendBatchAsync(); foreach (var tx in await Task.WhenAll(tasks)) { string hex = tx.ToHex(); hexes.Add(tx.GetHash(), hex); lock (TransactionHexCacheLock) { if (TransactionHexCache.TryAdd(tx.GetHash(), hex) && TransactionHexCache.Count >= 1000) { TransactionHexCache.Remove(TransactionHexCache.Keys.First()); } } } } // Order hexes according to the order of the query. var orderedResult = parsedIds.Where(x => hexes.ContainsKey(x)).Select(x => hexes[x]); return(Ok(orderedResult)); } catch (Exception ex) { Logger.LogDebug(ex); return(BadRequest(ex.Message)); } }
public async Task <IActionResult> GetTransactionsAsync([FromQuery, Required] IEnumerable <string> transactionIds) { var maxTxToRequest = 10; if (transactionIds.Count() > maxTxToRequest) { return(BadRequest($"Maximum {maxTxToRequest} transactions can be requested.")); } var parsedIds = new List <uint256>(); try { // Remove duplicates, do not use Distinct(), order is not guaranteed. foreach (var txid in transactionIds.Select(x => new uint256(x))) { if (!parsedIds.Contains(txid)) { parsedIds.Add(txid); } } } catch { return(BadRequest("Invalid transaction Ids.")); } try { var hexes = new Dictionary <uint256, string>(); List <uint256> missingTxs = new(); lock (TransactionHexCacheLock) { foreach (var txid in parsedIds) { if (TransactionHexCache.TryGetValue(txid, out string?hex)) { hexes.Add(txid, hex); } else { missingTxs.Add(txid); } } } if (missingTxs.Any()) { foreach (var tx in await RpcClient.GetRawTransactionsAsync(missingTxs, CancellationToken.None)) { string hex = tx.ToHex(); hexes.Add(tx.GetHash(), hex); lock (TransactionHexCacheLock) { if (TransactionHexCache.TryAdd(tx.GetHash(), hex) && TransactionHexCache.Count >= 1000) { TransactionHexCache.Remove(TransactionHexCache.Keys.First()); } } } } // Order hexes according to the order of the query. var orderedResult = parsedIds.Where(x => hexes.ContainsKey(x)).Select(x => hexes[x]); return(Ok(orderedResult)); } catch (Exception ex) { Logger.LogDebug(ex); return(BadRequest(ex.Message)); } }