Skip to content

Conversation

shaavan
Copy link
Owner

@shaavan shaavan commented Jul 26, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced support for BOLT 12 invoice and refund handling, with improved processing of multiple invoice request variants.
    • More flexible and robust invoice builder creation, supporting both derived and explicit signing key strategies.
  • Bug Fixes

    • Improved error handling and response construction for invoice requests.
  • Refactor

    • Streamlined and modularized invoice and refund logic for better maintainability and clarity.
    • Updated internal handling of signing keys and invoice request verification.
  • Tests

    • Updated tests to explicitly handle new invoice request verification outcomes and accessor methods.

shaavan added 6 commits July 26, 2025 18:24
In the upcoming commits, we will be phasing the current style of
VerifiedInvoiceRequest, in favour of newer version.
To keep the changes modular, and clean we rename the current
VerifiedInvoiceRequest to VerifiedInvoiceRequestLegacy.
In the following commits we will introduce `fields` function
for other types as well, so to keep code DRY we convert the
function to a macro.
This commit reintroduces `VerifiedInvoiceRequest`, now parameterized by
`SigningPubkeyStrategy`.

The key motivation is to restrict which functions can be called on a
`VerifiedInvoiceRequest` based on its strategy type. This enables
compile-time guarantees — ensuring that an incorrect `InvoiceBuilder`
cannot be constructed for a given request, and misuses are caught early.
This commit replaces the legacy `VerifiedInvoiceRequestLegacy`
with the new `VerifiedInvoiceRequestEnum` type in the codebase.
This change improves type safety and architectural clarity
by introducing dedicated `InvoiceBuilder` methods tied to
each variant of `VerifiedInvoiceRequestEnum`.

With this change, users are now required to match on the
enum variant before calling the corresponding builder method.
This pushes the responsibility of selecting the correct
builder to the user and ensures that invalid builder
usage is caught at compile time, rather than relying
on runtime checks.

The signing logic has also been moved from the builder
to the `ChannelManager`. This shift simplifies the
builder's role and aligns it with the rest of the API,
where builder methods return a configurable object that
can be extended before signing. The result is a more
consistent and predictable interface that separates
concerns cleanly and makes future maintenance easier.
To ensure correct Bolt12 payment flow behavior, the `amount_msats`
used for generating the `payment_hash`, `payment_secret`,
and payment path must remain consistent. Previously, these steps
could inadvertently diverge due to separate sources of `amount_msats`.

This commit refactors the interface to use a `get_payment_info` closure,
which captures the required variables and provides a single source of
truth for both payment info (payment_hash, payment_secret) and path
generation. This ensures consistency and eliminates subtle bugs
that could arise from mismatched amounts across the flow.
Copy link

coderabbitai bot commented Jul 26, 2025

Walkthrough

This set of changes refactors and extends the BOLT 12 invoice and refund handling across the Lightning Network codebase. It introduces a generic strategy for signing keys in verified invoice requests, adds a new enum to distinguish between derived and explicit signing key types, and updates invoice creation, processing, and test logic to use these new abstractions. The control flow for handling invoice requests is modularized, and error handling is improved, with explicit handling of different verification outcomes throughout the code and tests.

Changes

File(s) Change Summary
lightning/src/ln/channelmanager.rs Refactored invoice/refund creation to use closure-based inbound payment creation and handle VerifiedInvoiceRequestEnum variants; updated method signatures and control flow for invoice request processing.
lightning/src/ln/offers_tests.rs Updated test to handle VerifiedInvoiceRequestEnum explicitly, matching on variants to ensure only requests with keys are processed.
lightning/src/offers/flow.rs Refactored invoice builder creation logic to use key-type-specific methods, unified payment info retrieval via callback, and modularized error handling; updated enum and method signatures.
lightning/src/offers/invoice.rs Updated tests to handle VerifiedInvoiceRequestEnum by matching on variants, improving clarity in verification outcome handling.
lightning/src/offers/invoice_request.rs Made VerifiedInvoiceRequest generic over signing key strategy, introduced VerifiedInvoiceRequestEnum, refactored verification methods to return enum, added accessors, and updated macros and method implementations for new types.
lightning/src/offers/offer.rs Updated test assertions to use the new offer_id() accessor method instead of direct field access.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ChannelManager
    participant OffersFlow
    participant InvoiceBuilder

    User->>ChannelManager: Send InvoiceRequest
    ChannelManager->>OffersFlow: Verify InvoiceRequest
    OffersFlow-->>ChannelManager: VerifiedInvoiceRequestEnum (WithKeys/WithoutKeys)
    ChannelManager->>OffersFlow: Create InvoiceBuilder (variant-specific)
    OffersFlow->>InvoiceBuilder: Build Invoice (with payment info closure)
    InvoiceBuilder-->>OffersFlow: Unsigned Invoice
    OffersFlow-->>ChannelManager: (InvoiceBuilder, Context) or Error
    ChannelManager->>User: Send Invoice or InvoiceError
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

In fields of code where invoices bloom,
A rabbit hops and sweeps the room.
With keys derived or keys explicit,
Each enum variant is now explicit!
Builders build and tests are keen,
Lightning flows, robust and clean.
🐇✨ Hooray for tidy BOLT 12 scenes!

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ir-check-review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
lightning/src/offers/flow.rs (1)

991-1055: Consider reducing code duplication between the two invoice builder methods.

While the implementation is correct, there's significant duplication between create_invoice_builder_from_invoice_request_with_keys and create_invoice_builder_from_invoice_request_without_keys. The only differences are:

  1. The type parameter constraint
  2. The response method called (respond_using_derived_keys vs respond_with)

Consider extracting the common logic into a shared helper method.

Here's a suggested refactor to reduce duplication:

fn create_invoice_builder_common<'a, ES: Deref, R: Deref, F>(
    &'a self, router: &R, entropy_source: ES,
    amount_msats: u64, offer_id: OfferId,
    invoice_request_fields: &InvoiceRequestFields,
    usable_channels: Vec<ChannelDetails>,
    get_payment_info: F,
) -> Result<(Vec<BlindedPaymentPath>, PaymentHash, MessageContext), Bolt12SemanticError>
where
    ES::Target: EntropySource,
    R::Target: Router,
    F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
{
    let entropy = &*entropy_source;
    let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
    
    let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
    
    let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
        offer_id,
        invoice_request: invoice_request_fields.clone(),
    });
    
    let payment_paths = self
        .create_blinded_payment_paths(
            router,
            entropy,
            usable_channels,
            Some(amount_msats),
            payment_secret,
            context,
            relative_expiry,
        )
        .map_err(|_| Bolt12SemanticError::MissingPaths)?;
    
    let message_context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
    
    Ok((payment_paths, payment_hash, message_context))
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ceb625 and ff02fd5.

