From: Matt Corallo Date: Sun, 30 May 2021 00:30:50 +0000 (+0000) Subject: lulz X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=refs%2Fheads%2F2021-05-ser-fast-byte;p=rust-lightning lulz --- diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index af67dca79..d8662340a 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -218,6 +218,19 @@ pub trait Readable { /// Reads a Self in from the given Read fn read(reader: &mut R) -> Result; + + const FIXED_LEN: Option = None; + ///a + fn fixed_len_read(&self) -> Option { Self::FIXED_LEN } +} +pub(crate) trait Lulz { + fn lulz_len_read(&self) -> Option; +} +impl Lulz for Option { + #[inline] + fn lulz_len_read(&self) -> Option { + T::FIXED_LEN + } } /// A trait that various higher-level rust-lightning types implement allowing them to be read in @@ -247,6 +260,7 @@ impl Readable for OptionDeserWrapper { fn read(reader: &mut R) -> Result { Ok(Self(Some(Readable::read(reader)?))) } + const FIXED_LEN: Option = T::FIXED_LEN; } pub(crate) struct U8Wrapper(pub u8); @@ -400,6 +414,7 @@ macro_rules! impl_writeable_primitive { reader.read_exact(&mut buf)?; Ok(<$val_type>::from_be_bytes(buf)) } + const FIXED_LEN: Option = Some($len); } impl Readable for HighZeroBytesDroppedVarInt<$val_type> { #[inline] @@ -447,6 +462,7 @@ impl Readable for u8 { reader.read_exact(&mut buf)?; Ok(buf[0]) } + const FIXED_LEN: Option = Some(1); } impl Writeable for bool { @@ -465,6 +481,7 @@ impl Readable for bool { } Ok(buf[0] == 1) } + const FIXED_LEN: Option = Some(1); } // u8 arrays @@ -486,6 +503,7 @@ macro_rules! impl_array { r.read_exact(&mut buf)?; Ok(buf) } + const FIXED_LEN: Option = Some($size); } ); } @@ -611,6 +629,7 @@ impl Readable for PublicKey { Err(_) => return Err(DecodeError::InvalidValue), } } + const FIXED_LEN: Option = Some(PUBLIC_KEY_SIZE); } impl Writeable for SecretKey { @@ -633,6 +652,7 @@ impl Readable for SecretKey { Err(_) => return Err(DecodeError::InvalidValue), } } + const FIXED_LEN: Option = Some(32); } impl Writeable for Sha256dHash { @@ -648,6 +668,7 @@ impl Readable for Sha256dHash { let buf: [u8; 32] = Readable::read(r)?; Ok(Sha256dHash::from_slice(&buf[..]).unwrap()) } + const FIXED_LEN: Option = Some(32); } impl Writeable for Signature { @@ -668,6 +689,7 @@ impl Readable for Signature { Err(_) => return Err(DecodeError::InvalidValue), } } + const FIXED_LEN: Option = Some(COMPACT_SIGNATURE_SIZE); } impl Writeable for PaymentPreimage { @@ -681,6 +703,7 @@ impl Readable for PaymentPreimage { let buf: [u8; 32] = Readable::read(r)?; Ok(PaymentPreimage(buf)) } + const FIXED_LEN: Option = Some(32); } impl Writeable for PaymentHash { @@ -694,6 +717,7 @@ impl Readable for PaymentHash { let buf: [u8; 32] = Readable::read(r)?; Ok(PaymentHash(buf)) } + const FIXED_LEN: Option = Some(32); } impl Writeable for PaymentSecret { @@ -707,6 +731,7 @@ impl Readable for PaymentSecret { let buf: [u8; 32] = Readable::read(r)?; Ok(PaymentSecret(buf)) } + const FIXED_LEN: Option = Some(32); } impl Writeable for Option { @@ -748,6 +773,7 @@ impl Readable for Txid { let buf: [u8; 32] = Readable::read(r)?; Ok(Txid::from_slice(&buf[..]).unwrap()) } + const FIXED_LEN: Option = Some(32); } impl Writeable for BlockHash { @@ -763,6 +789,7 @@ impl Readable for BlockHash { let buf: [u8; 32] = Readable::read(r)?; Ok(BlockHash::from_slice(&buf[..]).unwrap()) } + const FIXED_LEN: Option = Some(32); } impl Writeable for OutPoint { diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 5f37fb996..0b1e6646c 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -93,6 +93,10 @@ macro_rules! decode_tlv { }; ($name_ty: path, $stream: expr, {$(($reqtype: expr, $reqfield: ident)),*}, {$(($type: expr, $field: ident)),*}) => { { use ln::msgs::DecodeError; + #[allow(unused_imports)] + use std::io::Read; + #[allow(unused_imports)] + use util::ser::Lulz; let mut last_seen_type = None; 'tlv_read: loop { use util::ser; @@ -135,29 +139,72 @@ macro_rules! decode_tlv { last_seen_type = Some(typ.0); // Finally, read the length and value itself: - let length: ser::BigSize = Readable::read($stream)?; - let mut s = ser::FixedLengthReader::new($stream, length.0); match typ.0 { $($reqtype => { - $reqfield = ser::Readable::read(&mut s)?; - if s.bytes_remain() { - s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes - Err(DecodeError::InvalidValue)? + match $reqfield.fixed_len_read() { + Some(len) if len != 0 => { + let mut v = [0u8; 9]; + let bslen = { + let mut w = &mut v[..]; + ser::BigSize(len as u64).write(&mut w).unwrap(); + 9 - w.len() + }; + assert!(bslen < 9); + let mut r = [0; 9]; + $stream.read_exact(&mut r[0..bslen])?; + if r[..bslen] != v[..bslen] { + Err(DecodeError::InvalidValue)? + } + $reqfield = ser::Readable::read($stream)?; + }, + _ => { + let length: ser::BigSize = Readable::read($stream)?; + let mut s = ser::FixedLengthReader::new($stream, length.0); + $reqfield = ser::Readable::read(&mut s)?; + if s.bytes_remain() { + s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes + Err(DecodeError::InvalidValue)? + } + } } },)* $($type => { - $field = Some(ser::Readable::read(&mut s)?); - if s.bytes_remain() { - s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes - Err(DecodeError::InvalidValue)? + match $field.lulz_len_read() { + Some(len) if len != 0 => { + let mut v = [0u8; 9]; + let bslen = { + let mut w = &mut v[..]; + ser::BigSize(len as u64).write(&mut w).unwrap(); + 9 - w.len() + }; + assert!(bslen < 9); + let mut r = [0; 9]; + $stream.read_exact(&mut r[0..bslen])?; + if r[..bslen] != v[..bslen] { + Err(DecodeError::InvalidValue)? + } + $field = Some(ser::Readable::read($stream)?); + }, + _ => { + let length: ser::BigSize = Readable::read($stream)?; + let mut s = ser::FixedLengthReader::new($stream, length.0); + $field = Some(ser::Readable::read(&mut s)?); + if s.bytes_remain() { + s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes + Err(DecodeError::InvalidValue)? + } + } } },)* x if x % 2 == 0 => { Err(DecodeError::UnknownRequiredFeature)? }, - _ => {}, + _ => { + let length: ser::BigSize = Readable::read($stream)?; + let mut s = ser::FixedLengthReader::new($stream, length.0); + s.eat_remaining()?; + }, } - s.eat_remaining()?; } // Make sure we got to each required type after we've read every TLV: $({ @@ -213,6 +260,7 @@ macro_rules! impl_writeable { $($field: ::util::ser::Readable::read(r)?),* }) } + const FIXED_LEN: Option = Some($len); } } }