2018-05-01 20:33:43 -05:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
2018-05-11 14:07:46 -05:00
|
|
|
|
using BTCPayServer.Payments.Lightning;
|
2018-05-01 20:33:43 -05:00
|
|
|
|
using BTCPayServer.Payments.Lightning.Lnd;
|
|
|
|
|
using NBitcoin;
|
2018-05-11 14:07:46 -05:00
|
|
|
|
using NBitcoin.RPC;
|
2018-05-01 20:33:43 -05:00
|
|
|
|
using Xunit;
|
|
|
|
|
using Xunit.Abstractions;
|
2018-05-12 00:23:10 -05:00
|
|
|
|
using System.Linq;
|
2018-05-12 00:43:13 -05:00
|
|
|
|
using System.Threading;
|
2018-05-25 10:44:59 -05:00
|
|
|
|
using NBitpayClient;
|
2018-05-01 20:33:43 -05:00
|
|
|
|
|
2018-05-25 10:44:59 -05:00
|
|
|
|
namespace BTCPayServer.Tests.Lnd
|
2018-05-01 20:33:43 -05:00
|
|
|
|
{
|
2018-05-11 16:59:24 -05:00
|
|
|
|
// this depends for now on `docker-compose up devlnd`
|
2018-05-25 10:44:59 -05:00
|
|
|
|
public class UnitTests
|
2018-05-01 20:33:43 -05:00
|
|
|
|
{
|
|
|
|
|
private readonly ITestOutputHelper output;
|
|
|
|
|
|
2018-05-25 10:44:59 -05:00
|
|
|
|
public UnitTests(ITestOutputHelper output)
|
2018-05-01 20:33:43 -05:00
|
|
|
|
{
|
|
|
|
|
this.output = output;
|
2018-05-11 14:07:46 -05:00
|
|
|
|
initializeEnvironment();
|
2018-05-01 20:33:43 -05:00
|
|
|
|
|
2018-05-11 16:59:24 -05:00
|
|
|
|
MerchantLnd = LndSwaggerClientCustomHttp.Create(new Uri("http://127.0.0.1:53280"), Network.RegTest);
|
2018-05-14 22:18:08 -05:00
|
|
|
|
InvoiceClient = new LndInvoiceClient(MerchantLnd);
|
2018-05-11 16:59:24 -05:00
|
|
|
|
|
|
|
|
|
CustomerLnd = LndSwaggerClientCustomHttp.Create(new Uri("http://127.0.0.1:53281"), Network.RegTest);
|
2018-05-01 20:33:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-11 16:59:24 -05:00
|
|
|
|
private LndSwaggerClientCustomHttp MerchantLnd { get; set; }
|
2018-05-14 22:18:08 -05:00
|
|
|
|
private LndInvoiceClient InvoiceClient { get; set; }
|
2018-05-11 14:07:46 -05:00
|
|
|
|
|
2018-05-11 16:59:24 -05:00
|
|
|
|
private LndSwaggerClientCustomHttp CustomerLnd { get; set; }
|
|
|
|
|
|
2018-05-01 20:33:43 -05:00
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetInfo()
|
|
|
|
|
{
|
2018-05-11 14:07:46 -05:00
|
|
|
|
var res = await InvoiceClient.GetInfo();
|
2018-05-01 20:33:43 -05:00
|
|
|
|
output.WriteLine("Result: " + res.ToJson());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task CreateInvoice()
|
|
|
|
|
{
|
2018-05-11 14:07:46 -05:00
|
|
|
|
var res = await InvoiceClient.CreateInvoice(10000, "Hello world", TimeSpan.FromSeconds(3600));
|
2018-05-01 20:33:43 -05:00
|
|
|
|
output.WriteLine("Result: " + res.ToJson());
|
|
|
|
|
}
|
2018-05-11 14:07:46 -05:00
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetInvoice()
|
|
|
|
|
{
|
|
|
|
|
var createInvoice = await InvoiceClient.CreateInvoice(10000, "Hello world", TimeSpan.FromSeconds(3600));
|
|
|
|
|
var getInvoice = await InvoiceClient.GetInvoice(createInvoice.Id);
|
|
|
|
|
|
|
|
|
|
Assert.Equal(createInvoice.BOLT11, getInvoice.BOLT11);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-05-25 10:44:59 -05:00
|
|
|
|
//integration tests
|
2018-05-11 14:07:46 -05:00
|
|
|
|
|
|
|
|
|
[Fact]
|
2018-05-12 00:43:13 -05:00
|
|
|
|
public async Task CreateLndInvoiceAndPay()
|
2018-05-11 14:07:46 -05:00
|
|
|
|
{
|
2018-05-12 00:43:13 -05:00
|
|
|
|
var merchantInvoice = await InvoiceClient.CreateInvoice(10000, "Hello world", TimeSpan.FromSeconds(3600));
|
|
|
|
|
|
2018-05-12 00:23:10 -05:00
|
|
|
|
await EnsureLightningChannelAsync();
|
2018-05-12 00:43:13 -05:00
|
|
|
|
var payResponse = await CustomerLnd.SendPaymentSyncAsync(new LnrpcSendRequest
|
|
|
|
|
{
|
|
|
|
|
Payment_request = merchantInvoice.BOLT11
|
|
|
|
|
});
|
2018-05-20 10:27:11 -05:00
|
|
|
|
|
2018-05-12 00:43:13 -05:00
|
|
|
|
var invoice = await InvoiceClient.GetInvoice(merchantInvoice.Id);
|
|
|
|
|
|
|
|
|
|
Assert.True(invoice.PaidAt.HasValue);
|
2018-05-12 00:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<LnrpcChannel> EnsureLightningChannelAsync()
|
|
|
|
|
{
|
|
|
|
|
var merchantInfo = await WaitLNSynched();
|
2018-05-14 15:54:44 -05:00
|
|
|
|
var merchantNodeAddress = new LnrpcLightningAddress
|
2018-05-12 00:23:10 -05:00
|
|
|
|
{
|
|
|
|
|
Pubkey = merchantInfo.NodeId,
|
|
|
|
|
Host = "merchant_lnd:9735"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
while (true)
|
2018-05-11 16:59:24 -05:00
|
|
|
|
{
|
2018-05-12 00:23:10 -05:00
|
|
|
|
// if channel is pending generate blocks until confirmed
|
|
|
|
|
var pendingResponse = await CustomerLnd.PendingChannelsAsync();
|
|
|
|
|
if (pendingResponse.Pending_open_channels?
|
2018-05-14 15:54:44 -05:00
|
|
|
|
.Any(a => a.Channel?.Remote_node_pub == merchantNodeAddress.Pubkey) == true)
|
2018-05-11 16:59:24 -05:00
|
|
|
|
{
|
2018-05-12 00:23:10 -05:00
|
|
|
|
ExplorerNode.Generate(1);
|
|
|
|
|
await WaitLNSynched();
|
|
|
|
|
continue;
|
2018-05-11 16:59:24 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-12 00:23:10 -05:00
|
|
|
|
// check if channel is established
|
|
|
|
|
var chanResponse = await CustomerLnd.ListChannelsAsync(null, null, null, null);
|
2018-05-20 10:27:11 -05:00
|
|
|
|
LnrpcChannel channelToMerchant = null;
|
|
|
|
|
if (chanResponse != null && chanResponse.Channels != null)
|
|
|
|
|
{
|
|
|
|
|
channelToMerchant = chanResponse.Channels
|
2018-05-14 15:54:44 -05:00
|
|
|
|
.Where(a => a.Remote_pubkey == merchantNodeAddress.Pubkey)
|
2018-05-12 00:23:10 -05:00
|
|
|
|
.FirstOrDefault();
|
2018-05-20 10:27:11 -05:00
|
|
|
|
}
|
2018-05-11 14:07:46 -05:00
|
|
|
|
|
2018-05-12 00:23:10 -05:00
|
|
|
|
if (channelToMerchant == null)
|
|
|
|
|
{
|
|
|
|
|
// create new channel
|
|
|
|
|
var isConnected = await CustomerLnd.ListPeersAsync();
|
2018-05-20 10:27:11 -05:00
|
|
|
|
if (isConnected.Peers == null ||
|
|
|
|
|
!isConnected.Peers.Any(a => a.Pub_key == merchantInfo.NodeId))
|
2018-05-12 00:23:10 -05:00
|
|
|
|
{
|
|
|
|
|
var connectResp = await CustomerLnd.ConnectPeerAsync(new LnrpcConnectPeerRequest
|
|
|
|
|
{
|
2018-05-14 15:54:44 -05:00
|
|
|
|
Addr = merchantNodeAddress
|
2018-05-12 00:23:10 -05:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var addressResponse = await CustomerLnd.NewWitnessAddressAsync();
|
|
|
|
|
var address = BitcoinAddress.Create(addressResponse.Address, Network.RegTest);
|
|
|
|
|
await ExplorerNode.SendToAddressAsync(address, Money.Coins(0.2m));
|
|
|
|
|
ExplorerNode.Generate(1);
|
|
|
|
|
await WaitLNSynched();
|
|
|
|
|
|
|
|
|
|
var channelReq = new LnrpcOpenChannelRequest
|
|
|
|
|
{
|
|
|
|
|
Local_funding_amount = 16777215.ToString(),
|
|
|
|
|
Node_pubkey_string = merchantInfo.NodeId
|
|
|
|
|
};
|
|
|
|
|
var channelResp = await CustomerLnd.OpenChannelSyncAsync(channelReq);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// channel exists, return it
|
|
|
|
|
ExplorerNode.Generate(1);
|
|
|
|
|
await WaitLNSynched();
|
|
|
|
|
return channelToMerchant;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-11 14:07:46 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<LightningNodeInformation> WaitLNSynched()
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
var merchantInfo = await InvoiceClient.GetInfo();
|
|
|
|
|
var blockCount = await ExplorerNode.GetBlockCountAsync();
|
|
|
|
|
if (merchantInfo.BlockHeight != blockCount)
|
|
|
|
|
{
|
2018-05-12 00:23:10 -05:00
|
|
|
|
await Task.Delay(500);
|
2018-05-11 14:07:46 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return merchantInfo;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
private void initializeEnvironment()
|
|
|
|
|
{
|
|
|
|
|
NetworkProvider = new BTCPayNetworkProvider(NetworkType.Regtest);
|
|
|
|
|
ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_BTCRPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork("BTC").NBitcoinNetwork);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BTCPayNetworkProvider NetworkProvider { get; private set; }
|
|
|
|
|
public RPCClient ExplorerNode { get; set; }
|
|
|
|
|
|
|
|
|
|
internal string GetEnvironment(string variable, string defaultValue)
|
|
|
|
|
{
|
|
|
|
|
var var = Environment.GetEnvironmentVariable(variable);
|
|
|
|
|
return String.IsNullOrEmpty(var) ? defaultValue : var;
|
|
|
|
|
}
|
2018-05-01 20:33:43 -05:00
|
|
|
|
}
|
|
|
|
|
}
|