Skip to content

Commit 85ba6fd

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 4b40122 commit 85ba6fd

File tree

7 files changed

+165
-21
lines changed

7 files changed

+165
-21
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, OnionMessagePath, OnionMessenger};
14+
use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessagePath, 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/channelmanager.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VA
5555
use crate::ln::outbound_payment;
5656
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment};
5757
use crate::ln::wire::Encode;
58-
use crate::onion_message::{OffersMessage, OffersMessageHandler};
58+
use crate::onion_message::{OffersMessage, OffersMessageHandler, ResponseError, ResponseErrorHandler};
5959
use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner};
6060
use crate::util::config::{UserConfig, ChannelConfig};
6161
use crate::util::wakers::{Future, Notifier};
@@ -7055,7 +7055,25 @@ where
70557055
R::Target: Router,
70567056
L::Target: Logger,
70577057
{
7058-
fn handle_message(&self, _message: OffersMessage) {
7058+
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
7059+
None
7060+
}
7061+
}
7062+
7063+
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
7064+
ResponseErrorHandler for ChannelManager<M, T, ES, NS, SP, F, R, L>
7065+
where
7066+
M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
7067+
T::Target: BroadcasterInterface,
7068+
ES::Target: EntropySource,
7069+
NS::Target: NodeSigner,
7070+
SP::Target: SignerProvider,
7071+
F::Target: FeeEstimator,
7072+
R::Target: Router,
7073+
L::Target: Logger,
7074+
{
7075+
fn handle_response_error(&self, _error: ResponseError) {
7076+
todo!()
70597077
}
70607078
}
70617079

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, Type};
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;
@@ -117,18 +117,24 @@ impl OnionMessageHandler for IgnoringMessageHandler {
117117
}
118118
}
119119
impl OffersMessageHandler for IgnoringMessageHandler {
120-
fn handle_message(&self, _msg: OffersMessage) {}
120+
fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
121121
}
122122
impl CustomOnionMessageHandler for IgnoringMessageHandler {
123123
type CustomMessage = Infallible;
124-
fn handle_custom_message(&self, _msg: Infallible) {
124+
fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
125125
// Since we always return `None` in the read the handle method should never be called.
126126
unreachable!();
127127
}
128128
fn read_custom_message<R: io::Read>(&self, _msg_type: u64, _buffer: &mut R) -> Result<Option<Infallible>, msgs::DecodeError> where Self: Sized {
129129
Ok(None)
130130
}
131131
}
132+
impl ResponseErrorHandler for IgnoringMessageHandler {
133+
fn handle_response_error(&self, _error: ResponseError) {
134+
// Since handler implementations return None for a response.
135+
unreachable!();
136+
}
137+
}
132138

133139
impl CustomOnionMessageContents for Infallible {
134140
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, OnionMessagePath, OnionMessenger, SendError};
16+
use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, 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: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,41 @@ pub enum SendError {
221221
///
222222
/// [`IgnoringMessageHandler`]: crate::ln::peer_handler::IgnoringMessageHandler
223223
/// [`CustomMessage`]: Self::CustomMessage
224-
pub trait CustomOnionMessageHandler {
224+
pub trait CustomOnionMessageHandler: ResponseErrorHandler {
225225
/// The message known to the handler. To support multiple message types, you may want to make this
226226
/// an enum with a variant for each supported message.
227227
type CustomMessage: CustomOnionMessageContents;
228-
/// Called with the custom message that was received.
229-
fn handle_custom_message(&self, msg: Self::CustomMessage);
228+
229+
/// Called with the custom message that was received, returning a response to send, if any.
230+
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
231+
230232
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
231233
/// message type is unknown.
232234
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
233235
}
234236

237+
/// Handler for errors occurring when responding to an onion message.
238+
///
239+
/// Each message handler may choose to reply to an onion message with a response. This handler is
240+
/// used when an error occurs when responding.
241+
pub trait ResponseErrorHandler {
242+
/// Called if an error occurred when sending a response to the handled message.
243+
fn handle_response_error(&self, error: ResponseError);
244+
}
245+
246+
/// An error when replying to an onion message.
247+
#[derive(Debug, PartialEq, Eq)]
248+
pub enum ResponseError {
249+
/// Failed to get the node id from the [`NodeSigner`].
250+
GetNodeIdFailed,
251+
/// No reply path in the onion message.
252+
NoReplyPath,
253+
/// Could not find a path to the destination.
254+
PathNotFound,
255+
/// Failed to send the reply.
256+
Sending(SendError),
257+
}
258+
235259
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
236260
OnionMessenger<ES, NS, L, MR, OMH, CMH>
237261
where
@@ -321,6 +345,54 @@ where
321345
}
322346
}
323347

