mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-23 14:40:36 +01:00
229 lines
9.2 KiB
C#
229 lines
9.2 KiB
C#
using BTCPayServer.Controllers;
|
|
using System.Linq;
|
|
using BTCPayServer.Models.AccountViewModels;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using NBitcoin;
|
|
using NBitcoin.RPC;
|
|
using NBitpayClient;
|
|
using NBXplorer;
|
|
using NBXplorer.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Threading;
|
|
using System.Globalization;
|
|
using BTCPayServer.Payments.Lightning.CLightning;
|
|
using BTCPayServer.Payments.Lightning.Charge;
|
|
using BTCPayServer.Tests.Lnd;
|
|
using BTCPayServer.Payments.Lightning;
|
|
|
|
namespace BTCPayServer.Tests
|
|
{
|
|
public class ServerTester : IDisposable
|
|
{
|
|
public static ServerTester Create([CallerMemberNameAttribute]string scope = null)
|
|
{
|
|
return new ServerTester(scope);
|
|
}
|
|
|
|
string _Directory;
|
|
public ServerTester(string scope)
|
|
{
|
|
_Directory = scope;
|
|
if (Directory.Exists(_Directory))
|
|
Utils.DeleteDirectory(_Directory);
|
|
if (!Directory.Exists(_Directory))
|
|
Directory.CreateDirectory(_Directory);
|
|
|
|
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);
|
|
LTCExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_LTCRPCCONNECTION", "server=http://127.0.0.1:43783;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork("LTC").NBitcoinNetwork);
|
|
|
|
ExplorerClient = new ExplorerClient(NetworkProvider.GetNetwork("BTC").NBXplorerNetwork, new Uri(GetEnvironment("TESTS_BTCNBXPLORERURL", "http://127.0.0.1:32838/")));
|
|
LTCExplorerClient = new ExplorerClient(NetworkProvider.GetNetwork("LTC").NBXplorerNetwork, new Uri(GetEnvironment("TESTS_LTCNBXPLORERURL", "http://127.0.0.1:32838/")));
|
|
|
|
var btc = NetworkProvider.GetNetwork("BTC").NBitcoinNetwork;
|
|
CustomerLightningD = (CLightningRPCClient)LightningClientFactory.CreateClient(GetEnvironment("TEST_CUSTOMERLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30992/"), btc);
|
|
MerchantLightningD = (CLightningRPCClient)LightningClientFactory.CreateClient(GetEnvironment("TEST_MERCHANTLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30993/"), btc);
|
|
|
|
MerchantCharge = new ChargeTester(this, "TEST_MERCHANTCHARGE", "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify", "merchant_lightningd", btc);
|
|
|
|
MerchantLnd = new LndMockTester(this, "TEST_MERCHANTLND", "https://lnd:lnd@127.0.0.1:53280/", "merchant_lnd", btc);
|
|
|
|
PayTester = new BTCPayServerTester(Path.Combine(_Directory, "pay"))
|
|
{
|
|
NBXplorerUri = ExplorerClient.Address,
|
|
LTCNBXplorerUri = LTCExplorerClient.Address,
|
|
Postgres = GetEnvironment("TESTS_POSTGRES", "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver"),
|
|
IntegratedLightning = MerchantCharge.Client.Uri
|
|
};
|
|
PayTester.Port = int.Parse(GetEnvironment("TESTS_PORT", Utils.FreeTcpPort().ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture);
|
|
PayTester.HostName = GetEnvironment("TESTS_HOSTNAME", "127.0.0.1");
|
|
PayTester.InContainer = bool.Parse(GetEnvironment("TESTS_INCONTAINER", "false"));
|
|
}
|
|
|
|
public bool Dockerized
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
PayTester.Start();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Connect a customer LN node to the merchant LN node
|
|
/// </summary>
|
|
public void PrepareLightning(LightningConnectionType lndBackend)
|
|
{
|
|
ILightningInvoiceClient client = MerchantCharge.Client;
|
|
if (lndBackend == LightningConnectionType.LndREST)
|
|
client = MerchantLnd.Client;
|
|
|
|
PrepareLightningAsync(client).GetAwaiter().GetResult();
|
|
}
|
|
|
|
|
|
private static readonly string[] SKIPPED_STATES =
|
|
{ "ONCHAIN", "CHANNELD_SHUTTING_DOWN", "CLOSINGD_SIGEXCHANGE", "CLOSINGD_COMPLETE", "FUNDING_SPEND_SEEN" };
|
|
|
|
/// <summary>
|
|
/// Connect a customer LN node to the merchant LN node
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task PrepareLightningAsync(ILightningInvoiceClient client)
|
|
{
|
|
bool awaitingLocking = false;
|
|
while (true)
|
|
{
|
|
var merchantInfo = await WaitLNSynched(client, CustomerLightningD, MerchantLightningD);
|
|
|
|
var peers = await CustomerLightningD.ListPeersAsync();
|
|
var filteringToTargetedPeers = peers.Where(a => a.Id == merchantInfo.NodeId);
|
|
var channel = filteringToTargetedPeers
|
|
.SelectMany(p => p.Channels)
|
|
.Where(c => !SKIPPED_STATES.Contains(c.State ?? ""))
|
|
.FirstOrDefault();
|
|
|
|
switch (channel?.State)
|
|
{
|
|
case null:
|
|
var address = await CustomerLightningD.NewAddressAsync();
|
|
await ExplorerNode.SendToAddressAsync(address, Money.Coins(0.5m));
|
|
ExplorerNode.Generate(1);
|
|
await WaitLNSynched(client, CustomerLightningD, MerchantLightningD);
|
|
await Task.Delay(1000);
|
|
|
|
var merchantNodeInfo = new NodeInfo(merchantInfo.NodeId, merchantInfo.Address, merchantInfo.P2PPort);
|
|
await CustomerLightningD.ConnectAsync(merchantNodeInfo);
|
|
await CustomerLightningD.FundChannelAsync(merchantNodeInfo, Money.Satoshis(16777215));
|
|
break;
|
|
case "CHANNELD_AWAITING_LOCKIN":
|
|
ExplorerNode.Generate(awaitingLocking ? 1 : 10);
|
|
await WaitLNSynched(client, CustomerLightningD, MerchantLightningD);
|
|
awaitingLocking = true;
|
|
break;
|
|
case "CHANNELD_NORMAL":
|
|
return;
|
|
default:
|
|
throw new NotSupportedException(channel?.State ?? "");
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task<LightningNodeInformation> WaitLNSynched(params ILightningInvoiceClient[] clients)
|
|
{
|
|
while (true)
|
|
{
|
|
var blockCount = await ExplorerNode.GetBlockCountAsync();
|
|
var synching = clients.Select(c => WaitLNSynchedCore(blockCount, c)).ToArray();
|
|
await Task.WhenAll(synching);
|
|
if (synching.All(c => c.Result != null))
|
|
return synching[0].Result;
|
|
await Task.Delay(1000);
|
|
}
|
|
}
|
|
|
|
private async Task<LightningNodeInformation> WaitLNSynchedCore(int blockCount, ILightningInvoiceClient client)
|
|
{
|
|
var merchantInfo = await client.GetInfo();
|
|
if (merchantInfo.BlockHeight == blockCount)
|
|
{
|
|
return merchantInfo;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void SendLightningPayment(Invoice invoice)
|
|
{
|
|
SendLightningPaymentAsync(invoice).GetAwaiter().GetResult();
|
|
}
|
|
|
|
public async Task SendLightningPaymentAsync(Invoice invoice)
|
|
{
|
|
var bolt11 = invoice.CryptoInfo.Where(o => o.PaymentUrls.BOLT11 != null).First().PaymentUrls.BOLT11;
|
|
bolt11 = bolt11.Replace("lightning:", "", StringComparison.OrdinalIgnoreCase);
|
|
await CustomerLightningD.SendAsync(bolt11);
|
|
}
|
|
|
|
public CLightningRPCClient CustomerLightningD { get; set; }
|
|
|
|
public CLightningRPCClient MerchantLightningD { get; private set; }
|
|
public ChargeTester MerchantCharge { get; private set; }
|
|
public LndMockTester MerchantLnd { get; set; }
|
|
|
|
internal string GetEnvironment(string variable, string defaultValue)
|
|
{
|
|
var var = Environment.GetEnvironmentVariable(variable);
|
|
return String.IsNullOrEmpty(var) ? defaultValue : var;
|
|
}
|
|
|
|
public TestAccount NewAccount()
|
|
{
|
|
return new TestAccount(this);
|
|
}
|
|
|
|
public BTCPayNetworkProvider NetworkProvider { get; private set; }
|
|
public RPCClient ExplorerNode
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
public RPCClient LTCExplorerNode
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
public ExplorerClient ExplorerClient
|
|
{
|
|
get; set;
|
|
}
|
|
public ExplorerClient LTCExplorerClient { get; set; }
|
|
|
|
HttpClient _Http = new HttpClient();
|
|
|
|
public BTCPayServerTester PayTester
|
|
{
|
|
get; set;
|
|
}
|
|
public List<string> Stores { get; internal set; } = new List<string>();
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach(var store in Stores)
|
|
{
|
|
Xunit.Assert.True(PayTester.StoreRepository.DeleteStore(store).GetAwaiter().GetResult());
|
|
}
|
|
if (PayTester != null)
|
|
PayTester.Dispose();
|
|
}
|
|
}
|
|
}
|