예제 #1
0
    public async Task AddNewFiltersAsync(IEnumerable <FilterModel> filters, CancellationToken cancel)
    {
        var successAny = false;

        foreach (var filter in filters)
        {
            var success = false;

            using (await IndexLock.LockAsync(cancel).ConfigureAwait(false))
            {
                success = TryProcessFilter(filter, enqueue: true);
            }
            successAny = successAny || success;

            if (success)
            {
                NewFilter?.Invoke(this, filter);                 // Event always outside the lock.
            }
        }

        if (successAny)
        {
            AbandonedTasks.AddAndClearCompleted(TryCommitToFileAsync(TimeSpan.FromSeconds(3), cancel));
        }
    }
예제 #2
0
        public async Task AddNewFiltersAsync(IEnumerable <FilterModel> filters, CancellationToken cancel)
        {
            foreach (var filter in filters)
            {
                using (await IndexLock.LockAsync())
                {
                    ProcessFilter(filter, enqueue: true);
                }

                NewFilter?.Invoke(this, filter);                 // Event always outside the lock.
            }

            _ = TryCommitToFileAsync(TimeSpan.FromSeconds(3), cancel);
        }
예제 #3
0
        public void Synchronize(TimeSpan requestInterval)
        {
            Guard.NotNull(nameof(requestInterval), requestInterval);
            Interlocked.Exchange(ref _running, 1);

            Task.Run(async() =>
            {
                FilterModel bestKnownFilter = null;

                try
                {
                    while (IsRunning)
                    {
                        try
                        {
                            // If stop was requested return.
                            if (IsRunning == false)
                            {
                                return;
                            }

                            using (await IndexLock.LockAsync())
                            {
                                bestKnownFilter = Index.Last();
                            }

                            var filters = await WasabiClient.GetFiltersAsync(bestKnownFilter.BlockHash, 1000);

                            if (!filters.Any())
                            {
                                continue;
                            }
                            using (await IndexLock.LockAsync())
                            {
                                var filtersList = filters.ToList();                                 // performance
                                for (int i = 0; i < filtersList.Count; i++)
                                {
                                    var filterModel = FilterModel.FromLine(filtersList[i], bestKnownFilter.BlockHeight + i + 1);

                                    Index.Add(filterModel);
                                    NewFilter?.Invoke(this, filterModel);
                                }

                                if (filtersList.Count == 1)                                 // minor optimization
                                {
                                    await File.AppendAllLinesAsync(IndexFilePath, new[] { Index.Last().ToLine() });
                                }
                                else
                                {
                                    await File.WriteAllLinesAsync(IndexFilePath, Index.Select(x => x.ToLine()));
                                }

                                Logger.LogInfo <IndexDownloader>($"Downloaded filters for blocks from {bestKnownFilter.BlockHeight.Value + 1} to {Index.Last().BlockHeight}.");
                            }

                            continue;
                        }
                        catch (HttpRequestException ex) when(ex.Message.StartsWith(HttpStatusCode.NotFound.ToReasonString()))
                        {
                            // Reorg happened
                            var reorgedHash = bestKnownFilter.BlockHash;
                            Logger.LogInfo <IndexDownloader>($"REORG Invalid Block: {reorgedHash}");
                            // 1. Rollback index
                            using (await IndexLock.LockAsync())
                            {
                                Index.RemoveAt(Index.Count - 1);
                            }

                            Reorged?.Invoke(this, reorgedHash);

                            // 2. Serialize Index. (Remove last line.)
                            var lines = File.ReadAllLines(IndexFilePath);
                            File.WriteAllLines(IndexFilePath, lines.Take(lines.Length - 1).ToArray());

                            // 3. Skip the last valid block.
                            continue;
                        }
                        catch (Exception ex)
                        {
                            Logger.LogError <IndexDownloader>(ex);
                        }
                        finally
                        {
                            await Task.Delay(requestInterval);                             // Ask for new index in every requestInterval.
                        }
                    }
                }
                finally
                {
                    if (IsStopping)
                    {
                        Interlocked.Exchange(ref _running, 3);
                    }
                }
            });
        }
예제 #4
0
 private void OnNewFilter(FilterModel filter) => NewFilter?.Invoke(this, filter);
예제 #5
0
        public void Synchronize(TimeSpan requestInterval)
        {
            Guard.NotNull(nameof(requestInterval), requestInterval);
            Interlocked.Exchange(ref _running, 1);

            Task.Run(async() =>
            {
                try
                {
                    while (IsRunning)
                    {
                        try
                        {
                            // If stop was requested return.
                            if (IsRunning == false)
                            {
                                return;
                            }

                            FilterModel bestKnownFilter;
                            using (await IndexLock.LockAsync())
                            {
                                bestKnownFilter = Index.Last();
                            }

                            var response = await Client.SendAsync(HttpMethod.Get, $"/api/v1/btc/blockchain/filters?bestKnownBlockHash={bestKnownFilter.BlockHash}&count=1000");

                            if (response.StatusCode == HttpStatusCode.NoContent)
                            {
                                continue;
                            }
                            if (response.StatusCode == HttpStatusCode.OK)
                            {
                                var filters = await response.Content.ReadAsJsonAsync <List <string> >();
                                using (await IndexLock.LockAsync())
                                {
                                    for (int i = 0; i < filters.Count; i++)
                                    {
                                        var filterModel = FilterModel.FromLine(filters[i], bestKnownFilter.BlockHeight + i + 1);

                                        Index.Add(filterModel);
                                        NewFilter?.Invoke(this, filterModel);
                                    }

                                    if (filters.Count == 1)                                     // minor optimization
                                    {
                                        await File.AppendAllLinesAsync(IndexFilePath, new[] { Index.Last().ToLine() });
                                    }
                                    else
                                    {
                                        await File.WriteAllLinesAsync(IndexFilePath, Index.Select(x => x.ToLine()));
                                    }

                                    Logger.LogInfo <IndexDownloader>($"Downloaded filters for blocks from {bestKnownFilter.BlockHeight.Value + 1} to {Index.Last().BlockHeight}.");
                                }

                                continue;
                            }
                            else if (response.StatusCode == HttpStatusCode.NotFound)
                            {
                                // Reorg happened
                                var reorgedHash = bestKnownFilter.BlockHash;
                                Logger.LogInfo <IndexDownloader>($"REORG Invalid Block: {reorgedHash}");
                                // 1. Rollback index
                                using (await IndexLock.LockAsync())
                                {
                                    Index.RemoveAt(Index.Count - 1);
                                }

                                Reorged?.Invoke(this, reorgedHash);

                                // 2. Serialize Index. (Remove last line.)
                                var lines = File.ReadAllLines(IndexFilePath);
                                File.WriteAllLines(IndexFilePath, lines.Take(lines.Length - 1).ToArray());

                                // 3. Skip the last valid block.
                                continue;
                            }
                            else
                            {
                                var error = await response.Content.ReadAsStringAsync();
                                throw new HttpRequestException($"{response.StatusCode.ToReasonString()}: {error}");
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.LogError <IndexDownloader>(ex);
                        }
                        finally
                        {
                            await Task.Delay(requestInterval);                             // Ask for new index in every requestInterval.
                        }
                    }
                }
                finally
                {
                    if (IsStopping)
                    {
                        Interlocked.Exchange(ref _running, 3);
                    }
                }
            });
        }