Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add function to decode an entire slice #23

Merged
merged 11 commits into from
Aug 5, 2024
Merged
37 changes: 36 additions & 1 deletion crates/rlp/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,24 @@ mod std_impl {
}
}

/// Decodes the entire input, ensuring no trailing bytes remain.
///
/// # Errors
///
/// Returns an error if the encoding is invalid or if data remains after decoding the RLP item.
#[inline]
pub fn decode_exact<T: Decodable>(bytes: impl AsRef<[u8]>) -> Result<T> {
let mut buf = bytes.as_ref();
let out = T::decode(&mut buf)?;

// check if there are any remaining bytes after decoding
if !buf.is_empty() {
return Err(Error::TrailingBytes);
}

Ok(out)
}

/// Left-pads a slice to a statically known size array.
///
/// # Errors
Expand Down Expand Up @@ -212,7 +230,7 @@ fn slice_to_array<const N: usize>(slice: &[u8]) -> Result<[u8; N]> {
#[cfg(test)]
mod tests {
use super::*;
use crate::Encodable;
use crate::{encode, Encodable};
use core::fmt::Debug;
use hex_literal::hex;

Expand Down Expand Up @@ -356,4 +374,21 @@ mod tests {
check_decode::<u8, _>([(Err(Error::InputTooShort), &hex!("82")[..])]);
check_decode::<u64, _>([(Err(Error::InputTooShort), &hex!("82")[..])]);
}

#[test]
fn rlp_full() {
fn check_decode_exact<T: Decodable + Encodable + PartialEq + Debug>(input: T) {
let encoded = encode(&input);
assert_eq!(decode_exact::<T>(&encoded), Ok(input));
assert_eq!(
decode_exact::<T>([encoded, vec![0x00]].concat()),
Err(Error::TrailingBytes)
);
}

check_decode_exact::<String>("".into());
check_decode_exact::<String>("test1234".into());
check_decode_exact::<Vec<u64>>(vec![]);
check_decode_exact::<Vec<u64>>(vec![0; 4]);
}
}
3 changes: 3 additions & 0 deletions crates/rlp/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub enum Error {
LeadingZero,
/// Overran input while decoding.
InputTooShort,
/// Additional trailing bytes found after decoding.
TrailingBytes,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be expressed with the Unexptectedlength variant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering that this is currently returned when the payload length doesn't match the array size or other payload length issues, I didn't think it would be a good fit for this since decode_exact() doesn't look at the payload, but rather the entire RLP encoded data. However, if this is just me, I can definitely adjust `UnexpectedLength' to better account for both cases...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be ok with the new variant however this is unfortunately a breaking change because the enum is not marked as #[non_exhaustive]. So for now I would prefer the other option and adding a TODO for the new variant

/// Expected single byte, but got invalid value.
NonCanonicalSingleByte,
/// Expected size, but got invalid value.
Expand Down Expand Up @@ -42,6 +44,7 @@ impl fmt::Display for Error {
Self::Overflow => f.write_str("overflow"),
Self::LeadingZero => f.write_str("leading zero"),
Self::InputTooShort => f.write_str("input too short"),
Self::TrailingBytes => f.write_str("trailing bytes"),
Self::NonCanonicalSingleByte => f.write_str("non-canonical single byte"),
Self::NonCanonicalSize => f.write_str("non-canonical size"),
Self::UnexpectedLength => f.write_str("unexpected length"),
Expand Down
2 changes: 1 addition & 1 deletion crates/rlp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
extern crate alloc;

mod decode;
pub use decode::{Decodable, Rlp};
pub use decode::{decode_exact, Decodable, Rlp};

mod error;
pub use error::{Error, Result};
Expand Down
Loading