348+
fn respond_with_onion_message<T: CustomOnionMessageContents, EH: ResponseErrorHandler>(
349+
&self, response: OnionMessageContents<T>, path_id: Option<[u8; 32]>,
350+
reply_path: Option<BlindedPath>, error_handler: &EH
351+
) {
352+
let sender = match self.node_signer.get_node_id(Recipient::Node) {
353+
Ok(node_id) => node_id,
354+
Err(_) => {
355+
log_info!(
356+
self.logger, "No sender to respond to onion message with path_id {:02x?}",
357+
path_id
358+
);
359+
return error_handler.handle_response_error(ResponseError::GetNodeIdFailed);
360+
}
361+
};
362+
363+
let destination = match reply_path {
364+
Some(reply_path) => Destination::BlindedPath(reply_path),
365+
None => {
366+
log_info!(
367+
self.logger, "No reply path to respond to onion message with path_id {:02x?}",
368+
path_id
369+
);
370+
return error_handler.handle_response_error(ResponseError::NoReplyPath);
371+
},
372+
};
373+
374+
let path = match self.message_router.find_path(&sender, destination) {
375+
Ok(path) => path,
376+
Err(()) => {
377+
log_info!(
378+
self.logger, "No path to respond to onion message with path_id {:02x?}",
379+
path_id
380+
);
381+
return error_handler.handle_response_error(ResponseError::PathNotFound);
382+
},
383+
};
384+
385+
log_info!(self.logger, "Responding to onion message with path_id {:02x?}", path_id);
386+
387+
if let Err(e) = self.send_onion_message(path, response, None) {
388+
log_info!(
389+
self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}",
390+
path_id, e
391+
);
392+
return error_handler.handle_response_error(ResponseError::Sending(e));
393+
}
394+
}
395+
324396
#[cfg(test)]
325397
pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, VecDeque<msgs::OnionMessage>> {
326398
let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -364,7 +436,7 @@ where
364436
NS::Target: NodeSigner,
365437
L::Target: Logger + Sized,
366438
MR::Target: MessageRouter,
367-
OMH::Target: OffersMessageHandler,
439+
OMH::Target: OffersMessageHandler + Sized,
368440
CMH::Target: CustomOnionMessageHandler + Sized,
369441
{
370442
/// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
@@ -403,9 +475,27 @@ where
403475
log_info!(self.logger,
404476
"Received an onion message with path_id {:02x?} and {} reply_path",
405477
path_id, if reply_path.is_some() { "a" } else { "no" });
406-
match message {
407-
OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg),
408-
OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
478+
479+
let response = match message {
480+
OnionMessageContents::Offers(msg) => {
481+
self.offers_handler.handle_message(msg)
482+
.map(|msg| OnionMessageContents::Offers(msg))
483+
},
484+
OnionMessageContents::Custom(msg) => {
485+
self.custom_handler.handle_custom_message(msg)
486+
.map(|msg| OnionMessageContents::Custom(msg))
487+
},
488+
};
489+
490+
if let Some(response) = response {
491+
match response {
492+
OnionMessageContents::Offers(_) => self.respond_with_onion_message(
493+
response, path_id, reply_path, &*self.offers_handler
494+
),
495+
OnionMessageContents::Custom(_) => self.respond_with_onion_message(
496+
response, path_id, reply_path, &*self.custom_handler
497+
),
498+
}
409499
}
410500
},
411501
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, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
30+
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, 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: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::offers::invoice_error::InvoiceError;
1616
use crate::offers::invoice_request::InvoiceRequest;
1717
use crate::offers::invoice::Invoice;
1818
use crate::offers::parse::ParseError;
19+
use crate::onion_message::messenger::ResponseErrorHandler;
1920
use crate::util::logger::Logger;
2021
use crate::util::ser::{ReadableArgs, Writeable, Writer};
2122

@@ -29,10 +30,10 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68;
2930
/// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload.
3031
///
3132
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
32-
pub trait OffersMessageHandler {
33+
pub trait OffersMessageHandler: ResponseErrorHandler {
3334
/// Handles the given message by either responding with an [`Invoice`], sending a payment, or
3435
/// replying with an error.
35-
fn handle_message(&self, message: OffersMessage);
36+
fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage>;
3637
}
3738

3839
/// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].

0 commit comments

Comments
 (0)