Generalize CustomOnionMessageContents trait

Rename CustomOnionMessageContents to OnionMessageContents and use it as
a trait bound on messages passed to OnionMessenger methods. This allows
using the trait in an upcoming commit as a bound on the contents of
PendingOnionMessage.

Also, make ParsedOnionMessageContent implement OnionMessageContents so
that Payload can be bounded by OnionMessageContents directly, but used
when either reading a ParsedOnionMessageContent or writing a specific
type of OnionMessageContents (e.g., OffersMessage).
This commit is contained in:
Jeffrey Czyz 2023-09-19 12:35:13 -05:00
parent 94573dda33
commit 840efd5334
No known key found for this signature in database
GPG key ID: 3A4E08275D5E96D2
7 changed files with 104 additions and 94 deletions

View file

@ -14,7 +14,7 @@ use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::util::test_channel_signer::TestChannelSigner;
use lightning::util::logger::Logger;
use lightning::util::ser::{Readable, Writeable, Writer};
use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessagePath, OnionMessenger};
use lightning::onion_message::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger};
use crate::utils::test_logger;
@ -84,7 +84,7 @@ struct TestCustomMessage {}
const CUSTOM_MESSAGE_TYPE: u64 = 4242;
const CUSTOM_MESSAGE_CONTENTS: [u8; 32] = [42; 32];
impl CustomOnionMessageContents for TestCustomMessage {
impl OnionMessageContents for TestCustomMessage {
fn tlv_type(&self) -> u64 {
CUSTOM_MESSAGE_TYPE
}
@ -216,9 +216,9 @@ mod tests {
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
"Received an onion message with path_id None and a reply_path".to_string())), Some(&1));
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
"Sending onion message when responding to onion message with path_id None".to_string())), Some(&1));
"Sending onion message when responding to Custom onion message with path_id None".to_string())), Some(&1));
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
"Failed sending onion message when responding to onion message with path_id None: TooFewBlindedHops".to_string())), Some(&1));
"Failed sending onion message when responding to Custom onion message with path_id None: TooFewBlindedHops".to_string())), Some(&1));
}
let two_unblinded_hops_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d000000000000000000000000000000eb0000000000000000000000000000000000000000000000000000000000000036041096000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000";

View file

