Skip to content

Commit b6e60e6

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 b83c7d4 commit b6e60e6

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

@@ -68,7 +68,15 @@ impl MessageRouter for TestMessageRouter {
6868
struct TestOffersMessageHandler {}
6969

7070
impl OffersMessageHandler for TestOffersMessageHandler {
71-
fn handle_message(&self, _message: OffersMessage) {}
71+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
72+
None
73+
}
74+
}
75+
76+
impl ResponseErrorHandler for TestOffersMessageHandler {
77+
fn handle_response_error(&self, _error: ResponseError) {
78+
unreachable!()
79+
}
7280
}
7381

7482
struct TestCustomMessage {}
@@ -92,14 +100,22 @@ struct TestCustomMessageHandler {}
92100

93101
impl CustomOnionMessageHandler for TestCustomMessageHandler {
94102
type CustomMessage = TestCustomMessage;
95-
fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
103+
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
104+
None
105+
}
96106
fn read_custom_message<R: io::Read>(&self, _message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
97107
let mut buf = Vec::new();
98108
buffer.read_to_end(&mut buf)?;
99109
return Ok(Some(TestCustomMessage {}))
100110
}
101111
}
102112

113+
impl ResponseErrorHandler for TestCustomMessageHandler {
114+
fn handle_response_error(&self, _error: ResponseError) {
115+
unreachable!()
116+
}
117+
}
118+
103119
pub struct VecWriter(pub Vec<u8>);
104120
impl Writer for VecWriter {
105121
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

@@ -58,7 +58,13 @@ impl MessageRouter for TestMessageRouter {
5858
struct TestOffersMessageHandler {}
5959

6060
impl OffersMessageHandler for TestOffersMessageHandler {
61-
fn handle_message(&self, _message: OffersMessage) {
61+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
62+
todo!()
63+
}
64+
}
65+
66+
impl ResponseErrorHandler for TestOffersMessageHandler {
67+
fn handle_response_error(&self, _error: ResponseError) {
6268
todo!()
6369
}
6470
}
@@ -104,8 +110,9 @@ impl Drop for TestCustomMessageHandler {
104110

105111
impl CustomOnionMessageHandler for TestCustomMessageHandler {
106112
type CustomMessage = TestCustomMessage;
107-
fn handle_custom_message(&self, _msg: Self::CustomMessage) {
113+
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
108114
self.num_messages_expected.fetch_sub(1, Ordering::SeqCst);
115+
None
109116
}
110117
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
111118
if message_type == CUSTOM_MESSAGE_TYPE {
@@ -117,6 +124,12 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
117124
}
118125
}
119126

127+
impl ResponseErrorHandler for TestCustomMessageHandler {
128+
fn handle_response_error(&self, _error: ResponseError) {
129+
todo!()
130+
}
131+
}
132+
120133
fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
121134
let mut nodes = Vec::new();
122135
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
@@ -207,17 +207,39 @@ pub enum SendError {
207207
///
208208
/// [`IgnoringMessageHandler`]: crate::ln::peer_handler::IgnoringMessageHandler
209209
/// [`CustomMessage`]: Self::CustomMessage
210-
pub trait CustomOnionMessageHandler {
210+
pub trait CustomOnionMessageHandler: ResponseErrorHandler {
211211
/// The message known to the handler. To support multiple message types, you may want to make this
212212
/// an enum with a variant for each supported message.
213213
type CustomMessage: CustomOnionMessageContents;
214-
/// Called with the custom message that was received.
215-
fn handle_custom_message(&self, msg: Self::CustomMessage);
214+
215+
/// Called with the custom message that was received, returning a response to send, if any.
216+
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
217+
216218
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
217219
/// message type is unknown.
218220
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
219221
}
220222

223+
/// Handler for errors occurring when responding to an onion message.
224+
///
225+
/// Each message handler may choose to reply to an onion message with a response. This handler is
226+
/// used when an error occurs when responding.
227+
pub trait ResponseErrorHandler {
228+
/// Called if an error occurred when sending a response to the handled message.
229+
fn handle_response_error(&self, error: ResponseError);
230+
}
231+
232+
/// An error when replying to an onion message.
233+
#[derive(Debug, PartialEq, Eq)]
234+
pub enum ResponseError {
235+
/// Failed to get the node id from the [`NodeSigner`].
236+
GetNodeIdFailed,
237+
/// No reply path in the onion message.
238+
NoReplyPath,
239+
/// Failed to send the reply.
240+
Sending(SendError),
241+
}
242+
221243
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
222244
OnionMessenger<ES, NS, L, MR, OMH, CMH>
223245
where
@@ -302,6 +324,45 @@ where
302324
}
303325
}
304326

327+
fn respond_with_onion_message<T: CustomOnionMessageContents, EH: ResponseErrorHandler>(
328+
&self, response: OnionMessageContents<T>, path_id: Option<[u8; 32]>,
329+
reply_path: Option<BlindedPath>, error_handler: &EH
330+
) {
331+
let sender = match self.node_signer.get_node_id(Recipient::Node) {
332+
Ok(node_id) => node_id,
333+
Err(_) => {
334+
log_info!(
335+
self.logger, "No sender to respond to onion message with path_id {:02x?}",
336+
path_id
337+
);
338+
return error_handler.handle_response_error(ResponseError::GetNodeIdFailed);
339+
}
340+
};
341+
342+
let destination = match reply_path {
343+
Some(reply_path) => Destination::BlindedPath(reply_path),
344+
None => {
345+
log_info!(
346+
self.logger, "No reply path to respond to onion message with path_id {:02x?}",
347+
path_id
348+
);
349+
return error_handler.handle_response_error(ResponseError::NoReplyPath);
350+
},
351+
};
352+
353+
let intermediate_nodes = self.message_router.find_route(&sender, &destination);
354+
355+
log_info!(self.logger, "Responding to onion message with path_id {:02x?}", path_id);
356+
357+
if let Err(e) = self.send_onion_message(&intermediate_nodes, destination, response, None) {
358+
log_info!(
359+
self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}",
360+
path_id, e
361+
);
362+
return error_handler.handle_response_error(ResponseError::Sending(e));
363+
}
364+
}
365+
305366
#[cfg(test)]
306367
pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, VecDeque<msgs::OnionMessage>> {
307368
let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -345,7 +406,7 @@ where
345406
NS::Target: NodeSigner,
346407
L::Target: Logger,
347408
MR::Target: MessageRouter,
348-
OMH::Target: OffersMessageHandler,
409+
OMH::Target: OffersMessageHandler + Sized,
349410
CMH::Target: CustomOnionMessageHandler + Sized,
350411
{
351412
/// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
@@ -384,9 +445,27 @@ where
384445
log_info!(self.logger,
385446
"Received an onion message with path_id {:02x?} and {} reply_path",
386447
path_id, if reply_path.is_some() { "a" } else { "no" });
387-
match message {
388-
OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg),
389-
OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
448+
449+
let response = match message {
450+
OnionMessageContents::Offers(msg) => {
451+
self.offers_handler.handle_message(msg)
452+
.map(|msg| OnionMessageContents::Offers(msg))
453+
},
454+
OnionMessageContents::Custom(msg) => {
455+
self.custom_handler.handle_custom_message(msg)
456+
.map(|msg| OnionMessageContents::Custom(msg))
457+
},
458+
};
459+
460+
if let Some(response) = response {
461+
match response {
462+
OnionMessageContents::Offers(_) => self.respond_with_onion_message(
463+
response, path_id, reply_path, &*self.offers_handler
464+
),
465+
OnionMessageContents::Custom(_) => self.respond_with_onion_message(
466+
response, path_id, reply_path, &*self.custom_handler
467+
),
468+
}
390469
}
391470
},
392471
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
@@ -20,6 +20,7 @@ use crate::offers::invoice_error::InvoiceError;
2020
use crate::offers::invoice_request::InvoiceRequest;
2121
use crate::offers::invoice::Invoice;
2222
use crate::offers::parse::ParseError;
23+
use crate::onion_message::messenger::{ResponseError, ResponseErrorHandler};
2324
use crate::routing::router::Router;
2425
use crate::sign::{EntropySource, NodeSigner, SignerProvider};
2526
use crate::util::logger::Logger;
@@ -35,10 +36,10 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68;
3536
/// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload.
3637
///
3738
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
38-
pub trait OffersMessageHandler {
39+
pub trait OffersMessageHandler: ResponseErrorHandler {
3940
/// Handles the given message by either responding with an [`Invoice`], sending a payment, or
4041
/// replying with an error.
41-
fn handle_message(&self, message: OffersMessage);
42+
fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage>;
4243
}
4344

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

0 commit comments

Comments
 (0)