diff --git a/backend/src/main/java/de/cotto/lndmanagej/service/RouteHintService.java b/backend/src/main/java/de/cotto/lndmanagej/service/RouteHintService.java index 813a68c8..7299366d 100644 --- a/backend/src/main/java/de/cotto/lndmanagej/service/RouteHintService.java +++ b/backend/src/main/java/de/cotto/lndmanagej/service/RouteHintService.java @@ -19,6 +19,7 @@ import java.util.stream.Collectors; @Component public class RouteHintService { + private static final Coins ONE_MILLI_SATOSHI = Coins.ofMilliSatoshis(1); private static final Coins FIFTY_COINS = Coins.ofSatoshis(5_000_000_000L); private static final Duration MAX_AGE = Duration.ofHours(1); @@ -55,7 +56,14 @@ public class RouteHintService { } private Policy toPolicy(RouteHint routeHint) { - return new Policy(routeHint.feeRate(), routeHint.baseFee(), true, routeHint.cltvExpiryDelta(), FIFTY_COINS); + return new Policy( + routeHint.feeRate(), + routeHint.baseFee(), + true, + routeHint.cltvExpiryDelta(), + ONE_MILLI_SATOSHI, + FIFTY_COINS + ); } @SuppressWarnings("UnusedVariable") diff --git a/backend/src/test/java/de/cotto/lndmanagej/service/GraphServiceTest.java b/backend/src/test/java/de/cotto/lndmanagej/service/GraphServiceTest.java index 1f5771cf..91d92807 100644 --- a/backend/src/test/java/de/cotto/lndmanagej/service/GraphServiceTest.java +++ b/backend/src/test/java/de/cotto/lndmanagej/service/GraphServiceTest.java @@ -77,7 +77,7 @@ class GraphServiceTest { @Test void getNodesWithHighFeeRate_ignores_disabled_channels() { Set edges = edges(9, 200, PUBKEY_2); - Policy policy = new Policy(2_000, Coins.NONE, false, 40, Coins.ofSatoshis(10_000)); + Policy policy = new Policy(2_000, Coins.NONE, false, 40, Coins.ofMilliSatoshis(1), Coins.ofSatoshis(10_000)); edges.add(edge(policy, Coins.ofSatoshis(10_000_000), PUBKEY_2)); assertThat(graphService.getNodesWithHighFeeRate()).isEmpty(); } @@ -135,7 +135,7 @@ class GraphServiceTest { } private DirectedChannelEdge edge(long feeRate, long capacityMillionSat, Pubkey target) { - Policy policy = new Policy(feeRate, Coins.NONE, true, 40, Coins.ofSatoshis(10_000)); + Policy policy = new Policy(feeRate, Coins.NONE, true, 40, Coins.ofMilliSatoshis(1), Coins.ofSatoshis(10_000)); Coins capacity = Coins.ofSatoshis(capacityMillionSat * 1_000_000); return edge(policy, capacity, target); } diff --git a/backend/src/test/java/de/cotto/lndmanagej/service/PolicyServiceTest.java b/backend/src/test/java/de/cotto/lndmanagej/service/PolicyServiceTest.java index b685be98..7a757a2a 100644 --- a/backend/src/test/java/de/cotto/lndmanagej/service/PolicyServiceTest.java +++ b/backend/src/test/java/de/cotto/lndmanagej/service/PolicyServiceTest.java @@ -108,8 +108,9 @@ class PolicyServiceTest { } private void mockPolicy(ChannelId channelId, int feeRate) { + Policy policy = new Policy(feeRate, Coins.NONE, false, 0, Coins.NONE, Coins.NONE); when(grpcChannelPolicy.getPolicyFrom(channelId, PUBKEY)) - .thenReturn(Optional.of(new Policy(feeRate, Coins.NONE, false, 0, Coins.NONE))); + .thenReturn(Optional.of(policy)); } } @@ -137,8 +138,9 @@ class PolicyServiceTest { } private void mockPolicy(ChannelId channelId, int feeRate) { + Policy policy = new Policy(feeRate, Coins.NONE, false, 0, Coins.NONE, Coins.NONE); when(grpcChannelPolicy.getPolicyTo(channelId, PUBKEY)) - .thenReturn(Optional.of(new Policy(feeRate, Coins.NONE, false, 0, Coins.NONE))); + .thenReturn(Optional.of(policy)); } } } diff --git a/backend/src/test/java/de/cotto/lndmanagej/service/RouteHintServiceTest.java b/backend/src/test/java/de/cotto/lndmanagej/service/RouteHintServiceTest.java index fc96b67e..68803871 100644 --- a/backend/src/test/java/de/cotto/lndmanagej/service/RouteHintServiceTest.java +++ b/backend/src/test/java/de/cotto/lndmanagej/service/RouteHintServiceTest.java @@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThatCode; @ExtendWith(MockitoExtension.class) class RouteHintServiceTest { + private static final Coins ONE_MILLI_SATOSHI = Coins.ofMilliSatoshis(1); private static final Coins FIFTY_COINS = Coins.ofSatoshis(5_000_000_000L); @InjectMocks @@ -36,8 +37,8 @@ class RouteHintServiceTest { @Test void get_after_adding_decoded_payment_request() { routeHintService.addDecodedPaymentRequest(DECODED_PAYMENT_REQUEST); - Policy policy1 = new Policy(123, Coins.NONE, true, 9, FIFTY_COINS); - Policy policy2 = new Policy(1234, Coins.ofMilliSatoshis(1), true, 40, FIFTY_COINS); + Policy policy1 = new Policy(123, Coins.NONE, true, 9, ONE_MILLI_SATOSHI, FIFTY_COINS); + Policy policy2 = new Policy(1234, ONE_MILLI_SATOSHI, true, 40, ONE_MILLI_SATOSHI, FIFTY_COINS); DirectedChannelEdge edge1 = new DirectedChannelEdge(CHANNEL_ID, FIFTY_COINS, PUBKEY, PUBKEY_4, policy1); DirectedChannelEdge edge2 = new DirectedChannelEdge(CHANNEL_ID_2, FIFTY_COINS, PUBKEY_3, PUBKEY_4, policy2); assertThat(routeHintService.getEdgesFromPaymentHints()).contains(edge1, edge2); diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcGraph.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcGraph.java index cc1866a1..b173aca2 100644 --- a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcGraph.java +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcGraph.java @@ -18,7 +18,7 @@ import java.util.Set; @Component public class GrpcGraph { - private static final Policy DEFAULT_DISABLED_POLICY = new Policy(0, Coins.NONE, false, 0, Coins.NONE); + private static final Policy DEFAULT_DISABLED_POLICY = new Policy(0, Coins.NONE, false, 0, Coins.NONE, Coins.NONE); private final GrpcService grpcService; private final LoadingCache>> channelEdgeCache; private final GrpcPolicy grpcPolicy; diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPolicy.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPolicy.java index 3e11f681..2be92e06 100644 --- a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPolicy.java +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPolicy.java @@ -17,6 +17,7 @@ public class GrpcPolicy { Coins.ofMilliSatoshis(routingPolicy.getFeeBaseMsat()), !routingPolicy.getDisabled(), routingPolicy.getTimeLockDelta(), + Coins.ofMilliSatoshis(routingPolicy.getMinHtlc()), Coins.ofMilliSatoshis(routingPolicy.getMaxHtlcMsat()) ); } diff --git a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelPolicyTest.java b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelPolicyTest.java index 4e7b23ea..ceb31af2 100644 --- a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelPolicyTest.java +++ b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelPolicyTest.java @@ -29,6 +29,7 @@ class GrpcChannelPolicyTest { private static final int FEE_RATE_FIRST = 123; private static final int FEE_RATE_SECOND = 456; private static final int TIME_LOCK_DELTA = 40; + private static final Coins MIN_HTLC = Coins.ofMilliSatoshis(159); private static final Coins MAX_HTLC = Coins.ofMilliSatoshis(5_432); @InjectMocks @@ -53,14 +54,14 @@ class GrpcChannelPolicyTest { void getLocalPolicy_local_first() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY, PUBKEY_2))); assertThat(grpcChannelPolicy.getLocalPolicy(CHANNEL_ID)) - .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test void getLocalPolicy_local_second() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY_2, PUBKEY))); assertThat(grpcChannelPolicy.getLocalPolicy(CHANNEL_ID)) - .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test @@ -78,14 +79,14 @@ class GrpcChannelPolicyTest { void getRemotePolicy_local_first() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY, PUBKEY_2))); assertThat(grpcChannelPolicy.getRemotePolicy(CHANNEL_ID)) - .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test void getRemotePolicy_local_second() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY_2, PUBKEY))); assertThat(grpcChannelPolicy.getRemotePolicy(CHANNEL_ID)) - .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test @@ -98,14 +99,14 @@ class GrpcChannelPolicyTest { void getPolicyFrom_first() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY_2, PUBKEY_3))); assertThat(grpcChannelPolicy.getPolicyFrom(CHANNEL_ID, PUBKEY_2)) - .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test void getPolicyFrom_second() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY_2, PUBKEY_3))); assertThat(grpcChannelPolicy.getPolicyFrom(CHANNEL_ID, PUBKEY_3)) - .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test @@ -118,14 +119,14 @@ class GrpcChannelPolicyTest { void getPolicyTo_first() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY_2, PUBKEY_3))); assertThat(grpcChannelPolicy.getPolicyTo(CHANNEL_ID, PUBKEY_3)) - .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_FIRST, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test void getPolicyTo_second() { when(grpcService.getChannelEdge(CHANNEL_ID)).thenReturn(Optional.of(channelEdge(PUBKEY_2, PUBKEY_3))); assertThat(grpcChannelPolicy.getPolicyTo(CHANNEL_ID, PUBKEY_2)) - .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MAX_HTLC)); + .contains(new Policy(FEE_RATE_SECOND, Coins.NONE, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC)); } @Test @@ -175,7 +176,8 @@ class GrpcChannelPolicyTest { return RoutingPolicy.newBuilder() .setFeeRateMilliMsat(feeRate) .setTimeLockDelta(TIME_LOCK_DELTA) - .setMaxHtlcMsat(5_432) + .setMinHtlc(MIN_HTLC.milliSatoshis()) + .setMaxHtlcMsat(MAX_HTLC.milliSatoshis()) .build(); } } diff --git a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcGraphTest.java b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcGraphTest.java index de8a1468..a35cfcfc 100644 --- a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcGraphTest.java +++ b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcGraphTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class GrpcGraphTest { + private static final Coins MIN_HTLC = Coins.ofMilliSatoshis(159); private static final Coins MAX_HTLC = Coins.ofMilliSatoshis(5_432); @InjectMocks private GrpcGraph grpcGraph; @@ -76,14 +77,14 @@ class GrpcGraphTest { CAPACITY, PUBKEY, PUBKEY_2, - new Policy(0, Coins.NONE, false, 40, MAX_HTLC) + new Policy(0, Coins.NONE, false, 40, MIN_HTLC, MAX_HTLC) ); DirectedChannelEdge expectedEdge2 = new DirectedChannelEdge( CHANNEL_ID, CAPACITY, PUBKEY_2, PUBKEY, - new Policy(1, Coins.NONE, true, 144, MAX_HTLC) + new Policy(1, Coins.NONE, true, 144, MIN_HTLC, MAX_HTLC) ); ChannelEdge edge2 = ChannelEdge.newBuilder() .setChannelId(CHANNEL_ID_2.getShortChannelId()) @@ -98,14 +99,14 @@ class GrpcGraphTest { CAPACITY_2, PUBKEY_3, PUBKEY_4, - new Policy(456, Coins.NONE, true, 123, MAX_HTLC) + new Policy(456, Coins.NONE, true, 123, MIN_HTLC, MAX_HTLC) ); DirectedChannelEdge expectedEdge4 = new DirectedChannelEdge( CHANNEL_ID_2, CAPACITY_2, PUBKEY_4, PUBKEY_3, - new Policy(123, Coins.ofMilliSatoshis(1), true, 456, MAX_HTLC) + new Policy(123, Coins.ofMilliSatoshis(1), true, 456, MIN_HTLC, MAX_HTLC) ); ChannelGraph channelGraph = ChannelGraph.newBuilder() .addEdges(edge1) @@ -130,14 +131,14 @@ class GrpcGraphTest { CAPACITY, PUBKEY, PUBKEY_2, - new Policy(0, Coins.NONE, false, 0, Coins.NONE) + new Policy(0, Coins.NONE, false, 0, Coins.NONE, Coins.NONE) ); DirectedChannelEdge expectedPolicyForNode2 = new DirectedChannelEdge( CHANNEL_ID, CAPACITY, PUBKEY_2, PUBKEY, - new Policy(0, Coins.NONE, false, 0, Coins.NONE) + new Policy(0, Coins.NONE, false, 0, Coins.NONE, Coins.NONE) ); ChannelGraph channelGraph = ChannelGraph.newBuilder().addEdges(edgeWithMissingPolicy).build(); when(grpcService.describeGraph()).thenReturn(Optional.of(channelGraph)); @@ -160,7 +161,8 @@ class GrpcGraphTest { .setFeeBaseMsat(baseFee) .setDisabled(disabled) .setTimeLockDelta(timeLockDelta) - .setMaxHtlcMsat(5_432) + .setMinHtlc(MIN_HTLC.milliSatoshis()) + .setMaxHtlcMsat(MAX_HTLC.milliSatoshis()) .build(); } } diff --git a/model/src/main/java/de/cotto/lndmanagej/model/Policy.java b/model/src/main/java/de/cotto/lndmanagej/model/Policy.java index 3f5746d6..4cc1409a 100644 --- a/model/src/main/java/de/cotto/lndmanagej/model/Policy.java +++ b/model/src/main/java/de/cotto/lndmanagej/model/Policy.java @@ -1,7 +1,7 @@ package de.cotto.lndmanagej.model; -public record Policy(long feeRate, Coins baseFee, boolean enabled, int timeLockDelta, Coins maxHtlc) { - public static final Policy UNKNOWN = new Policy(0, Coins.NONE, false, 0, Coins.NONE); +public record Policy(long feeRate, Coins baseFee, boolean enabled, int timeLockDelta, Coins minHtlc, Coins maxHtlc) { + public static final Policy UNKNOWN = new Policy(0, Coins.NONE, false, 0, Coins.NONE, Coins.NONE); public boolean disabled() { return !enabled; diff --git a/model/src/test/java/de/cotto/lndmanagej/model/PolicyTest.java b/model/src/test/java/de/cotto/lndmanagej/model/PolicyTest.java index dd2def23..753e87b4 100644 --- a/model/src/test/java/de/cotto/lndmanagej/model/PolicyTest.java +++ b/model/src/test/java/de/cotto/lndmanagej/model/PolicyTest.java @@ -30,6 +30,11 @@ class PolicyTest { assertThat(POLICY_DISABLED.disabled()).isTrue(); } + @Test + void minHtlc() { + assertThat(POLICY_1.minHtlc()).isEqualTo(Coins.ofSatoshis(159)); + } + @Test void maxHtlc() { assertThat(POLICY_1.maxHtlc()).isEqualTo(Coins.ofSatoshis(10_000)); @@ -37,6 +42,6 @@ class PolicyTest { @Test void unknown() { - assertThat(Policy.UNKNOWN).isEqualTo(new Policy(0, Coins.NONE, false, 0, Coins.NONE)); + assertThat(Policy.UNKNOWN).isEqualTo(new Policy(0, Coins.NONE, false, 0, Coins.NONE, Coins.NONE)); } } diff --git a/model/src/test/java/de/cotto/lndmanagej/model/RouteTest.java b/model/src/test/java/de/cotto/lndmanagej/model/RouteTest.java index f8b2944c..c15b514e 100644 --- a/model/src/test/java/de/cotto/lndmanagej/model/RouteTest.java +++ b/model/src/test/java/de/cotto/lndmanagej/model/RouteTest.java @@ -29,6 +29,7 @@ class RouteTest { private static final int ONE_MILLION = 1_000_000; private static final int TIME_LOCK_DELTA = 40; private static final int BLOCK_HEIGHT = 700_000; + private static final Coins MIN_HTLC = Coins.ofSatoshis(159); private static final Coins MAX_HTLC = Coins.ofSatoshis(12_345); @Test @@ -495,12 +496,12 @@ class RouteTest { private List edgesWithTimeLockDeltas(int... timeLockDeltas) { return Arrays.stream(timeLockDeltas) - .mapToObj(timeLockDelta -> new Policy(0, Coins.NONE, true, timeLockDelta, MAX_HTLC)) + .mapToObj(timeLockDelta -> new Policy(0, Coins.NONE, true, timeLockDelta, MIN_HTLC, MAX_HTLC)) .map(policy -> new Edge(CHANNEL_ID, PUBKEY, PUBKEY_2, CAPACITY, policy)) .toList(); } private Policy policy(Coins baseFee, int ppm) { - return new Policy(ppm, baseFee, true, TIME_LOCK_DELTA, MAX_HTLC); + return new Policy(ppm, baseFee, true, TIME_LOCK_DELTA, MIN_HTLC, MAX_HTLC); } } diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/PolicyFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/PolicyFixtures.java index 6b2b7c39..e943dee1 100644 --- a/model/src/testFixtures/java/de/cotto/lndmanagej/model/PolicyFixtures.java +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/PolicyFixtures.java @@ -2,13 +2,13 @@ package de.cotto.lndmanagej.model; public class PolicyFixtures { public static final Policy POLICY_1 = - new Policy(200, Coins.NONE, true, 40, Coins.ofSatoshis(10_000)); + new Policy(200, Coins.NONE, true, 40, Coins.ofSatoshis(159), Coins.ofSatoshis(10_000)); public static final Policy POLICY_WITH_BASE_FEE = - new Policy(200, Coins.ofMilliSatoshis(10), true, 40, Coins.ofSatoshis(10_000)); + new Policy(200, Coins.ofMilliSatoshis(10), true, 40, Coins.ofSatoshis(159), Coins.ofSatoshis(10_000)); public static final Policy POLICY_DISABLED = - new Policy(200, Coins.NONE, false, 40, Coins.ofSatoshis(0)); + new Policy(200, Coins.NONE, false, 40, Coins.NONE, Coins.NONE); public static final Policy POLICY_2 = - new Policy(300, Coins.ofMilliSatoshis(0), true, 144, Coins.ofSatoshis(22_222)); + new Policy(300, Coins.ofMilliSatoshis(0), true, 144, Coins.ofSatoshis(159), Coins.ofSatoshis(22_222)); public static final PoliciesForLocalChannel POLICIES_FOR_LOCAL_CHANNEL = new PoliciesForLocalChannel(POLICY_DISABLED, POLICY_2); diff --git a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java index ecfd4b94..8bcefd89 100644 --- a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java +++ b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java @@ -324,7 +324,7 @@ class ArcInitializerTest { ArcInitializer arcInitializer = getArcInitializer(quantization, feeRateWeight); addEdgeWithBaseFee(baseFee, quantization, arcInitializer); - long expectedFeeRate = (long) Math.ceil(200 + 10); + long expectedFeeRate = 210; assertThat(minCostFlow.getUnitCost(0)).isEqualTo(expectedFeeRate); } @@ -337,12 +337,12 @@ class ArcInitializerTest { ArcInitializer arcInitializer = getArcInitializer(quantization, feeRateWeight); addEdgeWithBaseFee(baseFee, quantization, arcInitializer); - long expectedFeeRate = (long) Math.ceil(200 + 12); + long expectedFeeRate = 212; assertThat(minCostFlow.getUnitCost(0)).isEqualTo(expectedFeeRate); } private void addEdgeWithBaseFee(Coins baseFee, int quantization, ArcInitializer arcInitializer) { - Policy policy = new Policy(200, baseFee, true, 40, Coins.ofSatoshis(10_000)); + Policy policy = new Policy(200, baseFee, true, 40, Coins.ofMilliSatoshis(1), Coins.ofSatoshis(10_000)); EdgeWithLiquidityInformation edge = EdgeWithLiquidityInformation.forKnownLiquidity( new Edge(CHANNEL_ID, PUBKEY, PUBKEY_2, CAPACITY, policy), Coins.ofSatoshis(30L * quantization) 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 845452e9..4daf0b51 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 @@ -117,7 +117,7 @@ class EdgeComputationTest { void does_not_add_edge_exceeding_maximum_time_lock_delta() { int edgeDelta = 40; int maximumTimeLockDelta = edgeDelta - 1; - Policy policy = new Policy(0, Coins.NONE, true, edgeDelta, Coins.ofSatoshis(10_000)); + Policy policy = new Policy(0, Coins.NONE, true, edgeDelta, Coins.ofMilliSatoshis(1), Coins.ofSatoshis(10_000)); DirectedChannelEdge edge = new DirectedChannelEdge(CHANNEL_ID, CAPACITY, PUBKEY, PUBKEY_2, policy); when(grpcGraph.getChannelEdges()).thenReturn(Optional.of(Set.of(edge))); assertThat(edgeComputation.getEdges(DEFAULT_PAYMENT_OPTIONS, maximumTimeLockDelta).edges()).isEmpty(); @@ -228,8 +228,9 @@ class EdgeComputationTest { @Test void adds_edge_from_route_hint_service() { when(grpcGraph.getChannelEdges()).thenReturn(Optional.of(Set.of())); + Coins oneMilliSatoshi = Coins.ofMilliSatoshis(1); Coins fiftyCoins = Coins.ofSatoshis(5_000_000_000L); - Policy policy = new Policy(200, Coins.NONE, true, 40, fiftyCoins); + Policy policy = new Policy(200, Coins.NONE, true, 40, oneMilliSatoshi, fiftyCoins); Edge edge = new Edge(CHANNEL_ID, PUBKEY, PUBKEY_2, fiftyCoins, policy); when(routeHintService.getEdgesFromPaymentHints()).thenReturn(Set.of( new DirectedChannelEdge( @@ -447,7 +448,7 @@ class EdgeComputationTest { } private static Policy policy(int feeRate) { - return new Policy(feeRate, Coins.NONE, true, 40, Coins.ofSatoshis(0)); + return new Policy(feeRate, Coins.NONE, true, 40, Coins.NONE, Coins.NONE); } private void mockInactiveChannel() { diff --git a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/MultiPathPaymentSplitterTest.java b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/MultiPathPaymentSplitterTest.java index e9ab03a7..16739dcd 100644 --- a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/MultiPathPaymentSplitterTest.java +++ b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/MultiPathPaymentSplitterTest.java @@ -626,7 +626,7 @@ class MultiPathPaymentSplitterTest { private Edge mockExtensionEdge(Pubkey destination, int feeRate) { Policy policyExtension = - new Policy(feeRate, Coins.NONE, true, 40, Coins.ofSatoshis(10_000)); + new Policy(feeRate, Coins.NONE, true, 40, Coins.ofMilliSatoshis(1), Coins.ofSatoshis(10_000)); when(channelService.getOpenChannelsWith(PUBKEY_2)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL)); when(policyService.getPolicyFrom(CHANNEL_ID, PUBKEY_2)).thenReturn(Optional.of(policyExtension)); Edge extensionEdge = @@ -637,7 +637,7 @@ class MultiPathPaymentSplitterTest { } private static Policy policyFor(int feeRate) { - return new Policy(feeRate, Coins.NONE, true, 40, Coins.ofSatoshis(10_000)); + return new Policy(feeRate, Coins.NONE, true, 40, Coins.ofMilliSatoshis(1), Coins.ofSatoshis(10_000)); } private EdgeWithLiquidityInformation noInformationFor(Edge edgeSmallCapacity) { diff --git a/ui-demo/src/main/java/de/cotto/lndmanagej/ui/demo/data/DeriveDataUtil.java b/ui-demo/src/main/java/de/cotto/lndmanagej/ui/demo/data/DeriveDataUtil.java index 84072ed8..00a0d075 100644 --- a/ui-demo/src/main/java/de/cotto/lndmanagej/ui/demo/data/DeriveDataUtil.java +++ b/ui-demo/src/main/java/de/cotto/lndmanagej/ui/demo/data/DeriveDataUtil.java @@ -25,6 +25,7 @@ import static de.cotto.lndmanagej.model.OpenInitiator.REMOTE; @SuppressWarnings("PMD.TooManyMethods") public final class DeriveDataUtil { + private static final Coins MIN_HTLC = Coins.ofMilliSatoshis(1); private static final Coins MAX_HTLC = Coins.ofSatoshis(1_000_000); private DeriveDataUtil() { @@ -98,7 +99,7 @@ public final class DeriveDataUtil { Coins baseFee = Coins.ofMilliSatoshis(rand.nextLong(2) * 1000); boolean enabled = rand.nextInt(10) != 0; int timeLockDelta = (rand.nextInt(5) + 1) * 10; - return new Policy(feeRate, baseFee, enabled, timeLockDelta, MAX_HTLC); + return new Policy(feeRate, baseFee, enabled, timeLockDelta, MIN_HTLC, MAX_HTLC); } static ChannelStatusDto deriveChannelStatus(ChannelId channelId) { diff --git a/ui/src/test/java/de/cotto/lndmanagej/ui/page/PageServiceTest.java b/ui/src/test/java/de/cotto/lndmanagej/ui/page/PageServiceTest.java index 6745cfc0..4d021fd4 100644 --- a/ui/src/test/java/de/cotto/lndmanagej/ui/page/PageServiceTest.java +++ b/ui/src/test/java/de/cotto/lndmanagej/ui/page/PageServiceTest.java @@ -397,7 +397,7 @@ class PageServiceTest { } private static PolicyDto policy(int feeRate, int baseFee) { - return new PolicyDto(feeRate, String.valueOf(baseFee), true, 0, "0"); + return new PolicyDto(feeRate, String.valueOf(baseFee), true, 0, "0", "0"); } private BalanceInformation balanceWithRemoteSat(int satoshis) { diff --git a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java index 53228ac5..06cccd6e 100644 --- a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java +++ b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java @@ -170,11 +170,13 @@ class ChannelControllerIT { .jsonPath("$.policies.local.feeRatePpm").value(is(200)) .jsonPath("$.policies.local.baseFeeMilliSat").value(is("0")) .jsonPath("$.policies.local.timeLockDelta").value(is(40)) + .jsonPath("$.policies.local.minHtlcMilliSat").value(is("0")) .jsonPath("$.policies.local.maxHtlcMilliSat").value(is("0")) .jsonPath("$.policies.remote.enabled").value(is(true)) .jsonPath("$.policies.remote.feeRatePpm").value(is(300)) .jsonPath("$.policies.remote.baseFeeMilliSat").value(is("0")) .jsonPath("$.policies.remote.timeLockDelta").value(is(144)) + .jsonPath("$.policies.remote.minHtlcMilliSat").value(is("159000")) .jsonPath("$.policies.remote.maxHtlcMilliSat").value(is("22222000")) .jsonPath("$.feeReport.earnedMilliSat").value(is("1234")) .jsonPath("$.feeReport.sourcedMilliSat").value(is("567")) diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java index c46824de..1f715343 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java @@ -7,6 +7,7 @@ public record PolicyDto( String baseFeeMilliSat, boolean enabled, int timeLockDelta, + String minHtlcMilliSat, String maxHtlcMilliSat ) { public static PolicyDto createFromModel(Policy policy) { @@ -15,6 +16,7 @@ public record PolicyDto( String.valueOf(policy.baseFee().milliSatoshis()), policy.enabled(), policy.timeLockDelta(), + String.valueOf(policy.minHtlc().milliSatoshis()), String.valueOf(policy.maxHtlc().milliSatoshis()) ); } diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java index 88c498b0..03b6635a 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java @@ -9,14 +9,14 @@ import static org.assertj.core.api.Assertions.assertThat; class PolicyDtoTest { @Test void createFromModel_disabled() { - PolicyDto expected = new PolicyDto(200, "0", false, 40, "0"); + PolicyDto expected = new PolicyDto(200, "0", false, 40, "0", "0"); PolicyDto dto = PolicyDto.createFromModel(POLICY_DISABLED); assertThat(dto).isEqualTo(expected); } @Test void createFromModel_with_base_fee() { - PolicyDto expected = new PolicyDto(200, "10", true, 40, "10000000"); + PolicyDto expected = new PolicyDto(200, "10", true, 40, "159000", "10000000"); PolicyDto dto = PolicyDto.createFromModel(POLICY_WITH_BASE_FEE); assertThat(dto).isEqualTo(expected); }