Skip to content

Commit 8f320f9

Browse files
committed
Enable Custom data for message::ReceiveTlvs
- Introduces the ability for users to include custom data within blinded paths. - For paths used to reach them (e.g., offer or reply paths), users can attach custom data that is returned when the path is utilized.
1 parent abf72a5 commit 8f320f9

File tree

13 files changed

+195
-111
lines changed

13 files changed

+195
-111
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
3333
use bitcoin::hashes::Hash as TraitImport;
3434
use bitcoin::WPubkeyHash;
3535

36-
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
36+
use lightning::blinded_path::message::{self, BlindedMessagePath};
3737
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
3838
use lightning::chain;
3939
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
@@ -141,7 +141,7 @@ impl MessageRouter for FuzzRouter {
141141
}
142142

143143
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
144-
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
144+
&self, _recipient: PublicKey, _receive_tlvs: message::ReceiveTlvs, _peers: Vec<PublicKey>,
145145
_secp_ctx: &Secp256k1<T>,
146146
) -> Result<Vec<BlindedMessagePath>, ()> {
147147
unreachable!()

fuzz/src/full_stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use bitcoin::hashes::Hash as _;
3030
use bitcoin::hex::FromHex;
3131
use bitcoin::WPubkeyHash;
3232

33-
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
33+
use lightning::blinded_path::message::{self, BlindedMessagePath};
3434
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
3535
use lightning::chain;
3636
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
@@ -176,7 +176,7 @@ impl MessageRouter for FuzzRouter {
176176
}
177177

178178
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
179-
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
179+
&self, _recipient: PublicKey, _receive_tlvs: message::ReceiveTlvs, _peers: Vec<PublicKey>,
180180
_secp_ctx: &Secp256k1<T>,
181181
) -> Result<Vec<BlindedMessagePath>, ()> {
182182
unreachable!()

fuzz/src/onion_message.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bitcoin::secp256k1::schnorr;
66
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
77

88
use lightning::blinded_path::message::{
9-
AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext,
9+
AsyncPaymentsContext, BlindedMessagePath, OffersContext, ReceiveTlvs,
1010
};
1111
use lightning::blinded_path::EmptyNodeIdLookUp;
1212
use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler};
@@ -99,7 +99,7 @@ impl MessageRouter for TestMessageRouter {
9999
}
100100

