From 17df6e86e6b0466d97a14dfa3b820ce6cd41f72b Mon Sep 17 00:00:00 2001 From: Slyghtning Date: Mon, 11 May 2026 16:19:46 +0200 Subject: [PATCH] instantout/reservation: extend RPC state wait timeout RequestReservationFromServer blocked for defaultWaitForStateTime (15s) waiting for the FSM to reach SendPrepaymentPayment. Reaching that state requires, in order: - Wallet.DeriveNextKey (local lnd round-trip) - server's RequestReservation gRPC (network + server's own lnd invoice creation, including hold-invoice persistence) - LightningClient.DecodePaymentRequest - Store.CreateReservation 15 seconds was achievable on a fast LAN with idle servers, but under even modest load (server-side hold-invoice creation can routinely take several seconds in the wild) the timer expired and the RPC returned an error to the caller. The FSM kept running in the background and the wallet would still pay the prepay LN invoice -- so the user got an error, but their funds still moved. The next call to the same reservation_id would then fail mysteriously because the server-side state was already advanced. Bump to 60s. The right longer-term fix is to plumb the caller's gRPC context into the FSM SendEvent so cancellation actually aborts the in-flight server call instead of orphaning it; that's a larger refactor and is left as a follow-up. --- instantout/reservation/manager.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/instantout/reservation/manager.go b/instantout/reservation/manager.go index 02c3fda4..fe2952b8 100644 --- a/instantout/reservation/manager.go +++ b/instantout/reservation/manager.go @@ -16,7 +16,17 @@ import ( ) var ( - defaultWaitForStateTime = time.Second * 15 + // defaultWaitForStateTime is how long RequestReservationFromServer + // blocks waiting for the FSM to advance to SendPrepaymentPayment. + // The action that drives that transition performs a server RPC + // round-trip that itself creates an lnd hold invoice on the swap + // server side, plus an lnd DecodePaymentRequest, plus a local + // CreateReservation. Under load any one of these can take a few + // seconds, so 15s is too tight: when the RPC times out the FSM + // continues running in the background and may still pay the + // prepay invoice after the caller has been told the request + // failed. 60s gives realistic head-room. + defaultWaitForStateTime = time.Second * 60 ) // FSMSendEventReq contains the information needed to send an event to the FSM.