From 567d6ce2e419288273df6236acb0ad7acdc414fb Mon Sep 17 00:00:00 2001 From: sprites0 <199826320+sprites0@users.noreply.github.com> Date: Sun, 5 Oct 2025 23:34:04 +0000 Subject: [PATCH] feat: Introduce HlHeader --- src/node/primitives/header.rs | 187 ++++++++++++++++++++++++++++++++++ src/node/primitives/mod.rs | 1 + src/node/types/mod.rs | 17 +++- 3 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 src/node/primitives/header.rs diff --git a/src/node/primitives/header.rs b/src/node/primitives/header.rs new file mode 100644 index 000000000..f6fa1794d --- /dev/null +++ b/src/node/primitives/header.rs @@ -0,0 +1,187 @@ +use alloy_consensus::Header; +use alloy_primitives::{Address, B64, B256, BlockNumber, Bloom, Bytes, Sealable, U256}; +use alloy_rlp::{RlpDecodable, RlpEncodable}; +use reth_codecs::Compact; +use reth_primitives_traits::{BlockHeader, InMemorySize, serde_bincode_compat::RlpBincode}; +use serde::{Deserialize, Serialize}; + +use crate::node::types::HlExtras; + +/// The header type of this node +/// +/// This type extends the regular ethereum header with an extension. +#[derive( + Clone, + Debug, + PartialEq, + Eq, + Hash, + derive_more::AsRef, + derive_more::Deref, + Default, + RlpEncodable, + RlpDecodable, + Serialize, + Deserialize, +)] +#[serde(rename_all = "camelCase")] +pub struct HlHeader { + /// The regular eth header + #[as_ref] + #[deref] + #[serde(flatten)] + pub inner: Header, + /// The extended header fields that is not part of the block hash + pub logs_bloom_with_system_txs: Bloom, + pub system_tx_count: u64, + pub read_precompile_calls: HlExtras, +} + +impl From
for HlHeader { + fn from(_value: Header) -> Self { + unreachable!() + } +} + +impl AsRef for HlHeader { + fn as_ref(&self) -> &Self { + self + } +} + +impl Sealable for HlHeader { + fn hash_slow(&self) -> B256 { + self.inner.hash_slow() + } +} + +impl alloy_consensus::BlockHeader for HlHeader { + fn parent_hash(&self) -> B256 { + self.inner.parent_hash() + } + + fn ommers_hash(&self) -> B256 { + self.inner.ommers_hash() + } + + fn beneficiary(&self) -> Address { + self.inner.beneficiary() + } + + fn state_root(&self) -> B256 { + self.inner.state_root() + } + + fn transactions_root(&self) -> B256 { + self.inner.transactions_root() + } + + fn receipts_root(&self) -> B256 { + self.inner.receipts_root() + } + + fn withdrawals_root(&self) -> Option { + self.inner.withdrawals_root() + } + + fn logs_bloom(&self) -> Bloom { + self.inner.logs_bloom() + } + + fn difficulty(&self) -> U256 { + self.inner.difficulty() + } + + fn number(&self) -> BlockNumber { + self.inner.number() + } + + fn gas_limit(&self) -> u64 { + self.inner.gas_limit() + } + + fn gas_used(&self) -> u64 { + self.inner.gas_used() + } + + fn timestamp(&self) -> u64 { + self.inner.timestamp() + } + + fn mix_hash(&self) -> Option { + self.inner.mix_hash() + } + + fn nonce(&self) -> Option { + self.inner.nonce() + } + + fn base_fee_per_gas(&self) -> Option { + self.inner.base_fee_per_gas() + } + + fn blob_gas_used(&self) -> Option { + self.inner.blob_gas_used() + } + + fn excess_blob_gas(&self) -> Option { + self.inner.excess_blob_gas() + } + + fn parent_beacon_block_root(&self) -> Option { + self.inner.parent_beacon_block_root() + } + + fn requests_hash(&self) -> Option { + self.inner.requests_hash() + } + + fn extra_data(&self) -> &Bytes { + self.inner.extra_data() + } +} + +impl InMemorySize for HlHeader { + fn size(&self) -> usize { + self.inner.size() + + self.logs_bloom_with_system_txs.data().len() + + self.system_tx_count.size() + + self.read_precompile_calls.size() + } +} + +impl reth_codecs::Compact for HlHeader { + fn to_compact(&self, buf: &mut B) -> usize + where + B: alloy_rlp::bytes::BufMut + AsMut<[u8]>, + { + // It's too tedious to implement to_compact for every field, so use rmp_serde to serialize + // This also helps the struct to be upgradable in future thanks to serde's flexibility. + let result: Bytes = rmp_serde::to_vec(&self).unwrap().into(); + result.to_compact(buf) + } + + fn from_compact(buf: &[u8], identifier: usize) -> (Self, &[u8]) { + let header: HlHeader = rmp_serde::from_slice(&buf[identifier..]).unwrap(); + (header, &buf[identifier + buf.len()..]) + } +} + +impl reth_db_api::table::Compress for HlHeader { + type Compressed = Vec; + + fn compress_to_buf>(&self, buf: &mut B) { + let _ = Compact::to_compact(self, buf); + } +} + +impl reth_db_api::table::Decompress for HlHeader { + fn decompress(value: &[u8]) -> Result { + let (obj, _) = Compact::from_compact(value, value.len()); + Ok(obj) + } +} + +impl BlockHeader for HlHeader {} + +impl RlpBincode for HlHeader {} diff --git a/src/node/primitives/mod.rs b/src/node/primitives/mod.rs index aa2029efa..2d49b8343 100644 --- a/src/node/primitives/mod.rs +++ b/src/node/primitives/mod.rs @@ -9,6 +9,7 @@ pub mod block; pub use block::HlBlock; pub mod body; pub use body::HlBlockBody; +pub mod header; pub mod rlp; pub mod serde_bincode_compat; diff --git a/src/node/types/mod.rs b/src/node/types/mod.rs index 8d6dc353b..9029ee57e 100644 --- a/src/node/types/mod.rs +++ b/src/node/types/mod.rs @@ -5,23 +5,34 @@ use alloy_primitives::{Address, B256, Bytes, Log}; use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable}; use bytes::BufMut; +use reth_primitives_traits::InMemorySize; use serde::{Deserialize, Serialize}; use crate::HlBlock; pub type ReadPrecompileCall = (Address, Vec<(ReadPrecompileInput, ReadPrecompileResult)>); -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default, Hash)] pub struct ReadPrecompileCalls(pub Vec); pub(crate) mod reth_compat; -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[derive( + Debug, Clone, Serialize, Deserialize, Default, RlpEncodable, RlpDecodable, Eq, PartialEq, Hash, +)] +#[rlp(trailing)] pub struct HlExtras { pub read_precompile_calls: Option, pub highest_precompile_address: Option
, } +impl InMemorySize for HlExtras { + fn size(&self) -> usize { + self.read_precompile_calls.as_ref().map_or(0, |s| s.0.len()) + + self.highest_precompile_address.as_ref().map_or(0, |_| 20) + } +} + impl Encodable for ReadPrecompileCalls { fn encode(&self, out: &mut dyn BufMut) { let buf: Bytes = rmp_serde::to_vec(&self.0).unwrap().into(); @@ -117,7 +128,7 @@ pub struct ReadPrecompileInput { pub gas_limit: u64, } -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] pub enum ReadPrecompileResult { Ok { gas_used: u64, bytes: Bytes }, OutOfGas,