Skip to content

Commit

Permalink
Allow create_blinded_paths function to take Recipient Data as a field
Browse files Browse the repository at this point in the history
1. Recipient Data is intended to be sent along with the reply_path
   provided to the counterparty.
2. This commit introduces recipient data in the create_blinded_path
   flow, optionally appending it within the created reply_path.
3. Also update the test, to test the new added feature.
  • Loading branch information
shaavan committed May 30, 2024
1 parent e057531 commit 3a648c9
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 52 deletions.
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hash_types::{BlockHash, WPubkeyHash};

use lightning::blinded_path::BlindedPath;
use lightning::blinded_path::message::ForwardNode;
use lightning::blinded_path::message::{ForwardNode, RecipientData};
use lightning::blinded_path::payment::ReceiveTlvs;
use lightning::chain;
use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, channelmonitor, Confirm, Watch};
Expand Down Expand Up @@ -120,7 +120,7 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _recipient_data: Option<RecipientData>, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedPath>, ()> {
unreachable!()
}
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};

use lightning::blinded_path::BlindedPath;
use lightning::blinded_path::message::ForwardNode;
use lightning::blinded_path::message::{ForwardNode, RecipientData};
use lightning::blinded_path::payment::ReceiveTlvs;
use lightning::chain;
use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen};
Expand Down Expand Up @@ -158,7 +158,7 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _recipient_data: Option<RecipientData>, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedPath>, ()> {
unreachable!()
}
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/invoice_request_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
],
];
let paths = vec![
BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), &entropy_source, secp_ctx).unwrap(),
BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), &entropy_source, secp_ctx).unwrap(),
BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), None, &entropy_source, secp_ctx).unwrap(),
BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), None, &entropy_source, secp_ctx).unwrap(),
];

let payinfo = vec![
Expand Down
3 changes: 2 additions & 1 deletion fuzz/src/onion_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ impl MessageRouter for TestMessageRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _recipient_data: Option<RecipientData>,
_peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedPath>, ()> {
unreachable!()
}
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/refund_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
],
];
let paths = vec![
BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), &entropy_source, secp_ctx).unwrap(),
BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), &entropy_source, secp_ctx).unwrap(),
BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), None, &entropy_source, secp_ctx).unwrap(),
BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), None, &entropy_source, secp_ctx).unwrap(),
];

let payinfo = vec![
Expand Down
5 changes: 3 additions & 2 deletions lightning/src/blinded_path/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,11 @@ impl Writeable for ReceiveTlvs {
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey,
session_priv: &SecretKey
recipient_data: Option<RecipientData>, session_priv: &SecretKey
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
let pks = intermediate_nodes.iter().map(|node| &node.node_id)
.chain(core::iter::once(&recipient_node_id));
let recipient_data = recipient_data.unwrap_or(RecipientData::new());
let tlvs = pks.clone()
.skip(1) // The first node's TLVs contains the next node's pubkey
.zip(intermediate_nodes.iter().map(|node| node.short_channel_id))
Expand All @@ -124,7 +125,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
None => NextMessageHop::NodeId(*pubkey),
})
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None, recipient_data: RecipientData::new() })));
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None, recipient_data })));

utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
}
Expand Down
10 changes: 6 additions & 4 deletions lightning/src/blinded_path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub(crate) mod utils;
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
use core::ops::Deref;

use crate::blinded_path::message::RecipientData;
use crate::ln::msgs::DecodeError;
use crate::offers::invoice::BlindedPayInfo;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
Expand Down Expand Up @@ -123,9 +124,9 @@ pub struct BlindedHop {
impl BlindedPath {
/// Create a one-hop blinded path for a message.
pub fn one_hop_for_message<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
recipient_node_id: PublicKey, entropy_source: ES, secp_ctx: &Secp256k1<T>
recipient_node_id: PublicKey, recipient_data: Option<RecipientData>, entropy_source: ES, secp_ctx: &Secp256k1<T>
) -> Result<Self, ()> where ES::Target: EntropySource {
Self::new_for_message(&[], recipient_node_id, entropy_source, secp_ctx)
Self::new_for_message(&[], recipient_node_id, recipient_data, entropy_source, secp_ctx)
}

/// Create a blinded path for an onion message, to be forwarded along `node_pks`. The last node
Expand All @@ -135,7 +136,7 @@ impl BlindedPath {
// TODO: make all payloads the same size with padding + add dummy hops
pub fn new_for_message<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
intermediate_nodes: &[message::ForwardNode], recipient_node_id: PublicKey,
entropy_source: ES, secp_ctx: &Secp256k1<T>
recipient_data: Option<RecipientData>, entropy_source: ES, secp_ctx: &Secp256k1<T>
) -> Result<Self, ()> where ES::Target: EntropySource {
let introduction_node = IntroductionNode::NodeId(
intermediate_nodes.first().map_or(recipient_node_id, |n| n.node_id)
Expand All @@ -147,7 +148,8 @@ impl BlindedPath {
introduction_node,
blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
blinded_hops: message::blinded_hops(
secp_ctx, intermediate_nodes, recipient_node_id, &blinding_secret,
secp_ctx, intermediate_nodes, recipient_node_id, recipient_data,
&blinding_secret,
).map_err(|_| ())?,
})
}
Expand Down
19 changes: 13 additions & 6 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8573,7 +8573,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;

let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let path = $self.create_blinded_path(None).map_err(|_| Bolt12SemanticError::MissingPaths)?;
let builder = OfferBuilder::deriving_signing_pubkey(
node_id, expanded_key, entropy, secp_ctx
)
Expand Down Expand Up @@ -8640,7 +8640,11 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;

let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let recipient_data = RecipientData {
payment_id: Some(payment_id)
};

let path = $self.create_blinded_path(Some(recipient_data)).map_err(|_| Bolt12SemanticError::MissingPaths)?;
let builder = RefundBuilder::deriving_payer_id(
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
)?
Expand Down Expand Up @@ -8763,7 +8767,10 @@ where
Some(payer_note) => builder.payer_note(payer_note),
};
let invoice_request = builder.build_and_sign()?;
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let recipient_data = RecipientData {
payment_id: Some(payment_id)
};
let reply_path = self.create_blinded_path(Some(recipient_data)).map_err(|_| Bolt12SemanticError::MissingPaths)?;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);

