Skip to content

Commit 38690bf

Browse files
authored
Merge pull request #2907 from shaavan/issue2882
Introduce ResponseInstructions for OnionMessage Handling
2 parents 74c9f9b + 15d016a commit 38690bf

File tree

7 files changed

+144
-54
lines changed

7 files changed

+144
-54
lines changed

fuzz/src/onion_message.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use lightning::sign::{Recipient, KeyMaterial, EntropySource, NodeSigner, SignerP
1616
use lightning::util::test_channel_signer::TestChannelSigner;
1717
use lightning::util::logger::Logger;
1818
use lightning::util::ser::{Readable, Writeable, Writer};
19-
use lightning::onion_message::messenger::{CustomOnionMessageHandler, Destination, MessageRouter, OnionMessagePath, OnionMessenger, PendingOnionMessage};
19+
use lightning::onion_message::messenger::{CustomOnionMessageHandler, Destination, MessageRouter, OnionMessagePath, OnionMessenger, PendingOnionMessage, Responder, ResponseInstruction};
2020
use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler};
2121
use lightning::onion_message::packet::OnionMessageContents;
2222

@@ -97,8 +97,8 @@ impl MessageRouter for TestMessageRouter {
9797
struct TestOffersMessageHandler {}
9898

9999
impl OffersMessageHandler for TestOffersMessageHandler {
100-
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
101-
None
100+
fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
101+
ResponseInstruction::NoResponse
102102
}
103103
}
104104

@@ -112,6 +112,9 @@ impl OnionMessageContents for TestCustomMessage {
112112
fn tlv_type(&self) -> u64 {
113113
CUSTOM_MESSAGE_TYPE
114114
}
115+
fn msg_type(&self) -> &'static str {
116+
"Custom Message"
117+
}
115118
}
116119

117120
impl Writeable for TestCustomMessage {
@@ -124,8 +127,11 @@ struct TestCustomMessageHandler {}
124127

125128
impl CustomOnionMessageHandler for TestCustomMessageHandler {
126129
type CustomMessage = TestCustomMessage;
127-
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
128-
Some(TestCustomMessage {})
130+
fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
131+
match responder {
132+
Some(responder) => responder.respond(message),
133+
None => ResponseInstruction::NoResponse
134+
}
129135
}
130136
fn read_custom_message<R: io::Read>(&self, _message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
131137
let mut buf = Vec::new();
@@ -280,9 +286,9 @@ mod tests {
280286
"Received an onion message with path_id None and a reply_path: Custom(TestCustomMessage)"
281287
.to_string())), Some(&1));
282288
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
283-
"Constructing onion message when responding to Custom onion message with path_id None: TestCustomMessage".to_string())), Some(&1));
289+
"Constructing onion message when responding with Custom Message to an onion message with path_id None: TestCustomMessage".to_string())), Some(&1));
284290
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
285-
"Buffered onion message when responding to Custom onion message with path_id None".to_string())), Some(&1));
291+
"Buffered onion message when responding with Custom Message to an onion message with path_id None".to_string())), Some(&1));
286292
}
287293

288294
let two_unblinded_hops_om = "\

