-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: migrate to factory-based block executor pattern #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
38f50fb
refactor: add receipt buulder in block executor
panos-xyz 1336459
refactor: add ethereum primitives features for evm crate tests
panos-xyz a33b4fc
refactor: add morph block executor factory
panos-xyz 6b30d5d
refactor: get token fee error when tx sender invaild
panos-xyz 261e856
refactor: return error when fetch token id and fee limit error
panos-xyz 91736d8
docs: add some comments
panos-xyz 4e7facd
refactor: add all morph tx fields in receipt builder
panos-xyz fa5e4da
refactor: reduced commit_transaction hardfork calculate
panos-xyz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,67 +1,136 @@ | ||
| use crate::{ | ||
| MorphEvmConfig, MorphEvmFactory, block::MorphReceiptBuilder, context::MorphBlockExecutionCtx, | ||
| }; | ||
| use alloy_evm::{block::BlockExecutionError, eth::EthBlockExecutorFactory}; | ||
| use crate::MorphEvmConfig; | ||
| use alloy_consensus::{BlockBody, EMPTY_OMMER_ROOT_HASH, Header, TxReceipt, proofs}; | ||
| use alloy_evm::block::{BlockExecutionError, BlockExecutionResult}; | ||
| use alloy_primitives::{Address, B64, logs_bloom}; | ||
| use morph_chainspec::MorphChainSpec; | ||
| use morph_primitives::MorphHeader; | ||
| use morph_primitives::{MorphHeader, receipt::calculate_receipt_root_no_memo}; | ||
| use reth_chainspec::EthereumHardforks; | ||
| use reth_evm::execute::{BlockAssembler, BlockAssemblerInput}; | ||
| use reth_evm_ethereum::EthBlockAssembler; | ||
| use reth_primitives_traits::SealedHeader; | ||
| use revm::context::Block; | ||
| use std::sync::Arc; | ||
|
|
||
| /// Assembler for Morph blocks. | ||
| /// | ||
| /// This assembler builds Morph blocks from the execution output. | ||
| /// Unlike `EthBlockAssembler`, it produces `MorphHeader` with proper | ||
| /// L2-specific fields (next_l1_msg_index, batch_hash). | ||
| #[derive(Debug, Clone)] | ||
| pub struct MorphBlockAssembler { | ||
| pub(crate) inner: EthBlockAssembler<MorphChainSpec>, | ||
| /// Chain specification | ||
| chain_spec: Arc<MorphChainSpec>, | ||
| } | ||
|
|
||
| impl MorphBlockAssembler { | ||
| /// Creates a new [`MorphBlockAssembler`] with the given chain specification. | ||
| /// | ||
| /// # Arguments | ||
| /// * `chain_spec` - The Morph chain specification used for hardfork detection | ||
| pub fn new(chain_spec: Arc<MorphChainSpec>) -> Self { | ||
| Self { | ||
| inner: EthBlockAssembler::new(chain_spec), | ||
| } | ||
| Self { chain_spec } | ||
| } | ||
|
|
||
| /// Returns the chain spec. | ||
| pub const fn chain_spec(&self) -> &Arc<MorphChainSpec> { | ||
| &self.chain_spec | ||
| } | ||
| } | ||
|
|
||
| impl BlockAssembler<MorphEvmConfig> for MorphBlockAssembler { | ||
| type Block = morph_primitives::Block; | ||
|
|
||
| /// Assembles a Morph block from execution results. | ||
| /// | ||
| /// This method constructs a complete [`Block`] from the execution output, | ||
| /// including building the proper [`MorphHeader`] with L2-specific fields. | ||
| /// | ||
| /// # Block Assembly Process | ||
| /// 1. **Calculate Merkle Roots**: Computes transaction root and receipt root | ||
| /// 2. **Build Logs Bloom**: Aggregates logs from all receipts | ||
| /// 3. **Check Hardforks**: Determines if EIP-1559 (London) is active for base fee | ||
| /// 4. **Build Header**: Creates standard Ethereum header fields | ||
| /// 5. **Wrap in MorphHeader**: Adds L2-specific fields (next_l1_msg_index, batch_hash) | ||
| /// 6. **Build Block Body**: Combines transactions and empty ommers | ||
| /// | ||
| /// # L2-Specific Fields | ||
| /// - `next_l1_msg_index`: Inherited from parent block | ||
| /// - `batch_hash`: Set to default (will be filled by payload builder) | ||
| /// | ||
| /// # Arguments | ||
| /// * `input` - Contains execution context, transactions, receipts, and state root | ||
| /// | ||
| /// # Returns | ||
| /// A fully assembled Morph block ready for sealing. | ||
| /// | ||
| /// # Errors | ||
| /// Returns error if block assembly fails (should not occur in normal operation). | ||
| fn assemble_block( | ||
| &self, | ||
| input: BlockAssemblerInput<'_, '_, MorphEvmConfig, MorphHeader>, | ||
| ) -> Result<Self::Block, BlockExecutionError> { | ||
| let BlockAssemblerInput { | ||
| evm_env, | ||
| execution_ctx: MorphBlockExecutionCtx { inner }, | ||
| execution_ctx, | ||
| parent, | ||
| transactions, | ||
| output, | ||
| bundle_state, | ||
| state_provider, | ||
| output: BlockExecutionResult { | ||
| receipts, gas_used, .. | ||
| }, | ||
| state_root, | ||
| .. | ||
| } = input; | ||
|
|
||
| // Convert MorphHeader parent to standard Header for the inner assembler. | ||
| // We extract the inner Header since EthBlockAssembler works with standard Headers. | ||
| let inner_parent = SealedHeader::new_unhashed(parent.header().inner.clone()); | ||
| let timestamp = evm_env.block_env.timestamp(); | ||
| let block_number: u64 = evm_env.block_env.number().to(); | ||
|
|
||
| // Delegate block building to the inner assembler | ||
| let block = self.inner.assemble_block(BlockAssemblerInput::< | ||
| EthBlockExecutorFactory<MorphReceiptBuilder, MorphChainSpec, MorphEvmFactory>, | ||
| >::new( | ||
| evm_env, | ||
| inner, | ||
| &inner_parent, | ||
| transactions, | ||
| output, | ||
| bundle_state, | ||
| state_provider, | ||
| // Calculate roots and bloom | ||
| let transactions_root = proofs::calculate_transaction_root(&transactions); | ||
| let receipts_root = calculate_receipt_root_no_memo(receipts); | ||
| let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| r.logs())); | ||
|
|
||
| // Determine if EIP-1559 is active | ||
| let is_london_active = self.chain_spec.is_london_active_at_block(block_number); | ||
|
|
||
| // Build standard Ethereum header | ||
| let inner = Header { | ||
| parent_hash: execution_ctx.parent_hash, | ||
| ommers_hash: EMPTY_OMMER_ROOT_HASH, | ||
| beneficiary: Address::ZERO, | ||
| state_root, | ||
| ))?; | ||
| transactions_root, | ||
| receipts_root, | ||
| withdrawals_root: None, | ||
| logs_bloom, | ||
| timestamp: timestamp.to(), | ||
| mix_hash: evm_env.block_env.prevrandao().unwrap_or_default(), | ||
| nonce: B64::ZERO, | ||
| // Only include base_fee_per_gas after London (EIP-1559) | ||
| base_fee_per_gas: is_london_active.then_some(evm_env.block_env.basefee()), | ||
| number: block_number, | ||
| gas_limit: evm_env.block_env.gas_limit(), | ||
| difficulty: evm_env.block_env.difficulty(), | ||
| gas_used: *gas_used, | ||
| extra_data: Default::default(), | ||
| parent_beacon_block_root: None, | ||
| blob_gas_used: None, | ||
| excess_blob_gas: None, | ||
| requests_hash: None, | ||
| }; | ||
|
|
||
| // Wrap in MorphHeader with L2-specific fields | ||
| // Note: next_l1_msg_index and batch_hash will be set by the payload builder | ||
| let header = MorphHeader { | ||
| inner, | ||
| next_l1_msg_index: parent.header().next_l1_msg_index, | ||
| batch_hash: Default::default(), | ||
| }; | ||
panos-xyz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Convert the standard Header back to MorphHeader. | ||
| // The next_l1_msg_index and batch_hash will be set by the payload builder. | ||
| Ok(block.map_header(MorphHeader::from)) | ||
| Ok(alloy_consensus::Block::new( | ||
| header, | ||
| BlockBody { | ||
| transactions, | ||
| ommers: Default::default(), | ||
| withdrawals: None, | ||
| }, | ||
| )) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| //! Block executor factory for Morph. | ||
| //! | ||
| //! This module provides the [`MorphBlockExecutorFactory`] which creates block executors | ||
| //! that can execute Morph L2 blocks with proper L1 fee calculation and receipt building. | ||
|
|
||
| use crate::{ | ||
| block::{DefaultMorphReceiptBuilder, MorphBlockExecutor}, | ||
| evm::MorphEvm, | ||
| }; | ||
| use alloy_evm::{ | ||
| Database, | ||
| block::{BlockExecutorFactory, BlockExecutorFor}, | ||
| eth::EthBlockExecutionCtx, | ||
| revm::{Inspector, database::State}, | ||
| }; | ||
| use morph_chainspec::MorphChainSpec; | ||
| use morph_primitives::{MorphReceipt, MorphTxEnvelope}; | ||
| use morph_revm::evm::MorphContext; | ||
| use std::sync::Arc; | ||
|
|
||
| use crate::evm::MorphEvmFactory; | ||
|
|
||
| /// Block executor factory for Morph. | ||
| /// | ||
| /// This factory creates [`MorphBlockExecutor`] instances that handle Morph-specific | ||
| /// block execution logic including: | ||
| /// - L1 fee calculation for transactions | ||
| /// - Token fee information extraction for MorphTx (0x7F) transactions | ||
| /// - Curie hardfork application | ||
| /// | ||
| /// Unlike using `EthBlockExecutorFactory`, this factory uses the custom | ||
| /// `MorphReceiptBuilder` trait which includes `l1_fee` in its context, | ||
| /// ensuring receipts are built with complete information. | ||
| #[derive(Debug, Clone)] | ||
| pub(crate) struct MorphBlockExecutorFactory { | ||
| /// Receipt builder | ||
| receipt_builder: DefaultMorphReceiptBuilder, | ||
| /// Chain specification | ||
| spec: Arc<MorphChainSpec>, | ||
| /// EVM factory | ||
| evm_factory: MorphEvmFactory, | ||
| } | ||
|
|
||
| impl MorphBlockExecutorFactory { | ||
| /// Creates a new [`MorphBlockExecutorFactory`]. | ||
| pub(crate) fn new(spec: Arc<MorphChainSpec>, evm_factory: MorphEvmFactory) -> Self { | ||
| Self { | ||
| receipt_builder: DefaultMorphReceiptBuilder, | ||
| spec, | ||
| evm_factory, | ||
| } | ||
| } | ||
|
|
||
| /// Returns the chain spec. | ||
| pub(crate) const fn spec(&self) -> &Arc<MorphChainSpec> { | ||
| &self.spec | ||
| } | ||
|
|
||
| /// Returns the EVM factory. | ||
| pub(crate) const fn evm_factory(&self) -> &MorphEvmFactory { | ||
| &self.evm_factory | ||
| } | ||
| } | ||
|
|
||
| impl BlockExecutorFactory for MorphBlockExecutorFactory { | ||
| type EvmFactory = MorphEvmFactory; | ||
| type ExecutionCtx<'a> = EthBlockExecutionCtx<'a>; | ||
| type Transaction = MorphTxEnvelope; | ||
| type Receipt = MorphReceipt; | ||
|
|
||
| fn evm_factory(&self) -> &Self::EvmFactory { | ||
| &self.evm_factory | ||
| } | ||
|
|
||
| fn create_executor<'a, DB, I>( | ||
| &'a self, | ||
| evm: MorphEvm<&'a mut State<DB>, I>, | ||
| _ctx: Self::ExecutionCtx<'a>, | ||
| ) -> impl BlockExecutorFor<'a, Self, DB, I> | ||
| where | ||
| DB: Database + 'a, | ||
| I: Inspector<MorphContext<&'a mut State<DB>>> + 'a, | ||
| { | ||
| MorphBlockExecutor::new(evm, &self.spec, &self.receipt_builder) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.