mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-30 09:38:24 -05:00
chore: reuse alloy rpc serde helpers (#6105)
This commit is contained in:
@@ -18,7 +18,9 @@ mod otterscan;
|
||||
mod peer;
|
||||
pub mod relay;
|
||||
mod rpc;
|
||||
pub mod serde_helpers;
|
||||
|
||||
// re-export for convenience
|
||||
pub use alloy_rpc_types::serde_helpers;
|
||||
|
||||
// Ethereum specific rpc types coming from alloy.
|
||||
pub use alloy_rpc_types::*;
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
//! Json U256 serde helpers.
|
||||
|
||||
use alloy_primitives::U256;
|
||||
use serde::{
|
||||
de::{Error, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
/// Wrapper around primitive U256 type that also supports deserializing numbers
|
||||
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub struct JsonU256(pub U256);
|
||||
|
||||
impl From<JsonU256> for U256 {
|
||||
fn from(value: JsonU256) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U256> for JsonU256 {
|
||||
fn from(value: U256) -> Self {
|
||||
JsonU256(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for JsonU256 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for JsonU256 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for JsonU256 {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
deserializer.deserialize_any(JsonU256Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor pattern for `JsonU256` deserialization.
|
||||
struct JsonU256Visitor;
|
||||
|
||||
impl<'a> Visitor<'a> for JsonU256Visitor {
|
||||
type Value = JsonU256;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(formatter, "a hex encoding or decimal number")
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(JsonU256(U256::from(value)))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let value = u256_from_str(value)?;
|
||||
Ok(JsonU256(value))
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.visit_str(value.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
/// Supports parsing `U256` numbers as strings via [JsonU256]
|
||||
pub fn deserialize_json_u256<'de, D>(deserializer: D) -> Result<U256, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let num = JsonU256::deserialize(deserializer)?;
|
||||
Ok(num.into())
|
||||
}
|
||||
|
||||
/// Supports parsing `U256` numbers as strings via [JsonU256]
|
||||
pub fn deserialize_json_u256_opt<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let num = Option::<JsonU256>::deserialize(deserializer)?;
|
||||
Ok(num.map(Into::into))
|
||||
}
|
||||
|
||||
/// Supports deserializing a [U256] from a [String].
|
||||
pub fn u256_from_str<E>(raw: &str) -> Result<U256, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let value = match raw.len() {
|
||||
0 => U256::ZERO,
|
||||
2 if raw.starts_with("0x") => U256::ZERO,
|
||||
_ if raw.starts_with("0x") => U256::from_str(raw)
|
||||
.map_err(|e| Error::custom(format!("Parsing JsonU256 as hex failed {raw}: {e}")))?,
|
||||
_ => U256::from_str_radix(raw, 10).map_err(|e| {
|
||||
Error::custom(format!("Parsing JsonU256 as decimal failed {raw}: {e:?}"))
|
||||
})?,
|
||||
};
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Supports parsing the TTD as an `Option<u64>`, or `Option<f64>` specifically for the mainnet TTD
|
||||
/// (5.875e22).
|
||||
pub fn deserialize_json_ttd_opt<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = Option::<Value>::deserialize(deserializer)?;
|
||||
value.map(|value| ttd_from_value::<'de, D>(value)).transpose()
|
||||
}
|
||||
|
||||
/// Converts the given [serde_json::Value] into a `U256` value for TTD deserialization.
|
||||
fn ttd_from_value<'de, D>(val: Value) -> Result<U256, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let val = match val {
|
||||
Value::Number(num) => num,
|
||||
Value::String(raw) => return u256_from_str(&raw),
|
||||
_ => return Err(Error::custom("TTD must be a number or string")),
|
||||
};
|
||||
|
||||
let num = if let Some(val) = val.as_u64() {
|
||||
U256::from(val)
|
||||
} else if let Some(value) = val.as_f64() {
|
||||
// The ethereum mainnet TTD is 58750000000000000000000, and geth serializes this
|
||||
// without quotes, because that is how golang `big.Int`s marshal in JSON. Numbers
|
||||
// are arbitrary precision in JSON, so this is valid JSON. This number is also
|
||||
// greater than a `u64`.
|
||||
//
|
||||
// Unfortunately, serde_json only supports parsing up to `u64`, resorting to `f64`
|
||||
// once `u64` overflows:
|
||||
// <https://github.com/serde-rs/json/blob/4bc1eaa03a6160593575bc9bc60c94dba4cab1e3/src/de.rs#L1411-L1415>
|
||||
// <https://github.com/serde-rs/json/blob/4bc1eaa03a6160593575bc9bc60c94dba4cab1e3/src/de.rs#L479-L484>
|
||||
// <https://github.com/serde-rs/json/blob/4bc1eaa03a6160593575bc9bc60c94dba4cab1e3/src/de.rs#L102-L108>
|
||||
//
|
||||
// serde_json does have an arbitrary precision feature, but this breaks untagged
|
||||
// enums in serde:
|
||||
// <https://github.com/serde-rs/serde/issues/2230>
|
||||
// <https://github.com/serde-rs/serde/issues/1183>
|
||||
//
|
||||
// To solve this, we use the captured float and return the TTD as a U256 if it's equal.
|
||||
if value == 5.875e22 {
|
||||
U256::from(58750000000000000000000u128)
|
||||
} else {
|
||||
// We could try to convert to a u128 here but there would probably be loss of
|
||||
// precision, so we just return an error.
|
||||
return Err(Error::custom("Deserializing a large non-mainnet TTD is not supported"))
|
||||
}
|
||||
} else {
|
||||
// must be i64 - negative numbers are not supported
|
||||
return Err(Error::custom("Negative TTD values are invalid and will not be deserialized"))
|
||||
};
|
||||
|
||||
Ok(num)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::JsonU256;
|
||||
use alloy_primitives::U256;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[test]
|
||||
fn jsonu256_deserialize() {
|
||||
let deserialized: Vec<JsonU256> =
|
||||
serde_json::from_str(r#"["","0", "0x","10",10,"0x10"]"#).unwrap();
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
vec![
|
||||
JsonU256(U256::ZERO),
|
||||
JsonU256(U256::ZERO),
|
||||
JsonU256(U256::ZERO),
|
||||
JsonU256(U256::from(10)),
|
||||
JsonU256(U256::from(10)),
|
||||
JsonU256(U256::from(16)),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jsonu256_serialize() {
|
||||
let data = JsonU256(U256::from(16));
|
||||
let serialized = serde_json::to_string(&data).unwrap();
|
||||
|
||||
assert_eq!(serialized, r#""0x10""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_ttd() {
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Ttd(#[serde(deserialize_with = "super::deserialize_json_ttd_opt")] Option<U256>);
|
||||
|
||||
let deserialized: Vec<Ttd> = serde_json::from_str(
|
||||
r#"["",0,"0","0x0","58750000000000000000000",58750000000000000000000]"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
vec![
|
||||
Ttd(Some(U256::ZERO)),
|
||||
Ttd(Some(U256::ZERO)),
|
||||
Ttd(Some(U256::ZERO)),
|
||||
Ttd(Some(U256::ZERO)),
|
||||
Ttd(Some(U256::from(58750000000000000000000u128))),
|
||||
Ttd(Some(U256::from(58750000000000000000000u128))),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//! Serde helpers for primitive types.
|
||||
|
||||
use alloy_primitives::B256;
|
||||
use serde::Serializer;
|
||||
|
||||
pub mod json_u256;
|
||||
pub use json_u256::JsonU256;
|
||||
|
||||
/// Helpers for dealing with numbers.
|
||||
pub mod num;
|
||||
pub use num::*;
|
||||
|
||||
/// Storage related helpers.
|
||||
pub mod storage;
|
||||
pub use storage::JsonStorageKey;
|
||||
|
||||
/// Serialize a byte vec as a hex string _without_ the "0x" prefix.
|
||||
///
|
||||
/// This behaves the same as [`hex::encode`](alloy_primitives::hex::encode).
|
||||
pub fn serialize_hex_string_no_prefix<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
s.serialize_str(&alloy_primitives::hex::encode(x.as_ref()))
|
||||
}
|
||||
|
||||
/// Serialize a [B256] as a hex string _without_ the "0x" prefix.
|
||||
pub fn serialize_b256_hex_string_no_prefix<S>(x: &B256, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
s.serialize_str(&format!("{x:x}"))
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
//! Numeric serde helpers.
|
||||
|
||||
use alloy_primitives::{U256, U64};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// A `u64` wrapper type that deserializes from hex or a u64 and serializes as hex.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// use reth_rpc_types::num::U64HexOrNumber;
|
||||
/// let number_json = "100";
|
||||
/// let hex_json = "\"0x64\"";
|
||||
///
|
||||
/// let number: U64HexOrNumber = serde_json::from_str(number_json).unwrap();
|
||||
/// let hex: U64HexOrNumber = serde_json::from_str(hex_json).unwrap();
|
||||
/// assert_eq!(number, hex);
|
||||
/// assert_eq!(hex.to(), 100);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
pub struct U64HexOrNumber(U64);
|
||||
|
||||
impl U64HexOrNumber {
|
||||
/// Returns the wrapped u64
|
||||
pub fn to(self) -> u64 {
|
||||
self.0.to()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for U64HexOrNumber {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(U64::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U64> for U64HexOrNumber {
|
||||
fn from(value: U64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U64HexOrNumber> for u64 {
|
||||
fn from(value: U64HexOrNumber) -> Self {
|
||||
value.to()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U64HexOrNumber> for U64 {
|
||||
fn from(value: U64HexOrNumber) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for U64HexOrNumber {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum NumberOrHexU64 {
|
||||
Hex(U64),
|
||||
Int(u64),
|
||||
}
|
||||
match NumberOrHexU64::deserialize(deserializer)? {
|
||||
NumberOrHexU64::Int(val) => Ok(val.into()),
|
||||
NumberOrHexU64::Hex(val) => Ok(val.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// serde functions for handling `u64` as [U64]
|
||||
pub mod u64_hex {
|
||||
use alloy_primitives::U64;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
/// Deserializes an `u64` from [U64] accepting a hex quantity string with optional 0x prefix
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
U64::deserialize(deserializer).map(|val| val.to())
|
||||
}
|
||||
|
||||
/// Serializes u64 as hex string
|
||||
pub fn serialize<S: Serializer>(value: &u64, s: S) -> Result<S::Ok, S::Error> {
|
||||
U64::from(*value).serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// serde functions for handling `Option<u64>` as [U64]
|
||||
pub mod u64_hex_opt {
|
||||
use alloy_primitives::U64;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
/// Serializes u64 as hex string
|
||||
pub fn serialize<S: Serializer>(value: &Option<u64>, s: S) -> Result<S::Ok, S::Error> {
|
||||
match value {
|
||||
Some(val) => U64::from(*val).serialize(s),
|
||||
None => s.serialize_none(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes an `Option` from [U64] accepting a hex quantity string with optional 0x prefix
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(U64::deserialize(deserializer)
|
||||
.map_or(None, |v| Some(u64::from_be_bytes(v.to_be_bytes()))))
|
||||
}
|
||||
}
|
||||
|
||||
/// serde functions for handling primitive `u64` as [U64]
|
||||
pub mod u64_hex_or_decimal {
|
||||
use crate::serde_helpers::num::U64HexOrNumber;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
/// Deserializes an `u64` accepting a hex quantity string with optional 0x prefix or
|
||||
/// a number
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
U64HexOrNumber::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
|
||||
/// Serializes u64 as hex string
|
||||
pub fn serialize<S: Serializer>(value: &u64, s: S) -> Result<S::Ok, S::Error> {
|
||||
U64HexOrNumber::from(*value).serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// serde functions for handling primitive optional `u64` as [U64]
|
||||
pub mod u64_hex_or_decimal_opt {
|
||||
use crate::serde_helpers::num::U64HexOrNumber;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
/// Deserializes an `u64` accepting a hex quantity string with optional 0x prefix or
|
||||
/// a number
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match Option::<U64HexOrNumber>::deserialize(deserializer)? {
|
||||
Some(val) => Ok(Some(val.into())),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes u64 as hex string
|
||||
pub fn serialize<S: Serializer>(value: &Option<u64>, s: S) -> Result<S::Ok, S::Error> {
|
||||
match value {
|
||||
Some(val) => U64HexOrNumber::from(*val).serialize(s),
|
||||
None => s.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes the input into an `Option<U256>`, using [`from_int_or_hex`] to deserialize the
|
||||
/// inner value.
|
||||
pub fn from_int_or_hex_opt<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
match Option::<NumberOrHexU256>::deserialize(deserializer)? {
|
||||
Some(val) => val.try_into_u256().map(Some),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// An enum that represents either a [serde_json::Number] integer, or a hex [U256].
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum NumberOrHexU256 {
|
||||
/// An integer
|
||||
Int(serde_json::Number),
|
||||
/// A hex U256
|
||||
Hex(U256),
|
||||
}
|
||||
|
||||
impl NumberOrHexU256 {
|
||||
/// Tries to convert this into a [U256]].
|
||||
pub fn try_into_u256<E: de::Error>(self) -> Result<U256, E> {
|
||||
match self {
|
||||
NumberOrHexU256::Int(num) => {
|
||||
U256::from_str(num.to_string().as_str()).map_err(E::custom)
|
||||
}
|
||||
NumberOrHexU256::Hex(val) => Ok(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes the input into a U256, accepting both 0x-prefixed hex and decimal strings with
|
||||
/// arbitrary precision, defined by serde_json's [`Number`](serde_json::Number).
|
||||
pub fn from_int_or_hex<'de, D>(deserializer: D) -> Result<U256, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
NumberOrHexU256::deserialize(deserializer)?.try_into_u256()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[test]
|
||||
fn test_hex_u64() {
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
struct Value {
|
||||
#[serde(with = "u64_hex")]
|
||||
inner: u64,
|
||||
}
|
||||
|
||||
let val = Value { inner: 1000 };
|
||||
let s = serde_json::to_string(&val).unwrap();
|
||||
assert_eq!(s, "{\"inner\":\"0x3e8\"}");
|
||||
|
||||
let deserialized: Value = serde_json::from_str(&s).unwrap();
|
||||
assert_eq!(val, deserialized);
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
use alloy_primitives::{Bytes, B256, U256};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::{collections::HashMap, fmt::Write};
|
||||
|
||||
/// A storage key type that can be serialized to and from a hex string up to 32 bytes. Used for
|
||||
/// `eth_getStorageAt` and `eth_getProof` RPCs.
|
||||
///
|
||||
/// This is a wrapper type meant to mirror geth's serialization and deserialization behavior for
|
||||
/// storage keys.
|
||||
///
|
||||
/// In `eth_getStorageAt`, this is used for deserialization of the `index` field. Internally, the
|
||||
/// index is a [B256], but in `eth_getStorageAt` requests, its serialization can be _up to_ 32
|
||||
/// bytes. To support this, the storage key is deserialized first as a U256, and converted to a
|
||||
/// B256 for use internally.
|
||||
///
|
||||
/// `eth_getProof` also takes storage keys up to 32 bytes as input, so the `keys` field is
|
||||
/// similarly deserialized. However, geth populates the storage proof `key` fields in the response
|
||||
/// by mirroring the `key` field used in the input.
|
||||
/// * See how `storageKey`s (the input) are populated in the `StorageResult` (the output):
|
||||
/// <https://github.com/ethereum/go-ethereum/blob/00a73fbcce3250b87fc4160f3deddc44390848f4/internal/ethapi/api.go#L658-L690>
|
||||
///
|
||||
/// The contained [B256] and From implementation for String are used to preserve the input and
|
||||
/// implement this behavior from geth.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(from = "U256", into = "String")]
|
||||
pub struct JsonStorageKey(pub B256);
|
||||
|
||||
impl From<U256> for JsonStorageKey {
|
||||
fn from(value: U256) -> Self {
|
||||
// SAFETY: Address (B256) and U256 have the same number of bytes
|
||||
JsonStorageKey(B256::from(value.to_be_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsonStorageKey> for String {
|
||||
fn from(value: JsonStorageKey) -> Self {
|
||||
// SAFETY: Address (B256) and U256 have the same number of bytes
|
||||
let uint = U256::from_be_bytes(value.0 .0);
|
||||
|
||||
// serialize byte by byte
|
||||
//
|
||||
// this is mainly so we can return an output that hive testing expects, because the
|
||||
// `eth_getProof` implementation in geth simply mirrors the input
|
||||
//
|
||||
// see the use of `hexKey` in the `eth_getProof` response:
|
||||
// <https://github.com/ethereum/go-ethereum/blob/00a73fbcce3250b87fc4160f3deddc44390848f4/internal/ethapi/api.go#L658-L690>
|
||||
let bytes = uint.to_be_bytes_trimmed_vec();
|
||||
let mut hex = String::with_capacity(2 + bytes.len() * 2);
|
||||
hex.push_str("0x");
|
||||
for byte in bytes {
|
||||
write!(hex, "{:02x}", byte).unwrap();
|
||||
}
|
||||
hex
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a Bytes value into a B256, accepting inputs that are less than 32 bytes long. These
|
||||
/// inputs will be left padded with zeros.
|
||||
pub fn from_bytes_to_b256<'de, D>(bytes: Bytes) -> Result<B256, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if bytes.0.len() > 32 {
|
||||
return Err(serde::de::Error::custom("input too long to be a B256"))
|
||||
}
|
||||
|
||||
// left pad with zeros to 32 bytes
|
||||
let mut padded = [0u8; 32];
|
||||
padded[32 - bytes.0.len()..].copy_from_slice(&bytes.0);
|
||||
|
||||
// then convert to B256 without a panic
|
||||
Ok(B256::from_slice(&padded))
|
||||
}
|
||||
|
||||
/// Deserializes the input into an Option<HashMap<B256, B256>>, using [from_bytes_to_b256] which
|
||||
/// allows cropped values:
|
||||
///
|
||||
/// ```json
|
||||
/// {
|
||||
/// "0x0000000000000000000000000000000000000000000000000000000000000001": "0x22"
|
||||
/// }
|
||||
/// ```
|
||||
pub fn deserialize_storage_map<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<HashMap<B256, B256>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let map = Option::<HashMap<Bytes, Bytes>>::deserialize(deserializer)?;
|
||||
match map {
|
||||
Some(mut map) => {
|
||||
let mut res_map = HashMap::with_capacity(map.len());
|
||||
for (k, v) in map.drain() {
|
||||
let k_deserialized = from_bytes_to_b256::<'de, D>(k)?;
|
||||
let v_deserialized = from_bytes_to_b256::<'de, D>(v)?;
|
||||
res_map.insert(k_deserialized, v_deserialized);
|
||||
}
|
||||
Ok(Some(res_map))
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user