Expand Down Expand Up @@ -8863,7 +8870,7 @@ where
)?;
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
let reply_path = self.create_blinded_path()
let reply_path = self.create_blinded_path(None)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
Expand Down Expand Up @@ -8992,7 +8999,7 @@ where
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
///
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
fn create_blinded_path(&self, recipient_data: Option<RecipientData>) -> Result<BlindedPath, ()> {
let recipient = self.get_our_node_id();
let secp_ctx = &self.secp_ctx;

Expand All @@ -9011,7 +9018,7 @@ where
.collect::<Vec<_>>();

self.router
.create_blinded_paths(recipient, peers, secp_ctx)
.create_blinded_paths(recipient, recipient_data, peers, secp_ctx)
.and_then(|paths| paths.into_iter().next().ok_or(()))
}

Expand Down
10 changes: 10 additions & 0 deletions lightning/src/ln/offers_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,16 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {

let invoice_error = extract_invoice_error(david, &onion_message);
assert_eq!(invoice_error, InvoiceError::from(Bolt12SemanticError::MissingPaths));

// Confirm that david drops this failed payment from his pending outbound payments.
let events = david.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
Event::InvoiceRequestFailed { payment_id: pay_id} => {
assert_eq!(pay_id, payment_id)
},
_ => panic!("Unexpected Event"),
}
}

#[test]
Expand Down
30 changes: 15 additions & 15 deletions lightning/src/onion_message/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ fn one_blinded_hop() {
let test_msg = TestCustomMessage::Pong;

let secp_ctx = Secp256k1::new();
let blinded_path = BlindedPath::new_for_message(&[], nodes[1].node_id, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let blinded_path = BlindedPath::new_for_message(&[], nodes[1].node_id, None, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path);
nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap();
nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong);
Expand All @@ -373,7 +373,7 @@ fn two_unblinded_two_blinded() {

let secp_ctx = Secp256k1::new();
let intermediate_nodes = [ForwardNode { node_id: nodes[3].node_id, short_channel_id: None }];
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[4].node_id, &*nodes[4].entropy_source, &secp_ctx).unwrap();
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[4].node_id, None, &*nodes[4].entropy_source, &secp_ctx).unwrap();
let path = OnionMessagePath {
intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id],
destination: Destination::BlindedPath(blinded_path),
Expand All @@ -395,7 +395,7 @@ fn three_blinded_hops() {
ForwardNode { node_id: nodes[1].node_id, short_channel_id: None },
ForwardNode { node_id: nodes[2].node_id, short_channel_id: None },
];
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, &*nodes[3].entropy_source, &secp_ctx).unwrap();
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, None, &*nodes[3].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path);

nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap();
Expand All @@ -418,7 +418,7 @@ fn async_response_over_one_blinded_hop() {

// 3. Simulate the creation of a Blinded Reply path provided by Bob.
let secp_ctx = Secp256k1::new();
let reply_path = BlindedPath::new_for_message(&[], nodes[1].node_id, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let reply_path = BlindedPath::new_for_message(&[], nodes[1].node_id, None, &*nodes[1].entropy_source, &secp_ctx).unwrap();

// 4. Create a responder using the reply path for Alice.
let responder = Some(Responder::new(reply_path, path_id));
Expand Down Expand Up @@ -454,7 +454,7 @@ fn async_response_with_reply_path_succeeds() {
// Alice receives a message from Bob with an added reply_path for responding back.
let message = TestCustomMessage::Ping;
let path_id = Some([2; 32]);
let reply_path = BlindedPath::new_for_message(&[], bob.node_id, &*bob.entropy_source, &secp_ctx).unwrap();
let reply_path = BlindedPath::new_for_message(&[], bob.node_id, None, &*bob.entropy_source, &secp_ctx).unwrap();

// Alice asynchronously responds to Bob, expecting a response back from him.
let responder = Responder::new(reply_path, path_id);
Expand Down Expand Up @@ -491,7 +491,7 @@ fn async_response_with_reply_path_fails() {
// Alice receives a message from Bob with an added reply_path for responding back.
let message = TestCustomMessage::Ping;
let path_id = Some([2; 32]);
let reply_path = BlindedPath::new_for_message(&[], bob.node_id, &*bob.entropy_source, &secp_ctx).unwrap();
let reply_path = BlindedPath::new_for_message(&[], bob.node_id, None, &*bob.entropy_source, &secp_ctx).unwrap();

// Alice tries to asynchronously respond to Bob, but fails because the nodes are unannounced.
// Therefore, the reply_path cannot be used for the response.
Expand Down Expand Up @@ -534,7 +534,7 @@ fn we_are_intro_node() {
ForwardNode { node_id: nodes[0].node_id, short_channel_id: None },
ForwardNode { node_id: nodes[1].node_id, short_channel_id: None },
];
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, &*nodes[2].entropy_source, &secp_ctx).unwrap();
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, None, &*nodes[2].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path);

nodes[0].messenger.send_onion_message(test_msg.clone(), destination, None).unwrap();
Expand All @@ -543,7 +543,7 @@ fn we_are_intro_node() {

// Try with a two-hop blinded path where we are the introduction node.
let intermediate_nodes = [ForwardNode { node_id: nodes[0].node_id, short_channel_id: None }];
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[1].node_id, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[1].node_id, None, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path);
nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap();
nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong);
Expand All @@ -559,7 +559,7 @@ fn invalid_blinded_path_error() {

let secp_ctx = Secp256k1::new();
let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }];
let mut blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, &*nodes[2].entropy_source, &secp_ctx).unwrap();
let mut blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, None, &*nodes[2].entropy_source, &secp_ctx).unwrap();
blinded_path.blinded_hops.clear();
let destination = Destination::BlindedPath(blinded_path);
let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err();
Expand All @@ -582,7 +582,7 @@ fn reply_path() {
ForwardNode { node_id: nodes[2].node_id, short_channel_id: None },
ForwardNode { node_id: nodes[1].node_id, short_channel_id: None },
];
let reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, &*nodes[0].entropy_source, &secp_ctx).unwrap();
let reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, None, &*nodes[0].entropy_source, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message_using_path(path, test_msg.clone(), Some(reply_path)).unwrap();
nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping);
pass_along_path(&nodes);
Expand All @@ -596,13 +596,13 @@ fn reply_path() {
ForwardNode { node_id: nodes[1].node_id, short_channel_id: None },
ForwardNode { node_id: nodes[2].node_id, short_channel_id: None },
];
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, &*nodes[3].entropy_source, &secp_ctx).unwrap();
let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, None, &*nodes[3].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path);
let intermediate_nodes = [
ForwardNode { node_id: nodes[2].node_id, short_channel_id: None },
ForwardNode { node_id: nodes[1].node_id, short_channel_id: None },
];
let reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, &*nodes[0].entropy_source, &secp_ctx).unwrap();
let reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, None, &*nodes[0].entropy_source, &secp_ctx).unwrap();

nodes[0].messenger.send_onion_message(test_msg, destination, Some(reply_path)).unwrap();
nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping);
Expand Down Expand Up @@ -684,7 +684,7 @@ fn requests_peer_connection_for_buffered_messages() {

let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }];
let blinded_path = BlindedPath::new_for_message(
&intermediate_nodes, nodes[2].node_id, &*nodes[0].entropy_source, &secp_ctx
&intermediate_nodes, nodes[2].node_id, None, &*nodes[0].entropy_source, &secp_ctx
).unwrap();
let destination = Destination::BlindedPath(blinded_path);

Expand Down Expand Up @@ -722,7 +722,7 @@ fn drops_buffered_messages_waiting_for_peer_connection() {

let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }];
let blinded_path = BlindedPath::new_for_message(
&intermediate_nodes, nodes[2].node_id, &*nodes[0].entropy_source, &secp_ctx
&intermediate_nodes, nodes[2].node_id, None, &*nodes[0].entropy_source, &secp_ctx
).unwrap();
let destination = Destination::BlindedPath(blinded_path);

Expand Down Expand Up @@ -772,7 +772,7 @@ fn intercept_offline_peer_oms() {
let secp_ctx = Secp256k1::new();
let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }];
let blinded_path = BlindedPath::new_for_message(
&intermediate_nodes, nodes[2].node_id, &*nodes[2].entropy_source, &secp_ctx
&intermediate_nodes, nodes[2].node_id, None, &*nodes[2].entropy_source, &secp_ctx
).unwrap();
let destination = Destination::BlindedPath(blinded_path);

Expand Down
Loading

0 comments on commit 3a648c9

Please sign in to comment.