Skip to content

Commit cf85e28

Browse files
committed
Introduce create_{offer,refund}_builder_using_router
Introduced two new builder functions that accept a custom `MessageRouter` as input. This gives users the flexibility to plug in their own router implementation, enabling custom logic for blinded path creation when building Offers or Refunds. It’s a step toward greater extensibility and control in how paths are constructed.
1 parent c326121 commit cf85e28

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10221,6 +10221,57 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
1022110221

1022210222
Ok(builder.into())
1022310223
}
10224+
10225+
/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
10226+
/// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer.
10227+
///
10228+
/// # Privacy
10229+
///
10230+
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the offer based on the given
10231+
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
10232+
/// privacy implications as well as those of the parameterized [`Router`], which implements
10233+
/// [`MessageRouter`].
10234+
///
10235+
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
10236+
///
10237+
/// # Limitations
10238+
///
10239+
/// Requires a direct connection to the introduction node in the responding [`InvoiceRequest`]'s
10240+
/// reply path.
10241+
///
10242+
/// # Errors
10243+
///
10244+
/// Errors if the provided [`Router`] is unable to create a blinded path for the offer.
10245+
///
10246+
/// [`Offer`]: crate::offers::offer::Offer
10247+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
10248+
pub fn create_offer_builder_using_router<ME: MessageRouter>(
10249+
&$self,
10250+
router: ME,
10251+
) -> Result<$builder, Bolt12SemanticError> {
10252+
let node_id = $self.get_our_node_id();
10253+
let expanded_key = &$self.inbound_payment_key;
10254+
let entropy = &*$self.entropy_source;
10255+
let secp_ctx = &$self.secp_ctx;
10256+
10257+
let nonce = Nonce::from_entropy_source(entropy);
10258+
let context = MessageContext::Offers(OffersContext::InvoiceRequest { nonce });
10259+
10260+
let peers = $self.get_peers_for_blinded_path();
10261+
10262+
let path = router.create_blinded_paths(node_id, context, peers, secp_ctx)
10263+
.map_err(|_| Bolt12SemanticError::MissingPaths)?
10264+
.into_iter().next();
10265+
10266+
let mut builder = OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx)
10267+
.chain_hash($self.chain_hash);
10268+
10269+
if let Some(path) = path {
10270+
builder = builder.path(path)
10271+
}
10272+
10273+
Ok(builder.into())
10274+
}
1022410275
} }
1022510276

1022610277
macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
@@ -10302,6 +10353,91 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1030210353

1030310354
Ok(builder.into())
1030410355
}
10356+
10357+
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
10358+
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
10359+
///
10360+
/// # Payment
10361+
///
10362+
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
10363+
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
10364+
///
10365+
/// The builder will have the provided expiration set. Any changes to the expiration on the
10366+
/// returned builder will not be honored by [`ChannelManager`]. For non-`std`, the highest seen
10367+
/// block time minus two hours is used for the current time when determining if the refund has
10368+
/// expired.
10369+
///
10370+
/// To revoke the refund, use [`ChannelManager::abandon_payment`] prior to receiving the
10371+
/// invoice. If abandoned, or an invoice isn't received before expiration, the payment will fail
10372+
/// with an [`Event::PaymentFailed`].
10373+
///
10374+
/// If `max_total_routing_fee_msat` is not specified, The default from
10375+
/// [`RouteParameters::from_payment_params_and_value`] is applied.
10376+
///
10377+
/// # Privacy
10378+
///
10379+
/// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
10380+
/// Users can implement a custom [`MessageRouter`] to define properties of the
10381+
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
10382+
///
10383+
/// Also, uses a derived payer id in the refund for payer privacy.
10384+
///
10385+
/// # Limitations
10386+
///
10387+
/// Requires a direct connection to an introduction node in the responding
10388+
/// [`Bolt12Invoice::payment_paths`].
10389+
///
10390+
/// # Errors
10391+
///
10392+
/// Errors if:
10393+
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
10394+
/// - `amount_msats` is invalid, or
10395+
/// - the provided [`Router`] is unable to create a blinded path for the refund.
10396+
///
10397+
/// [`Refund`]: crate::offers::refund::Refund
10398+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
10399+
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
10400+
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
10401+
pub fn create_refund_builder_using_router<ME: MessageRouter>(
10402+
&$self, router: ME, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
10403+
retry_strategy: Retry, route_params_config: RouteParametersConfig
10404+
) -> Result<$builder, Bolt12SemanticError> {
10405+
let node_id = $self.get_our_node_id();
10406+
let expanded_key = &$self.inbound_payment_key;
10407+
let entropy = &*$self.entropy_source;
10408+
let secp_ctx = &$self.secp_ctx;
10409+
10410+
let nonce = Nonce::from_entropy_source(entropy);
10411+
let context = MessageContext::Offers(
10412+
OffersContext::OutboundPayment { payment_id, nonce, hmac: None }
10413+
);
10414+
10415+
let peers = $self.get_peers_for_blinded_path();
10416+
let path = router.create_blinded_paths(node_id, context, peers, secp_ctx)
10417+
.map_err(|_| Bolt12SemanticError::MissingPaths)?
10418+
.into_iter().next();
10419+
10420+
let mut builder = RefundBuilder::deriving_signing_pubkey(
10421+
node_id, expanded_key, nonce, secp_ctx, amount_msats, payment_id
10422+
)?
10423+
.chain_hash($self.chain_hash)
10424+
.absolute_expiry(absolute_expiry);
10425+
10426+
if let Some(path) = path {
10427+
builder = builder.path(path)
10428+
}
10429+
10430+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
10431+
10432+
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
10433+
$self.pending_outbound_payments
10434+
.add_new_awaiting_invoice(
10435+
payment_id, expiration, retry_strategy, route_params_config, None,
10436+
)
10437+
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
10438+
10439+
Ok(builder.into())
10440+
}
1030510441
} }
1030610442

1030710443
/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent

0 commit comments

Comments
 (0)