#[doc(hidden)]
#[macro_export]
macro_rules! _encode_tlv {
($stream: expr, $type: expr, $field: expr, (default_value, $default: expr)) => {
$crate::_encode_tlv!($stream, $type, $field, required)
};
($stream: expr, $type: expr, $field: expr, (static_value, $value: expr)) => {
let _ = &$field; };
($stream: expr, $type: expr, $field: expr, required) => {
BigSize($type).write($stream)?;
BigSize($field.serialized_length() as u64).write($stream)?;
$field.write($stream)?;
};
($stream: expr, $type: expr, $field: expr, required_vec) => {
$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)?;
BigSize(field.serialized_length() as u64).write($stream)?;
field.write($stream)?;
}
};
($stream: expr, $type: expr, $field: expr, optional_vec) => {
if !$field.is_empty() {
$crate::_encode_tlv!($stream, $type, $field, required_vec);
}
};
($stream: expr, $type: expr, $field: expr, upgradable_required) => {
$crate::_encode_tlv!($stream, $type, $field, required);
};
($stream: expr, $type: expr, $field: expr, upgradable_option) => {
$crate::_encode_tlv!($stream, $type, $field, option);
};
($stream: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
$crate::_encode_tlv!($stream, $type, $field.map(|f| $encoding(f)), option);
};
($stream: expr, $type: expr, $field: expr, (option, encoding: $fieldty: ty)) => {
$crate::_encode_tlv!($stream, $type, $field, option);
};
($stream: expr, $type: expr, $field: expr, (option: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_encode_tlv!($stream, $type, $field, option);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _check_encoded_tlv_order {
($last_type: expr, $type: expr, (static_value, $value: expr)) => { };
($last_type: expr, $type: expr, $fieldty: tt) => {
if let Some(t) = $last_type {
#[allow(unused_comparisons)] (debug_assert!(t < $type))
}
$last_type = Some($type);
};
}
#[macro_export]
macro_rules! encode_tlv_stream {
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => {
$crate::_encode_tlv_stream!($stream, {$(($type, $field, $fieldty)),*})
}
}
#[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,
util::ser,
util::ser::BigSize,
util::ser::Writeable,
};
$(
$crate::_encode_tlv!($stream, $type, $field, $fieldty);
)*
for tlv in $extra_tlvs {
let (typ, value): &(u64, Vec<u8>) = tlv;
$crate::_encode_tlv!($stream, *typ, *value, required_vec);
}
#[allow(unused_mut, unused_variables, unused_assignments)]
#[cfg(debug_assertions)]
{
let mut last_seen: Option<u64> = None;
$(
$crate::_check_encoded_tlv_order!(last_seen, $type, $fieldty);
)*
for tlv in $extra_tlvs {
let (typ, _): &(u64, Vec<u8>) = tlv;
$crate::_check_encoded_tlv_order!(last_seen, *typ, required_vec);
}
}
} };
}
#[doc(hidden)]
#[macro_export]
macro_rules! _get_varint_length_prefixed_tlv_length {
($len: expr, $type: expr, $field: expr, (default_value, $default: expr)) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required)
};
($len: expr, $type: expr, $field: expr, (static_value, $value: expr)) => {
};
($len: expr, $type: expr, $field: expr, required) => {
BigSize($type).write(&mut $len).expect("No in-memory data may fail to serialize");
let field_len = $field.serialized_length();
BigSize(field_len as u64).write(&mut $len).expect("No in-memory data may fail to serialize");
$len.0 += field_len;
};
($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, $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");
let field_len = field.serialized_length();
BigSize(field_len as u64).write(&mut $len).expect("No in-memory data may fail to serialize");
$len.0 += field_len;
}
};
($len: expr, $type: expr, $field: expr, optional_vec) => {
if !$field.is_empty() {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required_vec);
}
};
($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);
};
($len: expr, $type: expr, $field: expr, upgradable_option) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, option);
};
}
#[doc(hidden)]
#[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<u8>) = 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)),* }, $extra_tlvs);
} };
}
#[doc(hidden)]
#[macro_export]
macro_rules! _check_decoded_tlv_order {
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (default_value, $default: expr)) => {{
#[allow(unused_comparisons)] let invalid_order = ($last_seen_type.is_none() || $last_seen_type.unwrap() < $type) && $typ.0 > $type;
if invalid_order {
$field = $default.into();
}
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (static_value, $value: expr)) => {
};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, required) => {{
#[allow(unused_comparisons)] let invalid_order = ($last_seen_type.is_none() || $last_seen_type.unwrap() < $type) && $typ.0 > $type;
if invalid_order {
return Err(DecodeError::InvalidValue);
}
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
$crate::_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required);
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, option) => {{
}};
($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, optional_vec) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, upgradable_required) => {{
_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required)
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, upgradable_option) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _check_missing_tlv {
($last_seen_type: expr, $type: expr, $field: ident, (default_value, $default: expr)) => {{
#[allow(unused_comparisons)] let missing_req_type = $last_seen_type.is_none() || $last_seen_type.unwrap() < $type;
if missing_req_type {
$field = $default.into();
}
}};
($last_seen_type: expr, $type: expr, $field: expr, (static_value, $value: expr)) => {
$field = $value;
};
($last_seen_type: expr, $type: expr, $field: ident, required) => {{
#[allow(unused_comparisons)] let missing_req_type = $last_seen_type.is_none() || $last_seen_type.unwrap() < $type;
if missing_req_type {
return Err(DecodeError::InvalidValue);
}
}};
($last_seen_type: expr, $type: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
$crate::_check_missing_tlv!($last_seen_type, $type, $field, required);
}};
($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, option) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, optional_vec) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, upgradable_required) => {{
_check_missing_tlv!($last_seen_type, $type, $field, required)
}};
($last_seen_type: expr, $type: expr, $field: ident, upgradable_option) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _decode_tlv {
($outer_reader: expr, $reader: expr, $field: ident, (default_value, $default: expr)) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, required)
}};
($outer_reader: expr, $reader: expr, $field: ident, (static_value, $value: expr)) => {{
}};
($outer_reader: expr, $reader: expr, $field: ident, required) => {{
$field = $crate::util::ser::Readable::read(&mut $reader)?;
}};
($outer_reader: expr, $reader: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
$field = $trait::read(&mut $reader $(, $read_arg)*)?;
}};
($outer_reader: expr, $reader: expr, $field: ident, required_vec) => {{
let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::Readable::read(&mut $reader)?;
$field = f.0;
}};
($outer_reader: expr, $reader: expr, $field: ident, option) => {{
$field = Some($crate::util::ser::Readable::read(&mut $reader)?);
}};
($outer_reader: expr, $reader: expr, $field: ident, optional_vec) => {{
let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::Readable::read(&mut $reader)?;
$field = Some(f.0);
}};
($outer_reader: expr, $reader: expr, $field: ident, upgradable_required) => {{
$field = match $crate::util::ser::MaybeReadable::read(&mut $reader)? {
Some(res) => res,
None => {
$crate::io_extras::copy($outer_reader, &mut $crate::io_extras::sink()).unwrap();
return Ok(None)
},
};
}};
($outer_reader: expr, $reader: expr, $field: ident, upgradable_option) => {{
$field = $crate::util::ser::MaybeReadable::read(&mut $reader)?;
if $field.is_none() {
#[cfg(not(debug_assertions))] {
$reader.eat_remaining()?;
}
}
}};
($outer_reader: expr, $reader: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
$field = Some($trait::read(&mut $reader $(, $read_arg)*)?);
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident, $encoder:ty))) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, (option, encoding: ($fieldty, $encoding)));
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {{
$field = {
let field: $encoding<$fieldty> = ser::Readable::read(&mut $reader)?;
Some(field.0)
};
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, encoding: $fieldty: ty)) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, option);
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _decode_tlv_stream_match_check {
($val: ident, $type: expr, (static_value, $value: expr)) => { false };
($val: ident, $type: expr, $fieldty: tt) => { $val == $type }
}
#[macro_export]
macro_rules! decode_tlv_stream {
($stream: expr, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
let rewind = |_, _| { unreachable!() };
$crate::_decode_tlv_stream_range!($stream, .., rewind, {$(($type, $field, $fieldty)),*});
}
}
macro_rules! decode_tlv_stream_with_custom_tlv_decode {
($stream: expr, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
$(, $decode_custom_tlv: expr)?) => { {
let rewind = |_, _| { unreachable!() };
_decode_tlv_stream_range!(
$stream, .., rewind, {$(($type, $field, $fieldty)),*} $(, $decode_custom_tlv)?
);
} }
}
#[doc(hidden)]
#[macro_export]
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<u64> = None;
let mut stream_ref = $stream;
'tlv_read: loop {
use $crate::util::ser;
let typ: ser::BigSize = {
let mut tracking_reader = ser::ReadTrackingReader::new(&mut stream_ref);
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;
} else {
return Err(DecodeError::ShortRead);
}
},
Err(e) => return Err(e),
Ok(t) => if core::ops::RangeBounds::contains(&$range, &t.0) { t } else {
drop(tracking_reader);
use $crate::util::ser::Writeable;
let bytes_read = t.serialized_length();
$rewind(stream_ref, bytes_read);
break 'tlv_read;
},
}
};
match last_seen_type {
Some(t) if typ.0 <= t => {
return Err(DecodeError::InvalidValue);
},
_ => {},
}
$({
$crate::_check_decoded_tlv_order!(last_seen_type, typ, $type, $field, $fieldty);
})*
last_seen_type = Some(typ.0);
let length: ser::BigSize = $crate::util::ser::Readable::read(&mut stream_ref)?;
let mut s = ser::FixedLengthReader::new(&mut stream_ref, length.0);
match typ.0 {
$(_t if $crate::_decode_tlv_stream_match_check!(_t, $type, $fieldty) => {
$crate::_decode_tlv!($stream, s, $field, $fieldty);
if s.bytes_remain() {
s.eat_remaining()?; return Err(DecodeError::InvalidValue);
}
},)*
t => {
$(
if $decode_custom_tlv(t, &mut s)? {
s.eat_remaining()?;
continue 'tlv_read;
}
)?
if t % 2 == 0 {
return Err(DecodeError::UnknownRequiredFeature);
}
}
}
s.eat_remaining()?;
}
$({
$crate::_check_missing_tlv!(last_seen_type, $type, $field, $fieldty);
})*
} }
}
#[macro_export]
macro_rules! impl_writeable_msg {
($st:ident, {$($field:ident),* $(,)*}, {$(($type: expr, $tlvfield: ident, $fieldty: tt)),* $(,)*}) => {
impl $crate::util::ser::Writeable for $st {
fn write<W: $crate::util::ser::Writer>(&self, w: &mut W) -> Result<(), $crate::io::Error> {
$( self.$field.write(w)?; )*
$crate::encode_tlv_stream!(w, {$(($type, self.$tlvfield.as_ref(), $fieldty)),*});
Ok(())
}
}
impl $crate::util::ser::Readable for $st {
fn read<R: $crate::io::Read>(r: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
$(let $field = $crate::util::ser::Readable::read(r)?;)*
$($crate::_init_tlv_field_var!($tlvfield, $fieldty);)*
$crate::decode_tlv_stream!(r, {$(($type, $tlvfield, $fieldty)),*});
Ok(Self {
$($field),*,
$($tlvfield),*
})
}
}
}
}
macro_rules! impl_writeable {
($st:ident, {$($field:ident),*}) => {
impl $crate::util::ser::Writeable for $st {
fn write<W: $crate::util::ser::Writer>(&self, w: &mut W) -> Result<(), $crate::io::Error> {
$( self.$field.write(w)?; )*
Ok(())
}
#[inline]
fn serialized_length(&self) -> usize {
let mut len_calc = 0;
$( len_calc += self.$field.serialized_length(); )*
return len_calc;
}
}
impl $crate::util::ser::Readable for $st {
fn read<R: $crate::io::Read>(r: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
Ok(Self {
$($field: $crate::util::ser::Readable::read(r)?),*
})
}
}
}
}
macro_rules! write_ver_prefix {
($stream: expr, $this_version: expr, $min_version_that_can_read_this: expr) => {
$stream.write_all(&[$this_version; 1])?;
$stream.write_all(&[$min_version_that_can_read_this; 1])?;
}
}
#[macro_export]
macro_rules! write_tlv_fields {
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => {
$crate::_encode_varint_length_prefixed_tlv!($stream, {$(($type, $field, $fieldty)),*})
}
}
macro_rules! read_ver_prefix {
($stream: expr, $this_version: expr) => { {
let ver: u8 = Readable::read($stream)?;
let min_ver: u8 = Readable::read($stream)?;
if min_ver > $this_version {
return Err(DecodeError::UnknownVersion);
}
ver
} }
}
#[macro_export]
macro_rules! read_tlv_fields {
($stream: expr, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => { {
let tlv_len: $crate::util::ser::BigSize = $crate::util::ser::Readable::read($stream)?;
let mut rd = $crate::util::ser::FixedLengthReader::new($stream, tlv_len.0);
$crate::decode_tlv_stream!(&mut rd, {$(($type, $field, $fieldty)),*});
rd.eat_remaining().map_err(|_| $crate::ln::msgs::DecodeError::ShortRead)?;
} }
}
#[doc(hidden)]
#[macro_export]
macro_rules! _init_tlv_based_struct_field {
($field: ident, (default_value, $default: expr)) => {
$field.0.unwrap()
};
($field: ident, (static_value, $value: expr)) => {
$field
};
($field: ident, option) => {
$field
};
($field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_based_struct_field!($field, option)
};
($field: ident, upgradable_required) => {
$field.0.unwrap()
};
($field: ident, upgradable_option) => {
$field
};
($field: ident, required) => {
$field.0.unwrap()
};
($field: ident, required_vec) => {
$field
};
($field: ident, optional_vec) => {
$field.unwrap()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _init_tlv_field_var {
($field: ident, (default_value, $default: expr)) => {
let mut $field = $crate::util::ser::RequiredWrapper(None);
};
($field: ident, (static_value, $value: expr)) => {
let $field;
};
($field: ident, required) => {
let mut $field = $crate::util::ser::RequiredWrapper(None);
};
($field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_field_var!($field, required);
};
($field: ident, required_vec) => {
let mut $field = Vec::new();
};
($field: ident, option) => {
let mut $field = None;
};
($field: ident, optional_vec) => {
let mut $field = Some(Vec::new());
};
($field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
$crate::_init_tlv_field_var!($field, option);
};
($field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_field_var!($field, option);
};
($field: ident, upgradable_required) => {
let mut $field = $crate::util::ser::UpgradableRequired(None);
};
($field: ident, upgradable_option) => {
let mut $field = None;
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _init_and_read_len_prefixed_tlv_fields {
($reader: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
$(
$crate::_init_tlv_field_var!($field, $fieldty);
)*
$crate::read_tlv_fields!($reader, {
$(($type, $field, $fieldty)),*
});
}
}
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)),*
});
}
}
#[macro_export]
macro_rules! impl_writeable_tlv_based {
($st: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
impl $crate::util::ser::Writeable for $st {
fn write<W: $crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), $crate::io::Error> {
$crate::write_tlv_fields!(writer, {
$(($type, self.$field, $fieldty)),*
});
Ok(())
}
#[inline]
fn serialized_length(&self) -> usize {
use $crate::util::ser::BigSize;
let len = {
#[allow(unused_mut)]
let mut len = $crate::util::ser::LengthCalculatingWriter(0);
$(
$crate::_get_varint_length_prefixed_tlv_length!(len, $type, self.$field, $fieldty);
)*
len.0
};
let mut len_calc = $crate::util::ser::LengthCalculatingWriter(0);
BigSize(len as u64).write(&mut len_calc).expect("No in-memory data may fail to serialize");
len + len_calc.0
}
}
impl $crate::util::ser::Readable for $st {
fn read<R: $crate::io::Read>(reader: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
$crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
$(($type, $field, $fieldty)),*
});
Ok(Self {
$(
$field: $crate::_init_tlv_based_struct_field!($field, $fieldty)
),*
})
}
}
}
}
macro_rules! tlv_stream {
($name:ident, $nameref:ident, $range:expr, {
$(($type:expr, $field:ident : $fieldty:tt)),* $(,)*
}) => {
#[derive(Debug)]
pub(super) struct $name {
$(
pub(super) $field: Option<tlv_record_type!($fieldty)>,
)*
}
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub(crate) struct $nameref<'a> {
$(
pub(super) $field: Option<tlv_record_ref_type!($fieldty)>,
)*
}
impl<'a> $crate::util::ser::Writeable for $nameref<'a> {
fn write<W: $crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), $crate::io::Error> {
encode_tlv_stream!(writer, {
$(($type, self.$field, (option, encoding: $fieldty))),*
});
Ok(())
}
}
impl $crate::util::ser::SeekReadable for $name {
fn read<R: $crate::io::Read + $crate::io::Seek>(reader: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
$(
_init_tlv_field_var!($field, option);
)*
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))),*
});
Ok(Self {
$(
$field: $field
),*
})
}
}
}
}
macro_rules! tlv_record_type {
(($type:ty, $wrapper:ident)) => { $type };
(($type:ty, $wrapper:ident, $encoder:ty)) => { $type };
($type:ty) => { $type };
}
macro_rules! tlv_record_ref_type {
(char) => { char };
(u8) => { u8 };
((u16, $wrapper: ident)) => { u16 };
((u32, $wrapper: ident)) => { u32 };
((u64, $wrapper: ident)) => { u64 };
(($type:ty, $wrapper:ident)) => { &'a $type };
(($type:ty, $wrapper:ident, $encoder:ty)) => { $encoder };
($type:ty) => { &'a $type };
}
#[doc(hidden)]
#[macro_export]
macro_rules! _impl_writeable_tlv_based_enum_common {
($st: ident, $(($variant_id: expr, $variant_name: ident) =>
{$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
),* $(,)*;
$(($tuple_variant_id: expr, $tuple_variant_name: ident)),* $(,)*) => {
impl $crate::util::ser::Writeable for $st {
fn write<W: $crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), $crate::io::Error> {
match self {
$($st::$variant_name { $(ref $field),* } => {
let id: u8 = $variant_id;
id.write(writer)?;
$crate::write_tlv_fields!(writer, {
$(($type, *$field, $fieldty)),*
});
}),*
$($st::$tuple_variant_name (ref field) => {
let id: u8 = $tuple_variant_id;
id.write(writer)?;
field.write(writer)?;
}),*
}
Ok(())
}
}
}
}
#[macro_export]
macro_rules! impl_writeable_tlv_based_enum {
($st: ident, $(($variant_id: expr, $variant_name: ident) =>
{$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
),* $(,)*;
$(($tuple_variant_id: expr, $tuple_variant_name: ident)),* $(,)*) => {
$crate::_impl_writeable_tlv_based_enum_common!($st,
$(($variant_id, $variant_name) => {$(($type, $field, $fieldty)),*}),*;
$(($tuple_variant_id, $tuple_variant_name)),*);
impl $crate::util::ser::Readable for $st {
fn read<R: $crate::io::Read>(reader: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
let id: u8 = $crate::util::ser::Readable::read(reader)?;
match id {
$($variant_id => {
let mut f = || {
$crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
$(($type, $field, $fieldty)),*
});
Ok($st::$variant_name {
$(
$field: $crate::_init_tlv_based_struct_field!($field, $fieldty)
),*
})
};
f()
}),*
$($tuple_variant_id => {
Ok($st::$tuple_variant_name($crate::util::ser::Readable::read(reader)?))
}),*
_ => {
Err($crate::ln::msgs::DecodeError::UnknownRequiredFeature)
},
}
}
}
}
}
#[macro_export]
macro_rules! impl_writeable_tlv_based_enum_upgradable {
($st: ident, $(($variant_id: expr, $variant_name: ident) =>
{$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
),* $(,)*
$(;
$(($tuple_variant_id: expr, $tuple_variant_name: ident)),* $(,)*)*) => {
$crate::_impl_writeable_tlv_based_enum_common!($st,
$(($variant_id, $variant_name) => {$(($type, $field, $fieldty)),*}),*;
$($(($tuple_variant_id, $tuple_variant_name)),*)*);
impl $crate::util::ser::MaybeReadable for $st {
fn read<R: $crate::io::Read>(reader: &mut R) -> Result<Option<Self>, $crate::ln::msgs::DecodeError> {
let id: u8 = $crate::util::ser::Readable::read(reader)?;
match id {
$($variant_id => {
let mut f = || {
$crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
$(($type, $field, $fieldty)),*
});
Ok(Some($st::$variant_name {
$(
$field: $crate::_init_tlv_based_struct_field!($field, $fieldty)
),*
}))
};
f()
}),*
$($($tuple_variant_id => {
Ok(Some($st::$tuple_variant_name(Readable::read(reader)?)))
}),*)*
_ if id % 2 == 1 => {
let tlv_len: $crate::util::ser::BigSize = $crate::util::ser::Readable::read(reader)?;
let mut rd = $crate::util::ser::FixedLengthReader::new(reader, tlv_len.0);
rd.eat_remaining().map_err(|_| $crate::ln::msgs::DecodeError::ShortRead)?;
Ok(None)
},
_ => Err($crate::ln::msgs::DecodeError::UnknownRequiredFeature),
}
}
}
}
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use crate::prelude::*;
use crate::io::{self, Cursor};
use crate::ln::msgs::DecodeError;
use crate::util::ser::{MaybeReadable, Readable, Writeable, HighZeroBytesDroppedBigSize, VecWriter};
use bitcoin::hashes::hex::FromHex;
use bitcoin::secp256k1::PublicKey;
fn tlv_reader(s: &[u8]) -> Result<(u64, u32, Option<u32>), DecodeError> {
let mut s = Cursor::new(s);
let mut a: u64 = 0;
let mut b: u32 = 0;
let mut c: Option<u32> = None;
decode_tlv_stream!(&mut s, {(2, a, required), (3, b, required), (4, c, option)});
Ok((a, b, c))
}
#[test]
fn tlv_v_short_read() {
if let Err(DecodeError::ShortRead) = tlv_reader(&<Vec<u8>>::from_hex(
concat!("0100", "0208deadbeef1badbeef", "0308deadbeef")
).unwrap()[..]) {
} else { panic!(); }
}
#[test]
fn tlv_types_out_of_order() {
if let Err(DecodeError::InvalidValue) = tlv_reader(&<Vec<u8>>::from_hex(
concat!("0100", "0304deadbeef", "0208deadbeef1badbeef")
).unwrap()[..]) {
} else { panic!(); }
if let Err(DecodeError::InvalidValue) = tlv_reader(&<Vec<u8>>::from_hex(
concat!("0208deadbeef1badbeef", "0100", "0304deadbeef")
).unwrap()[..]) {
} else { panic!(); }
}
#[test]
fn tlv_req_type_missing_or_extra() {
if let Err(DecodeError::UnknownRequiredFeature) = tlv_reader(&<Vec<u8>>::from_hex(
concat!("0100", "0208deadbeef1badbeef", "0304deadbeef", "0600")
).unwrap()[..]) {
} else { panic!(); }
if let Err(DecodeError::InvalidValue) = tlv_reader(&<Vec<u8>>::from_hex(
concat!("0100", "0208deadbeef1badbeef")
).unwrap()[..]) {
} else { panic!(); }
if let Err(DecodeError::InvalidValue) = tlv_reader(&<Vec<u8>>::from_hex(
concat!("0304deadbeef", "0500")
).unwrap()[..]) {
} else { panic!(); }
}
#[test]
fn tlv_simple_good_cases() {
assert_eq!(tlv_reader(&<Vec<u8>>::from_hex(
concat!("0208deadbeef1badbeef", "03041bad1dea")
).unwrap()[..]).unwrap(),
(0xdeadbeef1badbeef, 0x1bad1dea, None));
assert_eq!(tlv_reader(&<Vec<u8>>::from_hex(
concat!("0208deadbeef1badbeef", "03041bad1dea", "040401020304")
).unwrap()[..]).unwrap(),
(0xdeadbeef1badbeef, 0x1bad1dea, Some(0x01020304)));
}
#[derive(Debug, PartialEq)]
struct TestUpgradable {
a: u32,
b: u32,
c: Option<u32>,
}
fn upgradable_tlv_reader(s: &[u8]) -> Result<Option<TestUpgradable>, DecodeError> {
let mut s = Cursor::new(s);
let mut a = 0;
let mut b = 0;
let mut c: Option<u32> = None;
decode_tlv_stream!(&mut s, {(2, a, upgradable_required), (3, b, upgradable_required), (4, c, upgradable_option)});
Ok(Some(TestUpgradable { a, b, c, }))
}
#[test]
fn upgradable_tlv_simple_good_cases() {
assert_eq!(upgradable_tlv_reader(&<Vec<u8>>::from_hex(
concat!("0204deadbeef", "03041bad1dea", "0404deadbeef")
).unwrap()[..]).unwrap(),
Some(TestUpgradable { a: 0xdeadbeef, b: 0x1bad1dea, c: Some(0xdeadbeef) }));
assert_eq!(upgradable_tlv_reader(&<Vec<u8>>::from_hex(
concat!("0204deadbeef", "03041bad1dea")
).unwrap()[..]).unwrap(),
Some(TestUpgradable { a: 0xdeadbeef, b: 0x1bad1dea, c: None}));
}
#[test]
fn missing_required_upgradable() {
if let Err(DecodeError::InvalidValue) = upgradable_tlv_reader(&<Vec<u8>>::from_hex(
concat!("0100", "0204deadbeef")
).unwrap()[..]) {
} else { panic!(); }
if let Err(DecodeError::InvalidValue) = upgradable_tlv_reader(&<Vec<u8>>::from_hex(
concat!("0100", "03041bad1dea")
).unwrap()[..]) {
} else { panic!(); }
}
enum InnerEnumV1 {
StructVariantA {
field: u32,
},
}
impl_writeable_tlv_based_enum_upgradable!(InnerEnumV1,
(0, StructVariantA) => {
(0, field, required),
},
);
struct OuterStructOptionalEnumV1 {
inner_enum: Option<InnerEnumV1>,
other_field: u32,
}
impl_writeable_tlv_based!(OuterStructOptionalEnumV1, {
(0, inner_enum, upgradable_option),
(2, other_field, required),
});
enum InnerEnumV2 {
StructVariantA {
field: u32,
},
StructVariantB {
field2: u64,
}
}
impl_writeable_tlv_based_enum_upgradable!(InnerEnumV2,
(0, StructVariantA) => {
(0, field, required),
},
(1, StructVariantB) => {
(0, field2, required),
},
);
struct OuterStructOptionalEnumV2 {
inner_enum: Option<InnerEnumV2>,
other_field: u32,
}
impl_writeable_tlv_based!(OuterStructOptionalEnumV2, {
(0, inner_enum, upgradable_option),
(2, other_field, required),
});
#[test]
fn upgradable_enum_option() {
let serialized_bytes = OuterStructOptionalEnumV2 {
inner_enum: Some(InnerEnumV2::StructVariantB { field2: 64 }),
other_field: 0x1bad1dea,
}.encode();
let mut s = Cursor::new(serialized_bytes);
let outer_struct: OuterStructOptionalEnumV1 = Readable::read(&mut s).unwrap();
assert!(outer_struct.inner_enum.is_none());
assert_eq!(outer_struct.other_field, 0x1bad1dea);
}
struct OuterStructRequiredEnum {
#[allow(unused)]
inner_enum: InnerEnumV1,
}
impl MaybeReadable for OuterStructRequiredEnum {
fn read<R: io::Read>(reader: &mut R) -> Result<Option<Self>, DecodeError> {
let mut inner_enum = crate::util::ser::UpgradableRequired(None);
read_tlv_fields!(reader, {
(0, inner_enum, upgradable_required),
});
Ok(Some(Self {
inner_enum: inner_enum.0.unwrap(),
}))
}
}
impl Writeable for OuterStructRequiredEnum {
fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
write_tlv_fields!(writer, {
(0, InnerEnumV2::StructVariantB { field2: 0xdeadbeef }, required),
});
Ok(())
}
}
struct OuterOuterStruct {
outer_struct: Option<OuterStructRequiredEnum>,
other_field: u32,
}
impl_writeable_tlv_based!(OuterOuterStruct, {
(0, outer_struct, upgradable_option),
(2, other_field, required),
});
#[test]
fn upgradable_enum_required() {
let dummy_inner_enum = InnerEnumV1::StructVariantA { field: 42 };
let serialized_bytes = OuterOuterStruct {
outer_struct: Some(OuterStructRequiredEnum { inner_enum: dummy_inner_enum }),
other_field: 0x1bad1dea,
}.encode();
let mut s = Cursor::new(serialized_bytes);
let outer_outer_struct: OuterOuterStruct = Readable::read(&mut s).unwrap();
assert!(outer_outer_struct.outer_struct.is_none());
assert_eq!(outer_outer_struct.other_field, 0x1bad1dea);
}
fn tlv_reader_n1(s: &[u8]) -> Result<(Option<HighZeroBytesDroppedBigSize<u64>>, Option<u64>, Option<(PublicKey, u64, u64)>, Option<u16>), DecodeError> {
let mut s = Cursor::new(s);
let mut tlv1: Option<HighZeroBytesDroppedBigSize<u64>> = None;
let mut tlv2: Option<u64> = None;
let mut tlv3: Option<(PublicKey, u64, u64)> = None;
let mut tlv4: Option<u16> = None;
decode_tlv_stream!(&mut s, {(1, tlv1, option), (2, tlv2, option), (3, tlv3, option), (254, tlv4, option)});
Ok((tlv1, tlv2, tlv3, tlv4))
}
#[test]
fn bolt_tlv_bogus_stream() {
macro_rules! do_test {
($stream: expr, $reason: ident) => {
if let Err(DecodeError::$reason) = tlv_reader_n1(&<Vec<u8>>::from_hex($stream).unwrap()[..]) {
} else { panic!(); }
}
}
do_test!(concat!("fd01"), ShortRead);
do_test!(concat!("fd0001", "00"), InvalidValue);
do_test!(concat!("fd0101"), ShortRead);
do_test!(concat!("0f", "fd"), ShortRead);
do_test!(concat!("0f", "fd26"), ShortRead);
do_test!(concat!("0f", "fd2602"), ShortRead);
do_test!(concat!("0f", "fd0001", "00"), InvalidValue);
do_test!(concat!("0f", "fd0201", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), ShortRead);
do_test!(concat!("12", "00"), UnknownRequiredFeature);
do_test!(concat!("fd0102", "00"), UnknownRequiredFeature);
do_test!(concat!("fe01000002", "00"), UnknownRequiredFeature);
do_test!(concat!("ff0100000000000002", "00"), UnknownRequiredFeature);
}
#[test]
fn bolt_tlv_bogus_n1_stream() {
macro_rules! do_test {
($stream: expr, $reason: ident) => {
if let Err(DecodeError::$reason) = tlv_reader_n1(&<Vec<u8>>::from_hex($stream).unwrap()[..]) {
} else { panic!(); }
}
}
do_test!(concat!("01", "09", "ffffffffffffffffff"), InvalidValue);
do_test!(concat!("01", "01", "00"), InvalidValue);
do_test!(concat!("01", "02", "0001"), InvalidValue);
do_test!(concat!("01", "03", "000100"), InvalidValue);
do_test!(concat!("01", "04", "00010000"), InvalidValue);
do_test!(concat!("01", "05", "0001000000"), InvalidValue);
do_test!(concat!("01", "06", "000100000000"), InvalidValue);
do_test!(concat!("01", "07", "00010000000000"), InvalidValue);
do_test!(concat!("01", "08", "0001000000000000"), InvalidValue);
do_test!(concat!("02", "07", "01010101010101"), ShortRead);
do_test!(concat!("02", "09", "010101010101010101"), InvalidValue);
do_test!(concat!("03", "21", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb"), ShortRead);
do_test!(concat!("03", "29", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb0000000000000001"), ShortRead);
do_test!(concat!("03", "30", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb000000000000000100000000000001"), ShortRead);
do_test!(concat!("03", "31", "043da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb00000000000000010000000000000002"), InvalidValue);
do_test!(concat!("03", "32", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb0000000000000001000000000000000001"), InvalidValue);
do_test!(concat!("fd00fe", "00"), ShortRead);
do_test!(concat!("fd00fe", "01", "01"), ShortRead);
do_test!(concat!("fd00fe", "03", "010101"), InvalidValue);
do_test!(concat!("00", "00"), UnknownRequiredFeature);
do_test!(concat!("02", "08", "0000000000000226", "01", "01", "2a"), InvalidValue);
do_test!(concat!("02", "08", "0000000000000231", "02", "08", "0000000000000451"), InvalidValue);
do_test!(concat!("1f", "00", "0f", "01", "2a"), InvalidValue);
do_test!(concat!("1f", "00", "1f", "01", "2a"), InvalidValue);
do_test!(concat!("ffffffffffffffffff", "00", "01", "00"), InvalidValue);
}
#[test]
fn bolt_tlv_valid_n1_stream() {
macro_rules! do_test {
($stream: expr, $tlv1: expr, $tlv2: expr, $tlv3: expr, $tlv4: expr) => {
if let Ok((tlv1, tlv2, tlv3, tlv4)) = tlv_reader_n1(&<Vec<u8>>::from_hex($stream).unwrap()[..]) {
assert_eq!(tlv1.map(|v| v.0), $tlv1);
assert_eq!(tlv2, $tlv2);
assert_eq!(tlv3, $tlv3);
assert_eq!(tlv4, $tlv4);
} else { panic!(); }
}
}
do_test!(concat!(""), None, None, None, None);
do_test!(concat!("21", "00"), None, None, None, None);
do_test!(concat!("fd0201", "00"), None, None, None, None);
do_test!(concat!("fd00fd", "00"), None, None, None, None);
do_test!(concat!("fd00ff", "00"), None, None, None, None);
do_test!(concat!("fe02000001", "00"), None, None, None, None);
do_test!(concat!("ff0200000000000001", "00"), None, None, None, None);
do_test!(concat!("01", "00"), Some(0), None, None, None);
do_test!(concat!("01", "01", "01"), Some(1), None, None, None);
do_test!(concat!("01", "02", "0100"), Some(256), None, None, None);
do_test!(concat!("01", "03", "010000"), Some(65536), None, None, None);
do_test!(concat!("01", "04", "01000000"), Some(16777216), None, None, None);
do_test!(concat!("01", "05", "0100000000"), Some(4294967296), None, None, None);
do_test!(concat!("01", "06", "010000000000"), Some(1099511627776), None, None, None);
do_test!(concat!("01", "07", "01000000000000"), Some(281474976710656), None, None, None);
do_test!(concat!("01", "08", "0100000000000000"), Some(72057594037927936), None, None, None);
do_test!(concat!("02", "08", "0000000000000226"), None, Some((0 << 30) | (0 << 5) | (550 << 0)), None, None);
do_test!(concat!("03", "31", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb00000000000000010000000000000002"),
None, None, Some((
PublicKey::from_slice(&<Vec<u8>>::from_hex("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]).unwrap(), 1, 2)),
None);
do_test!(concat!("fd00fe", "02", "0226"), None, None, None, Some(550));
}
fn do_simple_test_tlv_write() -> Result<(), io::Error> {
let mut stream = VecWriter(Vec::new());
stream.0.clear();
_encode_varint_length_prefixed_tlv!(&mut stream, {(1, 1u8, required), (42, None::<u64>, option)});
assert_eq!(stream.0, <Vec<u8>>::from_hex("03010101").unwrap());
stream.0.clear();
_encode_varint_length_prefixed_tlv!(&mut stream, {(1, Some(1u8), option)});
assert_eq!(stream.0, <Vec<u8>>::from_hex("03010101").unwrap());
stream.0.clear();
_encode_varint_length_prefixed_tlv!(&mut stream, {(4, 0xabcdu16, required), (42, None::<u64>, option)});
assert_eq!(stream.0, <Vec<u8>>::from_hex("040402abcd").unwrap());
stream.0.clear();
_encode_varint_length_prefixed_tlv!(&mut stream, {(42, None::<u64>, option), (0xff, 0xabcdu16, required)});
assert_eq!(stream.0, <Vec<u8>>::from_hex("06fd00ff02abcd").unwrap());
stream.0.clear();
_encode_varint_length_prefixed_tlv!(&mut stream, {(0, 1u64, required), (42, None::<u64>, option), (0xff, HighZeroBytesDroppedBigSize(0u64), required)});
assert_eq!(stream.0, <Vec<u8>>::from_hex("0e00080000000000000001fd00ff00").unwrap());
stream.0.clear();
_encode_varint_length_prefixed_tlv!(&mut stream, {(0, Some(1u64), option), (0xff, HighZeroBytesDroppedBigSize(0u64), required)});
assert_eq!(stream.0, <Vec<u8>>::from_hex("0e00080000000000000001fd00ff00").unwrap());
Ok(())
}
#[test]
fn simple_test_tlv_write() {
do_simple_test_tlv_write().unwrap();
}
}