Skip to content

Commit

Permalink
Implement ResponseInstruction Usage in OnionMessage Handling
Browse files Browse the repository at this point in the history
This commit integrates the newly introduced ResponseInstruction structs
and enums into the codebase for handling OnionMessage responses.
  • Loading branch information
shaavan committed Mar 25, 2024
1 parent e241b8a commit febac75
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 55 deletions.
10 changes: 6 additions & 4 deletions fuzz/src/onion_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ impl MessageRouter for TestMessageRouter {
struct TestOffersMessageHandler {}

impl OffersMessageHandler for TestOffersMessageHandler {
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
None
fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder<OffersMessage>>) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
}

Expand All @@ -123,8 +123,10 @@ struct TestCustomMessageHandler {}

impl CustomOnionMessageHandler for TestCustomMessageHandler {
type CustomMessage = TestCustomMessage;
fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
Some(TestCustomMessage {})
fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder<Self::CustomMessage>>) -> ResponseInstruction<Self::CustomMessage> {
if let Some(responder) = responder {
responder.respond(TestCustomMessage {})
}
}
fn read_custom_message<R: io::Read>(&self, _message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
let mut buf = Vec::new();
Expand Down
36 changes: 25 additions & 11 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ use crate::offers::merkle::SignError;
use crate::offers::offer::{Offer, OfferBuilder};
use crate::offers::parse::Bolt12SemanticError;
use crate::offers::refund::{Refund, RefundBuilder};
use crate::onion_message::messenger::{Destination, MessageRouter, PendingOnionMessage, new_pending_onion_message};
use crate::onion_message::messenger::{new_pending_onion_message, Destination, MessageRouter, PendingOnionMessage, Responder, ResponseInstruction};
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider};
use crate::sign::ecdsa::WriteableEcdsaChannelSigner;
Expand All @@ -76,6 +76,7 @@ use crate::util::string::UntrustedString;
use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter};
use crate::util::logger::{Level, Logger, WithContext};
use crate::util::errors::APIError;

#[cfg(not(c_bindings))]
use {
crate::offers::offer::DerivedMetadata,
Expand Down Expand Up @@ -9450,24 +9451,32 @@ where
R::Target: Router,
L::Target: Logger,
{
fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage> {
fn handle_message(&self, message: OffersMessage, responder: Option<Responder<OffersMessage>>) -> ResponseInstruction<OffersMessage>
{
let secp_ctx = &self.secp_ctx;
let expanded_key = &self.inbound_payment_key;

match message {
let responder = match responder {
Some(responder) => responder,
None => return ResponseInstruction::NoResponse,
};

let response_opt = match &message {
OffersMessage::InvoiceRequest(invoice_request) => {
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
&invoice_request
) {
Ok(amount_msats) => amount_msats,
Err(error) => return Some(OffersMessage::InvoiceError(error.into())),
Err(error) => {
return responder.respond(OffersMessage::InvoiceError(error.into()));
}
};
let invoice_request = match invoice_request.verify(expanded_key, secp_ctx) {
let invoice_request = match invoice_request.clone().verify(expanded_key, secp_ctx) {
Ok(invoice_request) => invoice_request,
Err(()) => {
let error = Bolt12SemanticError::InvalidMetadata;
return Some(OffersMessage::InvoiceError(error.into()));
},
return responder.respond(OffersMessage::InvoiceError(error.into()));
}
};

let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
Expand All @@ -9477,8 +9486,8 @@ where
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
Err(()) => {
let error = Bolt12SemanticError::InvalidAmount;
return Some(OffersMessage::InvoiceError(error.into()));
},
return responder.respond(OffersMessage::InvoiceError(error.into()));
}
};

let payment_paths = match self.create_blinded_payment_paths(
Expand All @@ -9487,8 +9496,8 @@ where
Ok(payment_paths) => payment_paths,
Err(()) => {
let error = Bolt12SemanticError::MissingPaths;
return Some(OffersMessage::InvoiceError(error.into()));
},
return responder.respond(OffersMessage::InvoiceError(error.into()));
}
};

#[cfg(not(feature = "std"))]
Expand Down Expand Up @@ -9565,6 +9574,11 @@ where
log_trace!(self.logger, "Received invoice_error: {}", invoice_error);
None
},
};

match response_opt {
Some(response) => responder.respond(response),
None => ResponseInstruction::NoResponse
}
}

