From 1feddaeafd343c50f29fd79a33a00bc7282b802a Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 5 Jun 2023 15:55:13 -0500 Subject: [PATCH 01/15] Support WithoutLength for UntrustedString --- lightning/src/util/ser.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index cbdb5485e7b..fb0d0ad8e44 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -43,6 +43,7 @@ use crate::ln::msgs::PartialSignatureWithNonce; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use crate::util::byte_utils::{be48_to_array, slice_to_be48}; +use crate::util::string::UntrustedString; /// serialization buffer size pub const MAX_BUF_SIZE: usize = 64 * 1024; @@ -629,6 +630,21 @@ impl<'a> From<&'a String> for WithoutLength<&'a String> { fn from(s: &'a String) -> Self { Self(s) } } + +impl Writeable for WithoutLength<&UntrustedString> { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + WithoutLength(&self.0.0).write(w) + } +} +impl Readable for WithoutLength { + #[inline] + fn read(r: &mut R) -> Result { + let s: WithoutLength = Readable::read(r)?; + Ok(Self(UntrustedString(s.0))) + } +} + impl<'a, T: Writeable> Writeable for WithoutLength<&'a Vec> { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { From 9b3a35a133c8f8c5864ab2a748e09ebeaf417525 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 18 May 2023 17:08:46 -0500 Subject: [PATCH 02/15] Add InvoiceError message If an InvoiceRequest or an Invoice delivered via an onion message cannot be handled, the recipient should reply with an InvoiceError if a reply path was given. Define the message and conversion from SemanticError. --- lightning/src/offers/invoice_error.rs | 233 ++++++++++++++++++++++++++ lightning/src/offers/mod.rs | 1 + lightning/src/util/ser_macros.rs | 3 + 3 files changed, 237 insertions(+) create mode 100644 lightning/src/offers/invoice_error.rs diff --git a/lightning/src/offers/invoice_error.rs b/lightning/src/offers/invoice_error.rs new file mode 100644 index 00000000000..e843264b4e3 --- /dev/null +++ b/lightning/src/offers/invoice_error.rs @@ -0,0 +1,233 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Data structures and encoding for `invoice_error` messages. + +use crate::io; +use crate::ln::msgs::DecodeError; +use crate::offers::parse::SemanticError; +use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer}; +use crate::util::string::UntrustedString; + +use crate::prelude::*; + +/// An error in response to an [`InvoiceRequest`] or an [`Invoice`]. +/// +/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest +/// [`Invoice`]: crate::offers::invoice::Invoice +#[derive(Clone, Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub struct InvoiceError { + /// The field in the [`InvoiceRequest`] or the [`Invoice`] that contained an error. + /// + /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest + /// [`Invoice`]: crate::offers::invoice::Invoice + pub erroneous_field: Option, + + /// An explanation of the error. + pub message: UntrustedString, +} + +/// The field in the [`InvoiceRequest`] or the [`Invoice`] that contained an error. +/// +/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest +/// [`Invoice`]: crate::offers::invoice::Invoice +#[derive(Clone, Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub struct ErroneousField { + /// The type number of the TLV field containing the error. + pub tlv_fieldnum: u64, + + /// A value to use for the TLV field to avoid the error. + pub suggested_value: Option>, +} + +impl core::fmt::Display for InvoiceError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { + self.message.fmt(f) + } +} + +impl Writeable for InvoiceError { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let tlv_fieldnum = self.erroneous_field.as_ref().map(|f| f.tlv_fieldnum); + let suggested_value = + self.erroneous_field.as_ref().and_then(|f| f.suggested_value.as_ref()); + write_tlv_fields!(writer, { + (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, suggested_value, (option, encoding: (Vec, WithoutLength))), + (5, WithoutLength(&self.message), required), + }); + Ok(()) + } +} + +impl Readable for InvoiceError { + fn read(reader: &mut R) -> Result { + _init_and_read_tlv_fields!(reader, { + (1, erroneous_field, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, suggested_value, (option, encoding: (Vec, WithoutLength))), + (5, error, (option, encoding: (UntrustedString, WithoutLength))), + }); + + let erroneous_field = match (erroneous_field, suggested_value) { + (None, None) => None, + (None, Some(_)) => return Err(DecodeError::InvalidValue), + (Some(tlv_fieldnum), suggested_value) => { + Some(ErroneousField { tlv_fieldnum, suggested_value }) + }, + }; + + let message = match error { + None => return Err(DecodeError::InvalidValue), + Some(error) => error, + }; + + Ok(InvoiceError { erroneous_field, message }) + } +} + +impl From for InvoiceError { + fn from(error: SemanticError) -> Self { + InvoiceError { + erroneous_field: None, + message: UntrustedString(format!("{:?}", error)), + } + } +} + +#[cfg(test)] +mod tests { + use super::{ErroneousField, InvoiceError}; + + use crate::ln::msgs::DecodeError; + use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, VecWriter, WithoutLength, Writeable}; + use crate::util::string::UntrustedString; + + #[test] + fn parses_invoice_error_without_erroneous_field() { + let mut writer = VecWriter(Vec::new()); + let invoice_error = InvoiceError { + erroneous_field: None, + message: UntrustedString("Invalid value".to_string()), + }; + invoice_error.write(&mut writer).unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(invoice_error) => { + assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string())); + assert_eq!(invoice_error.erroneous_field, None); + } + Err(e) => panic!("Unexpected error: {:?}", e), + } + } + + #[test] + fn parses_invoice_error_with_erroneous_field() { + let mut writer = VecWriter(Vec::new()); + let invoice_error = InvoiceError { + erroneous_field: Some(ErroneousField { + tlv_fieldnum: 42, + suggested_value: Some(vec![42; 32]), + }), + message: UntrustedString("Invalid value".to_string()), + }; + invoice_error.write(&mut writer).unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(invoice_error) => { + assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string())); + assert_eq!( + invoice_error.erroneous_field, + Some(ErroneousField { tlv_fieldnum: 42, suggested_value: Some(vec![42; 32]) }), + ); + } + Err(e) => panic!("Unexpected error: {:?}", e), + } + } + + #[test] + fn parses_invoice_error_without_suggested_value() { + let mut writer = VecWriter(Vec::new()); + let invoice_error = InvoiceError { + erroneous_field: Some(ErroneousField { + tlv_fieldnum: 42, + suggested_value: None, + }), + message: UntrustedString("Invalid value".to_string()), + }; + invoice_error.write(&mut writer).unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(invoice_error) => { + assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string())); + assert_eq!( + invoice_error.erroneous_field, + Some(ErroneousField { tlv_fieldnum: 42, suggested_value: None }), + ); + } + Err(e) => panic!("Unexpected error: {:?}", e), + } + } + + #[test] + fn fails_parsing_invoice_error_without_message() { + let tlv_fieldnum: Option = None; + let suggested_value: Option<&Vec> = None; + let error: Option<&String> = None; + + let mut writer = VecWriter(Vec::new()); + let mut write_tlv = || -> Result<(), DecodeError> { + write_tlv_fields!(&mut writer, { + (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, suggested_value, (option, encoding: (Vec, WithoutLength))), + (5, error, (option, encoding: (String, WithoutLength))), + }); + Ok(()) + }; + write_tlv().unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(_) => panic!("Expected error"), + Err(e) => { + assert_eq!(e, DecodeError::InvalidValue); + }, + } + } + + #[test] + fn fails_parsing_invoice_error_without_field() { + let tlv_fieldnum: Option = None; + let suggested_value = vec![42; 32]; + let error = "Invalid value".to_string(); + + let mut writer = VecWriter(Vec::new()); + let mut write_tlv = || -> Result<(), DecodeError> { + write_tlv_fields!(&mut writer, { + (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, Some(&suggested_value), (option, encoding: (Vec, WithoutLength))), + (5, Some(&error), (option, encoding: (String, WithoutLength))), + }); + Ok(()) + }; + write_tlv().unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(_) => panic!("Expected error"), + Err(e) => { + assert_eq!(e, DecodeError::InvalidValue); + }, + } + } +} diff --git a/lightning/src/offers/mod.rs b/lightning/src/offers/mod.rs index 0fb20f42d79..31d8bf9cbdf 100644 --- a/lightning/src/offers/mod.rs +++ b/lightning/src/offers/mod.rs @@ -13,6 +13,7 @@ //! Offers are a flexible protocol for Lightning payments. pub mod invoice; +pub mod invoice_error; pub mod invoice_request; mod merkle; pub mod offer; diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index d6a03a88fbe..8ffcec6d175 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -178,6 +178,9 @@ macro_rules! _get_varint_length_prefixed_tlv_length { ($len: expr, $type: expr, $field: expr, (option: $trait: ident $(, $read_arg: expr)?)) => { $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, option); }; + ($len: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident))) => { + $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field.map(|f| $encoding(f)), option); + }; ($len: expr, $type: expr, $field: expr, upgradable_required) => { $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required); }; From 7533a3c42fea0ba08494b617a4f872dd04ef7f1e Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 2 Jun 2023 08:08:59 -0500 Subject: [PATCH 03/15] Pass logger to onion payload decoder In an upcoming commit, messages for BOLT 12 offers are read from the onion payload. Passing a logger allows for logging semantic errors when parsing the messages. --- lightning/src/onion_message/messenger.rs | 9 +++++---- lightning/src/onion_message/packet.rs | 8 +++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 5171422cb89..86570060945 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -301,7 +301,7 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap OnionMessageHandler for OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, - L::Target: Logger, + L::Target: Logger + Sized, CMH::Target: CustomOnionMessageHandler + Sized, { /// Handle an incoming onion message. Currently, if a message was destined for us we will log, but @@ -331,9 +331,10 @@ impl OnionMessageHandler for OnionMe } } }; - match onion_utils::decode_next_untagged_hop(onion_decode_ss, &msg.onion_routing_packet.hop_data[..], - msg.onion_routing_packet.hmac, (control_tlvs_ss, &*self.custom_handler)) - { + match onion_utils::decode_next_untagged_hop( + onion_decode_ss, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, + (control_tlvs_ss, &*self.custom_handler, &*self.logger) + ) { Ok((Payload::Receive::<<::Target as CustomOnionMessageHandler>::CustomMessage> { message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path, }, None)) => { diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 2fb2407dbdd..d4f08109cd9 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -17,6 +17,7 @@ use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; use super::messenger::CustomOnionMessageHandler; use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter}; +use crate::util::logger::Logger; use crate::util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer}; use core::cmp; @@ -201,9 +202,10 @@ impl Writeable for (Payload, [u8; 32]) { } // Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV. -impl ReadableArgs<(SharedSecret, &H)> for Payload<::CustomMessage> { - fn read(r: &mut R, args: (SharedSecret, &H)) -> Result { - let (encrypted_tlvs_ss, handler) = args; +impl +ReadableArgs<(SharedSecret, &H, &L)> for Payload<::CustomMessage> { + fn read(r: &mut R, args: (SharedSecret, &H, &L)) -> Result { + let (encrypted_tlvs_ss, handler, _logger) = args; let v: BigSize = Readable::read(r)?; let mut rd = FixedLengthReader::new(r, v.0); From a799fc9b30f039bb921f0745439a64b4964d75ca Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 14 Feb 2023 17:41:18 -0600 Subject: [PATCH 04/15] Onion message payload for BOLT 12 Offers BOLT 12 Offers makes use of onion messages to request and respond with invoices. Add these types and an error type to OnionMessageContents along with the necessary parsing and encoding. --- lightning/src/onion_message/messenger.rs | 5 +- lightning/src/onion_message/mod.rs | 1 + lightning/src/onion_message/offers.rs | 109 +++++++++++++++++++++++ lightning/src/onion_message/packet.rs | 29 +++--- 4 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 lightning/src/onion_message/offers.rs diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 86570060945..dbfa0bc636a 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -216,8 +216,8 @@ impl OnionMessenger return Err(SendError::TooFewBlindedHops); } } - let OnionMessageContents::Custom(ref msg) = message; - if msg.tlv_type() < 64 { return Err(SendError::InvalidMessage) } + + if message.tlv_type() < 64 { return Err(SendError::InvalidMessage) } // If we are sending straight to a blinded path and we are the introduction node, we need to // advance the blinded path by 1 hop so the second hop is the new introduction node. @@ -342,6 +342,7 @@ impl OnionMessageHandler for OnionMe "Received an onion message with path_id {:02x?} and {} reply_path", path_id, if reply_path.is_some() { "a" } else { "no" }); match message { + OnionMessageContents::Offers(_msg) => todo!(), OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg), } }, diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 713b83c62d6..0fcf3cc791b 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -21,6 +21,7 @@ //! [blinded paths]: crate::blinded_path::BlindedPath mod messenger; +mod offers; mod packet; #[cfg(test)] mod functional_tests; diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs new file mode 100644 index 00000000000..36363c90a62 --- /dev/null +++ b/lightning/src/onion_message/offers.rs @@ -0,0 +1,109 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Message handling for BOLT 12 Offers. + +use core::convert::TryFrom; +use crate::io::{self, Read}; +use crate::ln::msgs::DecodeError; +use crate::offers::invoice_error::InvoiceError; +use crate::offers::invoice_request::InvoiceRequest; +use crate::offers::invoice::Invoice; +use crate::offers::parse::ParseError; +use crate::util::logger::Logger; +use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; + +use crate::prelude::*; + +// TLV record types for the `onionmsg_tlv` TLV stream as defined in BOLT 4. +const INVOICE_REQUEST_TLV_TYPE: u64 = 64; +const INVOICE_TLV_TYPE: u64 = 66; +const INVOICE_ERROR_TLV_TYPE: u64 = 68; + +/// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. +/// +/// [`OnionMessage`]: crate::ln::msgs::OnionMessage +#[derive(Debug)] +pub enum OffersMessage { + /// A request for an [`Invoice`] for a particular [`Offer`]. + /// + /// [`Offer`]: crate::offers::offer::Offer + InvoiceRequest(InvoiceRequest), + + /// An [`Invoice`] sent in response to an [`InvoiceRequest`] or a [`Refund`]. + /// + /// [`Refund`]: crate::offers::refund::Refund + Invoice(Invoice), + + /// An error from handling an [`OffersMessage`]. + InvoiceError(InvoiceError), +} + +impl OffersMessage { + /// Returns whether `tlv_type` corresponds to a TLV record for Offers. + pub fn is_known_type(tlv_type: u64) -> bool { + match tlv_type { + INVOICE_REQUEST_TLV_TYPE | INVOICE_TLV_TYPE | INVOICE_ERROR_TLV_TYPE => true, + _ => false, + } + } + + /// 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) -> Result { + match tlv_type { + INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)), + INVOICE_TLV_TYPE => Ok(Self::Invoice(Invoice::try_from(bytes)?)), + _ => Err(ParseError::Decode(DecodeError::InvalidValue)), + } + } +} + +impl Writeable for OffersMessage { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + match self { + OffersMessage::InvoiceRequest(message) => message.write(w), + OffersMessage::Invoice(message) => message.write(w), + OffersMessage::InvoiceError(message) => message.write(w), + } + } +} + +impl ReadableArgs<(u64, &L)> for OffersMessage { + fn read(r: &mut R, read_args: (u64, &L)) -> Result { + let (tlv_type, logger) = read_args; + if tlv_type == INVOICE_ERROR_TLV_TYPE { + return Ok(Self::InvoiceError(InvoiceError::read(r)?)); + } + + let mut bytes = Vec::new(); + r.read_to_end(&mut bytes).unwrap(); + + match Self::parse(tlv_type, bytes) { + Ok(message) => Ok(message), + Err(ParseError::Decode(e)) => Err(e), + Err(ParseError::InvalidSemantics(e)) => { + log_trace!(logger, "Invalid semantics for TLV type {}: {:?}", tlv_type, e); + Err(DecodeError::InvalidValue) + }, + Err(ParseError::InvalidSignature(e)) => { + log_trace!(logger, "Invalid signature for TLV type {}: {:?}", tlv_type, e); + Err(DecodeError::InvalidValue) + }, + Err(_) => Err(DecodeError::InvalidValue), + } + } +} diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index d4f08109cd9..9322f9489bc 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -16,6 +16,7 @@ use crate::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs}; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; use super::messenger::CustomOnionMessageHandler; +use super::offers::OffersMessage; use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter}; use crate::util::logger::Logger; use crate::util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer}; @@ -109,10 +110,8 @@ pub(super) enum Payload { /// The contents of an onion message. In the context of offers, this would be the invoice, invoice /// request, or invoice error. pub enum OnionMessageContents { - // Coming soon: - // Invoice, - // InvoiceRequest, - // InvoiceError, + /// A message related to BOLT 12 Offers. + Offers(OffersMessage), /// A custom onion message specified by the user. Custom(T), } @@ -123,6 +122,7 @@ impl OnionMessageContents { /// This is not exported to bindings users as methods on non-cloneable enums are not currently exportable pub fn tlv_type(&self) -> u64 { match self { + &OnionMessageContents::Offers(ref msg) => msg.tlv_type(), &OnionMessageContents::Custom(ref msg) => msg.tlv_type(), } } @@ -132,6 +132,7 @@ impl OnionMessageContents { impl Writeable for OnionMessageContents { fn write(&self, w: &mut W) -> Result<(), io::Error> { match self { + OnionMessageContents::Offers(msg) => Ok(msg.write(w)?), OnionMessageContents::Custom(msg) => Ok(msg.write(w)?), } } @@ -205,7 +206,7 @@ impl Writeable for (Payload, [u8; 32]) { impl ReadableArgs<(SharedSecret, &H, &L)> for Payload<::CustomMessage> { fn read(r: &mut R, args: (SharedSecret, &H, &L)) -> Result { - let (encrypted_tlvs_ss, handler, _logger) = args; + let (encrypted_tlvs_ss, handler, logger) = args; let v: BigSize = Readable::read(r)?; let mut rd = FixedLengthReader::new(r, v.0); @@ -223,13 +224,19 @@ ReadableArgs<(SharedSecret, &H, &L)> for Payload< { - message = Some(msg); + match msg_type { + tlv_type if OffersMessage::is_known_type(tlv_type) => { + let msg = OffersMessage::read(msg_reader, (tlv_type, logger))?; + message = Some(OnionMessageContents::Offers(msg)); Ok(true) }, - Ok(None) => Ok(false), - Err(e) => Err(e), + _ => match handler.read_custom_message(msg_type, msg_reader)? { + Some(msg) => { + message = Some(OnionMessageContents::Custom(msg)); + Ok(true) + }, + None => Ok(false), + }, } }); rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?; @@ -247,7 +254,7 @@ ReadableArgs<(SharedSecret, &H, &L)> for Payload< Date: Thu, 18 May 2023 13:15:00 -0500 Subject: [PATCH 05/15] Avoid an unnecessary unwrap --- lightning/src/onion_message/packet.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 9322f9489bc..e5fb93f4501 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -250,13 +250,12 @@ ReadableArgs<(SharedSecret, &H, &L)> for Payload< { - if message.is_none() { return Err(DecodeError::InvalidValue) } Ok(Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(tlvs), reply_path, - message: message.unwrap(), + message: message.ok_or(DecodeError::InvalidValue)?, }) - } + }, } } } From f521e4cceb022768a459285e7ab3922f0f59f9d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 15 Feb 2023 16:10:59 -0600 Subject: [PATCH 06/15] OffersMessageHandler trait for OnionMessenger Add a trait for handling BOLT 12 Offers messages to OnionMessenger and a skeleton implementation of it for ChannelManager. This allows users to either provide their own custom handling Offers messages or rely on a version provided by LDK using stateless verification. --- fuzz/src/onion_message.rs | 13 ++- lightning/src/ln/peer_handler.rs | 5 +- .../src/onion_message/functional_tests.rs | 15 +++- lightning/src/onion_message/messenger.rs | 83 ++++++++++++------- lightning/src/onion_message/mod.rs | 1 + lightning/src/onion_message/offers.rs | 11 ++- lightning/src/onion_message/packet.rs | 2 +- 7 files changed, 94 insertions(+), 36 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 5fb2122ced4..ec467e22dda 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -11,7 +11,7 @@ use lightning::ln::script::ShutdownScript; use lightning::util::enforcing_trait_impls::EnforcingSigner; use lightning::util::logger::Logger; use lightning::util::ser::{Readable, Writeable, Writer}; -use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OnionMessenger}; +use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessenger}; use crate::utils::test_logger; @@ -29,8 +29,11 @@ pub fn do_test(data: &[u8], logger: &L) { node_secret: secret, counter: AtomicU64::new(0), }; + let offers_msg_handler = TestOffersMessageHandler {}; let custom_msg_handler = TestCustomMessageHandler {}; - let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &custom_msg_handler); + let onion_messenger = OnionMessenger::new( + &keys_manager, &keys_manager, logger, &offers_msg_handler, &custom_msg_handler + ); let mut pk = [2; 33]; pk[1] = 0xff; let peer_node_id_not_used = PublicKey::from_slice(&pk).unwrap(); onion_messenger.handle_onion_message(&peer_node_id_not_used, &msg); @@ -50,6 +53,12 @@ pub extern "C" fn onion_message_run(data: *const u8, datalen: usize) { do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, &logger); } +struct TestOffersMessageHandler {} + +impl OffersMessageHandler for TestOffersMessageHandler { + fn handle_message(&self, _message: OffersMessage) {} +} + struct TestCustomMessage {} const CUSTOM_MESSAGE_TYPE: u64 = 4242; diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 06c6932cce3..f5c6341bb3e 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -28,7 +28,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, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias}; use crate::util::atomic_counter::AtomicCounter; use crate::util::logger::Logger; @@ -118,6 +118,9 @@ impl OnionMessageHandler for IgnoringMessageHandler { InitFeatures::empty() } } +impl OffersMessageHandler for IgnoringMessageHandler { + fn handle_message(&self, _msg: OffersMessage) {} +} impl CustomOnionMessageHandler for IgnoringMessageHandler { type CustomMessage = Infallible; fn handle_custom_message(&self, _msg: Infallible) { diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 96e0c44b2ce..cc83f2d2c9e 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -13,7 +13,7 @@ use crate::blinded_path::BlindedPath; use crate::sign::{NodeSigner, Recipient}; use crate::ln::features::InitFeatures; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; -use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError}; +use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, SendError}; use crate::util::ser::{Writeable, Writer}; use crate::util::test_utils; @@ -27,7 +27,7 @@ use crate::sync::Arc; struct MessengerNode { keys_manager: Arc, - messenger: OnionMessenger, Arc, Arc, Arc>, + messenger: OnionMessenger, Arc, Arc, Arc, Arc>, custom_message_handler: Arc, logger: Arc, } @@ -38,6 +38,14 @@ impl MessengerNode { } } +struct TestOffersMessageHandler {} + +impl OffersMessageHandler for TestOffersMessageHandler { + fn handle_message(&self, _message: OffersMessage) { + todo!() + } +} + #[derive(Clone)] struct TestCustomMessage {} @@ -98,10 +106,11 @@ fn create_nodes(num_messengers: u8) -> Vec { let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i))); let seed = [i as u8; 32]; let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet)); + let offers_message_handler = Arc::new(TestOffersMessageHandler {}); let custom_message_handler = Arc::new(TestCustomMessageHandler::new()); nodes.push(MessengerNode { keys_manager: keys_manager.clone(), - messenger: OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), custom_message_handler.clone()), + messenger: OnionMessenger::new(keys_manager.clone(), keys_manager, logger.clone(), offers_message_handler, custom_message_handler.clone()), custom_message_handler, logger, }); diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index dbfa0bc636a..23c9db0c45b 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -23,6 +23,7 @@ use crate::ln::msgs::{self, OnionMessageHandler}; use crate::ln::onion_utils; use crate::ln::peer_handler::IgnoringMessageHandler; pub use super::packet::{CustomOnionMessageContents, OnionMessageContents}; +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; use crate::util::ser::Writeable; @@ -63,10 +64,11 @@ use crate::prelude::*; /// # let hop_node_id1 = PublicKey::from_secret_key(&secp_ctx, &node_secret); /// # let (hop_node_id2, hop_node_id3, hop_node_id4) = (hop_node_id1, hop_node_id1, hop_node_id1); /// # let destination_node_id = hop_node_id1; -/// # let your_custom_message_handler = IgnoringMessageHandler {}; +/// # let custom_message_handler = IgnoringMessageHandler {}; +/// # let offers_message_handler = IgnoringMessageHandler {}; /// // Create the onion messenger. This must use the same `keys_manager` as is passed to your /// // ChannelManager. -/// let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &your_custom_message_handler); +/// let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &offers_message_handler, &custom_message_handler); /// /// # struct YourCustomMessage {} /// impl Writeable for YourCustomMessage { @@ -103,20 +105,21 @@ use crate::prelude::*; /// /// [offers]: /// [`OnionMessenger`]: crate::onion_message::OnionMessenger -pub struct OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH:: Target: CustomOnionMessageHandler, +pub struct OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + OMH::Target: OffersMessageHandler, + CMH:: Target: CustomOnionMessageHandler, { entropy_source: ES, node_signer: NS, logger: L, pending_messages: Mutex>>, secp_ctx: Secp256k1, + offers_handler: OMH, custom_handler: CMH, - // Coming soon: - // invoice_handler: InvoiceHandler, } /// The destination of an onion message. @@ -187,15 +190,19 @@ pub trait CustomOnionMessageHandler { fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError>; } -impl OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH::Target: CustomOnionMessageHandler, +impl OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + OMH::Target: OffersMessageHandler, + CMH::Target: CustomOnionMessageHandler, { /// Constructs a new `OnionMessenger` to send, forward, and delegate received onion messages to /// their respective handlers. - pub fn new(entropy_source: ES, node_signer: NS, logger: L, custom_handler: CMH) -> Self { + pub fn new( + entropy_source: ES, node_signer: NS, logger: L, offers_handler: OMH, custom_handler: CMH + ) -> Self { let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); OnionMessenger { @@ -204,6 +211,7 @@ impl OnionMessenger pending_messages: Mutex::new(HashMap::new()), secp_ctx, logger, + offers_handler, custom_handler, } } @@ -298,11 +306,14 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap OnionMessageHandler for OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger + Sized, - CMH::Target: CustomOnionMessageHandler + Sized, +impl OnionMessageHandler +for OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + OMH::Target: OffersMessageHandler, + CMH::Target: CustomOnionMessageHandler + Sized, { /// Handle an incoming onion message. Currently, if a message was destined for us we will log, but /// soon we'll delegate the onion message to a handler that can generate invoices or send @@ -342,7 +353,7 @@ impl OnionMessageHandler for OnionMe "Received an onion message with path_id {:02x?} and {} reply_path", path_id, if reply_path.is_some() { "a" } else { "no" }); match message { - OnionMessageContents::Offers(_msg) => todo!(), + OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg), OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg), } }, @@ -445,11 +456,14 @@ impl OnionMessageHandler for OnionMe } } -impl OnionMessageProvider for OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH::Target: CustomOnionMessageHandler, +impl OnionMessageProvider +for OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + OMH::Target: OffersMessageHandler, + CMH::Target: CustomOnionMessageHandler, { fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option { let mut pending_msgs = self.pending_messages.lock().unwrap(); @@ -469,7 +483,14 @@ impl OnionMessageProvider for OnionM /// /// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager /// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager -pub type SimpleArcOnionMessenger = OnionMessenger, Arc, Arc, IgnoringMessageHandler>; +pub type SimpleArcOnionMessenger = OnionMessenger< + Arc, + Arc, + Arc, + IgnoringMessageHandler, + IgnoringMessageHandler +>; + /// Useful for simplifying the parameters of [`SimpleRefChannelManager`] and /// [`SimpleRefPeerManager`]. See their docs for more details. /// @@ -477,7 +498,13 @@ pub type SimpleArcOnionMessenger = OnionMessenger, Arc = OnionMessenger<&'a KeysManager, &'a KeysManager, &'b L, IgnoringMessageHandler>; +pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger< + &'a KeysManager, + &'a KeysManager, + &'b L, + IgnoringMessageHandler, + IgnoringMessageHandler +>; /// Construct onion packet payloads and keys for sending an onion message along the given /// `unblinded_path` to the given `destination`. diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 0fcf3cc791b..e0b3f500195 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -28,4 +28,5 @@ mod functional_tests; // Re-export structs so they can be imported with just the `onion_message::` module prefix. pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::offers::{OffersMessage, OffersMessageHandler}; pub(crate) use self::packet::{ControlTlvs, Packet}; diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 36363c90a62..98276d1bfb7 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -26,6 +26,15 @@ const INVOICE_REQUEST_TLV_TYPE: u64 = 64; const INVOICE_TLV_TYPE: u64 = 66; const INVOICE_ERROR_TLV_TYPE: u64 = 68; +/// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload. +/// +/// [`OnionMessage`]: crate::ln::msgs::OnionMessage +pub trait OffersMessageHandler { + /// Handles the given message by either responding with an [`Invoice`], sending a payment, or + /// replying with an error. + fn handle_message(&self, message: OffersMessage); +} + /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. /// /// [`OnionMessage`]: crate::ln::msgs::OnionMessage @@ -82,7 +91,7 @@ impl Writeable for OffersMessage { } } -impl ReadableArgs<(u64, &L)> for OffersMessage { +impl ReadableArgs<(u64, &L)> for OffersMessage { fn read(r: &mut R, read_args: (u64, &L)) -> Result { let (tlv_type, logger) = read_args; if tlv_type == INVOICE_ERROR_TLV_TYPE { diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index e5fb93f4501..663a0b0cdc7 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -203,7 +203,7 @@ impl Writeable for (Payload, [u8; 32]) { } // Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV. -impl +impl ReadableArgs<(SharedSecret, &H, &L)> for Payload<::CustomMessage> { fn read(r: &mut R, args: (SharedSecret, &H, &L)) -> Result { let (encrypted_tlvs_ss, handler, logger) = args; From f15da3d294414b9948938ebeb0e64d2df44f90b9 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 25 May 2023 15:02:10 -0500 Subject: [PATCH 07/15] Add OnionMessagePath wrapper struct To avoid confusion in the upcoming MessageRouter trait, introduce an OnionMessagePath struct that wraps the intermediate nodes and the destination. Use this in OnionMessenger::send_onion_message. --- .../src/onion_message/functional_tests.rs | 94 +++++++++++++++---- lightning/src/onion_message/messenger.rs | 38 ++++++-- lightning/src/onion_message/mod.rs | 2 +- 3 files changed, 106 insertions(+), 28 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index cc83f2d2c9e..90243f357c3 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -13,7 +13,7 @@ use crate::blinded_path::BlindedPath; use crate::sign::{NodeSigner, Recipient}; use crate::ln::features::InitFeatures; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; -use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, SendError}; +use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError}; use crate::util::ser::{Writeable, Writer}; use crate::util::test_utils; @@ -146,7 +146,11 @@ fn one_hop() { let nodes = create_nodes(2); let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); - nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::Node(nodes[1].get_node_pk()), + }; + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); pass_along_path(&nodes); } @@ -155,7 +159,11 @@ fn two_unblinded_hops() { let nodes = create_nodes(3); let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); - nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), test_msg, None).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![nodes[1].get_node_pk()], + destination: Destination::Node(nodes[2].get_node_pk()), + }; + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); pass_along_path(&nodes); } @@ -166,8 +174,12 @@ fn two_unblinded_two_blinded() { 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(); + let path = OnionMessagePath { + intermediate_nodes: vec![nodes[1].get_node_pk(), nodes[2].get_node_pk()], + destination: Destination::BlindedPath(blinded_path), + }; - nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedPath(blinded_path), test_msg, None).unwrap(); + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); pass_along_path(&nodes); } @@ -178,8 +190,12 @@ fn three_blinded_hops() { 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(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), test_msg, None).unwrap(); + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); pass_along_path(&nodes); } @@ -190,8 +206,12 @@ fn too_big_packet_error() { let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); let hop_node_id = nodes[1].get_node_pk(); - let hops = [hop_node_id; 400]; - let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), test_msg, None).unwrap_err(); + let hops = vec![hop_node_id; 400]; + let path = OnionMessagePath { + intermediate_nodes: hops, + destination: Destination::Node(hop_node_id), + }; + let err = nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap_err(); assert_eq!(err, SendError::TooBigPacket); } @@ -204,13 +224,21 @@ fn we_are_intro_node() { let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); pass_along_path(&nodes); // Try with a two-hop blinded path where we are the introduction node. let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk()], &*nodes[1].keys_manager, &secp_ctx).unwrap(); - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), None).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap(); nodes.remove(2); pass_along_path(&nodes); } @@ -225,14 +253,22 @@ fn invalid_blinded_path_error() { let secp_ctx = Secp256k1::new(); let mut blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); blinded_path.blinded_hops.clear(); - let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg.clone()), None).unwrap_err(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; + let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), None).unwrap_err(); assert_eq!(err, SendError::TooFewBlindedHops); // 1 hop let mut blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); blinded_path.blinded_hops.remove(0); assert_eq!(blinded_path.blinded_hops.len(), 1); - let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), None).unwrap_err(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; + let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap_err(); assert_eq!(err, SendError::TooFewBlindedHops); } @@ -243,8 +279,12 @@ fn reply_path() { let secp_ctx = Secp256k1::new(); // Destination::Node + let path = OnionMessagePath { + intermediate_nodes: vec![nodes[1].get_node_pk(), nodes[2].get_node_pk()], + 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(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap(); pass_along_path(&nodes); // Make sure the last node successfully decoded the reply path. nodes[3].logger.assert_log_contains( @@ -253,9 +293,13 @@ fn reply_path() { // Destination::BlindedPath 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(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_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(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap(); pass_along_path(&nodes); nodes[3].logger.assert_log_contains( "lightning::onion_message::messenger", @@ -279,7 +323,11 @@ fn invalid_custom_message_type() { } let test_msg = OnionMessageContents::Custom(InvalidCustomMessage {}); - let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap_err(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::Node(nodes[1].get_node_pk()), + }; + let err = nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap_err(); assert_eq!(err, SendError::InvalidMessage); } @@ -287,10 +335,14 @@ fn invalid_custom_message_type() { fn peer_buffer_full() { let nodes = create_nodes(2); let test_msg = TestCustomMessage {}; + let path = OnionMessagePath { + intermediate_nodes: vec![], + 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(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); + nodes[0].messenger.send_onion_message(path.clone(), OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); } - let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg), None).unwrap_err(); + let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap_err(); assert_eq!(err, SendError::BufferFull); } @@ -302,11 +354,15 @@ fn many_hops() { let nodes = create_nodes(num_nodes as u8); let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); - let mut intermediates = vec![]; + let mut intermediate_nodes = vec![]; for i in 1..(num_nodes-1) { - intermediates.push(nodes[i].get_node_pk()); + intermediate_nodes.push(nodes[i].get_node_pk()); } - nodes[0].messenger.send_onion_message(&intermediates, Destination::Node(nodes[num_nodes-1].get_node_pk()), test_msg, None).unwrap(); + let path = OnionMessagePath { + intermediate_nodes, + destination: Destination::Node(nodes[num_nodes-1].get_node_pk()), + }; + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); pass_along_path(&nodes); } diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 23c9db0c45b..09a23075916 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -46,7 +46,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, OnionMessageContents, OnionMessenger}; +/// # use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessagePath, OnionMessenger}; /// # use lightning::util::logger::{Logger, Record}; /// # use lightning::util::ser::{Writeable, Writer}; /// # use lightning::io; @@ -84,11 +84,14 @@ use crate::prelude::*; /// } /// } /// // Send a custom onion message to a node id. -/// let intermediate_hops = [hop_node_id1, hop_node_id2]; +/// let path = OnionMessagePath { +/// intermediate_nodes: vec![hop_node_id1, hop_node_id2], +/// destination: Destination::Node(destination_node_id), +/// }; /// let reply_path = None; /// # let your_custom_message = YourCustomMessage {}; /// let message = OnionMessageContents::Custom(your_custom_message); -/// onion_messenger.send_onion_message(&intermediate_hops, Destination::Node(destination_node_id), message, reply_path); +/// onion_messenger.send_onion_message(path, message, reply_path); /// /// // Create a blinded path to yourself, for someone to send an onion message to. /// # let your_node_id = hop_node_id1; @@ -96,11 +99,14 @@ use crate::prelude::*; /// let blinded_path = BlindedPath::new_for_message(&hops, &keys_manager, &secp_ctx).unwrap(); /// /// // Send a custom onion message to a blinded path. -/// # let intermediate_hops = [hop_node_id1, hop_node_id2]; +/// let path = OnionMessagePath { +/// intermediate_nodes: vec![hop_node_id1, hop_node_id2], +/// destination: Destination::BlindedPath(blinded_path), +/// }; /// let reply_path = None; /// # let your_custom_message = YourCustomMessage {}; /// let message = OnionMessageContents::Custom(your_custom_message); -/// onion_messenger.send_onion_message(&intermediate_hops, Destination::BlindedPath(blinded_path), message, reply_path); +/// onion_messenger.send_onion_message(path, message, reply_path); /// ``` /// /// [offers]: @@ -122,7 +128,18 @@ where custom_handler: CMH, } +/// A path for sending an [`msgs::OnionMessage`]. +#[derive(Clone)] +pub struct OnionMessagePath { + /// Nodes on the path between the sender and the destination. + pub intermediate_nodes: Vec, + + /// The recipient of the message. + pub destination: Destination, +} + /// The destination of an onion message. +#[derive(Clone)] pub enum Destination { /// We're sending this onion message to a node. Node(PublicKey), @@ -216,9 +233,14 @@ where } } - /// Send an onion message with contents `message` to `destination`, routing it through `intermediate_nodes`. + /// Send an onion message with contents `message` to the destination of `path`. + /// /// See [`OnionMessenger`] for example usage. - pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], mut destination: Destination, message: OnionMessageContents, reply_path: Option) -> Result<(), SendError> { + pub fn send_onion_message( + &self, path: OnionMessagePath, message: OnionMessageContents, + reply_path: Option + ) -> Result<(), SendError> { + let OnionMessagePath { intermediate_nodes, mut destination } = path; if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination { if blinded_hops.len() < 2 { return Err(SendError::TooFewBlindedHops); @@ -252,7 +274,7 @@ where } }; let (packet_payloads, packet_keys) = packet_payloads_and_keys( - &self.secp_ctx, intermediate_nodes, destination, message, reply_path, &blinding_secret) + &self.secp_ctx, &intermediate_nodes, destination, message, reply_path, &blinding_secret) .map_err(|e| SendError::Secp256k1(e))?; let prng_seed = self.entropy_source.get_secure_random_bytes(); diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index e0b3f500195..35bf6a99e6d 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -27,6 +27,6 @@ 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, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; pub use self::offers::{OffersMessage, OffersMessageHandler}; pub(crate) use self::packet::{ControlTlvs, Packet}; From a71000f35dd23949d26fffd421d6f6478f0cd6b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 22 Feb 2023 22:22:42 -0600 Subject: [PATCH 08/15] MessageRouter trait for OnionMessenger Add a trait for finding routes for onion messages and parameterize OnionMessenger with it. This allows OnionMessenger to reply to messages that it handles via one of its handlers (e.g., OffersMessageHandler). --- fuzz/src/onion_message.rs | 16 +++++- lightning-background-processor/src/lib.rs | 3 +- lightning/src/ln/peer_handler.rs | 22 +++++++- .../src/onion_message/functional_tests.rs | 27 ++++++++-- lightning/src/onion_message/messenger.rs | 54 +++++++++++++++---- lightning/src/onion_message/mod.rs | 2 +- 6 files changed, 104 insertions(+), 20 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index ec467e22dda..fd19a611458 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -11,7 +11,7 @@ use lightning::ln::script::ShutdownScript; use lightning::util::enforcing_trait_impls::EnforcingSigner; use lightning::util::logger::Logger; use lightning::util::ser::{Readable, Writeable, Writer}; -use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessenger}; +use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessagePath, OnionMessenger}; use crate::utils::test_logger; @@ -29,10 +29,12 @@ pub fn do_test(data: &[u8], logger: &L) { node_secret: secret, counter: AtomicU64::new(0), }; + let message_router = TestMessageRouter {}; let offers_msg_handler = TestOffersMessageHandler {}; let custom_msg_handler = TestCustomMessageHandler {}; let onion_messenger = OnionMessenger::new( - &keys_manager, &keys_manager, logger, &offers_msg_handler, &custom_msg_handler + &keys_manager, &keys_manager, logger, &message_router, &offers_msg_handler, + &custom_msg_handler ); let mut pk = [2; 33]; pk[1] = 0xff; let peer_node_id_not_used = PublicKey::from_slice(&pk).unwrap(); @@ -53,6 +55,16 @@ pub extern "C" fn onion_message_run(data: *const u8, datalen: usize) { do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, &logger); } +struct TestMessageRouter {} + +impl MessageRouter for TestMessageRouter { + fn find_path( + &self, _sender: PublicKey, _peers: Vec, _destination: Destination + ) -> Result { + unreachable!() + } +} + struct TestOffersMessageHandler {} impl OffersMessageHandler for TestOffersMessageHandler { diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 248f79dd59e..0cfa9801bad 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -519,8 +519,9 @@ use core::task; /// # type MyUtxoLookup = dyn lightning::routing::utxo::UtxoLookup + Send + Sync; /// # type MyFilter = dyn lightning::chain::Filter + Send + Sync; /// # type MyLogger = dyn lightning::util::logger::Logger + Send + Sync; +/// # type MyMessageRouter = dyn lightning::onion_message::MessageRouter + Send + Sync; /// # type MyChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; -/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; +/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; /// # type MyNetworkGraph = lightning::routing::gossip::NetworkGraph>; /// # type MyGossipSync = lightning::routing::gossip::P2PGossipSync, Arc, Arc>; /// # type MyChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager; diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index f5c6341bb3e..56e0a1e0a44 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -607,7 +607,15 @@ impl Peer { /// issues such as overly long function definitions. /// /// This is not exported to bindings users as `Arc`s don't make sense in bindings. -pub type SimpleArcPeerManager = PeerManager>, Arc>>, Arc, Arc>>, Arc>, Arc, IgnoringMessageHandler, Arc>; +pub type SimpleArcPeerManager = PeerManager< + SD, + Arc>, + Arc>>, Arc, Arc>>, + Arc>, + Arc, + IgnoringMessageHandler, + Arc +>; /// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference /// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't @@ -617,7 +625,17 @@ pub type SimpleArcPeerManager = PeerManager = PeerManager, &'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, &'i SimpleRefOnionMessenger<'j, 'k, L>, &'f L, IgnoringMessageHandler, &'c KeysManager>; +pub type SimpleRefPeerManager< + 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, SD, M, T, F, C, L, R +> = PeerManager< + SD, + &'n SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'm, M, T, F, L>, + &'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, + &'i SimpleRefOnionMessenger<'g, 'm, 'n, L, R>, + &'f L, + IgnoringMessageHandler, + &'c KeysManager +>; /// A generic trait which is implemented for all [`PeerManager`]s. This makes bounding functions or diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 90243f357c3..a5effdd92fe 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -13,7 +13,7 @@ use crate::blinded_path::BlindedPath; use crate::sign::{NodeSigner, Recipient}; use crate::ln::features::InitFeatures; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; -use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError}; +use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError}; use crate::util::ser::{Writeable, Writer}; use crate::util::test_utils; @@ -27,7 +27,14 @@ use crate::sync::Arc; struct MessengerNode { keys_manager: Arc, - messenger: OnionMessenger, Arc, Arc, Arc, Arc>, + messenger: OnionMessenger< + Arc, + Arc, + Arc, + Arc, + Arc, + Arc + >, custom_message_handler: Arc, logger: Arc, } @@ -38,6 +45,16 @@ impl MessengerNode { } } +struct TestMessageRouter {} + +impl MessageRouter for TestMessageRouter { + fn find_path( + &self, _sender: PublicKey, _peers: Vec, _destination: Destination + ) -> Result { + todo!() + } +} + struct TestOffersMessageHandler {} impl OffersMessageHandler for TestOffersMessageHandler { @@ -106,11 +123,15 @@ fn create_nodes(num_messengers: u8) -> Vec { let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i))); let seed = [i as u8; 32]; let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet)); + let message_router = Arc::new(TestMessageRouter {}); let offers_message_handler = Arc::new(TestOffersMessageHandler {}); let custom_message_handler = Arc::new(TestCustomMessageHandler::new()); nodes.push(MessengerNode { keys_manager: keys_manager.clone(), - messenger: OnionMessenger::new(keys_manager.clone(), keys_manager, logger.clone(), offers_message_handler, custom_message_handler.clone()), + messenger: OnionMessenger::new( + keys_manager.clone(), keys_manager, logger.clone(), message_router, + offers_message_handler, custom_message_handler.clone() + ), custom_message_handler, logger, }); diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 09a23075916..07cb0bc1e98 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -46,7 +46,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, OnionMessageContents, OnionMessagePath, OnionMessenger}; +/// # use lightning::onion_message::{CustomOnionMessageContents, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger}; /// # use lightning::util::logger::{Logger, Record}; /// # use lightning::util::ser::{Writeable, Writer}; /// # use lightning::io; @@ -55,6 +55,12 @@ use crate::prelude::*; /// # impl Logger for FakeLogger { /// # fn log(&self, record: &Record) { unimplemented!() } /// # } +/// # struct FakeMessageRouter {} +/// # impl MessageRouter for FakeMessageRouter { +/// # fn find_path(&self, sender: PublicKey, peers: Vec, destination: Destination) -> Result { +/// # unimplemented!() +/// # } +/// # } /// # let seed = [42u8; 32]; /// # let time = Duration::from_secs(123456); /// # let keys_manager = KeysManager::new(&seed, time.as_secs(), time.subsec_nanos()); @@ -64,11 +70,15 @@ use crate::prelude::*; /// # let hop_node_id1 = PublicKey::from_secret_key(&secp_ctx, &node_secret); /// # let (hop_node_id2, hop_node_id3, hop_node_id4) = (hop_node_id1, hop_node_id1, hop_node_id1); /// # let destination_node_id = hop_node_id1; +/// # let message_router = Arc::new(FakeMessageRouter {}); /// # let custom_message_handler = IgnoringMessageHandler {}; /// # let offers_message_handler = IgnoringMessageHandler {}; /// // Create the onion messenger. This must use the same `keys_manager` as is passed to your /// // ChannelManager. -/// let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &offers_message_handler, &custom_message_handler); +/// let onion_messenger = OnionMessenger::new( +/// &keys_manager, &keys_manager, logger, message_router, &offers_message_handler, +/// &custom_message_handler +/// ); /// /// # struct YourCustomMessage {} /// impl Writeable for YourCustomMessage { @@ -111,11 +121,12 @@ use crate::prelude::*; /// /// [offers]: /// [`OnionMessenger`]: crate::onion_message::OnionMessenger -pub struct OnionMessenger +pub struct OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, + MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, CMH:: Target: CustomOnionMessageHandler, { @@ -124,10 +135,23 @@ where logger: L, pending_messages: Mutex>>, secp_ctx: Secp256k1, + message_router: MR, offers_handler: OMH, custom_handler: CMH, } +/// A trait defining behavior for routing an [`OnionMessage`]. +/// +/// [`OnionMessage`]: msgs::OnionMessage +pub trait MessageRouter { + /// Returns a route for sending an [`OnionMessage`] to the given [`Destination`]. + /// + /// [`OnionMessage`]: msgs::OnionMessage + fn find_path( + &self, sender: PublicKey, peers: Vec, destination: Destination + ) -> Result; +} + /// A path for sending an [`msgs::OnionMessage`]. #[derive(Clone)] pub struct OnionMessagePath { @@ -207,18 +231,21 @@ pub trait CustomOnionMessageHandler { fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError>; } -impl OnionMessenger +impl +OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, + MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, CMH::Target: CustomOnionMessageHandler, { /// Constructs a new `OnionMessenger` to send, forward, and delegate received onion messages to /// their respective handlers. pub fn new( - entropy_source: ES, node_signer: NS, logger: L, offers_handler: OMH, custom_handler: CMH + entropy_source: ES, node_signer: NS, logger: L, message_router: MR, offers_handler: OMH, + custom_handler: CMH ) -> Self { let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); @@ -228,6 +255,7 @@ where pending_messages: Mutex::new(HashMap::new()), secp_ctx, logger, + message_router, offers_handler, custom_handler, } @@ -328,12 +356,13 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap OnionMessageHandler -for OnionMessenger +impl OnionMessageHandler +for OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, + MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, CMH::Target: CustomOnionMessageHandler + Sized, { @@ -478,12 +507,13 @@ where } } -impl OnionMessageProvider -for OnionMessenger +impl OnionMessageProvider +for OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, + MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, CMH::Target: CustomOnionMessageHandler, { @@ -505,10 +535,11 @@ where /// /// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager /// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager -pub type SimpleArcOnionMessenger = OnionMessenger< +pub type SimpleArcOnionMessenger = OnionMessenger< Arc, Arc, Arc, + Arc, IgnoringMessageHandler, IgnoringMessageHandler >; @@ -520,10 +551,11 @@ pub type SimpleArcOnionMessenger = OnionMessenger< /// /// [`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager /// [`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager -pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger< +pub type SimpleRefOnionMessenger<'a, 'b, 'c, L, R> = OnionMessenger< &'a KeysManager, &'a KeysManager, &'b L, + &'c R, IgnoringMessageHandler, IgnoringMessageHandler >; diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 35bf6a99e6d..556ae89820b 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -27,6 +27,6 @@ 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, Destination, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; pub use self::offers::{OffersMessage, OffersMessageHandler}; pub(crate) use self::packet::{ControlTlvs, Packet}; From c17c2ae3c02487c41e9be8bc507656e43878bb3f Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Sat, 18 Feb 2023 19:29:14 -0600 Subject: [PATCH 09/15] Support onion message replies in OnionMessenger Modify onion message handlers to return an optional response message for OnionMessenger to reply with. --- fuzz/src/onion_message.rs | 8 +- lightning/src/ln/peer_handler.rs | 4 +- .../src/onion_message/functional_tests.rs | 7 +- lightning/src/onion_message/messenger.rs | 73 +++++++++++++++++-- lightning/src/onion_message/offers.rs | 2 +- 5 files changed, 81 insertions(+), 13 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index fd19a611458..0e31347f523 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -68,7 +68,9 @@ impl MessageRouter for TestMessageRouter { struct TestOffersMessageHandler {} impl OffersMessageHandler for TestOffersMessageHandler { - fn handle_message(&self, _message: OffersMessage) {} + fn handle_message(&self, _message: OffersMessage) -> Option { + None + } } struct TestCustomMessage {} @@ -92,7 +94,9 @@ struct TestCustomMessageHandler {} impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, _msg: Self::CustomMessage) {} + fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option { + None + } fn read_custom_message(&self, _message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError> { let mut buf = Vec::new(); buffer.read_to_end(&mut buf)?; diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 56e0a1e0a44..931e8c4e424 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -119,11 +119,11 @@ impl OnionMessageHandler for IgnoringMessageHandler { } } impl OffersMessageHandler for IgnoringMessageHandler { - fn handle_message(&self, _msg: OffersMessage) {} + fn handle_message(&self, _msg: OffersMessage) -> Option { None } } impl CustomOnionMessageHandler for IgnoringMessageHandler { type CustomMessage = Infallible; - fn handle_custom_message(&self, _msg: Infallible) { + fn handle_custom_message(&self, _msg: Infallible) -> Option { // Since we always return `None` in the read the handle method should never be called. unreachable!(); } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index a5effdd92fe..e6058c459eb 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -58,8 +58,8 @@ impl MessageRouter for TestMessageRouter { struct TestOffersMessageHandler {} impl OffersMessageHandler for TestOffersMessageHandler { - fn handle_message(&self, _message: OffersMessage) { - todo!() + fn handle_message(&self, _message: OffersMessage) -> Option { + None } } @@ -104,8 +104,9 @@ impl Drop for TestCustomMessageHandler { impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, _msg: Self::CustomMessage) { + fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option { self.num_messages_expected.fetch_sub(1, Ordering::SeqCst); + None } fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, DecodeError> where Self: Sized { if message_type == CUSTOM_MESSAGE_TYPE { diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 07cb0bc1e98..7c259113934 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -224,8 +224,10 @@ 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; - /// Called with the custom message that was received. - fn handle_custom_message(&self, msg: Self::CustomMessage); + + /// Called with the custom message that was received, returning a response to send, if any. + fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option; + /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the /// message type is unknown. fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError>; @@ -320,6 +322,56 @@ where } } + fn respond_with_onion_message( + &self, response: OnionMessageContents, path_id: Option<[u8; 32]>, + reply_path: Option + ) { + let sender = match self.node_signer.get_node_id(Recipient::Node) { + Ok(node_id) => node_id, + Err(_) => { + log_warn!( + self.logger, "Unable to retrieve node id when responding to onion message with \ + path_id {:02x?}", path_id + ); + return; + } + }; + + let peers = self.pending_messages.lock().unwrap().keys().copied().collect(); + + let destination = match reply_path { + Some(reply_path) => Destination::BlindedPath(reply_path), + None => { + log_trace!( + self.logger, "Missing reply path when responding to onion message with path_id \ + {:02x?}", path_id + ); + return; + }, + }; + + let path = match self.message_router.find_path(sender, peers, destination) { + Ok(path) => path, + Err(()) => { + log_trace!( + self.logger, "Failed to find path when responding to onion message with \ + path_id {:02x?}", path_id + ); + return; + }, + }; + + log_trace!(self.logger, "Responding to onion message with path_id {:02x?}", path_id); + + if let Err(e) = self.send_onion_message(path, response, None) { + log_trace!( + self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}", + path_id, e + ); + return; + } + } + #[cfg(test)] pub(super) fn release_pending_msgs(&self) -> HashMap> { let mut pending_msgs = self.pending_messages.lock().unwrap(); @@ -403,9 +455,20 @@ where log_info!(self.logger, "Received an onion message with path_id {:02x?} and {} reply_path", path_id, if reply_path.is_some() { "a" } else { "no" }); - match message { - OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg), - OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg), + + let response = match message { + OnionMessageContents::Offers(msg) => { + self.offers_handler.handle_message(msg) + .map(|msg| OnionMessageContents::Offers(msg)) + }, + OnionMessageContents::Custom(msg) => { + self.custom_handler.handle_custom_message(msg) + .map(|msg| OnionMessageContents::Custom(msg)) + }, + }; + + if let Some(response) = response { + self.respond_with_onion_message(response, path_id, reply_path); } }, Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs { diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 98276d1bfb7..f82afdd618a 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -32,7 +32,7 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68; pub trait OffersMessageHandler { /// Handles the given message by either responding with an [`Invoice`], sending a payment, or /// replying with an error. - fn handle_message(&self, message: OffersMessage); + fn handle_message(&self, message: OffersMessage) -> Option; } /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. From c83d5bf16225057c86fdab53d0b3333e7536ce56 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 8 Jun 2023 14:30:38 -0500 Subject: [PATCH 10/15] Remove unnecessary Sized bound --- lightning/src/onion_message/messenger.rs | 2 +- lightning/src/onion_message/packet.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 7c259113934..655fb6e491d 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -416,7 +416,7 @@ where L::Target: Logger, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, - CMH::Target: CustomOnionMessageHandler + Sized, + CMH::Target: CustomOnionMessageHandler, { /// Handle an incoming onion message. Currently, if a message was destined for us we will log, but /// soon we'll delegate the onion message to a handler that can generate invoices or send diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 663a0b0cdc7..1c3595c3712 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -203,7 +203,7 @@ impl Writeable for (Payload, [u8; 32]) { } // Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV. -impl +impl ReadableArgs<(SharedSecret, &H, &L)> for Payload<::CustomMessage> { fn read(r: &mut R, args: (SharedSecret, &H, &L)) -> Result { let (encrypted_tlvs_ss, handler, logger) = args; From ceb90386a95637ed613b872b8c081a5c5d4d8495 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 23 Feb 2023 16:54:58 -0600 Subject: [PATCH 11/15] Split TestCustomMessage into Request and Response This will allow for testing onion message replies. --- .../src/onion_message/functional_tests.rs | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index e6058c459eb..dfa7c6a3b0a 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -64,20 +64,31 @@ impl OffersMessageHandler for TestOffersMessageHandler { } #[derive(Clone)] -struct TestCustomMessage {} +enum TestCustomMessage { + Request, + Response, +} -const CUSTOM_MESSAGE_TYPE: u64 = 4242; -const CUSTOM_MESSAGE_CONTENTS: [u8; 32] = [42; 32]; +const CUSTOM_REQUEST_MESSAGE_TYPE: u64 = 4242; +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 { fn tlv_type(&self) -> u64 { - CUSTOM_MESSAGE_TYPE + match self { + TestCustomMessage::Request => CUSTOM_REQUEST_MESSAGE_TYPE, + TestCustomMessage::Response => CUSTOM_RESPONSE_MESSAGE_TYPE, + } } } impl Writeable for TestCustomMessage { fn write(&self, w: &mut W) -> Result<(), io::Error> { - Ok(CUSTOM_MESSAGE_CONTENTS.write(w)?) + match self { + TestCustomMessage::Request => Ok(CUSTOM_REQUEST_MESSAGE_CONTENTS.write(w)?), + TestCustomMessage::Response => Ok(CUSTOM_RESPONSE_MESSAGE_CONTENTS.write(w)?), + } } } @@ -104,17 +115,27 @@ impl Drop for TestCustomMessageHandler { impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option { + fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option { self.num_messages_expected.fetch_sub(1, Ordering::SeqCst); - None + match msg { + TestCustomMessage::Request => Some(TestCustomMessage::Response), + TestCustomMessage::Response => None, + } } fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, DecodeError> where Self: Sized { - if message_type == CUSTOM_MESSAGE_TYPE { - let buf = read_to_end(buffer)?; - assert_eq!(buf, CUSTOM_MESSAGE_CONTENTS); - return Ok(Some(TestCustomMessage {})) + match message_type { + CUSTOM_REQUEST_MESSAGE_TYPE => { + let buf = read_to_end(buffer)?; + assert_eq!(buf, CUSTOM_REQUEST_MESSAGE_CONTENTS); + Ok(Some(TestCustomMessage::Request)) + }, + CUSTOM_RESPONSE_MESSAGE_TYPE => { + let buf = read_to_end(buffer)?; + assert_eq!(buf, CUSTOM_RESPONSE_MESSAGE_CONTENTS); + Ok(Some(TestCustomMessage::Response)) + }, + _ => Ok(None), } - Ok(None) } } @@ -166,7 +187,7 @@ fn pass_along_path(path: &Vec) { #[test] fn one_hop() { let nodes = create_nodes(2); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); let path = OnionMessagePath { intermediate_nodes: vec![], @@ -179,7 +200,7 @@ fn one_hop() { #[test] fn two_unblinded_hops() { let nodes = create_nodes(3); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); let path = OnionMessagePath { intermediate_nodes: vec![nodes[1].get_node_pk()], @@ -192,7 +213,7 @@ fn two_unblinded_hops() { #[test] fn two_unblinded_two_blinded() { let nodes = create_nodes(5); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(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(); @@ -208,7 +229,7 @@ fn two_unblinded_two_blinded() { #[test] fn three_blinded_hops() { let nodes = create_nodes(4); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(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(); @@ -225,7 +246,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 = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); let hop_node_id = nodes[1].get_node_pk(); let hops = vec![hop_node_id; 400]; @@ -242,7 +263,7 @@ fn we_are_intro_node() { // If we are sending straight to a blinded path and we are the introduction node, we need to // advance the blinded path by 1 hop so the second hop is the new introduction node. let mut nodes = create_nodes(3); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); @@ -269,7 +290,7 @@ fn we_are_intro_node() { fn invalid_blinded_path_error() { // Make sure we error as expected if a provided blinded path has 0 or 1 hops. let nodes = create_nodes(3); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Response; // 0 hops let secp_ctx = Secp256k1::new(); @@ -297,7 +318,7 @@ fn invalid_blinded_path_error() { #[test] fn reply_path() { let nodes = create_nodes(4); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); // Destination::Node @@ -356,7 +377,7 @@ fn invalid_custom_message_type() { #[test] fn peer_buffer_full() { let nodes = create_nodes(2); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Response; let path = OnionMessagePath { intermediate_nodes: vec![], destination: Destination::Node(nodes[1].get_node_pk()), @@ -374,7 +395,7 @@ fn many_hops() { // of size [`crate::onion_message::packet::BIG_PACKET_HOP_DATA_LEN`]. let num_nodes: usize = 25; let nodes = create_nodes(num_nodes as u8); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = TestCustomMessage::Response; let mut intermediate_nodes = vec![]; for i in 1..(num_nodes-1) { @@ -385,6 +406,6 @@ fn many_hops() { intermediate_nodes, destination: Destination::Node(nodes[num_nodes-1].get_node_pk()), }; - nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap(); pass_along_path(&nodes); } From fac5f4b86bbe17dd182a0b2b78bf51f3fc4d344c Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 23 Feb 2023 18:06:25 -0600 Subject: [PATCH 12/15] Test onion message replies --- .../src/onion_message/functional_tests.rs | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index dfa7c6a3b0a..d1b01b71eef 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -20,10 +20,11 @@ use crate::util::test_utils; use bitcoin::network::constants::Network; use bitcoin::secp256k1::{PublicKey, Secp256k1}; -use core::sync::atomic::{AtomicU16, Ordering}; use crate::io; use crate::io_extras::read_to_end; -use crate::sync::Arc; +use crate::sync::{Arc, Mutex}; + +use crate::prelude::*; struct MessengerNode { keys_manager: Arc, @@ -36,7 +37,6 @@ struct MessengerNode { Arc >, custom_message_handler: Arc, - logger: Arc, } impl MessengerNode { @@ -49,9 +49,12 @@ struct TestMessageRouter {} impl MessageRouter for TestMessageRouter { fn find_path( - &self, _sender: PublicKey, _peers: Vec, _destination: Destination + &self, _sender: PublicKey, _peers: Vec, destination: Destination ) -> Result { - todo!() + Ok(OnionMessagePath { + intermediate_nodes: vec![], + destination, + }) } } @@ -63,7 +66,7 @@ impl OffersMessageHandler for TestOffersMessageHandler { } } -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] enum TestCustomMessage { Request, Response, @@ -93,12 +96,16 @@ impl Writeable for TestCustomMessage { } struct TestCustomMessageHandler { - num_messages_expected: AtomicU16, + expected_messages: Mutex>, } impl TestCustomMessageHandler { fn new() -> Self { - Self { num_messages_expected: AtomicU16::new(0) } + Self { expected_messages: Mutex::new(VecDeque::new()) } + } + + fn expect_message(&self, message: TestCustomMessage) { + self.expected_messages.lock().unwrap().push_back(message); } } @@ -109,14 +116,18 @@ impl Drop for TestCustomMessageHandler { return; } } - assert_eq!(self.num_messages_expected.load(Ordering::SeqCst), 0); + assert!(self.expected_messages.lock().unwrap().is_empty()); } } impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option { - self.num_messages_expected.fetch_sub(1, Ordering::SeqCst); + match self.expected_messages.lock().unwrap().pop_front() { + Some(expected_msg) => assert_eq!(expected_msg, msg), + None => panic!("Unexpected message: {:?}", msg), + } + match msg { TestCustomMessage::Request => Some(TestCustomMessage::Response), TestCustomMessage::Response => None, @@ -155,7 +166,6 @@ fn create_nodes(num_messengers: u8) -> Vec { offers_message_handler, custom_message_handler.clone() ), custom_message_handler, - logger, }); } for idx in 0..num_messengers - 1 { @@ -170,7 +180,6 @@ fn create_nodes(num_messengers: u8) -> Vec { } fn pass_along_path(path: &Vec) { - path[path.len() - 1].custom_message_handler.num_messages_expected.fetch_add(1, Ordering::SeqCst); let mut prev_node = &path[0]; for node in path.into_iter().skip(1) { let events = prev_node.messenger.release_pending_msgs(); @@ -194,6 +203,7 @@ fn one_hop() { destination: Destination::Node(nodes[1].get_node_pk()), }; nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -207,6 +217,7 @@ fn two_unblinded_hops() { destination: Destination::Node(nodes[2].get_node_pk()), }; nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -223,6 +234,7 @@ fn two_unblinded_two_blinded() { }; nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[4].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -239,6 +251,7 @@ fn three_blinded_hops() { }; nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[3].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -273,6 +286,7 @@ fn we_are_intro_node() { }; nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); + nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); // Try with a two-hop blinded path where we are the introduction node. @@ -282,6 +296,7 @@ fn we_are_intro_node() { destination: Destination::BlindedPath(blinded_path), }; nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap(); + nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); nodes.remove(2); pass_along_path(&nodes); } @@ -317,8 +332,8 @@ fn invalid_blinded_path_error() { #[test] fn reply_path() { - let nodes = create_nodes(4); - let test_msg = TestCustomMessage::Response; + let mut nodes = create_nodes(4); + let test_msg = TestCustomMessage::Request; let secp_ctx = Secp256k1::new(); // Destination::Node @@ -328,11 +343,12 @@ 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, OnionMessageContents::Custom(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. - nodes[3].logger.assert_log_contains( - "lightning::onion_message::messenger", - &format!("Received an onion message with path_id None and a reply_path"), 1); + nodes[0].custom_message_handler.expect_message(TestCustomMessage::Response); + nodes.reverse(); + pass_along_path(&nodes); // Destination::BlindedPath 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(); @@ -343,10 +359,13 @@ 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, OnionMessageContents::Custom(test_msg), 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. + nodes[0].custom_message_handler.expect_message(TestCustomMessage::Response); + nodes.reverse(); pass_along_path(&nodes); - nodes[3].logger.assert_log_contains( - "lightning::onion_message::messenger", - &format!("Received an onion message with path_id None and a reply_path"), 2); } #[test] @@ -377,7 +396,7 @@ fn invalid_custom_message_type() { #[test] fn peer_buffer_full() { let nodes = create_nodes(2); - let test_msg = TestCustomMessage::Response; + let test_msg = TestCustomMessage::Request; let path = OnionMessagePath { intermediate_nodes: vec![], destination: Destination::Node(nodes[1].get_node_pk()), @@ -407,5 +426,6 @@ fn many_hops() { destination: Destination::Node(nodes[num_nodes-1].get_node_pk()), }; nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap(); + nodes[num_nodes-1].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } From 4257f65738a521ae76dca3cbfb7693907264efac Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 7 Jun 2023 10:55:00 -0500 Subject: [PATCH 13/15] Use different node secrets in onion message fuzzer When generating onion message fuzz data, the same public key was used for each node. However, the code now advances the blinded path if the sender is the introduction node. Use different node secrets for each node to avoid this. Note that the exercised handling code is for the sender's immediate peer. --- fuzz/src/onion_message.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 0e31347f523..cfa27ac2f0c 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -22,7 +22,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; /// Actual fuzz test, method signature and name are fixed pub fn do_test(data: &[u8], logger: &L) { if let Ok(msg) = ::read(&mut Cursor::new(data)) { - let mut secret_bytes = [0; 32]; + let mut secret_bytes = [1; 32]; secret_bytes[31] = 2; let secret = SecretKey::from_slice(&secret_bytes).unwrap(); let keys_manager = KeyProvider { @@ -190,7 +190,7 @@ mod tests { #[test] fn test_no_onion_message_breakage() { - let one_hop_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0136041095000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000"; + let one_hop_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e013604106d000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(one_hop_om).unwrap(), &logger); { @@ -199,28 +199,28 @@ mod tests { "Received an onion message with path_id None and no reply_path".to_string())), Some(&1)); } - let two_unblinded_hops_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210200000000000000000000000000000000000000000000000000000000000000029500000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003604104b000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000"; + let two_unblinded_hops_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d000000000000000000000000000000eb0000000000000000000000000000000000000000000000000000000000000036041096000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(two_unblinded_hops_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020000000000000000000000000000000000000000000000000000000000000002".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020202020202020202020202020202020202020202020202020202020202020202".to_string())), Some(&1)); } - let two_unblinded_two_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e01350433042102000000000000000000000000000000000000000000000000000000000000000295000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000058045604210200000000000000000000000000000000000000000000000000000000000000020821020000000000000000000000000000000000000000000000000000000000000e014b000000000000000000000000000000b20000000000000000000000000000000000000000000000000000000000000035043304210200000000000000000000000000000000000000000000000000000000000000029500000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003604104b000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000"; + let two_unblinded_two_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d0000000000000000000000000000009e0000000000000000000000000000000000000000000000000000000000000058045604210203030303030303030303030303030303030303030303030303030303030303020821020000000000000000000000000000000000000000000000000000000000000e0196000000000000000000000000000000e9000000000000000000000000000000000000000000000000000000000000003504330421020404040404040404040404040404040404040404040404040404040404040402ca00000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000003604103f000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(two_unblinded_two_blinded_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020000000000000000000000000000000000000000000000000000000000000002".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020202020202020202020202020202020202020202020202020202020202020202".to_string())), Some(&1)); } - let three_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e013504330421020000000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000035043304210200000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000360410d1000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000"; + let three_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d000000000000000000000000000000b20000000000000000000000000000000000000000000000000000000000000035043304210203030303030303030303030303030303030303030303030303030303030303029600000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003604104e000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(three_blinded_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020000000000000000000000000000000000000000000000000000000000000002".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020202020202020202020202020202020202020202020202020202020202020202".to_string())), Some(&1)); } } } From c16ecbae923b64b942f68e7c64fec1173b395b52 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 24 Feb 2023 17:27:18 -0600 Subject: [PATCH 14/15] Fuzz test onion message replies --- fuzz/src/onion_message.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index cfa27ac2f0c..d323ecb21fb 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -59,9 +59,12 @@ struct TestMessageRouter {} impl MessageRouter for TestMessageRouter { fn find_path( - &self, _sender: PublicKey, _peers: Vec, _destination: Destination + &self, _sender: PublicKey, _peers: Vec, destination: Destination ) -> Result { - unreachable!() + Ok(OnionMessagePath { + intermediate_nodes: vec![], + destination, + }) } } @@ -95,7 +98,7 @@ struct TestCustomMessageHandler {} impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option { - None + Some(TestCustomMessage {}) } fn read_custom_message(&self, _message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError> { let mut buf = Vec::new(); @@ -190,13 +193,17 @@ mod tests { #[test] fn test_no_onion_message_breakage() { - let one_hop_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e013604106d000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000"; + let one_hop_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e01ae0276020000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000e0101022a0000000000000000000000000000014551231950b75fc4402da1732fc9bebf00109500000000000000000000000000000004106d000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(one_hop_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), - "Received an onion message with path_id None and no reply_path".to_string())), Some(&1)); + "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(), + "Responding to onion message with path_id None".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), + "Failed responding to onion message with path_id None: TooFewBlindedHops".to_string())), Some(&1)); } let two_unblinded_hops_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d000000000000000000000000000000eb0000000000000000000000000000000000000000000000000000000000000036041096000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; From 3fd6b4404390e4d321cf6b5b6986ae1db3284df5 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 13 Jun 2023 12:35:41 -0500 Subject: [PATCH 15/15] Reduce log level of potential noisy log statement --- lightning/src/onion_message/messenger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 655fb6e491d..2c3cf430734 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -452,7 +452,7 @@ where Ok((Payload::Receive::<<::Target as CustomOnionMessageHandler>::CustomMessage> { message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path, }, None)) => { - log_info!(self.logger, + 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" });