예제 #1
0
        private async void Synchronizer_ResponseArrivedAsync(object sender, SynchronizeResponse response)
        {
            try
            {
                using (await ProcessLock.LockAsync())
                {
                    var unconfirmedCoinJoinHashes = response.UnconfirmedCoinJoins;
                    if (!unconfirmedCoinJoinHashes.Any())
                    {
                        return;
                    }

                    var txsNotKnownByAWallet = WalletManager.FilterUnknownCoinjoins(unconfirmedCoinJoinHashes);

                    using var client = new WasabiClient(Synchronizer.WasabiClient.TorClient.DestinationUriAction, Synchronizer.WasabiClient.TorClient.TorSocks5EndPoint);

                    var unconfirmedCoinJoins = await client.GetTransactionsAsync(Synchronizer.Network, txsNotKnownByAWallet, CancellationToken.None).ConfigureAwait(false);

                    foreach (var tx in unconfirmedCoinJoins.Select(x => new SmartTransaction(x, Height.Mempool)))
                    {
                        if (RpcClient is null ||
                            await TryBroadcastTransactionWithRpcAsync(tx).ConfigureAwait(false) ||
                            (await RpcClient.TestAsync().ConfigureAwait(false)) is { })                                // If the test throws exception then I believe it, because RPC is down and the backend is the god.
                        {
                            WalletManager.ProcessCoinJoin(tx);
                        }
                    }
        private async Task BroadcastTransactionToBackendAsync(SmartTransaction transaction)
        {
            Logger.LogInfo("Broadcasting with backend...");
            using (TorHttpClient torHttpClient = Synchronizer.HttpClientFactory.NewBackendTorHttpClient(isolateStream: true))
            {
                var client = new WasabiClient(torHttpClient);

                try
                {
                    await client.BroadcastAsync(transaction).ConfigureAwait(false);
                }
                catch (HttpRequestException ex2) when(RpcErrorTools.IsSpentError(ex2.Message))
                {
                    if (transaction.Transaction.Inputs.Count == 1)                     // If we tried to only spend one coin, then we can mark it as spent. If there were more coins, then we do not know.
                    {
                        OutPoint input = transaction.Transaction.Inputs.First().PrevOut;
                        foreach (var coin in WalletManager.CoinsByOutPoint(input))
                        {
                            coin.SpentAccordingToBackend = true;
                        }
                    }

                    throw;
                }
            }

            BelieveTransaction(transaction);

            Logger.LogInfo($"Transaction is successfully broadcasted to backend: {transaction.GetHash()}.");
        }
        public async Task GetExchangeRateAsync(NetworkType networkType)         // xunit wtf: If this function is called GetExchangeRatesAsync, it'll stuck on 1 CPU VMs (Manjuro, Fedora)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);
            var exchangeRates = await client.GetExchangeRatesAsync();

            Assert.True(exchangeRates.NotNullAndNotEmpty());
        }
        public async Task GetFeesAsync(NetworkType networkType)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);
            var feeEstimationPairs = await client.GetFeesAsync(1000);

            Assert.True(feeEstimationPairs.NotNullAndNotEmpty());
        }
        private async Task BroadcastTransactionToBackendAsync(SmartTransaction transaction)
        {
            Logger.LogInfo("Broadcasting with backend...");
            using (var client = new WasabiClient(Synchronizer.WasabiClient.TorClient.DestinationUriAction, Synchronizer.WasabiClient.TorClient.TorSocks5EndPoint))
            {
                try
                {
                    await client.BroadcastAsync(transaction).ConfigureAwait(false);
                }
                catch (HttpRequestException ex2) when(ex2.Message.Contains("bad-txns-inputs-missingorspent", StringComparison.InvariantCultureIgnoreCase) ||
                                                      ex2.Message.Contains("missing-inputs", StringComparison.InvariantCultureIgnoreCase) ||
                                                      ex2.Message.Contains("txn-mempool-conflict", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (transaction.Transaction.Inputs.Count == 1)                     // If we tried to only spend one coin, then we can mark it as spent. If there were more coins, then we do not know.
                    {
                        OutPoint input = transaction.Transaction.Inputs.First().PrevOut;
                        lock (WalletServicesLock)
                        {
                            foreach (var walletService in AliveWalletServices)
                            {
                                SmartCoin coin = walletService.Coins.GetByOutPoint(input);
                                if (coin != default)
                                {
                                    coin.SpentAccordingToBackend = true;
                                }
                            }
                        }
                    }
                }
            }

            BelieveTransaction(transaction);

            Logger.LogInfo($"Transaction is successfully broadcasted to backend: {transaction.GetHash()}.");
        }
예제 #6
0
        public async Task GetTransactionsTestAsync()
        {
            var mempool = Enumerable.Range(0, 1_100).Select(_ => CreateTransaction()).ToArray();

            Task <HttpResponseMessage> FakeServerCode(HttpMethod method, string action, NameValueCollection parameters, string body)
            {
                Assert.True(parameters.Count <= 10);

                IEnumerable <uint256> requestedTxIds = parameters["transactionIds"].Split(",").Select(x => uint256.Parse(x));
                IEnumerable <string>  result         = mempool.Where(tx => requestedTxIds.Contains(tx.GetHash())).Select(tx => tx.ToHex());

                var response = new HttpResponseMessage(HttpStatusCode.OK);

                response.Content = new StringContent(JsonConvert.SerializeObject(result));
                return(Task.FromResult(response));
            };

            var torHttpClient = new MockTorHttpClient();

            torHttpClient.OnSendAsync = FakeServerCode;
            var client = new WasabiClient(torHttpClient);

            Assert.Empty(WasabiClient.TransactionCache);

            // Requests one transaction
            var searchedTxId = mempool[0].GetHash();
            var txs          = await client.GetTransactionsAsync(Network.Main, new[] { searchedTxId }, CancellationToken.None);

            Assert.Equal(searchedTxId, txs.First().GetHash());
            Assert.NotEmpty(WasabiClient.TransactionCache);
            Assert.True(WasabiClient.TransactionCache.ContainsKey(searchedTxId));

            // Requests 20 transaction
            var searchedTxIds = mempool[..20].Select(x => x.GetHash());
예제 #7
0
        public async Task GetClientVersionAsync()
        {
            using var client = new WasabiClient(new Uri(RegTestFixture.BackendEndPoint), null);
            var uptodate = await client.CheckUpdatesAsync(CancellationToken.None);

            Assert.True(uptodate.BackendCompatible);
            Assert.True(uptodate.ClientUpToDate);
        }
예제 #8
0
        public async Task GetClientVersionAsync()
        {
            var client   = new WasabiClient(BackendHttpClient);
            var uptodate = await client.CheckUpdatesAsync(CancellationToken.None);

            Assert.True(uptodate.BackendCompatible);
            Assert.True(uptodate.ClientUpToDate);
        }
예제 #9
0
        public async Task GetExchangeRatesAsync(NetworkType networkType)
        {
            using (var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType]))
            {
                var exchangeRates = await client.GetExchangeRatesAsync();

                Assert.True(exchangeRates.NotNullAndNotEmpty());
            }
        }
