X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fonion_message%2Fpacket.rs;h=a76371b39eb9fa12769e2144fb6cdd02067b70f7;hb=808a51e70105f61e999718c4306476386fe3680b;hp=41b8a1634f6bcf68147e15e301c72515a543004f;hpb=ad82c9ea5bf735068c11c8eebdf68ac57f135eec;p=rust-lightning diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 41b8a163..a76371b3 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -12,15 +12,20 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::secp256k1::ecdh::SharedSecret; -use ln::msgs::DecodeError; -use ln::onion_utils; -use super::blinded_route::{BlindedRoute, ForwardTlvs, ReceiveTlvs}; -use util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter}; -use util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, MaybeReadableArgs, Readable, ReadableArgs, Writeable, Writer}; +use crate::blinded_path::BlindedPath; +use crate::blinded_path::message::{ForwardTlvs, ReceiveTlvs}; +use crate::blinded_path::utils::Padding; +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}; use core::cmp; -use io::{self, Read}; -use prelude::*; +use crate::io::{self, Read}; +use crate::prelude::*; // Per the spec, an onion message packet's `hop_data` field length should be // SMALL_PACKET_HOP_DATA_LEN if it fits, else BIG_PACKET_HOP_DATA_LEN if it fits. @@ -98,7 +103,7 @@ pub(super) enum Payload { /// This payload is for the final hop. Receive { control_tlvs: ReceiveControlTlvs, - reply_path: Option, + reply_path: Option, message: OnionMessageContents, } } @@ -106,47 +111,50 @@ pub(super) enum Payload { #[derive(Debug)] /// The contents of an onion message. In the context of offers, this would be the invoice, invoice /// request, or invoice error. -pub enum OnionMessageContents where T: CustomOnionMessageContents { - // Coming soon: - // Invoice, - // InvoiceRequest, - // InvoiceError, +pub enum OnionMessageContents { + /// A message related to BOLT 12 Offers. + Offers(OffersMessage), /// A custom onion message specified by the user. Custom(T), } -impl OnionMessageContents where T: CustomOnionMessageContents { +impl OnionMessageContents { /// Returns the type that was used to decode the message payload. + /// + /// This is not exported to bindings users as methods on non-cloneable enums are not currently exportable pub fn tlv_type(&self) -> u64 { match self { + &OnionMessageContents::Offers(ref msg) => msg.tlv_type(), &OnionMessageContents::Custom(ref msg) => msg.tlv_type(), } } } +/// This is not exported to bindings users as methods on non-cloneable enums are not currently exportable 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)?), } } } -/// The contents of a custom onion message. Must implement `MaybeReadableArgs` where the `u64` -/// is the custom TLV type attempting to be read, and return `Ok(None)` if the TLV type is unknown. -pub trait CustomOnionMessageContents: Writeable + MaybeReadableArgs { +/// The contents of a custom onion message. +pub trait CustomOnionMessageContents: Writeable { /// Returns the TLV type identifying the message contents. MUST be >= 64. fn tlv_type(&self) -> u64; } /// Forward control TLVs in their blinded and unblinded form. pub(super) enum ForwardControlTlvs { - /// If we're sending to a blinded route, the node that constructed the blinded route has provided + /// If we're sending to a blinded path, the node that constructed the blinded path has provided /// this hop's control TLVs, already encrypted into bytes. Blinded(Vec), /// If we're constructing an onion message hop through an intermediate unblinded node, we'll need /// to construct the intermediate hop's control TLVs in their unblinded state to avoid encoding - /// them into an intermediate Vec. See [`super::blinded_route::ForwardTlvs`] for more info. + /// them into an intermediate Vec. See [`crate::blinded_path::message::ForwardTlvs`] for more + /// info. Unblinded(ForwardTlvs), } @@ -154,7 +162,7 @@ pub(super) enum ForwardControlTlvs { pub(super) enum ReceiveControlTlvs { /// See [`ForwardControlTlvs::Blinded`]. Blinded(Vec), - /// See [`ForwardControlTlvs::Unblinded`] and [`super::blinded_route::ReceiveTlvs`]. + /// See [`ForwardControlTlvs::Unblinded`] and [`crate::blinded_path::message::ReceiveTlvs`]. Unblinded(ReceiveTlvs), } @@ -163,22 +171,22 @@ impl Writeable for (Payload, [u8; 32]) { fn write(&self, w: &mut W) -> Result<(), io::Error> { match &self.0 { Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) => { - encode_varint_length_prefixed_tlv!(w, { - (4, encrypted_bytes, vec_type) + _encode_varint_length_prefixed_tlv!(w, { + (4, *encrypted_bytes, required_vec) }) }, Payload::Receive { control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes), reply_path, message, } => { - encode_varint_length_prefixed_tlv!(w, { + _encode_varint_length_prefixed_tlv!(w, { (2, reply_path, option), - (4, encrypted_bytes, vec_type), + (4, *encrypted_bytes, required_vec), (message.tlv_type(), message, required) }) }, Payload::Forward(ForwardControlTlvs::Unblinded(control_tlvs)) => { let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs); - encode_varint_length_prefixed_tlv!(w, { + _encode_varint_length_prefixed_tlv!(w, { (4, write_adapter, required) }) }, @@ -186,7 +194,7 @@ impl Writeable for (Payload, [u8; 32]) { control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs), reply_path, message, } => { let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs); - encode_varint_length_prefixed_tlv!(w, { + _encode_varint_length_prefixed_tlv!(w, { (2, reply_path, option), (4, write_adapter, required), (message.tlv_type(), message, required) @@ -198,16 +206,19 @@ impl Writeable for (Payload, [u8; 32]) { } // Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV. -impl ReadableArgs for Payload { - fn read(r: &mut R, encrypted_tlvs_ss: SharedSecret) -> Result { +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); - let mut reply_path: Option = None; + let mut reply_path: Option = None; let mut read_adapter: Option> = None; let rho = onion_utils::gen_rho_from_shared_secret(&encrypted_tlvs_ss.secret_bytes()); let mut message_type: Option = None; let mut message = None; - decode_tlv_stream!(&mut rd, { + decode_tlv_stream_with_custom_tlv_decode!(&mut rd, { (2, reply_path, option), (4, read_adapter, (option: LengthReadableArgs, rho)), }, |msg_type, msg_reader| { @@ -216,13 +227,19 @@ impl ReadableArgs for Payload { if message_type.is_some() { return Err(DecodeError::InvalidValue) } message_type = Some(msg_type); - match T::read(msg_reader, msg_type) { - Ok(Some(msg)) => { - 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)?; @@ -236,21 +253,21 @@ impl ReadableArgs for Payload { Ok(Payload::Forward(ForwardControlTlvs::Unblinded(tlvs))) }, Some(ChaChaPolyReadAdapter { readable: ControlTlvs::Receive(tlvs)}) => { - if message.is_none() { return Err(DecodeError::InvalidValue) } Ok(Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(tlvs), reply_path, - message: OnionMessageContents::Custom(message.unwrap()), + message: message.ok_or(DecodeError::InvalidValue)?, }) - } + }, } } } /// When reading a packet off the wire, we don't know a priori whether the packet is to be forwarded -/// or received. Thus we read a ControlTlvs rather than reading a ForwardControlTlvs or -/// ReceiveControlTlvs directly. -pub(super) enum ControlTlvs { +/// or received. Thus we read a `ControlTlvs` rather than reading a [`ForwardTlvs`] or +/// [`ReceiveTlvs`] directly. Also useful on the encoding side to keep forward and receive TLVs in +/// the same iterator. +pub(crate) enum ControlTlvs { /// This onion message is intended to be forwarded. Forward(ForwardTlvs), /// This onion message is intended to be received. @@ -258,19 +275,16 @@ pub(super) enum ControlTlvs { } impl Readable for ControlTlvs { - fn read(mut r: &mut R) -> Result { - let mut _padding: Option = None; - let mut _short_channel_id: Option = None; - let mut next_node_id: Option = None; - let mut path_id: Option<[u8; 32]> = None; - let mut next_blinding_override: Option = None; - decode_tlv_stream!(&mut r, { + fn read(r: &mut R) -> Result { + _init_and_read_tlv_stream!(r, { (1, _padding, option), (2, _short_channel_id, option), (4, next_node_id, option), (6, path_id, option), (8, next_blinding_override, option), }); + let _padding: Option = _padding; + let _short_channel_id: Option = _short_channel_id; let valid_fwd_fmt = next_node_id.is_some() && path_id.is_none(); let valid_recv_fmt = next_node_id.is_none() && next_blinding_override.is_none(); @@ -292,15 +306,11 @@ impl Readable for ControlTlvs { } } -/// Reads padding to the end, ignoring what's read. -pub(crate) struct Padding {} -impl Readable for Padding { - #[inline] - fn read(reader: &mut R) -> Result { - loop { - let mut buf = [0; 8192]; - if reader.read(&mut buf[..])? == 0 { break; } +impl Writeable for ControlTlvs { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + match self { + Self::Forward(tlvs) => tlvs.write(w), + Self::Receive(tlvs) => tlvs.write(w), } - Ok(Self {}) } }