101101
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
102-
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
102+
&self, _recipient: PublicKey, _receive_tlvs: ReceiveTlvs, _peers: Vec<PublicKey>,
103103
_secp_ctx: &Secp256k1<T>,
104104
) -> Result<Vec<BlindedMessagePath>, ()> {
105105
unreachable!()
@@ -111,7 +111,7 @@ struct TestOffersMessageHandler {}
111111
impl OffersMessageHandler for TestOffersMessageHandler {
112112
fn handle_message(
113113
&self, _message: OffersMessage, _context: Option<OffersContext>,
114-
_responder: Option<Responder>,
114+
_custom_data: Option<Vec<u8>>, _responder: Option<Responder>,
115115
) -> Option<(OffersMessage, ResponseInstruction)> {
116116
None
117117
}

lightning-dns-resolver/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ mod test {
159159
use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
160160
use bitcoin::Block;
161161

162-
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
162+
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, ReceiveTlvs};
163163
use lightning::blinded_path::NodeIdLookUp;
164164
use lightning::events::{Event, PaymentPurpose};
165165
use lightning::ln::channelmanager::{PaymentId, Retry};
@@ -225,11 +225,11 @@ mod test {
225225
}
226226

227227
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
228-
&self, recipient: PublicKey, context: MessageContext, _peers: Vec<PublicKey>,
228+
&self, recipient: PublicKey, receive_tlvs: ReceiveTlvs, _peers: Vec<PublicKey>,
229229
secp_ctx: &Secp256k1<T>,
230230
) -> Result<Vec<BlindedMessagePath>, ()> {
231231
let keys = KeysManager::new(&[0; 32], 42, 43);
232-
Ok(vec![BlindedMessagePath::one_hop(recipient, context, &keys, secp_ctx).unwrap()])
232+
Ok(vec![BlindedMessagePath::one_hop(recipient, receive_tlvs, &keys, secp_ctx).unwrap()])
233233
}
234234
}
235235
impl Deref for DirectlyConnectedRouter {
@@ -331,8 +331,9 @@ mod test {
331331
let (msg, context) =
332332
payer.resolver.resolve_name(payment_id, name.clone(), &*payer_keys).unwrap();
333333
let query_context = MessageContext::DNSResolver(context);
334+
let receive_tlvs = ReceiveTlvs { context: Some(query_context), custom_data: None };
334335
let reply_path =
335-
BlindedMessagePath::one_hop(payer_id, query_context, &*payer_keys, &secp_ctx).unwrap();
336+
BlindedMessagePath::one_hop(payer_id, receive_tlvs, &*payer_keys, &secp_ctx).unwrap();
336337
payer.pending_messages.lock().unwrap().push((
337338
DNSResolverMessage::DNSSECQuery(msg),
338339
MessageSendInstructions::WithSpecifiedReplyPath {

lightning/src/blinded_path/message.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ impl Readable for BlindedMessagePath {
5555
impl BlindedMessagePath {
5656
/// Create a one-hop blinded path for a message.
5757
pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
58-
recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>
58+
recipient_node_id: PublicKey, receive_tlvs: ReceiveTlvs, entropy_source: ES, secp_ctx: &Secp256k1<T>
5959
) -> Result<Self, ()> where ES::Target: EntropySource {
60-
Self::new(&[], recipient_node_id, context, entropy_source, secp_ctx)
60+
Self::new(&[], recipient_node_id, receive_tlvs, entropy_source, secp_ctx)
6161
}
6262

6363
/// Create a path for an onion message, to be forwarded along `node_pks`. The last node
@@ -67,7 +67,7 @@ impl BlindedMessagePath {
6767
// TODO: make all payloads the same size with padding + add dummy hops
6868
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
6969
intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey,
70-
context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>,
70+
receive_tlvs: ReceiveTlvs, entropy_source: ES, secp_ctx: &Secp256k1<T>,
7171
) -> Result<Self, ()> where ES::Target: EntropySource {
7272
let introduction_node = IntroductionNode::NodeId(
7373
intermediate_nodes.first().map_or(recipient_node_id, |n| n.node_id)
@@ -80,7 +80,7 @@ impl BlindedMessagePath {
8080
blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
8181
blinded_hops: blinded_hops(
8282
secp_ctx, intermediate_nodes, recipient_node_id,
83-
context, &blinding_secret,
83+
receive_tlvs, &blinding_secret,
8484
).map_err(|_| ())?,
8585
}))
8686
}
@@ -236,12 +236,26 @@ pub(crate) struct ForwardTlvs {
236236
pub(crate) next_blinding_override: Option<PublicKey>,
237237
}
238238

239-
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
240-
pub(crate) struct ReceiveTlvs {
239+
#[derive(Clone)]
240+
/// Similar to Forward Tlvs, but these TLVs are for the final node.
241+
pub struct ReceiveTlvs {
241242
/// If `context` is `Some`, it is used to identify the blinded path that this onion message is
242243
/// sending to. This is useful for receivers to check that said blinded path is being used in
243244
/// the right context.
244-
pub context: Option<MessageContext>
245+
pub context: Option<MessageContext>,
246+
247+
/// Custom data set by the user. If `custom_data` is `Some`, it will be returned when the
248+
/// blinded path is used.
249+
///
250+
/// This field allows encoding custom data intended to be retrieved when the blinded path is used.
251+
///
252+
/// ## Note on Forward Compatibility:
253+
/// Users can encode any kind of data into the `Vec<u8>` bytes here. However, they should ensure
254+
/// that the data is structured in a forward-compatible manner. This is especially important as
255+
/// `ReceiveTlvs` created in one version of the software may still appear in messages received
256+
/// shortly after a software upgrade. Proper forward compatibility helps prevent data loss or
257+
/// misinterpretation in future versions.
258+
pub custom_data: Option<Vec<u8>>,
245259
}
246260

247261
impl Writeable for ForwardTlvs {
@@ -265,6 +279,7 @@ impl Writeable for ReceiveTlvs {
265279
// TODO: write padding
266280
encode_tlv_stream!(writer, {
267281
(65537, self.context, option),
282+
(65539, self.custom_data, option),
268283
});
269284
Ok(())
270285
}
@@ -456,7 +471,7 @@ impl_writeable_tlv_based!(DNSResolverContext, {
456471
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
457472
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
458473
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],
459-
recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey,
474+
recipient_node_id: PublicKey, receive_tlvs: ReceiveTlvs, session_priv: &SecretKey,
460475
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
461476
let pks = intermediate_nodes.iter().map(|node| node.node_id)
462477
.chain(core::iter::once(recipient_node_id));
@@ -468,7 +483,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
468483
None => NextMessageHop::NodeId(pubkey),
469484
})
470485
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
471-
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) })));
486+
.chain(core::iter::once(ControlTlvs::Receive(receive_tlvs)));
472487

473488
let path = pks.zip(tlvs);
474489

lightning/src/ln/channelmanager.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use bitcoin::secp256k1::Secp256k1;
3333
use bitcoin::{secp256k1, Sequence, Weight};
3434

3535
use crate::events::FundingInfo;
36-
use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, OffersContext};
36+
use crate::blinded_path::message::{self, AsyncPaymentsContext, MessageContext, OffersContext};
3737
use crate::blinded_path::NodeIdLookUp;
3838
use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode};
3939
use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
@@ -10452,8 +10452,13 @@ where
1045210452
.map(|(node_id, _)| *node_id)
1045310453
.collect::<Vec<_>>();
1045410454