Expand Down
11 changes: 8 additions & 3 deletions lightning/src/ln/peer_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer};
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor, NextNoiseStep, MessageBuf, MSG_BUF_ALLOC_SIZE};
use crate::ln::wire;
use crate::ln::wire::{Encode, Type};
use crate::onion_message::messenger::{CustomOnionMessageHandler, PendingOnionMessage};
use crate::onion_message::messenger::{CustomOnionMessageHandler, PendingOnionMessage, Responder, ResponseInstruction};
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
use crate::onion_message::packet::OnionMessageContents;
use crate::routing::gossip::{NodeId, NodeAlias};
Expand Down Expand Up @@ -120,6 +120,7 @@ impl RoutingMessageHandler for IgnoringMessageHandler {
}
fn processing_queue_high(&self) -> bool { false }
}

impl OnionMessageHandler for IgnoringMessageHandler {
fn handle_onion_message(&self, _their_node_id: &PublicKey, _msg: &msgs::OnionMessage) {}
fn next_onion_message_for_peer(&self, _peer_node_id: PublicKey) -> Option<msgs::OnionMessage> { None }
Expand All @@ -131,12 +132,15 @@ impl OnionMessageHandler for IgnoringMessageHandler {
InitFeatures::empty()
}
}

impl OffersMessageHandler for IgnoringMessageHandler {
fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder<OffersMessage>>) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
}
impl CustomOnionMessageHandler for IgnoringMessageHandler {
type CustomMessage = Infallible;
fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
fn handle_custom_message(&self, _message: Self::CustomMessage, _responder: Option<Responder<Self::CustomMessage>>) -> ResponseInstruction<Self::CustomMessage> {
// Since we always return `None` in the read the handle method should never be called.
unreachable!();
}
Expand All @@ -150,6 +154,7 @@ impl CustomOnionMessageHandler for IgnoringMessageHandler {

impl OnionMessageContents for Infallible {
fn tlv_type(&self) -> u64 { unreachable!(); }
fn msg_type(&self) -> &'static str { unreachable!(); }
}

impl Deref for IgnoringMessageHandler {
Expand Down
26 changes: 18 additions & 8 deletions lightning/src/onion_message/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::routing::test_utils::{add_channel, add_or_update_node};
use crate::sign::{NodeSigner, Recipient};
use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer};
use crate::util::test_utils;
use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, SendError};
use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, Responder, ResponseInstruction, SendError};
use super::offers::{OffersMessage, OffersMessageHandler};
use super::packet::{OnionMessageContents, Packet};

Expand Down Expand Up @@ -61,8 +61,8 @@ struct MessengerNode {
struct TestOffersMessageHandler {}

impl OffersMessageHandler for TestOffersMessageHandler {
fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
None
fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder<OffersMessage>>) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
}

Expand All @@ -84,6 +84,9 @@ impl OnionMessageContents for TestCustomMessage {
TestCustomMessage::Response => CUSTOM_RESPONSE_MESSAGE_TYPE,
}
}
fn msg_type(&self) -> &'static str {
&"Custom"
}
}

