Esempio n. 1
0
        private async Task Listen(BTCPayWallet wallet)
        {
            var  network = wallet.Network;
            bool cleanup = false;

            try
            {
                if (_SessionsByCryptoCode.ContainsKey(network.CryptoCode))
                {
                    return;
                }
                var client = _ExplorerClients.GetExplorerClient(network);
                if (client == null)
                {
                    return;
                }
                if (_Cts.IsCancellationRequested)
                {
                    return;
                }
                var session = await client.CreateWebsocketNotificationSessionAsync(_Cts.Token).ConfigureAwait(false);

                if (!_SessionsByCryptoCode.TryAdd(network.CryptoCode, session))
                {
                    await session.DisposeAsync();

                    return;
                }
                cleanup = true;

                using (session)
                {
                    await session.ListenNewBlockAsync(_Cts.Token).ConfigureAwait(false);

                    await session.ListenAllTrackedSourceAsync(cancellation : _Cts.Token).ConfigureAwait(false);

                    Logs.PayServer.LogInformation($"{network.CryptoCode}: Checking if any pending invoice got paid while offline...");
                    int paymentCount = await FindPaymentViaPolling(wallet, network);

                    Logs.PayServer.LogInformation($"{network.CryptoCode}: {paymentCount} payments happened while offline");

                    Logs.PayServer.LogInformation($"Connected to WebSocket of NBXplorer ({network.CryptoCode})");
                    while (!_Cts.IsCancellationRequested)
                    {
                        var newEvent = await session.NextEventAsync(_Cts.Token).ConfigureAwait(false);

                        switch (newEvent)
                        {
                        case NBXplorer.Models.NewBlockEvent evt:
                            await UpdatePaymentStates(wallet, await _InvoiceRepository.GetPendingInvoices());

                            _Aggregator.Publish(new Events.NewBlockEvent()
                            {
                                CryptoCode = evt.CryptoCode
                            });
                            break;

                        case NBXplorer.Models.NewTransactionEvent evt:
                            if (evt.DerivationStrategy != null)
                            {
                                wallet.InvalidateCache(evt.DerivationStrategy);
                                var validOutputs = network.GetValidOutputs(evt).ToList();
                                if (!validOutputs.Any())
                                {
                                    break;
                                }
                                foreach (var output in validOutputs)
                                {
                                    var key = output.Item1.ScriptPubKey.Hash + "#" +
                                              network.CryptoCode.ToUpperInvariant();
                                    var invoice = (await _InvoiceRepository.GetInvoicesFromAddresses(new[] { key }))
                                                  .FirstOrDefault();
                                    if (invoice != null)
                                    {
                                        var address = network.NBXplorerNetwork.CreateAddress(evt.DerivationStrategy,
                                                                                             output.Item1.KeyPath, output.Item1.ScriptPubKey);

                                        var paymentData = new BitcoinLikePaymentData(address,
                                                                                     output.matchedOutput.Value, output.outPoint,
                                                                                     evt.TransactionData.Transaction.RBF, output.matchedOutput.KeyPath);

                                        var alreadyExist = invoice
                                                           .GetAllBitcoinPaymentData(false).Any(c => c.GetPaymentId() == paymentData.GetPaymentId());
                                        if (!alreadyExist)
                                        {
                                            var payment = await _paymentService.AddPayment(invoice.Id,
                                                                                           DateTimeOffset.UtcNow, paymentData, network);

                                            if (payment != null)
                                            {
                                                await ReceivedPayment(wallet, invoice, payment,
                                                                      evt.DerivationStrategy);
                                            }
                                        }
                                        else
                                        {
                                            await UpdatePaymentStates(wallet, invoice.Id);
                                        }
                                    }
                                }
                            }

                            _Aggregator.Publish(new NewOnChainTransactionEvent()
                            {
                                CryptoCode          = wallet.Network.CryptoCode,
                                NewTransactionEvent = evt
                            });

                            break;

                        default:
                            Logs.PayServer.LogWarning("Received unknown message from NBXplorer");
                            break;
                        }
                    }
                }
            }
            catch when(_Cts.IsCancellationRequested)
            {
            }
        private async Task Listen(BTCPayWallet wallet)
        {
            var  network = wallet.Network;
            bool cleanup = false;

            try
            {
                if (_SessionsByCryptoCode.ContainsKey(network.CryptoCode))
                {
                    return;
                }
                var client = _ExplorerClients.GetExplorerClient(network);
                if (client == null)
                {
                    return;
                }
                if (_Cts.IsCancellationRequested)
                {
                    return;
                }
                var session = await client.CreateNotificationSessionAsync(_Cts.Token).ConfigureAwait(false);

                if (!_SessionsByCryptoCode.TryAdd(network.CryptoCode, session))
                {
                    await session.DisposeAsync();

                    return;
                }
                cleanup = true;

                using (session)
                {
                    await session.ListenNewBlockAsync(_Cts.Token).ConfigureAwait(false);

                    await session.ListenAllDerivationSchemesAsync(cancellation : _Cts.Token).ConfigureAwait(false);

                    Logs.PayServer.LogInformation($"{network.CryptoCode}: Checking if any pending invoice got paid while offline...");
                    int paymentCount = await FindPaymentViaPolling(wallet, network);

                    Logs.PayServer.LogInformation($"{network.CryptoCode}: {paymentCount} payments happened while offline");

                    Logs.PayServer.LogInformation($"Connected to WebSocket of NBXplorer ({network.CryptoCode})");
                    while (!_Cts.IsCancellationRequested)
                    {
                        var newEvent = await session.NextEventAsync(_Cts.Token).ConfigureAwait(false);

                        switch (newEvent)
                        {
                        case NBXplorer.Models.NewBlockEvent evt:

                            await Task.WhenAll((await _InvoiceRepository.GetPendingInvoices())
                                               .Select(invoiceId => UpdatePaymentStates(wallet, invoiceId))
                                               .ToArray());

                            _Aggregator.Publish(new Events.NewBlockEvent()
                            {
                                CryptoCode = evt.CryptoCode
                            });
                            break;

                        case NBXplorer.Models.NewTransactionEvent evt:
                            wallet.InvalidateCache(evt.DerivationStrategy);
                            foreach (var output in evt.Outputs)
                            {
                                foreach (var txCoin in evt.TransactionData.Transaction.Outputs.AsCoins()
                                         .Where(o => o.ScriptPubKey == output.ScriptPubKey)
                                         .Select(o => output.Redeem == null ? o : o.ToScriptCoin(output.Redeem)))
                                {
                                    var invoice = await _InvoiceRepository.GetInvoiceFromScriptPubKey(output.ScriptPubKey, network.CryptoCode);

                                    if (invoice != null)
                                    {
                                        var paymentData  = new BitcoinLikePaymentData(txCoin, evt.TransactionData.Transaction.RBF);
                                        var alreadyExist = GetAllBitcoinPaymentData(invoice).Where(c => c.GetPaymentId() == paymentData.GetPaymentId()).Any();
                                        if (!alreadyExist)
                                        {
                                            var payment = await _InvoiceRepository.AddPayment(invoice.Id, DateTimeOffset.UtcNow, paymentData, network.CryptoCode);
                                            await ReceivedPayment(wallet, invoice.Id, payment, evt.DerivationStrategy);
                                        }
                                        else
                                        {
                                            await UpdatePaymentStates(wallet, invoice.Id);
                                        }
                                    }
                                }
                            }
                            break;

                        default:
                            Logs.PayServer.LogWarning("Received unknown message from NBXplorer");
                            break;
                        }
                    }
                }
            }
            catch when(_Cts.IsCancellationRequested)
            {
            }