Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
3071826f06 | |||
c3684eb064 | |||
335dd9e66d | |||
cd1611dbcd | |||
c17793aca9 |
@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<Version>1.0.1.27</Version>
|
||||
<Version>1.0.1.30</Version>
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
@ -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<string> 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<IActionResult> DeleteStore(string storeId)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using NBitcoin;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBXplorer;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using System;
|
||||
@ -10,6 +11,8 @@ using BTCPayServer.Data;
|
||||
using System.Threading;
|
||||
using NBXplorer.Models;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using BTCPayServer.Logging;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace BTCPayServer.Services.Wallets
|
||||
{
|
||||
@ -25,7 +28,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; }
|
||||
}
|
||||
@ -100,22 +102,62 @@ namespace BTCPayServer.Services.Wallets
|
||||
public void InvalidateCache(DerivationStrategyBase strategy)
|
||||
{
|
||||
_MemoryCache.Remove("CACHEDCOINS_" + strategy.ToString());
|
||||
_FetchingUTXOs.TryRemove(strategy.ToString(), out var unused);
|
||||
}
|
||||
ConcurrentDictionary<string, TaskCompletionSource<UTXOChanges>> _FetchingUTXOs = new ConcurrentDictionary<string, TaskCompletionSource<UTXOChanges>>();
|
||||
|
||||
public Task<NetworkCoins> GetCoins(DerivationStrategyBase strategy, CancellationToken cancellation = default(CancellationToken))
|
||||
|
||||
public async Task<NetworkCoins> 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<UTXOChanges> GetUTXOChanges(DerivationStrategyBase strategy, CancellationToken cancellation)
|
||||
{
|
||||
var thisCompletionSource = new TaskCompletionSource<UTXOChanges>();
|
||||
var completionSource = _FetchingUTXOs.GetOrAdd(strategy.ToString(), (s) => thisCompletionSource);
|
||||
if (thisCompletionSource != completionSource)
|
||||
return await completionSource.Task;
|
||||
try
|
||||
{
|
||||
var utxos = await _MemoryCache.GetOrCreateAsync("CACHEDCOINS_" + strategy.ToString(), async entry =>
|
||||
{
|
||||
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
|
||||
};
|
||||
});
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
UTXOChanges result = null;
|
||||
try
|
||||
{
|
||||
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;
|
||||
});
|
||||
completionSource.TrySetResult(utxos);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_FetchingUTXOs.TryRemove(strategy.ToString(), out var unused);
|
||||
}
|
||||
return await completionSource.Task;
|
||||
}
|
||||
|
||||
public Task<BroadcastResult[]> BroadcastTransactionsAsync(List<Transaction> transactions)
|
||||
@ -128,7 +170,7 @@ namespace BTCPayServer.Services.Wallets
|
||||
|
||||
public async Task<(Coin[], Dictionary<Script, KeyPath>)> 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<Script, KeyPath>();
|
||||
foreach (var coin in changes.GetUnspentUTXOs())
|
||||
{
|
||||
@ -137,10 +179,10 @@ namespace BTCPayServer.Services.Wallets
|
||||
return (changes.GetUnspentCoins(), keyPaths);
|
||||
}
|
||||
|
||||
public async Task<Money> GetBalance(DerivationStrategyBase derivationStrategy)
|
||||
public async Task<Money> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,15 @@ namespace BTCPayServer.Services.Wallets
|
||||
_Client = client;
|
||||
_NetworkProvider = networkProvider;
|
||||
_Options = memoryCacheOption;
|
||||
|
||||
foreach(var network in networkProvider.GetAll())
|
||||
{
|
||||
_Wallets.Add(network.CryptoCode, new BTCPayWallet(_Client.GetExplorerClient(network.CryptoCode), new MemoryCache(_Options), network));
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, BTCPayWallet> _Wallets = new Dictionary<string, BTCPayWallet>();
|
||||
|
||||
public BTCPayWallet GetWallet(BTCPayNetwork network)
|
||||
{
|
||||
if (network == null)
|
||||
@ -33,11 +40,8 @@ namespace BTCPayServer.Services.Wallets
|
||||
{
|
||||
if (cryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(cryptoCode));
|
||||
var network = _NetworkProvider.GetNetwork(cryptoCode);
|
||||
var client = _Client.GetExplorerClient(cryptoCode);
|
||||
if (network == null || client == null)
|
||||
return null;
|
||||
return new BTCPayWallet(client, new MemoryCache(_Options), network);
|
||||
_Wallets.TryGetValue(cryptoCode, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool IsAvailable(BTCPayNetwork network)
|
||||
|
Reference in New Issue
Block a user