Skip to content

Commit 594bb95

Browse files
committed
Update create_refund_builder to use create_blinded_paths
This change mirrors the previous update to `create_offer_builder`, applying the **“One `MessageRouter`, one `BlindedPath` type”** principle to refund creation. Now, `create_refund_builder` uses the `create_blinded_paths` method of the `MessageRouter` associated with the `ChannelManager` or `OffersMessageFlow`. For non-default path behavior, users can call `create_refund_builder_using_router` and pass a custom `MessageRouter`. See previous commit for detailed reasoning.
1 parent 9b29554 commit 594bb95

File tree

2 files changed

+189
-34
lines changed

2 files changed

+189
-34
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10937,10 +10937,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1093710937
///
1093810938
/// # Privacy
1093910939
///
10940-
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
10941-
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
10942-
/// privacy implications as well as those of the parameterized [`Router`], which implements
10943-
/// [`MessageRouter`].
10940+
/// Uses the [`ChannelManager`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`]
10941+
/// for the offer. See those docs for privacy implications.
1094410942
///
1094510943
/// Also, uses a derived payer id in the refund for payer privacy.
1094610944
///
@@ -10978,6 +10976,77 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1097810976

1097910977
Ok(builder.into())
1098010978
}
10979+
10980+
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
10981+
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
10982+
///
10983+
/// # Payment
10984+
///
10985+
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
10986+
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
10987+
///
10988+
/// The builder will have the provided expiration set. Any changes to the expiration on the
10989+
/// returned builder will not be honored by [`ChannelManager`]. For non-`std`, the highest seen
10990+
/// block time minus two hours is used for the current time when determining if the refund has
10991+
/// expired.
10992+
///
10993+
/// To revoke the refund, use [`ChannelManager::abandon_payment`] prior to receiving the
10994+
/// invoice. If abandoned, or an invoice isn't received before expiration, the payment will fail
10995+
/// with an [`Event::PaymentFailed`].
10996+
///
10997+
/// If `max_total_routing_fee_msat` is not specified, The default from
10998+
/// [`RouteParameters::from_payment_params_and_value`] is applied.
10999+
///
11000+
/// # Privacy
11001+
///
11002+
/// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
11003+
/// Users can implement a custom [`MessageRouter`] to define properties of the
11004+
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
11005+
///
11006+
/// Also, uses a derived payer id in the refund for payer privacy.
11007+
///
11008+
/// # Limitations
11009+
///
11010+
/// Requires a direct connection to an introduction node in the responding
11011+
/// [`Bolt12Invoice::payment_paths`].
11012+
///
11013+
/// # Errors
11014+
///
11015+
/// Errors if:
11016+
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
11017+
/// - `amount_msats` is invalid, or
11018+
/// - the provided [`MessageRouter`] is unable to create a blinded path for the refund.
11019+
///
11020+
/// [`Refund`]: crate::offers::refund::Refund
11021+
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
11022+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
11023+
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
11024+
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
11025+
pub fn create_refund_builder_using_router<ME: Deref>(
11026+
&$self, router: ME, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
11027+
retry_strategy: Retry, route_params_config: RouteParametersConfig
11028+
) -> Result<$builder, Bolt12SemanticError>
11029+
where
11030+
ME::Target: MessageRouter,
11031+
{
11032+
let entropy = &*$self.entropy_source;
11033+
11034+
let builder = $self.flow.create_refund_builder_using_router(
11035+
router, entropy, amount_msats, absolute_expiry,
11036+
payment_id, $self.get_peers_for_blinded_path()
11037+
)?;
11038+
11039+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
11040+
11041+
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
11042+
$self.pending_outbound_payments
11043+
.add_new_awaiting_invoice(
11044+
payment_id, expiration, retry_strategy, route_params_config, None,
11045+
)
11046+
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
11047+
11048+
Ok(builder.into())
11049+
}
1098111050
} }
1098211051

1098311052
impl<

lightning/src/offers/flow.rs

Lines changed: 116 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -572,28 +572,70 @@ where
572572
})
573573
}
574574

