public async Task PrepareLightningAsync() { // Activate segwit var blockCount = ExplorerNode.GetBlockCountAsync(); // Fetch node info, but that in cache var merchantInfo = MerchantCharge.Client.GetInfoAsync(); var customer = CustomerEclair.GetNodeInfoAsync(); var channels = CustomerEclair.RPC.ChannelsAsync(); var info = await merchantInfo; var clightning = new NodeInfo(info.Id, MerchantCharge.P2PHost, info.Port); var connect = CustomerEclair.RPC.ConnectAsync(clightning); await Task.WhenAll(blockCount, customer, channels, connect); // Mine until segwit is activated if (blockCount.Result <= 432) { ExplorerNode.Generate(433 - blockCount.Result); } if (channels.Result.Length == 0) { await CustomerEclair.RPC.OpenAsync(clightning, Money.Satoshis(16777215)); while ((await CustomerEclair.RPC.ChannelsAsync())[0].State != "NORMAL") { ExplorerNode.Generate(1); } } }
/// <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 ?? ""); } } }
public async Task PrepareLightningAsync() { // Activate segwit var blockCount = ExplorerNode.GetBlockCountAsync(); // Fetch node info, but that in cache var merchantInfo = MerchantCharge.Client.GetInfoAsync(); var customer = CustomerEclair.GetNodeInfoAsync(); var channels = CustomerEclair.RPC.ChannelsAsync(); var info = await merchantInfo; var clightning = new NodeInfo(info.Id, MerchantCharge.P2PHost, info.Port); var connect = CustomerEclair.RPC.ConnectAsync(clightning); await Task.WhenAll(blockCount, customer, channels, connect); // If the channel is not created, let's do it if (channels.Result.Length == 0) { var c = (await CustomerEclair.RPC.ChannelsAsync()); bool generated = false; bool createdChannel = false; CancellationTokenSource timeout = new CancellationTokenSource(); timeout.CancelAfter(10000); while (c.Length == 0 || c[0].State != "NORMAL") { if (timeout.IsCancellationRequested) { timeout = new CancellationTokenSource(); timeout.CancelAfter(10000); createdChannel = c.Length == 0; generated = false; } if (!createdChannel) { await CustomerEclair.RPC.OpenAsync(clightning, Money.Satoshis(16777215)); createdChannel = true; } if (!generated && c.Length != 0 && c[0].State == "WAIT_FOR_FUNDING_CONFIRMED") { ExplorerNode.Generate(6); generated = true; } c = (await CustomerEclair.RPC.ChannelsAsync()); } } }
public async Task PrepareLightningAsync() { // Activate segwit var blockCount = ExplorerNode.GetBlockCountAsync(); // Fetch node info, but that in cache var merchant = MerchantEclair.GetNodeInfoAsync(); var customer = CustomerEclair.GetNodeInfoAsync(); var channels = CustomerEclair.RPC.ChannelsAsync(); var connect = CustomerEclair.RPC.ConnectAsync(merchant.Result); await Task.WhenAll(blockCount, merchant, customer, channels, connect); // Mine until segwit is activated if (blockCount.Result <= 432) { ExplorerNode.Generate(433 - blockCount.Result); } }
/// <summary> /// Connect a customer LN node to the merchant LN node /// </summary> /// <returns></returns> public async Task PrepareLightningAsync() { while (true) { var skippedStates = new[] { "ONCHAIN", "CHANNELD_SHUTTING_DOWN", "CLOSINGD_SIGEXCHANGE", "CLOSINGD_COMPLETE", "FUNDING_SPEND_SEEN" }; var channel = (await CustomerLightningD.ListPeersAsync()) .SelectMany(p => p.Channels) .Where(c => !skippedStates.Contains(c.State ?? "")) .FirstOrDefault(); switch (channel?.State) { case null: var merchantInfo = await WaitLNSynched(); var clightning = new NodeInfo(merchantInfo.Id, MerchantCharge.P2PHost, merchantInfo.Port); await CustomerLightningD.ConnectAsync(clightning); var address = await CustomerLightningD.NewAddressAsync(); await ExplorerNode.SendToAddressAsync(address, Money.Coins(0.2m)); ExplorerNode.Generate(1); await WaitLNSynched(); await Task.Delay(1000); await CustomerLightningD.FundChannelAsync(clightning, Money.Satoshis(16777215)); break; case "CHANNELD_AWAITING_LOCKIN": ExplorerNode.Generate(1); await WaitLNSynched(); break; case "CHANNELD_NORMAL": return; default: throw new NotSupportedException(channel?.State ?? ""); } } }
public async Task <LnrpcChannel> EnsureLightningChannelAsync() { var merchantInfo = await WaitLNSynched(); var merchantNodeAddress = new LnrpcLightningAddress { Pubkey = merchantInfo.NodeId, Host = "merchant_lnd:9735" }; while (true) { // if channel is pending generate blocks until confirmed var pendingResponse = await CustomerLnd.PendingChannelsAsync(); if (pendingResponse.Pending_open_channels? .Any(a => a.Channel?.Remote_node_pub == merchantNodeAddress.Pubkey) == true) { ExplorerNode.Generate(1); await WaitLNSynched(); continue; } // check if channel is established var chanResponse = await CustomerLnd.ListChannelsAsync(null, null, null, null); LnrpcChannel channelToMerchant = null; if (chanResponse != null && chanResponse.Channels != null) { channelToMerchant = chanResponse.Channels .Where(a => a.Remote_pubkey == merchantNodeAddress.Pubkey) .FirstOrDefault(); } if (channelToMerchant == null) { // create new channel var isConnected = await CustomerLnd.ListPeersAsync(); if (isConnected.Peers == null || !isConnected.Peers.Any(a => a.Pub_key == merchantInfo.NodeId)) { var connectResp = await CustomerLnd.ConnectPeerAsync(new LnrpcConnectPeerRequest { Addr = merchantNodeAddress }); } 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(CultureInfo.InvariantCulture), Node_pubkey_string = merchantInfo.NodeId }; var channelResp = await CustomerLnd.OpenChannelSyncAsync(channelReq); } else { // channel exists, return it ExplorerNode.Generate(1); await WaitLNSynched(); return(channelToMerchant); } } }