//! [`BlindedPath`]: crate::blinded_path::BlindedPath
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
-
#[allow(unused_imports)]
use crate::prelude::*;
use crate::blinded_path::utils;
use crate::io;
use crate::io::Cursor;
+use crate::ln::channelmanager::PaymentId;
use crate::ln::onion_utils;
use crate::onion_message::packet::ControlTlvs;
use crate::sign::{NodeSigner, Recipient};
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
pub(crate) struct ReceiveTlvs {
- /// If `path_id` is `Some`, it is used to identify the blinded path that this onion message is
+ /// If `context` is `Some`, it is used to identify the blinded path that this onion message is
/// sending to. This is useful for receivers to check that said blinded path is being used in
/// the right context.
- pub(crate) path_id: Option<[u8; 32]>,
+ pub context: Option<MessageContext>
}
impl Writeable for ForwardTlvs {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// TODO: write padding
encode_tlv_stream!(writer, {
- (6, self.path_id, option),
+ (65537, self.context, option),
});
Ok(())
}
}
+/// Represents additional data included by the recipient in a [`BlindedPath`].
+///
+/// This data is encrypted by the recipient and remains invisible to anyone else.
+/// It is included in the [`BlindedPath`], making it accessible again to the recipient
+/// whenever the [`BlindedPath`] is used.
+/// The recipient can authenticate the message and utilize it for further processing
+/// if needed.
+#[derive(Clone, Debug)]
+pub enum MessageContext {
+ /// Represents the data specific to [`OffersMessage`]
+ ///
+ /// [`OffersMessage`]: crate::onion_message::offers::OffersMessage
+ Offers(OffersContext),
+ /// Represents custom data received in a Custom Onion Message.
+ Custom(Vec<u8>),
+}
+
+/// Contains the data specific to [`OffersMessage`]
+///
+/// [`OffersMessage`]: crate::onion_message::offers::OffersMessage
+#[derive(Clone, Debug)]
+pub enum OffersContext {
+ /// Represents an unknown BOLT12 payment context.
+ /// This variant is used when a message is sent without
+ /// using a [`BlindedPath`] or over one created prior to
+ /// LDK version 0.0.124.
+ Unknown {},
+ /// Represents an outbound BOLT12 payment context.
+ OutboundPayment {
+ /// Payment ID of the outbound BOLT12 payment.
+ payment_id: PaymentId
+ },
+}
+
+impl_writeable_tlv_based_enum!(MessageContext, ;
+ (0, Offers),
+ (1, Custom),
+);
+
+impl_writeable_tlv_based_enum!(OffersContext,
+ (0, Unknown) => {},
+ (1, OutboundPayment) => {
+ (0, payment_id, required),
+ },
+;);
+
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey,
None => NextMessageHop::NodeId(*pubkey),
})
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
- .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None })));
+ .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { context: None })));
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
}
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
use crate::blinded_path::{BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp};
-use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, ReceiveTlvs};
+use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, ReceiveTlvs, MessageContext};
use crate::blinded_path::utils;
use crate::events::{Event, EventHandler, EventsProvider};
use crate::sign::{EntropySource, NodeSigner, Recipient};
pub enum PeeledOnion<T: OnionMessageContents> {
/// Forwarded onion, with the next node id and a new onion
Forward(NextMessageHop, OnionMessage),
- /// Received onion message, with decrypted contents, path_id, and reply path
- Receive(ParsedOnionMessageContents<T>, Option<[u8; 32]>, Option<BlindedPath>)
+ /// Received onion message, with decrypted contents, context, and reply path
+ Receive(ParsedOnionMessageContents<T>, Option<MessageContext>, Option<BlindedPath>)
}
(control_tlvs_ss, custom_handler.deref(), logger.deref())
) {
Ok((Payload::Receive::<ParsedOnionMessageContents<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage>> {
- message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
+ message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context }), reply_path,
}, None)) => {
- Ok(PeeledOnion::Receive(message, path_id, reply_path))
+ match (&message, &context) {
+ (_, None) => {
+ Ok(PeeledOnion::Receive(message, None, reply_path))
+ }
+ (ParsedOnionMessageContents::Offers(_), Some(MessageContext::Offers(_))) => {
+ Ok(PeeledOnion::Receive(message, context, reply_path))
+ }
+ (ParsedOnionMessageContents::Custom(_), Some(MessageContext::Custom(_))) => {
+ Ok(PeeledOnion::Receive(message, context, reply_path))
+ }
+ _ => {
+ log_trace!(logger, "Received message was sent on a blinded path with the wrong context.");
+ Err(())
+ }
+ }
},
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
next_hop, next_blinding_override
fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage) {
let logger = WithContext::from(&self.logger, Some(*peer_node_id), None, None);
match self.peel_onion_message(msg) {
- Ok(PeeledOnion::Receive(message, path_id, reply_path)) => {
+ Ok(PeeledOnion::Receive(message, _context, reply_path)) => {
log_trace!(
logger,
- "Received an onion message with path_id {:02x?} and {} reply_path: {:?}",
- path_id, if reply_path.is_some() { "a" } else { "no" }, message);
+ "Received an onion message with {} reply_path: {:?}",
+ if reply_path.is_some() { "a" } else { "no" }, message);
let responder = reply_path.map(Responder::new);
match message {
}, prev_control_tlvs_ss.unwrap()));
} else {
payloads.push((Payload::Receive {
- control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id: None, }),
+ control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context: None }),
reply_path: reply_path.take(),
message,
}, prev_control_tlvs_ss.unwrap()));
(1, _padding, option),
(2, short_channel_id, option),
(4, next_node_id, option),
- (6, path_id, option),
(8, next_blinding_override, option),
+ (65537, context, option),
});
let _padding: Option<Padding> = _padding;
(None, None) => None,
};
- let valid_fwd_fmt = next_hop.is_some() && path_id.is_none();
+ let valid_fwd_fmt = next_hop.is_some();
let valid_recv_fmt = next_hop.is_none() && next_blinding_override.is_none();
let payload_fmt = if valid_fwd_fmt {
})
} else if valid_recv_fmt {
ControlTlvs::Receive(ReceiveTlvs {
- path_id,
+ context,
})
} else {
return Err(DecodeError::InvalidValue)