impl Writeable for TestCustomMessage {
Expand Down Expand Up @@ -122,15 +125,19 @@ impl Drop for TestCustomMessageHandler {

impl CustomOnionMessageHandler for TestCustomMessageHandler {
type CustomMessage = TestCustomMessage;
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder<Self::CustomMessage>>) -> ResponseInstruction<Self::CustomMessage> {
match self.expected_messages.lock().unwrap().pop_front() {
Some(expected_msg) => assert_eq!(expected_msg, msg),
None => panic!("Unexpected message: {:?}", msg),
Some(expected_msg) => assert_eq!(expected_msg, message),
None => panic!("Unexpected message: {:?}", message),
}

match msg {
let response_option = match message {
TestCustomMessage::Request => Some(TestCustomMessage::Response),
TestCustomMessage::Response => None,
};
if let (Some(response), Some(responder)) = (response_option, responder) {
responder.respond(response)
} else {
ResponseInstruction::NoResponse
}
}
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
Expand Down Expand Up @@ -420,6 +427,9 @@ fn invalid_custom_message_type() {
// Onion message contents must have a TLV >= 64.
63
}
fn msg_type(&self) -> &'static str {
&"Invalid"
}
}

impl Writeable for InvalidCustomMessage {
Expand Down
48 changes: 21 additions & 27 deletions lightning/src/onion_message/messenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ pub trait CustomOnionMessageHandler {
/// Called with the custom message that was received, returning a response to send, if any.
///
/// The returned [`Self::CustomMessage`], if any, is enqueued to be sent by [`OnionMessenger`].
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder<Self::CustomMessage>>) -> ResponseInstruction<Self::CustomMessage>;

/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
/// message type is unknown.
Expand Down Expand Up @@ -893,19 +893,12 @@ where
}

fn handle_onion_message_response<T: OnionMessageContents>(
&self, response: Option<T>, reply_path: Option<BlindedPath>, log_suffix: fmt::Arguments
&self, response: ResponseInstruction<T>, log_suffix: fmt::Arguments
) {
if let Some(response) = response {
match reply_path {
Some(reply_path) => {
let _ = self.find_path_and_enqueue_onion_message(
response, Destination::BlindedPath(reply_path), None, log_suffix
);
},
None => {
log_trace!(self.logger, "Missing reply path {}", log_suffix);
},
}
if let ResponseInstruction::WithoutReplyPath(response) = response {
let _ = self.find_path_and_enqueue_onion_message(
response.message, Destination::BlindedPath(response.reply_path), None, log_suffix
);
}
}

Expand Down Expand Up @@ -985,24 +978,25 @@ where
"Received an onion message with path_id {:02x?} and {} reply_path: {:?}",
path_id, if reply_path.is_some() { "a" } else { "no" }, message);

let message_type = message.msg_type();
match message {
ParsedOnionMessageContents::Offers(msg) => {
let response = self.offers_handler.handle_message(msg);
self.handle_onion_message_response(
response, reply_path, format_args!(
"when responding to Offers onion message with path_id {:02x?}",
path_id
)
);
let responder = reply_path.map(|path| Responder::new(path));
let response_instructions = self.offers_handler.handle_message(msg, responder);
self.handle_onion_message_response(response_instructions, format_args!(
"when responding to {} onion message with path_id {:02x?}",
message_type,
path_id
))
},
ParsedOnionMessageContents::Custom(msg) => {
let response = self.custom_handler.handle_custom_message(msg);
self.handle_onion_message_response(
response, reply_path, format_args!(
"when responding to Custom onion message with path_id {:02x?}",
path_id
)
);
let responder = reply_path.map(|path| Responder::new(path));
let response_instructions = self.custom_handler.handle_custom_message(msg, responder);
self.handle_onion_message_response(response_instructions, format_args!(
"when responding to {} onion message with path_id {:02x?}",
message_type,
path_id
))
},
}
},
Expand Down
7 changes: 5 additions & 2 deletions lightning/src/onion_message/offers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::onion_message::packet::OnionMessageContents;
use crate::util::logger::Logger;
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
#[cfg(not(c_bindings))]
use crate::onion_message::messenger::PendingOnionMessage;
use crate::onion_message::messenger::{PendingOnionMessage, ResponseInstruction, Responder};

use crate::prelude::*;

Expand All @@ -40,7 +40,7 @@ pub trait OffersMessageHandler {
/// The returned [`OffersMessage`], if any, is enqueued to be sent by [`OnionMessenger`].
///
/// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger
fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage>;
fn handle_message(&self, message: OffersMessage, responder: Option<Responder<OffersMessage>>) -> ResponseInstruction<OffersMessage>;

/// Releases any [`OffersMessage`]s that need to be sent.
///
Expand Down Expand Up @@ -118,6 +118,9 @@ impl OnionMessageContents for OffersMessage {
OffersMessage::InvoiceError(_) => INVOICE_ERROR_TLV_TYPE,
}
}
fn msg_type(&self) -> &'static str {
&"Offers"
}
}

impl Writeable for OffersMessage {
Expand Down
9 changes: 9 additions & 0 deletions lightning/src/onion_message/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ impl<T: OnionMessageContents> OnionMessageContents for ParsedOnionMessageContent
&ParsedOnionMessageContents::Custom(ref msg) => msg.tlv_type(),
}
}
fn msg_type(&self) -> &'static str {
match self {
&ParsedOnionMessageContents::Offers(ref msg) => msg.msg_type(),
&ParsedOnionMessageContents::Custom(ref msg) => msg.msg_type(),
}
}
}

impl<T: OnionMessageContents> Writeable for ParsedOnionMessageContents<T> {
Expand All @@ -150,6 +156,9 @@ impl<T: OnionMessageContents> Writeable for ParsedOnionMessageContents<T> {
pub trait OnionMessageContents: Writeable + core::fmt::Debug {
/// Returns the TLV type identifying the message contents. MUST be >= 64.
fn tlv_type(&self) -> u64;

/// Returns the message type
fn msg_type(&self) -> &'static str;
}

/// Forward control TLVs in their blinded and unblinded form.
Expand Down

0 comments on commit febac75

Please sign in to comment.