Advance self blinded payment paths

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.
This commit is contained in:
Jeffrey Czyz 2024-06-13 17:15:19 -05:00
parent 55ba2aab41
commit 642913c586
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5
4 changed files with 66 additions and 10 deletions

View 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)
)
}

View 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

View 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),
);

View 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 { .. } => &[],