lulz 2021-05-ser-fast-byte
authorMatt Corallo <git@bluematt.me>
Sun, 30 May 2021 00:30:50 +0000 (00:30 +0000)
committerMatt Corallo <git@bluematt.me>
Sun, 30 May 2021 00:33:25 +0000 (00:33 +0000)
lightning/src/util/ser.rs
lightning/src/util/ser_macros.rs

index af67dca799dbde7194ed5b78acc1df809743e5a4..d8662340aef6a6a599b9cecc00485968ff139664 100644 (file)
@@ -218,6 +218,19 @@ pub trait Readable
 {
        /// Reads a Self in from the given Read
        fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError>;
+
+       const FIXED_LEN: Option<usize> = None;
+       ///a
+       fn fixed_len_read(&self) -> Option<usize> { Self::FIXED_LEN }
+}
+pub(crate) trait Lulz {
+       fn lulz_len_read(&self) -> Option<usize>;
+}
+impl<T: Readable> Lulz for Option<T> {
+       #[inline]
+       fn lulz_len_read(&self) -> Option<usize> {
+               T::FIXED_LEN
+       }
 }
 
 /// A trait that various higher-level rust-lightning types implement allowing them to be read in
@@ -247,6 +260,7 @@ impl<T: Readable> Readable for OptionDeserWrapper<T> {
        fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
                Ok(Self(Some(Readable::read(reader)?)))
        }
+       const FIXED_LEN: Option<usize> = 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<usize> = 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<usize> = Some(1);
 }
 
 impl Writeable for bool {
@@ -465,6 +481,7 @@ impl Readable for bool {
                }
                Ok(buf[0] == 1)
        }
+       const FIXED_LEN: Option<usize> = Some(1);
 }
 
 // u8 arrays
@@ -486,6 +503,7 @@ macro_rules! impl_array {
                                r.read_exact(&mut buf)?;
                                Ok(buf)
                        }
+                       const FIXED_LEN: Option<usize> = Some($size);
                }
        );
 }
@@ -611,6 +629,7 @@ impl Readable for PublicKey {
                        Err(_) => return Err(DecodeError::InvalidValue),
                }
        }
+       const FIXED_LEN: Option<usize> = 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<usize> = 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<usize> = Some(32);
 }
 
 impl Writeable for Signature {
@@ -668,6 +689,7 @@ impl Readable for Signature {
                        Err(_) => return Err(DecodeError::InvalidValue),
                }
        }
+       const FIXED_LEN: Option<usize> = 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<usize> = 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<usize> = 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<usize> = Some(32);
 }
 
 impl<T: Writeable> Writeable for Option<T> {
@@ -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<usize> = 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<usize> = Some(32);
 }
 
 impl Writeable for OutPoint {
index 5f37fb996ffd40f9ec684826df4cfca1db9092b9..0b1e6646c43144e1d0c31c7ab507257bae9fa6c3 100644 (file)
@@ -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<usize> = Some($len);
                }
        }
 }