mirror of
https://github.com/aljazceru/lnd-manageJ.git
synced 2026-01-21 06:54:29 +01:00
get LN graph via gRPC
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package de.cotto.lndmanagej.grpc;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import de.cotto.lndmanagej.caching.CacheBuilder;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.DirectedChannelEdge;
|
||||
import de.cotto.lndmanagej.model.Policy;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import lnrpc.ChannelEdge;
|
||||
import lnrpc.ChannelGraph;
|
||||
import lnrpc.RoutingPolicy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
public class GrpcGraph {
|
||||
private final GrpcService grpcService;
|
||||
private final LoadingCache<Object, Optional<Set<DirectedChannelEdge>>> channelEdgeCache;
|
||||
|
||||
public GrpcGraph(GrpcService grpcService) {
|
||||
this.grpcService = grpcService;
|
||||
channelEdgeCache = new CacheBuilder()
|
||||
.withExpiry(Duration.ofMinutes(2))
|
||||
.withRefresh(Duration.ofMinutes(1))
|
||||
.withSoftValues(true)
|
||||
.build(this::getChannelEdgesWithoutCache);
|
||||
}
|
||||
|
||||
public Optional<Set<DirectedChannelEdge>> getChannelEdges() {
|
||||
return channelEdgeCache.get("");
|
||||
}
|
||||
|
||||
public Optional<Set<DirectedChannelEdge>> getChannelEdgesWithoutCache() {
|
||||
ChannelGraph channelGraph = grpcService.describeGraph().orElse(null);
|
||||
if (channelGraph == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Set<DirectedChannelEdge> channelEdges = new LinkedHashSet<>();
|
||||
for (ChannelEdge channelEdge : channelGraph.getEdgesList()) {
|
||||
ChannelId channelId = ChannelId.fromShortChannelId(channelEdge.getChannelId());
|
||||
Coins capacity = Coins.ofSatoshis(channelEdge.getCapacity());
|
||||
Pubkey node1Pubkey = Pubkey.create(channelEdge.getNode1Pub());
|
||||
Pubkey node2Pubkey = Pubkey.create(channelEdge.getNode2Pub());
|
||||
DirectedChannelEdge directedChannelEdge1 = new DirectedChannelEdge(
|
||||
channelId,
|
||||
capacity,
|
||||
node1Pubkey,
|
||||
node2Pubkey,
|
||||
toPolicy(channelEdge.getNode1Policy())
|
||||
);
|
||||
DirectedChannelEdge directedChannelEdge2 = new DirectedChannelEdge(
|
||||
channelId,
|
||||
capacity,
|
||||
node2Pubkey,
|
||||
node1Pubkey,
|
||||
toPolicy(channelEdge.getNode2Policy())
|
||||
);
|
||||
channelEdges.add(directedChannelEdge1);
|
||||
channelEdges.add(directedChannelEdge2);
|
||||
}
|
||||
return Optional.of(channelEdges);
|
||||
}
|
||||
|
||||
private Policy toPolicy(RoutingPolicy routingPolicy) {
|
||||
return new Policy(
|
||||
routingPolicy.getFeeRateMilliMsat(),
|
||||
Coins.ofMilliSatoshis(routingPolicy.getFeeBaseMsat()),
|
||||
!routingPolicy.getDisabled()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import lnrpc.ChanInfoRequest;
|
||||
import lnrpc.Channel;
|
||||
import lnrpc.ChannelCloseSummary;
|
||||
import lnrpc.ChannelEdge;
|
||||
import lnrpc.ChannelGraph;
|
||||
import lnrpc.ChannelGraphRequest;
|
||||
import lnrpc.ClosedChannelsRequest;
|
||||
import lnrpc.ForwardingHistoryRequest;
|
||||
import lnrpc.ForwardingHistoryResponse;
|
||||
@@ -182,6 +184,14 @@ public class GrpcService extends GrpcBase {
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Timed
|
||||
public Optional<ChannelGraph> describeGraph() {
|
||||
ChannelGraphRequest request = ChannelGraphRequest.newBuilder()
|
||||
.setIncludeUnannounced(true)
|
||||
.build();
|
||||
return get(() -> lightningStub.describeGraph(request));
|
||||
}
|
||||
|
||||
private Optional<List<Transaction>> getTransactionsWithoutCache() {
|
||||
return get(
|
||||
() -> lightningStub.getTransactions(GetTransactionsRequest.getDefaultInstance()).getTransactionsList()
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package de.cotto.lndmanagej.grpc;
|
||||
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.DirectedChannelEdge;
|
||||
import de.cotto.lndmanagej.model.Policy;
|
||||
import lnrpc.ChannelEdge;
|
||||
import lnrpc.ChannelGraph;
|
||||
import lnrpc.RoutingPolicy;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY;
|
||||
import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY_2;
|
||||
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID;
|
||||
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_2;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_3;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_4;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class GrpcGraphTest {
|
||||
@Mock
|
||||
private GrpcService grpcService;
|
||||
|
||||
@InjectMocks
|
||||
private GrpcGraph grpcGraph;
|
||||
|
||||
@Test
|
||||
void empty() {
|
||||
when(grpcService.describeGraph()).thenReturn(Optional.empty());
|
||||
assertThat(grpcGraph.getChannelEdges()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void no_edge() {
|
||||
ChannelGraph channelGraph = ChannelGraph.getDefaultInstance();
|
||||
when(grpcService.describeGraph()).thenReturn(Optional.of(channelGraph));
|
||||
assertThat(grpcGraph.getChannelEdges()).contains(Set.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
void two_edges() {
|
||||
ChannelEdge edge1 = ChannelEdge.newBuilder()
|
||||
.setChannelId(CHANNEL_ID.getShortChannelId())
|
||||
.setCapacity(CAPACITY.satoshis())
|
||||
.setNode1Pub(PUBKEY.toString())
|
||||
.setNode2Pub(PUBKEY_2.toString())
|
||||
.setNode1Policy(policy(0, 0, true))
|
||||
.setNode2Policy(policy(1, 0, false))
|
||||
.build();
|
||||
DirectedChannelEdge expectedEdge1 = new DirectedChannelEdge(
|
||||
CHANNEL_ID,
|
||||
CAPACITY,
|
||||
PUBKEY,
|
||||
PUBKEY_2,
|
||||
new Policy(0, Coins.NONE, false)
|
||||
);
|
||||
DirectedChannelEdge expectedEdge2 = new DirectedChannelEdge(
|
||||
CHANNEL_ID,
|
||||
CAPACITY,
|
||||
PUBKEY_2,
|
||||
PUBKEY,
|
||||
new Policy(1, Coins.NONE, true)
|
||||
);
|
||||
ChannelEdge edge2 = ChannelEdge.newBuilder()
|
||||
.setChannelId(CHANNEL_ID_2.getShortChannelId())
|
||||
.setCapacity(CAPACITY_2.satoshis())
|
||||
.setNode1Pub(PUBKEY_3.toString())
|
||||
.setNode2Pub(PUBKEY_4.toString())
|
||||
.setNode1Policy(policy(456, 0, false))
|
||||
.setNode2Policy(policy(123, 1, false))
|
||||
.build();
|
||||
DirectedChannelEdge expectedEdge3 = new DirectedChannelEdge(
|
||||
CHANNEL_ID_2,
|
||||
CAPACITY_2,
|
||||
PUBKEY_3,
|
||||
PUBKEY_4,
|
||||
new Policy(456, Coins.NONE, true)
|
||||
);
|
||||
DirectedChannelEdge expectedEdge4 = new DirectedChannelEdge(
|
||||
CHANNEL_ID_2,
|
||||
CAPACITY_2,
|
||||
PUBKEY_4,
|
||||
PUBKEY_3,
|
||||
new Policy(123, Coins.ofMilliSatoshis(1), true)
|
||||
);
|
||||
ChannelGraph channelGraph = ChannelGraph.newBuilder()
|
||||
.addEdges(edge1)
|
||||
.addEdges(edge2)
|
||||
.build();
|
||||
when(grpcService.describeGraph()).thenReturn(Optional.of(channelGraph));
|
||||
assertThat(grpcGraph.getChannelEdges().orElseThrow()).containsExactlyInAnyOrder(
|
||||
expectedEdge1, expectedEdge2, expectedEdge3, expectedEdge4
|
||||
);
|
||||
}
|
||||
|
||||
private RoutingPolicy policy(int feeRate, int baseFee, boolean disabled) {
|
||||
return RoutingPolicy.newBuilder()
|
||||
.setFeeRateMilliMsat(feeRate)
|
||||
.setFeeBaseMsat(baseFee)
|
||||
.setDisabled(disabled)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package de.cotto.lndmanagej.model;
|
||||
|
||||
public record DirectedChannelEdge(ChannelId channelId, Coins capacity, Pubkey source, Pubkey target, Policy policy) {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.cotto.lndmanagej.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY;
|
||||
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID;
|
||||
import static de.cotto.lndmanagej.model.DirectedChannelEdgeFixtures.CHANNEL_EDGE_WITH_POLICY;
|
||||
import static de.cotto.lndmanagej.model.PolicyFixtures.POLICY_1;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DirectedChannelEdgeTest {
|
||||
@Test
|
||||
void channelId() {
|
||||
assertThat(CHANNEL_EDGE_WITH_POLICY.channelId()).isEqualTo(CHANNEL_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void capacity() {
|
||||
assertThat(CHANNEL_EDGE_WITH_POLICY.capacity()).isEqualTo(CAPACITY);
|
||||
}
|
||||
|
||||
@Test
|
||||
void source() {
|
||||
assertThat(CHANNEL_EDGE_WITH_POLICY.source()).isEqualTo(PUBKEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
void target() {
|
||||
assertThat(CHANNEL_EDGE_WITH_POLICY.target()).isEqualTo(PUBKEY_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void policy() {
|
||||
assertThat(CHANNEL_EDGE_WITH_POLICY.policy()).isEqualTo(POLICY_1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.cotto.lndmanagej.model;
|
||||
|
||||
import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY;
|
||||
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID;
|
||||
import static de.cotto.lndmanagej.model.PolicyFixtures.POLICY_1;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2;
|
||||
|
||||
public class DirectedChannelEdgeFixtures {
|
||||
public static final DirectedChannelEdge CHANNEL_EDGE_WITH_POLICY = new DirectedChannelEdge(
|
||||
CHANNEL_ID,
|
||||
CAPACITY,
|
||||
PUBKEY,
|
||||
PUBKEY_2,
|
||||
POLICY_1
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user