Skip to content

Introduce Bolt12 Recurrence to LDK Node - #1119

Closed
shaavan wants to merge 9 commits into
lightningdevkit:mainfrom
shaavan:node-recurrence
Closed

shaavan wants to merge 9 commits into
lightningdevkit:mainfrom
shaavan:node-recurrence

Conversation

@shaavan

@shaavan shaavan commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

Overview

This PR adds recurring BOLT 12 payments to LDK Node, based on lightning/bolts#1240 and the recurrence support in rust-lightning #4882.

rust-lightning handles the protocol: recurrence fields in offers, invoice requests, and invoices; message validation; payment-window calculations; stable payer identity; and requests to pay or cancel a recurrence.

LDK Node manages the payer’s ongoing workflow. It persists recurrence state, links individual payments to a recurrence, updates that state as payments succeed or fail, resumes after a restart, schedules and retries payments, and provides APIs for applications to manage recurrences.

Scope

  • Persistent state: Store the recurrence identity, original offer, payer configuration, payment attempts, and lifecycle state.
  • Initial payment: Validate the offer, amount, quantity, and starting period. Persist the recurrence and first attempt before requesting the first invoice.
  • Payment progression: Advance to the next period after a successful payment. Record failures without advancing, and allow applications to pay the next eligible period within its payment window.
  • Recovery and automatic payments: Reconcile stored attempts with LDK after a restart, schedule future payments when enabled, and retry failures within the payment window without creating overlapping attempts.
  • Management APIs: Let applications inspect and configure recurrences, inspect payment windows, pay the next period, cancel a recurrence, and remove terminal records.
  • Events and bindings: Emit lifecycle events, expose recurrence management through UniFFI, and document the behavior of identifiers, attempts, retries, and cancellation.
  • Tests: Cover serialization and storage compatibility, payment outcomes, window boundaries, restart recovery, cancellation, event replay, and binding-facing types.

Development approach

I’ll develop the implementation incrementally in this PR. If it becomes too large to review effectively, I’ll split out independently reviewable components into separate PRs and link them here.

Update LDK Node's Cargo.toml to use recurrence-aware versions of
rust-lightning and bitcoin-payment-instructions.

This makes the recurrence APIs available for implementing recurrence
support in subsequent commits.

Co-authored-by: GLaDOS
@ldk-reviews-bot

Copy link
Copy Markdown

👋 Hi! I see this is a draft PR.
I'll wait to assign reviewers until you mark it as ready for review.
Just convert it out of draft status when you're ready for review!

@shaavan
shaavan force-pushed the node-recurrence branch 2 times, most recently from ea3bf1e to bd797ab Compare October 5, 2026 10:33
Recurring offers outlive individual payment attempts and node processes.
To resume a recurrence safely after restart, the node must retain its
original offer terms, lifecycle state, payment progress, and payee-provided
opaque state.

Add RecurrenceDetails and RecurrenceStatus with TLV serialization and
RecurrenceId-based persistence. Load recurrence records during node
construction under a dedicated "recurrences" namespace, retaining all
entries for the lifetime of each recurrence.

Thread RecurrenceStore through Node, EventHandler, and Bolt12Payment to
establish the persistence foundation for recurrence scheduling and payment
handling. Recurring payment execution remains disabled in this commit.

Co-Authored-By: GLaDOS
@shaavan
shaavan force-pushed the node-recurrence branch 2 times, most recently from cf19305 to 09ff237 Compare October 9, 2026 15:26
Add an API to start a recurring payment by submitting the initial invoice
request. Persist the recurrence state so subsequent payments can continue
the same recurring relationship.

Co-Authored-By: GLaDOS
On successful completion of a payment that corresponds to a recurrence
we introduce logic to update the details after validating the invoice
parameters.

Co-authored-by: GLaDOS
A terminal payment failure must release the recurrence's active attempt
while retaining its payment ID. Otherwise, the recurrence continues to
appear busy after the attempt has ended.

Update only the unique recurrence whose active payment ID matches the
failed payment. Replayed failures leave already-handled or newer attempts
unchanged. Request event replay when persistence fails.

Co-Authored-By: GLaDOS
Allow callers to submit subsequent payments using the stored recurring
offer and payment parameters. Require an active recurrence, a successful
initial payment, no active attempt and an open payment window.

Validate the next period against the inclusive recurrence limit. After
submission, persist the payment record and associate its ID with the
recurrence for event handling.

Return the payment ID on successful submission and an error on synchronous
failure. Submission failures other than duplicate payment IDs are recorded
as failed payments, while the recurrence attempt is marked active.

Co-Authored-By: GLaDOS
Abandon active payments and persist the cancelled recurrence status.
Queue a cancellation request for the payee after a successful payment.

Co-Authored-By: GLaDOS
Failed initial payments cannot be retried through pay_next_recurrence,
which requires the first payment to have succeeded.

Add retry_recurrence for active recurrences with a failed attempt.
Reuse payment submission without advancing the recurrence period.
Require an open payment window unless the first payment has not yet
established the basetime.

Co-Authored-By: GLaDOS
Recurrences need to progress without callers polling payment windows
or manually retrying failed attempts.

Scan active recurrences every 30 seconds to retry failed payments,
update missed/completed status, and submit future payments when
automatic payment is enabled.

Reserve attempts before submission and serialize cancellation to prevent
concurrent manual and scheduled payments from paying the same period.
Keep uncertain attempts active to avoid duplicate payments.

Co-Authored-By: GLaDOS
@shaavan

shaavan commented Oct 26, 2026

Copy link
Copy Markdown
Member Author

Superceded by #1205 and #1207

@shaavan shaavan closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants