get closed channels

This commit is contained in:
Carsten Otto
2021-11-15 09:25:06 +01:00
parent 66a1f809d1
commit 9013d23feb
18 changed files with 287 additions and 110 deletions

View File

@@ -19,9 +19,11 @@ import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_3;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_COMPACT;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_COMPACT_3;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_3;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_3;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_3;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS;
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2;
@@ -73,32 +75,39 @@ class LegacyControllerIT {
@Test
void getOpenChannelIds_for_peer() throws Exception {
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
mockMvc.perform(get(PUBKEY_BASE + "/open-channels"))
.andExpect(content().string(CHANNEL_ID + "\n" + CHANNEL_ID_3));
}
@Test
void getOpenChannelIds() throws Exception {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
mockMvc.perform(get("/legacy/open-channels"))
.andExpect(content().string(CHANNEL_ID + "\n" + CHANNEL_ID_3));
}
@Test
void getOpenChannelIdsCompact() throws Exception {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
mockMvc.perform(get("/legacy/open-channels/compact"))
.andExpect(content().string(CHANNEL_ID_COMPACT + "\n" + CHANNEL_ID_COMPACT_3));
}
@Test
void getOpenChannelIdsPretty() throws Exception {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
mockMvc.perform(get("/legacy/open-channels/pretty"))
.andExpect(status().isOk());
}
@Test
void getClosedChannelIds() throws Exception {
when(channelService.getClosedChannels()).thenReturn(Set.of(CLOSED_CHANNEL, CLOSED_CHANNEL_3));
mockMvc.perform(get("/legacy/closed-channels"))
.andExpect(content().string(CHANNEL_ID + "\n" + CHANNEL_ID_3));
}
@Test
void isSyncedToChain_true() throws Exception {
when(ownNodeService.isSyncedToChain()).thenReturn(true);
@@ -113,7 +122,7 @@ class LegacyControllerIT {
@Test
void getPeerPubkeys() throws Exception {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_TO_NODE_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_TO_NODE_3));
mockMvc.perform(get("/legacy/peer-pubkeys"))
.andExpect(content().string(PUBKEY_2 + "\n" + PUBKEY_3));
}

View File

@@ -4,7 +4,7 @@ import com.codahale.metrics.MetricRegistry;
import de.cotto.lndmanagej.metrics.Metrics;
import de.cotto.lndmanagej.model.Channel;
import de.cotto.lndmanagej.model.ChannelId;
import de.cotto.lndmanagej.model.LocalChannel;
import de.cotto.lndmanagej.model.LocalOpenChannel;
import de.cotto.lndmanagej.model.Pubkey;
import de.cotto.lndmanagej.service.BalanceService;
import de.cotto.lndmanagej.service.ChannelService;
@@ -83,22 +83,30 @@ public class LegacyController {
public String getOpenChannelIdsPretty() {
mark("getOpenChannelIdsPretty");
return channelService.getOpenChannels().stream()
.sorted(Comparator.comparing(LocalChannel::getId))
.map(localChannel -> {
Pubkey pubkey = localChannel.getRemotePubkey();
return localChannel.getId().getCompactForm() +
.sorted(Comparator.comparing(LocalOpenChannel::getId))
.map(localOpenChannel -> {
Pubkey pubkey = localOpenChannel.getRemotePubkey();
return localOpenChannel.getId().getCompactForm() +
"\t" + pubkey +
"\t" + localChannel.getCapacity() +
"\t" + localOpenChannel.getCapacity() +
"\t" + nodeService.getAlias(pubkey);
})
.collect(Collectors.joining(NEWLINE));
}
@GetMapping("/closed-channels")
public String getClosedChannelIds() {
mark("getClosedChannelIds");
return getClosedChannelIdsSorted()
.map(ChannelId::toString)
.collect(Collectors.joining(NEWLINE));
}
@GetMapping("/peer-pubkeys")
public String getPeerPubkeys() {
mark("getPeerPubkeys");
return channelService.getOpenChannels().stream()
.map(LocalChannel::getRemotePubkey)
.map(LocalOpenChannel::getRemotePubkey)
.map(Pubkey::toString)
.sorted()
.distinct()
@@ -165,6 +173,12 @@ public class LegacyController {
.sorted();
}
private Stream<ChannelId> getClosedChannelIdsSorted() {
return channelService.getClosedChannels().stream()
.map(Channel::getId)
.sorted();
}
private void mark(String name) {
metrics.mark(MetricRegistry.name(getClass(), name));
}

View File

@@ -4,7 +4,7 @@ import de.cotto.lndmanagej.grpc.GrpcChannels;
import de.cotto.lndmanagej.model.BalanceInformation;
import de.cotto.lndmanagej.model.ChannelId;
import de.cotto.lndmanagej.model.Coins;
import de.cotto.lndmanagej.model.LocalChannel;
import de.cotto.lndmanagej.model.LocalOpenChannel;
import de.cotto.lndmanagej.model.Pubkey;
import org.springframework.stereotype.Component;
@@ -22,7 +22,7 @@ public class BalanceService {
public Coins getAvailableLocalBalance(Pubkey peer) {
return channelService.getOpenChannelsWith(peer).stream()
.map(LocalChannel::getId)
.map(LocalOpenChannel::getId)
.map(this::getAvailableLocalBalance)
.reduce(Coins.NONE, Coins::add);
}
@@ -35,7 +35,7 @@ public class BalanceService {
public Coins getAvailableRemoteBalance(Pubkey peer) {
return channelService.getOpenChannelsWith(peer).stream()
.map(LocalChannel::getId)
.map(LocalOpenChannel::getId)
.map(this::getAvailableRemoteBalance)
.reduce(Coins.NONE, Coins::add);
}
@@ -48,6 +48,6 @@ public class BalanceService {
private Optional<BalanceInformation> getBalanceInformation(ChannelId channelId) {
return grpcChannels.getChannel(channelId)
.map(LocalChannel::getBalanceInformation);
.map(LocalOpenChannel::getBalanceInformation);
}
}

View File

@@ -3,7 +3,8 @@ package de.cotto.lndmanagej.service;
import com.google.common.cache.LoadingCache;
import de.cotto.lndmanagej.caching.CacheBuilder;
import de.cotto.lndmanagej.grpc.GrpcChannels;
import de.cotto.lndmanagej.model.LocalChannel;
import de.cotto.lndmanagej.model.ClosedChannel;
import de.cotto.lndmanagej.model.LocalOpenChannel;
import de.cotto.lndmanagej.model.Pubkey;
import org.springframework.stereotype.Component;
@@ -12,26 +13,31 @@ import java.util.stream.Collectors;
@Component
public class ChannelService {
private static final int MAXIMUM_SIZE = 500;
private static final int CACHE_EXPIRY_MINUTES = 1;
private final LoadingCache<Object, Set<LocalChannel>> channelsCache;
private final LoadingCache<Object, Set<LocalOpenChannel>> channelsCache;
private final LoadingCache<Object, Set<ClosedChannel>> closedChannelsCache;
public ChannelService(GrpcChannels grpcChannels) {
channelsCache = new CacheBuilder()
.withExpiryMinutes(CACHE_EXPIRY_MINUTES)
.withMaximumSize(MAXIMUM_SIZE)
.build(grpcChannels::getChannels);
closedChannelsCache = new CacheBuilder()
.withExpiryMinutes(CACHE_EXPIRY_MINUTES)
.build(grpcChannels::getClosedChannels);
}
public Set<LocalChannel> getOpenChannels() {
public Set<LocalOpenChannel> getOpenChannels() {
return channelsCache.getUnchecked("");
}
public Set<LocalChannel> getOpenChannelsWith(Pubkey peer) {
public Set<ClosedChannel> getClosedChannels() {
return closedChannelsCache.getUnchecked("");
}
public Set<LocalOpenChannel> getOpenChannelsWith(Pubkey peer) {
return getOpenChannels().stream()
.filter(c -> peer.equals(c.getRemotePubkey()))
.collect(Collectors.toSet());
}
}

View File

@@ -4,7 +4,7 @@ import de.cotto.lndmanagej.metrics.Metrics;
import de.cotto.lndmanagej.model.Channel;
import de.cotto.lndmanagej.model.ChannelFixtures;
import de.cotto.lndmanagej.model.Coins;
import de.cotto.lndmanagej.model.LocalChannel;
import de.cotto.lndmanagej.model.LocalOpenChannel;
import de.cotto.lndmanagej.service.BalanceService;
import de.cotto.lndmanagej.service.ChannelService;
import de.cotto.lndmanagej.service.FeeService;
@@ -27,10 +27,12 @@ import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_3;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_COMPACT;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_COMPACT_3;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_COMPACT_4;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_3;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_3;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_3;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS;
import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS_2;
import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS_3;
@@ -74,7 +76,7 @@ class LegacyControllerTest {
@Test
void getOpenChannelIds_for_peer() {
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
assertThat(legacyController.getOpenChannelIdsForPubkey(PUBKEY)).isEqualTo(
CHANNEL_ID + "\n" + CHANNEL_ID_3
);
@@ -83,7 +85,7 @@ class LegacyControllerTest {
@Test
void getOpenChannelIds_for_peer_ordered() {
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_CHANNEL_3, LOCAL_CHANNEL));
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL_3, LOCAL_OPEN_CHANNEL));
assertThat(legacyController.getOpenChannelIdsForPubkey(PUBKEY)).isEqualTo(
CHANNEL_ID + "\n" + CHANNEL_ID_3
);
@@ -91,7 +93,7 @@ class LegacyControllerTest {
@Test
void getOpenChannelIds() {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
assertThat(legacyController.getOpenChannelIds()).isEqualTo(
CHANNEL_ID + "\n" + CHANNEL_ID_3
);
@@ -100,7 +102,7 @@ class LegacyControllerTest {
@Test
void getOpenChannelIds_ordered() {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL_3, LOCAL_CHANNEL));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL_3, LOCAL_OPEN_CHANNEL));
assertThat(legacyController.getOpenChannelIds()).isEqualTo(
CHANNEL_ID + "\n" + CHANNEL_ID_3
);
@@ -108,7 +110,7 @@ class LegacyControllerTest {
@Test
void getOpenChannelIdsCompact() {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
assertThat(legacyController.getOpenChannelIdsCompact()).isEqualTo(
CHANNEL_ID_COMPACT + "\n" + CHANNEL_ID_COMPACT_3
);
@@ -119,7 +121,7 @@ class LegacyControllerTest {
void getOpenChannelIdsPretty() {
when(nodeService.getAlias(PUBKEY_2)).thenReturn(ALIAS_2);
when(nodeService.getAlias(PUBKEY_3)).thenReturn(ALIAS_3);
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_TO_NODE_3));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_TO_NODE_3));
assertThat(legacyController.getOpenChannelIdsPretty()).isEqualTo(
CHANNEL_ID_COMPACT + "\t" + PUBKEY_2 + "\t" + CAPACITY + "\t" + ALIAS_2 + "\n" +
CHANNEL_ID_COMPACT_4 + "\t" + PUBKEY_3 + "\t" + CAPACITY_2 + "\t" + ALIAS_3
@@ -128,12 +130,29 @@ class LegacyControllerTest {
}
@Test
void getOpenChannelIdsPretty_sorted() {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL_TO_NODE_3, LOCAL_CHANNEL));
void getOpenChannelIdsPretty_ordered() {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL_TO_NODE_3, LOCAL_OPEN_CHANNEL));
assertThat(legacyController.getOpenChannelIdsPretty())
.matches(CHANNEL_ID_COMPACT + ".*\n" + CHANNEL_ID_COMPACT_4 + ".*");
}
@Test
void getClosedChannelIds() {
when(channelService.getClosedChannels()).thenReturn(Set.of(CLOSED_CHANNEL, CLOSED_CHANNEL_3));
assertThat(legacyController.getClosedChannelIds()).isEqualTo(
CHANNEL_ID + "\n" + CHANNEL_ID_3
);
verify(metrics).mark(argThat(name -> name.endsWith(".getClosedChannelIds")));
}
@Test
void getClosedChannelIds_ordered() {
when(channelService.getClosedChannels()).thenReturn(Set.of(CLOSED_CHANNEL_3, CLOSED_CHANNEL));
assertThat(legacyController.getClosedChannelIds()).isEqualTo(
CHANNEL_ID + "\n" + CHANNEL_ID_3
);
}
@Test
void syncedToChain() {
when(ownNodeService.isSyncedToChain()).thenReturn(true);
@@ -150,8 +169,8 @@ class LegacyControllerTest {
@Test
void getPeerPubkeys() {
Channel channel = ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2);
LocalChannel channel2 = new LocalChannel(channel, PUBKEY, BALANCE_INFORMATION);
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, channel2));
LocalOpenChannel channel2 = new LocalOpenChannel(channel, PUBKEY, BALANCE_INFORMATION);
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, channel2));
assertThat(legacyController.getPeerPubkeys()).isEqualTo(PUBKEY_2 + "\n" + PUBKEY_3);
verify(metrics).mark(argThat(name -> name.endsWith(".getPeerPubkeys")));
}
@@ -159,14 +178,14 @@ class LegacyControllerTest {
@Test
void getPeerPubkeys_sorted() {
Channel channel = ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2);
LocalChannel channel2 = new LocalChannel(channel, PUBKEY, BALANCE_INFORMATION);
when(channelService.getOpenChannels()).thenReturn(Set.of(channel2, LOCAL_CHANNEL));
LocalOpenChannel channel2 = new LocalOpenChannel(channel, PUBKEY, BALANCE_INFORMATION);
when(channelService.getOpenChannels()).thenReturn(Set.of(channel2, LOCAL_OPEN_CHANNEL));
assertThat(legacyController.getPeerPubkeys()).isEqualTo(PUBKEY_2 + "\n" + PUBKEY_3);
}
@Test
void getPeerPubkeys_without_duplicates() {
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_2));
when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2));
assertThat(legacyController.getPeerPubkeys()).isEqualTo(PUBKEY_2.toString());
}

