Skip to content

Commit 9853bc7

Browse files
committed
Generalize onion message ForwardTlvs::next_node_id
Allow either using a node id or a short channel id when forwarding an onion message. This allows for a more compact representation of blinded paths, which is advantageous for reducing offer QR code size. Follow-up commits will implement handling the short channel id case as it requires looking up the destination node id.
1 parent 806fef5 commit 9853bc7

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use core::ops::Deref;
1717
/// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded
1818
/// route, they are encoded into [`BlindedHop::encrypted_payload`].
1919
pub(crate) struct ForwardTlvs {
20-
/// The node id of the next hop in the onion message's path.
21-
pub(crate) next_node_id: PublicKey,
20+
/// The next hop in the onion message's path.
21+
pub(crate) next_hop: NextHop,
2222
/// Senders to a blinded path use this value to concatenate the route they find to the
2323
/// introduction node with the blinded path.
2424
pub(crate) next_blinding_override: Option<PublicKey>,
@@ -32,11 +32,24 @@ pub(crate) struct ReceiveTlvs {
3232
pub(crate) path_id: Option<[u8; 32]>,
3333
}
3434

35+
/// The next hop to forward the onion message along its path.
36+
pub(crate) enum NextHop {
37+
/// The node id of the next hop.
38+
NodeId(PublicKey),
39+
/// The short channel id leading to the next hop.
40+
ShortChannelId(u64),
41+
}
42+
3543
impl Writeable for ForwardTlvs {
3644
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
45+
let (next_node_id, short_channel_id) = match self.next_hop {
46+
NextHop::NodeId(pubkey) => (Some(pubkey), None),
47+
NextHop::ShortChannelId(scid) => (None, Some(scid)),
48+
};
3749
// TODO: write padding
3850
encode_tlv_stream!(writer, {
39-
(4, self.next_node_id, required),
51+
(2, short_channel_id, option),
52+
(4, next_node_id, option),
4053
(8, self.next_blinding_override, option)
4154
});
4255
Ok(())
@@ -59,9 +72,8 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
5972
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
6073
let blinded_tlvs = unblinded_path.iter()
6174
.skip(1) // The first node's TLVs contains the next node's pubkey
62-
.map(|pk| {
63-
ControlTlvs::Forward(ForwardTlvs { next_node_id: *pk, next_blinding_override: None })
64-
})
75+
.map(|pk| ForwardTlvs { next_hop: NextHop::NodeId(*pk), next_blinding_override: None })
76+
.map(|tlvs| ControlTlvs::Forward(tlvs))
6577
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None })));
6678

6779
utils::construct_blinded_hops(secp_ctx, unblinded_path.iter(), blinded_tlvs, session_priv)
@@ -78,9 +90,13 @@ pub(crate) fn advance_path_by_one<NS: Deref, T: secp256k1::Signing + secp256k1::
7890
let mut s = Cursor::new(&encrypted_control_tlvs);
7991
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
8092
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
81-
Ok(ChaChaPolyReadAdapter { readable: ControlTlvs::Forward(ForwardTlvs {
82-
mut next_node_id, next_blinding_override,
83-
})}) => {
93+
Ok(ChaChaPolyReadAdapter {
94+
readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override })
95+
}) => {
96+
let mut next_node_id = match next_hop {
97+
NextHop::NodeId(pubkey) => pubkey,
98+
NextHop::ShortChannelId(_) => todo!(),
99+
};
84100
let mut new_blinding_point = match next_blinding_override {
85101
Some(blinding_point) => blinding_point,
86102
None => {

lightning/src/onion_message/messenger.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
1616
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
1717

1818
use crate::blinded_path::BlindedPath;
19-
use crate::blinded_path::message::{advance_path_by_one, ForwardTlvs, ReceiveTlvs};
19+
use crate::blinded_path::message::{advance_path_by_one, ForwardTlvs, NextHop, ReceiveTlvs};
2020
use crate::blinded_path::utils;
2121
use crate::events::{Event, EventHandler, EventsProvider};
2222
use crate::sign::{EntropySource, NodeSigner, Recipient};
@@ -647,9 +647,9 @@ where
647647
Ok(PeeledOnion::Receive(message, path_id, reply_path))
648648
},
649649
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
650-
next_node_id, next_blinding_override
650+
next_hop, next_blinding_override
651651
})), Some((next_hop_hmac, new_packet_bytes)))) => {
652-
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
652+
// TODO: we need to check whether `next_hop` is our node, in which case this is a dummy
653653
// blinded hop and this onion message is destined for us. In this situation, we should keep
654654
// unwrapping the onion layers to get to the final payload. Since we don't have the option
655655
// of creating blinded paths with dummy hops currently, we should be ok to not handle this
@@ -685,6 +685,11 @@ where
685685
onion_routing_packet: outgoing_packet,
686686
};
687687

