add force/breach info to close details

This commit is contained in:
Carsten Otto
2021-12-11 13:10:25 +01:00
parent 382777f5ee
commit ddf353b854
11 changed files with 141 additions and 29 deletions

View File

@@ -23,4 +23,9 @@ public class BreachForceClosedChannel extends ForceClosedChannel {
resolutions
);
}
@Override
public boolean isBreach() {
return true;
}
}

View File

@@ -42,6 +42,10 @@ public class ForceClosedChannel extends ClosedChannel {
return this;
}
public boolean isBreach() {
return false;
}
@Override
public boolean equals(Object other) {
if (this == other) {

View File

@@ -110,6 +110,11 @@ class BreachForceClosedChannelTest {
assertThat(FORCE_CLOSED_CHANNEL_BREACH.getResolutions()).containsExactlyInAnyOrder(RESOLUTION_2);
}
@Test
void isBreach() {
assertThat(FORCE_CLOSED_CHANNEL_BREACH.isBreach()).isTrue();
}
@Test
void testEquals() {
EqualsVerifier.forClass(BreachForceClosedChannel.class).usingGetClass().verify();

View File

@@ -123,6 +123,11 @@ class ForceClosedChannelTest {
assertThat(FORCE_CLOSED_CHANNEL.getResolutions()).containsExactlyInAnyOrder(RESOLUTION, RESOLUTION_2);
}
@Test
void isBreach() {
assertThat(FORCE_CLOSED_CHANNEL.isBreach()).isFalse();
}
@Test
void testEquals() {
EqualsVerifier.forClass(ForceClosedChannel.class).usingGetClass().verify();

View File

@@ -25,6 +25,8 @@ 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.ChannelPointFixtures.CHANNEL_POINT;
import static de.cotto.lndmanagej.model.CoopClosedChannelFixtures.CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ForceClosedChannelFixtures.FORCE_CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ForceClosedChannelFixtures.FORCE_CLOSED_CHANNEL_BREACH;
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_PRIVATE;
@@ -230,7 +232,29 @@ class ChannelControllerIT {
when(channelService.getClosedChannel(CHANNEL_ID)).thenReturn(Optional.of(CLOSED_CHANNEL));
mockMvc.perform(get(CHANNEL_PREFIX + "/close-details"))
.andExpect(jsonPath("$.initiator", is("REMOTE")))
.andExpect(jsonPath("$.height", is(987_654)));
.andExpect(jsonPath("$.height", is(987_654)))
.andExpect(jsonPath("$.force", is(false)))
.andExpect(jsonPath("$.breach", is(false)));
}
@Test
void getCloseDetails_force() throws Exception {
when(channelService.getClosedChannel(CHANNEL_ID)).thenReturn(Optional.of(FORCE_CLOSED_CHANNEL));
mockMvc.perform(get(CHANNEL_PREFIX + "/close-details"))
.andExpect(jsonPath("$.initiator", is("REMOTE")))
.andExpect(jsonPath("$.height", is(987_654)))
.andExpect(jsonPath("$.force", is(true)))
.andExpect(jsonPath("$.breach", is(false)));
}
@Test
void getCloseDetails_breach() throws Exception {
when(channelService.getClosedChannel(CHANNEL_ID)).thenReturn(Optional.of(FORCE_CLOSED_CHANNEL_BREACH));
mockMvc.perform(get(CHANNEL_PREFIX + "/close-details"))
.andExpect(jsonPath("$.breach", is(true)))
.andExpect(jsonPath("$.initiator", is("REMOTE")))
.andExpect(jsonPath("$.height", is(987_654)))
.andExpect(jsonPath("$.force", is(true)));
}
@Test

View File

@@ -118,7 +118,7 @@ public class ChannelController {
if (closedChannel == null) {
throw new NotFoundException();
}
return new ClosedChannelDetailsDto(closedChannel.getCloseInitiator(), closedChannel.getCloseHeight());
return ClosedChannelDetailsDto.createFromModel(closedChannel);
}
@Timed
@@ -151,11 +151,6 @@ public class ChannelController {
}
private ClosedChannelDetailsDto getCloseDetailsForChannel(LocalChannel localChannel) {
if (localChannel.isClosed()) {
ClosedChannel closedChannel = localChannel.getAsClosedChannel();
return new ClosedChannelDetailsDto(closedChannel.getCloseInitiator(), closedChannel.getCloseHeight());
} else {
return ClosedChannelDetailsDto.UNKNOWN;
}
return ClosedChannelDetailsDto.createFromModel(localChannel);
}
}

View File

@@ -1,11 +1,28 @@
package de.cotto.lndmanagej.controller.dto;
import de.cotto.lndmanagej.model.CloseInitiator;
import de.cotto.lndmanagej.model.ClosedChannel;
import de.cotto.lndmanagej.model.LocalChannel;
public record ClosedChannelDetailsDto(String initiator, int height) {
public static final ClosedChannelDetailsDto UNKNOWN = new ClosedChannelDetailsDto("", 0);
public record ClosedChannelDetailsDto(String initiator, int height, boolean force, boolean breach) {
public static final ClosedChannelDetailsDto UNKNOWN =
new ClosedChannelDetailsDto("", 0, false, false);
public ClosedChannelDetailsDto(CloseInitiator initiator, int height) {
this(initiator.toString(), height);
public ClosedChannelDetailsDto(CloseInitiator initiator, int height, boolean force, boolean breach) {
this(initiator.toString(), height, force, breach);
}
public static ClosedChannelDetailsDto createFromModel(LocalChannel localChannel) {
boolean closed = localChannel.isClosed();
if (closed) {
ClosedChannel closedChannel = localChannel.getAsClosedChannel();
boolean forceClosed = closedChannel.isForceClosed();
boolean breach = forceClosed && closedChannel.getAsForceClosedChannel().isBreach();
return new ClosedChannelDetailsDto(
closedChannel.getCloseInitiator(), closedChannel.getCloseHeight(), forceClosed, breach
);
} else {
return UNKNOWN;
}
}
}

View File

@@ -8,7 +8,6 @@ import de.cotto.lndmanagej.controller.dto.FeeReportDto;
import de.cotto.lndmanagej.controller.dto.OffChainCostsDto;
import de.cotto.lndmanagej.controller.dto.PoliciesDto;
import de.cotto.lndmanagej.model.BalanceInformation;
import de.cotto.lndmanagej.model.CloseInitiator;
import de.cotto.lndmanagej.model.Coins;
import de.cotto.lndmanagej.model.FeeReport;
import de.cotto.lndmanagej.model.LocalChannel;
@@ -54,7 +53,7 @@ class ChannelControllerTest {
private static final OffChainCostsDto OFF_CHAIN_COSTS = new OffChainCostsDto(SOURCE_COSTS, TARGET_COSTS);
private static final PoliciesDto FEE_CONFIGURATION_DTO = PoliciesDto.createFromModel(POLICIES);
private static final ClosedChannelDetailsDto CLOSED_CHANNEL_DETAILS_DTO =
new ClosedChannelDetailsDto(CloseInitiator.REMOTE, 987_654);
ClosedChannelDetailsDto.createFromModel(CLOSED_CHANNEL);
private static final FeeReport FEE_REPORT = new FeeReport(Coins.ofMilliSatoshis(1_234), Coins.ofMilliSatoshis(567));
@InjectMocks
@@ -158,17 +157,13 @@ class ChannelControllerTest {
@Test
void getDetails_closed() throws NotFoundException {
ChannelDetailsDto expectedDetails = mockForChannelWithoutPolicies(
CLOSED_CHANNEL,
CLOSED_CHANNEL.getCloseInitiator().toString(),
CLOSED_CHANNEL.getCloseHeight()
);
ChannelDetailsDto expectedDetails = mockForChannelWithoutPolicies(CLOSED_CHANNEL);
assertThat(channelController.getDetails(CHANNEL_ID)).isEqualTo(expectedDetails);
}
@Test
void getDetails_waiting_close() throws NotFoundException {
ChannelDetailsDto expectedDetails = mockForChannelWithoutPolicies(WAITING_CLOSE_CHANNEL, "", 0);
ChannelDetailsDto expectedDetails = mockForChannelWithoutPolicies(WAITING_CLOSE_CHANNEL);
assertThat(channelController.getDetails(CHANNEL_ID)).isEqualTo(expectedDetails);
}
@@ -216,11 +211,7 @@ class ChannelControllerTest {
assertThat(channelController.getFeeReport(CHANNEL_ID)).isEqualTo(FeeReportDto.createFromModel(FEE_REPORT));
}
private ChannelDetailsDto mockForChannelWithoutPolicies(
LocalChannel channel,
String closeInitiator,
int closeHeight
) {
private ChannelDetailsDto mockForChannelWithoutPolicies(LocalChannel channel) {
when(nodeService.getAlias(PUBKEY_2)).thenReturn(ALIAS_2);
when(channelService.getLocalChannel(CHANNEL_ID)).thenReturn(Optional.of(channel));
when(balanceService.getBalanceInformation(CHANNEL_ID)).thenReturn(Optional.empty());
@@ -231,7 +222,7 @@ class ChannelControllerTest {
ON_CHAIN_COSTS,
OFF_CHAIN_COSTS,
PoliciesDto.EMPTY,
new ClosedChannelDetailsDto(closeInitiator, closeHeight),
ClosedChannelDetailsDto.createFromModel(channel),
FEE_REPORT
);
}

View File

@@ -24,7 +24,8 @@ class ChannelDetailsDtoTest {
new OnChainCosts(Coins.ofSatoshis(1), Coins.ofSatoshis(2), Coins.ofSatoshis(3));
private static final OffChainCostsDto OFF_CHAIN_COSTS =
new OffChainCostsDto(Coins.ofSatoshis(3), Coins.ofSatoshis(4));
private static final ClosedChannelDetailsDto CLOSE_DETAILS = new ClosedChannelDetailsDto("abc", 123);
private static final ClosedChannelDetailsDto CLOSE_DETAILS =
ClosedChannelDetailsDto.createFromModel(CLOSED_CHANNEL);
private static final FeeReport FEE_REPORT =
new FeeReport(Coins.ofMilliSatoshis(1234), Coins.ofMilliSatoshis(567));
private static final ChannelDetailsDto CHANNEL_DETAILS_DTO = new ChannelDetailsDto(

View File

@@ -16,7 +16,8 @@ import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2;
import static org.assertj.core.api.Assertions.assertThat;
class ChannelDtoTest {
private static final ClosedChannelDetailsDto CLOSE_DETAILS = new ClosedChannelDetailsDto("abc", 123);
private static final ClosedChannelDetailsDto CLOSE_DETAILS =
ClosedChannelDetailsDto.createFromModel(CLOSED_CHANNEL);
private static final ChannelDto CHANNEL_DTO = new ChannelDto(CLOSED_CHANNEL, CLOSE_DETAILS);
@Test

View File

@@ -3,11 +3,75 @@ package de.cotto.lndmanagej.controller.dto;
import de.cotto.lndmanagej.model.CloseInitiator;
import org.junit.jupiter.api.Test;
import static de.cotto.lndmanagej.model.CoopClosedChannelFixtures.CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ForceClosedChannelFixtures.FORCE_CLOSED_CHANNEL;
import static de.cotto.lndmanagej.model.ForceClosedChannelFixtures.FORCE_CLOSED_CHANNEL_BREACH;
import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL;
import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL;
import static org.assertj.core.api.Assertions.assertThat;
class ClosedChannelDetailsDtoTest {
private static final ClosedChannelDetailsDto DTO =
new ClosedChannelDetailsDto(CloseInitiator.LOCAL, 987_654, true, false);
@Test
void initiator() {
assertThat(new ClosedChannelDetailsDto(CloseInitiator.LOCAL, 987_654).initiator()).isEqualTo("LOCAL");
assertThat(DTO.initiator()).isEqualTo("LOCAL");
}
@Test
void height() {
assertThat(DTO.height()).isEqualTo(987_654);
}
@Test
void forceClose() {
assertThat(DTO.force()).isEqualTo(true);
}
@Test
void createFromModel_open() {
assertThat(ClosedChannelDetailsDto.createFromModel(LOCAL_OPEN_CHANNEL))
.isEqualTo(ClosedChannelDetailsDto.UNKNOWN);
}
@Test
void createFromModel_closing() {
assertThat(ClosedChannelDetailsDto.createFromModel(FORCE_CLOSING_CHANNEL))
.isEqualTo(ClosedChannelDetailsDto.UNKNOWN);
}
@Test
void createFromModel_coop_closed() {
ClosedChannelDetailsDto expected = new ClosedChannelDetailsDto(
CLOSED_CHANNEL.getCloseInitiator().toString(),
CLOSED_CHANNEL.getCloseHeight(),
false,
false
);
assertThat(ClosedChannelDetailsDto.createFromModel(CLOSED_CHANNEL)).isEqualTo(expected);
}
@Test
void createFromModel_force_closed() {
ClosedChannelDetailsDto expected = new ClosedChannelDetailsDto(
FORCE_CLOSED_CHANNEL.getCloseInitiator().toString(),
FORCE_CLOSED_CHANNEL.getCloseHeight(),
true,
false
);
assertThat(ClosedChannelDetailsDto.createFromModel(FORCE_CLOSED_CHANNEL)).isEqualTo(expected);
}
@Test
void createFromModel_breach() {
ClosedChannelDetailsDto expected = new ClosedChannelDetailsDto(
FORCE_CLOSED_CHANNEL_BREACH.getCloseInitiator().toString(),
FORCE_CLOSED_CHANNEL_BREACH.getCloseHeight(),
true,
true
);
assertThat(ClosedChannelDetailsDto.createFromModel(FORCE_CLOSED_CHANNEL_BREACH)).isEqualTo(expected);
}
}