Skip to content

Commit 55f09e1

Browse files
committed
Support onion message replies in OnionMessenger
1 parent faede5e commit 55f09e1

File tree

6 files changed

+138
-20
lines changed

6 files changed

+138
-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, OffersMessage, OffersMessageHandler, OnionMessenger};
14+
use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessenger, ResponseError, ResponseErrorHandler};
1515

1616
use crate::utils::test_logger;
1717

@@ -56,7 +56,15 @@ pub extern "C" fn onion_message_run(data: *const u8, datalen: usize) {
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+
None
61+
}
62+
}
63+
64+
impl ResponseErrorHandler for TestOffersMessageHandler {
65+
fn handle_response_error(&self, _error: ResponseError) {
66+
unreachable!()
67+
}
6068
}
6169

6270
struct TestCustomMessage {}
@@ -80,14 +88,22 @@ struct TestCustomMessageHandler {}
8088

8189
impl CustomOnionMessageHandler for TestCustomMessageHandler {
8290
type CustomMessage = TestCustomMessage;
83-
fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
91+
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
92+
None
93+
}
8494
fn read_custom_message<R: io::Read>(&self, _message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
8595
let mut buf = Vec::new();
8696
buffer.read_to_end(&mut buf)?;
8797
return Ok(Some(TestCustomMessage {}))
8898
}
8999
}
90100

101+
impl ResponseErrorHandler for TestCustomMessageHandler {
102+
fn handle_response_error(&self, _error: ResponseError) {
103+
unreachable!()
104+
}
105+
}
106+
91107
pub struct VecWriter(pub Vec<u8>);
92108
impl Writer for VecWriter {
93109
fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {

lightning/src/ln/peer_handler.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer};
2626
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
2727
use crate::ln::wire;
2828
use crate::ln::wire::Encode;
29-
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
29+
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, ResponseError, ResponseErrorHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
3030
use crate::routing::gossip::{NetworkGraph, P2PGossipSync};
3131
use crate::util::atomic_counter::AtomicCounter;
3232
use crate::util::events::{MessageSendEvent, MessageSendEventsProvider, OnionMessageProvider};
@@ -95,18 +95,21 @@ impl OnionMessageHandler for IgnoringMessageHandler {
9595
}
9696
}
9797
impl OffersMessageHandler for IgnoringMessageHandler {
98-
fn handle_message(&self, _msg: OffersMessage) {}
98+
fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
9999
}
100100
impl CustomOnionMessageHandler for IgnoringMessageHandler {
101101
type CustomMessage = Infallible;
102-
fn handle_custom_message(&self, _msg: Infallible) {
102+
fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
103103
// Since we always return `None` in the read the handle method should never be called.
104104
unreachable!();
105105
}
106106
fn read_custom_message<R: io::Read>(&self, _msg_type: u64, _buffer: &mut R) -> Result<Option<Infallible>, msgs::DecodeError> where Self: Sized {
107107
Ok(None)
108108
}
109109
}
110+
impl ResponseErrorHandler for IgnoringMessageHandler {
111+
fn handle_response_error(&self, _error: ResponseError) {}
112+
}
110113

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

lightning/src/onion_message/functional_tests.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use crate::chain::keysinterface::{NodeSigner, Recipient};
1313
use crate::ln::features::InitFeatures;
1414
use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
15-
use super::{BlindedPath, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, SendError};
15+
use super::{BlindedPath, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, ResponseError, ResponseErrorHandler, SendError};
1616
use crate::util::ser::{Writeable, Writer};
1717
use crate::util::test_utils;
1818

@@ -37,7 +37,13 @@ impl MessengerNode {
3737
struct TestOffersMessageHandler {}
3838

3939
impl OffersMessageHandler for TestOffersMessageHandler {
40-
fn handle_message(&self, _message: OffersMessage) {
40+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
41+
todo!()
42+
}
43+
}
44+
45+
impl ResponseErrorHandler for TestOffersMessageHandler {
46+
fn handle_response_error(&self, _error: ResponseError) {
4147
todo!()
4248
}
4349
}
@@ -64,7 +70,9 @@ struct TestCustomMessageHandler {}
6470

6571
impl CustomOnionMessageHandler for TestCustomMessageHandler {
6672
type CustomMessage = TestCustomMessage;
67-
fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
73+
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
74+
None
75+
}
6876
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
6977
if message_type == CUSTOM_MESSAGE_TYPE {
7078
let mut buf = Vec::new();
@@ -76,6 +84,12 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
7684
}
7785
}
7886