View File

@@ -13,8 +13,8 @@ import java.util.Set;
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.LocalChannelFixtures.LOCAL_CHANNEL;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_2;
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@@ -32,7 +32,7 @@ class BalanceServiceTest {
@Test
void getAvailableLocalBalance_channel() {
when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_CHANNEL));
when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL));
assertThat(balanceService.getAvailableLocalBalance(CHANNEL_ID)).isEqualTo(Coins.ofSatoshis(900));
}
@@ -43,7 +43,7 @@ class BalanceServiceTest {
@Test
void getAvailableRemoteBalance_channel() {
when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_CHANNEL));
when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL));
assertThat(balanceService.getAvailableRemoteBalance(CHANNEL_ID)).isEqualTo(Coins.ofSatoshis(113));
}
@@ -75,8 +75,8 @@ class BalanceServiceTest {
}
private void mockChannels() {
when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_CHANNEL));
when(grpcChannels.getChannel(CHANNEL_ID_2)).thenReturn(Optional.of(LOCAL_CHANNEL_2));
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_2));
when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL));
when(grpcChannels.getChannel(CHANNEL_ID_2)).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL_2));
when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2));
}
}

View File

@@ -3,7 +3,7 @@ package de.cotto.lndmanagej.service;
import de.cotto.lndmanagej.grpc.GrpcChannels;
import de.cotto.lndmanagej.model.Channel;
import de.cotto.lndmanagej.model.ChannelFixtures;
import de.cotto.lndmanagej.model.LocalChannel;
import de.cotto.lndmanagej.model.LocalOpenChannel;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -14,9 +14,11 @@ import java.util.Set;
import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_2;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL_3;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_3;
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;
@@ -33,23 +35,33 @@ class ChannelServiceTest {
@Test
void getOpenChannelsWith_by_pubkey() {
when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_3));
when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3));
assertThat(channelService.getOpenChannelsWith(PUBKEY_2))
.containsExactlyInAnyOrder(LOCAL_CHANNEL, LOCAL_CHANNEL_3);
.containsExactlyInAnyOrder(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3);
}
@Test
void getOpenChannelsWith_ignores_channel_to_other_node() {
Channel channel = ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2);
LocalChannel localChannel2 = new LocalChannel(channel, PUBKEY, BALANCE_INFORMATION);
when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_CHANNEL, localChannel2, LOCAL_CHANNEL_3));
LocalOpenChannel localOpenChannel2 = new LocalOpenChannel(channel, PUBKEY, BALANCE_INFORMATION);
when(grpcChannels.getChannels()).thenReturn(
Set.of(LOCAL_OPEN_CHANNEL, localOpenChannel2, LOCAL_OPEN_CHANNEL_3)
);
assertThat(channelService.getOpenChannelsWith(PUBKEY_2))
.containsExactlyInAnyOrder(LOCAL_CHANNEL, LOCAL_CHANNEL_3);
.containsExactlyInAnyOrder(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3);
}
@Test
void getOpenChannels() {
when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_CHANNEL, LOCAL_CHANNEL_2));
assertThat(channelService.getOpenChannels()).containsExactlyInAnyOrder(LOCAL_CHANNEL, LOCAL_CHANNEL_2);
when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2));
assertThat(channelService.getOpenChannels())
.containsExactlyInAnyOrder(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2);
}
@Test
void getClosedChannels() {
when(grpcChannels.getClosedChannels()).thenReturn(Set.of(CLOSED_CHANNEL, CLOSED_CHANNEL_2));
assertThat(channelService.getClosedChannels())
.containsExactlyInAnyOrder(CLOSED_CHANNEL, CLOSED_CHANNEL_2);
}
}

