diff --git a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java index ca5f7b1a..34d484a4 100644 --- a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java +++ b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java @@ -21,6 +21,8 @@ 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.ClosedChannelFixtures.CLOSED_CHANNEL; import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_3; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_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; @@ -115,6 +117,14 @@ class LegacyControllerIT { .andExpect(content().string(CHANNEL_ID + "\n" + CHANNEL_ID_3)); } + @Test + void getForceClosingChannels() throws Exception { + when(channelService.getForceClosingChannels()) + .thenReturn(Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_3)); + mockMvc.perform(get("/legacy/force-closing-channels")) + .andExpect(content().string(CHANNEL_ID + "\n" + CHANNEL_ID_3)); + } + @Test void isSyncedToChain_true() throws Exception { when(ownNodeService.isSyncedToChain()).thenReturn(true); diff --git a/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java b/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java index 03505cbd..75d3429b 100644 --- a/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java +++ b/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java @@ -112,6 +112,16 @@ public class LegacyController { .collect(Collectors.joining(NEWLINE)); } + @GetMapping("/force-closing-channels") + public String getForceClosingChannelIds() { + mark("getForceClosingChannelIds"); + return channelService.getForceClosingChannels().stream() + .map(Channel::getId) + .sorted() + .map(ChannelId::toString) + .collect(Collectors.joining(NEWLINE)); + } + @GetMapping("/peer-pubkeys") public String getPeerPubkeys() { mark("getPeerPubkeys"); diff --git a/application/src/main/java/de/cotto/lndmanagej/service/ChannelIdResolverImpl.java b/application/src/main/java/de/cotto/lndmanagej/service/ChannelIdResolverImpl.java index 37ff26a8..b75279a3 100644 --- a/application/src/main/java/de/cotto/lndmanagej/service/ChannelIdResolverImpl.java +++ b/application/src/main/java/de/cotto/lndmanagej/service/ChannelIdResolverImpl.java @@ -5,6 +5,8 @@ import de.cotto.lndmanagej.model.ChannelIdResolver; import de.cotto.lndmanagej.model.ChannelPoint; import de.cotto.lndmanagej.transactions.model.Transaction; import de.cotto.lndmanagej.transactions.service.TransactionService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.util.Optional; @@ -12,6 +14,7 @@ import java.util.Optional; @Component public class ChannelIdResolverImpl implements ChannelIdResolver { private final TransactionService transactionService; + private final Logger logger = LoggerFactory.getLogger(getClass()); public ChannelIdResolverImpl(TransactionService transactionService) { this.transactionService = transactionService; @@ -19,8 +22,12 @@ public class ChannelIdResolverImpl implements ChannelIdResolver { @Override public Optional resolveFromChannelPoint(ChannelPoint channelPoint) { - return transactionService.getTransaction(channelPoint.getTransactionHash()) - .map(transaction -> getChannelId(transaction, channelPoint)); + String transactionHash = channelPoint.getTransactionHash(); + Optional transactionOptional = transactionService.getTransaction(transactionHash); + if (transactionOptional.isEmpty()) { + logger.warn("Unable resolve transaction ID for {}", transactionHash); + } + return transactionOptional.map(transaction -> getChannelId(transaction, channelPoint)); } private ChannelId getChannelId(Transaction transaction, ChannelPoint channelPoint) { diff --git a/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java b/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java index 63492cd9..758e21f4 100644 --- a/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java +++ b/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java @@ -4,6 +4,7 @@ import com.google.common.cache.LoadingCache; import de.cotto.lndmanagej.caching.CacheBuilder; import de.cotto.lndmanagej.grpc.GrpcChannels; import de.cotto.lndmanagej.model.ClosedChannel; +import de.cotto.lndmanagej.model.ForceClosingChannel; import de.cotto.lndmanagej.model.LocalChannel; import de.cotto.lndmanagej.model.LocalOpenChannel; import de.cotto.lndmanagej.model.Pubkey; @@ -39,6 +40,10 @@ public class ChannelService { return closedChannelsCache.getUnchecked(""); } + public Set getForceClosingChannels() { + return grpcChannels.getForceClosingChannels(); + } + public Set getOpenChannelsWith(Pubkey peer) { return getOpenChannels().stream() .filter(c -> peer.equals(c.getRemotePubkey())) @@ -47,9 +52,11 @@ public class ChannelService { public Set getAllChannelsWith(Pubkey pubkey) { Stream openChannels = getOpenChannelsWith(pubkey).stream(); + Stream forceClosingChannels = getForceClosingChannels().stream() + .filter(c -> c.getRemotePubkey().equals(pubkey)); Stream closedChannels = getClosedChannels().stream() .filter(c -> c.getRemotePubkey().equals(pubkey)); - return Stream.of(openChannels, closedChannels).flatMap(s -> s) + return Stream.of(openChannels, closedChannels, forceClosingChannels).flatMap(s -> s) .collect(Collectors.toSet()); } diff --git a/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java b/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java index 8de24c64..9d322c37 100644 --- a/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java @@ -24,6 +24,8 @@ 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.ClosedChannelFixtures.CLOSED_CHANNEL; import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_3; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_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; @@ -165,6 +167,25 @@ class LegacyControllerTest { ); } + @Test + void getForceClosingChannelIds() { + when(channelService.getForceClosingChannels()) + .thenReturn(Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_3)); + assertThat(legacyController.getForceClosingChannelIds()).isEqualTo( + CHANNEL_ID + "\n" + CHANNEL_ID_3 + ); + verify(metrics).mark(argThat(name -> name.endsWith(".getForceClosingChannelIds"))); + } + + @Test + void getForceClosingChannelIds_ordered() { + when(channelService.getForceClosingChannels()) + .thenReturn(Set.of(FORCE_CLOSING_CHANNEL_3, FORCE_CLOSING_CHANNEL)); + assertThat(legacyController.getForceClosingChannelIds()).isEqualTo( + CHANNEL_ID + "\n" + CHANNEL_ID_3 + ); + } + @Test void syncedToChain() { when(ownNodeService.isSyncedToChain()).thenReturn(true); diff --git a/application/src/test/java/de/cotto/lndmanagej/service/ChannelIdResolverImplTest.java b/application/src/test/java/de/cotto/lndmanagej/service/ChannelIdResolverImplTest.java index 2f16fac9..cac8ee54 100644 --- a/application/src/test/java/de/cotto/lndmanagej/service/ChannelIdResolverImplTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/service/ChannelIdResolverImplTest.java @@ -2,11 +2,14 @@ package de.cotto.lndmanagej.service; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.transactions.service.TransactionService; +import org.junit.jupiter.api.BeforeEach; 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 uk.org.lidalia.slf4jtest.TestLogger; +import uk.org.lidalia.slf4jtest.TestLoggerFactory; import java.util.Optional; @@ -18,19 +21,30 @@ import static de.cotto.lndmanagej.transactions.model.TransactionFixtures.POSITIO import static de.cotto.lndmanagej.transactions.model.TransactionFixtures.TRANSACTION; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import static uk.org.lidalia.slf4jtest.LoggingEvent.warn; @ExtendWith(MockitoExtension.class) class ChannelIdResolverImplTest { + private final TestLogger logger = TestLoggerFactory.getTestLogger(ChannelIdResolverImpl.class); + @InjectMocks private ChannelIdResolverImpl channelIdResolver; @Mock private TransactionService transactionService; + @BeforeEach + void setUp() { + logger.clearAll(); + } + @Test void unknown() { when(transactionService.getTransaction(TRANSACTION_HASH)).thenReturn(Optional.empty()); assertThat(channelIdResolver.resolveFromChannelPoint(CHANNEL_POINT)).isEmpty(); + assertThat(logger.getLoggingEvents()).contains( + warn("Unable resolve transaction ID for {}", TRANSACTION_HASH) + ); } @Test @@ -38,5 +52,6 @@ class ChannelIdResolverImplTest { ChannelId expectedChannelId = ChannelId.fromCompactForm(BLOCK_HEIGHT + ":" + POSITION_IN_BLOCK + ":" + OUTPUT); when(transactionService.getTransaction(TRANSACTION_HASH)).thenReturn(Optional.of(TRANSACTION)); assertThat(channelIdResolver.resolveFromChannelPoint(CHANNEL_POINT)).contains(expectedChannelId); + assertThat(logger.getLoggingEvents()).isEmpty(); } } \ No newline at end of file diff --git a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java index 2912430c..35a10df3 100644 --- a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java @@ -13,6 +13,9 @@ 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.ClosedChannelFixtures.CLOSED_CHANNEL_3; import static de.cotto.lndmanagej.model.ClosedChannelFixtures.CLOSED_CHANNEL_TO_NODE_3; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL_2; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL_TO_NODE_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; @@ -60,12 +63,22 @@ class ChannelServiceTest { .containsExactlyInAnyOrder(CLOSED_CHANNEL, CLOSED_CHANNEL_2); } + @Test + void getForceClosingChannels() { + when(grpcChannels.getForceClosingChannels()) + .thenReturn(Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2)); + assertThat(channelService.getForceClosingChannels()) + .containsExactlyInAnyOrder(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2); + } + @Test void getAllChannels_by_pubkey() { when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_TO_NODE_3)); + when(grpcChannels.getForceClosingChannels()) + .thenReturn(Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_TO_NODE_3)); when(grpcChannels.getClosedChannels()) .thenReturn(Set.of(CLOSED_CHANNEL_3, CLOSED_CHANNEL_TO_NODE_3)); assertThat(channelService.getAllChannelsWith(PUBKEY_2)) - .containsExactlyInAnyOrder(LOCAL_OPEN_CHANNEL, CLOSED_CHANNEL_3); + .containsExactlyInAnyOrder(LOCAL_OPEN_CHANNEL, CLOSED_CHANNEL_3, FORCE_CLOSING_CHANNEL); } } \ No newline at end of file diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java index 0cd66539..e6aeff01 100644 --- a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java @@ -6,10 +6,13 @@ import de.cotto.lndmanagej.model.ChannelIdResolver; import de.cotto.lndmanagej.model.ChannelPoint; import de.cotto.lndmanagej.model.ClosedChannel; import de.cotto.lndmanagej.model.Coins; +import de.cotto.lndmanagej.model.ForceClosingChannel; import de.cotto.lndmanagej.model.LocalOpenChannel; import de.cotto.lndmanagej.model.Pubkey; import lnrpc.ChannelCloseSummary; import lnrpc.ChannelCloseSummary.ClosureType; +import lnrpc.PendingChannelsResponse.ForceClosedChannel; +import lnrpc.PendingChannelsResponse.PendingChannel; import org.springframework.stereotype.Component; import java.util.Optional; @@ -49,6 +52,26 @@ public class GrpcChannels { .collect(toSet()); } + public Set getForceClosingChannels() { + Pubkey ownPubkey = grpcGetInfo.getPubkey(); + return grpcService.getForceClosingChannels().stream() + .map(forceClosedChannel -> toForceClosingChannel(forceClosedChannel, ownPubkey)) + .flatMap(Optional::stream) + .collect(toSet()); + } + + private Optional toForceClosingChannel( + ForceClosedChannel forceClosedChannel, + Pubkey ownPubkey + ) { + PendingChannel pendingChannel = forceClosedChannel.getChannel(); + ChannelPoint channelPoint = ChannelPoint.create(pendingChannel.getChannelPoint()); + Coins capacity = Coins.ofSatoshis(pendingChannel.getCapacity()); + Pubkey remotePubkey = Pubkey.create(pendingChannel.getRemoteNodePub()); + return channelIdResolver.resolveFromChannelPoint(channelPoint) + .map(id -> new ForceClosingChannel(id, channelPoint, capacity, ownPubkey, remotePubkey)); + } + public Optional getChannel(ChannelId channelId) { Pubkey ownPubkey = grpcGetInfo.getPubkey(); long expectedChannelId = channelId.getShortChannelId(); diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcService.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcService.java index cfd2424a..fccd0ad7 100644 --- a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcService.java +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcService.java @@ -17,6 +17,8 @@ import lnrpc.LightningGrpc; import lnrpc.ListChannelsRequest; import lnrpc.NodeInfo; import lnrpc.NodeInfoRequest; +import lnrpc.PendingChannelsRequest; +import lnrpc.PendingChannelsResponse.ForceClosedChannel; import org.springframework.stereotype.Component; import javax.annotation.PreDestroy; @@ -71,6 +73,14 @@ public class GrpcService extends GrpcBase { .orElse(List.of()); } + public List getForceClosingChannels() { + mark("closedChannels"); + return get(() -> + lightningStub.pendingChannels(PendingChannelsRequest.getDefaultInstance()) + .getPendingForceClosingChannelsList() + ).orElse(List.of()); + } + private List getChannelsWithoutCache() { mark("listChannels"); return get(() -> lightningStub.listChannels(ListChannelsRequest.getDefaultInstance()).getChannelsList()) diff --git a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java index 2f43eeda..4eb46412 100644 --- a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java +++ b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java @@ -2,9 +2,12 @@ package de.cotto.lndmanagej.grpc; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.ChannelIdResolver; +import de.cotto.lndmanagej.model.ChannelPoint; import lnrpc.Channel; import lnrpc.ChannelCloseSummary; import lnrpc.ChannelConstraints; +import lnrpc.PendingChannelsResponse; +import lnrpc.PendingChannelsResponse.ForceClosedChannel; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -21,9 +24,13 @@ 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.ChannelIdFixtures.CHANNEL_ID_3; import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT_2; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT_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.ClosedChannelFixtures.CLOSED_CHANNEL_3; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_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; @@ -81,6 +88,26 @@ class GrpcChannelsTest { verify(channelIdResolver, never()).resolveFromChannelPoint(any()); } + @Test + void getForceClosingChannels_both_resolved() { + when(channelIdResolver.resolveFromChannelPoint(CHANNEL_POINT)).thenReturn(Optional.of(CHANNEL_ID)); + when(channelIdResolver.resolveFromChannelPoint(CHANNEL_POINT_2)).thenReturn(Optional.of(CHANNEL_ID_2)); + when(grpcService.getForceClosingChannels()).thenReturn( + List.of(forceClosingChannel(CHANNEL_POINT), forceClosingChannel(CHANNEL_POINT_2)) + ); + assertThat(grpcChannels.getForceClosingChannels()) + .containsExactlyInAnyOrder(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2); + } + + @Test + void getForceClosingChannels_just_one_resolved() { + when(channelIdResolver.resolveFromChannelPoint(CHANNEL_POINT)).thenReturn(Optional.of(CHANNEL_ID)); + when(grpcService.getForceClosingChannels()).thenReturn( + List.of(forceClosingChannel(CHANNEL_POINT), forceClosingChannel(CHANNEL_POINT_3)) + ); + assertThat(grpcChannels.getForceClosingChannels()).containsExactlyInAnyOrder(FORCE_CLOSING_CHANNEL); + } + @Test void getClosedChannels_with_zero_channel_id_not_resolved() { when(grpcService.getClosedChannels()).thenReturn( @@ -156,6 +183,16 @@ class GrpcChannelsTest { .build(); } + private ForceClosedChannel forceClosingChannel(ChannelPoint channelPoint) { + return ForceClosedChannel.newBuilder() + .setChannel(PendingChannelsResponse.PendingChannel.newBuilder() + .setRemoteNodePub(PUBKEY_2.toString()) + .setCapacity(CAPACITY.satoshis()) + .setChannelPoint(channelPoint.toString()) + .build()) + .build(); + } + private ChannelCloseSummary closedChannelWithType(ChannelCloseSummary.ClosureType abandoned) { return ChannelCloseSummary.newBuilder() .setChanId(0) diff --git a/model/src/main/java/de/cotto/lndmanagej/model/ForceClosingChannel.java b/model/src/main/java/de/cotto/lndmanagej/model/ForceClosingChannel.java new file mode 100644 index 00000000..29b19cd4 --- /dev/null +++ b/model/src/main/java/de/cotto/lndmanagej/model/ForceClosingChannel.java @@ -0,0 +1,13 @@ +package de.cotto.lndmanagej.model; + +public final class ForceClosingChannel extends LocalChannel { + public ForceClosingChannel( + ChannelId channelId, + ChannelPoint channelPoint, + Coins capacity, + Pubkey ownPubkey, + Pubkey remotePubkey + ) { + super(channelId, channelPoint, capacity, ownPubkey, remotePubkey); + } +} diff --git a/model/src/test/java/de/cotto/lndmanagej/model/ForceClosingChannelTest.java b/model/src/test/java/de/cotto/lndmanagej/model/ForceClosingChannelTest.java new file mode 100644 index 00000000..ef519242 --- /dev/null +++ b/model/src/test/java/de/cotto/lndmanagej/model/ForceClosingChannelTest.java @@ -0,0 +1,50 @@ +package de.cotto.lndmanagej.model; + +import nl.jqno.equalsverifier.EqualsVerifier; +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.ChannelPointFixtures.CHANNEL_POINT; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL; +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 ForceClosingChannelTest { + @Test + void create() { + assertThat(new ForceClosingChannel(CHANNEL_ID, CHANNEL_POINT, CAPACITY, PUBKEY, PUBKEY_2)) + .isEqualTo(FORCE_CLOSING_CHANNEL); + } + + @Test + void getId() { + assertThat(FORCE_CLOSING_CHANNEL.getId()).isEqualTo(CHANNEL_ID); + } + + @Test + void getRemotePubkey() { + assertThat(FORCE_CLOSING_CHANNEL.getRemotePubkey()).isEqualTo(PUBKEY_2); + } + + @Test + void getCapacity() { + assertThat(FORCE_CLOSING_CHANNEL.getCapacity()).isEqualTo(CAPACITY); + } + + @Test + void getChannelPoint() { + assertThat(FORCE_CLOSING_CHANNEL.getChannelPoint()).isEqualTo(CHANNEL_POINT); + } + + @Test + void getPubkeys() { + assertThat(FORCE_CLOSING_CHANNEL.getPubkeys()).containsExactlyInAnyOrder(PUBKEY, PUBKEY_2); + } + + @Test + void testEquals() { + EqualsVerifier.forClass(ForceClosingChannel.class).usingGetClass().verify(); + } +} \ No newline at end of file diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/ChannelPointFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/ChannelPointFixtures.java index 908c0716..5c19de0c 100644 --- a/model/src/testFixtures/java/de/cotto/lndmanagej/model/ChannelPointFixtures.java +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/ChannelPointFixtures.java @@ -2,6 +2,10 @@ package de.cotto.lndmanagej.model; public class ChannelPointFixtures { public static final String TRANSACTION_HASH = "abc000abc000abc000abc000abc000abc000abc000abc000abc000abc000abc0"; + public static final String TRANSACTION_HASH_2 = "abc111abc000abc000abc000abc000abc000abc000abc000abc000abc000abc0"; public static final int OUTPUT = 1; + public static final int OUTPUT_2 = 123; public static final ChannelPoint CHANNEL_POINT = ChannelPoint.create(TRANSACTION_HASH + ":" + OUTPUT); + public static final ChannelPoint CHANNEL_POINT_2 = ChannelPoint.create(TRANSACTION_HASH + ":" + OUTPUT_2); + public static final ChannelPoint CHANNEL_POINT_3 = ChannelPoint.create(TRANSACTION_HASH_2 + ":" + OUTPUT); } diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/ForceClosingChannelFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/ForceClosingChannelFixtures.java new file mode 100644 index 00000000..d57d9e83 --- /dev/null +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/ForceClosingChannelFixtures.java @@ -0,0 +1,22 @@ +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.ChannelIdFixtures.CHANNEL_ID_2; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_3; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT_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; + +public class ForceClosingChannelFixtures { + public static final ForceClosingChannel FORCE_CLOSING_CHANNEL = + new ForceClosingChannel(CHANNEL_ID, CHANNEL_POINT, CAPACITY, PUBKEY, PUBKEY_2); + public static final ForceClosingChannel FORCE_CLOSING_CHANNEL_2 + = new ForceClosingChannel(CHANNEL_ID_2, CHANNEL_POINT_2, CAPACITY, PUBKEY, PUBKEY_2); + public static final ForceClosingChannel FORCE_CLOSING_CHANNEL_3 = + new ForceClosingChannel(CHANNEL_ID_3, CHANNEL_POINT, CAPACITY, PUBKEY, PUBKEY_2); + public static final ForceClosingChannel FORCE_CLOSING_CHANNEL_TO_NODE_3 = + new ForceClosingChannel(CHANNEL_ID_3, CHANNEL_POINT, CAPACITY, PUBKEY, PUBKEY_3); +}