From c17793aca938d778244bf0c9f325a96eecaeed09 Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Thu, 15 Feb 2018 13:33:29 +0900 Subject: [PATCH] do not freeze the stores page --- BTCPayServer/BTCPayServer.csproj | 2 +- BTCPayServer/Controllers/StoresController.cs | 21 ++++++-- BTCPayServer/Services/Wallets/BTCPayWallet.cs | 52 +++++++++++++------ 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index c392836c0..d8212942d 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -2,7 +2,7 @@ Exe netcoreapp2.0 - 1.0.1.27 + 1.0.1.28 NU1701 diff --git a/BTCPayServer/Controllers/StoresController.cs b/BTCPayServer/Controllers/StoresController.cs index 266aa470c..b9910cbf9 100644 --- a/BTCPayServer/Controllers/StoresController.cs +++ b/BTCPayServer/Controllers/StoresController.cs @@ -312,10 +312,10 @@ namespace BTCPayServer.Controllers var stores = await _Repo.GetStoresByUserId(GetUserId()); var balances = stores .Select(s => s.GetDerivationStrategies(_NetworkProvider) - .Select(d => (Wallet: _WalletProvider.GetWallet(d.Network), - DerivationStrategy: d.DerivationStrategyBase)) + .Select(d => ((Wallet: _WalletProvider.GetWallet(d.Network), + DerivationStrategy: d.DerivationStrategyBase))) .Where(_ => _.Wallet != null) - .Select(async _ => (await _.Wallet.GetBalance(_.DerivationStrategy)).ToString() + " " + _.Wallet.Network.CryptoCode)) + .Select(async _ => (await GetBalanceString(_)).ToString() + " " + _.Wallet.Network.CryptoCode)) .ToArray(); await Task.WhenAll(balances.SelectMany(_ => _)); @@ -333,6 +333,21 @@ namespace BTCPayServer.Controllers return View(result); } + private static async Task GetBalanceString((BTCPayWallet Wallet, DerivationStrategyBase DerivationStrategy) _) + { + using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))) + { + try + { + return (await _.Wallet.GetBalance(_.DerivationStrategy, cts.Token)).ToString(); + } + catch + { + return "--"; + } + } + } + [HttpGet] [Route("{storeId}/delete")] public async Task DeleteStore(string storeId) diff --git a/BTCPayServer/Services/Wallets/BTCPayWallet.cs b/BTCPayServer/Services/Wallets/BTCPayWallet.cs index 6f1e9f7a0..35f124e5a 100644 --- a/BTCPayServer/Services/Wallets/BTCPayWallet.cs +++ b/BTCPayServer/Services/Wallets/BTCPayWallet.cs @@ -1,4 +1,5 @@ using NBitcoin; +using Microsoft.Extensions.Logging; using NBXplorer; using NBXplorer.DerivationStrategy; using System; @@ -10,6 +11,7 @@ using BTCPayServer.Data; using System.Threading; using NBXplorer.Models; using Microsoft.Extensions.Caching.Memory; +using BTCPayServer.Logging; namespace BTCPayServer.Services.Wallets { @@ -25,7 +27,6 @@ namespace BTCPayServer.Services.Wallets public Coin Coin { get; set; } } public TimestampedCoin[] TimestampedCoins { get; set; } - public KnownState State { get; set; } public DerivationStrategyBase Strategy { get; set; } public BTCPayWallet Wallet { get; set; } } @@ -102,19 +103,40 @@ namespace BTCPayServer.Services.Wallets _MemoryCache.Remove("CACHEDCOINS_" + strategy.ToString()); } - public Task GetCoins(DerivationStrategyBase strategy, CancellationToken cancellation = default(CancellationToken)) + public async Task GetCoins(DerivationStrategyBase strategy, CancellationToken cancellation = default(CancellationToken)) { - return _MemoryCache.GetOrCreateAsync("CACHEDCOINS_" + strategy.ToString(), async entry => + UTXOChanges changes = await GetUTXOChanges(strategy, cancellation); + + return new NetworkCoins() { - entry.AbsoluteExpiration = DateTimeOffset.UtcNow + CacheSpan; - var changes = await _Client.GetUTXOsAsync(strategy, null, false, cancellation).ConfigureAwait(false); - return new NetworkCoins() + TimestampedCoins = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).Select(c => new NetworkCoins.TimestampedCoin() { Coin = c.AsCoin(), DateTime = c.Timestamp }).ToArray(), + Strategy = strategy, + Wallet = this + }; + } + + private async Task GetUTXOChanges(DerivationStrategyBase strategy, CancellationToken cancellation) + { + return await _MemoryCache.GetOrCreateAsync("CACHEDCOINS_" + strategy.ToString(), async entry => + { + var now = DateTimeOffset.UtcNow; + UTXOChanges result = null; + try { - TimestampedCoins = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).Select(c => new NetworkCoins.TimestampedCoin() { Coin = c.AsCoin(), DateTime = c.Timestamp }).ToArray(), - State = new KnownState() { PreviousCall = changes }, - Strategy = strategy, - Wallet = this - }; + result = await _Client.GetUTXOsAsync(strategy, null, false, cancellation).ConfigureAwait(false); + } + catch + { + Logs.PayServer.LogError("Call to NBXplorer GetUTXOsAsync timed out, this should never happen, please report this issue to NBXplorer developers"); + throw; + } + var spentTime = DateTimeOffset.UtcNow - now; + if (spentTime.TotalSeconds > 30) + { + Logs.PayServer.LogWarning($"NBXplorer took {(int)spentTime.TotalSeconds} seconds to reply, there is something wrong, please report this issue to NBXplorer developers"); + } + entry.AbsoluteExpiration = DateTimeOffset.UtcNow + CacheSpan; + return result; }); } @@ -128,7 +150,7 @@ namespace BTCPayServer.Services.Wallets public async Task<(Coin[], Dictionary)> GetUnspentCoins(DerivationStrategyBase derivationStrategy, CancellationToken cancellation = default(CancellationToken)) { - var changes = await _Client.GetUTXOsAsync(derivationStrategy, null, false, cancellation).ConfigureAwait(false); + var changes = await GetUTXOChanges(derivationStrategy, cancellation); var keyPaths = new Dictionary(); foreach (var coin in changes.GetUnspentUTXOs()) { @@ -137,10 +159,10 @@ namespace BTCPayServer.Services.Wallets return (changes.GetUnspentCoins(), keyPaths); } - public async Task GetBalance(DerivationStrategyBase derivationStrategy) + public async Task GetBalance(DerivationStrategyBase derivationStrategy, CancellationToken cancellation = default(CancellationToken)) { - var result = await _Client.GetUTXOsAsync(derivationStrategy, null, true); - return result.GetUnspentUTXOs().Select(c => c.Value).Sum(); + UTXOChanges changes = await GetUTXOChanges(derivationStrategy, cancellation); + return changes.GetUnspentUTXOs().Select(c => c.Value).Sum(); } } }