diff --git a/src/addons/hl_node_compliance.rs b/src/addons/hl_node_compliance.rs index 0331926bd..60deeb6f8 100644 --- a/src/addons/hl_node_compliance.rs +++ b/src/addons/hl_node_compliance.rs @@ -23,7 +23,7 @@ use jsonrpsee::{PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink, use jsonrpsee_core::{RpcResult, async_trait}; use jsonrpsee_types::{ErrorObject, error::INTERNAL_ERROR_CODE}; use reth::{api::FullNodeComponents, builder::rpc::RpcContext, tasks::TaskSpawner}; -use reth_primitives_traits::{BlockBody as _, SignedTransaction}; +use reth_primitives_traits::SignedTransaction; use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, ReceiptProvider}; use reth_rpc::{EthFilter, EthPubSub, RpcTypes, eth::pubsub::SubscriptionSerializeError}; use reth_rpc_eth_api::{ @@ -579,9 +579,9 @@ async fn adjust_transaction_receipt( // This function assumes that `block_id` is already validated by the caller. fn system_tx_count_for_block(eth_api: &Eth, block_id: BlockId) -> usize { let provider = eth_api.provider(); - let block = provider.block_by_id(block_id).unwrap().unwrap(); + let header = provider.header_by_id(block_id).unwrap().unwrap(); - block.body.transactions().iter().filter(|tx| tx.is_system_transaction()).count() + header.extras.system_tx_count.try_into().unwrap() } #[async_trait] diff --git a/src/chainspec/mod.rs b/src/chainspec/mod.rs index 783ddbabf..19ae4bdc0 100644 --- a/src/chainspec/mod.rs +++ b/src/chainspec/mod.rs @@ -1,8 +1,7 @@ pub mod hl; pub mod parser; -use crate::hardforks::HlHardforks; -use alloy_consensus::Header; +use crate::{hardforks::HlHardforks, node::primitives::{header::HlHeaderExtras, HlHeader}}; use alloy_eips::eip7840::BlobParams; use alloy_genesis::Genesis; use alloy_primitives::{Address, B256, U256}; @@ -20,10 +19,11 @@ pub const TESTNET_CHAIN_ID: u64 = 998; #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct HlChainSpec { pub inner: ChainSpec, + pub genesis_header: HlHeader, } impl EthChainSpec for HlChainSpec { - type Header = Header; + type Header = HlHeader; fn blob_params_at_timestamp(&self, timestamp: u64) -> Option { self.inner.blob_params_at_timestamp(timestamp) @@ -57,8 +57,8 @@ impl EthChainSpec for HlChainSpec { Box::new(self.inner.display_hardforks()) } - fn genesis_header(&self) -> &Header { - self.inner.genesis_header() + fn genesis_header(&self) -> &HlHeader { + &self.genesis_header } fn genesis(&self) -> &Genesis { @@ -127,4 +127,10 @@ impl HlChainSpec { _ => unreachable!("Unreachable since ChainSpecParser won't return other chains"), } } + + fn new(inner: ChainSpec) -> Self { + let genesis_header = + HlHeader { inner: inner.genesis_header().clone(), extras: HlHeaderExtras::default() }; + Self { inner, genesis_header } + } } diff --git a/src/chainspec/parser.rs b/src/chainspec/parser.rs index 0ac712b8b..a85d73005 100644 --- a/src/chainspec/parser.rs +++ b/src/chainspec/parser.rs @@ -26,8 +26,8 @@ impl ChainSpecParser for HlChainSpecParser { /// Currently only mainnet is supported. pub fn chain_value_parser(s: &str) -> eyre::Result> { match s { - "mainnet" => Ok(Arc::new(HlChainSpec { inner: hl_mainnet() })), - "testnet" => Ok(Arc::new(HlChainSpec { inner: hl_testnet() })), + "mainnet" => Ok(Arc::new(HlChainSpec::new(hl_mainnet()))), + "testnet" => Ok(Arc::new(HlChainSpec::new(hl_testnet()))), _ => Err(eyre::eyre!("Unsupported chain: {}", s)), } } diff --git a/src/evm/api/patch.rs b/src/evm/api/patch.rs index 62c85ac48..f333d845d 100644 --- a/src/evm/api/patch.rs +++ b/src/evm/api/patch.rs @@ -7,36 +7,12 @@ use alloy_primitives::keccak256; use revm::{ context::Host, interpreter::{ - InstructionContext, InterpreterTypes, as_u64_saturated, interpreter_types::StackTr, + _count, InstructionContext, InterpreterTypes, as_u64_saturated, interpreter_types::StackTr, popn_top, }, primitives::{BLOCK_HASH_HISTORY, U256}, }; -#[doc(hidden)] -#[macro_export] -#[collapse_debuginfo(yes)] -macro_rules! _count { - (@count) => { 0 }; - (@count $head:tt $($tail:tt)*) => { 1 + _count!(@count $($tail)*) }; - ($($arg:tt)*) => { _count!(@count $($arg)*) }; -} - -/// Pops n values from the stack and returns the top value. Fails the instruction if n values can't -/// be popped. -#[macro_export] -#[collapse_debuginfo(yes)] -macro_rules! popn_top { - ([ $($x:ident),* ], $top:ident, $interpreter:expr $(,$ret:expr)? ) => { - // Workaround for https://github.com/rust-lang/rust/issues/144329. - if $interpreter.stack.len() < (1 + $crate::_count!($($x)*)) { - $interpreter.halt_underflow(); - return $($ret)?; - } - let ([$( $x ),*], $top) = unsafe { $interpreter.stack.popn_top().unwrap_unchecked() }; - }; -} - /// Implements the BLOCKHASH instruction. /// /// Gets the hash of one of the 256 most recent complete blocks. diff --git a/src/lib.rs b/src/lib.rs index 8291c71a5..e3cbf55d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,4 +7,4 @@ pub mod node; pub mod pseudo_peer; pub mod version; -pub use node::primitives::{HlBlock, HlBlockBody, HlPrimitives}; +pub use node::primitives::{HlBlock, HlBlockBody, HlHeader, HlPrimitives}; diff --git a/src/node/consensus/mod.rs b/src/node/consensus/mod.rs index 7a990bc9b..aec2d76db 100644 --- a/src/node/consensus/mod.rs +++ b/src/node/consensus/mod.rs @@ -1,5 +1,4 @@ -use crate::{HlBlock, HlBlockBody, HlPrimitives, hardforks::HlHardforks, node::HlNode}; -use alloy_consensus::Header; +use crate::{hardforks::HlHardforks, node::{primitives::HlHeader, HlNode}, HlBlock, HlBlockBody, HlPrimitives}; use reth::{ api::{FullNodeTypes, NodeTypes}, beacon_consensus::EthBeaconConsensus, @@ -101,14 +100,14 @@ where impl Consensus for HlConsensus where - ChainSpec: EthChainSpec
+ HlHardforks, + ChainSpec: EthChainSpec
+ HlHardforks, { type Error = ConsensusError; fn validate_body_against_header( &self, body: &HlBlockBody, - header: &SealedHeader, + header: &SealedHeader, ) -> Result<(), ConsensusError> { Consensus::::validate_body_against_header(&self.inner, body, header) } @@ -148,7 +147,7 @@ mod reth_copy; impl FullConsensus for HlConsensus where - ChainSpec: EthChainSpec
+ HlHardforks, + ChainSpec: EthChainSpec
+ HlHardforks, { fn validate_block_post_execution( &self, diff --git a/src/node/consensus/reth_copy.rs b/src/node/consensus/reth_copy.rs index f4934dfed..1adf4c8dd 100644 --- a/src/node/consensus/reth_copy.rs +++ b/src/node/consensus/reth_copy.rs @@ -1,21 +1,21 @@ //! Copy of reth codebase. +use crate::HlBlock; use alloy_consensus::{BlockHeader, TxReceipt, proofs::calculate_receipt_root}; use alloy_eips::eip7685::Requests; use alloy_primitives::{B256, Bloom}; use reth::consensus::ConsensusError; use reth_chainspec::EthereumHardforks; use reth_primitives::{GotExpected, RecoveredBlock, gas_spent_by_transactions}; -use reth_primitives_traits::{Block, Receipt as ReceiptTrait}; +use reth_primitives_traits::Receipt as ReceiptTrait; -pub fn validate_block_post_execution( - block: &RecoveredBlock, +pub fn validate_block_post_execution( + block: &RecoveredBlock, chain_spec: &ChainSpec, receipts: &[R], requests: &Requests, ) -> Result<(), ConsensusError> where - B: Block, R: ReceiptTrait, ChainSpec: EthereumHardforks, { @@ -42,7 +42,7 @@ where receipts.iter().filter(|&r| r.cumulative_gas_used() != 0).cloned().collect::>(); if let Err(error) = verify_receipts( block.header().receipts_root(), - block.header().logs_bloom(), + block.header().inner.logs_bloom(), &receipts_for_root, ) { tracing::debug!(%error, ?receipts, "receipts verification failed"); diff --git a/src/node/evm/assembler.rs b/src/node/evm/assembler.rs index 4a3911024..62aee3250 100644 --- a/src/node/evm/assembler.rs +++ b/src/node/evm/assembler.rs @@ -1,8 +1,6 @@ use crate::{ - HlBlock, - node::evm::config::{HlBlockExecutorFactory, HlEvmConfig}, + node::evm::config::{HlBlockExecutorFactory, HlEvmConfig}, HlBlock, HlHeader }; -use alloy_consensus::Header; use reth_evm::{ block::BlockExecutionError, execute::{BlockAssembler, BlockAssemblerInput}, @@ -13,7 +11,7 @@ impl BlockAssembler for HlEvmConfig { fn assemble_block( &self, - input: BlockAssemblerInput<'_, '_, HlBlockExecutorFactory, Header>, + input: BlockAssemblerInput<'_, '_, HlBlockExecutorFactory, HlHeader>, ) -> Result { let HlBlock { header, body } = self.block_assembler.assemble_block(input)?; Ok(HlBlock { header, body }) diff --git a/src/node/evm/config.rs b/src/node/evm/config.rs index 60958cf58..dcf226ec8 100644 --- a/src/node/evm/config.rs +++ b/src/node/evm/config.rs @@ -1,6 +1,6 @@ use super::{executor::HlBlockExecutor, factory::HlEvmFactory}; use crate::{ - HlBlock, HlBlockBody, HlPrimitives, + HlBlock, HlBlockBody, HlHeader, HlPrimitives, chainspec::HlChainSpec, evm::{spec::HlSpecId, transaction::HlTxEnv}, hardforks::HlHardforks, @@ -54,7 +54,7 @@ where fn assemble_block( &self, - input: BlockAssemblerInput<'_, '_, F>, + input: BlockAssemblerInput<'_, '_, F, HlHeader>, ) -> Result { // TODO: Copy of EthBlockAssembler::assemble_block let inner = &self.inner; @@ -136,6 +136,9 @@ where excess_blob_gas, requests_hash, }; + let system_tx_count = + transactions.iter().filter(|t| is_system_transaction(t)).count() as u64; + let header = HlHeader::from_ethereum_header(header, receipts, system_tx_count); Ok(Self::Block { header, @@ -269,6 +272,8 @@ where } } +static EMPTY_OMMERS: [Header; 0] = []; + impl ConfigureEvm for HlEvmConfig where Self: Send + Sync + Unpin + Clone + 'static, @@ -287,7 +292,7 @@ where self } - fn evm_env(&self, header: &Header) -> Result, Self::Error> { + fn evm_env(&self, header: &HlHeader) -> Result, Self::Error> { let blob_params = self.chain_spec().blob_params_at_timestamp(header.timestamp); let spec = revm_spec_by_timestamp_and_block_number( self.chain_spec().clone(), @@ -332,7 +337,7 @@ where fn next_evm_env( &self, - parent: &Header, + parent: &HlHeader, attributes: &Self::NextBlockEnvCtx, ) -> Result, Self::Error> { // ensure we're not missing any timestamp based hardforks @@ -382,7 +387,7 @@ where ctx: EthBlockExecutionCtx { parent_hash: block.header().parent_hash, parent_beacon_block_root: block.header().parent_beacon_block_root, - ommers: &block.body().ommers, + ommers: &EMPTY_OMMERS, withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed), }, extras: HlExtras { @@ -420,7 +425,7 @@ impl ConfigureEngineEvm for HlEvmConfig { ctx: EthBlockExecutionCtx { parent_hash: block.header.parent_hash, parent_beacon_block_root: block.header.parent_beacon_block_root, - ommers: &block.body.ommers, + ommers: &EMPTY_OMMERS, withdrawals: block.body.withdrawals.as_ref().map(Cow::Borrowed), }, extras: HlExtras { diff --git a/src/node/network/block_import/service.rs b/src/node/network/block_import/service.rs index 9860348fd..359d9ed72 100644 --- a/src/node/network/block_import/service.rs +++ b/src/node/network/block_import/service.rs @@ -179,7 +179,7 @@ where #[cfg(test)] mod tests { - use crate::chainspec::hl::hl_mainnet; + use crate::{chainspec::hl::hl_mainnet, HlHeader}; use super::*; use alloy_primitives::{B256, U128}; @@ -355,7 +355,7 @@ mod tests { /// Creates a test block message fn create_test_block() -> NewBlockMessage { let block = HlBlock { - header: Header::default(), + header: HlHeader::default(), body: HlBlockBody { inner: BlockBody { transactions: Vec::new(), diff --git a/src/node/network/mod.rs b/src/node/network/mod.rs index a9fc469e0..70ed586c2 100644 --- a/src/node/network/mod.rs +++ b/src/node/network/mod.rs @@ -38,10 +38,10 @@ pub struct HlNewBlock(pub NewBlock); mod rlp { use super::*; use crate::{ - HlBlockBody, + HlBlockBody, HlHeader, node::primitives::{BlockBody, TransactionSigned}, }; - use alloy_consensus::{BlobTransactionSidecar, Header}; + use alloy_consensus::BlobTransactionSidecar; use alloy_primitives::{Address, U128}; use alloy_rlp::{RlpDecodable, RlpEncodable}; use alloy_rpc_types::Withdrawals; @@ -50,9 +50,9 @@ mod rlp { #[derive(RlpEncodable, RlpDecodable)] #[rlp(trailing)] struct BlockHelper<'a> { - header: Cow<'a, Header>, + header: Cow<'a, HlHeader>, transactions: Cow<'a, Vec>, - ommers: Cow<'a, Vec
>, + ommers: Cow<'a, Vec>, withdrawals: Option>, } diff --git a/src/node/primitives/block.rs b/src/node/primitives/block.rs new file mode 100644 index 000000000..7462a82c6 --- /dev/null +++ b/src/node/primitives/block.rs @@ -0,0 +1,49 @@ +use super::{HlBlockBody, HlHeader, rlp}; +use alloy_rlp::Encodable; +use reth_primitives_traits::{Block, InMemorySize}; +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; + +/// Block for HL +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct HlBlock { + pub header: HlHeader, + pub body: HlBlockBody, +} + +impl InMemorySize for HlBlock { + fn size(&self) -> usize { + self.header.size() + self.body.size() + } +} + +impl Block for HlBlock { + type Header = HlHeader; + type Body = HlBlockBody; + + fn new(header: Self::Header, body: Self::Body) -> Self { + Self { header, body } + } + fn header(&self) -> &Self::Header { + &self.header + } + fn body(&self) -> &Self::Body { + &self.body + } + fn split(self) -> (Self::Header, Self::Body) { + (self.header, self.body) + } + + fn rlp_length(header: &Self::Header, body: &Self::Body) -> usize { + rlp::BlockHelper { + header: Cow::Borrowed(header), + transactions: Cow::Borrowed(&body.inner.transactions), + ommers: Cow::Borrowed(&body.inner.ommers), + withdrawals: body.inner.withdrawals.as_ref().map(Cow::Borrowed), + sidecars: body.sidecars.as_ref().map(Cow::Borrowed), + read_precompile_calls: body.read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: body.highest_precompile_address.as_ref().map(Cow::Borrowed), + } + .length() + } +} diff --git a/src/node/primitives/body.rs b/src/node/primitives/body.rs new file mode 100644 index 000000000..cdf7e196c --- /dev/null +++ b/src/node/primitives/body.rs @@ -0,0 +1,73 @@ +use alloy_consensus::BlobTransactionSidecar; +use alloy_primitives::Address; +use reth_primitives_traits::{BlockBody as BlockBodyTrait, InMemorySize}; +use serde::{Deserialize, Serialize}; + +use crate::node::primitives::{BlockBody, TransactionSigned}; +pub use crate::node::types::{ReadPrecompileCall, ReadPrecompileCalls}; + +/// Block body for HL. It is equivalent to Ethereum [`BlockBody`] but additionally stores sidecars +/// for blob transactions. +#[derive( + Debug, + Clone, + Default, + PartialEq, + Eq, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct HlBlockBody { + #[serde(flatten)] + #[deref] + #[deref_mut] + pub inner: BlockBody, + pub sidecars: Option>, + pub read_precompile_calls: Option, + pub highest_precompile_address: Option
, +} + +impl InMemorySize for HlBlockBody { + fn size(&self) -> usize { + self.inner.size() + + self.sidecars + .as_ref() + .map_or(0, |s| s.capacity() * core::mem::size_of::()) + + self.read_precompile_calls + .as_ref() + .map_or(0, |s| s.0.capacity() * core::mem::size_of::()) + } +} + +impl BlockBodyTrait for HlBlockBody { + type Transaction = TransactionSigned; + type OmmerHeader = super::HlHeader; + + fn transactions(&self) -> &[Self::Transaction] { + BlockBodyTrait::transactions(&self.inner) + } + fn into_ethereum_body(self) -> BlockBody { + self.inner + } + fn into_transactions(self) -> Vec { + self.inner.into_transactions() + } + fn withdrawals(&self) -> Option<&alloy_rpc_types::Withdrawals> { + self.inner.withdrawals() + } + fn ommers(&self) -> Option<&[Self::OmmerHeader]> { + self.inner.ommers() + } + + fn calculate_tx_root(&self) -> alloy_primitives::B256 { + alloy_consensus::proofs::calculate_transaction_root( + &self + .transactions() + .iter() + .filter(|tx| !tx.is_system_transaction()) + .collect::>(), + ) + } +} diff --git a/src/node/primitives/header.rs b/src/node/primitives/header.rs new file mode 100644 index 000000000..3734ba2e5 --- /dev/null +++ b/src/node/primitives/header.rs @@ -0,0 +1,241 @@ +use alloy_consensus::Header; +use alloy_primitives::{Address, B64, B256, BlockNumber, Bloom, Bytes, Sealable, U256}; +use alloy_rlp::{RlpDecodable, RlpEncodable}; +use reth_cli_commands::common::CliHeader; +use reth_codecs::Compact; +use reth_ethereum_primitives::EthereumReceipt; +use reth_primitives::{SealedHeader, logs_bloom}; +use reth_primitives_traits::{BlockHeader, InMemorySize, serde_bincode_compat::RlpBincode}; +use reth_rpc_convert::transaction::FromConsensusHeader; +use serde::{Deserialize, Serialize}; + +/// 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] + pub inner: Header, + /// The extended header fields that is not part of the block hash + pub extras: HlHeaderExtras, +} + +#[derive( + Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, RlpEncodable, RlpDecodable, Hash, +)] +pub struct HlHeaderExtras { + pub logs_bloom_with_system_txs: Bloom, + pub system_tx_count: u64, +} + +impl HlHeader { + pub(crate) fn from_ethereum_header(header: Header, receipts: &[EthereumReceipt], system_tx_count: u64) -> HlHeader { + let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| &r.logs)); + HlHeader { + inner: header, + extras: HlHeaderExtras { logs_bloom_with_system_txs: logs_bloom, system_tx_count }, + } + } +} + +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.extras.logs_bloom_with_system_txs + } + + 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() + } + + fn is_empty(&self) -> bool { + self.extras.system_tx_count == 0 && self.inner.is_empty() + } +} + +impl InMemorySize for HlHeader { + fn size(&self) -> usize { + self.inner.size() + self.extras.size() + } +} + +impl InMemorySize for HlHeaderExtras { + fn size(&self) -> usize { + self.logs_bloom_with_system_txs.data().len() + self.system_tx_count.size() + } +} + +impl reth_codecs::Compact for HlHeader { + fn to_compact(&self, buf: &mut B) -> usize + where + B: alloy_rlp::bytes::BufMut + AsMut<[u8]>, + { + // Because Header ends with extra_data which is `Bytes`, we can't use to_compact for extras, + // because Compact trait requires the Bytes field to be placed at the end of the struct. + // Bytes::from_compact just reads all trailing data as the Bytes field. + // + // Hence we need to use other form of serialization, since extra headers are not Compact-compatible. + // We just treat all header fields as rmp-serialized one `Bytes` field. + let result: Bytes = rmp_serde::to_vec(&self).unwrap().into(); + result.to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (bytes, remaining) = Bytes::from_compact(buf, len); + let header: HlHeader = rmp_serde::from_slice(&bytes).unwrap(); + (header, remaining) + } +} + +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 {} + +impl CliHeader for HlHeader { + fn set_number(&mut self, number: u64) { + self.inner.set_number(number); + } +} + +impl From for Header { + fn from(value: HlHeader) -> Self { + value.inner + } +} + +pub fn to_ethereum_ommers(ommers: &[HlHeader]) -> Vec
{ + ommers.iter().map(|ommer| ommer.clone().into()).collect() +} + +impl FromConsensusHeader for alloy_rpc_types::Header { + fn from_consensus_header(header: SealedHeader, block_size: usize) -> Self { + FromConsensusHeader::
::from_consensus_header( + SealedHeader::
::new(header.inner.clone(), header.hash()), + block_size, + ) + } +} diff --git a/src/node/primitives/mod.rs b/src/node/primitives/mod.rs index c76efa70a..c4622e617 100644 --- a/src/node/primitives/mod.rs +++ b/src/node/primitives/mod.rs @@ -1,17 +1,18 @@ -#![allow(clippy::owned_cow)] -use alloy_consensus::{BlobTransactionSidecar, Header}; -use alloy_primitives::Address; -use alloy_rlp::{Encodable, RlpDecodable, RlpEncodable}; use reth_ethereum_primitives::Receipt; use reth_primitives::NodePrimitives; -use reth_primitives_traits::{Block, BlockBody as BlockBodyTrait, InMemorySize}; -use serde::{Deserialize, Serialize}; -use std::borrow::Cow; -use crate::node::types::{ReadPrecompileCall, ReadPrecompileCalls}; +pub mod transaction; +pub use transaction::{BlockBody, TransactionSigned}; -pub mod tx_wrapper; -pub use tx_wrapper::{BlockBody, TransactionSigned}; +pub mod block; +pub use block::HlBlock; +pub mod body; +pub use body::HlBlockBody; +pub mod header; +pub use header::HlHeader; + +pub mod rlp; +pub mod serde_bincode_compat; /// Primitive types for HyperEVM. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] @@ -20,321 +21,8 @@ pub struct HlPrimitives; impl NodePrimitives for HlPrimitives { type Block = HlBlock; - type BlockHeader = Header; + type BlockHeader = HlHeader; type BlockBody = HlBlockBody; type SignedTx = TransactionSigned; type Receipt = Receipt; } - -/// Block body for HL. It is equivalent to Ethereum [`BlockBody`] but additionally stores sidecars -/// for blob transactions. -#[derive( - Debug, - Clone, - Default, - PartialEq, - Eq, - Serialize, - Deserialize, - derive_more::Deref, - derive_more::DerefMut, -)] -pub struct HlBlockBody { - #[serde(flatten)] - #[deref] - #[deref_mut] - pub inner: BlockBody, - pub sidecars: Option>, - pub read_precompile_calls: Option, - pub highest_precompile_address: Option
, -} - -impl InMemorySize for HlBlockBody { - fn size(&self) -> usize { - self.inner.size() + - self.sidecars - .as_ref() - .map_or(0, |s| s.capacity() * core::mem::size_of::()) + - self.read_precompile_calls - .as_ref() - .map_or(0, |s| s.0.capacity() * core::mem::size_of::()) - } -} - -impl BlockBodyTrait for HlBlockBody { - type Transaction = TransactionSigned; - type OmmerHeader = Header; - - fn transactions(&self) -> &[Self::Transaction] { - BlockBodyTrait::transactions(&self.inner) - } - fn into_ethereum_body(self) -> BlockBody { - self.inner - } - fn into_transactions(self) -> Vec { - self.inner.into_transactions() - } - fn withdrawals(&self) -> Option<&alloy_rpc_types::Withdrawals> { - self.inner.withdrawals() - } - fn ommers(&self) -> Option<&[Self::OmmerHeader]> { - self.inner.ommers() - } - - fn calculate_tx_root(&self) -> alloy_primitives::B256 { - alloy_consensus::proofs::calculate_transaction_root( - &self - .transactions() - .iter() - .filter(|tx| !tx.is_system_transaction()) - .collect::>(), - ) - } -} - -/// Block for HL -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub struct HlBlock { - pub header: Header, - pub body: HlBlockBody, -} - -impl InMemorySize for HlBlock { - fn size(&self) -> usize { - self.header.size() + self.body.size() - } -} - -impl Block for HlBlock { - type Header = Header; - type Body = HlBlockBody; - - fn new(header: Self::Header, body: Self::Body) -> Self { - Self { header, body } - } - fn header(&self) -> &Self::Header { - &self.header - } - fn body(&self) -> &Self::Body { - &self.body - } - fn split(self) -> (Self::Header, Self::Body) { - (self.header, self.body) - } - - fn rlp_length(header: &Self::Header, body: &Self::Body) -> usize { - rlp::BlockHelper { - header: Cow::Borrowed(header), - transactions: Cow::Borrowed(&body.inner.transactions), - ommers: Cow::Borrowed(&body.inner.ommers), - withdrawals: body.inner.withdrawals.as_ref().map(Cow::Borrowed), - sidecars: body.sidecars.as_ref().map(Cow::Borrowed), - read_precompile_calls: body.read_precompile_calls.as_ref().map(Cow::Borrowed), - highest_precompile_address: body.highest_precompile_address.as_ref().map(Cow::Borrowed), - } - .length() - } -} - -mod rlp { - use super::*; - use alloy_eips::eip4895::Withdrawals; - use alloy_rlp::Decodable; - - #[derive(RlpEncodable, RlpDecodable)] - #[rlp(trailing)] - struct BlockBodyHelper<'a> { - transactions: Cow<'a, Vec>, - ommers: Cow<'a, Vec
>, - withdrawals: Option>, - sidecars: Option>>, - read_precompile_calls: Option>, - highest_precompile_address: Option>, - } - - #[derive(RlpEncodable, RlpDecodable)] - #[rlp(trailing)] - pub(crate) struct BlockHelper<'a> { - pub(crate) header: Cow<'a, Header>, - pub(crate) transactions: Cow<'a, Vec>, - pub(crate) ommers: Cow<'a, Vec
>, - pub(crate) withdrawals: Option>, - pub(crate) sidecars: Option>>, - pub(crate) read_precompile_calls: Option>, - pub(crate) highest_precompile_address: Option>, - } - - impl<'a> From<&'a HlBlockBody> for BlockBodyHelper<'a> { - fn from(value: &'a HlBlockBody) -> Self { - let HlBlockBody { - inner: BlockBody { transactions, ommers, withdrawals }, - sidecars, - read_precompile_calls, - highest_precompile_address, - } = value; - Self { - transactions: Cow::Borrowed(transactions), - ommers: Cow::Borrowed(ommers), - withdrawals: withdrawals.as_ref().map(Cow::Borrowed), - sidecars: sidecars.as_ref().map(Cow::Borrowed), - read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), - highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), - } - } - } - - impl<'a> From<&'a HlBlock> for BlockHelper<'a> { - fn from(value: &'a HlBlock) -> Self { - let HlBlock { - header, - body: - HlBlockBody { - inner: BlockBody { transactions, ommers, withdrawals }, - sidecars, - read_precompile_calls, - highest_precompile_address, - }, - } = value; - Self { - header: Cow::Borrowed(header), - transactions: Cow::Borrowed(transactions), - ommers: Cow::Borrowed(ommers), - withdrawals: withdrawals.as_ref().map(Cow::Borrowed), - sidecars: sidecars.as_ref().map(Cow::Borrowed), - read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), - highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), - } - } - } - - impl Encodable for HlBlockBody { - fn encode(&self, out: &mut dyn bytes::BufMut) { - BlockBodyHelper::from(self).encode(out); - } - fn length(&self) -> usize { - BlockBodyHelper::from(self).length() - } - } - - impl Decodable for HlBlockBody { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let BlockBodyHelper { - transactions, - ommers, - withdrawals, - sidecars, - read_precompile_calls, - highest_precompile_address, - } = BlockBodyHelper::decode(buf)?; - Ok(Self { - inner: BlockBody { - transactions: transactions.into_owned(), - ommers: ommers.into_owned(), - withdrawals: withdrawals.map(|w| w.into_owned()), - }, - sidecars: sidecars.map(|s| s.into_owned()), - read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), - highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), - }) - } - } - - impl Encodable for HlBlock { - fn encode(&self, out: &mut dyn bytes::BufMut) { - BlockHelper::from(self).encode(out); - } - fn length(&self) -> usize { - BlockHelper::from(self).length() - } - } - - impl Decodable for HlBlock { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let BlockHelper { - header, - transactions, - ommers, - withdrawals, - sidecars, - read_precompile_calls, - highest_precompile_address, - } = BlockHelper::decode(buf)?; - Ok(Self { - header: header.into_owned(), - body: HlBlockBody { - inner: BlockBody { - transactions: transactions.into_owned(), - ommers: ommers.into_owned(), - withdrawals: withdrawals.map(|w| w.into_owned()), - }, - sidecars: sidecars.map(|s| s.into_owned()), - read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), - highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), - }, - }) - } - } -} - -pub mod serde_bincode_compat { - use super::*; - use reth_primitives_traits::serde_bincode_compat::{BincodeReprFor, SerdeBincodeCompat}; - - #[derive(Debug, Serialize, Deserialize)] - pub struct HlBlockBodyBincode<'a> { - inner: BincodeReprFor<'a, BlockBody>, - sidecars: Option>>, - read_precompile_calls: Option>, - highest_precompile_address: Option>, - } - - #[derive(Debug, Serialize, Deserialize)] - pub struct HlBlockBincode<'a> { - header: BincodeReprFor<'a, Header>, - body: BincodeReprFor<'a, HlBlockBody>, - } - - impl SerdeBincodeCompat for HlBlockBody { - type BincodeRepr<'a> = HlBlockBodyBincode<'a>; - - fn as_repr(&self) -> Self::BincodeRepr<'_> { - HlBlockBodyBincode { - inner: self.inner.as_repr(), - sidecars: self.sidecars.as_ref().map(Cow::Borrowed), - read_precompile_calls: self.read_precompile_calls.as_ref().map(Cow::Borrowed), - highest_precompile_address: self - .highest_precompile_address - .as_ref() - .map(Cow::Borrowed), - } - } - - fn from_repr(repr: Self::BincodeRepr<'_>) -> Self { - let HlBlockBodyBincode { - inner, - sidecars, - read_precompile_calls, - highest_precompile_address, - } = repr; - Self { - inner: BlockBody::from_repr(inner), - sidecars: sidecars.map(|s| s.into_owned()), - read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), - highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), - } - } - } - - impl SerdeBincodeCompat for HlBlock { - type BincodeRepr<'a> = HlBlockBincode<'a>; - - fn as_repr(&self) -> Self::BincodeRepr<'_> { - HlBlockBincode { header: self.header.as_repr(), body: self.body.as_repr() } - } - - fn from_repr(repr: Self::BincodeRepr<'_>) -> Self { - let HlBlockBincode { header, body } = repr; - Self { header: Header::from_repr(header), body: HlBlockBody::from_repr(body) } - } - } -} diff --git a/src/node/primitives/rlp.rs b/src/node/primitives/rlp.rs new file mode 100644 index 000000000..fb9c9975a --- /dev/null +++ b/src/node/primitives/rlp.rs @@ -0,0 +1,142 @@ +#![allow(clippy::owned_cow)] +use super::{HlBlock, HlBlockBody, TransactionSigned}; +use crate::{node::types::ReadPrecompileCalls, HlHeader}; +use alloy_consensus::{BlobTransactionSidecar, BlockBody}; +use alloy_eips::eip4895::Withdrawals; +use alloy_primitives::Address; +use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable}; +use std::borrow::Cow; + +#[derive(RlpEncodable, RlpDecodable)] +#[rlp(trailing)] +struct BlockBodyHelper<'a> { + transactions: Cow<'a, Vec>, + ommers: Cow<'a, Vec>, + withdrawals: Option>, + sidecars: Option>>, + read_precompile_calls: Option>, + highest_precompile_address: Option>, +} + +#[derive(RlpEncodable, RlpDecodable)] +#[rlp(trailing)] +pub(crate) struct BlockHelper<'a> { + pub(crate) header: Cow<'a, HlHeader>, + pub(crate) transactions: Cow<'a, Vec>, + pub(crate) ommers: Cow<'a, Vec>, + pub(crate) withdrawals: Option>, + pub(crate) sidecars: Option>>, + pub(crate) read_precompile_calls: Option>, + pub(crate) highest_precompile_address: Option>, +} + +impl<'a> From<&'a HlBlockBody> for BlockBodyHelper<'a> { + fn from(value: &'a HlBlockBody) -> Self { + let HlBlockBody { + inner: BlockBody { transactions, ommers, withdrawals }, + sidecars, + read_precompile_calls, + highest_precompile_address, + } = value; + Self { + transactions: Cow::Borrowed(transactions), + ommers: Cow::Borrowed(ommers), + withdrawals: withdrawals.as_ref().map(Cow::Borrowed), + sidecars: sidecars.as_ref().map(Cow::Borrowed), + read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), + } + } +} + +impl<'a> From<&'a HlBlock> for BlockHelper<'a> { + fn from(value: &'a HlBlock) -> Self { + let HlBlock { + header, + body: + HlBlockBody { + inner: BlockBody { transactions, ommers, withdrawals }, + sidecars, + read_precompile_calls, + highest_precompile_address, + }, + } = value; + Self { + header: Cow::Borrowed(header), + transactions: Cow::Borrowed(transactions), + ommers: Cow::Borrowed(ommers), + withdrawals: withdrawals.as_ref().map(Cow::Borrowed), + sidecars: sidecars.as_ref().map(Cow::Borrowed), + read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), + } + } +} + +impl Encodable for HlBlockBody { + fn encode(&self, out: &mut dyn bytes::BufMut) { + BlockBodyHelper::from(self).encode(out); + } + fn length(&self) -> usize { + BlockBodyHelper::from(self).length() + } +} + +impl Decodable for HlBlockBody { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { + let BlockBodyHelper { + transactions, + ommers, + withdrawals, + sidecars, + read_precompile_calls, + highest_precompile_address, + } = BlockBodyHelper::decode(buf)?; + Ok(Self { + inner: BlockBody { + transactions: transactions.into_owned(), + ommers: ommers.into_owned().into_iter().map(Into::into).collect(), + withdrawals: withdrawals.map(|w| w.into_owned()), + }, + sidecars: sidecars.map(|s| s.into_owned()), + read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), + }) + } +} + +impl Encodable for HlBlock { + fn encode(&self, out: &mut dyn bytes::BufMut) { + BlockHelper::from(self).encode(out); + } + fn length(&self) -> usize { + BlockHelper::from(self).length() + } +} + +impl Decodable for HlBlock { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { + let BlockHelper { + header, + transactions, + ommers, + withdrawals, + sidecars, + read_precompile_calls, + highest_precompile_address, + } = BlockHelper::decode(buf)?; + Ok(Self { + header: header.into_owned(), + body: HlBlockBody { + inner: BlockBody { + transactions: transactions.into_owned(), + ommers: ommers.into_owned(), + withdrawals: withdrawals.map(|w| w.into_owned()), + }, + sidecars: sidecars.map(|s| s.into_owned()), + read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), + }, + }) + } +} diff --git a/src/node/primitives/serde_bincode_compat.rs b/src/node/primitives/serde_bincode_compat.rs new file mode 100644 index 000000000..958ede8a9 --- /dev/null +++ b/src/node/primitives/serde_bincode_compat.rs @@ -0,0 +1,64 @@ +#![allow(clippy::owned_cow)] +use alloy_consensus::BlobTransactionSidecar; +use alloy_primitives::Address; +use reth_primitives_traits::serde_bincode_compat::{BincodeReprFor, SerdeBincodeCompat}; +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; + +use super::{HlBlock, HlBlockBody}; +use crate::{node::{primitives::BlockBody, types::ReadPrecompileCalls}, HlHeader}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct HlBlockBodyBincode<'a> { + inner: BincodeReprFor<'a, BlockBody>, + sidecars: Option>>, + read_precompile_calls: Option>, + highest_precompile_address: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct HlBlockBincode<'a> { + header: BincodeReprFor<'a, HlHeader>, + body: BincodeReprFor<'a, HlBlockBody>, +} + +impl SerdeBincodeCompat for HlBlockBody { + type BincodeRepr<'a> = HlBlockBodyBincode<'a>; + + fn as_repr(&self) -> Self::BincodeRepr<'_> { + HlBlockBodyBincode { + inner: self.inner.as_repr(), + sidecars: self.sidecars.as_ref().map(Cow::Borrowed), + read_precompile_calls: self.read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: self.highest_precompile_address.as_ref().map(Cow::Borrowed), + } + } + + fn from_repr(repr: Self::BincodeRepr<'_>) -> Self { + let HlBlockBodyBincode { + inner, + sidecars, + read_precompile_calls, + highest_precompile_address, + } = repr; + Self { + inner: BlockBody::from_repr(inner), + sidecars: sidecars.map(|s| s.into_owned()), + read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), + } + } +} + +impl SerdeBincodeCompat for HlBlock { + type BincodeRepr<'a> = HlBlockBincode<'a>; + + fn as_repr(&self) -> Self::BincodeRepr<'_> { + HlBlockBincode { header: self.header.as_repr(), body: self.body.as_repr() } + } + + fn from_repr(repr: Self::BincodeRepr<'_>) -> Self { + let HlBlockBincode { header, body } = repr; + Self { header: HlHeader::from_repr(header), body: HlBlockBody::from_repr(body) } + } +} diff --git a/src/node/primitives/tx_wrapper.rs b/src/node/primitives/transaction.rs similarity index 97% rename from src/node/primitives/tx_wrapper.rs rename to src/node/primitives/transaction.rs index 872439901..4e4f1bcb6 100644 --- a/src/node/primitives/tx_wrapper.rs +++ b/src/node/primitives/transaction.rs @@ -2,7 +2,7 @@ //! except that it supports pseudo signer for system transactions. use std::convert::Infallible; -use crate::evm::transaction::HlTxEnv; +use crate::{evm::transaction::HlTxEnv, HlHeader}; use alloy_consensus::{ SignableTransaction, Signed, Transaction as TransactionTrait, TransactionEnvelope, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy, TxType, TypedTransaction, crypto::RecoveryError, @@ -181,7 +181,7 @@ impl SerdeBincodeCompat for TransactionSigned { } } -pub type BlockBody = alloy_consensus::BlockBody; +pub type BlockBody = alloy_consensus::BlockBody; impl TryFrom for PooledTransactionVariant { type Error = >::Error; @@ -211,15 +211,15 @@ impl Decompress for TransactionSigned { } } -pub fn convert_to_eth_block_body(value: BlockBody) -> alloy_consensus::BlockBody { +pub fn convert_to_eth_block_body(value: BlockBody) -> alloy_consensus::BlockBody { alloy_consensus::BlockBody { transactions: value.transactions.into_iter().map(|tx| tx.into_inner()).collect(), - ommers: value.ommers, + ommers: value.ommers.into_iter().map(|ommer| ommer.into()).collect(), withdrawals: value.withdrawals, } } -pub fn convert_to_hl_block_body(value: alloy_consensus::BlockBody) -> BlockBody { +pub fn convert_to_hl_block_body(value: alloy_consensus::BlockBody) -> BlockBody { BlockBody { transactions: value.transactions.into_iter().map(TransactionSigned::Default).collect(), ommers: value.ommers, diff --git a/src/node/storage/mod.rs b/src/node/storage/mod.rs index 73f3d8bf6..b492bff1b 100644 --- a/src/node/storage/mod.rs +++ b/src/node/storage/mod.rs @@ -1,7 +1,7 @@ use crate::{ - HlBlock, HlBlockBody, HlPrimitives, + HlBlock, HlBlockBody, HlHeader, HlPrimitives, node::{ - primitives::tx_wrapper::{convert_to_eth_block_body, convert_to_hl_block_body}, + primitives::transaction::{convert_to_eth_block_body, convert_to_hl_block_body}, types::HlExtras, }, }; @@ -13,6 +13,8 @@ use reth_db::{ cursor::{DbCursorRO, DbCursorRW}, transaction::{DbTx, DbTxMut}, }; +use reth_primitives::TransactionSigned; +use reth_primitives_traits::Block; use reth_provider::{ BlockBodyReader, BlockBodyWriter, ChainSpecProvider, ChainStorageReader, ChainStorageWriter, DBProvider, DatabaseProvider, EthStorage, ProviderResult, ReadBodyInput, StorageLocation, @@ -23,7 +25,7 @@ pub mod tables; #[derive(Debug, Clone, Default)] #[non_exhaustive] -pub struct HlStorage(EthStorage); +pub struct HlStorage(EthStorage); impl HlStorage { fn write_precompile_calls( @@ -146,15 +148,15 @@ where inputs: Vec>, ) -> ProviderResult> { let read_precompile_calls = self.read_precompile_calls(provider, &inputs)?; - let eth_bodies = self.0.read_block_bodies( - provider, - inputs - .into_iter() - .map(|(header, transactions)| { - (header, transactions.into_iter().map(|tx| tx.into_inner()).collect()) - }) - .collect(), - )?; + let inputs: Vec<(&HlHeader, _)> = inputs + .into_iter() + .map(|(header, transactions)| { + (header, transactions.into_iter().map(|tx| tx.into_inner()).collect()) + }) + .collect(); + let inputs: Vec<(&::Header, _)> = inputs; + let eth_bodies = self.0.read_block_bodies(provider, inputs)?; + let eth_bodies: Vec> = eth_bodies; // NOTE: sidecars are not used in HyperEVM yet. Ok(eth_bodies diff --git a/src/node/types/mod.rs b/src/node/types/mod.rs index 8d6dc353b..bdfcf572c 100644 --- a/src/node/types/mod.rs +++ b/src/node/types/mod.rs @@ -2,26 +2,39 @@ //! //! Changes: //! - ReadPrecompileCalls supports RLP encoding / decoding +use alloy_consensus::TxType; use alloy_primitives::{Address, B256, Bytes, Log}; use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable}; use bytes::BufMut; +use reth_ethereum_primitives::EthereumReceipt; +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(); @@ -56,6 +69,7 @@ impl BlockAndReceipts { self.read_precompile_calls.clone(), self.highest_precompile_address, self.system_txs.clone(), + self.receipts.clone(), chain_id, ) } @@ -84,6 +98,23 @@ pub struct LegacyReceipt { logs: Vec, } +impl From for EthereumReceipt { + fn from(r: LegacyReceipt) -> Self { + EthereumReceipt { + tx_type: match r.tx_type { + LegacyTxType::Legacy => TxType::Legacy, + LegacyTxType::Eip2930 => TxType::Eip2930, + LegacyTxType::Eip1559 => TxType::Eip1559, + LegacyTxType::Eip4844 => TxType::Eip4844, + LegacyTxType::Eip7702 => TxType::Eip7702, + }, + success: r.success, + cumulative_gas_used: r.cumulative_gas_used, + logs: r.logs, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] enum LegacyTxType { Legacy = 0, @@ -117,7 +148,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, diff --git a/src/node/types/reth_compat.rs b/src/node/types/reth_compat.rs index aea0422bd..11e93a89e 100644 --- a/src/node/types/reth_compat.rs +++ b/src/node/types/reth_compat.rs @@ -10,11 +10,11 @@ use std::{ use tracing::info; use crate::{ - HlBlock, HlBlockBody, + HlBlock, HlBlockBody, HlHeader, node::{ primitives::TransactionSigned as TxSigned, spot_meta::{SpotId, erc20_contract_to_spot_token}, - types::{ReadPrecompileCalls, SystemTx}, + types::{LegacyReceipt, ReadPrecompileCalls, SystemTx}, }, }; @@ -114,22 +114,36 @@ impl SealedBlock { read_precompile_calls: ReadPrecompileCalls, highest_precompile_address: Option
, system_txs: Vec, + receipts: Vec, chain_id: u64, ) -> HlBlock { let mut merged_txs = vec![]; merged_txs.extend(system_txs.iter().map(|tx| system_tx_to_reth_transaction(tx, chain_id))); merged_txs.extend(self.body.transactions.iter().map(|tx| tx.to_reth_transaction())); + + let mut merged_receipts = vec![]; + merged_receipts.extend(system_txs.iter().map(|tx| tx.receipt.clone().unwrap().into())); + merged_receipts.extend(receipts.into_iter().map(From::from)); + let block_body = HlBlockBody { inner: reth_primitives::BlockBody { transactions: merged_txs, withdrawals: self.body.withdrawals.clone(), - ommers: self.body.ommers.clone(), + ommers: vec![], }, sidecars: None, read_precompile_calls: Some(read_precompile_calls), highest_precompile_address, }; - HlBlock { header: self.header.header.clone(), body: block_body } + let system_tx_count = system_txs.len() as u64; + HlBlock { + header: HlHeader::from_ethereum_header( + self.header.header.clone(), + &merged_receipts, + system_tx_count, + ), + body: block_body, + } } }