예제 #10
0
        public async Task GetFeesAsync(NetworkType networkType)
        {
            using (var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType]))
            {
                var feeEstimationPairs = await client.GetFeesAsync(1000);

                Assert.True(feeEstimationPairs.NotNullAndNotEmpty());
            }
        }
예제 #11
0
        public async Task GetExchangeRateAsync(NetworkType networkType)         // xunit wtf: If this function is called GetExchangeRatesAsync, it'll stuck on 1 CPU VMs (Manjuro, Fedora)
        {
            using var torHttpClient = MakeTorHttpClient(networkType);
            var client = new WasabiClient(torHttpClient);

            var exchangeRates = await client.GetExchangeRatesAsync();

            Assert.True(exchangeRates.NotNullAndNotEmpty());
        }
예제 #12
0
        /// <summary>
        /// Tries to perform mempool cleanup with the help of the backend.
        /// </summary>
        public async Task <bool> TryPerformMempoolCleanupAsync(Func <Uri> destAction, EndPoint torSocks)
        {
            // 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
            {
                // No need for locking when accessing Count.
                if (ProcessedTransactionHashes.Count == 0)
                {
                    // There's nothing to cleanup.
                    return(true);
                }

                Logger.LogInfo("Start cleaning out mempool...");
                using (var client = new WasabiClient(destAction, torSocks))
                {
                    var compactness      = 10;
                    var allMempoolHashes = await client.GetMempoolHashesAsync(compactness);

                    lock (ProcessedLock)
                    {
                        int removedTxCount = ProcessedTransactionHashes.RemoveWhere(x => !allMempoolHashes.Contains(x.ToString().Substring(0, compactness)));

                        Logger.LogInfo($"{removedTxCount} transactions were cleaned from mempool.");
                    }
                }

                // Display warning if total receives would be reached by duplicated receives.
                // Also reset the benchmarking.
                var totalReceived      = Interlocked.Exchange(ref _totalReceives, 0);
                var duplicatedReceived = Interlocked.Exchange(ref _duplicatedReceives, 0);
                if (duplicatedReceived >= totalReceived)
                {
                    // Note that the worst case scenario is not duplicatedReceived == totalReceived, but duplicatedReceived == (number of peers) * totalReceived.
                    // It's just duplicatedReceived == totalReceived is maximum what we want to tolerate.
                    // By turning off Tor, we can notice that the ratio is much better, so this mainly depends on the internet speed.
                    Logger.LogWarning($"Too many duplicated mempool transactions are downloaded.\n{nameof(duplicatedReceived)} : {duplicatedReceived}\n{nameof(totalReceived)} : {totalReceived}");
                }

                return(true);
            }
            catch (Exception ex)
            {
                Logger.LogWarning(ex);
            }
            finally
            {
                Interlocked.Exchange(ref _cleanupInProcess, 0);
            }

            return(false);
        }
