Beispiel #1
0
        /// <summary>
        /// Tries to perform mempool cleanup with the help of the connected nodes.
        /// NOTE: This results in heavy network activity! https://github.com/zkSNACKs/WalletWasabi/issues/1273
        /// </summary>
        public async Task <bool> TryPerformMempoolCleanupAsync(NodesGroup nodes, CancellationToken cancel)
        {
            // If already cleaning, then no need to run it that often.
            if (Interlocked.CompareExchange(ref _cleanupInProcess, 1, 0) == 1)
            {
                return(false);
            }

            // This function is designed to prevent forever growing mempool.
            try
            {
                if (!TransactionHashes.Any())
                {
                    return(true);                    // There's nothing to cleanup.
                }

                var delay = TimeSpan.FromMinutes(1);
                if (nodes?.ConnectedNodes is null)
                {
                    return(false);
                }

                while (nodes.ConnectedNodes.Count != nodes.MaximumNodeConnection && nodes.ConnectedNodes.All(x => x.IsConnected))
                {
                    if (cancel.IsCancellationRequested)
                    {
                        return(false);
                    }

                    Logger.LogInfo <MemPoolService>($"Not all nodes were in a connected state. Delaying mempool cleanup for {delay.TotalSeconds} seconds...");
                    await Task.Delay(delay, cancel);
                }

                Logger.LogInfo <MemPoolService>("Start cleaning out mempool...");

                var allTxs = new HashSet <uint256>();
                foreach (Node node in nodes.ConnectedNodes)
                {
                    try
                    {
                        if (!node.IsConnected)
                        {
                            continue;
                        }

                        if (cancel.IsCancellationRequested)
                        {
                            return(false);
                        }

                        uint256[] txs = node.GetMempool(cancel);
                        if (cancel.IsCancellationRequested)
                        {
                            return(false);
                        }

                        allTxs.UnionWith(txs);
                        if (cancel.IsCancellationRequested)
                        {
                            return(false);
                        }
                    }
                    catch (Exception ex) when((ex is InvalidOperationException && ex.Message.StartsWith("The node is not in a connected state", StringComparison.InvariantCultureIgnoreCase)) ||
                                              ex is OperationCanceledException ||
                                              ex is TaskCanceledException ||
                                              ex is TimeoutException)
                    {
                        Logger.LogTrace <MemPoolService>(ex);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogDebug <MemPoolService>(ex);
                    }
                }

                int removedTxCount = 0;
                foreach (uint256 tx in TransactionHashes.ToArray())
                {
                    if (!allTxs.Contains(tx))
                    {
                        if (TransactionHashes.TryRemove(tx))
                        {
                            removedTxCount++;
                        }
                    }
                }
                Logger.LogInfo <MemPoolService>($"{removedTxCount} transactions were cleaned from mempool.");

                return(true);
            }
            catch (Exception ex) when(ex is OperationCanceledException ||
                                      ex is TaskCanceledException ||
                                      ex is TimeoutException)
            {
                Logger.LogTrace <MemPoolService>(ex);
            }
            catch (Exception ex)
            {
                Logger.LogDebug <MemPoolService>(ex);
            }
            finally
            {
                Interlocked.Exchange(ref _cleanupInProcess, 0);
            }

            return(false);
        }