mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 22:44:29 +01:00
invoice watcher can watch several currencies
This commit is contained in:
@@ -71,13 +71,18 @@ namespace BTCPayServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Publish<T>(T evt) where T : class
|
public void Publish<T>(T evt) where T : class
|
||||||
|
{
|
||||||
|
Publish(evt, typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Publish(object evt, Type evtType)
|
||||||
{
|
{
|
||||||
if (evt == null)
|
if (evt == null)
|
||||||
throw new ArgumentNullException(nameof(evt));
|
throw new ArgumentNullException(nameof(evt));
|
||||||
List<Action<object>> actionList = new List<Action<object>>();
|
List<Action<object>> actionList = new List<Action<object>>();
|
||||||
lock (_Subscriptions)
|
lock (_Subscriptions)
|
||||||
{
|
{
|
||||||
if (_Subscriptions.TryGetValue(typeof(T), out Dictionary<Subscription, Action<object>> actions))
|
if (_Subscriptions.TryGetValue(evtType, out Dictionary<Subscription, Action<object>> actions))
|
||||||
{
|
{
|
||||||
actionList = actions.Values.ToList();
|
actionList = actions.Values.ToList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ using NBXplorer;
|
|||||||
using NBXplorer.Models;
|
using NBXplorer.Models;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using BTCPayServer.Services.Wallets;
|
||||||
|
|
||||||
namespace BTCPayServer
|
namespace BTCPayServer
|
||||||
{
|
{
|
||||||
@@ -27,7 +28,7 @@ namespace BTCPayServer
|
|||||||
return activeProvider != "Microsoft.EntityFrameworkCore.Sqlite";
|
return activeProvider != "Microsoft.EntityFrameworkCore.Sqlite";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this ExplorerClient client, uint256[] hashes, CancellationToken cts = default(CancellationToken))
|
public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this BTCPayWallet client, uint256[] hashes, CancellationToken cts = default(CancellationToken))
|
||||||
{
|
{
|
||||||
hashes = hashes.Distinct().ToArray();
|
hashes = hashes.Distinct().ToArray();
|
||||||
var transactions = hashes
|
var transactions = hashes
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using Hangfire;
|
|||||||
using BTCPayServer.Services.Wallets;
|
using BTCPayServer.Services.Wallets;
|
||||||
using BTCPayServer.Controllers;
|
using BTCPayServer.Controllers;
|
||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
namespace BTCPayServer.Services.Invoices
|
namespace BTCPayServer.Services.Invoices
|
||||||
{
|
{
|
||||||
@@ -24,23 +25,42 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
}
|
}
|
||||||
public class InvoiceWatcher : IHostedService
|
public class InvoiceWatcher : IHostedService
|
||||||
{
|
{
|
||||||
|
class UpdateInvoiceContext
|
||||||
|
{
|
||||||
|
public UpdateInvoiceContext()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<BTCPayNetwork, KnownState> KnownStates { get; set; }
|
||||||
|
public Dictionary<BTCPayNetwork, KnownState> ModifiedKnownStates { get; set; } = new Dictionary<BTCPayNetwork, KnownState>();
|
||||||
|
public InvoiceEntity Invoice { get; set; }
|
||||||
|
public List<object> Events { get; set; } = new List<object>();
|
||||||
|
|
||||||
|
bool _Dirty = false;
|
||||||
|
public void MarkDirty()
|
||||||
|
{
|
||||||
|
_Dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Dirty => _Dirty;
|
||||||
|
}
|
||||||
|
|
||||||
InvoiceRepository _InvoiceRepository;
|
InvoiceRepository _InvoiceRepository;
|
||||||
ExplorerClient _ExplorerClient;
|
|
||||||
EventAggregator _EventAggregator;
|
EventAggregator _EventAggregator;
|
||||||
BTCPayWallet _Wallet;
|
BTCPayWallet _Wallet;
|
||||||
BTCPayNetworkProvider _NetworkProvider;
|
BTCPayNetworkProvider _NetworkProvider;
|
||||||
|
|
||||||
public InvoiceWatcher(ExplorerClient explorerClient,
|
public InvoiceWatcher(
|
||||||
|
IHostingEnvironment env,
|
||||||
BTCPayNetworkProvider networkProvider,
|
BTCPayNetworkProvider networkProvider,
|
||||||
InvoiceRepository invoiceRepository,
|
InvoiceRepository invoiceRepository,
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
BTCPayWallet wallet,
|
BTCPayWallet wallet,
|
||||||
InvoiceWatcherAccessor accessor)
|
InvoiceWatcherAccessor accessor)
|
||||||
{
|
{
|
||||||
LongPollingMode = explorerClient.Network == Network.RegTest;
|
PollInterval = TimeSpan.FromMinutes(1.0);
|
||||||
PollInterval = explorerClient.Network == Network.RegTest ? TimeSpan.FromSeconds(10.0) : TimeSpan.FromMinutes(1.0);
|
|
||||||
_Wallet = wallet ?? throw new ArgumentNullException(nameof(wallet));
|
_Wallet = wallet ?? throw new ArgumentNullException(nameof(wallet));
|
||||||
_ExplorerClient = explorerClient ?? throw new ArgumentNullException(nameof(explorerClient));
|
|
||||||
_InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
|
_InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
|
||||||
_EventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
_EventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
||||||
_NetworkProvider = networkProvider;
|
_NetworkProvider = networkProvider;
|
||||||
@@ -48,11 +68,6 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
}
|
}
|
||||||
CompositeDisposable leases = new CompositeDisposable();
|
CompositeDisposable leases = new CompositeDisposable();
|
||||||
|
|
||||||
public bool LongPollingMode
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task NotifyReceived(Script scriptPubKey)
|
async Task NotifyReceived(Script scriptPubKey)
|
||||||
{
|
{
|
||||||
var invoice = await _InvoiceRepository.GetInvoiceIdFromScriptPubKey(scriptPubKey);
|
var invoice = await _InvoiceRepository.GetInvoiceIdFromScriptPubKey(scriptPubKey);
|
||||||
@@ -70,7 +85,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
|
|
||||||
private async Task UpdateInvoice(string invoiceId)
|
private async Task UpdateInvoice(string invoiceId)
|
||||||
{
|
{
|
||||||
UTXOChanges changes = null;
|
Dictionary<BTCPayNetwork, KnownState> changes = new Dictionary<BTCPayNetwork, KnownState>();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -79,22 +94,30 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
if (invoice == null)
|
if (invoice == null)
|
||||||
break;
|
break;
|
||||||
var stateBefore = invoice.Status;
|
var stateBefore = invoice.Status;
|
||||||
var postSaveActions = new List<Action>();
|
var updateContext = new UpdateInvoiceContext()
|
||||||
var result = await UpdateInvoice(changes, invoice, postSaveActions).ConfigureAwait(false);
|
{
|
||||||
changes = result.Changes;
|
Invoice = invoice,
|
||||||
if (result.NeedSave)
|
KnownStates = changes
|
||||||
{
|
};
|
||||||
|
await UpdateInvoice(updateContext).ConfigureAwait(false);
|
||||||
|
if (updateContext.Dirty)
|
||||||
|
{
|
||||||
await _InvoiceRepository.UpdateInvoiceStatus(invoice.Id, invoice.Status, invoice.ExceptionStatus).ConfigureAwait(false);
|
await _InvoiceRepository.UpdateInvoiceStatus(invoice.Id, invoice.Status, invoice.ExceptionStatus).ConfigureAwait(false);
|
||||||
_EventAggregator.Publish(new InvoiceDataChangedEvent() { InvoiceId = invoice.Id });
|
_EventAggregator.Publish(new InvoiceDataChangedEvent() { InvoiceId = invoice.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
var changed = stateBefore != invoice.Status;
|
var changed = stateBefore != invoice.Status;
|
||||||
|
|
||||||
foreach(var saveAction in postSaveActions)
|
foreach (var evt in updateContext.Events)
|
||||||
{
|
{
|
||||||
saveAction();
|
_EventAggregator.Publish(evt, evt.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach(var modifiedKnownState in updateContext.ModifiedKnownStates)
|
||||||
|
{
|
||||||
|
changes.AddOrReplace(modifiedKnownState.Key, modifiedKnownState.Value);
|
||||||
|
}
|
||||||
|
|
||||||
if (invoice.Status == "complete" ||
|
if (invoice.Status == "complete" ||
|
||||||
((invoice.Status == "invalid" || invoice.Status == "expired") && invoice.MonitoringExpiration < DateTimeOffset.UtcNow))
|
((invoice.Status == "invalid" || invoice.Status == "expired") && invoice.MonitoringExpiration < DateTimeOffset.UtcNow))
|
||||||
{
|
{
|
||||||
@@ -119,28 +142,34 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<(bool NeedSave, UTXOChanges Changes)> UpdateInvoice(UTXOChanges changes, InvoiceEntity invoice, List<Action> postSaveActions)
|
private async Task UpdateInvoice(UpdateInvoiceContext context)
|
||||||
{
|
{
|
||||||
bool needSave = false;
|
var invoice = context.Invoice;
|
||||||
//Fetch unknown payments
|
//Fetch unknown payments
|
||||||
var strategy = invoice.GetDerivationStrategies(_NetworkProvider).First(s => s.Network.IsBTC);
|
var strategies = invoice.GetDerivationStrategies(_NetworkProvider).ToArray();
|
||||||
changes = await _ExplorerClient.SyncAsync(strategy.DerivationStrategyBase, changes, !LongPollingMode, _Cts.Token).ConfigureAwait(false);
|
var getCoinsResponsesAsync = strategies
|
||||||
|
.Select(d => _Wallet.GetCoins(d, context.KnownStates.TryGet(d.Network), _Cts.Token))
|
||||||
|
.ToArray();
|
||||||
var utxos = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).ToArray();
|
await Task.WhenAll(getCoinsResponsesAsync);
|
||||||
List<Coin> receivedCoins = new List<Coin>();
|
var getCoinsResponses = getCoinsResponsesAsync.Select(g => g.Result).ToArray();
|
||||||
foreach (var received in utxos)
|
foreach (var response in getCoinsResponses)
|
||||||
if (invoice.AvailableAddressHashes.Contains(received.ScriptPubKey.Hash.ToString()))
|
|
||||||
receivedCoins.Add(received.AsCoin());
|
|
||||||
|
|
||||||
var alreadyAccounted = new HashSet<OutPoint>(invoice.Payments.Select(p => p.Outpoint));
|
|
||||||
bool dirtyAddress = false;
|
|
||||||
foreach (var coin in receivedCoins.Where(c => !alreadyAccounted.Contains(c.Outpoint)))
|
|
||||||
{
|
{
|
||||||
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin).ConfigureAwait(false);
|
response.Coins = response.Coins.Where(c => invoice.AvailableAddressHashes.Contains(c.ScriptPubKey.Hash.ToString())).ToArray();
|
||||||
invoice.Payments.Add(payment);
|
}
|
||||||
postSaveActions.Add(() => _EventAggregator.Publish(new InvoicePaymentEvent(invoice.Id)));
|
var coins = getCoinsResponses.Where(s => s.Coins.Length != 0).FirstOrDefault();
|
||||||
dirtyAddress = true;
|
|
||||||
|
bool dirtyAddress = false;
|
||||||
|
if (coins != null)
|
||||||
|
{
|
||||||
|
context.ModifiedKnownStates.Add(coins.Strategy.Network, coins.State);
|
||||||
|
var alreadyAccounted = new HashSet<OutPoint>(invoice.Payments.Select(p => p.Outpoint));
|
||||||
|
foreach (var coin in coins.Coins.Where(c => !alreadyAccounted.Contains(c.Outpoint)))
|
||||||
|
{
|
||||||
|
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin).ConfigureAwait(false);
|
||||||
|
invoice.Payments.Add(payment);
|
||||||
|
context.Events.Add(new InvoicePaymentEvent(invoice.Id));
|
||||||
|
dirtyAddress = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//////
|
//////
|
||||||
var network = _NetworkProvider.GetNetwork("BTC");
|
var network = _NetworkProvider.GetNetwork("BTC");
|
||||||
@@ -149,10 +178,10 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
var accounting = cryptoData.Calculate();
|
var accounting = cryptoData.Calculate();
|
||||||
if (invoice.Status == "new" && invoice.ExpirationTime < DateTimeOffset.UtcNow)
|
if (invoice.Status == "new" && invoice.ExpirationTime < DateTimeOffset.UtcNow)
|
||||||
{
|
{
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
|
|
||||||
postSaveActions.Add(() => _EventAggregator.Publish(new InvoiceStatusChangedEvent(invoice, "expired")));
|
context.Events.Add(new InvoiceStatusChangedEvent(invoice, "expired"));
|
||||||
invoice.Status = "expired";
|
invoice.Status = "expired";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,16 +192,16 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
{
|
{
|
||||||
if (invoice.Status == "new")
|
if (invoice.Status == "new")
|
||||||
{
|
{
|
||||||
postSaveActions.Add(() => _EventAggregator.Publish(new InvoiceStatusChangedEvent(invoice, "paid")));
|
context.Events.Add(new InvoiceStatusChangedEvent(invoice, "paid"));
|
||||||
invoice.Status = "paid";
|
invoice.Status = "paid";
|
||||||
invoice.ExceptionStatus = null;
|
invoice.ExceptionStatus = null;
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
else if (invoice.Status == "expired")
|
else if (invoice.Status == "expired")
|
||||||
{
|
{
|
||||||
invoice.ExceptionStatus = "paidLate";
|
invoice.ExceptionStatus = "paidLate";
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,17 +209,17 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
{
|
{
|
||||||
invoice.ExceptionStatus = "paidOver";
|
invoice.ExceptionStatus = "paidOver";
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalPaid < accounting.TotalDue && invoice.Payments.Count != 0 && invoice.ExceptionStatus != "paidPartial")
|
if (totalPaid < accounting.TotalDue && invoice.Payments.Count != 0 && invoice.ExceptionStatus != "paidPartial")
|
||||||
{
|
{
|
||||||
Logs.PayServer.LogInformation("Paid to " + cryptoData.DepositAddress);
|
Logs.PayServer.LogInformation("Paid to " + cryptoData.DepositAddress);
|
||||||
invoice.ExceptionStatus = "paidPartial";
|
invoice.ExceptionStatus = "paidPartial";
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
if (dirtyAddress)
|
if (dirtyAddress)
|
||||||
{
|
{
|
||||||
var address = await _Wallet.ReserveAddressAsync(strategy);
|
var address = await _Wallet.ReserveAddressAsync(coins.Strategy);
|
||||||
Logs.PayServer.LogInformation("Generate new " + address);
|
Logs.PayServer.LogInformation("Generate new " + address);
|
||||||
await _InvoiceRepository.NewAddress(invoice.Id, address, network);
|
await _InvoiceRepository.NewAddress(invoice.Id, address, network);
|
||||||
}
|
}
|
||||||
@@ -223,9 +252,9 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
(chainTotalConfirmed < accounting.TotalDue))
|
(chainTotalConfirmed < accounting.TotalDue))
|
||||||
{
|
{
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
postSaveActions.Add(() => _EventAggregator.Publish(new InvoiceStatusChangedEvent(invoice, "invalid")));
|
context.Events.Add(new InvoiceStatusChangedEvent(invoice, "invalid"));
|
||||||
invoice.Status = "invalid";
|
invoice.Status = "invalid";
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -233,9 +262,9 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
if (totalConfirmed >= accounting.TotalDue)
|
if (totalConfirmed >= accounting.TotalDue)
|
||||||
{
|
{
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
postSaveActions.Add(() => _EventAggregator.Publish(new InvoiceStatusChangedEvent(invoice, "confirmed")));
|
context.Events.Add(new InvoiceStatusChangedEvent(invoice, "confirmed"));
|
||||||
invoice.Status = "confirmed";
|
invoice.Status = "confirmed";
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,17 +276,16 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
var totalConfirmed = transactions.Select(t => t.Payment.GetValue(cryptoDataAll, cryptoData.CryptoCode)).Sum();
|
var totalConfirmed = transactions.Select(t => t.Payment.GetValue(cryptoDataAll, cryptoData.CryptoCode)).Sum();
|
||||||
if (totalConfirmed >= accounting.TotalDue)
|
if (totalConfirmed >= accounting.TotalDue)
|
||||||
{
|
{
|
||||||
postSaveActions.Add(() => _EventAggregator.Publish(new InvoiceStatusChangedEvent(invoice, "complete")));
|
context.Events.Add(new InvoiceStatusChangedEvent(invoice, "complete"));
|
||||||
invoice.Status = "complete";
|
invoice.Status = "complete";
|
||||||
needSave = true;
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (needSave, changes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<AccountedPaymentEntity>> GetPaymentsWithTransaction(InvoiceEntity invoice)
|
private async Task<IEnumerable<AccountedPaymentEntity>> GetPaymentsWithTransaction(InvoiceEntity invoice)
|
||||||
{
|
{
|
||||||
var transactions = await _ExplorerClient.GetTransactions(invoice.Payments.Select(t => t.Outpoint.Hash).ToArray());
|
var transactions = await _Wallet.GetTransactions(invoice.Payments.Select(t => t.Outpoint.Hash).ToArray());
|
||||||
|
|
||||||
var spentTxIn = new Dictionary<OutPoint, AccountedPaymentEntity>();
|
var spentTxIn = new Dictionary<OutPoint, AccountedPaymentEntity>();
|
||||||
var result = invoice.Payments.Select(p => p.Outpoint).ToHashSet();
|
var result = invoice.Payments.Select(p => p.Outpoint).ToHashSet();
|
||||||
|
|||||||
@@ -7,9 +7,22 @@ using System.Text;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
|
using System.Threading;
|
||||||
|
using NBXplorer.Models;
|
||||||
|
|
||||||
namespace BTCPayServer.Services.Wallets
|
namespace BTCPayServer.Services.Wallets
|
||||||
{
|
{
|
||||||
|
public class KnownState
|
||||||
|
{
|
||||||
|
public uint256 UnconfirmedHash { get; set; }
|
||||||
|
public uint256 ConfirmedHash { get; set; }
|
||||||
|
}
|
||||||
|
public class GetCoinsResult
|
||||||
|
{
|
||||||
|
public Coin[] Coins { get; set; }
|
||||||
|
public KnownState State { get; set; }
|
||||||
|
public DerivationStrategy Strategy { get; set; }
|
||||||
|
}
|
||||||
public class BTCPayWallet
|
public class BTCPayWallet
|
||||||
{
|
{
|
||||||
private ExplorerClient _Client;
|
private ExplorerClient _Client;
|
||||||
@@ -25,6 +38,7 @@ namespace BTCPayServer.Services.Wallets
|
|||||||
_Client = client;
|
_Client = client;
|
||||||
_DBFactory = factory;
|
_DBFactory = factory;
|
||||||
_Serializer = new NBXplorer.Serializer(_Client.Network);
|
_Serializer = new NBXplorer.Serializer(_Client.Network);
|
||||||
|
LongPollingMode = client.Network == Network.RegTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -39,6 +53,24 @@ namespace BTCPayServer.Services.Wallets
|
|||||||
await _Client.TrackAsync(derivationStrategy.DerivationStrategyBase);
|
await _Client.TrackAsync(derivationStrategy.DerivationStrategyBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<TransactionResult> GetTransactionAsync(uint256 txId, CancellationToken cancellation = default(CancellationToken))
|
||||||
|
{
|
||||||
|
return _Client.GetTransactionAsync(txId, cancellation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LongPollingMode { get; set; }
|
||||||
|
public async Task<GetCoinsResult> GetCoins(DerivationStrategy strategy, KnownState state, CancellationToken cancellation = default(CancellationToken))
|
||||||
|
{
|
||||||
|
var changes = await _Client.SyncAsync(strategy.DerivationStrategyBase, state?.ConfirmedHash, state?.UnconfirmedHash, !LongPollingMode, cancellation).ConfigureAwait(false);
|
||||||
|
var utxos = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).Select(c => c.AsCoin()).ToArray();
|
||||||
|
return new GetCoinsResult()
|
||||||
|
{
|
||||||
|
Coins = utxos,
|
||||||
|
State = new KnownState() { ConfirmedHash = changes.Confirmed.Hash, UnconfirmedHash = changes.Unconfirmed.Hash },
|
||||||
|
Strategy = strategy,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] ToBytes<T>(T obj)
|
private byte[] ToBytes<T>(T obj)
|
||||||
{
|
{
|
||||||
return ZipUtils.Zip(_Serializer.ToString(obj));
|
return ZipUtils.Zip(_Serializer.ToString(obj));
|
||||||
|
|||||||
Reference in New Issue
Block a user