예제 #13
0
        private long _blockRequests;         // There are priority requests in queue.

        public WasabiSynchronizer(Network network, BitcoinStore bitcoinStore, Func <Uri> baseUriAction, EndPoint torSocks5EndPoint)
        {
            WasabiClient = new WasabiClient(baseUriAction, torSocks5EndPoint);
            Network      = Guard.NotNull(nameof(network), network);
            LastResponse = null;
            _running     = 0;
            Cancel       = new CancellationTokenSource();
            BitcoinStore = Guard.NotNull(nameof(bitcoinStore), bitcoinStore);
        }
        public async Task GetFiltersAsync(NetworkType networkType)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);
            var filterModel = StartingFilters.GetStartingFilter(Network.GetNetwork(networkType.ToString()));

            FiltersResponse filtersResponse = await client.GetFiltersAsync(filterModel.Header.BlockHash, 2);

            Assert.NotNull(filtersResponse);
            Assert.True(filtersResponse.Filters.Count() == 2);
        }
        public async Task GetVersionsTestsAsync(NetworkType networkType)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);

            var versions = await client.GetVersionsAsync(CancellationToken.None);

            Assert.InRange(versions.ClientVersion, new Version(1, 1, 10), new Version(1, 2));
            Assert.InRange(versions.ClientVersion, new Version(1, 1, 10), WalletWasabi.Helpers.Constants.ClientVersion);
            Assert.Equal(3, versions.BackendMajorVersion);
            Assert.Equal(new Version(2, 0), versions.LegalDocumentsVersion);
        }
