mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-03 17:36:59 +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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Payments.Lightning.Lnd;
|
||||
using NBitcoin;
|
||||
using NBitcoin.RPC;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -16,31 +18,96 @@ namespace BTCPayServer.Tests.UnitTests
|
|||
public LndTest(ITestOutputHelper output)
|
||||
{
|
||||
this.output = output;
|
||||
initializeEnvironment();
|
||||
|
||||
LndRpc = LndSwaggerClientCustomHttp.Create(new Uri("http://localhost:53280"), Network.RegTest);
|
||||
InvoiceClient = new LndClient(LndRpc);
|
||||
}
|
||||
|
||||
private LndClient Client
|
||||
{
|
||||
get
|
||||
{
|
||||
var lnd = new LndClient(new Uri("http://localhost:53280"), Network.RegTest);
|
||||
return lnd;
|
||||
}
|
||||
}
|
||||
private LndSwaggerClientCustomHttp LndRpc { get; set; }
|
||||
private LndClient InvoiceClient { get; set; }
|
||||
|
||||
[Fact]
|
||||
public async Task GetInfo()
|
||||
{
|
||||
var res = await Client.GetInfo();
|
||||
|
||||
var res = await InvoiceClient.GetInfo();
|
||||
output.WriteLine("Result: " + res.ToJson());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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());
|
||||
}
|
||||
|
||||
[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 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
|
||||
//_HttpClient = HttpClientFactoryForLnd.Generate(tlsCertificate, grpcMacaroon);
|
||||
|
||||
_HttpClient = new HttpClient();
|
||||
_Decorator = new LndSwaggerClient(uri.ToString().TrimEnd('/'), _HttpClient);
|
||||
_Decorator = decorator;
|
||||
}
|
||||
|
||||
private HttpClient _HttpClient;
|
||||
private LndSwaggerClient _Decorator;
|
||||
|
||||
public async Task<LightningInvoice> CreateInvoice(LightMoney amount, string description, TimeSpan expiry,
|
||||
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)
|
||||
{
|
||||
return BitConverter.ToString(bytes)
|
||||
|
@ -123,6 +115,11 @@ namespace BTCPayServer.Payments.Lightning.Lnd
|
|||
return invoice;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Invariant culture conversion
|
||||
public static class ConvertInv
|
||||
{
|
||||
|
@ -143,53 +140,7 @@ namespace BTCPayServer.Payments.Lightning.Lnd
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
partial class LndSwaggerClient
|
||||
public 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