Skip to content

Commit 572ee6e

Browse files
committed
Support onion message replies in OnionMessenger
Modify onion message handlers to return an optional response message for OnionMessenger to reply with. Also, add a ResponseErrorHandler for handling any errors that may occur when responding.
1 parent 046a998 commit 572ee6e

File tree

6 files changed

+152
-20
lines changed

6 files changed

+152
-20
lines changed

fuzz/src/onion_message.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use lightning::ln::script::ShutdownScript;
1111
use lightning::util::enforcing_trait_impls::EnforcingSigner;
1212
use lightning::util::logger::Logger;
1313
use lightning::util::ser::{Readable, Writeable, Writer};
14-
use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessenger};
14+
use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessenger, ResponseError, ResponseErrorHandler};
1515

1616
use crate::utils::test_logger;
1717

@@ -66,7 +66,15 @@ impl MessageRouter for TestMessageRouter {
6666
struct TestOffersMessageHandler {}
6767

6868
impl OffersMessageHandler for TestOffersMessageHandler {
69-
fn handle_message(&self, _message: OffersMessage) {}
69+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
70+
None
71+
}
72+
}
73+
74+
impl ResponseErrorHandler for TestOffersMessageHandler {
75+
fn handle_response_error(&self, _error: ResponseError) {
76+
unreachable!()
77+
}
7078
}
7179

7280
struct TestCustomMessage {}
@@ -90,14 +98,22 @@ struct TestCustomMessageHandler {}
9098

9199
impl CustomOnionMessageHandler for TestCustomMessageHandler {
92100
type CustomMessage = TestCustomMessage;
93-
fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
101+
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
102+
None
103+
}
94104
fn read_custom_message<R: io::Read>(&self, _message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
95105
let mut buf = Vec::new();
96106
buffer.read_to_end(&mut buf)?;
97107
return Ok(Some(TestCustomMessage {}))
98108
}
99109
}
100110

111+
impl ResponseErrorHandler for TestCustomMessageHandler {
112+
fn handle_response_error(&self, _error: ResponseError) {
113+
unreachable!()
114+
}
115+
}
116+
101117
pub struct VecWriter(pub Vec<u8>);
102118
impl Writer for VecWriter {
103119
fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {

lightning/src/ln/peer_handler.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer};
2727
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
2828
use crate::ln::wire;
2929
use crate::ln::wire::Encode;
30-
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
30+
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, ResponseError, ResponseErrorHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
3131
use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias};
3232
use crate::util::atomic_counter::AtomicCounter;
3333
use crate::util::logger::Logger;
@@ -103,18 +103,24 @@ impl OnionMessageHandler for IgnoringMessageHandler {
103103
}
104104
}
105105
impl OffersMessageHandler for IgnoringMessageHandler {
106-
fn handle_message(&self, _msg: OffersMessage) {}
106+
fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
107107
}
108108
impl CustomOnionMessageHandler for IgnoringMessageHandler {
109109
type CustomMessage = Infallible;
110-
fn handle_custom_message(&self, _msg: Infallible) {
110+
fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
111111
// Since we always return `None` in the read the handle method should never be called.
112112
unreachable!();
113113
}
114114
fn read_custom_message<R: io::Read>(&self, _msg_type: u64, _buffer: &mut R) -> Result<Option<Infallible>, msgs::DecodeError> where Self: Sized {
115115
Ok(None)
116116
}
117117
}
118+
impl ResponseErrorHandler for IgnoringMessageHandler {
119+
fn handle_response_error(&self, _error: ResponseError) {
120+
// Since handler implementations return None for a response.
121+
unreachable!();
122+
}
123+
}
118124

119125
impl CustomOnionMessageContents for Infallible {
120126
fn tlv_type(&self) -> u64 { unreachable!(); }

lightning/src/onion_message/functional_tests.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::blinded_path::BlindedPath;
1313
use crate::sign::{NodeSigner, Recipient};
1414
use crate::ln::features::InitFeatures;
1515
use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
16-
use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, SendError};
16+
use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, ResponseError, ResponseErrorHandler, SendError};
1717
use crate::util::ser::{Writeable, Writer};
1818
use crate::util::test_utils;
1919