@ -29,7 +29,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer};
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
use crate::ln::wire;
use crate::ln::wire::{Encode, Type};
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
use crate::onion_message::{CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessageContents, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias};
use crate::util::atomic_counter::AtomicCounter;
use crate::util::logger::Logger;
@ -131,7 +131,7 @@ impl CustomOnionMessageHandler for IgnoringMessageHandler {
}
}
impl CustomOnionMessageContents for Infallible {
impl OnionMessageContents for Infallible {
fn tlv_type(&self) -> u64 { unreachable!(); }
}

View file

@ -15,7 +15,7 @@ use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
use crate::sign::{NodeSigner, Recipient};
use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer};
use crate::util::test_utils;
use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, ParsedOnionMessageContents, OnionMessagePath, OnionMessenger, SendError};
use super::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError};
use bitcoin::network::constants::Network;
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
@ -77,7 +77,7 @@ const CUSTOM_RESPONSE_MESSAGE_TYPE: u64 = 4343;
const CUSTOM_REQUEST_MESSAGE_CONTENTS: [u8; 32] = [42; 32];
const CUSTOM_RESPONSE_MESSAGE_CONTENTS: [u8; 32] = [43; 32];
impl CustomOnionMessageContents for TestCustomMessage {
impl OnionMessageContents for TestCustomMessage {
fn tlv_type(&self) -> u64 {
match self {
TestCustomMessage::Request => CUSTOM_REQUEST_MESSAGE_TYPE,
@ -196,7 +196,7 @@ fn pass_along_path(path: &Vec<MessengerNode>) {
#[test]
fn one_hop() {
let nodes = create_nodes(2);
let test_msg = ParsedOnionMessageContents::Custom(TestCustomMessage::Response);
let test_msg = TestCustomMessage::Response;
let path = OnionMessagePath {
intermediate_nodes: vec![],
@ -210,7 +210,7 @@ fn one_hop() {
#[test]
fn two_unblinded_hops() {
let nodes = create_nodes(3);
let test_msg = ParsedOnionMessageContents::Custom(TestCustomMessage::Response);
let test_msg = TestCustomMessage::Response;
let path = OnionMessagePath {
intermediate_nodes: vec![nodes[1].get_node_pk()],
@ -224,7 +224,7 @@ fn two_unblinded_hops() {
#[test]
fn two_unblinded_two_blinded() {
let nodes = create_nodes(5);
let test_msg = ParsedOnionMessageContents::Custom(TestCustomMessage::Response);
let test_msg = TestCustomMessage::Response;
let secp_ctx = Secp256k1::new();
let blinded_path = BlindedPath::new_for_message(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
@ -241,7 +241,7 @@ fn two_unblinded_two_blinded() {
#[test]
fn three_blinded_hops() {
let nodes = create_nodes(4);
let test_msg = ParsedOnionMessageContents::Custom(TestCustomMessage::Response);
let test_msg = TestCustomMessage::Response;
let secp_ctx = Secp256k1::new();
let blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
@ -259,7 +259,7 @@ fn three_blinded_hops() {
fn too_big_packet_error() {
// Make sure we error as expected if a packet is too big to send.
let nodes = create_nodes(2);
let test_msg = ParsedOnionMessageContents::Custom(TestCustomMessage::Response);
let test_msg = TestCustomMessage::Response;
let hop_node_id = nodes[1].get_node_pk();
let hops = vec![hop_node_id; 400];
@ -285,7 +285,7 @@ fn we_are_intro_node() {
destination: Destination::BlindedPath(blinded_path),
};
nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg.clone()), None).unwrap();
nodes[0].messenger.send_onion_message(path, test_msg.clone(), None).unwrap();
nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response);
pass_along_path(&nodes);
@ -295,7 +295,7 @@ fn we_are_intro_node() {
intermediate_nodes: vec![],
destination: Destination::BlindedPath(blinded_path),
};
nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg), None).unwrap();
nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap();
nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response);
nodes.remove(2);
pass_along_path(&nodes);
@ -315,7 +315,7 @@ fn invalid_blinded_path_error() {
intermediate_nodes: vec![],
destination: Destination::BlindedPath(blinded_path),
};
let err = nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg.clone()), None).unwrap_err();
let err = nodes[0].messenger.send_onion_message(path, test_msg.clone(), None).unwrap_err();
assert_eq!(err, SendError::TooFewBlindedHops);
// 1 hop
@ -326,7 +326,7 @@ fn invalid_blinded_path_error() {
intermediate_nodes: vec![],
destination: Destination::BlindedPath(blinded_path),
};
let err = nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg), None).unwrap_err();
let err = nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap_err();
assert_eq!(err, SendError::TooFewBlindedHops);
}
@ -342,7 +342,7 @@ fn reply_path() {
destination: Destination::Node(nodes[3].get_node_pk()),
};
let reply_path = BlindedPath::new_for_message(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap();
nodes[0].messenger.send_onion_message(path, test_msg.clone(), Some(reply_path)).unwrap();
nodes[3].custom_message_handler.expect_message(TestCustomMessage::Request);
pass_along_path(&nodes);
// Make sure the last node successfully decoded the reply path.
@ -358,7 +358,7 @@ fn reply_path() {
};
let reply_path = BlindedPath::new_for_message(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap();
nodes[0].messenger.send_onion_message(path, test_msg, Some(reply_path)).unwrap();
nodes[3].custom_message_handler.expect_message(TestCustomMessage::Request);
pass_along_path(&nodes);
@ -373,7 +373,7 @@ fn invalid_custom_message_type() {
let nodes = create_nodes(2);
struct InvalidCustomMessage{}
impl CustomOnionMessageContents for InvalidCustomMessage {
impl OnionMessageContents for InvalidCustomMessage {
fn tlv_type(&self) -> u64 {
// Onion message contents must have a TLV >= 64.
63
@ -384,7 +384,7 @@ fn invalid_custom_message_type() {
fn write<W: Writer>(&self, _w: &mut W) -> Result<(), io::Error> { unreachable!() }
}
let test_msg = ParsedOnionMessageContents::Custom(InvalidCustomMessage {});
let test_msg = InvalidCustomMessage {};
let path = OnionMessagePath {
intermediate_nodes: vec![],
destination: Destination::Node(nodes[1].get_node_pk()),
@ -402,9 +402,9 @@ fn peer_buffer_full() {
destination: Destination::Node(nodes[1].get_node_pk()),
};
for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger
nodes[0].messenger.send_onion_message(path.clone(), ParsedOnionMessageContents::Custom(test_msg.clone()), None).unwrap();
nodes[0].messenger.send_onion_message(path.clone(), test_msg.clone(), None).unwrap();
}
let err = nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg), None).unwrap_err();
let err = nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap_err();
assert_eq!(err, SendError::BufferFull);
}
@ -425,7 +425,7 @@ fn many_hops() {
intermediate_nodes,
destination: Destination::Node(nodes[num_nodes-1].get_node_pk()),
};
nodes[0].messenger.send_onion_message(path, ParsedOnionMessageContents::Custom(test_msg), None).unwrap();
nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap();
nodes[num_nodes-1].custom_message_handler.expect_message(TestCustomMessage::Response);
pass_along_path(&nodes);
}

View file

@ -23,7 +23,8 @@ use crate::ln::features::{InitFeatures, NodeFeatures};
use crate::ln::msgs::{self, OnionMessage, OnionMessageHandler};
use crate::ln::onion_utils;
use crate::ln::peer_handler::IgnoringMessageHandler;
pub use super::packet::{CustomOnionMessageContents, ParsedOnionMessageContents};
pub use super::packet::OnionMessageContents;
use super::packet::ParsedOnionMessageContents;
use super::offers::OffersMessageHandler;
use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
use crate::util::logger::Logger;
@ -60,7 +61,7 @@ use crate::prelude::*;
/// # use lightning::blinded_path::BlindedPath;
/// # use lightning::sign::KeysManager;
/// # use lightning::ln::peer_handler::IgnoringMessageHandler;
/// # use lightning::onion_message::{CustomOnionMessageContents, Destination, MessageRouter, ParsedOnionMessageContents, OnionMessagePath, OnionMessenger};
/// # use lightning::onion_message::{OnionMessageContents, Destination, MessageRouter, OnionMessagePath, OnionMessenger};
/// # use lightning::util::logger::{Logger, Record};
/// # use lightning::util::ser::{Writeable, Writer};
/// # use lightning::io;
@ -101,7 +102,7 @@ use crate::prelude::*;
/// // Write your custom onion message to `w`
/// }
/// }
/// impl CustomOnionMessageContents for YourCustomMessage {
/// impl OnionMessageContents for YourCustomMessage {
/// fn tlv_type(&self) -> u64 {
/// # let your_custom_message_type = 42;
/// your_custom_message_type
@ -113,8 +114,7 @@ use crate::prelude::*;
/// destination: Destination::Node(destination_node_id),
/// };
/// let reply_path = None;
/// # let your_custom_message = YourCustomMessage {};
/// let message = ParsedOnionMessageContents::Custom(your_custom_message);
/// # let message = YourCustomMessage {};
/// onion_messenger.send_onion_message(path, message, reply_path);
///
/// // Create a blinded path to yourself, for someone to send an onion message to.
@ -128,8 +128,7 @@ use crate::prelude::*;
/// destination: Destination::BlindedPath(blinded_path),
/// };
/// let reply_path = None;
/// # let your_custom_message = YourCustomMessage {};
/// let message = ParsedOnionMessageContents::Custom(your_custom_message);
/// # let message = YourCustomMessage {};
/// onion_messenger.send_onion_message(path, message, reply_path);
/// ```
///
@ -244,7 +243,7 @@ pub enum SendError {
pub trait CustomOnionMessageHandler {
/// The message known to the handler. To support multiple message types, you may want to make this
/// an enum with a variant for each supported message.
type CustomMessage: CustomOnionMessageContents;
type CustomMessage: OnionMessageContents;
/// Called with the custom message that was received, returning a response to send, if any.
fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<Self::CustomMessage>;
@ -256,21 +255,20 @@ pub trait CustomOnionMessageHandler {
/// A processed incoming onion message, containing either a Forward (another onion message)
/// or a Receive payload with decrypted contents.
pub enum PeeledOnion<CM: CustomOnionMessageContents> {
pub enum PeeledOnion<T: OnionMessageContents> {
/// Forwarded onion, with the next node id and a new onion
Forward(PublicKey, OnionMessage),
/// Received onion message, with decrypted contents, path_id, and reply path
Receive(ParsedOnionMessageContents<CM>, Option<[u8; 32]>, Option<BlindedPath>)
Receive(ParsedOnionMessageContents<T>, Option<[u8; 32]>, Option<BlindedPath>)
}
/// Creates an [`OnionMessage`] with the given `contents` for sending to the destination of
/// `path`.
///
/// Returns both the node id of the peer to send the message to and the message itself.
pub fn create_onion_message<ES: Deref, NS: Deref, T: CustomOnionMessageContents>(
pub fn create_onion_message<ES: Deref, NS: Deref, T: OnionMessageContents>(
entropy_source: &ES, node_signer: &NS, secp_ctx: &Secp256k1<secp256k1::All>,
path: OnionMessagePath, contents: ParsedOnionMessageContents<T>,
reply_path: Option<BlindedPath>,
path: OnionMessagePath, contents: T, reply_path: Option<BlindedPath>,
) -> Result<(PublicKey, OnionMessage), SendError>
where
ES::Target: EntropySource,
@ -361,7 +359,7 @@ where
onion_decode_ss, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
(control_tlvs_ss, custom_handler.deref(), logger.deref())
) {
Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
Ok((Payload::Receive::<ParsedOnionMessageContents<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage>> {
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
}, None)) => {
Ok(PeeledOnion::Receive(message, path_id, reply_path))
@ -452,9 +450,8 @@ where
/// `path`.
///
/// See [`OnionMessenger`] for example usage.
pub fn send_onion_message<T: CustomOnionMessageContents>(
&self, path: OnionMessagePath, contents: ParsedOnionMessageContents<T>,
reply_path: Option<BlindedPath>
pub fn send_onion_message<T: OnionMessageContents>(
&self, path: OnionMessagePath, contents: T, reply_path: Option<BlindedPath>
) -> Result<(), SendError> {
let (first_node_id, onion_msg) = create_onion_message(
&self.entropy_source, &self.node_signer, &self.secp_ctx, path, contents, reply_path
@ -471,9 +468,25 @@ where
}
}
fn find_path_and_enqueue_onion_message<T: CustomOnionMessageContents>(
&self, contents: ParsedOnionMessageContents<T>, destination: Destination,
log_suffix: fmt::Arguments
fn handle_onion_message_response<T: OnionMessageContents>(
&self, response: Option<T>, reply_path: Option<BlindedPath>, log_suffix: fmt::Arguments
) {
if let Some(response) = response {
match reply_path {
Some(reply_path) => {
self.find_path_and_enqueue_onion_message(
response, Destination::BlindedPath(reply_path), log_suffix
);
},
None => {
log_trace!(self.logger, "Missing reply path {}", log_suffix);
},
}
}
}
fn find_path_and_enqueue_onion_message<T: OnionMessageContents>(
&self, contents: T, destination: Destination, log_suffix: fmt::Arguments
) {
let sender = match self.node_signer.get_node_id(Recipient::Node) {
Ok(node_id) => node_id,
@ -557,33 +570,26 @@ where
log_trace!(self.logger,
"Received an onion message with path_id {:02x?} and {} reply_path",
path_id, if reply_path.is_some() { "a" } else { "no" });
let response = match message {
match message {
ParsedOnionMessageContents::Offers(msg) => {
self.offers_handler.handle_message(msg)
.map(|msg| 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
)
);
},
ParsedOnionMessageContents::Custom(msg) => {
self.custom_handler.handle_custom_message(msg)
.map(|msg| ParsedOnionMessageContents::Custom(msg))
},
};
if let Some(response) = response {
match reply_path {
Some(reply_path) => {
self.find_path_and_enqueue_onion_message(
response, Destination::BlindedPath(reply_path), format_args!(
"when responding to onion message with path_id {:02x?}", path_id
)
);
},
None => {
log_trace!(
self.logger,
"Missing reply path when responding to onion message with path_id {:02x?}",
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
);
},
}
)
);
},
}
},
Ok(PeeledOnion::Forward(next_node_id, onion_message)) => {
@ -683,9 +689,9 @@ pub type SimpleRefOnionMessenger<'a, 'b, 'c, L> = OnionMessenger<
/// Construct onion packet payloads and keys for sending an onion message along the given
/// `unblinded_path` to the given `destination`.
fn packet_payloads_and_keys<T: CustomOnionMessageContents, S: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<S>, unblinded_path: &[PublicKey], destination: Destination,
message: ParsedOnionMessageContents<T>, mut reply_path: Option<BlindedPath>, session_priv: &SecretKey
fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<S>, unblinded_path: &[PublicKey], destination: Destination, message: T,
mut reply_path: Option<BlindedPath>, session_priv: &SecretKey
) -> Result<(Vec<(Payload<T>, [u8; 32])>, Vec<onion_utils::OnionKeys>), secp256k1::Error> {
let num_hops = unblinded_path.len() + destination.num_hops();
let mut payloads = Vec::with_capacity(num_hops);
@ -761,7 +767,7 @@ fn packet_payloads_and_keys<T: CustomOnionMessageContents, S: secp256k1::Signing
}
/// Errors if the serialized payload size exceeds onion_message::BIG_PACKET_HOP_DATA_LEN
fn construct_onion_message_packet<T: CustomOnionMessageContents>(payloads: Vec<(Payload<T>, [u8; 32])>, onion_keys: Vec<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Result<Packet, ()> {
fn construct_onion_message_packet<T: OnionMessageContents>(payloads: Vec<(Payload<T>, [u8; 32])>, onion_keys: Vec<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Result<Packet, ()> {
// Spec rationale:
// "`len` allows larger messages to be sent than the standard 1300 bytes allowed for an HTLC
// onion, but this should be used sparingly as it is reduces anonymity set, hence the

View file

@ -27,7 +27,7 @@ mod packet;
mod functional_tests;
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, ParsedOnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
pub use self::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
pub use self::offers::{OffersMessage, OffersMessageHandler};
pub use self::packet::Packet;
pub use self::packet::{Packet, ParsedOnionMessageContents};
pub(crate) use self::packet::ControlTlvs;

View file

@ -16,6 +16,7 @@ use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::InvoiceRequest;
use crate::offers::invoice::Bolt12Invoice;
use crate::offers::parse::Bolt12ParseError;
use crate::onion_message::OnionMessageContents;
use crate::util::logger::Logger;
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
@ -63,15 +64,6 @@ impl OffersMessage {
}
}
/// The TLV record type for the message as used in an `onionmsg_tlv` TLV stream.
pub fn tlv_type(&self) -> u64 {
match self {
OffersMessage::InvoiceRequest(_) => INVOICE_REQUEST_TLV_TYPE,
OffersMessage::Invoice(_) => INVOICE_TLV_TYPE,
OffersMessage::InvoiceError(_) => INVOICE_ERROR_TLV_TYPE,
}
}
fn parse(tlv_type: u64, bytes: Vec<u8>) -> Result<Self, Bolt12ParseError> {
match tlv_type {
INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)),
@ -81,6 +73,16 @@ impl OffersMessage {
}
}
impl OnionMessageContents for OffersMessage {
fn tlv_type(&self) -> u64 {
match self {
OffersMessage::InvoiceRequest(_) => INVOICE_REQUEST_TLV_TYPE,
OffersMessage::Invoice(_) => INVOICE_TLV_TYPE,
OffersMessage::InvoiceError(_) => INVOICE_ERROR_TLV_TYPE,
}
}
}
impl Writeable for OffersMessage {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
match self {

View file

@ -103,31 +103,33 @@ impl LengthReadable for Packet {
/// Onion message payloads contain "control" TLVs and "data" TLVs. Control TLVs are used to route
/// the onion message from hop to hop and for path verification, whereas data TLVs contain the onion
/// message content itself, such as an invoice request.
pub(super) enum Payload<T: CustomOnionMessageContents> {
pub(super) enum Payload<T: OnionMessageContents> {
/// This payload is for an intermediate hop.
Forward(ForwardControlTlvs),
/// This payload is for the final hop.
Receive {
control_tlvs: ReceiveControlTlvs,
reply_path: Option<BlindedPath>,
message: ParsedOnionMessageContents<T>,
message: T,
}
}
/// The contents of an onion message as read from the wire.
/// The contents of an [`OnionMessage`] as read from the wire.
///
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
#[derive(Debug)]
pub enum ParsedOnionMessageContents<T: CustomOnionMessageContents> {
pub enum ParsedOnionMessageContents<T: OnionMessageContents> {
/// A message related to BOLT 12 Offers.
Offers(OffersMessage),
/// A custom onion message specified by the user.
Custom(T),
}
impl<T: CustomOnionMessageContents> ParsedOnionMessageContents<T> {
impl<T: OnionMessageContents> OnionMessageContents for ParsedOnionMessageContents<T> {
/// Returns the type that was used to decode the message payload.
///
/// This is not exported to bindings users as methods on non-cloneable enums are not currently exportable
pub fn tlv_type(&self) -> u64 {
fn tlv_type(&self) -> u64 {
match self {
&ParsedOnionMessageContents::Offers(ref msg) => msg.tlv_type(),
&ParsedOnionMessageContents::Custom(ref msg) => msg.tlv_type(),
@ -136,7 +138,7 @@ impl<T: CustomOnionMessageContents> ParsedOnionMessageContents<T> {
}
/// This is not exported to bindings users as methods on non-cloneable enums are not currently exportable
impl<T: CustomOnionMessageContents> Writeable for ParsedOnionMessageContents<T> {
impl<T: OnionMessageContents> Writeable for ParsedOnionMessageContents<T> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
match self {
ParsedOnionMessageContents::Offers(msg) => Ok(msg.write(w)?),
@ -145,8 +147,8 @@ impl<T: CustomOnionMessageContents> Writeable for ParsedOnionMessageContents<T>
}
}
/// The contents of a custom onion message.
pub trait CustomOnionMessageContents: Writeable {
/// The contents of an onion message.
pub trait OnionMessageContents: Writeable {
/// Returns the TLV type identifying the message contents. MUST be >= 64.
fn tlv_type(&self) -> u64;
}
@ -172,7 +174,7 @@ pub(super) enum ReceiveControlTlvs {
}
// Uses the provided secret to simultaneously encode and encrypt the unblinded control TLVs.
impl<T: CustomOnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
impl<T: OnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
match &self.0 {
Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) => {
@ -211,8 +213,8 @@ impl<T: CustomOnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
}
// Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV.
impl<H: CustomOnionMessageHandler + ?Sized, L: Logger + ?Sized>
ReadableArgs<(SharedSecret, &H, &L)> for Payload<<H as CustomOnionMessageHandler>::CustomMessage> {
impl<H: CustomOnionMessageHandler + ?Sized, L: Logger + ?Sized> ReadableArgs<(SharedSecret, &H, &L)>
for Payload<ParsedOnionMessageContents<<H as CustomOnionMessageHandler>::CustomMessage>> {
fn read<R: Read>(r: &mut R, args: (SharedSecret, &H, &L)) -> Result<Self, DecodeError> {
let (encrypted_tlvs_ss, handler, logger) = args;