mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-04 01:53:52 +01:00
Refactoring LndClient, enabling passing of Swagger instance
This commit is contained in:
parent
cfbcf0947a
commit
b03d271f85
3 changed files with 173 additions and 72 deletions
|
@ -2,8 +2,10 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Payments.Lightning.Lnd;
|
using BTCPayServer.Payments.Lightning.Lnd;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
|
using NBitcoin.RPC;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
@ -16,31 +18,96 @@ namespace BTCPayServer.Tests.UnitTests
|
||||||
public LndTest(ITestOutputHelper output)
|
public LndTest(ITestOutputHelper output)
|
||||||
{
|
{
|
||||||
this.output = output;
|
this.output = output;
|
||||||
|
initializeEnvironment();
|
||||||
|
|
||||||
|
LndRpc = LndSwaggerClientCustomHttp.Create(new Uri("http://localhost:53280"), Network.RegTest);
|
||||||
|
InvoiceClient = new LndClient(LndRpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LndClient Client
|
private LndSwaggerClientCustomHttp LndRpc { get; set; }
|
||||||
{
|
private LndClient InvoiceClient { get; set; }
|
||||||
get
|
|
||||||
{
|
|
||||||
var lnd = new LndClient(new Uri("http://localhost:53280"), Network.RegTest);
|
|
||||||
return lnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetInfo()
|
public async Task GetInfo()
|
||||||
{
|
{
|
||||||
var res = await Client.GetInfo();
|
var res = await InvoiceClient.GetInfo();
|
||||||
|
|
||||||
output.WriteLine("Result: " + res.ToJson());
|
output.WriteLine("Result: " + res.ToJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateInvoice()
|
public async Task CreateInvoice()
|
||||||
{
|
{
|
||||||
var res = await Client.CreateInvoice(10000, "Hello world", TimeSpan.FromSeconds(3600));
|
var res = await InvoiceClient.CreateInvoice(10000, "Hello world", TimeSpan.FromSeconds(3600));
|
||||||
|
|
||||||
output.WriteLine("Result: " + res.ToJson());
|
output.WriteLine("Result: " + res.ToJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SetupWalletForPayment()
|
||||||
|
{
|
||||||
|
var nodeInfo = GetInfo();
|
||||||
|
var addressResponse = await LndRpc.NewWitnessAddressAsync();
|
||||||
|
var address = BitcoinAddress.Create(addressResponse.Address, Network.RegTest);
|
||||||
|
await ExplorerNode.SendToAddressAsync(address, Money.Coins(0.2m));
|
||||||
|
ExplorerNode.Generate(1);
|
||||||
|
await WaitLNSynched();
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
|
// We need two instances of lnd... one for merchant, one for buyer
|
||||||
|
// prepare that in next commit
|
||||||
|
//var channelReq = new LnrpcOpenChannelRequest
|
||||||
|
//{
|
||||||
|
// Local_funding_amount = 16777215.ToString()
|
||||||
|
//};
|
||||||
|
//var channelResp = await LndRpc.OpenChannelSyncAsync(channelReq);
|
||||||
|
|
||||||
|
output.WriteLine("Wallet Address: " + address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<LightningNodeInformation> WaitLNSynched()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var merchantInfo = await InvoiceClient.GetInfo();
|
||||||
|
var blockCount = await ExplorerNode.GetBlockCountAsync();
|
||||||
|
if (merchantInfo.BlockHeight != blockCount)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,18 +17,13 @@ namespace BTCPayServer.Payments.Lightning.Lnd
|
||||||
{
|
{
|
||||||
public class LndClient : ILightningInvoiceClient, ILightningListenInvoiceSession
|
public class LndClient : ILightningInvoiceClient, ILightningListenInvoiceSession
|
||||||
{
|
{
|
||||||
public LndClient(Uri uri, Network network, byte[] tlsCertificate = null, byte[] grpcMacaroon = null)
|
public LndSwaggerClient _Decorator;
|
||||||
|
|
||||||
|
public LndClient(LndSwaggerClient decorator)
|
||||||
{
|
{
|
||||||
// for now working with custom build of lnd that has no macaroons and is on http
|
_Decorator = decorator;
|
||||||
//_HttpClient = HttpClientFactoryForLnd.Generate(tlsCertificate, grpcMacaroon);
|
|
||||||
|
|
||||||
_HttpClient = new HttpClient();
|
|
||||||
_Decorator = new LndSwaggerClient(uri.ToString().TrimEnd('/'), _HttpClient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpClient _HttpClient;
|
|
||||||
private LndSwaggerClient _Decorator;
|
|
||||||
|
|
||||||
public async Task<LightningInvoice> CreateInvoice(LightMoney amount, string description, TimeSpan expiry,
|
public async Task<LightningInvoice> CreateInvoice(LightMoney amount, string description, TimeSpan expiry,
|
||||||
CancellationToken cancellation = default(CancellationToken))
|
CancellationToken cancellation = default(CancellationToken))
|
||||||
{
|
{
|
||||||
|
@ -84,11 +79,8 @@ namespace BTCPayServer.Payments.Lightning.Lnd
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_HttpClient?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// utility static methods... maybe move to separate class
|
||||||
private static string BitString(byte[] bytes)
|
private static string BitString(byte[] bytes)
|
||||||
{
|
{
|
||||||
return BitConverter.ToString(bytes)
|
return BitConverter.ToString(bytes)
|
||||||
|
@ -123,6 +115,11 @@ namespace BTCPayServer.Payments.Lightning.Lnd
|
||||||
return invoice;
|
return invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
// Invariant culture conversion
|
// Invariant culture conversion
|
||||||
public static class ConvertInv
|
public static class ConvertInv
|
||||||
{
|
{
|
||||||
|
@ -143,53 +140,7 @@ namespace BTCPayServer.Payments.Lightning.Lnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class HttpClientFactoryForLnd
|
public partial class LndSwaggerClient
|
||||||
{
|
|
||||||
internal static HttpClient Generate(byte[] tlsCertificate, byte[] grpcMacaroon)
|
|
||||||
{
|
|
||||||
var httpClient = new HttpClient(GetCertificate(tlsCertificate));
|
|
||||||
var macaroonHex = BitConverter.ToString(grpcMacaroon).Replace("-", "", StringComparison.InvariantCulture);
|
|
||||||
httpClient.DefaultRequestHeaders.Add("Grpc-Metadata-macaroon", macaroonHex);
|
|
||||||
|
|
||||||
return httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HttpClientHandler GetCertificate(byte[] certFile)
|
|
||||||
{
|
|
||||||
X509Certificate2 clientCertificate = null;
|
|
||||||
if (certFile != null)
|
|
||||||
clientCertificate = new X509Certificate2(certFile);
|
|
||||||
|
|
||||||
var handler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
SslProtocols = SslProtocols.Tls12
|
|
||||||
};
|
|
||||||
|
|
||||||
handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>
|
|
||||||
{
|
|
||||||
const SslPolicyErrors unforgivableErrors =
|
|
||||||
SslPolicyErrors.RemoteCertificateNotAvailable |
|
|
||||||
SslPolicyErrors.RemoteCertificateNameMismatch;
|
|
||||||
|
|
||||||
if ((errors & unforgivableErrors) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientCertificate == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
X509Certificate2 remoteRoot = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
|
|
||||||
var res = clientCertificate.RawData.SequenceEqual(remoteRoot.RawData);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
partial class LndSwaggerClient
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Security.Authentication;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NBitcoin;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Payments.Lightning.Lnd
|
||||||
|
{
|
||||||
|
public class LndSwaggerClientCustomHttp : LndSwaggerClient, IDisposable
|
||||||
|
{
|
||||||
|
public LndSwaggerClientCustomHttp(string baseUrl, HttpClient httpClient)
|
||||||
|
: base(baseUrl, httpClient)
|
||||||
|
{
|
||||||
|
_HttpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpClient _HttpClient;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_HttpClient.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
public static LndSwaggerClientCustomHttp Create(Uri uri, Network network, byte[] tlsCertificate = null, byte[] grpcMacaroon = null)
|
||||||
|
{
|
||||||
|
// for now working with custom build of lnd that has no macaroons and is on http
|
||||||
|
//_HttpClient = HttpClientFactoryForLnd.Generate(tlsCertificate, grpcMacaroon);
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
return new LndSwaggerClientCustomHttp(uri.ToString().TrimEnd('/'), httpClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class HttpClientFactoryForLnd
|
||||||
|
{
|
||||||
|
internal static HttpClient Generate(byte[] tlsCertificate, byte[] grpcMacaroon)
|
||||||
|
{
|
||||||
|
var httpClient = new HttpClient(GetCertificate(tlsCertificate));
|
||||||
|
var macaroonHex = BitConverter.ToString(grpcMacaroon).Replace("-", "", StringComparison.InvariantCulture);
|
||||||
|
httpClient.DefaultRequestHeaders.Add("Grpc-Metadata-macaroon", macaroonHex);
|
||||||
|
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpClientHandler GetCertificate(byte[] certFile)
|
||||||
|
{
|
||||||
|
X509Certificate2 clientCertificate = null;
|
||||||
|
if (certFile != null)
|
||||||
|
clientCertificate = new X509Certificate2(certFile);
|
||||||
|
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
SslProtocols = SslProtocols.Tls12
|
||||||
|
};
|
||||||
|
|
||||||
|
handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>
|
||||||
|
{
|
||||||
|
const SslPolicyErrors unforgivableErrors =
|
||||||
|
SslPolicyErrors.RemoteCertificateNotAvailable |
|
||||||
|
SslPolicyErrors.RemoteCertificateNameMismatch;
|
||||||
|
|
||||||
|
if ((errors & unforgivableErrors) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientCertificate == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
X509Certificate2 remoteRoot = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
|
||||||
|
var res = clientCertificate.RawData.SequenceEqual(remoteRoot.RawData);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue