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));
            }
        }
Exemple #2
0
        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));
            }
        }