View File

@@ -3,9 +3,11 @@ package de.cotto.lndmanagej.grpc;
import de.cotto.lndmanagej.model.BalanceInformation;
import de.cotto.lndmanagej.model.Channel;
import de.cotto.lndmanagej.model.ChannelId;
import de.cotto.lndmanagej.model.ClosedChannel;
import de.cotto.lndmanagej.model.Coins;
import de.cotto.lndmanagej.model.LocalChannel;
import de.cotto.lndmanagej.model.LocalOpenChannel;
import de.cotto.lndmanagej.model.Pubkey;
import lnrpc.ChannelCloseSummary;
import org.springframework.stereotype.Component;
import java.util.Optional;
@@ -26,23 +28,30 @@ public class GrpcChannels {
this.grpcGetInfo = grpcGetInfo;
}
public Set<LocalChannel> getChannels() {
public Set<LocalOpenChannel> getChannels() {
Pubkey ownPubkey = grpcGetInfo.getPubkey();
return grpcService.getChannels().stream()
.map(lndChannel -> toChannel(lndChannel, ownPubkey))
.map(lndChannel -> toLocalOpenChannel(lndChannel, ownPubkey))
.collect(toSet());
}
public Optional<LocalChannel> getChannel(ChannelId channelId) {
public Set<ClosedChannel> getClosedChannels() {
Pubkey ownPubkey = grpcGetInfo.getPubkey();
return grpcService.getClosedChannels().stream()
.map(channelCloseSummary -> toClosedChannel(channelCloseSummary, ownPubkey))
.collect(toSet());
}
public Optional<LocalOpenChannel> getChannel(ChannelId channelId) {
Pubkey ownPubkey = grpcGetInfo.getPubkey();
long expectedChannelId = channelId.shortChannelId();
return grpcService.getChannels().stream()
.filter(c -> c.getChanId() == expectedChannelId)
.map(lndChannel -> toChannel(lndChannel, ownPubkey))
.map(lndChannel -> toLocalOpenChannel(lndChannel, ownPubkey))
.findFirst();
}
private LocalChannel toChannel(lnrpc.Channel lndChannel, Pubkey ownPubkey) {
private LocalOpenChannel toLocalOpenChannel(lnrpc.Channel lndChannel, Pubkey ownPubkey) {
Channel channel = Channel.builder()
.withChannelId(ChannelId.fromShortChannelId(lndChannel.getChanId()))
.withCapacity(Coins.ofSatoshis(lndChannel.getCapacity()))
@@ -55,7 +64,16 @@ public class GrpcChannels {
Coins.ofSatoshis(lndChannel.getRemoteBalance()),
Coins.ofSatoshis(lndChannel.getRemoteConstraints().getChanReserveSat())
);
return new LocalChannel(channel, ownPubkey, balanceInformation);
return new LocalOpenChannel(channel, ownPubkey, balanceInformation);
}
private ClosedChannel toClosedChannel(ChannelCloseSummary channelCloseSummary, Pubkey ownPubkey) {
Channel channel = Channel.builder()
.withChannelId(ChannelId.fromShortChannelId(channelCloseSummary.getChanId()))
.withCapacity(Coins.ofSatoshis(channelCloseSummary.getCapacity()))
.withNode1(ownPubkey)
.withNode2(Pubkey.create(channelCloseSummary.getRemotePubkey()))
.build();
return new ClosedChannel(channel, ownPubkey);
}
}

View File

@@ -9,7 +9,9 @@ import de.cotto.lndmanagej.model.ChannelId;
import de.cotto.lndmanagej.model.Pubkey;
import lnrpc.ChanInfoRequest;
import lnrpc.Channel;
import lnrpc.ChannelCloseSummary;
import lnrpc.ChannelEdge;
import lnrpc.ClosedChannelsRequest;
import lnrpc.GetInfoResponse;
import lnrpc.LightningGrpc;
import lnrpc.ListChannelsRequest;
@@ -63,6 +65,12 @@ public class GrpcService extends GrpcBase {
return channelsCache.getUnchecked("");
}
public List<ChannelCloseSummary> getClosedChannels() {
mark("closedChannels");
return get(() -> lightningStub.closedChannels(ClosedChannelsRequest.getDefaultInstance()).getChannelsList())
.orElse(List.of());
}
private List<Channel> getChannelsWithoutCache() {
mark("listChannels");
return get(() -> lightningStub.listChannels(ListChannelsRequest.getDefaultInstance()).getChannelsList())

View File

@@ -2,6 +2,7 @@ package de.cotto.lndmanagej.grpc;
import de.cotto.lndmanagej.model.ChannelId;
import lnrpc.Channel;
import lnrpc.ChannelCloseSummary;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -14,9 +15,12 @@ import java.util.List;
import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY;
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.LocalChannelFixtures.LOCAL_CHANNEL;
import static de.cotto.lndmanagej.model.NodeFixtures.NODE_2;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_2;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_2;
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;
import static org.mockito.Mockito.when;
@@ -42,15 +46,28 @@ class GrpcChannelsTest {
}
@Test
void getChannels_one_channel() {
when(grpcService.getChannels()).thenReturn(List.of(channel(CHANNEL_ID)));
assertThat(grpcChannels.getChannels()).containsExactly(LOCAL_CHANNEL);
void getChannels() {
when(grpcService.getChannels()).thenReturn(List.of(channel(CHANNEL_ID), channel(CHANNEL_ID_2)));
assertThat(grpcChannels.getChannels()).containsExactlyInAnyOrder(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2);
}
@Test
void getClosedChannels_empty() {
assertThat(grpcChannels.getClosedChannels()).isEmpty();
}
@Test
void getClosedChannels() {
when(grpcService.getClosedChannels()).thenReturn(
List.of(closedChannel(CHANNEL_ID), closedChannel(CHANNEL_ID_2))
);
assertThat(grpcChannels.getClosedChannels()).containsExactlyInAnyOrder(CLOSED_CHANNEL, CLOSED_CHANNEL_2);
}
@Test
void getChannel() {
when(grpcService.getChannels()).thenReturn(List.of(channel(CHANNEL_ID_2), channel(CHANNEL_ID)));
assertThat(grpcChannels.getChannel(CHANNEL_ID)).contains(LOCAL_CHANNEL);
assertThat(grpcChannels.getChannel(CHANNEL_ID)).contains(LOCAL_OPEN_CHANNEL);
}
@Test
@@ -62,7 +79,15 @@ class GrpcChannelsTest {
return Channel.newBuilder()
.setChanId(channelId.shortChannelId())
.setCapacity(CAPACITY.satoshis())
.setRemotePubkey(NODE_2.pubkey().toString())
.setRemotePubkey(PUBKEY_2.toString())
.build();
}
private ChannelCloseSummary closedChannel(ChannelId channelId) {
return ChannelCloseSummary.newBuilder()
.setChanId(channelId.shortChannelId())
.setRemotePubkey(PUBKEY_2.toString())
.setCapacity(CAPACITY.satoshis())
.build();
}
}

View File

@@ -0,0 +1,7 @@
package de.cotto.lndmanagej.model;
public class ClosedChannel extends LocalChannel {
public ClosedChannel(Channel channel, Pubkey ownPubkey) {
super(channel, ownPubkey);
}
}

View File

@@ -4,9 +4,8 @@ import java.util.Set;
public class LocalChannel extends Channel {
private final Pubkey remotePubkey;
private final BalanceInformation balanceInformation;
public LocalChannel(Channel channel, Pubkey ownPubkey, BalanceInformation balanceInformation) {
protected LocalChannel(Channel channel, Pubkey ownPubkey) {
super(channel.getId(), channel.getCapacity(), channel.getPubkeys());
Set<Pubkey> pubkeys = channel.getPubkeys();
remotePubkey = pubkeys.stream()
@@ -16,14 +15,9 @@ public class LocalChannel extends Channel {
if (!pubkeys.contains(ownPubkey)) {
throw new IllegalArgumentException("Channel must have given pubkey as peer");
}
this.balanceInformation = balanceInformation;
}
public Pubkey getRemotePubkey() {
return remotePubkey;
}
public BalanceInformation getBalanceInformation() {
return balanceInformation;
}
}

View File

@@ -0,0 +1,14 @@
package de.cotto.lndmanagej.model;
public class LocalOpenChannel extends LocalChannel {
private final BalanceInformation balanceInformation;
public LocalOpenChannel(Channel channel, Pubkey ownPubkey, BalanceInformation balanceInformation) {
super(channel, ownPubkey);
this.balanceInformation = balanceInformation;
}
public BalanceInformation getBalanceInformation() {
return balanceInformation;
}
}

View File

@@ -0,0 +1,34 @@
package de.cotto.lndmanagej.model;
import org.junit.jupiter.api.Test;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_2;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID;
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 org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
class ClosedChannelTest {
@Test
void getRemotePubkey() {
Channel channel = ChannelFixtures.create(PUBKEY_2, PUBKEY, CHANNEL_ID);
ClosedChannel closedChannel = new ClosedChannel(channel, PUBKEY);
assertThat(closedChannel.getRemotePubkey()).isEqualTo(PUBKEY_2);
}
@Test
void getRemotePubkey_swapped() {
Channel channel = ChannelFixtures.create(PUBKEY_3, PUBKEY_2, CHANNEL_ID);
ClosedChannel closedChannel = new ClosedChannel(channel, PUBKEY_3);
assertThat(closedChannel.getRemotePubkey()).isEqualTo(PUBKEY_2);
}
@Test
void ownPubkey_not_in_pubkey_set() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ClosedChannel(CHANNEL_2, PUBKEY_3))
.withMessage("Channel must have given pubkey as peer");
}
}

View File

@@ -9,52 +9,52 @@ import static de.cotto.lndmanagej.model.BalanceInformationFixtures.REMOTE_BALANC
import static de.cotto.lndmanagej.model.BalanceInformationFixtures.REMOTE_RESERVE;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_2;
import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID;
import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
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 org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
class LocalChannelTest {
class LocalOpenChannelTest {
@Test
void getRemotePubkey() {
Channel channel = ChannelFixtures.create(PUBKEY_2, PUBKEY, CHANNEL_ID);
LocalChannel localChannel = new LocalChannel(channel, PUBKEY, BALANCE_INFORMATION);
assertThat(localChannel.getRemotePubkey()).isEqualTo(PUBKEY_2);
LocalOpenChannel localOpenChannel = new LocalOpenChannel(channel, PUBKEY, BALANCE_INFORMATION);
assertThat(localOpenChannel.getRemotePubkey()).isEqualTo(PUBKEY_2);
}
@Test
void getRemotePubkey_swapped() {
Channel channel = ChannelFixtures.create(PUBKEY_3, PUBKEY_2, CHANNEL_ID);
LocalChannel localChannel = new LocalChannel(channel, PUBKEY_3, BALANCE_INFORMATION);
assertThat(localChannel.getRemotePubkey()).isEqualTo(PUBKEY_2);
LocalOpenChannel localOpenChannel = new LocalOpenChannel(channel, PUBKEY_3, BALANCE_INFORMATION);
assertThat(localOpenChannel.getRemotePubkey()).isEqualTo(PUBKEY_2);
}
@Test
void ownPubkey_not_in_pubkey_set() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new LocalChannel(CHANNEL_2, PUBKEY_3, BALANCE_INFORMATION))
.isThrownBy(() -> new LocalOpenChannel(CHANNEL_2, PUBKEY_3, BALANCE_INFORMATION))
.withMessage("Channel must have given pubkey as peer");
}
@Test
void getLocalBalance() {
assertThat(LOCAL_CHANNEL.getBalanceInformation().localBalance()).isEqualTo(LOCAL_BALANCE);
assertThat(LOCAL_OPEN_CHANNEL.getBalanceInformation().localBalance()).isEqualTo(LOCAL_BALANCE);
}
@Test
void getLocalReserve() {
assertThat(LOCAL_CHANNEL.getBalanceInformation().localReserve()).isEqualTo(LOCAL_RESERVE);
assertThat(LOCAL_OPEN_CHANNEL.getBalanceInformation().localReserve()).isEqualTo(LOCAL_RESERVE);
}
@Test
void getRemoteBalance() {
assertThat(LOCAL_CHANNEL.getBalanceInformation().remoteBalance()).isEqualTo(REMOTE_BALANCE);
assertThat(LOCAL_OPEN_CHANNEL.getBalanceInformation().remoteBalance()).isEqualTo(REMOTE_BALANCE);
}
@Test
void getRemoteReserve() {
assertThat(LOCAL_CHANNEL.getBalanceInformation().remoteReserve()).isEqualTo(REMOTE_RESERVE);
assertThat(LOCAL_OPEN_CHANNEL.getBalanceInformation().remoteReserve()).isEqualTo(REMOTE_RESERVE);
}
}

View File

@@ -0,0 +1,14 @@
package de.cotto.lndmanagej.model;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_2;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_3;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
public class ClosedChannelFixtures {
public static final ClosedChannel CLOSED_CHANNEL = new ClosedChannel(CHANNEL, PUBKEY);
public static final ClosedChannel CLOSED_CHANNEL_2 = new ClosedChannel(CHANNEL_2, PUBKEY);
public static final ClosedChannel CLOSED_CHANNEL_3 = new ClosedChannel(CHANNEL_3, PUBKEY);
public static final ClosedChannel CLOSED_CHANNEL_TO_NODE_3 = new ClosedChannel(CHANNEL_TO_NODE_3, PUBKEY);
}

View File

@@ -1,16 +0,0 @@
package de.cotto.lndmanagej.model;
import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_2;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_3;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
public class LocalChannelFixtures {
public static final LocalChannel LOCAL_CHANNEL = new LocalChannel(CHANNEL, PUBKEY, BALANCE_INFORMATION);
public static final LocalChannel LOCAL_CHANNEL_2 = new LocalChannel(CHANNEL_2, PUBKEY, BALANCE_INFORMATION);
public static final LocalChannel LOCAL_CHANNEL_3 = new LocalChannel(CHANNEL_3, PUBKEY, BALANCE_INFORMATION);
public static final LocalChannel LOCAL_CHANNEL_TO_NODE_3 =
new LocalChannel(CHANNEL_TO_NODE_3, PUBKEY, BALANCE_INFORMATION);
}

View File

@@ -0,0 +1,19 @@
package de.cotto.lndmanagej.model;
import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_2;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_3;
import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_TO_NODE_3;
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
public class LocalOpenChannelFixtures {
public static final LocalOpenChannel LOCAL_OPEN_CHANNEL =
new LocalOpenChannel(CHANNEL, PUBKEY, BALANCE_INFORMATION);
public static final LocalOpenChannel LOCAL_OPEN_CHANNEL_2 =
new LocalOpenChannel(CHANNEL_2, PUBKEY, BALANCE_INFORMATION);
public static final LocalOpenChannel LOCAL_OPEN_CHANNEL_3 =
new LocalOpenChannel(CHANNEL_3, PUBKEY, BALANCE_INFORMATION);
public static final LocalOpenChannel LOCAL_OPEN_CHANNEL_TO_NODE_3 =
new LocalOpenChannel(CHANNEL_TO_NODE_3, PUBKEY, BALANCE_INFORMATION);
}