From 678aac0f0ffe0f7157857d705953a28e644664e8 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 3 Jul 2024 14:31:33 -0400 Subject: [PATCH] Set max path length when paying BOLT 12 invoices. --- .../src/ln/max_payment_path_len_tests.rs | 54 ++++++++++++++++++- lightning/src/ln/outbound_payment.rs | 14 +++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 7bd605c9d..a77d91e89 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -10,18 +10,21 @@ //! Tests for calculating the maximum length of a path based on the payment metadata, custom TLVs, //! and/or blinded paths present. -use bitcoin::secp256k1::Secp256k1; -use crate::blinded_path::BlindedPath; +use bitcoin::secp256k1::{Secp256k1, PublicKey}; +use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs}; use crate::events::MessageSendEventsProvider; use crate::ln::PaymentSecret; use crate::ln::blinded_payment_tests::get_blinded_route_parameters; use crate::ln::channelmanager::PaymentId; +use crate::ln::features::BlindedHopFeatures; use crate::ln::functional_test_utils::*; use crate::ln::msgs; +use crate::ln::msgs::OnionMessageHandler; use crate::ln::onion_utils; use crate::ln::onion_utils::MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY; use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure}; +use crate::offers::invoice::BlindedPayInfo; use crate::prelude::*; use crate::routing::router::{DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, PaymentParameters, RouteParameters}; use crate::util::errors::APIError; @@ -340,3 +343,50 @@ fn blinded_path_with_custom_tlv() { .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs) ); } + +#[test] +fn bolt12_invoice_too_large_blinded_paths() { + // Check that we'll fail paying BOLT 12 invoices with too-large blinded paths prior to + // pathfinding. + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + create_announced_chan_between_nodes(&nodes, 0, 1); + + nodes[1].router.expect_blinded_payment_paths(vec![( + BlindedPayInfo { + fee_base_msat: 42, + fee_proportional_millionths: 42, + cltv_expiry_delta: 42, + htlc_minimum_msat: 42, + htlc_maximum_msat: 42_000_000, + features: BlindedHopFeatures::empty(), + }, + BlindedPath { + introduction_node: IntroductionNode::NodeId(PublicKey::from_slice(&[2; 33]).unwrap()), + blinding_point: PublicKey::from_slice(&[2; 33]).unwrap(), + blinded_hops: vec![ + BlindedHop { + blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(), + encrypted_payload: vec![42; 1300], + }, + BlindedHop { + blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(), + encrypted_payload: vec![42; 1300], + }, + ], + } + )]); + + let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap(); + let payment_id = PaymentId([1; 32]); + nodes[0].node.pay_for_offer(&offer, None, Some(5000), None, payment_id, Retry::Attempts(0), None).unwrap(); + let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap(); + nodes[1].onion_messenger.handle_onion_message(&nodes[0].node.get_our_node_id(), &invreq_om); + + let invoice_om = nodes[1].onion_messenger.next_onion_message_for_peer(nodes[0].node.get_our_node_id()).unwrap(); + nodes[0].onion_messenger.handle_onion_message(&nodes[1].node.get_our_node_id(), &invoice_om); + // TODO: assert on the invoice error once we support replying to invoice OMs with failure info + nodes[0].logger.assert_log_contains("lightning::ln::channelmanager", "Failed paying invoice: OnionPacketSizeExceeded", 1); +} diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 1915a4c5a..443a7b2c3 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -510,6 +510,11 @@ pub enum Bolt12PaymentError { UnexpectedInvoice, /// Payment for an invoice with the corresponding [`PaymentId`] was already initiated. DuplicateInvoice, + /// The [`BlindedPath`]s provided are too large and caused us to exceed the maximum onion hop data + /// size of 1300 bytes. + /// + /// [`BlindedPath`]: crate::blinded_path::BlindedPath + OnionPacketSizeExceeded, } /// Indicates that we failed to send a payment probe. Further errors may be surfaced later via @@ -837,6 +842,15 @@ impl OutboundPayments { let mut route_params = RouteParameters::from_payment_params_and_value( payment_params, amount_msat ); + onion_utils::set_max_path_length( + &mut route_params, &RecipientOnionFields::spontaneous_empty(), None, best_block_height + ) + .map_err(|()| { + log_error!(logger, "Can't construct an onion packet without exceeding 1300-byte onion \ + hop_data length for payment with id {} and hash {}", payment_id, payment_hash); + Bolt12PaymentError::OnionPacketSizeExceeded + })?; + if let Some(max_fee_msat) = max_total_routing_fee_msat { route_params.max_total_routing_fee_msat = Some(max_fee_msat); } -- 2.39.5