📒 Files selected for processing (6)
  • lightning/src/ln/channelmanager.rs (4 hunks)
  • lightning/src/ln/offers_tests.rs (2 hunks)
  • lightning/src/offers/flow.rs (8 hunks)
  • lightning/src/offers/invoice.rs (3 hunks)
  • lightning/src/offers/invoice_request.rs (10 hunks)
  • lightning/src/offers/offer.rs (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
lightning/src/offers/offer.rs (3)
lightning/src/offers/invoice_request.rs (1)
  • offer_id (638-643)
lightning/src/offers/invoice.rs (1)
  • offer_id (982-984)
lightning/src/offers/static_invoice.rs (1)
  • offer_id (415-417)
lightning/src/offers/invoice.rs (2)
lightning/src/offers/static_invoice.rs (2)
  • invoice (801-827)
  • payment_paths (534-536)
lightning/src/offers/test_utils.rs (3)
  • payment_paths (75-110)
  • payment_hash (112-114)
  • now (116-120)
lightning/src/ln/channelmanager.rs (3)
lightning/src/offers/refund.rs (8)
  • refund (1488-1488)
  • refund (1510-1510)
  • refund (1532-1532)
  • refund (1567-1567)
  • refund (1621-1621)
  • refund (1641-1641)
  • amount_msats (533-535)
  • amount_msats (750-752)
lightning/src/offers/invoice_request.rs (2)
  • amount_msats (1121-1132)
  • amount_msats (1175-1177)
lightning/src/offers/invoice.rs (2)
  • amount_msats (1255-1257)
  • relative_expiry (1238-1240)
lightning/src/offers/flow.rs (3)
lightning/src/offers/invoice_request.rs (4)
  • sign (473-475)
  • amount_msats (1121-1132)
  • amount_msats (1175-1177)
  • from (428-437)
lightning/src/offers/invoice.rs (7)
  • sign (619-621)
  • payment_hash (1251-1253)
  • amount_msats (1255-1257)
  • relative_expiry (1238-1240)
  • payment_paths (1230-1232)
  • from (560-568)
  • from (575-583)
lightning/src/sign/mod.rs (1)
  • from (1084-1086)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: semver-checks
  • GitHub Check: linting
  • GitHub Check: build (windows-latest, stable)
  • GitHub Check: build-tx-sync (ubuntu-latest, 1.75.0)
  • GitHub Check: build-tx-sync (ubuntu-latest, stable)
  • GitHub Check: build-tx-sync (ubuntu-latest, beta)
  • GitHub Check: benchmark
  • GitHub Check: build-tx-sync (ubuntu-latest, 1.75.0)
  • GitHub Check: incremental-mutants
  • GitHub Check: build-tx-sync (macos-latest, beta)
  • GitHub Check: build-tx-sync (macos-latest, 1.75.0)
  • GitHub Check: benchmark
  • GitHub Check: build-tx-sync (ubuntu-latest, stable)
  • GitHub Check: build-tx-sync (ubuntu-latest, beta)
  • GitHub Check: build (windows-latest, beta)
  • GitHub Check: build (macos-latest, beta)
  • GitHub Check: build (macos-latest, 1.63.0)
  • GitHub Check: build (macos-latest, stable)
  • GitHub Check: build (windows-latest, stable)
  • GitHub Check: semver-checks
🔇 Additional comments (27)
lightning/src/offers/offer.rs (2)

1485-1485: Accessor usage aligns with new encapsulation

Replacing direct field access with the offer_id() accessor keeps the test in sync with the refactor that hides the field behind the enum. Looks good.


1566-1566: Consistent accessor adoption

Same update here ensures consistency across the test suite after the VerifiedInvoiceRequestEnum change. No issues spotted.

lightning/src/ln/offers_tests.rs (2)

60-60: LGTM: Import addition aligns with refactoring.

The import of VerifiedInvoiceRequestEnum is necessary to support the updated verification logic in the test.


2282-2294: LGTM: Test correctly adapted to new verification enum.

The test has been properly updated to handle the new VerifiedInvoiceRequestEnum that distinguishes between invoice requests verified with derived keys vs explicit keys. The logic correctly:

  1. Matches on the enum variants to handle different verification outcomes
  2. Processes the WithKeys variant using respond_using_derived_keys_no_std
  3. Panics appropriately for WithoutKeys since this test expects derived key verification

This change aligns with the broader refactoring mentioned in the PR summary while maintaining the test's original intent of verifying payment failure with unknown required features.

lightning/src/offers/invoice.rs (3)

1822-1822: LGTM: Clean import addition

The import of VerifiedInvoiceRequestEnum is properly added and necessary for the updated test cases that follow.


1239-1258: LGTM: Proper pattern matching implementation

The explicit pattern matching on VerifiedInvoiceRequestEnum variants correctly handles the refactored verification flow:

  • WithKeys variant proceeds with derived key response as expected
  • WithoutKeys variant appropriately panics since this test expects keys
  • Error handling for invoice building is properly implemented

This change aligns well with the broader refactor to distinguish between requests with derived signing keys vs. those requiring explicit keys.


1277-1285: LGTM: Correct handling of opposite test scenario

The pattern matching correctly handles the complementary test case:

  • WithKeys variant appropriately panics since this test expects no keys
  • WithoutKeys variant continues silently as expected
  • The logic properly validates the inverse scenario from the previous test

This ensures comprehensive coverage of both verification outcomes in the new enum-based flow.

lightning/src/ln/channelmanager.rs (4)

91-99: Import changes look good

The new imports for UnsignedBolt12Invoice and VerifiedInvoiceRequestEnum are properly added and align with the refactoring described in the PR objectives.


7197-7202: Proper use of new offer_id() accessor method

The change correctly uses the new offer_id() accessor method on the verified invoice request, which aligns with the refactoring pattern introduced across the codebase.


11997-12018: Well-structured refactoring with improved payment handling

The closure-based approach for inbound payment creation is cleaner and more flexible. Good addition of .allow_mpp() to enable multi-path payments, which improves payment reliability.


14089-14168: Comprehensive handling of verified invoice request variants

The implementation correctly handles both WithKeys and WithoutKeys variants with appropriate building and signing strategies. The error handling is consistent and properly returns InvoiceError messages.

Note the conditional compilation at line 14141-14142:

#[cfg(c_bindings)]
let mut invoice = invoice;

Please verify that this mutation pattern for C bindings is intentional and documented, as it creates a mutable binding only when compiling for C bindings.

lightning/src/offers/invoice_request.rs (10)

74-74: Import additions align with the new signing strategy pattern.

The import of DerivedSigningPubkey, ExplicitSigningPubkey, and SigningPubkeyStrategy is necessary for the refactoring that introduces generic signing key strategies.


596-617: Well-designed generic refactoring of VerifiedInvoiceRequest.

The introduction of the generic parameter S: SigningPubkeyStrategy and the updated documentation clearly explain the different response methods based on the signing key type. This provides better type safety and clearer API semantics.


619-644: Clean enum design for handling different signing key scenarios.

The VerifiedInvoiceRequestEnum effectively encapsulates the two possible states of a verified invoice request. The helper methods inner() and offer_id() provide ergonomic access to common fields across both variants.


776-777: Documentation correctly updated to reference the new enum.

The documentation now appropriately references VerifiedInvoiceRequestEnum methods, reflecting the new API design.


832-856: Verification methods correctly adapted to return the new enum.

The verify_using_metadata method now properly returns VerifiedInvoiceRequestEnum with the appropriate variant based on whether signing keys could be derived. The pattern matching logic is clear and correct.


875-901: Consistent implementation of recipient data verification.

The verify_using_recipient_data method follows the same pattern as verify_using_metadata, maintaining consistency in the API design.


1016-1045: Well-designed macro for unified field access.

The fields_accessor macro effectively reduces code duplication by providing a consistent way to extract InvoiceRequestFields across different types. The payer note truncation is handled correctly using the string_truncate_safe function.


1047-1089: Consistent implementations across signing key strategies.

The implementations for VerifiedInvoiceRequest<DerivedSigningPubkey>, VerifiedInvoiceRequest<ExplicitSigningPubkey>, and VerifiedInvoiceRequestEnum are well-structured and consistent. Each provides the appropriate response methods for its signing key strategy.


1003-1003: Correct access to derived signing keys.

The code correctly accesses the inner Keypair from the DerivedSigningPubkey tuple struct.


3083-3083: Test correctly updated to use the new API.

The test now uses the offer_id() method from the verified invoice request enum, validating the refactored code paths.

lightning/src/offers/flow.rs (6)

39-44: LGTM! Import changes align with the new architecture.

The addition of DEFAULT_RELATIVE_EXPIRY and VerifiedInvoiceRequestEnum imports properly supports the refactored invoice request handling logic.


405-408: Good architectural improvement using the new enum.

The change from a generic VerifiedInvoiceRequest to VerifiedInvoiceRequestEnum improves type safety by explicitly distinguishing between invoice requests with derived vs explicit signing keys.


869-889: Excellent refactoring to use callback pattern for payment info retrieval.

The change to use a callback get_payment_info instead of direct parameters improves flexibility and allows callers to defer payment creation until the exact moment it's needed. The error propagation is properly handled.


925-989: Well-implemented method for handling invoice requests with derived keys.

The implementation correctly:

  • Extracts amount from the invoice request
  • Uses the callback pattern consistently
  • Creates appropriate payment context with offer_id and invoice_request fields
  • Handles both std and no_std environments
  • Returns both the builder and message context for flexible response handling

1081-1082: Documentation formatting improvement.

Good practice using the full path for cross-references in documentation.


1127-1128: Consistent documentation formatting.

Maintains consistency with the earlier documentation change by using the full path.

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.

1 participant