예제 #16
0
        public async Task GetFiltersAsync(NetworkType networkType)
        {
            using (var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType]))
            {
                var filterModel = IndexDownloader.GetStartingFilter(Network.GetNetwork(networkType.ToString()));

                FiltersResponse filtersResponse = await client.GetFiltersAsync(filterModel.BlockHash, 2);

                Assert.NotNull(filtersResponse);
                Assert.True(filtersResponse.Filters.Count() == 2);
            }
        }
예제 #17
0
        public async Task GetVersionsTestsAsync(NetworkType networkType)
        {
            using var torHttpClient = MakeTorHttpClient(networkType);
            var client = new WasabiClient(torHttpClient);

            var versions = await client.GetVersionsAsync(CancellationToken.None);

            Assert.InRange(versions.ClientVersion, new Version(1, 1, 10), new Version(1, 2));
            Assert.InRange(versions.ClientVersion, new Version(1, 1, 10), WalletWasabi.Helpers.Constants.ClientVersion);
            Assert.Equal(4, versions.BackendMajorVersion);
            Assert.Equal(new Version(2, 0), versions.LegalDocumentsVersion);
        }
예제 #18
0
        public async Task GetFiltersAsync(NetworkType networkType)
        {
            Network network = (networkType == NetworkType.Mainnet) ? Network.Main : Network.TestNet;

            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Common.TorSocks5Endpoint);
            var filterModel = StartingFilters.GetStartingFilter(network);

            FiltersResponse filtersResponse = await client.GetFiltersAsync(filterModel.Header.BlockHash, 2);

            Assert.NotNull(filtersResponse);
            Assert.True(filtersResponse.Filters.Count() == 2);
        }
예제 #19
0
        public async Task StopAsync()
        {
            if (IsRunning)
            {
                Interlocked.Exchange(ref _running, 2);
            }
            while (IsStopping)
            {
                await Task.Delay(50);
            }

            WasabiClient?.Dispose();
        }
        public async Task GetLegalDocumentsTestsAsync(NetworkType networkType)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);

            var content = await client.GetLegalDocumentsAsync(CancellationToken.None);

            var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);

            Assert.Equal("Last Updated: 2020-04-05", lines[0]);
            var lineCount = lines.Length;

            Assert.InRange(lineCount, 100, 1000);
        }
예제 #21
0
        public async Task GetFiltersAsync(NetworkType networkType)
        {
            Network network = (networkType == NetworkType.Mainnet) ? Network.Main : Network.TestNet;

            using var torHttpClient = MakeTorHttpClient(networkType);
            var client = new WasabiClient(torHttpClient);

            var filterModel = StartingFilters.GetStartingFilter(network);

            FiltersResponse?filtersResponse = await client.GetFiltersAsync(filterModel.Header.BlockHash, 2);

            Assert.NotNull(filtersResponse);
            Assert.True(filtersResponse !.Filters.Count() == 2);
        }
예제 #22
0
        public async Task GetLegalDocumentsTestsAsync(NetworkType networkType)
        {
            using var torHttpClient = MakeTorHttpClient(networkType);
            var client = new WasabiClient(torHttpClient);

            var content = await client.GetLegalDocumentsAsync(CancellationToken.None);

            var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);

            Assert.Equal("Last Updated: 2020-04-05", lines[0]);
            var lineCount = lines.Length;

            Assert.InRange(lineCount, 100, 1000);
        }
예제 #23
0
        /// <summary>
        /// Tries to perform mempool cleanup with the help of the backend.
        /// </summary>
        public async Task <bool> TryPerformMempoolCleanupAsync(Func <Uri> destAction, IPEndPoint torSocks)
        {
            // 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.
                }

                Logger.LogInfo <MempoolService>("Start cleaning out mempool...");
                using (var client = new WasabiClient(destAction, torSocks))
                {
                    var compactness      = 10;
                    var allMempoolHashes = await client.GetMempoolHashesAsync(compactness);

                    var toRemove = TransactionHashes.Where(x => !allMempoolHashes.Contains(x.ToString().Substring(0, compactness)));

                    int removedTxCount = 0;
                    foreach (uint256 tx in toRemove)
                    {
                        if (TransactionHashes.TryRemove(tx))
                        {
                            removedTxCount++;
                        }
                    }

                    Logger.LogInfo <MempoolService>($"{removedTxCount} transactions were cleaned from mempool.");
                }

                return(true);
            }
            catch (Exception ex)
            {
                Logger.LogWarning <MempoolService>(ex);
            }
            finally
            {
                Interlocked.Exchange(ref _cleanupInProcess, 0);
            }

            return(false);
        }
