use core::fmt;
use eth_valkyoth_codec::{
DecodeError, DecodeLimits, decode_rlp_scalar, decode_rlp_u64, decode_rlp_u256_bytes,
encode_rlp_integer, encode_rlp_scalar, encoded_rlp_integer_len, encoded_rlp_scalar_len,
};
use crate::{Address, B256, BlockNumber, ChainId, Gas, Nonce, PrimitiveError, UnixTimestamp, Wei};
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PrimitiveRlpError {
Decode(DecodeError),
Primitive(PrimitiveError),
FixedWidthScalar {
expected: usize,
found: usize,
},
}
impl From<DecodeError> for PrimitiveRlpError {
fn from(error: DecodeError) -> Self {
Self::Decode(error)
}
}
impl From<PrimitiveError> for PrimitiveRlpError {
fn from(error: PrimitiveError) -> Self {
Self::Primitive(error)
}
}
impl fmt::Display for PrimitiveRlpError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Decode(error) => write!(f, "RLP decode error: {error}"),
Self::Primitive(error) => write!(f, "primitive domain error: {error}"),
Self::FixedWidthScalar { expected, found } => write!(
f,
"RLP scalar payload has wrong byte width for this primitive: expected {expected}, found {found}"
),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PrimitiveRlpError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Decode(error) => Some(error),
Self::Primitive(error) => Some(error),
Self::FixedWidthScalar { .. } => None,
}
}
}
macro_rules! rlp_u64_bridge {
($name:ident) => {
impl $name {
pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
encoded_u64_len(self.get())
}
pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
encode_u64(self.get(), output)
}
pub fn try_from_rlp(
input: &[u8],
limits: DecodeLimits,
) -> Result<Self, PrimitiveRlpError> {
decode_rlp_u64(input, limits)
.map(Self::new)
.map_err(Into::into)
}
}
};
}
impl ChainId {
pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
encoded_u64_len(self.get())
}
pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
encode_u64(self.get(), output)
}
pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
decode_rlp_u64(input, limits)
.map(Self::new)
.map_err(Into::into)
}
}
rlp_u64_bridge!(BlockNumber);
rlp_u64_bridge!(Gas);
rlp_u64_bridge!(Nonce);
rlp_u64_bridge!(UnixTimestamp);
impl Wei {
pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
let bytes = self.to_be_bytes();
encoded_rlp_integer_len(trim_u256_payload(&bytes)).map_err(Into::into)
}
pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
let bytes = self.to_be_bytes();
encode_rlp_integer(trim_u256_payload(&bytes), output).map_err(Into::into)
}
pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
decode_rlp_u256_bytes(input, limits)
.map(Self::from_be_bytes)
.map_err(Into::into)
}
}
impl Address {
pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
encoded_rlp_scalar_len(&self.to_bytes()).map_err(Into::into)
}
pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
encode_rlp_scalar(&self.to_bytes(), output).map_err(Into::into)
}
pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
let scalar = decode_rlp_scalar(input, limits)?;
let found = scalar.payload().len();
let bytes: [u8; 20] =
scalar
.payload()
.try_into()
.map_err(|_| PrimitiveRlpError::FixedWidthScalar {
expected: 20,
found,
})?;
Ok(Self::from_bytes(bytes))
}
}
impl B256 {
pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
encoded_rlp_scalar_len(&self.to_bytes()).map_err(Into::into)
}
pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
encode_rlp_scalar(&self.to_bytes(), output).map_err(Into::into)
}
pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
let scalar = decode_rlp_scalar(input, limits)?;
let found = scalar.payload().len();
let bytes: [u8; 32] =
scalar
.payload()
.try_into()
.map_err(|_| PrimitiveRlpError::FixedWidthScalar {
expected: 32,
found,
})?;
Ok(Self::from_bytes(bytes))
}
}
fn encoded_u64_len(value: u64) -> Result<usize, PrimitiveRlpError> {
let bytes = value.to_be_bytes();
encoded_rlp_integer_len(trim_u64_payload(&bytes)).map_err(Into::into)
}
fn encode_u64(value: u64, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
let bytes = value.to_be_bytes();
encode_rlp_integer(trim_u64_payload(&bytes), output).map_err(Into::into)
}
fn trim_u64_payload(bytes: &[u8; 8]) -> &[u8] {
let start = bytes.iter().position(|byte| *byte != 0).unwrap_or(8);
bytes.get(start..).unwrap_or(&[])
}
fn trim_u256_payload(bytes: &[u8; 32]) -> &[u8] {
let start = bytes.iter().position(|byte| *byte != 0).unwrap_or(32);
bytes.get(start..).unwrap_or(&[])
}