@@ -56,7 +56,13 @@ impl MessageRouter for TestMessageRouter {
5656
struct TestOffersMessageHandler {}
5757

5858
impl OffersMessageHandler for TestOffersMessageHandler {
59-
fn handle_message(&self, _message: OffersMessage) {
59+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
60+
todo!()
61+
}
62+
}
63+
64+
impl ResponseErrorHandler for TestOffersMessageHandler {
65+
fn handle_response_error(&self, _error: ResponseError) {
6066
todo!()
6167
}
6268
}
@@ -102,8 +108,9 @@ impl Drop for TestCustomMessageHandler {
102108

103109
impl CustomOnionMessageHandler for TestCustomMessageHandler {
104110
type CustomMessage = TestCustomMessage;
105-
fn handle_custom_message(&self, _msg: Self::CustomMessage) {
111+
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
106112
self.num_messages_expected.fetch_sub(1, Ordering::SeqCst);
113+
None
107114
}
108115
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
109116
if message_type == CUSTOM_MESSAGE_TYPE {
@@ -115,6 +122,12 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
115122
}
116123
}
117124

125+
impl ResponseErrorHandler for TestCustomMessageHandler {
126+
fn handle_response_error(&self, _error: ResponseError) {
127+
todo!()
128+
}
129+
}
130+
118131
fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
119132
let mut nodes = Vec::new();
120133
for i in 0..num_messengers {

lightning/src/onion_message/messenger.rs

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,17 +202,39 @@ pub enum SendError {
202202
///
203203
/// [`IgnoringMessageHandler`]: crate::ln::peer_handler::IgnoringMessageHandler
204204
/// [`CustomMessage`]: Self::CustomMessage
205-
pub trait CustomOnionMessageHandler {
205+
pub trait CustomOnionMessageHandler: ResponseErrorHandler {
206206
/// The message known to the handler. To support multiple message types, you may want to make this
207207
/// an enum with a variant for each supported message.
208208
type CustomMessage: CustomOnionMessageContents;
209-
/// Called with the custom message that was received.
210-
fn handle_custom_message(&self, msg: Self::CustomMessage);
209+
210+
/// Called with the custom message that was received, returning a response to send, if any.
211+
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
212+
211213
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
212214
/// message type is unknown.
213215
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
214216
}
215217

218+
/// Handler for errors occurring when responding to an onion message.
219+
///
220+
/// Each message handler may choose to reply to an onion message with a response. This handler is
221+
/// used when an error occurs when responding.
222+
pub trait ResponseErrorHandler {
223+
/// Called if an error occurred when sending a response to the handled message.
224+
fn handle_response_error(&self, error: ResponseError);
225+
}
226+
227+
/// An error when replying to an onion message.
228+
#[derive(Debug, PartialEq, Eq)]
229+
pub enum ResponseError {
230+
/// Failed to get the node id from the [`NodeSigner`].
231+
GetNodeIdFailed,
232+
/// No reply path in the onion message.
233+
NoReplyPath,
234+
/// Failed to send the reply.
235+
Sending(SendError),
236+
}
237+
216238
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
217239
OnionMessenger<ES, NS, L, MR, OMH, CMH>
218240
where
@@ -297,6 +319,45 @@ where
297319
}
298320
}
299321

322+
fn respond_with_onion_message<T: CustomOnionMessageContents, EH: ResponseErrorHandler>(
323+
&self, response: OnionMessageContents<T>, path_id: Option<[u8; 32]>,
324+
reply_path: Option<BlindedPath>, error_handler: &EH
325+
) {
326+
let sender = match self.node_signer.get_node_id(Recipient::Node) {
327+
Ok(node_id) => node_id,
328+
Err(_) => {
329+
log_info!(
330+
self.logger, "No sender to respond to onion message with path_id {:02x?}",
331+
path_id
332+
);
333+
return error_handler.handle_response_error(ResponseError::GetNodeIdFailed);
334+
}
335+
};
336+
337+
let destination = match reply_path {
338+
Some(reply_path) => Destination::BlindedPath(reply_path),
339+
None => {
340+
log_info!(
341+
self.logger, "No reply path to respond to onion message with path_id {:02x?}",
342+
path_id
343+
);
344+
return error_handler.handle_response_error(ResponseError::NoReplyPath);
345+
},
346+
};
347+
348+
let intermediate_nodes = self.message_router.find_route(&sender, &destination);
349+
350+
log_info!(self.logger, "Responding to onion message with path_id {:02x?}", path_id);
351+
352+
if let Err(e) = self.send_onion_message(&intermediate_nodes, destination, response, None) {
353+
log_info!(
354+
self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}",
355+
path_id, e
356+
);
357+
return error_handler.handle_response_error(ResponseError::Sending(e));
358+
}
359+
}
360+
300361
#[cfg(test)]
301362
pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, VecDeque<msgs::OnionMessage>> {
302363
let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -340,7 +401,7 @@ where
340401
NS::Target: NodeSigner,
341402
L::Target: Logger,
342403
MR::Target: MessageRouter,
343-
OMH::Target: OffersMessageHandler,
404+
OMH::Target: OffersMessageHandler + Sized,
344405
CMH::Target: CustomOnionMessageHandler + Sized,
345406
{
346407
/// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
@@ -379,9 +440,27 @@ where
379440
log_info!(self.logger,
380441
"Received an onion message with path_id {:02x?} and {} reply_path",
381442
path_id, if reply_path.is_some() { "a" } else { "no" });
382-
match message {
383-
OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg),
384-
OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
443+
444+
let response = match message {
445+
OnionMessageContents::Offers(msg) => {
446+
self.offers_handler.handle_message(msg)
447+
.map(|msg| OnionMessageContents::Offers(msg))
448+
},
449+
OnionMessageContents::Custom(msg) => {
450+
self.custom_handler.handle_custom_message(msg)
451+
.map(|msg| OnionMessageContents::Custom(msg))
452+
},
453+
};
454+
455+
if let Some(response) = response {
456+
match response {
457+
OnionMessageContents::Offers(_) => self.respond_with_onion_message(
458+
response, path_id, reply_path, &*self.offers_handler
459+
),
460+
OnionMessageContents::Custom(_) => self.respond_with_onion_message(
461+
response, path_id, reply_path, &*self.custom_handler
462+
),
463+
}
385464
}
386465
},
387466
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {

lightning/src/onion_message/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ mod packet;
2727
mod functional_tests;
2828

2929
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
30-
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
30+
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OnionMessageContents, OnionMessenger, ResponseError, ResponseErrorHandler, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
3131
pub use self::offers::{OffersMessage, OffersMessageHandler};
3232
pub(crate) use self::packet::{ControlTlvs, Packet};

lightning/src/onion_message/offers.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::ln::msgs::DecodeError;
1919
use crate::offers::invoice_request::InvoiceRequest;
2020
use crate::offers::invoice::Invoice;
2121
use crate::offers::parse::ParseError;
22+
use crate::onion_message::messenger::{ResponseError, ResponseErrorHandler};
2223
use crate::routing::router::Router;
2324
use crate::sign::{EntropySource, NodeSigner, SignerProvider};
2425
use crate::util::logger::Logger;
@@ -34,10 +35,10 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68;
3435
/// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload.
3536
///
3637
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
37-
pub trait OffersMessageHandler {
38+
pub trait OffersMessageHandler: ResponseErrorHandler {
3839
/// Handles the given message by either responding with an [`Invoice`], sending a payment, or
3940
/// replying with an error.
40-
fn handle_message(&self, message: OffersMessage);
41+
fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage>;
4142
}
4243

4344
/// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].
@@ -122,7 +123,24 @@ where
122123
R::Target: Router,
123124
L::Target: Logger,
124125
{
125-
fn handle_message(&self, _message: OffersMessage) {
126+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
127+
todo!()
128+
}
129+
}
130+
131+
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
132+
ResponseErrorHandler for ChannelManager<M, T, ES, NS, SP, F, R, L>
133+
where
134+
M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
135+
T::Target: BroadcasterInterface,
136+
ES::Target: EntropySource,
137+
NS::Target: NodeSigner,
138+
SP::Target: SignerProvider,
139+
F::Target: FeeEstimator,
140+
R::Target: Router,
141+
L::Target: Logger,
142+
{
143+
fn handle_response_error(&self, _error: ResponseError) {
126144
todo!()
127145
}
128146
}

0 commit comments

Comments
 (0)