예제 #24
0
    public async Task StaticClient()
    {
        NullNetworkDriver driver = new NullNetworkDriver();

        WasabiConfig config = new WasabiConfig();

        config.Credentials = new StringAccessKey("ExampleKeyId00000000", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY");
        config.Region      = WasabiRegion.EuCentral1;

        using WasabiClient client = new WasabiClient(config, driver);

        await client.GetObjectAsync("testbucket", "GetObjectAsync").ConfigureAwait(false);

        Assert.Equal("https://testbucket.s3.eu-central-1.wasabisys.com/GetObjectAsync", driver.LastUrl);
    }
예제 #25
0
        private async Task LoadDummyMempoolAsync()
        {
            if (BitcoinStore.TransactionStore.MempoolStore.IsEmpty())
            {
                return;
            }

            // Only clean the mempool if we're fully synchronized.
            if (BitcoinStore.SmartHeaderChain.HashesLeft == 0)
            {
                try
                {
                    using var client = new WasabiClient(Synchronizer.WasabiClient.TorClient.DestinationUriAction, Synchronizer.WasabiClient.TorClient.TorSocks5EndPoint);
                    var compactness = 10;

                    var mempoolHashes = await client.GetMempoolHashesAsync(compactness);

                    var txsToProcess = new List <SmartTransaction>();
                    foreach (var tx in BitcoinStore.TransactionStore.MempoolStore.GetTransactions())
                    {
                        uint256 hash = tx.GetHash();
                        if (mempoolHashes.Contains(hash.ToString().Substring(0, compactness)))
                        {
                            txsToProcess.Add(tx);
                            Logger.LogInfo($"Transaction was successfully tested against the backend's mempool hashes: {hash}.");
                        }
                        else
                        {
                            BitcoinStore.TransactionStore.MempoolStore.TryRemove(tx.GetHash(), out _);
                        }
                    }

                    TransactionProcessor.Process(txsToProcess);
                }
                catch (Exception ex)
                {
                    // When there's a connection failure do not clean the transactions, add them to processing.
                    TransactionProcessor.Process(BitcoinStore.TransactionStore.MempoolStore.GetTransactions());

                    Logger.LogWarning(ex);
                }
            }
            else
            {
                TransactionProcessor.Process(BitcoinStore.TransactionStore.MempoolStore.GetTransactions());
            }
        }
예제 #26
0
        public async Task CheckUpdatesTestsAsync(NetworkType networkType)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);

            var updateStatus = await client.CheckUpdatesAsync(CancellationToken.None);

            var expectedVersion = new Version(2, 0);

            Assert.Equal(new UpdateStatus(true, true, expectedVersion), updateStatus);
            Assert.True(updateStatus.BackendCompatible);
            Assert.True(updateStatus.ClientUpToDate);
            Assert.Equal(expectedVersion, updateStatus.LegalDocumentsVersion);

            var versions = await client.GetVersionsAsync(CancellationToken.None);

            Assert.Equal(versions.LegalDocumentsVersion, updateStatus.LegalDocumentsVersion);
        }
예제 #27
0
        public IndexDownloader(Network network, string indexFilePath, Uri indexHostUri, IPEndPoint torSocks5EndPoint = null)
        {
            Network       = Guard.NotNull(nameof(network), network);
            WasabiClient  = new WasabiClient(indexHostUri, torSocks5EndPoint);
            IndexFilePath = Guard.NotNullOrEmptyOrWhitespace(nameof(indexFilePath), indexFilePath);

            Index     = new List <FilterModel>();
            IndexLock = new AsyncLock();

            _running = 0;

            var indexDir = Path.GetDirectoryName(IndexFilePath);

            if (!string.IsNullOrEmpty(indexDir))
            {
                Directory.CreateDirectory(indexDir);
            }
            if (File.Exists(IndexFilePath))
            {
                if (Network == Network.RegTest)
                {
                    File.Delete(IndexFilePath);                     // RegTest is not a global ledger, better to delete it.
                    Index.Add(StartingFilter);
                    File.WriteAllLines(IndexFilePath, Index.Select(x => x.ToLine()));
                }
                else
                {
                    var height = StartingHeight;
                    foreach (var line in File.ReadAllLines(IndexFilePath))
                    {
                        var filter = FilterModel.FromLine(line, height);
                        height++;
                        Index.Add(filter);
                    }
                }
            }
            else
            {
                Index.Add(StartingFilter);
                File.WriteAllLines(IndexFilePath, Index.Select(x => x.ToLine()));
            }
        }
        public async Task GetTransactionsAsync(NetworkType networkType)
        {
            using var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], Global.Instance.TorSocks5Endpoint);
            var randomTxIds = Enumerable.Range(0, 20).Select(_ => RandomUtils.GetUInt256());
            var network     = networkType == NetworkType.Mainnet ? Network.Main : Network.TestNet;

            var ex = await Assert.ThrowsAsync <HttpRequestException>(async() =>
                                                                     await client.GetTransactionsAsync(network, randomTxIds.Take(4), CancellationToken.None));

            Assert.Equal("Bad Request\nNo such mempool or blockchain transaction. Use gettransaction for wallet transactions.", ex.Message);

            var mempoolTxIds = await client.GetMempoolHashesAsync(CancellationToken.None);

            randomTxIds = Enumerable.Range(0, 5).Select(_ => mempoolTxIds.RandomElement()).Distinct().ToArray();
            var txs = await client.GetTransactionsAsync(network, randomTxIds, CancellationToken.None);

            var returnedTxIds = txs.Select(tx => tx.GetHash());

            Assert.Equal(returnedTxIds.OrderBy(x => x).ToArray(), randomTxIds.OrderBy(x => x).ToArray());
        }
예제 #29
0
        public async Task CheckUpdatesTestsAsync(NetworkType networkType)
        {
            using var torHttpClient = MakeTorHttpClient(networkType);
            var client = new WasabiClient(torHttpClient);

            var updateStatus = await client.CheckUpdatesAsync(CancellationToken.None);

            var    expectedVersion = new Version(2, 0);
            ushort backendVersion  = 4;

            Assert.Equal(new UpdateStatus(true, true, expectedVersion, backendVersion), updateStatus);
            Assert.True(updateStatus.BackendCompatible);
            Assert.True(updateStatus.ClientUpToDate);
            Assert.Equal(expectedVersion, updateStatus.LegalDocumentsVersion);
            Assert.Equal(backendVersion, updateStatus.CurrentBackendMajorVersion);

            var versions = await client.GetVersionsAsync(CancellationToken.None);

            Assert.Equal(versions.LegalDocumentsVersion, updateStatus.LegalDocumentsVersion);
        }
예제 #30
0
        private static async Task AssertFiltersInitializedAsync(RegTestFixture regTestFixture, Backend.Global global)
        {
            var firstHash = await global.RpcClient.GetBlockHashAsync(0);

            while (true)
            {
                using var client = new WasabiClient(new Uri(regTestFixture.BackendEndPoint), null);
                FiltersResponse filtersResponse = await client.GetFiltersAsync(firstHash, 1000);

                Assert.NotNull(filtersResponse);

                var filterCount = filtersResponse.Filters.Count();
                if (filterCount >= 101)
                {
                    break;
                }
                else
                {
                    await Task.Delay(100);
                }
            }
        }