Skip to content

Commit 367d0cc

Browse files
committed
Drop risky unwraps in PaymentParameters::from_* methods
Previoously, we added a bunch of constructors for `PaymentParameters` that would panic if we ever misused the wrong APIs on a `Clear` or `Blinded` payee. While this was not immediately reachable, we here refactor these constructors to avoid the risk going forward.
1 parent 16a4596 commit 367d0cc

File tree

4 files changed

+33
-17
lines changed

4 files changed

+33
-17
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12518,6 +12518,10 @@ where
1251812518
);
1251912519
InvoiceError::from(Bolt12SemanticError::UnknownRequiredFeatures)
1252012520
},
12521+
Err(Bolt12PaymentError::InvalidInvoice) => {
12522+
log_trace!($logger, "Failed paying invalid/incompatible invoice");
12523+
return None;
12524+
},
1252112525
Err(Bolt12PaymentError::SendingFailed(e)) => {
1252212526
log_trace!($logger, "Failed paying invoice: {:?}", e);
1252312527
InvoiceError::from_string(format!("{:?}", e))

lightning/src/ln/offers_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ fn pays_bolt12_invoice_asynchronously() {
11861186
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
11871187
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
11881188

1189-
// Re-process the same onion message to ensure idempotency —
1189+
// Re-process the same onion message to ensure idempotency —
11901190
// we should not generate a duplicate `InvoiceReceived` event.
11911191
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
11921192

@@ -2302,7 +2302,7 @@ fn rejects_keysend_to_non_static_invoice_path() {
23022302

23032303
// Pay the invoice via keysend now that we have the preimage and make sure the recipient fails it
23042304
// due to incorrect payment context.
2305-
let pay_params = PaymentParameters::from_bolt12_invoice(&invoice);
2305+
let pay_params = PaymentParameters::from_bolt12_invoice(&invoice).unwrap();
23062306
let route_params = RouteParameters::from_payment_params_and_value(pay_params, amt_msat);
23072307
let keysend_payment_id = PaymentId([2; 32]);
23082308
let payment_hash = nodes[0].node.send_spontaneous_payment(

lightning/src/ln/outbound_payment.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@ pub enum Bolt11PaymentError {
593593
/// [`Bolt11Invoice`]: lightning_invoice::Bolt11Invoice
594594
/// [`ChannelManager::pay_for_bolt11_invoice`]: crate::ln::channelmanager::ChannelManager::pay_for_bolt11_invoice
595595
InvalidAmount,
596+
/// An invalid or incompatible invoice was provided to [`ChannelManager::pay_for_bolt11_invoice`].
597+
InvalidInvoice,
596598
/// The invoice was valid for the corresponding [`PaymentId`], but sending the payment failed.
597599
SendingFailed(RetryableSendFailure),
598600
}
@@ -604,6 +606,8 @@ pub enum Bolt12PaymentError {
604606
UnexpectedInvoice,
605607
/// Payment for an invoice with the corresponding [`PaymentId`] was already initiated.
606608
DuplicateInvoice,
609+
/// An invalid or incompatible invoice was provided to [`ChannelManager::pay_for_bolt12_invoice`].
610+
InvalidInvoice,
607611
/// The invoice was valid for the corresponding [`PaymentId`], but required unknown features.
608612
UnknownRequiredFeatures,
609613
/// The invoice was valid for the corresponding [`PaymentId`], but sending the payment failed.
@@ -902,6 +906,7 @@ impl OutboundPayments {
902906
recipient_onion.payment_metadata = invoice.payment_metadata().map(|v| v.clone());
903907

904908
let payment_params = PaymentParameters::from_bolt11_invoice(invoice)
909+
.map_err(|_| Bolt11PaymentError::InvalidInvoice)?
905910
.with_user_config_ignoring_fee_limit(route_params_config);
906911

907912
let mut route_params = RouteParameters::from_payment_params_and_value(payment_params, amount);
@@ -949,6 +954,7 @@ impl OutboundPayments {
949954

950955
let mut route_params = RouteParameters::from_payment_params_and_value(
951956
PaymentParameters::from_bolt12_invoice(&invoice)
957+
.map_err(|_| Bolt12PaymentError::InvalidInvoice)?
952958
.with_user_config_ignoring_fee_limit(params_config), invoice.amount_msats()
953959
);
954960
if let Some(max_fee_msat) = params_config.max_total_routing_fee_msat {
@@ -1127,6 +1133,7 @@ impl OutboundPayments {
11271133
let keysend_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
11281134
let payment_hash = PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array());
11291135
let pay_params = PaymentParameters::from_static_invoice(invoice)
1136+
.map_err(|_| Bolt12PaymentError::InvalidInvoice)?
11301137
.with_user_config_ignoring_fee_limit(*route_params_config);
11311138
let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat);
11321139
route_params.max_total_routing_fee_msat = route_params_config.max_total_routing_fee_msat;
@@ -3034,7 +3041,7 @@ mod tests {
30343041
assert!(outbound_payments.has_pending_payments());
30353042

30363043
let route_params = RouteParameters::from_payment_params_and_value(
3037-
PaymentParameters::from_bolt12_invoice(&invoice),
3044+
PaymentParameters::from_bolt12_invoice(&invoice).unwrap(),
30383045
invoice.amount_msats(),
30393046
);
30403047
router.expect_find_route(route_params, Err(""));
@@ -3086,7 +3093,7 @@ mod tests {
30863093
.sign(recipient_sign).unwrap();
30873094

30883095
let route_params = RouteParameters {
3089-
payment_params: PaymentParameters::from_bolt12_invoice(&invoice),
3096+
payment_params: PaymentParameters::from_bolt12_invoice(&invoice).unwrap(),
30903097
final_value_msat: invoice.amount_msats(),
30913098
max_total_routing_fee_msat: Some(1234),
30923099
};

lightning/src/routing/router.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -921,41 +921,46 @@ impl PaymentParameters {
921921
/// Creates parameters for paying to a blinded payee from the provided invoice. Sets
922922
/// [`Payee::Blinded::route_hints`], [`Payee::Blinded::features`], and
923923
/// [`PaymentParameters::expiry_time`].
924-
pub fn from_bolt11_invoice(invoice: &Bolt11Invoice) -> Self {
924+
///
925+
/// Will return an error if an incompatible invoice is provided.
926+
pub fn from_bolt11_invoice(invoice: &Bolt11Invoice) -> Result<Self, ()>{
925927
let mut payment_params = Self::from_node_id(
926928
invoice.recover_payee_pub_key(),
927929
invoice.min_final_cltv_expiry_delta() as u32,
928930
)
929-
.with_route_hints(invoice.route_hints())
930-
.unwrap();
931+
.with_route_hints(invoice.route_hints())?;
931932

932933
if let Some(expiry) = invoice.expires_at() {
933934
payment_params = payment_params.with_expiry_time(expiry.as_secs());
934935
}
935936
if let Some(features) = invoice.features() {
936-
payment_params = payment_params.with_bolt11_features(features.clone()).unwrap();
937+
payment_params = payment_params.with_bolt11_features(features.clone())?;
937938
}
938939

939-
payment_params
940+
Ok(payment_params)
940941
}
941942

942943
/// Creates parameters for paying to a blinded payee from the provided invoice. Sets
943944
/// [`Payee::Blinded::route_hints`], [`Payee::Blinded::features`], and
944945
/// [`PaymentParameters::expiry_time`].
945-
pub fn from_bolt12_invoice(invoice: &Bolt12Invoice) -> Self {
946-
Self::blinded(invoice.payment_paths().to_vec())
947-
.with_bolt12_features(invoice.invoice_features().clone()).unwrap()
948-
.with_expiry_time(invoice.created_at().as_secs().saturating_add(invoice.relative_expiry().as_secs()))
946+
///
947+
/// Will return an error if an incompatible invoice is provided.
948+
pub fn from_bolt12_invoice(invoice: &Bolt12Invoice) -> Result<Self, ()> {
949+
Ok(Self::blinded(invoice.payment_paths().to_vec())
950+
.with_bolt12_features(invoice.invoice_features().clone())?
951+
.with_expiry_time(invoice.created_at().as_secs().saturating_add(invoice.relative_expiry().as_secs())))
949952
}
950953

951954
/// Creates parameters for paying to a blinded payee from the provided invoice. Sets
952955
/// [`Payee::Blinded::route_hints`], [`Payee::Blinded::features`], and
953956
/// [`PaymentParameters::expiry_time`].
957+
///
958+
/// Will return an error if an incompatible invoice is provided.
954959
#[cfg(async_payments)]
955-
pub fn from_static_invoice(invoice: &StaticInvoice) -> Self {
956-
Self::blinded(invoice.payment_paths().to_vec())
957-
.with_bolt12_features(invoice.invoice_features().clone()).unwrap()
958-
.with_expiry_time(invoice.created_at().as_secs().saturating_add(invoice.relative_expiry().as_secs()))
960+
pub fn from_static_invoice(invoice: &StaticInvoice) -> Result<Self, ()> {
961+
Ok(Self::blinded(invoice.payment_paths().to_vec())
962+
.with_bolt12_features(invoice.invoice_features().clone())?
963+
.with_expiry_time(invoice.created_at().as_secs().saturating_add(invoice.relative_expiry().as_secs())))
959964
}
960965

961966
/// Creates parameters for paying to a blinded payee from the provided blinded route hints.

0 commit comments

Comments
 (0)