10455+
let receive_tlvs = message::ReceiveTlvs {
10456+
context: Some(context),
10457+
custom_data: None,
10458+
};
10459+
1045510460
self.message_router
10456-
.create_blinded_paths(recipient, context, peers, secp_ctx)
10461+
.create_blinded_paths(recipient, receive_tlvs, peers, secp_ctx)
1045710462
.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
1045810463
}
1045910464

@@ -10480,8 +10485,13 @@ where
1048010485
})
1048110486
.collect::<Vec<_>>();
1048210487

10488+
let receive_tlvs = message::ReceiveTlvs {
10489+
context: Some(MessageContext::Offers(context)),
10490+
custom_data: None,
10491+
};
10492+
1048310493
self.message_router
10484-
.create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
10494+
.create_compact_blinded_paths(recipient, receive_tlvs, peers, secp_ctx)
1048510495
.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
1048610496
}
1048710497

@@ -11952,7 +11962,7 @@ where
1195211962
L::Target: Logger,
1195311963
{
1195411964
fn handle_message(
11955-
&self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>,
11965+
&self, message: OffersMessage, context: Option<OffersContext>, custom_data: Option<Vec<u8>>, responder: Option<Responder>,
1195611966
) -> Option<(OffersMessage, ResponseInstruction)> {
1195711967
let secp_ctx = &self.secp_ctx;
1195811968
let expanded_key = &self.inbound_payment_key;
@@ -12095,7 +12105,7 @@ where
1209512105
let nonce = Nonce::from_entropy_source(&*self.entropy_source);
1209612106
let hmac = payment_hash.hmac_for_offer_payment(nonce, expanded_key);
1209712107
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash, nonce, hmac });
12098-
Some((OffersMessage::Invoice(invoice), responder.respond_with_reply_path(context)))
12108+
Some((OffersMessage::Invoice(invoice), responder.respond_with_reply_path(context, custom_data)))
1209912109
},
1210012110
Err(error) => Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
1210112111
}

lightning/src/ln/offers_tests.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ fn claim_bolt12_payment<'a, 'b, 'c>(
193193

194194
fn extract_offer_nonce<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> Nonce {
195195
match node.onion_messenger.peel_onion_message(message) {
196-
Ok(PeeledOnion::Receive(_, Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce })), _)) => nonce,
197-
Ok(PeeledOnion::Receive(_, context, _)) => panic!("Unexpected onion message context: {:?}", context),
196+
Ok(PeeledOnion::Receive(_, Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce })), _, _)) => nonce,
197+
Ok(PeeledOnion::Receive(_, context, _, _)) => panic!("Unexpected onion message context: {:?}", context),
198198
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
199199
Err(e) => panic!("Failed to process onion message {:?}", e),
200200
}
@@ -204,7 +204,7 @@ fn extract_invoice_request<'a, 'b, 'c>(
204204
node: &Node<'a, 'b, 'c>, message: &OnionMessage
205205
) -> (InvoiceRequest, BlindedMessagePath) {
206206
match node.onion_messenger.peel_onion_message(message) {
207-
Ok(PeeledOnion::Receive(message, _, reply_path)) => match message {
207+
Ok(PeeledOnion::Receive(message, _, _, reply_path)) => match message {
208208
ParsedOnionMessageContents::Offers(offers_message) => match offers_message {
209209
OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path.unwrap()),
210210
OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice),
@@ -221,7 +221,7 @@ fn extract_invoice_request<'a, 'b, 'c>(
221221

222222
fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> (Bolt12Invoice, BlindedMessagePath) {
223223
match node.onion_messenger.peel_onion_message(message) {
224-
Ok(PeeledOnion::Receive(message, _, reply_path)) => match message {
224+
Ok(PeeledOnion::Receive(message, _, _, reply_path)) => match message {
225225
ParsedOnionMessageContents::Offers(offers_message) => match offers_message {
226226
OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request),
227227
OffersMessage::Invoice(invoice) => (invoice, reply_path.unwrap()),
@@ -240,7 +240,7 @@ fn extract_invoice_error<'a, 'b, 'c>(
240240
node: &Node<'a, 'b, 'c>, message: &OnionMessage
241241
) -> InvoiceError {
242242
match node.onion_messenger.peel_onion_message(message) {
243-
Ok(PeeledOnion::Receive(message, _, _)) => match message {
243+
Ok(PeeledOnion::Receive(message, _, _, _)) => match message {
244244
ParsedOnionMessageContents::Offers(offers_message) => match offers_message {
245245
OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request),
246246
OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice),

lightning/src/ln/peer_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ impl OnionMessageHandler for IgnoringMessageHandler {
143143
}
144144

145145
impl OffersMessageHandler for IgnoringMessageHandler {
146-
fn handle_message(&self, _message: OffersMessage, _context: Option<OffersContext>, _responder: Option<Responder>) -> Option<(OffersMessage, ResponseInstruction)> {
146+
fn handle_message(&self, _message: OffersMessage, _context: Option<OffersContext>, _custom_data: Option<Vec<u8>>, _responder: Option<Responder>) -> Option<(OffersMessage, ResponseInstruction)> {
147147
None
148148
}
149149
}

0 commit comments

Comments
 (0)