private async Task WaitServersAreUp(string name, ILightningClient client) { var rpc = Tester.CreateRPC(); await rpc.ScanRPCCapabilitiesAsync(); await rpc.GenerateAsync(1); Exception realException = null; using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Timeout - 5))) { retry: try { if (realException != null) { await Task.Delay(1000, cts.Token); } await client.GetInfo(cts.Token); Logs.Tester.LogInformation($"{name}: Server is up"); } catch (Exception ex) when(!cts.IsCancellationRequested) { realException = ex; goto retry; } catch (Exception) { Logs.Tester.LogInformation(realException.ToString()); Assert.False(true, $"{name}: The server could not be started"); } } }
public static async Task CreateChannel(RPCClient cashCow, ILightningClient sender, ILightningClient dest) { var destInfo = await dest.GetInfo(); var destInvoice = await dest.CreateInvoice(1000, "EnsureConnectedToDestination", TimeSpan.FromSeconds(5000)); while (true) { var result = await sender.Pay(destInvoice.BOLT11); if (result.Result == PayResult.CouldNotFindRoute) { var openChannel = await sender.OpenChannel(new OpenChannelRequest() { NodeInfo = destInfo.NodeInfoList[0], ChannelAmount = Money.Satoshis(16777215), FeeRate = new FeeRate(1UL, 1) }); if (openChannel.Result == OpenChannelResult.CannotAffordFunding) { var address = await sender.GetDepositAddress(); try { await cashCow.SendToAddressAsync(address, Money.Coins(1.0m), null, null, true); } catch (RPCException ex) when(ex.RPCCode == RPCErrorCode.RPC_WALLET_INSUFFICIENT_FUNDS || ex.RPCCode == RPCErrorCode.RPC_WALLET_ERROR) { await cashCow.GenerateAsync(1); await cashCow.SendToAddressAsync(address, Money.Coins(1.0m), null, null, true); } await cashCow.GenerateAsync(10); await WaitLNSynched(cashCow, sender); await WaitLNSynched(cashCow, dest); } if (openChannel.Result == OpenChannelResult.PeerNotConnected) { await sender.ConnectTo(destInfo.NodeInfoList[0]); } if (openChannel.Result == OpenChannelResult.NeedMoreConf) { await cashCow.GenerateAsync(6); await WaitLNSynched(cashCow, sender); await WaitLNSynched(cashCow, dest); } if (openChannel.Result == OpenChannelResult.AlreadyExists) { await Task.Delay(1000); } } else if (result.Result == PayResult.Ok) { break; } } }
public async Task OutBoundChannelOpenRoundtrip(Clients clients, ILightningClient remoteClient) { var walletInfo = await clients.NRustLightningHttpClient.GetWalletInfoAsync(); var info = await remoteClient.GetInfo(); Assert.Single(info.NodeInfoList); var theirNodeKey = info.NodeInfoList.FirstOrDefault()?.NodeId; Assert.NotNull(theirNodeKey); await clients.NRustLightningHttpClient.OpenChannelAsync(new Infrastructure.Models.Request.OpenChannelRequest { TheirNetworkKey = theirNodeKey, ChannelValueSatoshis = 1000000, PushMSat = 100000 }); // wait until nbx detects unconfirmed funding tx. await Support.Utils.Retry(30, TimeSpan.FromSeconds(1.5), async() => { var e = (await clients.NBXClient.GetTransactionsAsync(walletInfo.DerivationStrategy)); return(e.UnconfirmedTransactions.Transactions.Count > 0); }); var addr = await clients.NRustLightningHttpClient.GetNewDepositAddressAsync(); await clients.BitcoinRPCClient.GenerateToAddressAsync(10, addr.Address); var localId = (await clients.NRustLightningHttpClient.GetInfoAsync()).ConnectionString.NodeId; await Support.Utils.Retry(20, TimeSpan.FromSeconds(1.2), async() => { var maybeLocalChannel = (await clients.NRustLightningHttpClient.GetChannelDetailsAsync()).Details.FirstOrDefault(cd => cd.RemoteNetworkId.Equals(theirNodeKey) && cd.IsLive); if (maybeLocalChannel is null) { return(false); } // CLightning client throws null reference exception when it is used as ILightningClient. // So we do dirty fallback here. if (remoteClient is CLightningClient cli) { var maybeRemoteChannel = (await cli.ListChannelsAsync()).Where(c => c.Active).FirstOrDefault(c => new PubKey(c.Destination).Equals(localId)); return(maybeRemoteChannel != null); } else { var maybeRemoteChannel = (await remoteClient.ListChannels()).Where(c => c.IsActive).FirstOrDefault(c => c.RemoteNode.Equals(localId)); return(maybeRemoteChannel != null); } }, "Failed to create outbound channel");
private static async Task <LightningNodeInformation> WaitLNSynched(RPCClient rpc, ILightningClient lightningClient) { while (true) { var merchantInfo = await lightningClient.GetInfo(); var blockCount = await rpc.GetBlockCountAsync(); if (merchantInfo.BlockHeight != blockCount) { await Task.Delay(500); } else { return(merchantInfo); } } }
public static async Task CreateChannel(RPCClient cashCow, ILightningClient sender, ILightningClient dest) { var destInfo = await dest.GetInfo(); var destInvoice = await dest.CreateInvoice(1000, "EnsureConnectedToDestination", TimeSpan.FromSeconds(5000)); while (true) { int payErrors = 0; var result = await Pay(sender, destInvoice.BOLT11); Logs.LogInformation($"Pay Result: {result.Result} {result.ErrorDetail}"); if (result.Result == PayResult.Ok) { break; } else if (result.Result == PayResult.CouldNotFindRoute) { // check channels that are in process of opening, to prevent double channel open await Task.Delay(100); var pendingChannels = await sender.ListChannels(); if (pendingChannels.Any(a => a.RemoteNode == destInfo.NodeInfoList[0].NodeId)) { Logs.LogInformation($"Channel to {destInfo.NodeInfoList[0]} is already open(ing)"); Logs.LogInformation($"Attempting to reconnect Result: {await sender.ConnectTo(destInfo.NodeInfoList.First())}"); await cashCow.GenerateAsync(1); await WaitLNSynched(cashCow, sender); await WaitLNSynched(cashCow, dest); continue; } Logs.LogInformation($"Opening channel to {destInfo.NodeInfoList[0]}"); var openChannel = await sender.OpenChannel(new OpenChannelRequest() { NodeInfo = destInfo.NodeInfoList[0], ChannelAmount = Money.Satoshis(16777215), FeeRate = new FeeRate(1UL, 1) }); Logs.LogInformation($"Channel opening result: {openChannel.Result}"); if (openChannel.Result == OpenChannelResult.CannotAffordFunding) { var address = await sender.GetDepositAddress(); try { await cashCow.SendToAddressAsync(address, Money.Coins(1.0m), new SendToAddressParameters() { Replaceable = true }); } catch (RPCException ex) when(ex.RPCCode == RPCErrorCode.RPC_WALLET_INSUFFICIENT_FUNDS || ex.RPCCode == RPCErrorCode.RPC_WALLET_ERROR) { await cashCow.GenerateAsync(1); await cashCow.SendToAddressAsync(address, Money.Coins(1.0m), new SendToAddressParameters() { Replaceable = true }); } await cashCow.GenerateAsync(10); await WaitLNSynched(cashCow, sender); await WaitLNSynched(cashCow, dest); } if (openChannel.Result == OpenChannelResult.PeerNotConnected) { await sender.ConnectTo(destInfo.NodeInfoList[0]); } if (openChannel.Result == OpenChannelResult.NeedMoreConf) { await cashCow.GenerateAsync(6); await WaitLNSynched(cashCow, sender); await WaitLNSynched(cashCow, dest); } if (openChannel.Result == OpenChannelResult.AlreadyExists) { await Task.Delay(1000); } if (openChannel.Result == OpenChannelResult.Ok) { // generate one block and a bit more time to confirm channel opening await cashCow.GenerateAsync(1); await WaitLNSynched(cashCow, sender); await WaitLNSynched(cashCow, dest); await Task.Delay(500); } } else { if (payErrors++ > 10) { throw new Exception($"Couldn't establish payment channel after {payErrors} repeated tries"); } await Task.Delay(1000); } } }