87+
impl ResponseErrorHandler for TestCustomMessageHandler {
88+
fn handle_response_error(&self, _error: ResponseError) {
89+
todo!()
90+
}
91+
}
92+
7993
fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
8094
let mut nodes = Vec::new();
8195
for i in 0..num_messengers {

lightning/src/onion_message/messenger.rs

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,34 @@ pub enum SendError {
181181
///
182182
/// [`IgnoringMessageHandler`]: crate::ln::peer_handler::IgnoringMessageHandler
183183
/// [`CustomMessage`]: Self::CustomMessage
184-
pub trait CustomOnionMessageHandler {
184+
pub trait CustomOnionMessageHandler: ResponseErrorHandler {
185185
/// The message known to the handler. To support multiple message types, you may want to make this
186186
/// an enum with a variant for each supported message.
187187
type CustomMessage: CustomOnionMessageContents;
188-
/// Called with the custom message that was received.
189-
fn handle_custom_message(&self, msg: Self::CustomMessage);
188+
189+
/// Called with the custom message that was received, returning a response to send, if any.
190+
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
191+
190192
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
191193
/// message type is unknown.
192194
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
193195
}
194196

197+
///
198+
pub trait ResponseErrorHandler {
199+
/// Called if an error occurred when sending a response to the handled message.
200+
fn handle_response_error(&self, error: ResponseError);
201+
}
202+
203+
///
204+
#[derive(Debug, PartialEq, Eq)]
205+
pub enum ResponseError {
206+
///
207+
NoReplyPath,
208+
///
209+
Sending(SendError),
210+
}
211+
195212
impl<ES: Deref, NS: Deref, L: Deref, OMH: Deref, CMH: Deref> OnionMessenger<ES, NS, L, OMH, CMH>
196213
where
197214
ES::Target: EntropySource,
@@ -272,6 +289,38 @@ where
272289
}
273290
}
274291

292+
fn respond_with_onion_message<T: CustomOnionMessageContents, EH: ResponseErrorHandler>(
293+
&self, response: OnionMessageContents<T>, path_id: Option<[u8; 32]>,
294+
reply_path: Option<BlindedPath>, error_handler: &EH
295+
) {
296+
match reply_path {
297+
Some(reply_path) => {
298+
let intermediate_nodes = vec![]; // TODO: replace with Router trait
299+
let destination = Destination::BlindedPath(reply_path);
300+
301+
log_info!(self.logger, "Responding to onion message with path_id {:02x?}", path_id);
302+
let send_result = self.send_onion_message(
303+
&intermediate_nodes, destination, response, None
304+
);
305+
306+
if let Err(e) = send_result {
307+
log_info!(
308+
self.logger,
309+
"Failed responding to onion message with path_id {:02x?}: {:?}", path_id, e
310+
);
311+
error_handler.handle_response_error(ResponseError::Sending(e));
312+
}
313+
},
314+
None => {
315+
log_info!(
316+
self.logger, "No reply path to respond to onion message with path_id {:02x?}",
317+
path_id
318+
);
319+
error_handler.handle_response_error(ResponseError::NoReplyPath);
320+
},
321+
}
322+
}
323+
275324
#[cfg(test)]
276325
pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, VecDeque<msgs::OnionMessage>> {
277326
let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -314,7 +363,7 @@ where
314363
ES::Target: EntropySource,
315364
NS::Target: NodeSigner,
316365
L::Target: Logger,
317-
OMH::Target: OffersMessageHandler,
366+
OMH::Target: OffersMessageHandler + Sized,
318367
CMH::Target: CustomOnionMessageHandler + Sized,
319368
{
320369
/// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
@@ -353,9 +402,27 @@ where
353402
log_info!(self.logger,
354403
"Received an onion message with path_id {:02x?} and {} reply_path",
355404
path_id, if reply_path.is_some() { "a" } else { "no" });
356-
match message {
357-
OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg),
358-
OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
405+
406+
let response = match message {
407+
OnionMessageContents::Offers(msg) => {
408+
self.offers_handler.handle_message(msg)
409+
.map(|msg| OnionMessageContents::Offers(msg))
410+
},
411+
OnionMessageContents::Custom(msg) => {
412+
self.custom_handler.handle_custom_message(msg)
413+
.map(|msg| OnionMessageContents::Custom(msg))
414+
},
415+
};
416+
417+
if let Some(response) = response {
418+
match response {
419+
OnionMessageContents::Offers(_) => self.respond_with_onion_message(
420+
response, path_id, reply_path, &*self.offers_handler
421+
),
422+
OnionMessageContents::Custom(_) => self.respond_with_onion_message(
423+
response, path_id, reply_path, &*self.custom_handler
424+
),
425+
}
359426
}
360427
},
361428
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
@@ -30,6 +30,6 @@ mod functional_tests;
3030

3131
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
3232
pub use self::blinded_path::{BlindedPath, BlindedHop};
33-
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
33+
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, ResponseError, ResponseErrorHandler, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
3434
pub use self::offers::{OffersMessage, OffersMessageHandler};
3535
pub(crate) use self::packet::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::ln::msgs::DecodeError;
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::util::logger::Logger;
2526
use crate::util::ser::{ReadableArgs, Writeable, Writer};
@@ -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)