use channel capacity instead of upper bound

This commit is contained in:
Carsten Otto
2022-03-27 00:29:15 +01:00
parent 6a20dc453c
commit 3b3d5e8d95
4 changed files with 53 additions and 24 deletions

View File

@@ -64,7 +64,8 @@ class ArcInitializer {
private Coins getMaximumCapacity(Collection<EdgeWithLiquidityInformation> edgesWithCapacityInformation) {
return edgesWithCapacityInformation.stream()
.map(EdgeWithLiquidityInformation::availableLiquidityUpperBound)
.map(EdgeWithLiquidityInformation::edge)
.map(Edge::capacity)
.max(Comparator.naturalOrder())
.orElse(Coins.NONE);
}

View File

@@ -6,4 +6,7 @@ import de.cotto.lndmanagej.model.Policy;
import de.cotto.lndmanagej.model.Pubkey;
public record Edge(ChannelId channelId, Pubkey startNode, Pubkey endNode, Coins capacity, Policy policy) {
public Edge withCapacity(Coins capacity) {
return new Edge(channelId(), startNode(), endNode(), capacity, policy());
}
}

View File

@@ -47,7 +47,7 @@ class ArcInitializerTest {
@Test
void ignores_edge_with_zero_capacity() {
arcInitializer.addArcs(Set.of(EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.NONE)));
arcInitializer.addArcs(Set.of(edge(EDGE, Coins.NONE)));
assertThat(minCostFlow.getNumArcs()).isZero();
}
@@ -62,7 +62,7 @@ class ArcInitializerTest {
PIECEWISE_LINEAR_APPROXIMATIONS
);
EdgeWithLiquidityInformation edgeWithLiquidityInformation =
EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(quantization));
edge(EDGE, Coins.ofSatoshis(quantization));
arcInitializer.addArcs(Set.of(edgeWithLiquidityInformation));
assertThat(minCostFlow.getNumArcs()).isOne();
}
@@ -78,11 +78,11 @@ class ArcInitializerTest {
piecesPerChannel
);
arcInitializer.addArcs(List.of(
EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(100)),
EdgeWithLiquidityInformation.forUpperBound(EDGE_2_3, Coins.ofSatoshis(200))
edge(EDGE, Coins.ofSatoshis(100)),
edge(EDGE_2_3, Coins.ofSatoshis(200))
));
assertThat(edgeMapping.get(0)).isEqualTo(EDGE);
assertThat(edgeMapping.get(piecesPerChannel)).isEqualTo(EDGE_2_3);
assertThat(edgeMapping.get(0)).isEqualTo(EDGE.withCapacity(Coins.ofSatoshis(100)));
assertThat(edgeMapping.get(piecesPerChannel)).isEqualTo(EDGE_2_3.withCapacity(Coins.ofSatoshis(200)));
}
@Test
@@ -96,7 +96,7 @@ class ArcInitializerTest {
PIECEWISE_LINEAR_APPROXIMATIONS
);
EdgeWithLiquidityInformation edgeWithLiquidityInformation =
EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(quantization - 1));
edge(EDGE, Coins.ofSatoshis(quantization - 1));
arcInitializer.addArcs(Set.of(edgeWithLiquidityInformation));
assertThat(minCostFlow.getNumArcs()).isZero();
}
@@ -111,7 +111,7 @@ class ArcInitializerTest {
quantization,
PIECEWISE_LINEAR_APPROXIMATIONS
);
arcInitializer.addArcs(Set.of(EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(20_123))));
arcInitializer.addArcs(Set.of(edge(EDGE, Coins.ofSatoshis(20_123))));
assertThat(minCostFlow.getCapacity(0)).isEqualTo(201);
}
@@ -126,15 +126,15 @@ class ArcInitializerTest {
PIECEWISE_LINEAR_APPROXIMATIONS
);
arcInitializer.addArcs(List.of(
EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(20_123)),
EdgeWithLiquidityInformation.forUpperBound(EDGE_3_4, Coins.ofSatoshis(1_000_000))
edge(EDGE, Coins.ofSatoshis(20_123)),
edge(EDGE_3_4, Coins.ofSatoshis(1_000_000))
));
assertThat(minCostFlow.getUnitCost(0)).isEqualTo(49);
}
@Test
void one_edge() {
arcInitializer.addArcs(Set.of(EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(1))));
arcInitializer.addArcs(Set.of(edge(EDGE, Coins.ofSatoshis(1))));
assertThat(minCostFlow.getNumArcs()).isOne();
}
@@ -150,8 +150,8 @@ class ArcInitializerTest {
piecewiseLinearApproximations
);
arcInitializer.addArcs(List.of(
EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(10_000)),
EdgeWithLiquidityInformation.forUpperBound(EDGE_2_3, Coins.ofSatoshis(30_000))
edge(EDGE, Coins.ofSatoshis(10_000)),
edge(EDGE_2_3, Coins.ofSatoshis(30_000))
));
assertThat(minCostFlow.getNumArcs()).isEqualTo(10);
assertThat(minCostFlow.getUnitCost(0)).isEqualTo(3);
@@ -168,42 +168,59 @@ class ArcInitializerTest {
@Test
void two_edges() {
EdgeWithLiquidityInformation edge1 = EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(1));
EdgeWithLiquidityInformation edge2 = EdgeWithLiquidityInformation.forUpperBound(EDGE_1_3, Coins.ofSatoshis(2));
EdgeWithLiquidityInformation edge1 = edge(EDGE, Coins.ofSatoshis(1));
EdgeWithLiquidityInformation edge2 = edge(EDGE_1_3, Coins.ofSatoshis(2));
arcInitializer.addArcs(Set.of(edge1, edge2));
assertThat(minCostFlow.getNumArcs()).isEqualTo(2);
}
@Test
void parallel_edges_are_not_combined() {
EdgeWithLiquidityInformation edge = EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(1));
EdgeWithLiquidityInformation edge = edge(EDGE, Coins.ofSatoshis(1));
arcInitializer.addArcs(List.of(edge, edge));
assertThat(minCostFlow.getNumArcs()).isEqualTo(2);
}
@Test
void computes_unit_cost_based_on_maximum_capacity() {
EdgeWithLiquidityInformation edge1 = EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(3));
EdgeWithLiquidityInformation edge2 = EdgeWithLiquidityInformation.forUpperBound(EDGE_1_3, Coins.ofSatoshis(21));
EdgeWithLiquidityInformation edge1 = edge(EDGE, Coins.ofSatoshis(3));
EdgeWithLiquidityInformation edge2 = edge(EDGE_1_3, Coins.ofSatoshis(21));
arcInitializer.addArcs(List.of(edge1, edge2));
assertThat(minCostFlow.getUnitCost(0)).isEqualTo(7L);
assertThat(minCostFlow.getUnitCost(1)).isEqualTo(1L);
}
@Test
void computes_unit_cost_based_on_maximum_capacity_even_if_upper_bound_is_lower() {
EdgeWithLiquidityInformation edge1 = edge(EDGE, Coins.ofSatoshis(3));
EdgeWithLiquidityInformation edge2 = EdgeWithLiquidityInformation.forUpperBound(
EDGE_1_3.withCapacity(Coins.ofSatoshis(42)),
Coins.ofSatoshis(8)
);
arcInitializer.addArcs(List.of(edge1, edge2));
assertThat(minCostFlow.getUnitCost(0)).isEqualTo(42 / 3);
assertThat(minCostFlow.getUnitCost(1)).isEqualTo(42 / 8);
}
@Test
void unit_cost_is_rounded_down() {
EdgeWithLiquidityInformation edge1 = EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(3));
EdgeWithLiquidityInformation edge2 = EdgeWithLiquidityInformation.forUpperBound(EDGE_1_3, Coins.ofSatoshis(20));
EdgeWithLiquidityInformation edge1 = edge(EDGE, Coins.ofSatoshis(3));
EdgeWithLiquidityInformation edge2 = edge(EDGE_1_3, Coins.ofSatoshis(20));
arcInitializer.addArcs(List.of(edge1, edge2));
assertThat(minCostFlow.getUnitCost(0)).isEqualTo(6L);
}
@Test
void computes_unit_cost_based_on_maximum_capacity_without_combining_parallel_edges() {
EdgeWithLiquidityInformation edge1 = EdgeWithLiquidityInformation.forUpperBound(EDGE, Coins.ofSatoshis(2));
EdgeWithLiquidityInformation edge2 = EdgeWithLiquidityInformation.forUpperBound(EDGE_1_3, Coins.ofSatoshis(20));
EdgeWithLiquidityInformation edge3 = EdgeWithLiquidityInformation.forUpperBound(EDGE_1_3, Coins.ofSatoshis(10));
EdgeWithLiquidityInformation edge1 = edge(EDGE, Coins.ofSatoshis(2));
EdgeWithLiquidityInformation edge2 = edge(EDGE_1_3, Coins.ofSatoshis(20));
EdgeWithLiquidityInformation edge3 = edge(EDGE_1_3, Coins.ofSatoshis(10));
arcInitializer.addArcs(List.of(edge1, edge2, edge3));
assertThat(minCostFlow.getUnitCost(0)).isEqualTo(10L);
}
private EdgeWithLiquidityInformation edge(Edge edge, Coins capacity) {
Edge edgeWithCapacity = edge.withCapacity(capacity);
return EdgeWithLiquidityInformation.forUpperBound(edgeWithCapacity, capacity);
}
}

View File

@@ -1,5 +1,6 @@
package de.cotto.lndmanagej.pickhardtpayments.model;
import de.cotto.lndmanagej.model.Coins;
import org.junit.jupiter.api.Test;
import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY;
@@ -35,4 +36,11 @@ class EdgeTest {
void policy() {
assertThat(EDGE.policy()).isEqualTo(POLICY_1);
}
@Test
void withCapacity() {
Coins newCapacity = Coins.ofSatoshis(1);
Edge expected = new Edge(EDGE.channelId(), EDGE.startNode(), EDGE.endNode(), newCapacity, EDGE.policy());
assertThat(EDGE.withCapacity(newCapacity)).isEqualTo(expected);
}
}