688+
let next_node_id = match next_hop {
689+
NextHop::NodeId(pubkey) => pubkey,
690+
NextHop::ShortChannelId(_) => todo!(),
691+
};
692+
688693
Ok(PeeledOnion::Forward(next_node_id, onion_message))
689694
},
690695
Err(e) => {
@@ -1133,7 +1138,7 @@ fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + sec
11331138
if let Some(ss) = prev_control_tlvs_ss.take() {
11341139
payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(
11351140
ForwardTlvs {
1136-
next_node_id: unblinded_pk_opt.unwrap(),
1141+
next_hop: NextHop::NodeId(unblinded_pk_opt.unwrap()),
11371142
next_blinding_override: None,
11381143
}
11391144
)), ss));
@@ -1143,7 +1148,7 @@ fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + sec
11431148
} else if let Some((intro_node_id, blinding_pt)) = intro_node_id_blinding_pt.take() {
11441149
if let Some(control_tlvs_ss) = prev_control_tlvs_ss.take() {
11451150
payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
1146-
next_node_id: intro_node_id,
1151+
next_hop: NextHop::NodeId(intro_node_id),
11471152
next_blinding_override: Some(blinding_pt),
11481153
})), control_tlvs_ss));
11491154
}

lightning/src/onion_message/packet.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use bitcoin::secp256k1::PublicKey;
1313
use bitcoin::secp256k1::ecdh::SharedSecret;
1414

1515
use crate::blinded_path::BlindedPath;
16-
use crate::blinded_path::message::{ForwardTlvs, ReceiveTlvs};
16+
use crate::blinded_path::message::{ForwardTlvs, NextHop, ReceiveTlvs};
1717
use crate::blinded_path::utils::Padding;
1818
use crate::ln::msgs::DecodeError;
1919
use crate::ln::onion_utils;
@@ -284,20 +284,26 @@ impl Readable for ControlTlvs {
284284
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
285285
_init_and_read_tlv_stream!(r, {
286286
(1, _padding, option),
287-
(2, _short_channel_id, option),
287+
(2, short_channel_id, option),
288288
(4, next_node_id, option),
289289
(6, path_id, option),
290290
(8, next_blinding_override, option),
291291
});
292292
let _padding: Option<Padding> = _padding;
293-
let _short_channel_id: Option<u64> = _short_channel_id;
294293

295-
let valid_fwd_fmt = next_node_id.is_some() && path_id.is_none();
296-
let valid_recv_fmt = next_node_id.is_none() && next_blinding_override.is_none();
294+
let next_hop = match (short_channel_id, next_node_id) {
295+
(Some(_), Some(_)) => return Err(DecodeError::InvalidValue),
296+
(Some(scid), None) => Some(NextHop::ShortChannelId(scid)),
297+
(None, Some(pubkey)) => Some(NextHop::NodeId(pubkey)),
298+
(None, None) => None,
299+
};
300+
301+
let valid_fwd_fmt = next_hop.is_some() && path_id.is_none();
302+
let valid_recv_fmt = next_hop.is_none() && next_blinding_override.is_none();
297303

298304
let payload_fmt = if valid_fwd_fmt {
299305
ControlTlvs::Forward(ForwardTlvs {
300-
next_node_id: next_node_id.unwrap(),
306+
next_hop: next_hop.unwrap(),
301307
next_blinding_override,
302308
})
303309
} else if valid_recv_fmt {

0 commit comments

Comments
 (0)