diff --git a/crates/zenith/src/block.rs b/crates/zenith/src/block.rs index 2f0f2c43..793fca22 100644 --- a/crates/zenith/src/block.rs +++ b/crates/zenith/src/block.rs @@ -1,10 +1,11 @@ -use std::{marker::PhantomData, sync::OnceLock}; - use crate::Zenith::BlockHeader as ZenithHeader; -use alloy::consensus::TxEnvelope; -use alloy::eips::eip2718::{Decodable2718, Encodable2718}; -use alloy::primitives::{keccak256, Address, B256}; -use alloy::rlp::Decodable; +use alloy::{ + consensus::TxEnvelope, + eips::eip2718::{Decodable2718, Encodable2718}, + primitives::{keccak256, Address, B256}, + rlp::Decodable, +}; +use std::{marker::PhantomData, sync::OnceLock}; /// Zenith processes normal Ethereum txns. pub type ZenithTransaction = TxEnvelope; @@ -44,7 +45,8 @@ impl Coder for Alloy2718Coder { } /// A Zenith block is just a list of transactions. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(bound = "C::Tx: serde::Serialize + serde::de::DeserializeOwned")] pub struct ZenithBlock { /// The zenith block header, which may be extracted from a /// [`crate::Zenith::BlockSubmitted`] event. @@ -53,14 +55,45 @@ pub struct ZenithBlock { /// blob data. transactions: Vec<::Tx>, - // memoization fields + // The encoded transactions, memoized to avoid re-encoding. + #[serde(skip)] encoded: OnceLock>, + + /// The hash of the encoded transactions. + #[serde(with = "oncelock_as_opt")] block_data_hash: OnceLock, /// The coder _pd: std::marker::PhantomData, } +mod oncelock_as_opt { + use serde::{Deserialize, Serialize}; + use std::sync::OnceLock; + + /// Serialize a `OnceLock` as an optional value. + pub(crate) fn serialize(value: &OnceLock, serializer: S) -> Result + where + S: serde::Serializer, + T: serde::Serialize, + { + value.get().serialize(serializer) + } + + /// Deserialize a `OnceLock` from an optional value. + pub(crate) fn deserialize<'de, D, T>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + T: serde::Deserialize<'de>, + { + if let Some(item) = Option::::deserialize(deserializer)? { + Ok(OnceLock::from(item)) + } else { + Ok(OnceLock::new()) + } + } +} + impl ZenithBlock where C: Coder,