mirror of
https://github.com/aljazceru/lnd-manageJ.git
synced 2026-02-23 15:04:39 +01:00
skip "in-flight" payments without in-flight HTLC created more than a day ago
this is a workaround for https://github.com/lightningnetwork/lnd/issues/6834
This commit is contained in:
@@ -20,6 +20,7 @@ import java.math.BigInteger;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -81,10 +82,30 @@ public class GrpcPayments {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(list.getPaymentsList().stream()
|
||||
.filter(payment -> payment.getStatus() != FAILED)
|
||||
.filter(this::isPendingOrSuccessful)
|
||||
.map(this::toPayment));
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.UnnecessaryLocalBeforeReturn")
|
||||
private boolean isPendingOrSuccessful(lnrpc.Payment payment) {
|
||||
if (payment.getStatus() == FAILED) {
|
||||
return false;
|
||||
}
|
||||
if (payment.getStatus() == lnrpc.Payment.PaymentStatus.IN_FLIGHT) {
|
||||
Instant creationDate = Instant.ofEpochMilli(payment.getCreationTimeNs() / 1_000_000);
|
||||
Instant oneDayAgo = Instant.now().minus(1, ChronoUnit.DAYS);
|
||||
boolean isYoung = creationDate.isAfter(oneDayAgo);
|
||||
if (isYoung) {
|
||||
return true;
|
||||
}
|
||||
boolean allHtlcsFailed = payment.getHtlcsList().stream()
|
||||
.allMatch(htlc -> htlc.getStatus() == HTLCAttempt.HTLCStatus.FAILED);
|
||||
return !allHtlcsFailed;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<RouteHint> getRouteHints(Pubkey destination, List<lnrpc.RouteHint> routeHintsList) {
|
||||
return routeHintsList.stream()
|
||||
.filter(routeHint -> routeHint.getHopHintsCount() == 1)
|
||||
@@ -104,7 +125,7 @@ public class GrpcPayments {
|
||||
if (lndPayment.getStatus() != SUCCEEDED) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Instant timestamp = Instant.ofEpochMilli(lndPayment.getCreationTimeNs() / 1_000);
|
||||
Instant timestamp = Instant.ofEpochMilli(lndPayment.getCreationTimeNs() / 1_000_000);
|
||||
String paymentHash = lndPayment.getPaymentHash();
|
||||
return Optional.of(new Payment(
|
||||
lndPayment.getPaymentIndex(),
|
||||
|
||||
@@ -25,7 +25,9 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -41,6 +43,9 @@ import static de.cotto.lndmanagej.model.PaymentFixtures.PAYMENT_2;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_3;
|
||||
import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_4;
|
||||
import static lnrpc.HTLCAttempt.HTLCStatus.FAILED;
|
||||
import static lnrpc.Payment.PaymentStatus.IN_FLIGHT;
|
||||
import static lnrpc.Payment.PaymentStatus.SUCCEEDED;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
@@ -77,7 +82,7 @@ class GrpcPaymentsTest {
|
||||
|
||||
@Test
|
||||
void with_payments() {
|
||||
mockResponse(payment(PaymentStatus.SUCCEEDED, PAYMENT), payment(PaymentStatus.SUCCEEDED, PAYMENT_2));
|
||||
mockResponse(payment(SUCCEEDED, PAYMENT), payment(SUCCEEDED, PAYMENT_2));
|
||||
assertThat(grpcPayments.getCompletePaymentsAfter(0L)).contains(
|
||||
List.of(PAYMENT, PAYMENT_2)
|
||||
);
|
||||
@@ -91,7 +96,7 @@ class GrpcPaymentsTest {
|
||||
.setStatus(HTLCAttempt.HTLCStatus.IN_FLIGHT)
|
||||
.build();
|
||||
lnrpc.Payment payment = lnrpc.Payment.newBuilder()
|
||||
.setStatus(PaymentStatus.SUCCEEDED)
|
||||
.setStatus(SUCCEEDED)
|
||||
.addHtlcs(htlc)
|
||||
.build();
|
||||
|
||||
@@ -117,7 +122,7 @@ class GrpcPaymentsTest {
|
||||
|
||||
@Test
|
||||
void ignores_non_settled_payment() {
|
||||
mockResponse(payment(PaymentStatus.IN_FLIGHT, null));
|
||||
mockResponse(payment(IN_FLIGHT, null));
|
||||
assertThat(grpcPayments.getCompletePaymentsAfter(0L)).contains(List.of());
|
||||
}
|
||||
|
||||
@@ -156,7 +161,7 @@ class GrpcPaymentsTest {
|
||||
.setRoute(route)
|
||||
.build();
|
||||
lnrpc.Payment payment = lnrpc.Payment.newBuilder()
|
||||
.setStatus(PaymentStatus.SUCCEEDED)
|
||||
.setStatus(SUCCEEDED)
|
||||
.setPaymentIndex(PAYMENT.index())
|
||||
.setPaymentHash(PAYMENT.paymentHash())
|
||||
.setValueMsat(PAYMENT.value().milliSatoshis())
|
||||
@@ -184,7 +189,7 @@ class GrpcPaymentsTest {
|
||||
|
||||
@Test
|
||||
void with_payments() {
|
||||
mockResponse(payment(PaymentStatus.SUCCEEDED, PAYMENT), payment(PaymentStatus.SUCCEEDED, PAYMENT_2));
|
||||
mockResponse(payment(SUCCEEDED, PAYMENT), payment(SUCCEEDED, PAYMENT_2));
|
||||
assertThat(grpcPayments.getCompleteAndPendingPaymentsAfter(0L)).contains(
|
||||
List.of(Optional.of(PAYMENT), Optional.of(PAYMENT_2))
|
||||
);
|
||||
@@ -192,7 +197,7 @@ class GrpcPaymentsTest {
|
||||
|
||||
@Test
|
||||
void skips_failed_payment() {
|
||||
mockResponse(payment(PaymentStatus.FAILED, PAYMENT), payment(PaymentStatus.SUCCEEDED, PAYMENT_2));
|
||||
mockResponse(payment(PaymentStatus.FAILED, PAYMENT), payment(SUCCEEDED, PAYMENT_2));
|
||||
assertThat(grpcPayments.getCompleteAndPendingPaymentsAfter(0L)).contains(
|
||||
List.of(Optional.of(PAYMENT_2))
|
||||
);
|
||||
@@ -200,12 +205,28 @@ class GrpcPaymentsTest {
|
||||
|
||||
@Test
|
||||
void with_in_flight_payment() {
|
||||
mockResponse(payment(PaymentStatus.IN_FLIGHT, PAYMENT), payment(PaymentStatus.SUCCEEDED, PAYMENT_2));
|
||||
mockResponse(payment(IN_FLIGHT, PAYMENT), payment(SUCCEEDED, PAYMENT_2));
|
||||
assertThat(grpcPayments.getCompleteAndPendingPaymentsAfter(0L)).contains(
|
||||
List.of(Optional.empty(), Optional.of(PAYMENT_2))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void with_recent_in_flight_payment_without_pending_htlc() {
|
||||
Payment payment = paymentWithAge(Duration.ofHours(23));
|
||||
mockResponse(payment(IN_FLIGHT, payment, FAILED));
|
||||
assertThat(grpcPayments.getCompleteAndPendingPaymentsAfter(0L)).contains(
|
||||
List.of(Optional.empty())
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void skips_old_in_flight_payment_without_pending_htlc() {
|
||||
Payment payment = paymentWithAge(Duration.ofHours(24));
|
||||
mockResponse(payment(IN_FLIGHT, payment, FAILED));
|
||||
assertThat(grpcPayments.getCompleteAndPendingPaymentsAfter(0L)).contains(List.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
void starts_at_the_beginning() {
|
||||
grpcPayments.getCompleteAndPendingPaymentsAfter(ADD_INDEX_OFFSET);
|
||||
@@ -225,6 +246,17 @@ class GrpcPaymentsTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static Payment paymentWithAge(Duration age) {
|
||||
return new Payment(
|
||||
PAYMENT.index(),
|
||||
PAYMENT.paymentHash(),
|
||||
LocalDateTime.now(ZoneOffset.UTC).minus(age),
|
||||
PAYMENT.value(),
|
||||
PAYMENT.fees(),
|
||||
PAYMENT.routes()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLimit() {
|
||||
assertThat(grpcPayments.getLimit()).isEqualTo(LIMIT);
|
||||
@@ -307,6 +339,14 @@ class GrpcPaymentsTest {
|
||||
}
|
||||
|
||||
private lnrpc.Payment payment(PaymentStatus paymentStatus, @Nullable Payment payment) {
|
||||
return payment(paymentStatus, payment, HTLCAttempt.HTLCStatus.SUCCEEDED);
|
||||
}
|
||||
|
||||
private lnrpc.Payment payment(
|
||||
PaymentStatus paymentStatus,
|
||||
@Nullable Payment payment,
|
||||
HTLCAttempt.HTLCStatus htlcStatus
|
||||
) {
|
||||
if (payment == null) {
|
||||
return lnrpc.Payment.newBuilder().setStatus(paymentStatus).build();
|
||||
}
|
||||
@@ -317,7 +357,7 @@ class GrpcPaymentsTest {
|
||||
paymentRoute.firstHop().ifPresent(hop -> addHop(routeBuilder, hop));
|
||||
paymentRoute.lastHop().ifPresent(hop -> addHop(routeBuilder, hop));
|
||||
htlcBuilder.setRoute(routeBuilder.build());
|
||||
htlcBuilder.setStatus(HTLCAttempt.HTLCStatus.SUCCEEDED);
|
||||
htlcBuilder.setStatus(htlcStatus);
|
||||
htlcs.add(htlcBuilder.build());
|
||||
}
|
||||
lnrpc.Payment.Builder builder = lnrpc.Payment.newBuilder()
|
||||
@@ -326,7 +366,7 @@ class GrpcPaymentsTest {
|
||||
.setPaymentHash(payment.paymentHash())
|
||||
.setValueMsat(payment.value().milliSatoshis())
|
||||
.setFeeMsat(payment.fees().milliSatoshis())
|
||||
.setCreationTimeNs(payment.creationDateTime().toInstant(ZoneOffset.UTC).toEpochMilli() * 1_000);
|
||||
.setCreationTimeNs(payment.creationDateTime().toInstant(ZoneOffset.UTC).toEpochMilli() * 1_000_000);
|
||||
htlcs.forEach(builder::addHtlcs);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user