mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-20 21:34:46 +00:00
Split common crates out into their own repos (#3890)
## Proposed Changes Split out several crates which now exist in separate repos under `sigp`. - [`ssz` and `ssz_derive`](https://github.com/sigp/ethereum_ssz) - [`tree_hash` and `tree_hash_derive`](https://github.com/sigp/tree_hash) - [`ethereum_hashing`](https://github.com/sigp/ethereum_hashing) - [`ethereum_serde_utils`](https://github.com/sigp/ethereum_serde_utils) - [`ssz_types`](https://github.com/sigp/ssz_types) For the published crates see: https://crates.io/teams/github:sigp:crates-io?sort=recent-updates. ## Additional Info - [x] Need to work out how to handle versioning. I was hoping to do 1.0 versions of several crates, but if they depend on `ethereum-types 0.x` that is not going to work. EDIT: decided to go with 0.5.x versions. - [x] Need to port several changes from `tree-states`, `capella`, `eip4844` branches to the external repos.
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
//! Formats `[u8; n]` as a 0x-prefixed hex string.
|
||||
//!
|
||||
//! E.g., `[0, 1, 2, 3]` serializes as `"0x00010203"`.
|
||||
|
||||
use crate::hex::PrefixedHexVisitor;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
macro_rules! bytes_hex {
|
||||
($num_bytes: tt) => {
|
||||
use super::*;
|
||||
|
||||
const BYTES_LEN: usize = $num_bytes;
|
||||
|
||||
pub fn serialize<S>(bytes: &[u8; BYTES_LEN], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut hex_string: String = "0x".to_string();
|
||||
hex_string.push_str(&hex::encode(&bytes));
|
||||
|
||||
serializer.serialize_str(&hex_string)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; BYTES_LEN], D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let decoded = deserializer.deserialize_str(PrefixedHexVisitor)?;
|
||||
|
||||
if decoded.len() != BYTES_LEN {
|
||||
return Err(D::Error::custom(format!(
|
||||
"expected {} bytes for array, got {}",
|
||||
BYTES_LEN,
|
||||
decoded.len()
|
||||
)));
|
||||
}
|
||||
|
||||
let mut array = [0; BYTES_LEN];
|
||||
array.copy_from_slice(&decoded);
|
||||
Ok(array)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod bytes_4_hex {
|
||||
bytes_hex!(4);
|
||||
}
|
||||
|
||||
pub mod bytes_8_hex {
|
||||
bytes_hex!(8);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
//! Provides utilities for parsing 0x-prefixed hex strings.
|
||||
|
||||
use serde::de::{self, Visitor};
|
||||
use std::fmt;
|
||||
|
||||
/// Encode `data` as a 0x-prefixed hex string.
|
||||
pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
|
||||
let hex = hex::encode(data);
|
||||
|
||||
let mut s = "0x".to_string();
|
||||
s.push_str(hex.as_str());
|
||||
s
|
||||
}
|
||||
|
||||
/// Decode `data` from a 0x-prefixed hex string.
|
||||
pub fn decode(s: &str) -> Result<Vec<u8>, String> {
|
||||
if let Some(stripped) = s.strip_prefix("0x") {
|
||||
hex::decode(stripped).map_err(|e| format!("invalid hex: {:?}", e))
|
||||
} else {
|
||||
Err("hex must have 0x prefix".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrefixedHexVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for PrefixedHexVisitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a hex string with 0x prefix")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
decode(value).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HexVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for HexVisitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a hex string (irrelevant of prefix)")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
hex::decode(value.trim_start_matches("0x"))
|
||||
.map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn encoding() {
|
||||
let bytes = vec![0, 255];
|
||||
let hex = encode(bytes);
|
||||
assert_eq!(hex.as_str(), "0x00ff");
|
||||
|
||||
let bytes = vec![];
|
||||
let hex = encode(bytes);
|
||||
assert_eq!(hex.as_str(), "0x");
|
||||
|
||||
let bytes = vec![1, 2, 3];
|
||||
let hex = encode(bytes);
|
||||
assert_eq!(hex.as_str(), "0x010203");
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
//! Formats `Vec<u8>` as a 0x-prefixed hex string.
|
||||
//!
|
||||
//! E.g., `vec![0, 1, 2, 3]` serializes as `"0x00010203"`.
|
||||
|
||||
use crate::hex::PrefixedHexVisitor;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut hex_string: String = "0x".to_string();
|
||||
hex_string.push_str(&hex::encode(bytes));
|
||||
|
||||
serializer.serialize_str(&hex_string)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_str(PrefixedHexVisitor)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//! Serialize a datatype as a JSON-blob within a single string.
|
||||
use serde::{
|
||||
de::{DeserializeOwned, Error as _},
|
||||
ser::Error as _,
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
/// Serialize as a JSON object within a string.
|
||||
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
T: Serialize,
|
||||
{
|
||||
serializer.serialize_str(&serde_json::to_string(value).map_err(S::Error::custom)?)
|
||||
}
|
||||
|
||||
/// Deserialize a JSON object embedded in a string.
|
||||
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let json_str = String::deserialize(deserializer)?;
|
||||
serde_json::from_str(&json_str).map_err(D::Error::custom)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
mod quoted_int;
|
||||
|
||||
pub mod fixed_bytes_hex;
|
||||
pub mod hex;
|
||||
pub mod hex_vec;
|
||||
pub mod json_str;
|
||||
pub mod list_of_bytes_lists;
|
||||
pub mod quoted_u64_vec;
|
||||
pub mod u256_hex_be;
|
||||
pub mod u32_hex;
|
||||
pub mod u64_hex_be;
|
||||
pub mod u8_hex;
|
||||
|
||||
pub use fixed_bytes_hex::{bytes_4_hex, bytes_8_hex};
|
||||
pub use quoted_int::{quoted_i64, quoted_u256, quoted_u32, quoted_u64, quoted_u8};
|
||||
@@ -1,49 +0,0 @@
|
||||
//! Formats `Vec<u64>` using quotes.
|
||||
//!
|
||||
//! E.g., `vec![0, 1, 2]` serializes as `["0", "1", "2"]`.
|
||||
//!
|
||||
//! Quotes can be optional during decoding.
|
||||
|
||||
use crate::hex;
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{de, Deserializer, Serializer};
|
||||
|
||||
pub struct ListOfBytesListVisitor;
|
||||
impl<'a> serde::de::Visitor<'a> for ListOfBytesListVisitor {
|
||||
type Value = Vec<Vec<u8>>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "a list of 0x-prefixed byte lists")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'a>,
|
||||
{
|
||||
let mut vec = vec![];
|
||||
|
||||
while let Some(val) = seq.next_element::<String>()? {
|
||||
vec.push(hex::decode(&val).map_err(de::Error::custom)?);
|
||||
}
|
||||
|
||||
Ok(vec)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S>(value: &[Vec<u8>], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(value.len()))?;
|
||||
for val in value {
|
||||
seq.serialize_element(&hex::encode(val))?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(ListOfBytesListVisitor)
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
//! Formats some integer types using quotes.
|
||||
//!
|
||||
//! E.g., `1` serializes as `"1"`.
|
||||
//!
|
||||
//! Quotes can be optional during decoding.
|
||||
|
||||
use ethereum_types::U256;
|
||||
use serde::{Deserializer, Serializer};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
macro_rules! define_mod {
|
||||
($int: ty) => {
|
||||
/// Serde support for deserializing quoted integers.
|
||||
///
|
||||
/// Configurable so that quotes are either required or optional.
|
||||
pub struct QuotedIntVisitor<T> {
|
||||
require_quotes: bool,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> serde::de::Visitor<'a> for QuotedIntVisitor<T>
|
||||
where
|
||||
T: From<$int> + Into<$int> + Copy + TryFrom<u64>,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
if self.require_quotes {
|
||||
write!(formatter, "a quoted integer")
|
||||
} else {
|
||||
write!(formatter, "a quoted or unquoted integer")
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
s.parse::<$int>()
|
||||
.map(T::from)
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if self.require_quotes {
|
||||
Err(serde::de::Error::custom(
|
||||
"received unquoted integer when quotes are required",
|
||||
))
|
||||
} else {
|
||||
T::try_from(v).map_err(|_| serde::de::Error::custom("invalid integer"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compositional wrapper type that allows quotes or no quotes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct MaybeQuoted<T>
|
||||
where
|
||||
T: From<$int> + Into<$int> + Copy + TryFrom<u64>,
|
||||
{
|
||||
#[serde(with = "self")]
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// Wrapper type for requiring quotes on a `$int`-like type.
|
||||
///
|
||||
/// Unlike using `serde(with = "quoted_$int::require_quotes")` this is composable, and can be nested
|
||||
/// inside types like `Option`, `Result` and `Vec`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Quoted<T>
|
||||
where
|
||||
T: From<$int> + Into<$int> + Copy + TryFrom<u64>,
|
||||
{
|
||||
#[serde(with = "require_quotes")]
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// Serialize with quotes.
|
||||
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
T: From<$int> + Into<$int> + Copy,
|
||||
{
|
||||
let v: $int = (*value).into();
|
||||
serializer.serialize_str(&format!("{}", v))
|
||||
}
|
||||
|
||||
/// Deserialize with or without quotes.
|
||||
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: From<$int> + Into<$int> + Copy + TryFrom<u64>,
|
||||
{
|
||||
deserializer.deserialize_any(QuotedIntVisitor {
|
||||
require_quotes: false,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Requires quotes when deserializing.
|
||||
///
|
||||
/// Usage: `#[serde(with = "quoted_u64::require_quotes")]`.
|
||||
pub mod require_quotes {
|
||||
pub use super::serialize;
|
||||
use super::*;
|
||||
|
||||
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: From<$int> + Into<$int> + Copy + TryFrom<u64>,
|
||||
{
|
||||
deserializer.deserialize_any(QuotedIntVisitor {
|
||||
require_quotes: true,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn require_quotes() {
|
||||
let x = serde_json::from_str::<Quoted<$int>>("\"8\"").unwrap();
|
||||
assert_eq!(x.value, 8);
|
||||
serde_json::from_str::<Quoted<$int>>("8").unwrap_err();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod quoted_u8 {
|
||||
use super::*;
|
||||
|
||||
define_mod!(u8);
|
||||
}
|
||||
|
||||
pub mod quoted_u32 {
|
||||
use super::*;
|
||||
|
||||
define_mod!(u32);
|
||||
}
|
||||
|
||||
pub mod quoted_u64 {
|
||||
use super::*;
|
||||
|
||||
define_mod!(u64);
|
||||
}
|
||||
|
||||
pub mod quoted_i64 {
|
||||
use super::*;
|
||||
|
||||
define_mod!(i64);
|
||||
}
|
||||
|
||||
pub mod quoted_u256 {
|
||||
use super::*;
|
||||
|
||||
struct U256Visitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for U256Visitor {
|
||||
type Value = U256;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a quoted U256 integer")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
U256::from_dec_str(v).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize with quotes.
|
||||
pub fn serialize<S>(value: &U256, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&format!("{}", value))
|
||||
}
|
||||
|
||||
/// Deserialize with quotes.
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<U256, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_str(U256Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct WrappedU256(#[serde(with = "quoted_u256")] U256);
|
||||
|
||||
#[test]
|
||||
fn u256_with_quotes() {
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&WrappedU256(U256::one())).unwrap(),
|
||||
"\"1\""
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<WrappedU256>("\"1\"").unwrap(),
|
||||
WrappedU256(U256::one())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u256_without_quotes() {
|
||||
serde_json::from_str::<WrappedU256>("1").unwrap_err();
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct WrappedI64(#[serde(with = "quoted_i64")] i64);
|
||||
|
||||
#[test]
|
||||
fn negative_i64_with_quotes() {
|
||||
assert_eq!(
|
||||
serde_json::from_str::<WrappedI64>("\"-200\"").unwrap().0,
|
||||
-200
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&WrappedI64(-12_500)).unwrap(),
|
||||
"\"-12500\""
|
||||
);
|
||||
}
|
||||
|
||||
// It would be OK if this worked, but we don't need it to (i64s should always be quoted).
|
||||
#[test]
|
||||
fn negative_i64_without_quotes() {
|
||||
serde_json::from_str::<WrappedI64>("-200").unwrap_err();
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
//! Formats `Vec<u64>` using quotes.
|
||||
//!
|
||||
//! E.g., `vec![0, 1, 2]` serializes as `["0", "1", "2"]`.
|
||||
//!
|
||||
//! Quotes can be optional during decoding.
|
||||
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{Deserializer, Serializer};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct QuotedIntWrapper {
|
||||
#[serde(with = "crate::quoted_u64")]
|
||||
pub int: u64,
|
||||
}
|
||||
|
||||
pub struct QuotedIntVecVisitor;
|
||||
impl<'a> serde::de::Visitor<'a> for QuotedIntVecVisitor {
|
||||
type Value = Vec<u64>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "a list of quoted or unquoted integers")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'a>,
|
||||
{
|
||||
let mut vec = vec![];
|
||||
|
||||
while let Some(val) = seq.next_element()? {
|
||||
let val: QuotedIntWrapper = val;
|
||||
vec.push(val.int);
|
||||
}
|
||||
|
||||
Ok(vec)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S>(value: &[u64], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(value.len()))?;
|
||||
for &int in value {
|
||||
seq.serialize_element(&QuotedIntWrapper { int })?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u64>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(QuotedIntVecVisitor)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Obj {
|
||||
#[serde(with = "crate::quoted_u64_vec")]
|
||||
values: Vec<u64>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quoted_list_success() {
|
||||
let obj: Obj = serde_json::from_str(r#"{ "values": ["1", "2", "3", "4"] }"#).unwrap();
|
||||
assert_eq!(obj.values, vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unquoted_list_success() {
|
||||
let obj: Obj = serde_json::from_str(r#"{ "values": [1, 2, 3, 4] }"#).unwrap();
|
||||
assert_eq!(obj.values, vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_list_success() {
|
||||
let obj: Obj = serde_json::from_str(r#"{ "values": ["1", 2, "3", "4"] }"#).unwrap();
|
||||
assert_eq!(obj.values, vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_list_success() {
|
||||
let obj: Obj = serde_json::from_str(r#"{ "values": [] }"#).unwrap();
|
||||
assert!(obj.values.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whole_list_quoted_err() {
|
||||
serde_json::from_str::<Obj>(r#"{ "values": "[1, 2, 3, 4]" }"#).unwrap_err();
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
use ethereum_types::U256;
|
||||
|
||||
use serde::de::Visitor;
|
||||
use serde::{de, Deserializer, Serialize, Serializer};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn serialize<S>(num: &U256, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
num.serialize(serializer)
|
||||
}
|
||||
|
||||
pub struct U256Visitor;
|
||||
|
||||
impl<'de> Visitor<'de> for U256Visitor {
|
||||
type Value = String;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a well formatted hex string")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
if !value.starts_with("0x") {
|
||||
return Err(de::Error::custom("must start with 0x"));
|
||||
}
|
||||
let stripped = &value[2..];
|
||||
if stripped.is_empty() {
|
||||
Err(de::Error::custom(format!(
|
||||
"quantity cannot be {:?}",
|
||||
stripped
|
||||
)))
|
||||
} else if stripped == "0" {
|
||||
Ok(value.to_string())
|
||||
} else if stripped.starts_with('0') {
|
||||
Err(de::Error::custom("cannot have leading zero"))
|
||||
} else {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<U256, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let decoded = deserializer.deserialize_string(U256Visitor)?;
|
||||
|
||||
U256::from_str(&decoded).map_err(|e| de::Error::custom(format!("Invalid U256 string: {}", e)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use ethereum_types::U256;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct Wrapper {
|
||||
#[serde(with = "super")]
|
||||
val: U256,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoding() {
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 0.into() }).unwrap(),
|
||||
"\"0x0\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 1.into() }).unwrap(),
|
||||
"\"0x1\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 256.into() }).unwrap(),
|
||||
"\"0x100\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 65.into() }).unwrap(),
|
||||
"\"0x41\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 1024.into() }).unwrap(),
|
||||
"\"0x400\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper {
|
||||
val: U256::max_value() - 1
|
||||
})
|
||||
.unwrap(),
|
||||
"\"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper {
|
||||
val: U256::max_value()
|
||||
})
|
||||
.unwrap(),
|
||||
"\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\""
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding() {
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>("\"0x0\"").unwrap(),
|
||||
Wrapper { val: 0.into() },
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>("\"0x41\"").unwrap(),
|
||||
Wrapper { val: 65.into() },
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>("\"0x400\"").unwrap(),
|
||||
Wrapper { val: 1024.into() },
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>(
|
||||
"\"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe\""
|
||||
)
|
||||
.unwrap(),
|
||||
Wrapper {
|
||||
val: U256::max_value() - 1
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>(
|
||||
"\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\""
|
||||
)
|
||||
.unwrap(),
|
||||
Wrapper {
|
||||
val: U256::max_value()
|
||||
},
|
||||
);
|
||||
serde_json::from_str::<Wrapper>("\"0x\"").unwrap_err();
|
||||
serde_json::from_str::<Wrapper>("\"0x0400\"").unwrap_err();
|
||||
serde_json::from_str::<Wrapper>("\"400\"").unwrap_err();
|
||||
serde_json::from_str::<Wrapper>("\"ff\"").unwrap_err();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
//! Formats `u32` as a 0x-prefixed, little-endian hex string.
|
||||
//!
|
||||
//! E.g., `0` serializes as `"0x00000000"`.
|
||||
|
||||
use crate::bytes_4_hex;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S>(num: &u32, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let hex = format!("0x{}", hex::encode(num.to_le_bytes()));
|
||||
serializer.serialize_str(&hex)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
bytes_4_hex::deserialize(deserializer).map(u32::from_le_bytes)
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
//! Formats `u64` as a 0x-prefixed, big-endian hex string.
|
||||
//!
|
||||
//! E.g., `0` serializes as `"0x0000000000000000"`.
|
||||
|
||||
use serde::de::{self, Error, Visitor};
|
||||
use serde::{Deserializer, Serializer};
|
||||
use std::fmt;
|
||||
|
||||
const BYTES_LEN: usize = 8;
|
||||
|
||||
pub struct QuantityVisitor;
|
||||
impl<'de> Visitor<'de> for QuantityVisitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a hex string")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
if !value.starts_with("0x") {
|
||||
return Err(de::Error::custom("must start with 0x"));
|
||||
}
|
||||
|
||||
let stripped = value.trim_start_matches("0x");
|
||||
|
||||
if stripped.is_empty() {
|
||||
Err(de::Error::custom(format!(
|
||||
"quantity cannot be {}",
|
||||
stripped
|
||||
)))
|
||||
} else if stripped == "0" {
|
||||
Ok(vec![0])
|
||||
} else if stripped.starts_with('0') {
|
||||
Err(de::Error::custom("cannot have leading zero"))
|
||||
} else if stripped.len() % 2 != 0 {
|
||||
hex::decode(format!("0{}", stripped))
|
||||
.map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))
|
||||
} else {
|
||||
hex::decode(stripped).map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S>(num: &u64, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let raw = hex::encode(num.to_be_bytes());
|
||||
let trimmed = raw.trim_start_matches('0');
|
||||
|
||||
let hex = if trimmed.is_empty() { "0" } else { trimmed };
|
||||
|
||||
serializer.serialize_str(&format!("0x{}", &hex))
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let decoded = deserializer.deserialize_str(QuantityVisitor)?;
|
||||
|
||||
// TODO: this is not strict about byte length like other methods.
|
||||
if decoded.len() > BYTES_LEN {
|
||||
return Err(D::Error::custom(format!(
|
||||
"expected max {} bytes for array, got {}",
|
||||
BYTES_LEN,
|
||||
decoded.len()
|
||||
)));
|
||||
}
|
||||
|
||||
let mut array = [0; BYTES_LEN];
|
||||
array[BYTES_LEN - decoded.len()..].copy_from_slice(&decoded);
|
||||
Ok(u64::from_be_bytes(array))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct Wrapper {
|
||||
#[serde(with = "super")]
|
||||
val: u64,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoding() {
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 0 }).unwrap(),
|
||||
"\"0x0\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 1 }).unwrap(),
|
||||
"\"0x1\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 256 }).unwrap(),
|
||||
"\"0x100\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 65 }).unwrap(),
|
||||
"\"0x41\""
|
||||
);
|
||||
assert_eq!(
|
||||
&serde_json::to_string(&Wrapper { val: 1024 }).unwrap(),
|
||||
"\"0x400\""
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding() {
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>("\"0x0\"").unwrap(),
|
||||
Wrapper { val: 0 },
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>("\"0x41\"").unwrap(),
|
||||
Wrapper { val: 65 },
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Wrapper>("\"0x400\"").unwrap(),
|
||||
Wrapper { val: 1024 },
|
||||
);
|
||||
serde_json::from_str::<Wrapper>("\"0x\"").unwrap_err();
|
||||
serde_json::from_str::<Wrapper>("\"0x0400\"").unwrap_err();
|
||||
serde_json::from_str::<Wrapper>("\"400\"").unwrap_err();
|
||||
serde_json::from_str::<Wrapper>("\"ff\"").unwrap_err();
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//! Formats `u8` as a 0x-prefixed hex string.
|
||||
//!
|
||||
//! E.g., `0` serializes as `"0x00"`.
|
||||
|
||||
use crate::hex::PrefixedHexVisitor;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S>(byte: &u8, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let hex = format!("0x{}", hex::encode([*byte]));
|
||||
serializer.serialize_str(&hex)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<u8, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?;
|
||||
if bytes.len() != 1 {
|
||||
return Err(D::Error::custom(format!(
|
||||
"expected 1 byte for u8, got {}",
|
||||
bytes.len()
|
||||
)));
|
||||
}
|
||||
Ok(bytes[0])
|
||||
}
|
||||
Reference in New Issue
Block a user