From fe1ee22f42d1912970485c5fa670dec600094a60 Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Mon, 15 Jan 2024 09:38:14 +0100 Subject: [PATCH] wait for 100th attempt to succeed --- .../pickhardtpayments/PaymentLoop.java | 16 +++++++++------ .../pickhardtpayments/PaymentLoopTest.java | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoop.java b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoop.java index 42b56ad2..c22c3054 100644 --- a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoop.java +++ b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoop.java @@ -99,13 +99,17 @@ public Instance( private void start() { int loopIterationCounter = 0; int failureCounter = 0; - while (shouldContinue(loopIterationCounter)) { + while (shouldContinue()) { loopIterationCounter++; Coins residualAmount = totalAmountToSend.subtract(inFlight); if (Coins.NONE.equals(residualAmount)) { paymentStatus.info(TIMEOUT_MESSAGE); return; } + if (shouldAbort(loopIterationCounter)) { + paymentStatus.failed("Failing after " + MAX_NUMBER_OF_LOOPS + " loop iterations."); + return; + } addLoopIterationInfo(loopIterationCounter, residualAmount); MultiPathPayment multiPathPayment = multiPathPaymentSplitter.getMultiPathPaymentTo( destination, @@ -166,11 +170,7 @@ private void addLoopIterationInfo(int loopCounter, Coins residualAmount) { ); } - private boolean shouldContinue(int loopIterationCounter) { - if (loopIterationCounter >= MAX_NUMBER_OF_LOOPS) { - paymentStatus.failed("Failing after " + MAX_NUMBER_OF_LOOPS + " loop iterations."); - return false; - } + private boolean shouldContinue() { updateInformation(); if (!paymentStatus.isPending()) { return false; @@ -183,6 +183,10 @@ private boolean shouldContinue(int loopIterationCounter) { return paymentStatus.isPending(); } + private boolean shouldAbort(int loopIterationCounter) { + return paymentStatus.isPending() && loopIterationCounter > MAX_NUMBER_OF_LOOPS; + } + private void updateInformation() { inFlight = multiPathPaymentObserver.getInFlight(paymentHash); if (multiPathPaymentObserver.isSettled(paymentHash)) { diff --git a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoopTest.java b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoopTest.java index 8ffaf942..bf6949c8 100644 --- a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoopTest.java +++ b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/PaymentLoopTest.java @@ -20,6 +20,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.OngoingStubbing; import java.util.LinkedHashMap; import java.util.Map; @@ -124,6 +125,25 @@ void fails_after_one_hundred_loop_iterations() { verify(grpcSendToRoute).forceFailureForPayment(DECODED_PAYMENT_REQUEST); } + @Test + void waits_for_last_iteration_to_succeed() { + when(multiPathPaymentSplitter.getMultiPathPaymentTo(any(), any(), any(), anyInt())) + .thenReturn(MULTI_PATH_PAYMENT); + OngoingStubbing stubbing = when(multiPathPaymentObserver.isSettled(PAYMENT_HASH)); + for (int i = 0; i < 100; i++) { + stubbing = stubbing.thenReturn(false); + } + stubbing.thenReturn(true); + paymentLoop.start(DECODED_PAYMENT_REQUEST, PAYMENT_OPTIONS, paymentStatus); + + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(paymentStatus.isSuccess()).isTrue(); + softly.assertThat(readAll(paymentStatus)).map(InstantWithString::string) + .doesNotContain("Failing after 100 loop iterations."); + softly.assertAll(); + verify(multiPathPaymentSplitter, times(100)).getMultiPathPaymentTo(any(), any(), any(), anyInt()); + } + @Test void cancels_invoice_from_own_node() { when(grpcGetInfo.getPubkey()).thenReturn(DECODED_PAYMENT_REQUEST.destination());