X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser_macros.rs;h=3e1d8a9280d43da344076854739a5a81436f450b;hb=53eb0d7aa7e7ee2c247a509d259fbdc7cf840426;hp=3ec0848680ffe62a2532e03d47d1fc5b62d7f4b8;hpb=838d48698384d41e8a9114f4f644dbb83ce5d6fa;p=rust-lightning diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 3ec08486..3e1d8a92 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -201,6 +201,17 @@ macro_rules! decode_tlv { // `Ok(false)` if the message type is unknown, and `Err(DecodeError)` if parsing fails. macro_rules! decode_tlv_stream { ($stream: expr, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*} + $(, $decode_custom_tlv: expr)?) => { { + let rewind = |_, _| { unreachable!() }; + use core::ops::RangeBounds; + decode_tlv_stream_range!( + $stream, .., rewind, {$(($type, $field, $fieldty)),*} $(, $decode_custom_tlv)? + ); + } } +} + +macro_rules! decode_tlv_stream_range { + ($stream: expr, $range: expr, $rewind: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*} $(, $decode_custom_tlv: expr)?) => { { use $crate::ln::msgs::DecodeError; let mut last_seen_type: Option = None; @@ -215,7 +226,7 @@ macro_rules! decode_tlv_stream { // UnexpectedEof. This should in every case be largely cosmetic, but its nice to // pass the TLV test vectors exactly, which requre this distinction. let mut tracking_reader = ser::ReadTrackingReader::new(&mut stream_ref); - match $crate::util::ser::Readable::read(&mut tracking_reader) { + match <$crate::util::ser::BigSize as $crate::util::ser::Readable>::read(&mut tracking_reader) { Err(DecodeError::ShortRead) => { if !tracking_reader.have_read { break 'tlv_read; @@ -224,7 +235,15 @@ macro_rules! decode_tlv_stream { } }, Err(e) => return Err(e), - Ok(t) => t, + Ok(t) => if $range.contains(&t.0) { t } else { + drop(tracking_reader); + + // Assumes the type id is minimally encoded, which is enforced on read. + use $crate::util::ser::Writeable; + let bytes_read = t.serialized_length(); + $rewind(stream_ref, bytes_read); + break 'tlv_read; + }, } }; @@ -412,6 +431,18 @@ macro_rules! init_tlv_field_var { }; } +macro_rules! init_and_read_tlv_fields { + ($reader: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => { + $( + init_tlv_field_var!($field, $fieldty); + )* + + read_tlv_fields!($reader, { + $(($type, $field, $fieldty)),* + }); + } +} + /// Implements Readable/Writeable for a struct storing it as a set of TLVs /// If $fieldty is `required`, then $field is a required field that is not an Option nor a Vec. /// If $fieldty is `option`, then $field is optional field. @@ -446,10 +477,7 @@ macro_rules! impl_writeable_tlv_based { impl $crate::util::ser::Readable for $st { fn read(reader: &mut R) -> Result { - $( - init_tlv_field_var!($field, $fieldty); - )* - read_tlv_fields!(reader, { + init_and_read_tlv_fields!(reader, { $(($type, $field, $fieldty)),* }); Ok(Self { @@ -472,11 +500,11 @@ macro_rules! impl_writeable_tlv_based { /// [`Readable`]: crate::util::ser::Readable /// [`Writeable`]: crate::util::ser::Writeable macro_rules! tlv_stream { - ($name:ident, $nameref:ident, { + ($name:ident, $nameref:ident, $range:expr, { $(($type:expr, $field:ident : $fieldty:tt)),* $(,)* }) => { #[derive(Debug)] - struct $name { + pub(crate) struct $name { $( $field: Option, )* @@ -497,12 +525,15 @@ macro_rules! tlv_stream { } } - impl $crate::util::ser::Readable for $name { - fn read(reader: &mut R) -> Result { + impl $crate::util::ser::SeekReadable for $name { + fn read(reader: &mut R) -> Result { $( init_tlv_field_var!($field, option); )* - decode_tlv_stream!(reader, { + let rewind = |cursor: &mut R, offset: usize| { + cursor.seek($crate::io::SeekFrom::Current(-(offset as i64))).expect(""); + }; + decode_tlv_stream_range!(reader, $range, rewind, { $(($type, $field, (option, encoding: $fieldty))),* }); @@ -583,10 +614,7 @@ macro_rules! impl_writeable_tlv_based_enum_upgradable { // Because read_tlv_fields creates a labeled loop, we cannot call it twice // in the same function body. Instead, we define a closure and call it. let f = || { - $( - init_tlv_field_var!($field, $fieldty); - )* - read_tlv_fields!(reader, { + init_and_read_tlv_fields!(reader, { $(($type, $field, $fieldty)),* }); Ok(Some($st::$variant_name { @@ -636,10 +664,7 @@ macro_rules! impl_writeable_tlv_based_enum { // Because read_tlv_fields creates a labeled loop, we cannot call it twice // in the same function body. Instead, we define a closure and call it. let f = || { - $( - init_tlv_field_var!($field, $fieldty); - )* - read_tlv_fields!(reader, { + init_and_read_tlv_fields!(reader, { $(($type, $field, $fieldty)),* }); Ok($st::$variant_name {