diff --git a/application/build.gradle b/application/build.gradle index 0da3247a..dadc33e4 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -6,6 +6,7 @@ dependencies { runtimeOnly project(':web') runtimeOnly project(':forwarding-history') runtimeOnly project(':invoices') + runtimeOnly project(':payments') runtimeOnly project(':statistics') runtimeOnly 'org.postgresql:postgresql' testRuntimeOnly 'com.h2database:h2' diff --git a/forwarding-history/src/integrationTest/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsRepositoryIT.java b/forwarding-history/src/integrationTest/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsRepositoryIT.java index cce5dabe..7afcbeef 100644 --- a/forwarding-history/src/integrationTest/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsRepositoryIT.java +++ b/forwarding-history/src/integrationTest/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsRepositoryIT.java @@ -20,21 +20,21 @@ class ForwardingEventsRepositoryIT { @Test void findMaxIndex_one_event() { - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT)); assertThat(repository.findMaxIndex()).contains(1); } @Test void findMaxIndex_two_events() { - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT_2)); - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT_2)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT)); assertThat(repository.findMaxIndex()).contains(2); } @Test void findByChannelIncoming() { - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT_2)); - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT_2)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT)); assertThat(repository.findByChannelIncoming(FORWARDING_EVENT.channelIn().getShortChannelId())) .map(ForwardingEventJpaDto::toModel) .containsExactly(FORWARDING_EVENT); @@ -42,8 +42,8 @@ class ForwardingEventsRepositoryIT { @Test void findByChannelOutgoing() { - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT_2)); - repository.save(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT_2)); + repository.save(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT)); assertThat(repository.findByChannelOutgoing(FORWARDING_EVENT.channelOut().getShortChannelId())) .map(ForwardingEventJpaDto::toModel) .containsExactly(FORWARDING_EVENT); diff --git a/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDto.java b/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDto.java index 81127a51..ee86b366 100644 --- a/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDto.java +++ b/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDto.java @@ -30,7 +30,7 @@ class ForwardingEventJpaDto { // for JPA } - public static ForwardingEventJpaDto createFromForwardingEvent(ForwardingEvent forwardingEvent) { + public static ForwardingEventJpaDto createFromModel(ForwardingEvent forwardingEvent) { ForwardingEventJpaDto jpaDto = new ForwardingEventJpaDto(); jpaDto.eventIndex = forwardingEvent.index(); jpaDto.amountIncoming = forwardingEvent.amountIn().milliSatoshis(); diff --git a/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImpl.java b/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImpl.java index 925d5015..04c730ad 100644 --- a/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImpl.java +++ b/forwarding-history/src/main/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImpl.java @@ -23,7 +23,7 @@ public class ForwardingEventsDaoImpl implements ForwardingEventsDao { @Override public void save(Collection forwardingEvents) { List converted = forwardingEvents.stream() - .map(ForwardingEventJpaDto::createFromForwardingEvent) + .map(ForwardingEventJpaDto::createFromModel) .collect(toList()); repository.saveAll(converted); } diff --git a/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDtoTest.java b/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDtoTest.java index 1b035562..382de4b3 100644 --- a/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDtoTest.java +++ b/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventJpaDtoTest.java @@ -10,8 +10,8 @@ import static org.assertj.core.api.Assertions.assertThat; class ForwardingEventJpaDtoTest { @Test @SuppressWarnings("PMD.JUnitTestContainsTooManyAsserts") - void createFromForwardingEvent() { - ForwardingEventJpaDto jpaDto = ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT); + void createFromModel() { + ForwardingEventJpaDto jpaDto = ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT); assertThat(jpaDto.getIndex()).isEqualTo(FORWARDING_EVENT.index()); assertThat(jpaDto.getAmountIncoming()).isEqualTo(FORWARDING_EVENT.amountIn().milliSatoshis()); assertThat(jpaDto.getAmountOutgoing()).isEqualTo(FORWARDING_EVENT.amountOut().milliSatoshis()); @@ -23,7 +23,7 @@ class ForwardingEventJpaDtoTest { @Test void toModel() { - assertThat(ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT).toModel()) + assertThat(ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT).toModel()) .isEqualTo(FORWARDING_EVENT); } } \ No newline at end of file diff --git a/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImplTest.java b/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImplTest.java index 8e185b01..c0073644 100644 --- a/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImplTest.java +++ b/forwarding-history/src/test/java/de/cotto/lndmanagej/forwardinghistory/persistence/ForwardingEventsDaoImplTest.java @@ -64,8 +64,8 @@ class ForwardingEventsDaoImplTest { @Test void getEventsWithOutgoingChannel() { when(repository.findByChannelOutgoing(CHANNEL_ID_2.getShortChannelId())).thenReturn(List.of( - ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT), - ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT_2) + ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT), + ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT_2) )); assertThat(dao.getEventsWithOutgoingChannel(CHANNEL_ID_2)) .containsExactly(FORWARDING_EVENT, FORWARDING_EVENT_2); @@ -79,8 +79,8 @@ class ForwardingEventsDaoImplTest { @Test void getEventsWithIncomingChannel() { when(repository.findByChannelIncoming(CHANNEL_ID_2.getShortChannelId())).thenReturn(List.of( - ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT), - ForwardingEventJpaDto.createFromForwardingEvent(FORWARDING_EVENT_2) + ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT), + ForwardingEventJpaDto.createFromModel(FORWARDING_EVENT_2) )); assertThat(dao.getEventsWithIncomingChannel(CHANNEL_ID_2)) .containsExactly(FORWARDING_EVENT, FORWARDING_EVENT_2); diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPayments.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPayments.java new file mode 100644 index 00000000..b847e093 --- /dev/null +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcPayments.java @@ -0,0 +1,53 @@ +package de.cotto.lndmanagej.grpc; + +import de.cotto.lndmanagej.model.Coins; +import de.cotto.lndmanagej.model.Payment; +import lnrpc.ListPaymentsResponse; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Optional; + +import static lnrpc.Payment.PaymentStatus.SUCCEEDED; + +@Component +public class GrpcPayments { + private static final int LIMIT = 1_000; + + private final GrpcService grpcService; + + public GrpcPayments(GrpcService grpcService) { + this.grpcService = grpcService; + } + + public int getLimit() { + return LIMIT; + } + + public Optional> getPaymentsAfter(long offset) { + ListPaymentsResponse list = grpcService.getPayments(offset, LIMIT).orElse(null); + if (list == null) { + return Optional.empty(); + } + return Optional.ofNullable(list.getPaymentsList().stream() + .map(this::toPayment) + .toList()); + } + + private Payment toPayment(lnrpc.Payment lndPayment) { + if (lndPayment.getStatus() != SUCCEEDED) { + throw new IllegalStateException(""); + } + Instant timestamp = Instant.ofEpochMilli(lndPayment.getCreationTimeNs() / 1_000); + return new Payment( + lndPayment.getPaymentIndex(), + lndPayment.getPaymentHash(), + LocalDateTime.ofInstant(timestamp, ZoneOffset.UTC), + Coins.ofMilliSatoshis(lndPayment.getValueMsat()), + Coins.ofMilliSatoshis(lndPayment.getFeeMsat()) + ); + } +} 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 88a1e22c..7e035c30 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 @@ -23,6 +23,8 @@ import lnrpc.LightningGrpc; import lnrpc.ListChannelsRequest; import lnrpc.ListInvoiceRequest; import lnrpc.ListInvoiceResponse; +import lnrpc.ListPaymentsRequest; +import lnrpc.ListPaymentsResponse; import lnrpc.ListPeersRequest; import lnrpc.NodeInfo; import lnrpc.NodeInfoRequest; @@ -158,6 +160,16 @@ public class GrpcService extends GrpcBase { return get(() -> lightningStub.listInvoices(request)); } + public Optional getPayments(long offset, int limit) { + ListPaymentsRequest request = ListPaymentsRequest.newBuilder() + .setIndexOffset(offset) + .setMaxPayments(limit) + .setIncludeIncomplete(false) + .setReversed(false) + .build(); + return get(() -> lightningStub.listPayments(request)); + } + @Timed public Optional> subscribeToSettledInvoices(long settleIndex) { return get(() -> lightningStub.subscribeInvoices(InvoiceSubscription.newBuilder() diff --git a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcPaymentsTest.java b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcPaymentsTest.java new file mode 100644 index 00000000..d430e34a --- /dev/null +++ b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcPaymentsTest.java @@ -0,0 +1,110 @@ +package de.cotto.lndmanagej.grpc; + +import de.cotto.lndmanagej.model.Payment; +import lnrpc.ListPaymentsResponse; +import lnrpc.Payment.PaymentStatus; +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 javax.annotation.Nullable; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Optional; + +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_2; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GrpcPaymentsTest { + private static final long ADD_INDEX_OFFSET = 123; + private static final int LIMIT = 1_000; + + @InjectMocks + private GrpcPayments grpcPayments; + + @Mock + private GrpcService grpcService; + + @Test + void empty_optional() { + when(grpcService.getPayments(anyLong(), anyInt())).thenReturn(Optional.empty()); + assertThat(grpcPayments.getPaymentsAfter(0L)).isEmpty(); + } + + @Test + void no_payment() { + ListPaymentsResponse response = ListPaymentsResponse.newBuilder().build(); + when(grpcService.getPayments(anyLong(), anyInt())).thenReturn(Optional.of(response)); + assertThat(grpcPayments.getPaymentsAfter(0L)).contains(List.of()); + } + + @Test + void with_payments() { + ListPaymentsResponse response = ListPaymentsResponse.newBuilder() + .addPayments(payment(PaymentStatus.SUCCEEDED, PAYMENT)) + .addPayments(payment(PaymentStatus.SUCCEEDED, PAYMENT_2)) + .build(); + when(grpcService.getPayments(anyLong(), anyInt())).thenReturn(Optional.of(response)); + assertThat(grpcPayments.getPaymentsAfter(0L)).contains( + List.of(PAYMENT, PAYMENT_2) + ); + } + + @Test + void throws_exception_for_unsuccessful_payment() { + mockResponse(payment(PaymentStatus.IN_FLIGHT, null)); + assertThatExceptionOfType(IllegalStateException.class).isThrownBy( + () -> grpcPayments.getPaymentsAfter(0L) + ); + } + + private void mockResponse(lnrpc.Payment payment) { + when(grpcService.getPayments(anyLong(), anyInt())).thenReturn(Optional.of(ListPaymentsResponse.newBuilder() + .addPayments(payment) + .build())); + } + + @Test + void starts_at_the_beginning() { + grpcPayments.getPaymentsAfter(ADD_INDEX_OFFSET); + verify(grpcService).getPayments(eq(ADD_INDEX_OFFSET), anyInt()); + } + + @Test + void uses_limit() { + grpcPayments.getPaymentsAfter(ADD_INDEX_OFFSET); + verify(grpcService).getPayments(ADD_INDEX_OFFSET, LIMIT); + } + + @Test + void getLimit() { + assertThat(grpcPayments.getLimit()).isEqualTo(LIMIT); + } + + private lnrpc.Payment payment( + PaymentStatus status, + @Nullable Payment payment + ) { + if (payment == null) { + return lnrpc.Payment.newBuilder().setStatus(status).build(); + } + return lnrpc.Payment.newBuilder() + .setStatus(status) + .setPaymentIndex(payment.index()) + .setPaymentHash(payment.paymentHash()) + .setValueMsat(payment.value().milliSatoshis()) + .setFeeMsat(payment.fees().milliSatoshis()) + .setCreationTimeNs(payment.creationDateTime().toInstant(ZoneOffset.UTC).toEpochMilli() * 1_000) + .build(); + } +} \ No newline at end of file diff --git a/invoices/src/integrationTest/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesRepositoryIT.java b/invoices/src/integrationTest/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesRepositoryIT.java index 19a9ac28..cb9824cb 100644 --- a/invoices/src/integrationTest/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesRepositoryIT.java +++ b/invoices/src/integrationTest/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesRepositoryIT.java @@ -56,7 +56,7 @@ class SettledInvoicesRepositoryIT { } private SettledInvoiceJpaDto invoice(int addIndex, int settleIndex) { - return SettledInvoiceJpaDto.createFromInvoice(new SettledInvoice( + return SettledInvoiceJpaDto.createFromModel(new SettledInvoice( addIndex, settleIndex, LocalDateTime.MIN, diff --git a/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoiceJpaDto.java b/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoiceJpaDto.java index 23f52308..71c26e4d 100644 --- a/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoiceJpaDto.java +++ b/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoiceJpaDto.java @@ -41,7 +41,7 @@ class SettledInvoiceJpaDto { // for JPA } - public static SettledInvoiceJpaDto createFromInvoice(SettledInvoice settledInvoice) { + public static SettledInvoiceJpaDto createFromModel(SettledInvoice settledInvoice) { SettledInvoiceJpaDto jpaDto = new SettledInvoiceJpaDto(); jpaDto.addIndex = settledInvoice.addIndex(); jpaDto.settleIndex = settledInvoice.settleIndex(); diff --git a/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesDaoImpl.java b/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesDaoImpl.java index 028627d0..ede80b89 100644 --- a/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesDaoImpl.java +++ b/invoices/src/main/java/de/cotto/lndmanagej/invoices/persistence/SettledInvoicesDaoImpl.java @@ -22,14 +22,14 @@ public class SettledInvoicesDaoImpl implements SettledInvoicesDao { @Override public void save(Collection settledInvoices) { List converted = settledInvoices.stream() - .map(SettledInvoiceJpaDto::createFromInvoice) + .map(SettledInvoiceJpaDto::createFromModel) .collect(toList()); repository.saveAll(converted); } @Override public void save(SettledInvoice settledInvoice) { - repository.save(SettledInvoiceJpaDto.createFromInvoice(settledInvoice)); + repository.save(SettledInvoiceJpaDto.createFromModel(settledInvoice)); } @Override diff --git a/invoices/src/test/java/de/cotto/lndmanagej/invoices/persistence/SettledSettledInvoiceJpaDtoTest.java b/invoices/src/test/java/de/cotto/lndmanagej/invoices/persistence/SettledSettledInvoiceJpaDtoTest.java index ce47c2c5..ef648f05 100644 --- a/invoices/src/test/java/de/cotto/lndmanagej/invoices/persistence/SettledSettledInvoiceJpaDtoTest.java +++ b/invoices/src/test/java/de/cotto/lndmanagej/invoices/persistence/SettledSettledInvoiceJpaDtoTest.java @@ -14,8 +14,8 @@ import static org.assertj.core.api.Assertions.assertThat; class SettledSettledInvoiceJpaDtoTest { @Test @SuppressWarnings("PMD.JUnitTestContainsTooManyAsserts") - void createFromInvoice() { - SettledInvoiceJpaDto jpaDto = SettledInvoiceJpaDto.createFromInvoice(SETTLED_INVOICE); + void createFromModel() { + SettledInvoiceJpaDto jpaDto = SettledInvoiceJpaDto.createFromModel(SETTLED_INVOICE); assertThat(jpaDto.getAddIndex()).isEqualTo(SETTLED_INVOICE.addIndex()); assertThat(jpaDto.getSettleIndex()).isEqualTo(SETTLED_INVOICE.settleIndex()); assertThat(jpaDto.getSettleDate()) @@ -28,32 +28,32 @@ class SettledSettledInvoiceJpaDtoTest { } @Test - void createFromInvoice_with_keysend_message() { - SettledInvoiceJpaDto jpaDto = SettledInvoiceJpaDto.createFromInvoice(SETTLED_INVOICE_KEYSEND); + void createFromModel_with_keysend_message() { + SettledInvoiceJpaDto jpaDto = SettledInvoiceJpaDto.createFromModel(SETTLED_INVOICE_KEYSEND); assertThat(jpaDto.getKeysendMessage()).isEqualTo(KEYSEND_MESSAGE); } @Test - void createFromInvoice_without_receivedVia_channel() { - SettledInvoiceJpaDto jpaDto = SettledInvoiceJpaDto.createFromInvoice(SETTLED_INVOICE_NO_CHANNEL_ID); + void createFromModel_without_receivedVia_channel() { + SettledInvoiceJpaDto jpaDto = SettledInvoiceJpaDto.createFromModel(SETTLED_INVOICE_NO_CHANNEL_ID); assertThat(jpaDto.getReceivedVia()).isEqualTo(0L); } @Test void toModel() { - assertThat(SettledInvoiceJpaDto.createFromInvoice(SETTLED_INVOICE).toModel()) + assertThat(SettledInvoiceJpaDto.createFromModel(SETTLED_INVOICE).toModel()) .isEqualTo(SETTLED_INVOICE); } @Test void toModel_without_receivedVia_channel() { - assertThat(SettledInvoiceJpaDto.createFromInvoice(SETTLED_INVOICE_NO_CHANNEL_ID).toModel()) + assertThat(SettledInvoiceJpaDto.createFromModel(SETTLED_INVOICE_NO_CHANNEL_ID).toModel()) .isEqualTo(SETTLED_INVOICE_NO_CHANNEL_ID); } @Test void toModel_with_keysend_message() { - assertThat(SettledInvoiceJpaDto.createFromInvoice(SETTLED_INVOICE_KEYSEND).toModel()) + assertThat(SettledInvoiceJpaDto.createFromModel(SETTLED_INVOICE_KEYSEND).toModel()) .isEqualTo(SETTLED_INVOICE_KEYSEND); } } diff --git a/model/src/main/java/de/cotto/lndmanagej/model/Payment.java b/model/src/main/java/de/cotto/lndmanagej/model/Payment.java new file mode 100644 index 00000000..d5d484b1 --- /dev/null +++ b/model/src/main/java/de/cotto/lndmanagej/model/Payment.java @@ -0,0 +1,12 @@ +package de.cotto.lndmanagej.model; + +import java.time.LocalDateTime; + +public record Payment( + long index, + String paymentHash, + LocalDateTime creationDateTime, + Coins value, + Coins fees +) { +} diff --git a/model/src/test/java/de/cotto/lndmanagej/model/PaymentTest.java b/model/src/test/java/de/cotto/lndmanagej/model/PaymentTest.java new file mode 100644 index 00000000..70b4552e --- /dev/null +++ b/model/src/test/java/de/cotto/lndmanagej/model/PaymentTest.java @@ -0,0 +1,38 @@ +package de.cotto.lndmanagej.model; + +import org.junit.jupiter.api.Test; + +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_CREATION_DATE_TIME; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_FEES; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_HASH; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_INDEX; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_VALUE; +import static org.assertj.core.api.Assertions.assertThat; + +class PaymentTest { + @Test + void index() { + assertThat(PAYMENT.index()).isEqualTo(PAYMENT_INDEX); + } + + @Test + void paymentHash() { + assertThat(PAYMENT.paymentHash()).isEqualTo(PAYMENT_HASH); + } + + @Test + void creationDateTime() { + assertThat(PAYMENT.creationDateTime()).isEqualTo(PAYMENT_CREATION_DATE_TIME); + } + + @Test + void value() { + assertThat(PAYMENT.value()).isEqualTo(PAYMENT_VALUE); + } + + @Test + void fees() { + assertThat(PAYMENT.fees()).isEqualTo(PAYMENT_FEES); + } +} \ No newline at end of file diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/PaymentFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/PaymentFixtures.java new file mode 100644 index 00000000..9fffc0c5 --- /dev/null +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/PaymentFixtures.java @@ -0,0 +1,21 @@ +package de.cotto.lndmanagej.model; + +import java.time.LocalDateTime; + +public class PaymentFixtures { + public static final int PAYMENT_INDEX = 2; + public static final int PAYMENT_INDEX_2 = 3; + public static final String PAYMENT_HASH = "abc"; + public static final Coins PAYMENT_VALUE = Coins.ofSatoshis(1_000_000); + public static final Coins PAYMENT_FEES = Coins.ofMilliSatoshis(10); + public static final LocalDateTime PAYMENT_CREATION_DATE_TIME = + LocalDateTime.of(2021, 12, 5, 22, 22, 22, 500_000_000); + + public static final Payment PAYMENT = new Payment( + PAYMENT_INDEX, PAYMENT_HASH, PAYMENT_CREATION_DATE_TIME, PAYMENT_VALUE, PAYMENT_FEES + ); + + public static final Payment PAYMENT_2 = new Payment( + PAYMENT_INDEX_2, PAYMENT_HASH, PAYMENT_CREATION_DATE_TIME, PAYMENT_VALUE, PAYMENT_FEES + ); +} diff --git a/payments/build.gradle b/payments/build.gradle new file mode 100644 index 00000000..c844fa62 --- /dev/null +++ b/payments/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'lnd-manageJ.java-library-conventions' +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation project(':model') + implementation project(':grpc-adapter') + testRuntimeOnly 'com.h2database:h2' + testFixturesApi testFixtures(project(':model')) +} \ No newline at end of file diff --git a/payments/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java b/payments/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java new file mode 100644 index 00000000..7b1634de --- /dev/null +++ b/payments/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java @@ -0,0 +1,10 @@ +package de.cotto.lndmanagej; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootConfiguration { + public SpringBootConfiguration() { + // default constructor + } +} diff --git a/payments/src/integrationTest/java/de/cotto/lndmanagej/payments/persistence/PaymentsRepositoryIT.java b/payments/src/integrationTest/java/de/cotto/lndmanagej/payments/persistence/PaymentsRepositoryIT.java new file mode 100644 index 00000000..8e8bd0a9 --- /dev/null +++ b/payments/src/integrationTest/java/de/cotto/lndmanagej/payments/persistence/PaymentsRepositoryIT.java @@ -0,0 +1,34 @@ +package de.cotto.lndmanagej.payments.persistence; + +import de.cotto.lndmanagej.model.Payment; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT; +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +class PaymentsRepositoryIT { + @Autowired + private PaymentsRepository repository; + + @Test + void getMaxIndex_no_payment() { + assertThat(repository.getMaxIndex()).isEqualTo(0); + } + + @Test + void getMaxIndex() { + repository.save(payment(1)); + repository.save(payment(2)); + repository.save(payment(3)); + assertThat(repository.getMaxIndex()).isEqualTo(3L); + } + + private PaymentJpaDto payment(int index) { + return PaymentJpaDto.createFromModel( + new Payment(index, PAYMENT.paymentHash(), PAYMENT.creationDateTime(), PAYMENT.value(), PAYMENT.fees()) + ); + } +} \ No newline at end of file diff --git a/payments/src/main/java/de/cotto/lndmanagej/payments/Payments.java b/payments/src/main/java/de/cotto/lndmanagej/payments/Payments.java new file mode 100644 index 00000000..125325ab --- /dev/null +++ b/payments/src/main/java/de/cotto/lndmanagej/payments/Payments.java @@ -0,0 +1,29 @@ +package de.cotto.lndmanagej.payments; + +import de.cotto.lndmanagej.grpc.GrpcPayments; +import de.cotto.lndmanagej.model.Payment; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Component +public class Payments { + private final GrpcPayments grpcPayments; + private final PaymentsDao dao; + + public Payments(GrpcPayments grpcPayments, PaymentsDao dao) { + this.grpcPayments = grpcPayments; + this.dao = dao; + } + + @Scheduled(fixedDelay = 10, timeUnit = TimeUnit.SECONDS) + public void refresh() { + List payments; + do { + payments = grpcPayments.getPaymentsAfter(dao.getIndexOffset()).orElse(List.of()); + dao.save(payments); + } while (payments.size() == grpcPayments.getLimit()); + } +} diff --git a/payments/src/main/java/de/cotto/lndmanagej/payments/PaymentsDao.java b/payments/src/main/java/de/cotto/lndmanagej/payments/PaymentsDao.java new file mode 100644 index 00000000..d85d9fc0 --- /dev/null +++ b/payments/src/main/java/de/cotto/lndmanagej/payments/PaymentsDao.java @@ -0,0 +1,13 @@ +package de.cotto.lndmanagej.payments; + +import de.cotto.lndmanagej.model.Payment; + +import java.util.Collection; + +public interface PaymentsDao { + void save(Collection payments); + + void save(Payment payment); + + long getIndexOffset(); +} diff --git a/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentJpaDto.java b/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentJpaDto.java new file mode 100644 index 00000000..0abb5cfa --- /dev/null +++ b/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentJpaDto.java @@ -0,0 +1,72 @@ +package de.cotto.lndmanagej.payments.persistence; + +import de.cotto.lndmanagej.model.Coins; +import de.cotto.lndmanagej.model.Payment; + +import javax.annotation.Nullable; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Objects; + +@Entity +@Table(name = "payments") +class PaymentJpaDto { + @Id + private long paymentIndex; + + @Nullable + private String hash; + private long timestamp; + private long value; + private long fees; + + public PaymentJpaDto() { + // for JPA + } + + public static PaymentJpaDto createFromModel(Payment payment) { + PaymentJpaDto jpaDto = new PaymentJpaDto(); + jpaDto.paymentIndex = payment.index(); + jpaDto.hash = payment.paymentHash(); + jpaDto.timestamp = payment.creationDateTime().toInstant(ZoneOffset.UTC).toEpochMilli(); + jpaDto.value = payment.value().milliSatoshis(); + jpaDto.fees = payment.fees().milliSatoshis(); + return jpaDto; + } + + public Payment toModel() { + long epochSecond = timestamp / 1_000; + int milliseconds = (int) (timestamp % 1_000); + int nanoseconds = milliseconds * 1_000_000; + return new Payment( + paymentIndex, + Objects.requireNonNull(hash), + LocalDateTime.ofEpochSecond(epochSecond, nanoseconds, ZoneOffset.UTC), + Coins.ofMilliSatoshis(value), + Coins.ofMilliSatoshis(fees) + ); + } + + public long getPaymentIndex() { + return paymentIndex; + } + + public String getHash() { + return Objects.requireNonNull(hash); + } + + public long getTimestamp() { + return timestamp; + } + + public long getValue() { + return value; + } + + public long getFees() { + return fees; + } +} diff --git a/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentsDaoImpl.java b/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentsDaoImpl.java new file mode 100644 index 00000000..ee19d9e4 --- /dev/null +++ b/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentsDaoImpl.java @@ -0,0 +1,39 @@ +package de.cotto.lndmanagej.payments.persistence; + +import de.cotto.lndmanagej.model.Payment; +import de.cotto.lndmanagej.payments.PaymentsDao; +import org.springframework.stereotype.Component; + +import javax.transaction.Transactional; +import java.util.Collection; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +@Component +@Transactional +public class PaymentsDaoImpl implements PaymentsDao { + private final PaymentsRepository repository; + + public PaymentsDaoImpl(PaymentsRepository repository) { + this.repository = repository; + } + + @Override + public void save(Collection payments) { + List converted = payments.stream() + .map(PaymentJpaDto::createFromModel) + .collect(toList()); + repository.saveAll(converted); + } + + @Override + public void save(Payment payment) { + repository.save(PaymentJpaDto.createFromModel(payment)); + } + + @Override + public long getIndexOffset() { + return repository.getMaxIndex(); + } +} diff --git a/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentsRepository.java b/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentsRepository.java new file mode 100644 index 00000000..5f0edbd1 --- /dev/null +++ b/payments/src/main/java/de/cotto/lndmanagej/payments/persistence/PaymentsRepository.java @@ -0,0 +1,9 @@ +package de.cotto.lndmanagej.payments.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface PaymentsRepository extends JpaRepository { + @Query("SELECT coalesce(max(paymentIndex), 0) FROM PaymentJpaDto") + long getMaxIndex(); +} diff --git a/payments/src/test/java/de/cotto/lndmanagej/payments/PaymentsTest.java b/payments/src/test/java/de/cotto/lndmanagej/payments/PaymentsTest.java new file mode 100644 index 00000000..7a92f1ef --- /dev/null +++ b/payments/src/test/java/de/cotto/lndmanagej/payments/PaymentsTest.java @@ -0,0 +1,63 @@ +package de.cotto.lndmanagej.payments; + +import de.cotto.lndmanagej.grpc.GrpcPayments; +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 java.util.List; +import java.util.Optional; + +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_2; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class PaymentsTest { + private static final long INDEX_OFFSET = 1_234; + + @InjectMocks + private Payments payments; + + @Mock + private GrpcPayments grpcPayments; + + @Mock + private PaymentsDao dao; + + @BeforeEach + void setUp() { + when(dao.getIndexOffset()).thenReturn(INDEX_OFFSET); + when(grpcPayments.getLimit()).thenReturn(1); + } + + @Test + void refresh_uses_known_offset() { + payments.refresh(); + verify(grpcPayments).getPaymentsAfter(INDEX_OFFSET); + } + + @Test + void refresh_saves_payment() { + when(grpcPayments.getPaymentsAfter(INDEX_OFFSET)).thenReturn( + Optional.of(List.of(PAYMENT, PAYMENT_2)) + ).thenReturn(Optional.of(List.of())); + payments.refresh(); + verify(dao).save(List.of(PAYMENT, PAYMENT_2)); + } + + @Test + void refresh_repeats_while_at_limit() { + when(grpcPayments.getPaymentsAfter(INDEX_OFFSET)) + .thenReturn(Optional.of(List.of(PAYMENT))) + .thenReturn(Optional.of(List.of(PAYMENT_2))) + .thenReturn(Optional.of(List.of())); + payments.refresh(); + verify(dao).save(List.of(PAYMENT)); + verify(dao).save(List.of(PAYMENT_2)); + } +} \ No newline at end of file diff --git a/payments/src/test/java/de/cotto/lndmanagej/payments/persistence/PaymentJpaDtoTest.java b/payments/src/test/java/de/cotto/lndmanagej/payments/persistence/PaymentJpaDtoTest.java new file mode 100644 index 00000000..110b001e --- /dev/null +++ b/payments/src/test/java/de/cotto/lndmanagej/payments/persistence/PaymentJpaDtoTest.java @@ -0,0 +1,34 @@ +package de.cotto.lndmanagej.payments.persistence; + +import org.junit.jupiter.api.Test; + +import java.time.ZoneOffset; + +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_CREATION_DATE_TIME; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_FEES; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_HASH; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_INDEX; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_VALUE; +import static org.assertj.core.api.Assertions.assertThat; + +class PaymentJpaDtoTest { + @Test + @SuppressWarnings("PMD.JUnitTestContainsTooManyAsserts") + void createFromModel() { + PaymentJpaDto jpaDto = PaymentJpaDto.createFromModel(PAYMENT); + assertThat(jpaDto.getPaymentIndex()).isEqualTo(PAYMENT_INDEX); + assertThat(jpaDto.getHash()).isEqualTo(PAYMENT_HASH); + assertThat(jpaDto.getTimestamp()) + .isEqualTo(PAYMENT_CREATION_DATE_TIME.toInstant(ZoneOffset.UTC).toEpochMilli()); + assertThat(jpaDto.getValue()).isEqualTo(PAYMENT_VALUE.milliSatoshis()); + assertThat(jpaDto.getFees()).isEqualTo(PAYMENT_FEES.milliSatoshis()); + } + + @Test + void toModel() { + assertThat(PaymentJpaDto.createFromModel(PAYMENT).toModel()) + .isEqualTo(PAYMENT); + } +} + diff --git a/payments/src/test/java/de/cotto/lndmanagej/payments/persistence/PaymentsDaoImplTest.java b/payments/src/test/java/de/cotto/lndmanagej/payments/persistence/PaymentsDaoImplTest.java new file mode 100644 index 00000000..549739e0 --- /dev/null +++ b/payments/src/test/java/de/cotto/lndmanagej/payments/persistence/PaymentsDaoImplTest.java @@ -0,0 +1,69 @@ +package de.cotto.lndmanagej.payments.persistence; + +import de.cotto.lndmanagej.model.Payment; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_2; +import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_INDEX; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class PaymentsDaoImplTest { + @InjectMocks + private PaymentsDaoImpl dao; + + @Mock + private PaymentsRepository repository; + + @Test + void getMaxIndex_initially_0() { + when(repository.getMaxIndex()).thenReturn(0L); + assertThat(dao.getIndexOffset()).isEqualTo(0L); + } + + @Test + void getMaxIndex() { + when(repository.getMaxIndex()).thenReturn(123L); + assertThat(dao.getIndexOffset()).isEqualTo(123L); + } + + @Test + void save_single() { + dao.save(PAYMENT); + verify(repository).save(argThat(jpaDto -> jpaDto.getPaymentIndex() == PAYMENT_INDEX)); + } + + @Test + void save_empty() { + dao.save(Set.of()); + verify(repository).saveAll(List.of()); + } + + @Test + void save_two() { + dao.save(Set.of(PAYMENT, PAYMENT_2)); + Set expected = Set.of(PAYMENT, PAYMENT_2); + verify(repository).saveAll(argThat(isSet(expected))); + } + + @SuppressWarnings("PMD.LinguisticNaming") + private ArgumentMatcher> isSet(Set expected) { + return iterable -> iterable instanceof List && ((List) iterable).stream() + .map(PaymentJpaDto::toModel) + .collect(Collectors.toSet()) + .equals(expected); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 87533ab9..a99e0445 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,7 @@ include 'grpc-adapter' include 'grpc-client' include 'invoices' include 'model' +include 'payments' include 'statistics' include 'transactions' include 'web' diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java b/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java index 3e483a79..c506b20d 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java @@ -95,7 +95,7 @@ public class ChannelController { public BalanceInformationDto getBalance(@PathVariable ChannelId channelId) { BalanceInformation balanceInformation = balanceService.getBalanceInformation(channelId) .orElse(BalanceInformation.EMPTY); - return BalanceInformationDto.createFrom(balanceInformation); + return BalanceInformationDto.createFromModel(balanceInformation); } @Timed @@ -122,7 +122,7 @@ public class ChannelController { } private FeeReportDto getFeeReportDto(ChannelId channelId) { - return FeeReportDto.createFrom(feeService.getFeeReportForChannel(channelId)); + return FeeReportDto.createFromModel(feeService.getFeeReportForChannel(channelId)); } private PoliciesDto getPoliciesForChannel(@Nullable LocalChannel channel) { @@ -130,7 +130,7 @@ public class ChannelController { return PoliciesDto.EMPTY; } Policies policies = policyService.getPolicies(channel.getId()); - return PoliciesDto.createFrom(policies); + return PoliciesDto.createFromModel(policies); } private BalanceInformation getBalanceInformation(ChannelId channelId) { diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/NodeController.java b/web/src/main/java/de/cotto/lndmanagej/controller/NodeController.java index 98a16671..786f86b8 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/NodeController.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/NodeController.java @@ -73,7 +73,7 @@ public class NodeController { toSortedList(channelService.getWaitingCloseChannelsWith(pubkey)), toSortedList(channelService.getForceClosingChannelsWith(pubkey)), new OnChainCostsDto(openCosts, closeCosts), - BalanceInformationDto.createFrom(balanceInformation), + BalanceInformationDto.createFromModel(balanceInformation), node.online(), getFeeReportDto(pubkey) ); @@ -96,7 +96,7 @@ public class NodeController { @Timed @GetMapping("/balance") public BalanceInformationDto getBalance(@PathVariable Pubkey pubkey) { - return BalanceInformationDto.createFrom(balanceService.getBalanceInformationForPeer(pubkey)); + return BalanceInformationDto.createFromModel(balanceService.getBalanceInformationForPeer(pubkey)); } @Timed @@ -106,7 +106,7 @@ public class NodeController { } private FeeReportDto getFeeReportDto(Pubkey pubkey) { - return FeeReportDto.createFrom(feeService.getFeeReportForPeer(pubkey)); + return FeeReportDto.createFromModel(feeService.getFeeReportForPeer(pubkey)); } private List toSortedList(Set channels) { diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDto.java index ab0ab7dc..d9aedb2e 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDto.java @@ -11,7 +11,7 @@ public record BalanceInformationDto( String remoteReserve, String remoteAvailable ) { - public static BalanceInformationDto createFrom(BalanceInformation balanceInformation) { + public static BalanceInformationDto createFromModel(BalanceInformation balanceInformation) { return new BalanceInformationDto( toString(balanceInformation.localBalance()), toString(balanceInformation.localReserve()), diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDto.java index 9d1cd272..5ac348b3 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDto.java @@ -46,7 +46,7 @@ public record ChannelDetailsDto( channelDto.totalSent(), channelDto.totalReceived(), channelDto.status(), - BalanceInformationDto.createFrom(balanceInformation), + BalanceInformationDto.createFromModel(balanceInformation), onChainCosts, policies, channelDto.closeDetails(), diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDto.java index 8512c4a5..8d0be17b 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelDto.java @@ -30,7 +30,7 @@ public record ChannelDto( String.valueOf(localChannel.getCapacity().satoshis()), String.valueOf(localChannel.getTotalSent().satoshis()), String.valueOf(localChannel.getTotalReceived().satoshis()), - ChannelStatusDto.createFrom(localChannel.getStatus()), + ChannelStatusDto.createFromModel(localChannel.getStatus()), localChannel.getOpenInitiator(), closeDetails ); diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDto.java index 0372c70f..14bbe779 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDto.java @@ -9,7 +9,7 @@ public record ChannelStatusDto( boolean closed, String openClosed ) { - public static ChannelStatusDto createFrom(ChannelStatus status) { + public static ChannelStatusDto createFromModel(ChannelStatus status) { return new ChannelStatusDto( status.privateChannel(), status.active(), diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeReportDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeReportDto.java index 7347b915..c72d6cac 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeReportDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeReportDto.java @@ -11,7 +11,7 @@ public record FeeReportDto(String earned, String sourced) { ); } - public static FeeReportDto createFrom(FeeReport feeReport) { + public static FeeReportDto createFromModel(FeeReport feeReport) { return new FeeReportDto(feeReport.earned(), feeReport.sourced()); } } diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/PoliciesDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/PoliciesDto.java index 3717da57..13eda07b 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/PoliciesDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/PoliciesDto.java @@ -9,10 +9,10 @@ public record PoliciesDto( public static final PoliciesDto EMPTY = new PoliciesDto(PolicyDto.EMPTY, PolicyDto.EMPTY); - public static PoliciesDto createFrom(Policies policies) { + public static PoliciesDto createFromModel(Policies policies) { return new PoliciesDto( - PolicyDto.createFrom(policies.local()), - PolicyDto.createFrom(policies.remote()) + PolicyDto.createFromModel(policies.local()), + PolicyDto.createFromModel(policies.remote()) ); } } diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java index ff2c8781..e3f834b2 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/PolicyDto.java @@ -14,7 +14,7 @@ public record PolicyDto( false ); - public static PolicyDto createFrom(Policy policy) { + public static PolicyDto createFromModel(Policy policy) { return new PolicyDto( policy.feeRate(), policy.baseFee().milliSatoshis(), diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java index 2eae5171..4d0146dd 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java @@ -46,11 +46,11 @@ class ChannelControllerTest { private static final Coins OPEN_COSTS = Coins.ofSatoshis(1); private static final Coins CLOSE_COSTS = Coins.ofSatoshis(2); private static final OnChainCostsDto ON_CHAIN_COSTS = new OnChainCostsDto(OPEN_COSTS, CLOSE_COSTS); - private static final PoliciesDto FEE_CONFIGURATION_DTO = PoliciesDto.createFrom(POLICIES); + private static final PoliciesDto FEE_CONFIGURATION_DTO = PoliciesDto.createFromModel(POLICIES); private static final ClosedChannelDetailsDto CLOSED_CHANNEL_DETAILS_DTO = new ClosedChannelDetailsDto(CloseInitiator.REMOTE, 987_654); private static final FeeReport FEE_REPORT = new FeeReport(Coins.ofMilliSatoshis(1_234), Coins.ofMilliSatoshis(567)); - private static final FeeReportDto FEE_REPORT_DTO = FeeReportDto.createFrom(FEE_REPORT); + private static final FeeReportDto FEE_REPORT_DTO = FeeReportDto.createFromModel(FEE_REPORT); @InjectMocks private ChannelController channelController; @@ -165,14 +165,14 @@ class ChannelControllerTest { void getBalance() { when(balanceService.getBalanceInformation(CHANNEL_ID)).thenReturn(Optional.of(BALANCE_INFORMATION)); assertThat(channelController.getBalance(CHANNEL_ID)) - .isEqualTo(BalanceInformationDto.createFrom(BALANCE_INFORMATION)); + .isEqualTo(BalanceInformationDto.createFromModel(BALANCE_INFORMATION)); } @Test void getBalance_not_found() { when(balanceService.getBalanceInformation(CHANNEL_ID)).thenReturn(Optional.empty()); assertThat(channelController.getBalance(CHANNEL_ID)) - .isEqualTo(BalanceInformationDto.createFrom(BalanceInformation.EMPTY)); + .isEqualTo(BalanceInformationDto.createFromModel(BalanceInformation.EMPTY)); } @Test diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java index 89ab23f0..2822088e 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java @@ -88,7 +88,7 @@ class NodeControllerTest { List.of(), List.of(), new OnChainCostsDto(Coins.NONE, Coins.NONE), - BalanceInformationDto.createFrom(BalanceInformation.EMPTY), + BalanceInformationDto.createFromModel(BalanceInformation.EMPTY), true, new FeeReportDto("0", "0") ); @@ -122,7 +122,7 @@ class NodeControllerTest { List.of(CHANNEL_ID, CHANNEL_ID_2), List.of(CHANNEL_ID, CHANNEL_ID_2, CHANNEL_ID_3), new OnChainCostsDto(openCosts, closeCosts), - BalanceInformationDto.createFrom(BALANCE_INFORMATION), + BalanceInformationDto.createFromModel(BALANCE_INFORMATION), false, new FeeReportDto("1234", "567") ); @@ -161,7 +161,8 @@ class NodeControllerTest { @Test void getBalance() { when(balanceService.getBalanceInformationForPeer(PUBKEY)).thenReturn(BALANCE_INFORMATION); - assertThat(nodeController.getBalance(PUBKEY)).isEqualTo(BalanceInformationDto.createFrom(BALANCE_INFORMATION)); + assertThat(nodeController.getBalance(PUBKEY)) + .isEqualTo(BalanceInformationDto.createFromModel(BALANCE_INFORMATION)); } @Test diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDtoTest.java index a3b92dec..9b1403ec 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/BalanceInformationDtoTest.java @@ -7,7 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; class BalanceInformationDtoTest { @Test - void createFrom() { + void createFromModel() { BalanceInformationDto expected = new BalanceInformationDto( String.valueOf(BALANCE_INFORMATION.localBalance().satoshis()), String.valueOf(BALANCE_INFORMATION.localReserve().satoshis()), @@ -16,6 +16,6 @@ class BalanceInformationDtoTest { String.valueOf(BALANCE_INFORMATION.remoteReserve().satoshis()), String.valueOf(BALANCE_INFORMATION.remoteAvailable().satoshis()) ); - assertThat(BalanceInformationDto.createFrom(BALANCE_INFORMATION)).isEqualTo(expected); + assertThat(BalanceInformationDto.createFromModel(BALANCE_INFORMATION)).isEqualTo(expected); } } \ No newline at end of file diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java index bf0dfab2..14b6c8cc 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java @@ -89,7 +89,7 @@ class ChannelDetailsDtoTest { FEE_REPORT ); ChannelStatusDto channelStatusDto = - ChannelStatusDto.createFrom(new ChannelStatus(false, true, false, OPEN)); + ChannelStatusDto.createFromModel(new ChannelStatus(false, true, false, OPEN)); assertThat(dto.status()).isEqualTo(channelStatusDto); } @@ -100,7 +100,7 @@ class ChannelDetailsDtoTest { @Test void balance() { - assertThat(CHANNEL_DETAILS_DTO.balance()).isEqualTo(BalanceInformationDto.createFrom(BALANCE_INFORMATION)); + assertThat(CHANNEL_DETAILS_DTO.balance()).isEqualTo(BalanceInformationDto.createFromModel(BALANCE_INFORMATION)); } @Test diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDtoTest.java index dc73bfa9..cf615256 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDtoTest.java @@ -80,7 +80,7 @@ class ChannelDtoTest { void status() { ChannelDto dto = new ChannelDto(LOCAL_OPEN_CHANNEL, CLOSE_DETAILS); ChannelStatusDto channelStatusDto = - ChannelStatusDto.createFrom(new ChannelStatus(false, true, false, OPEN)); + ChannelStatusDto.createFromModel(new ChannelStatus(false, true, false, OPEN)); assertThat(dto.status()).isEqualTo(channelStatusDto); } } \ No newline at end of file diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDtoTest.java index 613802ba..717061bb 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelStatusDtoTest.java @@ -12,7 +12,7 @@ class ChannelStatusDtoTest { private final ChannelStatus channelStatusOpen = new ChannelStatus(false, true, false, OPEN); @Test - void createFrom() { - assertThat(ChannelStatusDto.createFrom(channelStatusOpen)).isEqualTo(dtoOpen); + void createFromModel() { + assertThat(ChannelStatusDto.createFromModel(channelStatusOpen)).isEqualTo(dtoOpen); } } \ No newline at end of file diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeReportDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeReportDtoTest.java index a2a8646c..29d83ffb 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeReportDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeReportDtoTest.java @@ -22,8 +22,8 @@ class FeeReportDtoTest { } @Test - void createFrom() { - assertThat(FeeReportDto.createFrom(new FeeReport(Coins.ofSatoshis(1), Coins.ofSatoshis(2)))) + void createFromModel() { + assertThat(FeeReportDto.createFromModel(new FeeReport(Coins.ofSatoshis(1), Coins.ofSatoshis(2)))) .isEqualTo(new FeeReportDto("1000", "2000")); } } \ No newline at end of file diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/PoliciesDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/PoliciesDtoTest.java index d97e0417..20cc179f 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/PoliciesDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/PoliciesDtoTest.java @@ -9,11 +9,10 @@ import static org.assertj.core.api.Assertions.assertThat; class PoliciesDtoTest { @Test - void createFrom() { - PoliciesDto expected = new PoliciesDto(PolicyDto.createFrom(POLICY_1), PolicyDto.createFrom(POLICY_2)); - - PoliciesDto dto = PoliciesDto.createFrom(POLICIES); - + void createFromModel() { + PoliciesDto expected = + new PoliciesDto(PolicyDto.createFromModel(POLICY_1), PolicyDto.createFromModel(POLICY_2)); + PoliciesDto dto = PoliciesDto.createFromModel(POLICIES); assertThat(dto).isEqualTo(expected); } } \ No newline at end of file diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java index d02b5ea3..a4407f77 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/PolicyDtoTest.java @@ -7,9 +7,9 @@ import static org.assertj.core.api.Assertions.assertThat; class PolicyDtoTest { @Test - void createFrom() { + void createFromModel() { PolicyDto expected = new PolicyDto(100, 10, false); - PolicyDto dto = PolicyDto.createFrom(POLICY_1); + PolicyDto dto = PolicyDto.createFromModel(POLICY_1); assertThat(dto).isEqualTo(expected); } } \ No newline at end of file