From cd1438caacb26ae6d075edd56aadb98502fae6a8 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Mon, 30 Sep 2024 16:58:49 +0300 Subject: [PATCH] feat(7702): bincode compatibility --- crates/eip7702/Cargo.toml | 4 ++ crates/eip7702/src/auth_list.rs | 99 +++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/crates/eip7702/Cargo.toml b/crates/eip7702/Cargo.toml index dd0ff54..878eb7a 100644 --- a/crates/eip7702/Cargo.toml +++ b/crates/eip7702/Cargo.toml @@ -23,6 +23,7 @@ alloy-rlp = { workspace = true, features = ["derive"] } # serde serde = { workspace = true, optional = true } +serde_with = { version = "3", optional = true } # arbitrary arbitrary = { workspace = true, features = ["derive"], optional = true } @@ -32,12 +33,15 @@ k256 = { workspace = true, optional = true } rand = { workspace = true, optional = true } [dev-dependencies] +bincode = "1.3" +rand = "0.8" serde_json.workspace = true [features] default = ["std"] std = ["alloy-primitives/std", "alloy-rlp/std", "serde?/std"] serde = ["dep:serde", "alloy-primitives/serde"] +serde-bincode-compat = ["serde_with"] arbitrary = [ "std", "dep:arbitrary", diff --git a/crates/eip7702/src/auth_list.rs b/crates/eip7702/src/auth_list.rs index 80f759e..937e5be 100644 --- a/crates/eip7702/src/auth_list.rs +++ b/crates/eip7702/src/auth_list.rs @@ -372,3 +372,102 @@ mod tests { let _auth = SignedAuthorization::arbitrary(&mut unstructured).unwrap(); } } + +/// Bincode-compatible [`SignedAuthorization`] serde implementation. +#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))] +pub mod serde_bincode_compat { + use alloc::borrow::Cow; + use alloy_primitives::Signature; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde_with::{DeserializeAs, SerializeAs}; + + use crate::Authorization; + + /// Bincode-compatible [`super::SignedAuthorization`] serde implementation. + /// + /// Intended to use with the [`serde_with::serde_as`] macro in the following way: + /// ```rust + /// use alloy_eip7702::{serde_bincode_compat, SignedAuthorization}; + /// use serde::{Deserialize, Serialize}; + /// use serde_with::serde_as; + /// + /// #[serde_as] + /// #[derive(Serialize, Deserialize)] + /// struct Data { + /// #[serde_as(as = "serde_bincode_compat::SignedAuthorization")] + /// authorization: SignedAuthorization, + /// } + /// ``` + #[derive(Debug, Serialize, Deserialize)] + struct SignedAuthorization<'a> { + // Bincode doesn't support `#[serde(flatten)]`: + inner: Cow<'a, Authorization>, + signature: Cow<'a, Signature>, + } + + impl<'a> From<&'a super::SignedAuthorization> for SignedAuthorization<'a> { + fn from(value: &'a super::SignedAuthorization) -> Self { + Self { inner: Cow::Borrowed(&value.inner), signature: Cow::Borrowed(&value.signature) } + } + } + + impl<'a> From> for super::SignedAuthorization { + fn from(value: SignedAuthorization<'a>) -> Self { + Self { inner: value.inner.into_owned(), signature: value.signature.into_owned() } + } + } + + impl<'a> SerializeAs for SignedAuthorization<'a> { + fn serialize_as( + source: &super::SignedAuthorization, + serializer: S, + ) -> Result + where + S: Serializer, + { + SignedAuthorization::from(source).serialize(serializer) + } + } + + impl<'de> DeserializeAs<'de, super::SignedAuthorization> for SignedAuthorization<'de> { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + SignedAuthorization::deserialize(deserializer).map(Into::into) + } + } + + #[cfg(all(test, feature = "k256"))] + mod tests { + use arbitrary::Arbitrary; + use rand::Rng; + use serde::{Deserialize, Serialize}; + use serde_with::serde_as; + + use super::super::{serde_bincode_compat, SignedAuthorization}; + + #[test] + fn test_signed_authorization_bincode_roundtrip() { + #[serde_as] + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] + struct Data { + #[serde_as(as = "serde_bincode_compat::SignedAuthorization")] + authorization: SignedAuthorization, + } + + let mut bytes = [0u8; 1024]; + rand::thread_rng().fill(bytes.as_mut_slice()); + let data = Data { + authorization: SignedAuthorization::arbitrary(&mut arbitrary::Unstructured::new( + &bytes, + )) + .unwrap(), + }; + + let encoded = bincode::serialize(&data).unwrap(); + let decoded: Data = bincode::deserialize(&encoded).unwrap(); + assert_eq!(decoded, data); + } + } +}