From 47a0d8baf100d535a5890c10bcb314e6fa11c46b Mon Sep 17 00:00:00 2001 From: Rodrigo <39995243+RodriFS@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:26:23 +0200 Subject: [PATCH 1/3] Reversing node order when reviving remote initiated channels --- src/Jobs/ChannelMonitorJob.cs | 9 ++++++++- src/Services/LightningService.cs | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Jobs/ChannelMonitorJob.cs b/src/Jobs/ChannelMonitorJob.cs index 9c6c44ab..1f75c656 100644 --- a/src/Jobs/ChannelMonitorJob.cs +++ b/src/Jobs/ChannelMonitorJob.cs @@ -93,8 +93,10 @@ public async Task Execute(IJobExecutionContext context) _logger.LogInformation("{JobName} ended", nameof(ChannelMonitorJob)); } - public async Task RecoverGhostChannels(Node source, Node destination, Channel channel) + public async Task RecoverGhostChannels(Node node1, Node node2, Channel channel) { + var source = node1; + var destination = node2; if (!channel.Initiator && destination.IsManaged) return; try { @@ -113,6 +115,11 @@ public async Task RecoverGhostChannels(Node source, Node destination, Channel ch OutputIndex = Convert.ToUInt32(outputIndex) }; + if (!channel.Initiator) + { + source = node2; + destination = node1; + } var createdChannel = await LightningService.CreateChannel(source, destination.Id, parsedChannelPoint, channel.Capacity, channel.CloseAddress); createdChannel.CreatedByNodeGuard = false; diff --git a/src/Services/LightningService.cs b/src/Services/LightningService.cs index 3124f764..d393d9a6 100644 --- a/src/Services/LightningService.cs +++ b/src/Services/LightningService.cs @@ -226,7 +226,7 @@ public async Task OpenChannel(ChannelOperationRequest channelOperationRequest) throw new InvalidOperationException(); } - var feeRate = await _nbXplorerService.GetFeesByType(channelOperationRequest.MempoolRecommendedFeesTypes) ?? channelOperationRequest.FeeRate;; + var feeRate = await _nbXplorerService.GetFeesByType(channelOperationRequest.MempoolRecommendedFeesTypes) ?? channelOperationRequest.FeeRate; var initialFeeRate = feeRate ?? (await LightningHelper.GetFeeRateResult(network, _nbXplorerService)).FeeRate .SatoshiPerByte; From 0bd21140eefbeccefb49afcc0ada1c7cbe2b54e1 Mon Sep 17 00:00:00 2001 From: Rodrigo <39995243+RodriFS@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:37:49 +0200 Subject: [PATCH 2/3] Added unit testing for reviving remote initiated channels --- src/Jobs/ChannelMonitorJob.cs | 5 -- src/Services/LightningService.cs | 12 ++- .../Jobs/ChannelMonitorJobTests.cs | 83 ++++++++++++++++++- 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/Jobs/ChannelMonitorJob.cs b/src/Jobs/ChannelMonitorJob.cs index 1f75c656..5dab7646 100644 --- a/src/Jobs/ChannelMonitorJob.cs +++ b/src/Jobs/ChannelMonitorJob.cs @@ -115,11 +115,6 @@ public async Task RecoverGhostChannels(Node node1, Node node2, Channel channel) OutputIndex = Convert.ToUInt32(outputIndex) }; - if (!channel.Initiator) - { - source = node2; - destination = node1; - } var createdChannel = await LightningService.CreateChannel(source, destination.Id, parsedChannelPoint, channel.Capacity, channel.CloseAddress); createdChannel.CreatedByNodeGuard = false; diff --git a/src/Services/LightningService.cs b/src/Services/LightningService.cs index d393d9a6..e092862e 100644 --- a/src/Services/LightningService.cs +++ b/src/Services/LightningService.cs @@ -692,6 +692,14 @@ public static async Task CreateChannel(Node source, int destId, Channel throw new InvalidOperationException($"Error, channel not found for channel point: {channelPoint}"); } + var sourceNodeId = source.Id; + var destinationNodeId = destId; + if (!currentChannel.Initiator) + { + sourceNodeId = destId; + destinationNodeId = source.Id; + } + var channel = new Channel { ChanId = currentChannel.ChanId, @@ -702,8 +710,8 @@ public static async Task CreateChannel(Node source, int destId, Channel SatsAmount = satsAmount, UpdateDatetime = DateTimeOffset.Now, Status = Channel.ChannelStatus.Open, - SourceNodeId = source.Id, - DestinationNodeId = destId, + SourceNodeId = sourceNodeId, + DestinationNodeId = destinationNodeId, CreatedByNodeGuard = true, IsPrivate = currentChannel.Private }; diff --git a/test/NodeGuard.Tests/Jobs/ChannelMonitorJobTests.cs b/test/NodeGuard.Tests/Jobs/ChannelMonitorJobTests.cs index 18841091..b49cef86 100644 --- a/test/NodeGuard.Tests/Jobs/ChannelMonitorJobTests.cs +++ b/test/NodeGuard.Tests/Jobs/ChannelMonitorJobTests.cs @@ -102,7 +102,8 @@ public async Task RecoverGhostChannels_CreatesChannel(string? endpoint) ChanId = 123, Capacity = 1000, LocalBalance = 100, - RemoteBalance = 900 + RemoteBalance = 900, + Initiator = true } } }; @@ -122,10 +123,15 @@ public async Task RecoverGhostChannels_CreatesChannel(string? endpoint) var source = new Node() { + Id = 1, Endpoint = "localhost", ChannelAdminMacaroon = "abc" }; - var destination = new Node() { Endpoint = endpoint}; + var destination = new Node() + { + Id = 2, + Endpoint = endpoint + }; var channel = new Lnrpc.Channel() { ChanId = 1, @@ -137,6 +143,79 @@ public async Task RecoverGhostChannels_CreatesChannel(string? endpoint) await channelMonitorJob.RecoverGhostChannels(source, destination, channel); // Assert + var createdChannel = await context.Channels.FirstAsync(); + createdChannel.SourceNodeId.Should().Be(source.Id); + createdChannel.DestinationNodeId.Should().Be(destination.Id); + context.Channels.Count().Should().Be(1); + LightningService.CreateLightningClient = originalLightningClient; + } + + [Fact] + public async Task RecoverGhostChannels_CreatesChannelNotInitiator() + { + // Arrange + var logger = new Mock>(); + var dbContextFactory = SetupDbContextFactory(); + var context = await dbContextFactory.Object.CreateDbContextAsync(); + //Mock lightning client with iunmockable methods + var channelPoint = new ChannelPoint { FundingTxidBytes = ByteString.CopyFrom(Convert.FromHexString("a2dffe0545ae0ce9091949477a9a7d91bb9478eb054fd9fa142e73562287ca4e").Reverse().ToArray()), OutputIndex = 1 }; + + var listChannelsResponse = new ListChannelsResponse + { + Channels = + { + new Lnrpc.Channel + { + Active = true, + RemotePubkey = "03b48034270e522e4033afdbe43383d66d426638927b940d09a8a7a0de4d96e807", + ChannelPoint = $"{LightningHelper.DecodeTxId(channelPoint.FundingTxidBytes)}:{channelPoint.OutputIndex}", + ChanId = 123, + Capacity = 1000, + LocalBalance = 100, + RemoteBalance = 900, + Initiator = false + } + } + }; + + var lightningClient = Interceptor.For() + .Setup(x => x.ListChannelsAsync( + Arg.Ignore(), + Arg.Ignore(), + null, + Arg.Ignore() + )) + .Returns(MockHelpers.CreateAsyncUnaryCall(listChannelsResponse)); + var originalLightningClient = LightningService.CreateLightningClient; + LightningService.CreateLightningClient = (_) => lightningClient; + + var channelMonitorJob = new ChannelMonitorJob(logger.Object, dbContextFactory.Object, null, null, null); + + var source = new Node() + { + Id = 1, + Endpoint = "localhost", + ChannelAdminMacaroon = "abc" + }; + var destination = new Node() + { + Id = 2, + Endpoint = null, + }; + var channel = new Lnrpc.Channel() + { + ChanId = 1, + Initiator = false, + ChannelPoint = "a2dffe0545ae0ce9091949477a9a7d91bb9478eb054fd9fa142e73562287ca4e:1" + }; + + // Act + await channelMonitorJob.RecoverGhostChannels(source, destination, channel); + + // Assert + var createdChannel = await context.Channels.FirstAsync(); + createdChannel.SourceNodeId.Should().Be(destination.Id); + createdChannel.DestinationNodeId.Should().Be(source.Id); context.Channels.Count().Should().Be(1); LightningService.CreateLightningClient = originalLightningClient; } From 93d45e2d7417764406d4a98ee8812fee63497bce Mon Sep 17 00:00:00 2001 From: Rodrigo <39995243+RodriFS@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:39:17 +0200 Subject: [PATCH 3/3] rolled back unnecessary change --- src/Jobs/ChannelMonitorJob.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Jobs/ChannelMonitorJob.cs b/src/Jobs/ChannelMonitorJob.cs index 5dab7646..9c6c44ab 100644 --- a/src/Jobs/ChannelMonitorJob.cs +++ b/src/Jobs/ChannelMonitorJob.cs @@ -93,10 +93,8 @@ public async Task Execute(IJobExecutionContext context) _logger.LogInformation("{JobName} ended", nameof(ChannelMonitorJob)); } - public async Task RecoverGhostChannels(Node node1, Node node2, Channel channel) + public async Task RecoverGhostChannels(Node source, Node destination, Channel channel) { - var source = node1; - var destination = node2; if (!channel.Initiator && destination.IsManaged) return; try {