Skip to content

Commit b6c7006

Browse files
committed
Look up node id from scid in OnionMessenger
When forwarding onion messages, the next node may be represented by a short channel id instead of a node id. Parameterize OnionMessenger with a NodeIdLookUp trait to find which node is the next hop. Implement the trait for ChannelManager for forwarding to channel counterparties. Also use this trait when advancing a blinded path one hop when the sender is the introduction node.
1 parent 80d6250 commit b6c7006

File tree

6 files changed

+95
-31
lines changed

6 files changed

+95
-31
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
33
#[allow(unused_imports)]
44
use crate::prelude::*;
55

6-
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
6+
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
77
use crate::blinded_path::utils;
88
use crate::io;
99
use crate::io::Cursor;
@@ -84,9 +84,14 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
8484

8585
// Advance the blinded onion message path by one hop, so make the second hop into the new
8686
// introduction node.
87-
pub(crate) fn advance_path_by_one<NS: Deref, T: secp256k1::Signing + secp256k1::Verification>(
88-
path: &mut BlindedPath, node_signer: &NS, secp_ctx: &Secp256k1<T>
89-
) -> Result<(), ()> where NS::Target: NodeSigner {
87+
pub(crate) fn advance_path_by_one<NS: Deref, NL: Deref, T>(
88+
path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
89+
) -> Result<(), ()>
90+
where
91+
NS::Target: NodeSigner,
92+
NL::Target: NodeIdLookUp,
93+
T: secp256k1::Signing + secp256k1::Verification,
94+
{
9095
let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?;
9196
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
9297
let encrypted_control_tlvs = path.blinded_hops.remove(0).encrypted_payload;
@@ -98,7 +103,10 @@ pub(crate) fn advance_path_by_one<NS: Deref, T: secp256k1::Signing + secp256k1::
98103
}) => {
99104
let next_node_id = match next_hop {
100105
NextHop::NodeId(pubkey) => pubkey,
101-
NextHop::ShortChannelId(_) => todo!(),
106+
NextHop::ShortChannelId(scid) => match node_id_lookup.next_node_id(scid) {
107+
Some(pubkey) => pubkey,
108+
None => return Err(()),
109+
},
102110
};
103111
let mut new_blinding_point = match next_blinding_override {
104112
Some(blinding_point) => blinding_point,

lightning/src/blinded_path/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@ pub enum Direction {
6666
NodeTwo,
6767
}
6868

69+
/// An interface for looking up the node id of a channel counterparty for the purpose of forwarding
70+
/// an [`OnionMessage`].
71+
///
72+
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
73+
pub trait NodeIdLookUp {
74+
/// Returns the node if of the channel counterparty with `short_channel_id`.
75+
fn next_node_id(&self, short_channel_id: u64) -> Option<PublicKey>;
76+
}
77+
78+
/// A [`NodeIdLookUp`] that always returns `None`.
79+
pub struct EmptyNodeIdLookUp {}
80+
81+
impl NodeIdLookUp for EmptyNodeIdLookUp {
82+
fn next_node_id(&self, _short_channel_id: u64) -> Option<PublicKey> {
83+
None
84+
}
85+
}
86+
6987
/// An encrypted payload and node id corresponding to a hop in a payment or onion message path, to
7088
/// be encoded in the sender's onion packet. These hops cannot be identified by outside observers
7189
/// and thus can be used to hide the identity of the recipient.

lightning/src/ln/channelmanager.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey};
3131
use bitcoin::secp256k1::Secp256k1;
3232
use bitcoin::{secp256k1, Sequence};
3333

34-
use crate::blinded_path::BlindedPath;
34+
use crate::blinded_path::{BlindedPath, NodeIdLookUp};
3535
use crate::blinded_path::payment::{PaymentConstraints, ReceiveTlvs};
3636
use crate::chain;
3737
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
@@ -10433,6 +10433,23 @@ where
1043310433
}
1043410434
}
1043510435