575+
fn create_refund_builder_intern<PF, ES: Deref>(
576+
&self, make_paths: PF, entropy_source: ES, amount_msats: u64, absolute_expiry: Duration,
577+
payment_id: PaymentId,
578+
) -> Result<RefundBuilder<secp256k1::All>, Bolt12SemanticError>
579+
where
580+
PF: FnOnce(
581+
PublicKey,
582+
MessageContext,
583+
&secp256k1::Secp256k1<secp256k1::All>,
584+
) -> Result<Vec<BlindedMessagePath>, Bolt12SemanticError>,
585+
ES::Target: EntropySource,
586+
{
587+
let node_id = self.get_our_node_id();
588+
let expanded_key = &self.inbound_payment_key;
589+
let entropy = &*entropy_source;
590+
let secp_ctx = &self.secp_ctx;
591+
592+
let nonce = Nonce::from_entropy_source(entropy);
593+
let context = MessageContext::Offers(OffersContext::OutboundPayment {
594+
payment_id,
595+
nonce,
596+
hmac: None,
597+
});
598+
599+
// Create the base builder with common properties
600+
let mut builder = RefundBuilder::deriving_signing_pubkey(
601+
node_id,
602+
expanded_key,
603+
nonce,
604+
secp_ctx,
605+
amount_msats,
606+
payment_id,
607+
)?
608+
.chain_hash(self.chain_hash)
609+
.absolute_expiry(absolute_expiry);
610+
611+
for path in make_paths(node_id, context, secp_ctx)? {
612+
builder = builder.path(path);
613+
}
614+
615+
Ok(builder.into())
616+
}
617+
575618
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
576619
/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
577620
/// can be verified using [`Self::verify_bolt12_invoice`].
578621
///
622+
/// # Privacy
623+
///
624+
/// Uses the [`OffersMessageFlow`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`]
625+
/// for the offer. See those docs for privacy implications.
626+
///
579627
/// The builder will have the provided expiration set. Any changes to the expiration on the
580628
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
581629
/// block time minus two hours is used for the current time when determining if the refund has
582630
/// expired.
583631
///
584-
/// To refund can be revoked by the user prior to receiving the invoice.
632+
/// The refund can be revoked by the user prior to receiving the invoice.
585633
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
586634
/// with an [`Event::PaymentFailed`].
587635
///
588636
/// If `max_total_routing_fee_msat` is not specified, the default from
589637
/// [`RouteParameters::from_payment_params_and_value`] is applied.
590638
///
591-
/// # Privacy
592-
///
593-
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
594-
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
595-
/// privacy implications.
596-
///
597639
/// Also uses a derived payer id in the refund for payer privacy.
598640
///
599641
/// # Errors
@@ -612,32 +654,76 @@ where
612654
where
613655
ES::Target: EntropySource,
614656
{
615-
let node_id = self.get_our_node_id();
616-
let expanded_key = &self.inbound_payment_key;
617-
let entropy = &*entropy_source;
618-
let secp_ctx = &self.secp_ctx;
619-
620-
let nonce = Nonce::from_entropy_source(entropy);
621-
let context = OffersContext::OutboundPayment { payment_id, nonce, hmac: None };
622-
623-
let path = self
624-
.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry), peers)
625-
.and_then(|paths| paths.into_iter().next().ok_or(()))
626-
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
627-
628-
let builder = RefundBuilder::deriving_signing_pubkey(
629-
node_id,
630-
expanded_key,
631-
nonce,
632-
secp_ctx,
657+
self.create_refund_builder_intern(
658+
|_, context, _| {
659+
self.create_blinded_paths(peers, context)
660+
.map(|paths| paths.into_iter().take(1).collect())
661+
.map_err(|_| Bolt12SemanticError::MissingPaths)
662+
},
663+
&*entropy_source,
633664
amount_msats,
665+
absolute_expiry,
634666
payment_id,
635-
)?
636-
.chain_hash(self.chain_hash)
637-
.absolute_expiry(absolute_expiry)
638-
.path(path);
667+
)
668+
}
639669

640-
Ok(builder)
670+
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
671+
/// [`OffersMessageFlow`] when handling [`Bolt12Invoice`] messages for the refund.
672+
///
673+
/// # Privacy
674+
///
675+
/// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
676+
/// Users can implement a custom [`MessageRouter`] to define properties of the
677+
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
678+
///
679+
/// # Payment
680+
///
681+
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
682+
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
683+
///
684+
/// The builder will have the provided expiration set. Any changes to the expiration on the
685+
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
686+
/// block time minus two hours is used for the current time when determining if the refund has
687+
/// expired.
688+
///
689+
/// The refund can be revoked by the user prior to receiving the invoice.
690+
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
691+
/// with an [`Event::PaymentFailed`].
692+
///
693+
/// If `max_total_routing_fee_msat` is not specified, The default from
694+
/// [`RouteParameters::from_payment_params_and_value`] is applied.
695+
///
696+
/// Also, uses a derived payer id in the refund for payer privacy.
697+
///
698+
/// # Errors
699+
///
700+
/// Errors if:
701+
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
702+
/// - `amount_msats` is invalid, or
703+
/// - the provided [`MessageRouter`] is unable to create a blinded path for the refund.
704+
///
705+
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
706+
/// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
707+
pub fn create_refund_builder_using_router<ES: Deref, ME: Deref>(
708+
&self, router: ME, entropy_source: ES, amount_msats: u64, absolute_expiry: Duration,
709+
payment_id: PaymentId, peers: Vec<MessageForwardNode>,
710+
) -> Result<RefundBuilder<secp256k1::All>, Bolt12SemanticError>
711+
where
712+
ME::Target: MessageRouter,
713+
ES::Target: EntropySource,
714+
{
715+
self.create_refund_builder_intern(
716+
|node_id, context, secp_ctx| {
717+
router
718+
.create_blinded_paths(node_id, context, peers, secp_ctx)
719+
.map(|paths| paths.into_iter().take(1).collect())
720+
.map_err(|_| Bolt12SemanticError::MissingPaths)
721+
},
722+
&*entropy_source,
723+
amount_msats,
724+
absolute_expiry,
725+
payment_id,
726+
)
641727
}
642728

643729
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized

0 commit comments

Comments
 (0)