Advance self blinded payment paths
authorJeffrey Czyz <jkczyz@gmail.com>
Thu, 13 Jun 2024 22:15:19 +0000 (17:15 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Tue, 18 Jun 2024 14:26:29 +0000 (09:26 -0500)
DefaultRouter will ignore blinded paths where the sender is the
introduction node. Similar to message paths, advance such paths by one
so that payments may be sent to them.

lightning/src/ln/channelmanager.rs
lightning/src/ln/offers_tests.rs
lightning/src/ln/outbound_payment.rs
lightning/src/routing/router.rs

index 508d13a15822acffe1fc7a5d2decfd333632275f..9e573a705f7e51452d675424dd2bab348c0aff1b 100644 (file)
@@ -4031,8 +4031,8 @@ where
                self.pending_outbound_payments
                        .send_payment_for_bolt12_invoice(
                                invoice, payment_id, &self.router, self.list_usable_channels(),
-                               || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer,
-                               best_block_height, &self.logger, &self.pending_events,
+                               || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, &self,
+                               &self.secp_ctx, best_block_height, &self.logger, &self.pending_events,
                                |args| self.send_payment_along_path(args)
                        )
        }
index 1922ef71be88d23ea2b6174d6e9a7e311ccdb3dd..52375f723c75ec216241468456a43f5f63a4c69f 100644 (file)
@@ -986,10 +986,19 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
        alice.onion_messenger.handle_onion_message(&bob_id, &onion_message);
 
        let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
+       let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
+               offer_id: offer.id(),
+               invoice_request: InvoiceRequestFields {
+                       payer_id: invoice_request.payer_id(),
+                       quantity: None,
+                       payer_note_truncated: None,
+               },
+       });
        assert_ne!(invoice_request.payer_id(), bob_id);
        assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(alice_id));
 
        let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
+       bob.onion_messenger.handle_onion_message(&alice_id, &onion_message);
 
        let invoice = extract_invoice(bob, &onion_message);
        assert_ne!(invoice.signing_pubkey(), alice_id);
@@ -997,6 +1006,12 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
        for (_, path) in invoice.payment_paths() {
                assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
        }
+
+       route_bolt12_payment(bob, &[alice], &invoice);
+       expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
+
+       claim_bolt12_payment(bob, &[alice], payment_context);
+       expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
 }
 
 /// Checks that a refund can be created using an unannounced node as a blinded path's introduction
index 906f4c58c760f9cd1321bc7282b074ce9c399a7a..1915a4c5a14db61b4fe00c5ace6f36203f5791c2 100644 (file)
@@ -13,6 +13,8 @@ use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
 
+use crate::blinded_path::{IntroductionNode, NodeIdLookUp};
+use crate::blinded_path::payment::advance_path_by_one;
 use crate::events::{self, PaymentFailureReason};
 use crate::ln::types::{PaymentHash, PaymentPreimage, PaymentSecret};
 use crate::ln::channel_state::ChannelDetails;
@@ -775,10 +777,13 @@ impl OutboundPayments {
                }
        }
 
-       pub(super) fn send_payment_for_bolt12_invoice<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
+       pub(super) fn send_payment_for_bolt12_invoice<
+               R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref
+       >(
                &self, invoice: &Bolt12Invoice, payment_id: PaymentId, router: &R,
                first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
-               best_block_height: u32, logger: &L,
+               node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32,
+               logger: &L,
                pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
                send_payment_along_path: SP,
        ) -> Result<(), Bolt12PaymentError>
@@ -786,6 +791,7 @@ impl OutboundPayments {
                R::Target: Router,
                ES::Target: EntropySource,
                NS::Target: NodeSigner,
+               NL::Target: NodeIdLookUp,
                L::Target: Logger,
                IH: Fn() -> InFlightHtlcs,
                SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
@@ -807,7 +813,26 @@ impl OutboundPayments {
                        hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
                };
 
-               let payment_params = PaymentParameters::from_bolt12_invoice(&invoice);
+               let mut payment_params = PaymentParameters::from_bolt12_invoice(&invoice);
+
+               // Advance any blinded path where the introduction node is our node.
+               if let Ok(our_node_id) = node_signer.get_node_id(Recipient::Node) {
+                       for (_, path) in payment_params.payee.blinded_route_hints_mut().iter_mut() {
+                               let introduction_node_id = match path.introduction_node {
+                                       IntroductionNode::NodeId(pubkey) => pubkey,
+                                       IntroductionNode::DirectedShortChannelId(direction, scid) => {
+                                               match node_id_lookup.next_node_id(scid) {
+                                                       Some(next_node_id) => *direction.select_pubkey(&our_node_id, &next_node_id),
+                                                       None => continue,
+                                               }
+                                       },
+                               };
+                               if introduction_node_id == our_node_id {
+                                       let _ = advance_path_by_one(path, node_signer, node_id_lookup, secp_ctx);
+                               }
+                       }
+               }
+
                let amount_msat = invoice.amount_msats();
                let mut route_params = RouteParameters::from_payment_params_and_value(
                        payment_params, amount_msat
@@ -1858,6 +1883,7 @@ mod tests {
 
        use core::time::Duration;
 
+       use crate::blinded_path::EmptyNodeIdLookUp;
        use crate::events::{Event, PathFailure, PaymentFailureReason};
        use crate::ln::types::PaymentHash;
        use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
@@ -2201,6 +2227,7 @@ mod tests {
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
+               let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2229,7 +2256,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Ok(()),
                );
@@ -2252,6 +2280,7 @@ mod tests {
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
+               let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2288,7 +2317,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Ok(()),
                );
@@ -2311,6 +2341,7 @@ mod tests {
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
+               let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2360,7 +2391,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Err(Bolt12PaymentError::UnexpectedInvoice),
                );
@@ -2377,7 +2409,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| Ok(())
                        ),
                        Ok(()),
                );
@@ -2387,7 +2420,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Err(Bolt12PaymentError::DuplicateInvoice),
                );
index 19931d5c5d8dadcd44196eb3e85bd6dd5b3030b4..036d6372af098a05cee3c54dde87d8aafe6321f0 100644 (file)
@@ -1045,6 +1045,13 @@ impl Payee {
                }
        }
 
+       pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPath)] {
+               match self {
+                       Self::Blinded { route_hints, .. } => &mut route_hints[..],
+                       Self::Clear { .. } => &mut []
+               }
+       }
+
        fn unblinded_route_hints(&self) -> &[RouteHint] {
                match self {
                        Self::Blinded { .. } => &[],