Skip to content

Commit

Permalink
feat: add eip-7685 enc/decode traits (#704)
Browse files Browse the repository at this point in the history
* feat: add eip-7685 enc/decode traits

* chore: fmt

* feat: combined trait

* chore: mark non_exhaustive
  • Loading branch information
onbjerg authored May 7, 2024
1 parent 72ac13b commit e60d64c
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
124 changes: 124 additions & 0 deletions crates/eips/src/eip7685.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//! [EIP-7685]: General purpose execution layer requests
//!
//! Contains traits for encoding and decoding EIP-7685 requests, as well as validation functions.
//!
//! [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685

#[cfg(not(feature = "std"))]
use crate::alloc::{vec, vec::Vec};

use alloy_rlp::BufMut;
use core::{
fmt,
fmt::{Display, Formatter},
};

/// [EIP-7685] decoding errors.
///
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum Eip7685Error {
/// Rlp error from [`alloy_rlp`].
RlpError(alloy_rlp::Error),
/// Got an unexpected request type while decoding.
UnexpectedType(u8),
/// There was no request type in the buffer.
MissingType,
}

impl Display for Eip7685Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::RlpError(err) => write!(f, "{err}"),
Self::UnexpectedType(t) => write!(f, "Unexpected request type. Got {t}."),
Self::MissingType => write!(f, "There was no type flag"),
}
}
}

impl From<alloy_rlp::Error> for Eip7685Error {
fn from(err: alloy_rlp::Error) -> Self {
Self::RlpError(err)
}
}

/// Decoding trait for [EIP-7685] requests. The trait should be implemented for an envelope that
/// wraps each possible request type.
///
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
pub trait Decodable7685: Sized {
/// Extract the type byte from the buffer, if any. The type byte is the
/// first byte.
fn extract_type_byte(buf: &mut &[u8]) -> Option<u8> {
buf.first().copied()
}

/// Decode the appropriate variant, based on the request type.
///
/// This function is invoked by [`Self::decode_7685`] with the type byte, and the tail of the
/// buffer.
///
/// ## Note
///
/// This should be a simple match block that invokes an inner type's decoder. The decoder is
/// request type dependent.
fn typed_decode(ty: u8, buf: &mut &[u8]) -> Result<Self, Eip7685Error>;

/// Decode an EIP-7685 request into a concrete instance
fn decode_7685(buf: &mut &[u8]) -> Result<Self, Eip7685Error> {
Self::extract_type_byte(buf)
.map(|ty| Self::typed_decode(ty, &mut &buf[1..]))
.unwrap_or(Err(Eip7685Error::MissingType))
}
}

/// Encoding trait for [EIP-7685] requests. The trait should be implemented for an envelope that
/// wraps each possible request type.
///
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
pub trait Encodable7685: Sized + Send + Sync + 'static {
/// Return the request type.
fn request_type(&self) -> u8;

/// Encode the request according to [EIP-7685] rules.
///
/// First a 1-byte flag specifying the request type, then the encoded payload.
///
/// The encoding of the payload is request-type dependent.
///
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
fn encode_7685(&self, out: &mut dyn BufMut) {
out.put_u8(self.request_type());
self.encode_payload_7685(out);
}

/// Encode the request payload.
///
/// The encoding for the payload is request type dependent.
fn encode_payload_7685(&self, out: &mut dyn BufMut);

/// Encode the request according to [EIP-7685] rules.
///
/// First a 1-byte flag specifying the request type, then the encoded payload.
///
/// The encoding of the payload is request-type dependent.
///
/// This is a convenience method for encoding into a vec, and returning the
/// vec.
///
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
fn encoded_7685(&self) -> Vec<u8> {
let mut out = vec![];
self.encode_7685(&mut out);
out
}
}

/// An [EIP-7685] request envelope, blanket implemented for types that impl
/// [`Encodable7685`] and [`Decodable7685`]. This envelope is a wrapper around
/// a request, differentiated by the request type.
///
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
pub trait Eip7685RequestEnvelope: Decodable7685 + Encodable7685 {}
impl<T> Eip7685RequestEnvelope for T where T: Decodable7685 + Encodable7685 {}
2 changes: 2 additions & 0 deletions crates/eips/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ pub mod eip6110;
pub mod merge;

pub mod eip7002;

pub mod eip7685;

0 comments on commit e60d64c

Please sign in to comment.