diff --git a/src/Services/LightningService.cs b/src/Services/LightningService.cs index 3124f764..e092862e 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; @@ -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; }