Skip to content

Commit b4da06c

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 9dd44cb commit b4da06c

File tree

4 files changed

+39
-17
lines changed

4 files changed

+39
-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: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,10 @@ 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+
///
598+
/// [`ChannelManager::pay_for_bolt11_invoice`]: crate::ln::channelmanager::ChannelManager::pay_for_bolt11_invoice
599+
InvalidInvoice,
596600
/// The invoice was valid for the corresponding [`PaymentId`], but sending the payment failed.
597601
SendingFailed(RetryableSendFailure),
598602
}
@@ -604,7 +608,13 @@ pub enum Bolt12PaymentError {
604608
UnexpectedInvoice,
605609
/// Payment for an invoice with the corresponding [`PaymentId`] was already initiated.
606610
DuplicateInvoice,
611+
/// An invalid or incompatible invoice was provided to [`ChannelManager`].
612+
///
613+
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
614+
InvalidInvoice,
607615
/// The invoice was valid for the corresponding [`PaymentId`], but required unknown features.
616+
///
617+
/// [`ChannelManager::pay_for_bolt12_invoice`]: crate::ln::channelmanager::ChannelManager::pay_for_bolt12_invoice
608618
UnknownRequiredFeatures,
609619
/// The invoice was valid for the corresponding [`PaymentId`], but sending the payment failed.
610620
SendingFailed(RetryableSendFailure),
@@ -902,6 +912,7 @@ impl OutboundPayments {
902912
recipient_onion.payment_metadata = invoice.payment_metadata().map(|v| v.clone());
903913

904914
let payment_params = PaymentParameters::from_bolt11_invoice(invoice)
915+
.map_err(|_| Bolt11PaymentError::InvalidInvoice)?
905916
.with_user_config_ignoring_fee_limit(route_params_config);
906917

907918
let mut route_params = RouteParameters::from_payment_params_and_value(payment_params, amount);
@@ -949,6 +960,7 @@ impl OutboundPayments {
949960

950961
let mut route_params = RouteParameters::from_payment_params_and_value(
951962
PaymentParameters::from_bolt12_invoice(&invoice)
963+
.map_err(|_| Bolt12PaymentError::InvalidInvoice)?
952964
.with_user_config_ignoring_fee_limit(params_config), invoice.amount_msats()
953965
);
954966
if let Some(max_fee_msat) = params_config.max_total_routing_fee_msat {
@@ -1127,6 +1139,7 @@ impl OutboundPayments {
11271139
let keysend_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
11281140
let payment_hash = PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array());
11291141
let pay_params = PaymentParameters::from_static_invoice(invoice)
1142+
.map_err(|_| Bolt12PaymentError::InvalidInvoice)?
11301143
.with_user_config_ignoring_fee_limit(*route_params_config);
11311144
let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat);
11321145
route_params.max_total_routing_fee_msat = route_params_config.max_total_routing_fee_msat;
@@ -3034,7 +3047,7 @@ mod tests {
30343047
assert!(outbound_payments.has_pending_payments());
30353048

30363049
let route_params = RouteParameters::from_payment_params_and_value(
3037-
PaymentParameters::from_bolt12_invoice(&invoice),
3050+
PaymentParameters::from_bolt12_invoice(&invoice).unwrap(),
30383051
invoice.amount_msats(),
30393052
);
30403053
router.expect_find_route(route_params, Err(""));
@@ -3086,7 +3099,7 @@ mod tests {
30863099
.sign(recipient_sign).unwrap();
30873100

30883101
let route_params = RouteParameters {
3089-
payment_params: PaymentParameters::from_bolt12_invoice(&invoice),
3102+
payment_params: PaymentParameters::from_bolt12_invoice(&invoice).unwrap(),
30903103
final_value_msat: invoice.amount_msats(),
30913104
max_total_routing_fee_msat: Some(1234),
30923105
};

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)