From b871cdde82c2debfd49276f20a9e4ebc356deea2 Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Sat, 2 Apr 2022 19:00:02 +0200 Subject: [PATCH] do not use local channels that cannot be found or where peer is offline --- .../pickhardtpayments/EdgeComputation.java | 23 ++++++-- .../EdgeComputationTest.java | 56 +++++++++++++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java index 10f6baf4..50bfd664 100644 --- a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java +++ b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java @@ -7,6 +7,7 @@ import de.cotto.lndmanagej.grpc.GrpcGraph; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.Coins; import de.cotto.lndmanagej.model.DirectedChannelEdge; +import de.cotto.lndmanagej.model.LocalChannel; import de.cotto.lndmanagej.model.Policy; import de.cotto.lndmanagej.model.Pubkey; import de.cotto.lndmanagej.pickhardtpayments.model.Edge; @@ -15,6 +16,7 @@ import de.cotto.lndmanagej.pickhardtpayments.model.EdgesWithLiquidityInformation import de.cotto.lndmanagej.service.BalanceService; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.MissionControlService; +import de.cotto.lndmanagej.service.NodeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -23,6 +25,7 @@ import java.time.Duration; import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; +import java.util.function.Function; @Component public class EdgeComputation { @@ -31,6 +34,7 @@ public class EdgeComputation { private final GrpcGraph grpcGraph; private final GrpcGetInfo grpcGetInfo; private final ChannelService channelService; + private final NodeService nodeService; private final BalanceService balanceService; private final MissionControlService missionControlService; private final LoadingCache cache = new CacheBuilder() @@ -42,12 +46,14 @@ public class EdgeComputation { GrpcGraph grpcGraph, GrpcGetInfo grpcGetInfo, ChannelService channelService, + NodeService nodeService, BalanceService balanceService, MissionControlService missionControlService ) { this.grpcGraph = grpcGraph; this.grpcGetInfo = grpcGetInfo; this.channelService = channelService; + this.nodeService = nodeService; this.balanceService = balanceService; this.missionControlService = missionControlService; } @@ -110,13 +116,22 @@ public class EdgeComputation { } private Optional getLocalChannelAvailableLocal(ChannelId channelId) { - return channelService.getLocalChannel(channelId) - .map(c -> balanceService.getAvailableLocalBalance(channelId)); + return getLocalChannelAvailable(channelId, balanceService::getAvailableLocalBalance); } private Optional getLocalChannelAvailableRemote(ChannelId channelId) { - return channelService.getLocalChannel(channelId) - .map(c -> balanceService.getAvailableRemoteBalance(channelId)); + return getLocalChannelAvailable(channelId, balanceService::getAvailableRemoteBalance); + } + + private Optional getLocalChannelAvailable(ChannelId channelId, Function balanceProvider) { + LocalChannel localChannel = channelService.getLocalChannel(channelId).orElse(null); + if (localChannel == null) { + return Optional.of(Coins.NONE); + } + if (nodeService.getNode(localChannel.getRemotePubkey()).online()) { + return Optional.of(balanceProvider.apply(channelId)); + } + return Optional.of(Coins.NONE); } private Coins getAvailableLiquidityUpperBound(Edge edge) { diff --git a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java index 9ea3fcc2..d367e134 100644 --- a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java +++ b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java @@ -4,10 +4,13 @@ import de.cotto.lndmanagej.grpc.GrpcGetInfo; import de.cotto.lndmanagej.grpc.GrpcGraph; import de.cotto.lndmanagej.model.Coins; import de.cotto.lndmanagej.model.DirectedChannelEdge; +import de.cotto.lndmanagej.model.Node; +import de.cotto.lndmanagej.model.Pubkey; import de.cotto.lndmanagej.pickhardtpayments.model.EdgeWithLiquidityInformation; import de.cotto.lndmanagej.service.BalanceService; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.MissionControlService; +import de.cotto.lndmanagej.service.NodeService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -21,6 +24,7 @@ import java.util.Set; import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL; +import static de.cotto.lndmanagej.model.NodeFixtures.NODE_PEER; import static de.cotto.lndmanagej.model.PolicyFixtures.POLICY_1; import static de.cotto.lndmanagej.model.PolicyFixtures.POLICY_DISABLED; import static de.cotto.lndmanagej.model.PolicyFixtures.POLICY_WITH_BASE_FEE; @@ -31,6 +35,8 @@ import static de.cotto.lndmanagej.pickhardtpayments.model.EdgeFixtures.EDGE; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -53,10 +59,14 @@ class EdgeComputationTest { @Mock private MissionControlService missionControlService; + @Mock + private NodeService nodeService; + @BeforeEach void setUp() { lenient().when(grpcGetInfo.getPubkey()).thenReturn(PUBKEY_4); lenient().when(missionControlService.getMinimumOfRecentFailures(any(), any())).thenReturn(Optional.empty()); + lenient().when(nodeService.getNode(any())).thenReturn(NODE_PEER); } @Test @@ -91,6 +101,26 @@ class EdgeComputationTest { .contains(EdgeWithLiquidityInformation.forKnownLiquidity(EDGE, knownLiquidity)); } + @Test + void local_channel_not_found_as_end_node() { + mockEdge(); + when(grpcGetInfo.getPubkey()).thenReturn(EDGE.startNode()); + + assertThat(edgeComputation.getEdges().edges()) + .contains(EdgeWithLiquidityInformation.forKnownLiquidity(EDGE, Coins.NONE)); + } + + @Test + void reduces_liquidity_to_zero_for_offline_peer_as_end_node() { + mockEdge(); + mockOfflinePeer(); + when(grpcGetInfo.getPubkey()).thenReturn(EDGE.startNode()); + + assertThat(edgeComputation.getEdges().edges()) + .contains(EdgeWithLiquidityInformation.forKnownLiquidity(EDGE, Coins.NONE)); + verify(balanceService, never()).getAvailableLocalBalance(EDGE.channelId()); + } + @Test void adds_liquidity_information_for_local_channel_as_target() { mockEdge(); @@ -103,6 +133,32 @@ class EdgeComputationTest { .contains(EdgeWithLiquidityInformation.forKnownLiquidity(EDGE, knownLiquidity)); } + @Test + void local_channel_not_found_as_start_node() { + mockEdge(); + when(grpcGetInfo.getPubkey()).thenReturn(EDGE.endNode()); + + assertThat(edgeComputation.getEdges().edges()) + .contains(EdgeWithLiquidityInformation.forKnownLiquidity(EDGE, Coins.NONE)); + } + + @Test + void reduces_liquidity_to_zero_for_offline_peer_as_start_node() { + mockEdge(); + mockOfflinePeer(); + when(grpcGetInfo.getPubkey()).thenReturn(EDGE.endNode()); + + assertThat(edgeComputation.getEdges().edges()) + .contains(EdgeWithLiquidityInformation.forKnownLiquidity(EDGE, Coins.NONE)); + verify(balanceService, never()).getAvailableLocalBalance(EDGE.channelId()); + } + + private void mockOfflinePeer() { + Pubkey remotePubkey = LOCAL_OPEN_CHANNEL.getRemotePubkey(); + when(nodeService.getNode(remotePubkey)).thenReturn(new Node(remotePubkey, "", 0, false)); + when(channelService.getLocalChannel(EDGE.channelId())).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL)); + } + @Test void adds_upper_bound_from_mission_control() { mockEdge();