l402: pay challenge invoices via router's SendPaymentV2#249
l402: pay challenge invoices via router's SendPaymentV2#249DelleonMcglone wants to merge 1 commit into
Conversation
The client interceptor paid L402 challenge invoices through lndclient's LightningClient.PayInvoice, which uses lnd's legacy SendPaymentSync RPC. That RPC is deprecated in lnd and payments made through it can fail to initiate on recent lnd builds: the interceptor then times out waiting, leaving a pending token that every subsequent call tries (and fails) to resume with 'payment isn't initiated', until the token file is removed manually. Dispatch the payment through the router subserver instead (RouterClient.SendPayment -> SendPaymentV2) and consume status updates until a terminal state, mirroring the existing trackPayment flow. The router client is already part of the LndServices the interceptor holds, and the test mock already implements RouterClient.SendPayment, so the interceptor tests move from the SendPaymentChannel to the RouterSendPaymentChannel and deliver PaymentStatus updates instead of a PaymentResult. Observed in the wild running poold 0.7.1 against lnd 0.21.0-beta on testnet: InitAccount consistently failed with 'payment timed out' / 'payment isn't initiated' while lnd showed no payment attempt at all; paying the same invoice via SendPaymentV2 succeeded in about a second. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
hieblmi
left a comment
There was a problem hiding this comment.
Hi @DelleonMcglone, thanks for your contribution!
If we upgrade to github.com/lightninglabs/lndclient v0.21.0-2 we get a PayInvoice which already uses SendPaymentV2. So could we upgrade the client instead of calling it manually from aperture?
|
Thanks for taking a look! You're right — and digging into it, it's even simpler than an upgrade: the lndclient that aperture already pins (the Given that, this PR is only worth keeping if you prefer the explicit Your call — close, or trim to the explicit-call refactor? |
Problem
The L402 client interceptor pays challenge invoices through
lndclient'sLightningClient.PayInvoice, which drives lnd's legacySendPaymentSyncRPC. That RPC is deprecated in lnd, and on recent builds the payment can fail to even initiate. When that happens the failure mode is nasty:payL402Tokenstores the pending token, dispatches the payment, and times out — the operator seespayment timed out. try again to track payment.trackPayment, which fails withpayment isn't initiated(lnd has no record of the payment), forever — until the operator manually deletes the pending token file.Real-world reproduction: running
poold0.7.1 (which vendors this package) against lnd0.21.0-betaon testnet,InitAccountconsistently failed exactly this way;lncli listpayments --include_incompleteshowed zero payment attempts, confirming the send never reached the router. Paying the same L402 invoice out-of-band viaSendPaymentV2(lncli payinvoice) succeeded in ~1s and, with a hand-completed token, all subsequent auctioneer RPCs worked.Change
Dispatch the payment through the router subserver (
RouterClient.SendPayment→SendPaymentV2) and consume status updates until a terminal state, mirroring the flow the interceptor's owntrackPaymentalready uses. Notes:i.lnd.Routeris already part of theLndServicesthe interceptor holds — no new dependencies.PaymentStatus.Value/.Feeare msat, so the sat→msat conversions drop out.IN_FLIGHTetc.) are consumed and waited out;FAILEDreturns the failure reason; channel errors, the payment timeout, and parent-context cancellation keep their existing messages/hints.RouterClient.SendPayment, so the interceptor tests move fromSendPaymentChanneltoRouterSendPaymentChanneland deliverPaymentStatusupdates instead of aPaymentResult.Verification
go build ./...,go vet ./l402/...cleango test ./l402/...passes (all interceptor cases incl. pending-token resume and expired-token repay)🤖 Generated with Claude Code