mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
User receipt Serdebincodecompat for chain type serde (#14669)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@@ -30,10 +30,12 @@ serde_with = { workspace = true, optional = true }
|
||||
derive_more.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-primitives-traits = { workspace = true, features = ["test-utils", "arbitrary"] }
|
||||
reth-ethereum-primitives = { workspace = true, features = ["arbitrary"] }
|
||||
alloy-primitives = { workspace = true, features = ["rand", "arbitrary"] }
|
||||
arbitrary.workspace = true
|
||||
bincode.workspace = true
|
||||
rand.workspace = true
|
||||
reth-ethereum-primitives.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
||||
@@ -526,7 +526,7 @@ pub enum ChainSplit<N: NodePrimitives = reth_ethereum_primitives::EthPrimitives>
|
||||
/// Bincode-compatible [`Chain`] serde implementation.
|
||||
#[cfg(feature = "serde-bincode-compat")]
|
||||
pub(super) mod serde_bincode_compat {
|
||||
use crate::ExecutionOutcome;
|
||||
use crate::{serde_bincode_compat, ExecutionOutcome};
|
||||
use alloc::borrow::Cow;
|
||||
use alloy_primitives::BlockNumber;
|
||||
use reth_ethereum_primitives::EthPrimitives;
|
||||
@@ -562,7 +562,7 @@ pub(super) mod serde_bincode_compat {
|
||||
>,
|
||||
{
|
||||
blocks: RecoveredBlocks<'a, N::Block>,
|
||||
execution_outcome: Cow<'a, ExecutionOutcome<N::Receipt>>,
|
||||
execution_outcome: serde_bincode_compat::ExecutionOutcome<'a, N::Receipt>,
|
||||
trie_updates: Option<TrieUpdates<'a>>,
|
||||
}
|
||||
|
||||
@@ -615,7 +615,7 @@ pub(super) mod serde_bincode_compat {
|
||||
fn from(value: &'a super::Chain<N>) -> Self {
|
||||
Self {
|
||||
blocks: RecoveredBlocks(Cow::Borrowed(&value.blocks)),
|
||||
execution_outcome: Cow::Borrowed(&value.execution_outcome),
|
||||
execution_outcome: value.execution_outcome.as_repr(),
|
||||
trie_updates: value.trie_updates.as_ref().map(Into::into),
|
||||
}
|
||||
}
|
||||
@@ -630,7 +630,7 @@ pub(super) mod serde_bincode_compat {
|
||||
fn from(value: Chain<'a, N>) -> Self {
|
||||
Self {
|
||||
blocks: value.blocks.0.into_owned(),
|
||||
execution_outcome: value.execution_outcome.into_owned(),
|
||||
execution_outcome: ExecutionOutcome::from_repr(value.execution_outcome),
|
||||
trie_updates: value.trie_updates.map(Into::into),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,16 @@ use reth_trie_common::{HashedPostState, KeyHasher};
|
||||
use revm::state::AccountInfo;
|
||||
use revm_database::{states::BundleState, BundleAccount};
|
||||
|
||||
/// Type used to initialize revms bundle state.
|
||||
pub type BundleStateInit =
|
||||
HashMap<Address, (Option<Account>, Option<Account>, HashMap<B256, (U256, U256)>)>;
|
||||
|
||||
/// Types used inside `RevertsInit` to initialize revms reverts.
|
||||
pub type AccountRevertInit = (Option<Option<Account>>, Vec<StorageEntry>);
|
||||
|
||||
/// Type used to initialize revms reverts.
|
||||
pub type RevertsInit = HashMap<BlockNumber, HashMap<Address, AccountRevertInit>>;
|
||||
|
||||
/// Represents a changed account
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct ChangedAccount {
|
||||
@@ -60,16 +70,6 @@ impl<T> Default for ExecutionOutcome<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type used to initialize revms bundle state.
|
||||
pub type BundleStateInit =
|
||||
HashMap<Address, (Option<Account>, Option<Account>, HashMap<B256, (U256, U256)>)>;
|
||||
|
||||
/// Types used inside `RevertsInit` to initialize revms reverts.
|
||||
pub type AccountRevertInit = (Option<Option<Account>>, Vec<StorageEntry>);
|
||||
|
||||
/// Type used to initialize revms reverts.
|
||||
pub type RevertsInit = HashMap<BlockNumber, HashMap<Address, AccountRevertInit>>;
|
||||
|
||||
impl<T> ExecutionOutcome<T> {
|
||||
/// Creates a new `ExecutionOutcome`.
|
||||
///
|
||||
@@ -399,6 +399,155 @@ impl<T> From<(BlockExecutionOutput<T>, BlockNumber)> for ExecutionOutcome<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-bincode-compat")]
|
||||
pub(super) mod serde_bincode_compat {
|
||||
use alloc::borrow::Cow;
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::BlockNumber;
|
||||
use reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat;
|
||||
use revm_database::BundleState;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_with::{DeserializeAs, SerializeAs};
|
||||
|
||||
/// Bincode-compatible [`super::ExecutionOutcome`] serde implementation.
|
||||
///
|
||||
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
|
||||
/// ```rust
|
||||
/// use reth_execution_types::{serde_bincode_compat, ExecutionOutcome};
|
||||
/// ///
|
||||
/// use reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat;
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use serde_with::serde_as;
|
||||
///
|
||||
/// #[serde_as]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Data<T: SerdeBincodeCompat + core::fmt::Debug> {
|
||||
/// #[serde_as(as = "serde_bincode_compat::ExecutionOutcome<'_, T>")]
|
||||
/// chain: ExecutionOutcome<T>,
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ExecutionOutcome<'a, T>
|
||||
where
|
||||
T: SerdeBincodeCompat + core::fmt::Debug,
|
||||
{
|
||||
bundle: Cow<'a, BundleState>,
|
||||
receipts: Vec<Vec<T::BincodeRepr<'a>>>,
|
||||
first_block: BlockNumber,
|
||||
requests: Cow<'a, Vec<Requests>>,
|
||||
}
|
||||
|
||||
impl<'a, T> From<&'a super::ExecutionOutcome<T>> for ExecutionOutcome<'a, T>
|
||||
where
|
||||
T: SerdeBincodeCompat + core::fmt::Debug,
|
||||
{
|
||||
fn from(value: &'a super::ExecutionOutcome<T>) -> Self {
|
||||
ExecutionOutcome {
|
||||
bundle: Cow::Borrowed(&value.bundle),
|
||||
receipts: value
|
||||
.receipts
|
||||
.iter()
|
||||
.map(|vec| vec.iter().map(|receipt| T::as_repr(receipt)).collect())
|
||||
.collect(),
|
||||
first_block: value.first_block,
|
||||
requests: Cow::Borrowed(&value.requests),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<ExecutionOutcome<'a, T>> for super::ExecutionOutcome<T>
|
||||
where
|
||||
T: SerdeBincodeCompat + core::fmt::Debug,
|
||||
{
|
||||
fn from(value: ExecutionOutcome<'a, T>) -> Self {
|
||||
Self {
|
||||
bundle: value.bundle.into_owned(),
|
||||
receipts: value
|
||||
.receipts
|
||||
.into_iter()
|
||||
.map(|vec| vec.into_iter().map(|receipt| T::from_repr(receipt)).collect())
|
||||
.collect(),
|
||||
first_block: value.first_block,
|
||||
requests: value.requests.into_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SerializeAs<super::ExecutionOutcome<T>> for ExecutionOutcome<'_, T>
|
||||
where
|
||||
T: SerdeBincodeCompat + core::fmt::Debug,
|
||||
{
|
||||
fn serialize_as<S>(
|
||||
source: &super::ExecutionOutcome<T>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
ExecutionOutcome::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> DeserializeAs<'de, super::ExecutionOutcome<T>> for ExecutionOutcome<'de, T>
|
||||
where
|
||||
T: SerdeBincodeCompat + core::fmt::Debug,
|
||||
{
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::ExecutionOutcome<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
ExecutionOutcome::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerdeBincodeCompat + core::fmt::Debug> SerdeBincodeCompat for super::ExecutionOutcome<T> {
|
||||
type BincodeRepr<'a> = ExecutionOutcome<'a, T>;
|
||||
|
||||
fn as_repr(&self) -> Self::BincodeRepr<'_> {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
|
||||
repr.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{serde_bincode_compat, ExecutionOutcome};
|
||||
use rand::Rng;
|
||||
use reth_ethereum_primitives::Receipt;
|
||||
use reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
|
||||
#[test]
|
||||
fn test_chain_bincode_roundtrip() {
|
||||
#[serde_as]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Data<T: SerdeBincodeCompat + core::fmt::Debug> {
|
||||
#[serde_as(as = "serde_bincode_compat::ExecutionOutcome<'_, T>")]
|
||||
data: ExecutionOutcome<T>,
|
||||
}
|
||||
|
||||
let mut bytes = [0u8; 1024];
|
||||
rand::thread_rng().fill(bytes.as_mut_slice());
|
||||
let data = Data {
|
||||
data: ExecutionOutcome {
|
||||
bundle: Default::default(),
|
||||
receipts: vec![],
|
||||
first_block: 0,
|
||||
requests: vec![],
|
||||
},
|
||||
};
|
||||
|
||||
let encoded = bincode::serialize(&data).unwrap();
|
||||
let decoded = bincode::deserialize::<Data<Receipt>>(&encoded).unwrap();
|
||||
assert_eq!(decoded, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -29,5 +29,5 @@ pub use execution_outcome::*;
|
||||
/// Read more: <https://github.com/bincode-org/bincode/issues/326>
|
||||
#[cfg(feature = "serde-bincode-compat")]
|
||||
pub mod serde_bincode_compat {
|
||||
pub use super::chain::serde_bincode_compat::*;
|
||||
pub use super::{chain::serde_bincode_compat::*, execution_outcome::serde_bincode_compat::*};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user