Skip to content

Commit 1bd3f36

Browse files
Generate direct-connect event for private offline peers
Imagine an LSP with a mobile client. The LSP wants to pay an offer that client issued. It generates an onion messages invreq and sends it. The OnionMessenger notices it's not connected and searches the network graph. It doesn't find the mobile client so doesn't create a direct connect event. The message gets dropped and the payment fails. Here we start generating the DC event irrespective of the network graph so the LSP can use LSPS5 to wake the client.
1 parent 2460c46 commit 1bd3f36

File tree

5 files changed

+57
-28
lines changed

5 files changed

+57
-28
lines changed

fuzz/src/onion_message.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl MessageRouter for TestMessageRouter {
102102
fn find_path(
103103
&self, _sender: PublicKey, _peers: Vec<PublicKey>, destination: Destination,
104104
) -> Result<OnionMessagePath, ()> {
105-
Ok(OnionMessagePath { intermediate_nodes: vec![], destination, first_node_addresses: None })
105+
Ok(OnionMessagePath { intermediate_nodes: vec![], destination, first_node_addresses: vec![] })
106106
}
107107

108108
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(

lightning-dns-resolver/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ mod test {
222222
) -> Result<OnionMessagePath, ()> {
223223
Ok(OnionMessagePath {
224224
destination,
225-
first_node_addresses: None,
225+
first_node_addresses: Vec::new(),
226226
intermediate_nodes: Vec::new(),
227227
})
228228
}

lightning/src/events/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,9 @@ pub enum Event {
972972
ConnectionNeeded {
973973
/// The node id for the node needing a connection.
974974
node_id: PublicKey,
975-
/// Sockets for connecting to the node.
975+
/// Sockets for connecting to the node, if available. We don't require these addresses to be
976+
/// present in case the node id corresponds to a known peer that is offline and can be awoken,
977+
/// such as via the LSPS5 protocol.
976978
addresses: Vec<msgs::SocketAddress>,
977979
},
978980
/// Indicates a [`Bolt12Invoice`] in response to an [`InvoiceRequest`] or a [`Refund`] was

lightning/src/onion_message/functional_tests.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ fn two_unblinded_hops() {
419419
let path = OnionMessagePath {
420420
intermediate_nodes: vec![nodes[1].node_id],
421421
destination: Destination::Node(nodes[2].node_id),
422-
first_node_addresses: None,
422+
first_node_addresses: Vec::new(),
423423
};
424424

425425
nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap();
@@ -494,7 +494,7 @@ fn two_unblinded_two_blinded() {
494494
let path = OnionMessagePath {
495495
intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id],
496496
destination: Destination::BlindedPath(blinded_path),
497-
first_node_addresses: None,
497+
first_node_addresses: Vec::new(),
498498
};
499499

500500
nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap();
@@ -660,7 +660,7 @@ fn too_big_packet_error() {
660660
let path = OnionMessagePath {
661661
intermediate_nodes: hops,
662662
destination: Destination::Node(hop_node_id),
663-
first_node_addresses: None,
663+
first_node_addresses: Vec::new(),
664664
};
665665
let err = nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap_err();
666666
assert_eq!(err, SendError::TooBigPacket);
@@ -822,7 +822,7 @@ fn reply_path() {
822822
let path = OnionMessagePath {
823823
intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id],
824824
destination: Destination::Node(nodes[3].node_id),
825-
first_node_addresses: None,
825+
first_node_addresses: Vec::new(),
826826
};
827827
let intermediate_nodes = [
828828
MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None },
@@ -959,7 +959,7 @@ fn many_hops() {
959959
let path = OnionMessagePath {
960960
intermediate_nodes,
961961
destination: Destination::Node(nodes[num_nodes - 1].node_id),
962-
first_node_addresses: None,
962+
first_node_addresses: Vec::new(),
963963
};
964964
nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap();
965965
nodes[num_nodes - 1].custom_message_handler.expect_message(TestCustomMessage::Pong);
@@ -1012,6 +1012,29 @@ fn requests_peer_connection_for_buffered_messages() {
10121012
connect_peers(&nodes[0], &nodes[1]);
10131013
assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_some());
10141014
assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_none());
1015+
1016+
// Buffer an onion message for a disconnected node who is not in the network graph.
1017+
disconnect_peers(&nodes[0], &nodes[2]);
1018+
1019+
let message = TestCustomMessage::Ping;
1020+
let destination = Destination::Node(nodes[2].node_id);
1021+
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
1022+
nodes[0].messenger.send_onion_message(message.clone(), instructions.clone()).unwrap();
1023+
1024+
// Check that a ConnectionNeeded event for the peer is provided
1025+
let events = release_events(&nodes[0]);
1026+
assert_eq!(events.len(), 1);
1027+
match &events[0] {
1028+
Event::ConnectionNeeded { node_id, addresses } => {
1029+
assert_eq!(*node_id, nodes[2].node_id);
1030+
assert!(addresses.is_empty());
1031+
},
1032+
e => panic!("Unexpected event: {:?}", e),
1033+
}
1034+
1035+
// Release the buffered onion message when reconnected
1036+
connect_peers(&nodes[0], &nodes[2]);
1037+
assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[2].node_id).is_some());
10151038
}
10161039

10171040
#[test]

lightning/src/onion_message/messenger.rs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ where
210210
/// # Ok(OnionMessagePath {
211211
/// # intermediate_nodes: vec![hop_node_id1, hop_node_id2],
212212
/// # destination,
213-
/// # first_node_addresses: None,
213+
/// # first_node_addresses: Vec::new(),
214214
/// # })
215215
/// # }
216216
/// # fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
@@ -681,7 +681,7 @@ where
681681
Ok(OnionMessagePath {
682682
intermediate_nodes: vec![],
683683
destination,
684-
first_node_addresses: None,
684+
first_node_addresses: vec![],
685685
})
686686
} else {
687687
let node_details = network_graph
@@ -695,11 +695,19 @@ where
695695
Some((features, addresses))
696696
if features.supports_onion_messages() && addresses.len() > 0 =>
697697
{
698-
let first_node_addresses = Some(addresses.to_vec());
699698
Ok(OnionMessagePath {
700699
intermediate_nodes: vec![],
701700
destination,
702-
first_node_addresses,
701+
first_node_addresses: addresses.to_vec(),
702+
})
703+
},
704+
None => {
705+
// If the destination is an unannounced node, they may be a known peer that is offline and
706+
// can be woken by the sender.
707+
Ok(OnionMessagePath {
708+
intermediate_nodes: vec![],
709+
destination,
710+
first_node_addresses: vec![],
703711
})
704712
},
705713
_ => Err(()),
@@ -841,9 +849,9 @@ pub struct OnionMessagePath {
841849

842850
/// Addresses that may be used to connect to [`OnionMessagePath::first_node`].
843851
///
844-
/// Only needs to be set if a connection to the node is required. [`OnionMessenger`] may use
845-
/// this to initiate such a connection.
846-
pub first_node_addresses: Option<Vec<SocketAddress>>,
852+
/// Only needs to be filled in if a connection to the node is required and it is not a known peer.
853+
/// [`OnionMessenger`] may use this to initiate such a connection.
854+
pub first_node_addresses: Vec<SocketAddress>,
847855
}
848856

849857
impl OnionMessagePath {
@@ -1021,7 +1029,7 @@ pub fn create_onion_message_resolving_destination<
10211029
entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL,
10221030
network_graph: &ReadOnlyNetworkGraph, secp_ctx: &Secp256k1<secp256k1::All>,
10231031
mut path: OnionMessagePath, contents: T, reply_path: Option<BlindedMessagePath>,
1024-
) -> Result<(PublicKey, OnionMessage, Option<Vec<SocketAddress>>), SendError>
1032+
) -> Result<(PublicKey, OnionMessage, Vec<SocketAddress>), SendError>
10251033
where
10261034
ES::Target: EntropySource,
10271035
NS::Target: NodeSigner,
@@ -1054,7 +1062,7 @@ pub fn create_onion_message<ES: Deref, NS: Deref, NL: Deref, T: OnionMessageCont
10541062
entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL,
10551063
secp_ctx: &Secp256k1<secp256k1::All>, path: OnionMessagePath, contents: T,
10561064
reply_path: Option<BlindedMessagePath>,
1057-
) -> Result<(PublicKey, OnionMessage, Option<Vec<SocketAddress>>), SendError>
1065+
) -> Result<(PublicKey, OnionMessage, Vec<SocketAddress>), SendError>
10581066
where
10591067
ES::Target: EntropySource,
10601068
NS::Target: NodeSigner,
@@ -1515,7 +1523,7 @@ where
15151523
// If this onion message is being treated as a forward, we shouldn't pathfind to the next hop.
15161524
OnionMessagePath {
15171525
intermediate_nodes: Vec::new(),
1518-
first_node_addresses: None,
1526+
first_node_addresses: Vec::new(),
15191527
destination,
15201528
}
15211529
} else {
@@ -1633,23 +1641,19 @@ where
16331641
}
16341642