10436+
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
10437+
NodeIdLookUp for ChannelManager<M, T, ES, NS, SP, F, R, L>
10438+
where
10439+
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
10440+
T::Target: BroadcasterInterface,
10441+
ES::Target: EntropySource,
10442+
NS::Target: NodeSigner,
10443+
SP::Target: SignerProvider,
10444+
F::Target: FeeEstimator,
10445+
R::Target: Router,
10446+
L::Target: Logger,
10447+
{
10448+
fn next_node_id(&self, short_channel_id: u64) -> Option<PublicKey> {
10449+
self.short_to_chan_info.read().unwrap().get(&short_channel_id).map(|(pubkey, _)| *pubkey)
10450+
}
10451+
}
10452+
1043610453
/// Fetches the set of [`NodeFeatures`] flags that are provided by or required by
1043710454
/// [`ChannelManager`].
1043810455
pub(crate) fn provided_node_features(config: &UserConfig) -> NodeFeatures {

lightning/src/ln/functional_test_utils.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ type TestOnionMessenger<'chan_man, 'node_cfg, 'chan_mon_cfg> = OnionMessenger<
415415
DedicatedEntropy,
416416
&'node_cfg test_utils::TestKeysInterface,
417417
&'chan_mon_cfg test_utils::TestLogger,
418+
&'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>,
418419
&'node_cfg test_utils::TestMessageRouter<'chan_mon_cfg>,
419420
&'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>,
420421
IgnoringMessageHandler,
@@ -3199,8 +3200,8 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
31993200
for i in 0..node_count {
32003201
let dedicated_entropy = DedicatedEntropy(RandomBytes::new([i as u8; 32]));
32013202
let onion_messenger = OnionMessenger::new(
3202-
dedicated_entropy, cfgs[i].keys_manager, cfgs[i].logger, &cfgs[i].message_router,
3203-
&chan_mgrs[i], IgnoringMessageHandler {},
3203+
dedicated_entropy, cfgs[i].keys_manager, cfgs[i].logger, &chan_mgrs[i],
3204+
&cfgs[i].message_router, &chan_mgrs[i], IgnoringMessageHandler {},
32043205
);
32053206
let gossip_sync = P2PGossipSync::new(cfgs[i].network_graph.as_ref(), None, cfgs[i].logger);
32063207
let wallet_source = Arc::new(test_utils::TestWalletSource::new(SecretKey::from_slice(&[i as u8 + 1; 32]).unwrap()));

lightning/src/onion_message/functional_tests.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
//! Onion message testing and test utilities live here.
1111
12-
use crate::blinded_path::BlindedPath;
12+
use crate::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
1313
use crate::events::{Event, EventsProvider};
1414
use crate::ln::features::{ChannelFeatures, InitFeatures};
1515
use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
@@ -42,6 +42,7 @@ struct MessengerNode {
4242
Arc<test_utils::TestKeysInterface>,
4343
Arc<test_utils::TestNodeSigner>,
4444
Arc<test_utils::TestLogger>,
45+
Arc<EmptyNodeIdLookUp>,
4546
Arc<DefaultMessageRouter<
4647
Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
4748
Arc<test_utils::TestLogger>,
@@ -175,6 +176,7 @@ fn create_nodes_using_secrets(secrets: Vec<SecretKey>) -> Vec<MessengerNode> {
175176
let entropy_source = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet));
176177
let node_signer = Arc::new(test_utils::TestNodeSigner::new(secret_key));
177178

179+
let node_id_lookup = Arc::new(EmptyNodeIdLookUp {});
178180
let message_router = Arc::new(
179181
DefaultMessageRouter::new(network_graph.clone(), entropy_source.clone())
180182
);
@@ -185,7 +187,7 @@ fn create_nodes_using_secrets(secrets: Vec<SecretKey>) -> Vec<MessengerNode> {
185187
node_id: node_signer.get_node_id(Recipient::Node).unwrap(),
186188
entropy_source: entropy_source.clone(),
187189
messenger: OnionMessenger::new(
188-
entropy_source, node_signer, logger.clone(), message_router,
190+
entropy_source, node_signer, logger.clone(), node_id_lookup, message_router,
189191
offers_message_handler, custom_message_handler.clone()
190192
),
191193
custom_message_handler,

lightning/src/onion_message/messenger.rs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine};
1515
use bitcoin::hashes::sha256::Hash as Sha256;
1616
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
1717

18-
use crate::blinded_path::{BlindedPath, IntroductionNode};
18+
use crate::blinded_path::{BlindedPath, IntroductionNode, NodeIdLookUp};
1919
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};
@@ -70,7 +70,7 @@ pub(super) const MAX_TIMER_TICKS: usize = 2;
7070
/// # use bitcoin::hashes::_export::_core::time::Duration;
7171
/// # use bitcoin::hashes::hex::FromHex;
7272
/// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self};
73-
/// # use lightning::blinded_path::BlindedPath;
73+
/// # use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
7474
/// # use lightning::sign::{EntropySource, KeysManager};
7575
/// # use lightning::ln::peer_handler::IgnoringMessageHandler;
7676
/// # use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath, OnionMessenger};
@@ -111,14 +111,15 @@ pub(super) const MAX_TIMER_TICKS: usize = 2;
111111
/// # let hop_node_id1 = PublicKey::from_secret_key(&secp_ctx, &node_secret);
112112
/// # let (hop_node_id3, hop_node_id4) = (hop_node_id1, hop_node_id1);
113113
/// # let destination_node_id = hop_node_id1;
114+
/// # let node_id_lookup = EmptyNodeIdLookUp {};
114115
/// # let message_router = Arc::new(FakeMessageRouter {});
115116
/// # let custom_message_handler = IgnoringMessageHandler {};
116117
/// # let offers_message_handler = IgnoringMessageHandler {};
117118
/// // Create the onion messenger. This must use the same `keys_manager` as is passed to your
118119
/// // ChannelManager.
119120
/// let onion_messenger = OnionMessenger::new(
120-
/// &keys_manager, &keys_manager, logger, message_router, &offers_message_handler,
121-
/// &custom_message_handler
121+
/// &keys_manager, &keys_manager, logger, &node_id_lookup, message_router,
122+
/// &offers_message_handler, &custom_message_handler
122123
/// );
123124
124125
/// # #[derive(Debug)]
@@ -155,11 +156,12 @@ pub(super) const MAX_TIMER_TICKS: usize = 2;
155156
///
156157
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
157158
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
158-
pub struct OnionMessenger<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
159+
pub struct OnionMessenger<ES: Deref, NS: Deref, L: Deref, NL: Deref, MR: Deref, OMH: Deref, CMH: Deref>
159160
where
160161
ES::Target: EntropySource,
161162
NS::Target: NodeSigner,
162163
L::Target: Logger,
164+
NL::Target: NodeIdLookUp,
163165
MR::Target: MessageRouter,
164166
OMH::Target: OffersMessageHandler,
165167
CMH::Target: CustomOnionMessageHandler,
@@ -169,6 +171,7 @@ where
169171
logger: L,
170172
message_recipients: Mutex<HashMap<PublicKey, OnionMessageRecipient>>,
171173
secp_ctx: Secp256k1<secp256k1::All>,
174+
node_id_lookup: NL,
172175
message_router: MR,
173176
offers_handler: OMH,
174177
custom_handler: CMH,
@@ -579,13 +582,15 @@ pub enum PeeledOnion<T: OnionMessageContents> {
579582
///
580583
/// Returns the node id of the peer to send the message to, the message itself, and any addresses
581584
/// need to connect to the first node.
582-
pub fn create_onion_message<ES: Deref, NS: Deref, T: OnionMessageContents>(
583-
entropy_source: &ES, node_signer: &NS, secp_ctx: &Secp256k1<secp256k1::All>,
584-
path: OnionMessagePath, contents: T, reply_path: Option<BlindedPath>,
585+
pub fn create_onion_message<ES: Deref, NS: Deref, NL: Deref, T: OnionMessageContents>(
586+
entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL,
587+
secp_ctx: &Secp256k1<secp256k1::All>, path: OnionMessagePath, contents: T,
588+
reply_path: Option<BlindedPath>,
585589
) -> Result<(PublicKey, OnionMessage, Option<Vec<SocketAddress>>), SendError>
586590
where
587591
ES::Target: EntropySource,
588592
NS::Target: NodeSigner,
593+
NL::Target: NodeIdLookUp,
589594
{
590595
let OnionMessagePath { intermediate_nodes, mut destination, first_node_addresses } = path;
591596
if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination {
@@ -609,7 +614,7 @@ where
609614
let our_node_id = node_signer.get_node_id(Recipient::Node)
610615
.map_err(|()| SendError::GetNodeIdFailed)?;
611616
if introduction_node_id == our_node_id {
612-
advance_path_by_one(blinded_path, node_signer, &secp_ctx)
617+
advance_path_by_one(blinded_path, node_signer, node_id_lookup, &secp_ctx)
613618
.map_err(|()| SendError::BlindedPathAdvanceFailed)?;
614619
}
615620
}
@@ -741,21 +746,22 @@ where
741746
}
742747
}
743748

744-
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
745-
OnionMessenger<ES, NS, L, MR, OMH, CMH>
749+
impl<ES: Deref, NS: Deref, L: Deref, NL: Deref, MR: Deref, OMH: Deref, CMH: Deref>
750+
OnionMessenger<ES, NS, L, NL, MR, OMH, CMH>
746751
where
747752
ES::Target: EntropySource,
748753
NS::Target: NodeSigner,
749754
L::Target: Logger,
755+
NL::Target: NodeIdLookUp,
750756
MR::Target: MessageRouter,
751757
OMH::Target: OffersMessageHandler,
752758
CMH::Target: CustomOnionMessageHandler,
753759
{
754760
/// Constructs a new `OnionMessenger` to send, forward, and delegate received onion messages to
755761
/// their respective handlers.
756762
pub fn new(
757-
entropy_source: ES, node_signer: NS, logger: L, message_router: MR, offers_handler: OMH,
758-
custom_handler: CMH
763+
entropy_source: ES, node_signer: NS, logger: L, node_id_lookup: NL, message_router: MR,
764+
offers_handler: OMH, custom_handler: CMH
759765
) -> Self {
760766
let mut secp_ctx = Secp256k1::new();
761767
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
@@ -765,6 +771,7 @@ where
765771
message_recipients: Mutex::new(new_hash_map()),
766772
secp_ctx,
767773
logger,
774+
node_id_lookup,
768775
message_router,
769776
offers_handler,
770777
custom_handler,
@@ -847,7 +854,8 @@ where
847854
log_trace!(self.logger, "Constructing onion message {}: {:?}", log_suffix, contents);
848855

849856
let (first_node_id, onion_message, addresses) = create_onion_message(
850-
&self.entropy_source, &self.node_signer, &self.secp_ctx, path, contents, reply_path
857+
&self.entropy_source, &self.node_signer, &self.node_id_lookup, &self.secp_ctx, path,
858+
contents, reply_path,
851859
)?;
852860

853861
let mut message_recipients = self.message_recipients.lock().unwrap();
@@ -943,12 +951,13 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap<PublicKey, On
943951
false
944952
}
945953

946-
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref> EventsProvider
947-
for OnionMessenger<ES, NS, L, MR, OMH, CMH>
954+
impl<ES: Deref, NS: Deref, L: Deref, NL: Deref, MR: Deref, OMH: Deref, CMH: Deref> EventsProvider
955+
for OnionMessenger<ES, NS, L, NL, MR, OMH, CMH>
948956
where
949957
ES::Target: EntropySource,
950958
NS::Target: NodeSigner,
951959
L::Target: Logger,
960+
NL::Target: NodeIdLookUp,
952961
MR::Target: MessageRouter,
953962
OMH::Target: OffersMessageHandler,
954963
CMH::Target: CustomOnionMessageHandler,
@@ -964,12 +973,13 @@ where
964973
}
965974
}
966975

967-
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref> OnionMessageHandler
968-
for OnionMessenger<ES, NS, L, MR, OMH, CMH>
976+
impl<ES: Deref, NS: Deref, L: Deref, NL: Deref, MR: Deref, OMH: Deref, CMH: Deref> OnionMessageHandler
977+
for OnionMessenger<ES, NS, L, NL, MR, OMH, CMH>
969978
where
970979
ES::Target: EntropySource,
971980
NS::Target: NodeSigner,
972981
L::Target: Logger,
982+
NL::Target: NodeIdLookUp,
973983
MR::Target: MessageRouter,
974984
OMH::Target: OffersMessageHandler,
975985
CMH::Target: CustomOnionMessageHandler,
@@ -1007,7 +1017,13 @@ where
10071017
Ok(PeeledOnion::Forward(next_hop, onion_message)) => {
10081018
let next_node_id = match next_hop {
10091019
NextHop::NodeId(pubkey) => pubkey,
1010-
NextHop::ShortChannelId(_) => todo!(),
1020+
NextHop::ShortChannelId(scid) => match self.node_id_lookup.next_node_id(scid) {
1021+
Some(pubkey) => pubkey,
1022+
None => {
1023+
log_trace!(self.logger, "Dropping forwarded onion message to unresolved peer using SCID {}", scid);
1024+
return
1025+
},
1026+
},
10111027
};
10121028

10131029
let mut message_recipients = self.message_recipients.lock().unwrap();
@@ -1145,6 +1161,7 @@ pub type SimpleArcOnionMessenger<M, T, F, L> = OnionMessenger<
11451161
Arc<KeysManager>,
11461162
Arc<KeysManager>,
11471163
Arc<L>,
1164+
Arc<SimpleArcChannelManager<M, T, F, L>>,
11481165
Arc<DefaultMessageRouter<Arc<NetworkGraph<Arc<L>>>, Arc<L>, Arc<KeysManager>>>,
11491166
Arc<SimpleArcChannelManager<M, T, F, L>>,
11501167
IgnoringMessageHandler
@@ -1164,8 +1181,9 @@ pub type SimpleRefOnionMessenger<
11641181
&'a KeysManager,
11651182
&'a KeysManager,
11661183
&'b L,
1167-
&'i DefaultMessageRouter<&'g NetworkGraph<&'b L>, &'b L, &'a KeysManager>,
1168-
&'j SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L>,
1184+
&'i SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L>,
1185+
&'j DefaultMessageRouter<&'g NetworkGraph<&'b L>, &'b L, &'a KeysManager>,
1186+
&'i SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L>,
11691187
IgnoringMessageHandler
11701188
>;
11711189

0 commit comments

Comments
 (0)