X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser_macros.rs;h=247fdf60074dc4ff0bad148bef3c89ae374f26d6;hb=2e33acbd9c5ebd605829859a982822df6e0f1723;hp=37b8be54ebc2d4db6d53fe0c06582650edecc9f5;hpb=32846d33db1c402d6eb7a268ab0dbc717db39232;p=rust-lightning diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 37b8be54..247fdf60 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -13,6 +13,21 @@ //! [`Readable`]: crate::util::ser::Readable //! [`Writeable`]: crate::util::ser::Writeable +// There are quite a few TLV serialization "types" which behave differently. We currently only +// publicly document the `optional` and `required` types, not supporting anything else publicly and +// changing them at will. +// +// Some of the other types include: +// * (default_value, $default) - reads optionally, reading $default if no TLV is present +// * (static_value, $value) - ignores any TLVs, always using $value +// * required_vec - reads into a Vec without a length prefix, failing if no TLV is present. +// * optional_vec - reads into an Option without a length prefix, continuing if no TLV is +// present. Writes from a Vec directly, only if any elements are present. Note +// that the struct deserialization macros return a Vec, not an Option. +// * upgradable_option - reads via MaybeReadable. +// * upgradable_required - reads via MaybeReadable, requiring a TLV be present but may return None +// if MaybeReadable::read() returns None. + /// Implements serialization for a single TLV record. /// This is exported for use by other exported macros, do not use directly. #[doc(hidden)] @@ -32,9 +47,6 @@ macro_rules! _encode_tlv { ($stream: expr, $type: expr, $field: expr, required_vec) => { $crate::_encode_tlv!($stream, $type, $crate::util::ser::WithoutLength(&$field), required); }; - ($stream: expr, $type: expr, $field: expr, vec_type) => { - $crate::_encode_tlv!($stream, $type, $crate::util::ser::WithoutLength(&$field), required); - }; ($stream: expr, $optional_type: expr, $optional_field: expr, option) => { if let Some(ref field) = $optional_field { BigSize($optional_type).write($stream)?; @@ -120,7 +132,20 @@ macro_rules! _check_encoded_tlv_order { /// [`Writer`]: crate::util::ser::Writer #[macro_export] macro_rules! encode_tlv_stream { + ($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => { + $crate::_encode_tlv_stream!($stream, {$(($type, $field, $fieldty)),*}) + } +} + +/// Implementation of [`encode_tlv_stream`]. +/// This is exported for use by other exported macros, do not use directly. +#[doc(hidden)] +#[macro_export] +macro_rules! _encode_tlv_stream { ($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => { { + $crate::_encode_tlv_stream!($stream, { $(($type, $field, $fieldty)),* }, &[]) + } }; + ($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}, $extra_tlvs: expr) => { { #[allow(unused_imports)] use $crate::{ ln::msgs::DecodeError, @@ -132,6 +157,10 @@ macro_rules! encode_tlv_stream { $( $crate::_encode_tlv!($stream, $type, $field, $fieldty); )* + for tlv in $extra_tlvs { + let (typ, value): &(u64, Vec) = tlv; + $crate::_encode_tlv!($stream, *typ, *value, required_vec); + } #[allow(unused_mut, unused_variables, unused_assignments)] #[cfg(debug_assertions)] @@ -140,8 +169,12 @@ macro_rules! encode_tlv_stream { $( $crate::_check_encoded_tlv_order!(last_seen, $type, $fieldty); )* + for tlv in $extra_tlvs { + let (typ, _): &(u64, Vec) = tlv; + $crate::_check_encoded_tlv_order!(last_seen, *typ, required_vec); + } } - } } + } }; } /// Adds the length of the serialized field to a [`LengthCalculatingWriter`]. @@ -165,9 +198,6 @@ macro_rules! _get_varint_length_prefixed_tlv_length { ($len: expr, $type: expr, $field: expr, required_vec) => { $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $crate::util::ser::WithoutLength(&$field), required); }; - ($len: expr, $type: expr, $field: expr, vec_type) => { - $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $crate::util::ser::WithoutLength(&$field), required); - }; ($len: expr, $optional_type: expr, $optional_field: expr, option) => { if let Some(ref field) = $optional_field { BigSize($optional_type).write(&mut $len).expect("No in-memory data may fail to serialize"); @@ -201,18 +231,27 @@ macro_rules! _get_varint_length_prefixed_tlv_length { #[macro_export] macro_rules! _encode_varint_length_prefixed_tlv { ($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),*}) => { { + $crate::_encode_varint_length_prefixed_tlv!($stream, {$(($type, $field, $fieldty)),*}, &[]) + } }; + ($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),*}, $extra_tlvs: expr) => { { + extern crate alloc; use $crate::util::ser::BigSize; + use alloc::vec::Vec; let len = { #[allow(unused_mut)] let mut len = $crate::util::ser::LengthCalculatingWriter(0); $( $crate::_get_varint_length_prefixed_tlv_length!(len, $type, $field, $fieldty); )* + for tlv in $extra_tlvs { + let (typ, value): &(u64, Vec) = tlv; + $crate::_get_varint_length_prefixed_tlv_length!(len, *typ, *value, required_vec); + } len.0 }; BigSize(len as u64).write($stream)?; - $crate::encode_tlv_stream!($stream, { $(($type, $field, $fieldty)),* }); - } } + $crate::_encode_tlv_stream!($stream, { $(($type, $field, $fieldty)),* }, $extra_tlvs); + } }; } /// Errors if there are missing required TLV types between the last seen type and the type currently being processed. @@ -245,9 +284,6 @@ macro_rules! _check_decoded_tlv_order { ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, required_vec) => {{ $crate::_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required); }}; - ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, vec_type) => {{ - // no-op - }}; ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, optional_vec) => {{ // no-op }}; @@ -293,9 +329,6 @@ macro_rules! _check_missing_tlv { ($last_seen_type: expr, $type: expr, $field: ident, required_vec) => {{ $crate::_check_missing_tlv!($last_seen_type, $type, $field, required); }}; - ($last_seen_type: expr, $type: expr, $field: ident, vec_type) => {{ - // no-op - }}; ($last_seen_type: expr, $type: expr, $field: ident, option) => {{ // no-op }}; @@ -336,15 +369,12 @@ macro_rules! _decode_tlv { let f: $crate::util::ser::WithoutLength> = $crate::util::ser::Readable::read(&mut $reader)?; $field = f.0; }}; - ($reader: expr, $field: ident, vec_type) => {{ - let f: $crate::util::ser::WithoutLength> = $crate::util::ser::Readable::read(&mut $reader)?; - $field = Some(f.0); - }}; ($reader: expr, $field: ident, option) => {{ $field = Some($crate::util::ser::Readable::read(&mut $reader)?); }}; ($reader: expr, $field: ident, optional_vec) => {{ - $crate::_decode_tlv!($reader, $field, vec_type); + let f: $crate::util::ser::WithoutLength> = $crate::util::ser::Readable::read(&mut $reader)?; + $field = Some(f.0); }}; // `upgradable_required` indicates we're reading a required TLV that may have been upgraded // without backwards compat. We'll error if the field is missing, and return `Ok(None)` if the @@ -713,9 +743,6 @@ macro_rules! _init_tlv_based_struct_field { ($field: ident, required_vec) => { $field }; - ($field: ident, vec_type) => { - $field.unwrap() - }; ($field: ident, optional_vec) => { $field.unwrap() }; @@ -742,9 +769,6 @@ macro_rules! _init_tlv_field_var { ($field: ident, required_vec) => { let mut $field = Vec::new(); }; - ($field: ident, vec_type) => { - let mut $field = Some(Vec::new()); - }; ($field: ident, option) => { let mut $field = None; }; @@ -767,10 +791,13 @@ macro_rules! _init_tlv_field_var { /// Equivalent to running [`_init_tlv_field_var`] then [`read_tlv_fields`]. /// +/// If any unused values are read, their type MUST be specified or else `rustc` will read them as an +/// `i64`. +/// /// This is exported for use by other exported macros, do not use directly. #[doc(hidden)] #[macro_export] -macro_rules! _init_and_read_tlv_fields { +macro_rules! _init_and_read_len_prefixed_tlv_fields { ($reader: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => { $( $crate::_init_tlv_field_var!($field, $fieldty); @@ -782,6 +809,22 @@ macro_rules! _init_and_read_tlv_fields { } } +/// Equivalent to running [`_init_tlv_field_var`] then [`decode_tlv_stream`]. +/// +/// If any unused values are read, their type MUST be specified or else `rustc` will read them as an +/// `i64`. +macro_rules! _init_and_read_tlv_stream { + ($reader: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => { + $( + $crate::_init_tlv_field_var!($field, $fieldty); + )* + + $crate::decode_tlv_stream!($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 `(default_value, $default)`, then `$field` will be set to `$default` if not present. @@ -839,7 +882,7 @@ macro_rules! impl_writeable_tlv_based { impl $crate::util::ser::Readable for $st { fn read(reader: &mut R) -> Result { - $crate::_init_and_read_tlv_fields!(reader, { + $crate::_init_and_read_len_prefixed_tlv_fields!(reader, { $(($type, $field, $fieldty)),* }); Ok(Self { @@ -991,7 +1034,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 = || { - $crate::_init_and_read_tlv_fields!(reader, { + $crate::_init_and_read_len_prefixed_tlv_fields!(reader, { $(($type, $field, $fieldty)),* }); Ok($st::$variant_name { @@ -1003,7 +1046,7 @@ macro_rules! impl_writeable_tlv_based_enum { f() }),* $($tuple_variant_id => { - Ok($st::$tuple_variant_name(Readable::read(reader)?)) + Ok($st::$tuple_variant_name($crate::util::ser::Readable::read(reader)?)) }),* _ => { Err($crate::ln::msgs::DecodeError::UnknownRequiredFeature) @@ -1045,7 +1088,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 = || { - $crate::_init_and_read_tlv_fields!(reader, { + $crate::_init_and_read_len_prefixed_tlv_fields!(reader, { $(($type, $field, $fieldty)),* }); Ok(Some($st::$variant_name {