mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(exex, primitives): serde bincode compatibility (#11331)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -13,7 +13,8 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-provider.workspace = true
|
||||
reth-chain-state.workspace = true
|
||||
reth-execution-types.workspace = true
|
||||
|
||||
# reth
|
||||
alloy-primitives.workspace = true
|
||||
@ -21,7 +22,16 @@ alloy-eips.workspace = true
|
||||
|
||||
# misc
|
||||
serde = { workspace = true, optional = true }
|
||||
serde_with = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
reth-primitives = { workspace = true, features = ["arbitrary"] }
|
||||
|
||||
arbitrary.workspace = true
|
||||
bincode.workspace = true
|
||||
rand.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serde = ["dep:serde", "reth-provider/serde"]
|
||||
serde = ["dep:serde", "reth-execution-types/serde"]
|
||||
serde-bincode-compat = ["reth-execution-types/serde-bincode-compat", "serde_with"]
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
//! Commonly used types for exex usage.
|
||||
//! Commonly used ExEx types.
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
@ -15,3 +15,15 @@ mod notification;
|
||||
pub use finished_height::FinishedExExHeight;
|
||||
pub use head::ExExHead;
|
||||
pub use notification::ExExNotification;
|
||||
|
||||
/// Bincode-compatible serde implementations for commonly used ExEx types.
|
||||
///
|
||||
/// `bincode` crate doesn't work with optionally serializable serde fields, but some of the
|
||||
/// ExEx types require optional serialization for RPC compatibility. This module makes so that
|
||||
/// all fields are serialized.
|
||||
///
|
||||
/// Read more: <https://github.com/bincode-org/bincode/issues/326>
|
||||
#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
|
||||
pub mod serde_bincode_compat {
|
||||
pub use super::notification::serde_bincode_compat::*;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use reth_provider::{CanonStateNotification, Chain};
|
||||
use reth_chain_state::CanonStateNotification;
|
||||
use reth_execution_types::Chain;
|
||||
|
||||
/// Notifications sent to an `ExEx`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -67,3 +68,143 @@ impl From<CanonStateNotification> for ExExNotification {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Bincode-compatible [`ExExNotification`] serde implementation.
|
||||
#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
|
||||
pub(super) mod serde_bincode_compat {
|
||||
use std::sync::Arc;
|
||||
|
||||
use reth_execution_types::serde_bincode_compat::Chain;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_with::{DeserializeAs, SerializeAs};
|
||||
|
||||
/// Bincode-compatible [`super::ExExNotification`] serde implementation.
|
||||
///
|
||||
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
|
||||
/// ```rust
|
||||
/// use reth_exex_types::{serde_bincode_compat, ExExNotification};
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use serde_with::serde_as;
|
||||
///
|
||||
/// #[serde_as]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Data {
|
||||
/// #[serde_as(as = "serde_bincode_compat::ExExNotification")]
|
||||
/// notification: ExExNotification,
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ExExNotification<'a> {
|
||||
ChainCommitted { new: Chain<'a> },
|
||||
ChainReorged { old: Chain<'a>, new: Chain<'a> },
|
||||
ChainReverted { old: Chain<'a> },
|
||||
}
|
||||
|
||||
impl<'a> From<&'a super::ExExNotification> for ExExNotification<'a> {
|
||||
fn from(value: &'a super::ExExNotification) -> Self {
|
||||
match value {
|
||||
super::ExExNotification::ChainCommitted { new } => {
|
||||
ExExNotification::ChainCommitted { new: Chain::from(new.as_ref()) }
|
||||
}
|
||||
super::ExExNotification::ChainReorged { old, new } => {
|
||||
ExExNotification::ChainReorged {
|
||||
old: Chain::from(old.as_ref()),
|
||||
new: Chain::from(new.as_ref()),
|
||||
}
|
||||
}
|
||||
super::ExExNotification::ChainReverted { old } => {
|
||||
ExExNotification::ChainReverted { old: Chain::from(old.as_ref()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ExExNotification<'a>> for super::ExExNotification {
|
||||
fn from(value: ExExNotification<'a>) -> Self {
|
||||
match value {
|
||||
ExExNotification::ChainCommitted { new } => {
|
||||
Self::ChainCommitted { new: Arc::new(new.into()) }
|
||||
}
|
||||
ExExNotification::ChainReorged { old, new } => {
|
||||
Self::ChainReorged { old: Arc::new(old.into()), new: Arc::new(new.into()) }
|
||||
}
|
||||
ExExNotification::ChainReverted { old } => {
|
||||
Self::ChainReverted { old: Arc::new(old.into()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeAs<super::ExExNotification> for ExExNotification<'a> {
|
||||
fn serialize_as<S>(
|
||||
source: &super::ExExNotification,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
ExExNotification::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::ExExNotification> for ExExNotification<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::ExExNotification, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
ExExNotification::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use arbitrary::Arbitrary;
|
||||
use rand::Rng;
|
||||
use reth_execution_types::Chain;
|
||||
use reth_primitives::SealedBlockWithSenders;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
|
||||
use super::super::{serde_bincode_compat, ExExNotification};
|
||||
|
||||
#[test]
|
||||
fn test_exex_notification_bincode_roundtrip() {
|
||||
#[serde_as]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Data {
|
||||
#[serde_as(as = "serde_bincode_compat::ExExNotification")]
|
||||
notification: ExExNotification,
|
||||
}
|
||||
|
||||
let mut bytes = [0u8; 1024];
|
||||
rand::thread_rng().fill(bytes.as_mut_slice());
|
||||
let data = Data {
|
||||
notification: ExExNotification::ChainReorged {
|
||||
old: Arc::new(Chain::new(
|
||||
vec![SealedBlockWithSenders::arbitrary(&mut arbitrary::Unstructured::new(
|
||||
&bytes,
|
||||
))
|
||||
.unwrap()],
|
||||
Default::default(),
|
||||
None,
|
||||
)),
|
||||
new: Arc::new(Chain::new(
|
||||
vec![SealedBlockWithSenders::arbitrary(&mut arbitrary::Unstructured::new(
|
||||
&bytes,
|
||||
))
|
||||
.unwrap()],
|
||||
Default::default(),
|
||||
None,
|
||||
)),
|
||||
},
|
||||
};
|
||||
|
||||
let encoded = bincode::serialize(&data).unwrap();
|
||||
let decoded: Data = bincode::deserialize(&encoded).unwrap();
|
||||
assert_eq!(decoded, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user