eth-valkyoth-primitives 0.11.1

Core no_std Ethereum protocol primitives.
Documentation
use eth_valkyoth_codec::{DecodeError, RlpDecode, RlpDeriveError, RlpEncode, RlpInteger, RlpItem};

use crate::{
    Address, B256, BlockNumber, ChainId, Gas, Nonce, PrimitiveError, PrimitiveRlpError,
    UnixTimestamp, Wei,
};

impl From<PrimitiveRlpError> for RlpDeriveError {
    fn from(_error: PrimitiveRlpError) -> Self {
        Self::Field
    }
}

macro_rules! rlp_u64_traits {
    ($name:ident) => {
        impl RlpEncode for $name {
            type Error = PrimitiveRlpError;

            fn encoded_rlp_len(&self) -> Result<usize, Self::Error> {
                $name::encoded_rlp_len(*self)
            }

            fn encode_rlp(&self, output: &mut [u8]) -> Result<usize, Self::Error> {
                $name::encode_rlp(*self, output)
            }
        }

        impl RlpDecode for $name {
            type Error = PrimitiveRlpError;

            fn decode_rlp(
                input: &[u8],
                limits: eth_valkyoth_codec::DecodeLimits,
            ) -> Result<Self, Self::Error> {
                $name::try_from_rlp(input, limits)
            }

            fn decode_rlp_item(item: RlpItem<'_>) -> Result<Self, Self::Error> {
                decode_u64_item(item).map($name::new)
            }
        }
    };
}

rlp_u64_traits!(ChainId);
rlp_u64_traits!(BlockNumber);
rlp_u64_traits!(Gas);
rlp_u64_traits!(Nonce);
rlp_u64_traits!(UnixTimestamp);

impl RlpEncode for Wei {
    type Error = PrimitiveRlpError;

    fn encoded_rlp_len(&self) -> Result<usize, Self::Error> {
        Self::encoded_rlp_len(*self)
    }

    fn encode_rlp(&self, output: &mut [u8]) -> Result<usize, Self::Error> {
        Self::encode_rlp(*self, output)
    }
}

impl RlpDecode for Wei {
    type Error = PrimitiveRlpError;

    fn decode_rlp(
        input: &[u8],
        limits: eth_valkyoth_codec::DecodeLimits,
    ) -> Result<Self, Self::Error> {
        Self::try_from_rlp(input, limits)
    }

    fn decode_rlp_item(item: RlpItem<'_>) -> Result<Self, Self::Error> {
        let scalar = item.as_scalar().ok_or(DecodeError::UnexpectedList)?;
        RlpInteger::try_from_scalar(scalar)?
            .to_be_bytes32()
            .map(Self::from_be_bytes)
            .map_err(Into::into)
    }
}

macro_rules! rlp_fixed_scalar_traits {
    ($name:ident, $len:expr) => {
        impl RlpEncode for $name {
            type Error = PrimitiveRlpError;

            fn encoded_rlp_len(&self) -> Result<usize, Self::Error> {
                $name::encoded_rlp_len(*self)
            }

            fn encode_rlp(&self, output: &mut [u8]) -> Result<usize, Self::Error> {
                $name::encode_rlp(*self, output)
            }
        }

        impl RlpDecode for $name {
            type Error = PrimitiveRlpError;

            fn decode_rlp(
                input: &[u8],
                limits: eth_valkyoth_codec::DecodeLimits,
            ) -> Result<Self, Self::Error> {
                $name::try_from_rlp(input, limits)
            }

            fn decode_rlp_item(item: RlpItem<'_>) -> Result<Self, Self::Error> {
                let scalar = item.as_scalar().ok_or(DecodeError::UnexpectedList)?;
                let found = scalar.payload().len();
                let bytes = scalar.payload().try_into().map_err(|_| {
                    PrimitiveRlpError::FixedWidthScalar {
                        expected: $len,
                        found,
                    }
                })?;
                Ok($name::from_bytes(bytes))
            }
        }
    };
}

rlp_fixed_scalar_traits!(Address, 20);
rlp_fixed_scalar_traits!(B256, 32);

fn decode_u64_item(item: RlpItem<'_>) -> Result<u64, PrimitiveRlpError> {
    let scalar = item.as_scalar().ok_or(DecodeError::UnexpectedList)?;
    RlpInteger::try_from_scalar(scalar)?
        .to_u64()
        .map_err(map_decode_u64_error)
}

fn map_decode_u64_error(error: DecodeError) -> PrimitiveRlpError {
    match error {
        DecodeError::Malformed => PrimitiveRlpError::Primitive(PrimitiveError::NonCanonicalInteger),
        DecodeError::LengthOverflow | DecodeError::OffsetOutOfBounds => {
            PrimitiveRlpError::Primitive(PrimitiveError::IntegerTooLarge)
        }
        _ => PrimitiveRlpError::Decode(error),
    }
}