16351643
fn enqueue_outbound_onion_message(
1636-
&self, onion_message: OnionMessage, first_node_id: PublicKey,
1637-
addresses: Option<Vec<SocketAddress>>,
1644+
&self, onion_message: OnionMessage, first_node_id: PublicKey, addresses: Vec<SocketAddress>,
16381645
) -> Result<SendSuccess, SendError> {
16391646
let mut message_recipients = self.message_recipients.lock().unwrap();
16401647
if outbound_buffer_full(&first_node_id, &message_recipients) {
16411648
return Err(SendError::BufferFull);
16421649
}
16431650

16441651
match message_recipients.entry(first_node_id) {
1645-
hash_map::Entry::Vacant(e) => match addresses {
1646-
None => Err(SendError::InvalidFirstHop(first_node_id)),
1647-
Some(addresses) => {
1648-
e.insert(OnionMessageRecipient::pending_connection(addresses))
1649-
.enqueue_message(onion_message);
1650-
self.event_notifier.notify();
1651-
Ok(SendSuccess::BufferedAwaitingConnection(first_node_id))
1652-
},
1652+
hash_map::Entry::Vacant(e) => {
1653+
e.insert(OnionMessageRecipient::pending_connection(addresses))
1654+
.enqueue_message(onion_message);
1655+
self.event_notifier.notify();
1656+
Ok(SendSuccess::BufferedAwaitingConnection(first_node_id))
16531657
},
16541658
hash_map::Entry::Occupied(mut e) => {
16551659
e.get_mut().enqueue_message(onion_message);

0 commit comments

Comments
 (0)