diff --git a/BTCPayServer.Tests/README.md b/BTCPayServer.Tests/README.md index 5b1d7689b..4b65f03a4 100644 --- a/BTCPayServer.Tests/README.md +++ b/BTCPayServer.Tests/README.md @@ -26,7 +26,7 @@ docker-compose down If you want to stop, and remove all existing data ``` -docker-compose down -v +docker-compose down --v ``` You can run the tests inside a container by running @@ -35,7 +35,9 @@ You can run the tests inside a container by running docker-compose run --rm tests ``` -## Send commands to bitcoind +## How to manually test payments + +### Using the test bitcoin-cli You can call bitcoin-cli inside the container with `docker exec`, for example, if you want to send `0.23111090` to `mohu16LH66ptoWGEL1GtP6KHTBJYXMWhEf`: ``` @@ -47,7 +49,28 @@ If you are using Powershell: .\docker-bitcoin-cli.ps1 sendtoaddress "mohu16LH66ptoWGEL1GtP6KHTBJYXMWhEf" 0.23111090 ``` -For sending to litecoin, use .\docker-litecoin-cli.ps1 instead. +### Using the test litecoin-cli + +Same as bitcoin-cli, but with `.\docker-litecoin-cli.ps1` instead. + +### Using the test lightning-cli + +``` +docker exec -ti btcpayservertests_customer_lightningd_1 lightning-cli pay lnbcrt100u1pd2e6uspp5ajnadvhazjrz55twd5k6yeg9u87wpw0q2fdr7g960yl5asv5fmnqdq9d3hkccqpxmedyrk0ehw5ueqx5e0r4qrrv74cewddfcvsxaawqz7634cmjj39sqwy5tvhz0hasktkk6t9pqfdh3edmf3z09zst5y7khv3rvxh8ctqqw6mwhh +``` + +If you are using Powershell: +``` +.\docker-customer-lightning-cli.ps1 pay lnbcrt100u1pd2e6uspp5ajnadvhazjrz55twd5k6yeg9u87wpw0q2fdr7g960yl5asv5fmnqdq9d3hkccqpxmedyrk0ehw5ueqx5e0r4qrrv74cewddfcvsxaawqz7634cmjj39sqwy5tvhz0hasktkk6t9pqfdh3edmf3z09zst5y7khv3rvxh8ctqqw6mwhh +``` + +If you get this message: + +``` +{ "code" : 205, "message" : "Could not find a route", "data" : { "getroute_tries" : 1, "sendpay_tries" : 0 } } +``` + +Please, run the test `CanSetLightningServer`, this will establish a channel between the customer and the merchant, then, retry. ## FAQ diff --git a/BTCPayServer.Tests/ServerTester.cs b/BTCPayServer.Tests/ServerTester.cs index dbd01b834..04d526cd0 100644 --- a/BTCPayServer.Tests/ServerTester.cs +++ b/BTCPayServer.Tests/ServerTester.cs @@ -102,6 +102,7 @@ namespace BTCPayServer.Tests await ExplorerNode.SendToAddressAsync(address, Money.Coins(0.2m)); ExplorerNode.Generate(1); await WaitLNSynched(); + await Task.Delay(1000); await CustomerLightningD.FundChannelAsync(clightning, Money.Satoshis(16777215)); break; case "CHANNELD_AWAITING_LOCKIN": diff --git a/BTCPayServer.Tests/docker-compose.yml b/BTCPayServer.Tests/docker-compose.yml index ec45c6cff..7672bbec9 100644 --- a/BTCPayServer.Tests/docker-compose.yml +++ b/BTCPayServer.Tests/docker-compose.yml @@ -17,7 +17,7 @@ services: TESTS_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver TESTS_PORT: 80 TESTS_HOSTNAME: tests - TEST_CUSTOMERLIGHTNINGD: http://lightningd:9835/ + TEST_CUSTOMERLIGHTNINGD: http://customer_lightningd:9835/ TEST_MERCHANTCHARGE: http://api-token:foiewnccewuify@lightning-charged:9112/ expose: - "80" @@ -36,7 +36,8 @@ services: links: - nbxplorer - postgres - - lightningd + - customer_lightningd + - merchant_lightningd - lightning-charged nbxplorer: @@ -83,24 +84,7 @@ services: volumes: - "bitcoin_datadir:/data" - lightning-charged: - image: shesek/lightning-charge:0.3.5 - environment: - NETWORK: regtest - API_TOKEN: foiewnccewuify - SKIP_BITCOIND: 1 - BITCOIND_RPCCONNECT: bitcoind - volumes: - - "bitcoin_datadir:/etc/bitcoin" - expose: - - "9112" # Charge - - "9735" # Lightning - ports: - - "54938:9112" # Charge - links: - - bitcoind - - lightningd: + customer_lightningd: image: nicolasdorier/clightning environment: LIGHTNINGD_OPT: | @@ -115,6 +99,46 @@ services: - "9835" # api port volumes: - "bitcoin_datadir:/etc/bitcoin" + - "customer_lightningd_datadir:/root/.lightning" + links: + - bitcoind + + lightning-charged: + image: shesek/lightning-charge:0.3.5 + environment: + NETWORK: regtest + API_TOKEN: foiewnccewuify + SKIP_BITCOIND: 1 + BITCOIND_RPCCONNECT: bitcoind + volumes: + - "bitcoin_datadir:/etc/bitcoin" + - "lightning_charge_datadir:/data" + - "merchant_lightningd_datadir:/etc/lightning" + expose: + - "9112" # Charge + - "9735" # Lightning + ports: + - "54938:9112" # Charge + links: + - bitcoind + - merchant_lightningd + + merchant_lightningd: + image: nicolasdorier/clightning + environment: + LIGHTNINGD_OPT: | + bitcoin-datadir=/etc/bitcoin + bitcoin-rpcconnect=bitcoind + network=regtest + log-level=debug + ports: + - "30993:9835" # api port + expose: + - "9735" # server port + - "9835" # api port + volumes: + - "bitcoin_datadir:/etc/bitcoin" + - "merchant_lightningd_datadir:/root/.lightning" links: - bitcoind @@ -145,3 +169,6 @@ services: volumes: bitcoin_datadir: + customer_lightningd_datadir: + merchant_lightningd_datadir: + lightning_charge_datadir: diff --git a/BTCPayServer.Tests/docker-customer-lightning-cli.ps1 b/BTCPayServer.Tests/docker-customer-lightning-cli.ps1 new file mode 100644 index 000000000..64209bfe0 --- /dev/null +++ b/BTCPayServer.Tests/docker-customer-lightning-cli.ps1 @@ -0,0 +1 @@ +docker exec -ti btcpayservertests_customer_lightningd_1 lightning-cli $args diff --git a/BTCPayServer/Payments/Lightning/ChargeListener.cs b/BTCPayServer/Payments/Lightning/ChargeListener.cs index c2b7f6e6c..4f031409b 100644 --- a/BTCPayServer/Payments/Lightning/ChargeListener.cs +++ b/BTCPayServer/Payments/Lightning/ChargeListener.cs @@ -60,6 +60,8 @@ namespace BTCPayServer.Payments.Lightning private async Task EnsureListening(string invoiceId, bool poll) { + if (Listening(invoiceId)) + return; var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId); foreach (var paymentMethod in invoice.GetPaymentMethods(_NetworkProvider) .Where(c => c.GetId().PaymentType == PaymentTypes.LightningLike)) @@ -89,16 +91,13 @@ namespace BTCPayServer.Payments.Lightning var chargeInvoice = await charge.GetInvoice(lightningMethod.InvoiceId); if (chargeInvoice == null) continue; - if(chargeInvoice.Status == "paid") + if (chargeInvoice.Status == "paid") await AddPayment(network, chargeInvoice, listenedInvoice); if (chargeInvoice.Status == "paid" || chargeInvoice.Status == "expired") continue; } - if (!Listening(invoiceId)) - { - StartListening(listenedInvoice); - } + StartListening(listenedInvoice); } } @@ -157,6 +156,7 @@ namespace BTCPayServer.Payments.Lightning catch (Exception ex) { Logs.PayServer.LogError(ex, $"{supportedPaymentMethod.CryptoCode} (Lightning): Error while contacting {supportedPaymentMethod.GetLightningChargeUrl(false)}"); + DoneListening(supportedPaymentMethod.GetLightningChargeUrl(false)); } Logs.PayServer.LogInformation($"{supportedPaymentMethod.CryptoCode} (Lightning): Stop listening {supportedPaymentMethod.GetLightningChargeUrl(false)}"); } @@ -202,9 +202,26 @@ namespace BTCPayServer.Payments.Lightning return false; } + /// + /// Stop listening all invoices on this server + /// + /// + private void DoneListening(Uri uri) + { + lock (_ListenedInvoiceByChargeInvoiceId) + { + foreach (var listenedInvoice in _ListenedInvoiceByLightningUrl[uri.AbsoluteUri]) + { + _ListenedInvoiceByChargeInvoiceId.Remove(listenedInvoice.PaymentMethodDetails.InvoiceId); + _InvoiceIds.Remove(listenedInvoice.InvoiceId); + } + _ListenedInvoiceByLightningUrl.Remove(uri.AbsoluteUri); + } + } + bool Listening(string invoiceId) { - lock(_ListenedInvoiceByLightningUrl) + lock (_ListenedInvoiceByLightningUrl) { return _InvoiceIds.Contains(invoiceId); } @@ -230,10 +247,6 @@ namespace BTCPayServer.Payments.Lightning { var listen = Listen(listenedInvoice.SupportedPaymentMethod, listenedInvoice.Network); _ListeningLightning.Add(listen); - listen.ContinueWith(_ => - { - DoneListening(listenedInvoice); - }, TaskScheduler.Default); } _ListenedInvoiceByLightningUrl.Add(listenedInvoice.Uri, listenedInvoice); _ListenedInvoiceByChargeInvoiceId.Add(listenedInvoice.PaymentMethodDetails.InvoiceId, listenedInvoice); diff --git a/BTCPayServer/Services/Wallets/BTCPayWallet.cs b/BTCPayServer/Services/Wallets/BTCPayWallet.cs index af8cfd749..2877c91c3 100644 --- a/BTCPayServer/Services/Wallets/BTCPayWallet.cs +++ b/BTCPayServer/Services/Wallets/BTCPayWallet.cs @@ -126,13 +126,13 @@ namespace BTCPayServer.Services.Wallets } catch { - Logs.PayServer.LogError("Call to NBXplorer GetUTXOsAsync timed out, this should never happen, please report this issue to NBXplorer developers"); + Logs.PayServer.LogError($"{Network.CryptoCode}: 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"); + Logs.PayServer.LogWarning($"{Network.CryptoCode}: 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;