From 905d846ce87c5097a8364244929b569f83f94ca8 Mon Sep 17 00:00:00 2001 From: Wodann Date: Fri, 21 Jun 2024 17:22:48 +0000 Subject: [PATCH 1/5] fix: deserialization of null storage keys in AccessListItem --- crates/eips/src/eip2930.rs | 1 + crates/serde/src/lib.rs | 2 ++ crates/serde/src/optional.rs | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 crates/serde/src/optional.rs diff --git a/crates/eips/src/eip2930.rs b/crates/eips/src/eip2930.rs index a53715a963a..b0371bc314f 100644 --- a/crates/eips/src/eip2930.rs +++ b/crates/eips/src/eip2930.rs @@ -30,6 +30,7 @@ pub struct AccessListItem { strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=20)" ) )] + #[cfg_attr(feature = "serde", serde(deserialize_with = "alloy_serde::optional::or_default"))] pub storage_keys: Vec, } diff --git a/crates/serde/src/lib.rs b/crates/serde/src/lib.rs index ee8bb06fd15..9863846d9c8 100644 --- a/crates/serde/src/lib.rs +++ b/crates/serde/src/lib.rs @@ -18,6 +18,8 @@ use serde::Serializer; mod bool; pub use self::bool::*; +pub mod optional; + #[cfg_attr(not(test), deprecated = "use `quantity::{self, opt, vec}` instead")] pub mod num; #[allow(deprecated)] diff --git a/crates/serde/src/optional.rs b/crates/serde/src/optional.rs new file mode 100644 index 00000000000..819748c13f7 --- /dev/null +++ b/crates/serde/src/optional.rs @@ -0,0 +1,21 @@ +//! Serde functions for encoding optional values. +//! +//! This is defined as a "hex encoded unsigned integer", with a special case of 0 being `0x0`. +//! +//! A regex for this format is: `^0x([1-9a-f]+[0-9a-f]*|0)$`. +//! +//! This is only valid for human-readable [`serde`] implementations. +//! For non-human-readable implementations, the format is unspecified. +//! Currently, it uses a fixed-width big-endian byte-array. +use serde::{Deserialize, Deserializer}; + +/// For use with serde's `deserialize_with` on a sequence that must be +/// deserialized as a single but optional (i.e. possibly `null`) value. +pub fn or_default<'de, T, D>(deserializer: D) -> Result +where + T: Deserialize<'de> + Default, + D: Deserializer<'de>, +{ + let s: Option = Deserialize::deserialize(deserializer)?; + Ok(s.unwrap_or_default()) +} From 557b1fce050a99f2055144931b8246eaf0de1b68 Mon Sep 17 00:00:00 2001 From: Wodann Date: Fri, 21 Jun 2024 17:51:52 +0000 Subject: [PATCH 2/5] test: add test --- crates/eips/src/eip2930.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/crates/eips/src/eip2930.rs b/crates/eips/src/eip2930.rs index b0371bc314f..ca3752eeb65 100644 --- a/crates/eips/src/eip2930.rs +++ b/crates/eips/src/eip2930.rs @@ -30,6 +30,7 @@ pub struct AccessListItem { strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=20)" ) )] + // In JSON, we have to accept `null` for storage key, which is interpreted as an empty array. #[cfg_attr(feature = "serde", serde(deserialize_with = "alloy_serde::optional::or_default"))] pub storage_keys: Vec, } @@ -167,8 +168,24 @@ pub struct AccessListWithGasUsed { #[cfg(all(test, feature = "serde"))] mod tests { + use serde_json::json; + use super::*; + #[test] + fn access_list_null_storage_keys() { + let json = json!([ + { + "address": "0x81b7bdd5b89c90b63f604fc7cdd17035cb939707", + "storageKeys": null, + } + ]); + + let access_list = serde_json::from_value::(json).unwrap(); + assert_eq!(access_list.len(), 1); + assert_eq!(access_list[0].storage_keys, Vec::::default()); + } + #[test] fn access_list_serde() { let list = AccessList(vec![ From f33ce645b4a08876ea65393e419a9f1b417e639e Mon Sep 17 00:00:00 2001 From: Wodann Date: Fri, 21 Jun 2024 18:58:27 +0000 Subject: [PATCH 3/5] misc: apply review suggestions --- crates/serde/src/optional.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/serde/src/optional.rs b/crates/serde/src/optional.rs index 819748c13f7..5ef3288461c 100644 --- a/crates/serde/src/optional.rs +++ b/crates/serde/src/optional.rs @@ -1,17 +1,9 @@ //! Serde functions for encoding optional values. -//! -//! This is defined as a "hex encoded unsigned integer", with a special case of 0 being `0x0`. -//! -//! A regex for this format is: `^0x([1-9a-f]+[0-9a-f]*|0)$`. -//! -//! This is only valid for human-readable [`serde`] implementations. -//! For non-human-readable implementations, the format is unspecified. -//! Currently, it uses a fixed-width big-endian byte-array. use serde::{Deserialize, Deserializer}; /// For use with serde's `deserialize_with` on a sequence that must be /// deserialized as a single but optional (i.e. possibly `null`) value. -pub fn or_default<'de, T, D>(deserializer: D) -> Result +pub fn null_as_default<'de, T, D>(deserializer: D) -> Result where T: Deserialize<'de> + Default, D: Deserializer<'de>, From 4af7f9f9050eb0ef3192618f5aa1c7e77674fbd3 Mon Sep 17 00:00:00 2001 From: Wodann Date: Fri, 21 Jun 2024 16:20:58 -0500 Subject: [PATCH 4/5] Update crates/eips/src/eip2930.rs Co-authored-by: Matthias Seitz --- crates/eips/src/eip2930.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eips/src/eip2930.rs b/crates/eips/src/eip2930.rs index ca3752eeb65..d9e7e2165b3 100644 --- a/crates/eips/src/eip2930.rs +++ b/crates/eips/src/eip2930.rs @@ -31,7 +31,7 @@ pub struct AccessListItem { ) )] // In JSON, we have to accept `null` for storage key, which is interpreted as an empty array. - #[cfg_attr(feature = "serde", serde(deserialize_with = "alloy_serde::optional::or_default"))] + #[cfg_attr(feature = "serde", serde(deserialize_with = "alloy_serde::optional::null_as_default"))] pub storage_keys: Vec, } From fdd21940e2046775d223b23ffa02cc67f855379d Mon Sep 17 00:00:00 2001 From: Wodann Date: Fri, 21 Jun 2024 21:25:43 +0000 Subject: [PATCH 5/5] misc: apply review suggestion --- crates/eips/src/eip2930.rs | 2 +- crates/serde/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/eips/src/eip2930.rs b/crates/eips/src/eip2930.rs index d9e7e2165b3..2dd78fc3ecc 100644 --- a/crates/eips/src/eip2930.rs +++ b/crates/eips/src/eip2930.rs @@ -31,7 +31,7 @@ pub struct AccessListItem { ) )] // In JSON, we have to accept `null` for storage key, which is interpreted as an empty array. - #[cfg_attr(feature = "serde", serde(deserialize_with = "alloy_serde::optional::null_as_default"))] + #[cfg_attr(feature = "serde", serde(deserialize_with = "alloy_serde::null_as_default"))] pub storage_keys: Vec, } diff --git a/crates/serde/src/lib.rs b/crates/serde/src/lib.rs index 9863846d9c8..633216fc8b8 100644 --- a/crates/serde/src/lib.rs +++ b/crates/serde/src/lib.rs @@ -18,7 +18,8 @@ use serde::Serializer; mod bool; pub use self::bool::*; -pub mod optional; +mod optional; +pub use self::optional::*; #[cfg_attr(not(test), deprecated = "use `quantity::{self, opt, vec}` instead")] pub mod num;