lightning/src/ln/channelmanager.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder};
6565
use crate::offers::offer::{Offer, OfferBuilder};
6666
use crate::offers::parse::Bolt12SemanticError;
6767
use crate::offers::refund::{Refund, RefundBuilder};
68-
use crate::onion_message::messenger::{Destination, MessageRouter, PendingOnionMessage, new_pending_onion_message};
68+
use crate::onion_message::messenger::{new_pending_onion_message, Destination, MessageRouter, PendingOnionMessage, Responder, ResponseInstruction};
6969
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
7070
use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider};
7171
use crate::sign::ecdsa::WriteableEcdsaChannelSigner;
@@ -76,6 +76,7 @@ use crate::util::string::UntrustedString;
7676
use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter};
7777
use crate::util::logger::{Level, Logger, WithContext};
7878
use crate::util::errors::APIError;
79+
7980
#[cfg(not(c_bindings))]
8081
use {
8182
crate::offers::offer::DerivedMetadata,
@@ -10349,23 +10350,27 @@ where
1034910350
R::Target: Router,
1035010351
L::Target: Logger,
1035110352
{
10352-
fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage> {
10353+
fn handle_message(&self, message: OffersMessage, responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
1035310354
let secp_ctx = &self.secp_ctx;
1035410355
let expanded_key = &self.inbound_payment_key;
1035510356

1035610357
match message {
1035710358
OffersMessage::InvoiceRequest(invoice_request) => {
10359+
let responder = match responder {
10360+
Some(responder) => responder,
10361+
None => return ResponseInstruction::NoResponse,
10362+
};
1035810363
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
1035910364
&invoice_request
1036010365
) {
1036110366
Ok(amount_msats) => amount_msats,
10362-
Err(error) => return Some(OffersMessage::InvoiceError(error.into())),
10367+
Err(error) => return responder.respond(OffersMessage::InvoiceError(error.into())),
1036310368
};
1036410369
let invoice_request = match invoice_request.verify(expanded_key, secp_ctx) {
1036510370
Ok(invoice_request) => invoice_request,
1036610371
Err(()) => {
1036710372
let error = Bolt12SemanticError::InvalidMetadata;
10368-
return Some(OffersMessage::InvoiceError(error.into()));
10373+
return responder.respond(OffersMessage::InvoiceError(error.into()));
1036910374
},
1037010375
};
1037110376

@@ -10376,7 +10381,7 @@ where
1037610381
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
1037710382
Err(()) => {
1037810383
let error = Bolt12SemanticError::InvalidAmount;
10379-
return Some(OffersMessage::InvoiceError(error.into()));
10384+
return responder.respond(OffersMessage::InvoiceError(error.into()));
1038010385
},
1038110386
};
1038210387

@@ -10390,7 +10395,7 @@ where
1039010395
Ok(payment_paths) => payment_paths,
1039110396
Err(()) => {
1039210397
let error = Bolt12SemanticError::MissingPaths;
10393-
return Some(OffersMessage::InvoiceError(error.into()));
10398+
return responder.respond(OffersMessage::InvoiceError(error.into()));
1039410399
},
1039510400
};
1039610401

@@ -10435,8 +10440,8 @@ where
1043510440
};
1043610441

1043710442
match response {
10438-
Ok(invoice) => Some(OffersMessage::Invoice(invoice)),
10439-
Err(error) => Some(OffersMessage::InvoiceError(error.into())),
10443+
Ok(invoice) => return responder.respond(OffersMessage::Invoice(invoice)),
10444+
Err(error) => return responder.respond(OffersMessage::InvoiceError(error.into())),
1044010445
}
1044110446
},
1044210447
OffersMessage::Invoice(invoice) => {
@@ -10456,14 +10461,21 @@ where
1045610461
}
1045710462
});
1045810463

10459-
match response {
10460-
Ok(()) => None,
10461-
Err(e) => Some(OffersMessage::InvoiceError(e)),
10464+
match (responder, response) {
10465+
(Some(responder), Err(e)) => responder.respond(OffersMessage::InvoiceError(e)),
10466+
(None, Err(_)) => {
10467+
log_trace!(
10468+
self.logger,
10469+
"A response was generated, but there is no reply_path specified for sending the response."
10470+
);
10471+
return ResponseInstruction::NoResponse;
10472+
}
10473+
_ => return ResponseInstruction::NoResponse,
1046210474
}
1046310475
},
1046410476
OffersMessage::InvoiceError(invoice_error) => {
1046510477
log_trace!(self.logger, "Received invoice_error: {}", invoice_error);
10466-
None
10478+
return ResponseInstruction::NoResponse;
1046710479
},
1046810480
}
1046910481
}

lightning/src/ln/peer_handler.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer};
2828
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor, NextNoiseStep, MessageBuf, MSG_BUF_ALLOC_SIZE};
2929
use crate::ln::wire;
3030
use crate::ln::wire::{Encode, Type};
31-
use crate::onion_message::messenger::{CustomOnionMessageHandler, PendingOnionMessage};
31+
use crate::onion_message::messenger::{CustomOnionMessageHandler, PendingOnionMessage, Responder, ResponseInstruction};
3232
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
3333
use crate::onion_message::packet::OnionMessageContents;
3434
use crate::routing::gossip::{NodeId, NodeAlias};
@@ -123,6 +123,7 @@ impl RoutingMessageHandler for IgnoringMessageHandler {
123123
}
124124
fn processing_queue_high(&self) -> bool { false }
125125
}
126+
126127
impl OnionMessageHandler for IgnoringMessageHandler {
127128
fn handle_onion_message(&self, _their_node_id: &PublicKey, _msg: &msgs::OnionMessage) {}
128129
fn next_onion_message_for_peer(&self, _peer_node_id: PublicKey) -> Option<msgs::OnionMessage> { None }
@@ -134,12 +135,15 @@ impl OnionMessageHandler for IgnoringMessageHandler {
134135
InitFeatures::empty()
135136
}
136137
}
138+
137139
impl OffersMessageHandler for IgnoringMessageHandler {
138-
fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
140+
fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
141+
ResponseInstruction::NoResponse
142+
}
139143
}
140144
impl CustomOnionMessageHandler for IgnoringMessageHandler {
141145
type CustomMessage = Infallible;
142-
fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
146+
fn handle_custom_message(&self, _message: Self::CustomMessage, _responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
143147
// Since we always return `None` in the read the handle method should never be called.
144148
unreachable!();
145149
}
@@ -153,6 +157,7 @@ impl CustomOnionMessageHandler for IgnoringMessageHandler {
153157

154158
impl OnionMessageContents for Infallible {
155159
fn tlv_type(&self) -> u64 { unreachable!(); }
160+
fn msg_type(&self) -> &'static str { unreachable!(); }
156161
}
157162

158163
impl Deref for IgnoringMessageHandler {

lightning/src/onion_message/functional_tests.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::routing::test_utils::{add_channel, add_or_update_node};
1818
use crate::sign::{NodeSigner, Recipient};
1919
use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer};
2020
use crate::util::test_utils;
21-
use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, SendError};
21+
use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, Responder, ResponseInstruction, SendError};
2222
use super::offers::{OffersMessage, OffersMessageHandler};
2323
use super::packet::{OnionMessageContents, Packet};
2424

@@ -62,8 +62,8 @@ struct MessengerNode {
6262
struct TestOffersMessageHandler {}
6363

6464
impl OffersMessageHandler for TestOffersMessageHandler {
65-
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
66-
None
65+
fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
66+
ResponseInstruction::NoResponse
6767
}
6868
}
6969

@@ -85,6 +85,9 @@ impl OnionMessageContents for TestCustomMessage {
8585
TestCustomMessage::Response => CUSTOM_RESPONSE_MESSAGE_TYPE,
8686
}
8787
}
88+
fn msg_type(&self) -> &'static str {
89+
"Custom Message"
90+
}
8891
}
8992

9093
impl Writeable for TestCustomMessage {
@@ -123,15 +126,19 @@ impl Drop for TestCustomMessageHandler {
123126

124127
impl CustomOnionMessageHandler for TestCustomMessageHandler {
125128
type CustomMessage = TestCustomMessage;
126-
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
129+
fn handle_custom_message(&self, msg: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
127130
match self.expected_messages.lock().unwrap().pop_front() {
128131
Some(expected_msg) => assert_eq!(expected_msg, msg),
129132
None => panic!("Unexpected message: {:?}", msg),
130133
}
131-
132-
match msg {
134+
let response_option = match msg {
133135
TestCustomMessage::Request => Some(TestCustomMessage::Response),
134136
TestCustomMessage::Response => None,
137+
};
138+
if let (Some(response), Some(responder)) = (response_option, responder) {
139+
responder.respond(response)
140+
} else {
141+
ResponseInstruction::NoResponse
135142
}
136143
}
137144
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
@@ -422,6 +429,9 @@ fn invalid_custom_message_type() {
422429
// Onion message contents must have a TLV >= 64.
423430
63
424431
}
432+
fn msg_type(&self) -> &'static str {
433+
"Invalid Message"
434+
}
425435
}
426436

427437
impl Writeable for InvalidCustomMessage {

lightning/src/onion_message/messenger.rs

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub(super) const MAX_TIMER_TICKS: usize = 2;
135135
/// # let your_custom_message_type = 42;
136136
/// your_custom_message_type
137137
/// }
138+
/// fn msg_type(&self) -> &'static str { "YourCustomMessageType" }
138139
/// }
139140
/// // Send a custom onion message to a node id.
140141
/// let destination = Destination::Node(destination_node_id);
@@ -246,6 +247,50 @@ impl OnionMessageRecipient {
246247
}
247248
}
248249

250+
251+
/// The `Responder` struct creates an appropriate [`ResponseInstruction`]
252+
/// for responding to a message.
253+
pub struct Responder {
254+
/// The path along which a response can be sent.
255+
reply_path: BlindedPath,
256+
path_id: Option<[u8; 32]>
257+
}
258+
259+
impl Responder {
260+
/// Creates a new [`Responder`] instance with the provided reply path.
261+
fn new(reply_path: BlindedPath, path_id: Option<[u8; 32]>) -> Self {
262+
Responder {
263+
reply_path,
264+
path_id,
265+
}
266+
}
267+
268+
/// Creates the appropriate [`ResponseInstruction`] for a given response.
269+
pub fn respond<T: OnionMessageContents>(self, response: T) -> ResponseInstruction<T> {
270+
ResponseInstruction::WithoutReplyPath(OnionMessageResponse {
271+
message: response,
272+
reply_path: self.reply_path,
273+
path_id: self.path_id,
274+
})
275+
}
276+
}
277+
278+
/// This struct contains the information needed to reply to a received message.
279+
pub struct OnionMessageResponse<T: OnionMessageContents> {
280+
message: T,
281+
reply_path: BlindedPath,
282+
path_id: Option<[u8; 32]>,
283+
}
284+
285+
/// `ResponseInstruction` represents instructions for responding to received messages.
286+
pub enum ResponseInstruction<T: OnionMessageContents> {
287+
/// Indicates that a response should be sent without including a reply path
288+
/// for the recipient to respond back.
289+
WithoutReplyPath(OnionMessageResponse<T>),
290+
/// Indicates that there's no response to send back.
291+
NoResponse,
292+
}
293+
249294
/// An [`OnionMessage`] for [`OnionMessenger`] to send.
250295
///
251296
/// These are obtained when released from [`OnionMessenger`]'s handlers after which they are
@@ -546,7 +591,7 @@ pub trait CustomOnionMessageHandler {
546591
/// Called with the custom message that was received, returning a response to send, if any.
547592
///
548593
/// The returned [`Self::CustomMessage`], if any, is enqueued to be sent by [`OnionMessenger`].
549-
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
594+
fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage>;
550595

551596
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
552597
/// message type is unknown.
@@ -933,19 +978,18 @@ where
933978
}
934979

935980
fn handle_onion_message_response<T: OnionMessageContents>(
936-
&self, response: Option<T>, reply_path: Option<BlindedPath>, log_suffix: fmt::Arguments
981+
&self, response: ResponseInstruction<T>
937982
) {
938-
if let Some(response) = response {
939-
match reply_path {
940-
Some(reply_path) => {
941-
let _ = self.find_path_and_enqueue_onion_message(
942-
response, Destination::BlindedPath(reply_path), None, log_suffix
943-
);
944-
},
945-
None => {
946-
log_trace!(self.logger, "Missing reply path {}", log_suffix);
947-
},
948-
}
983+
if let ResponseInstruction::WithoutReplyPath(response) = response {
984+
let message_type = response.message.msg_type();
985+
let _ = self.find_path_and_enqueue_onion_message(
986+
response.message, Destination::BlindedPath(response.reply_path), None,
987+
format_args!(
988+
"when responding with {} to an onion message with path_id {:02x?}",
989+
message_type,
990+
response.path_id
991+
)
992+
);
949993
}
950994
}
951995

@@ -1029,22 +1073,18 @@ where
10291073

10301074
match message {
10311075
ParsedOnionMessageContents::Offers(msg) => {
1032-
let response = self.offers_handler.handle_message(msg);
1033-
self.handle_onion_message_response(
1034-
response, reply_path, format_args!(
1035-
"when responding to Offers onion message with path_id {:02x?}",
1036-
path_id
1037-
)
1076+
let responder = reply_path.map(
1077+
|reply_path| Responder::new(reply_path, path_id)
10381078
);
1079+
let response_instructions = self.offers_handler.handle_message(msg, responder);
1080+
self.handle_onion_message_response(response_instructions);
10391081
},
10401082
ParsedOnionMessageContents::Custom(msg) => {
1041-
let response = self.custom_handler.handle_custom_message(msg);
1042-
self.handle_onion_message_response(
1043-
response, reply_path, format_args!(
1044-
"when responding to Custom onion message with path_id {:02x?}",
1045-
path_id
1046-
)
1083+
let responder = reply_path.map(
1084+
|reply_path| Responder::new(reply_path, path_id)
10471085
);
1086+
let response_instructions = self.custom_handler.handle_custom_message(msg, responder);
1087+
self.handle_onion_message_response(response_instructions);
10481088
},
10491089
}
10501090
},

0 commit comments

Comments
 (0)