diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 17b501e7e..3730e4499 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -6,7 +6,10 @@ use crate::{ payload::{OpBuiltPayload, OpPayloadBuilderAttributes}, OpPayloadPrimitives, }; -use alloy_consensus::{Eip658Value, Header, Transaction, Typed2718, EMPTY_OMMER_ROOT_HASH}; +use alloy_consensus::{ + constants::EMPTY_WITHDRAWALS, Eip658Value, Header, Transaction, Typed2718, + EMPTY_OMMER_ROOT_HASH, +}; use alloy_eips::{eip4895::Withdrawals, merge::BEACON_NONCE}; use alloy_primitives::{Address, Bytes, B256, U256}; use alloy_rlp::Encodable; @@ -26,7 +29,9 @@ use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism; use reth_optimism_evm::{OpReceiptBuilder, ReceiptBuilderCtx}; use reth_optimism_forks::OpHardforks; -use reth_optimism_primitives::{transaction::signed::OpTransaction, OpTransactionSigned}; +use reth_optimism_primitives::{ + transaction::signed::OpTransaction, OpTransactionSigned, ADDRESS_L2_TO_L1_MESSAGE_PASSER, +}; use reth_payload_builder_primitives::PayloadBuilderError; use reth_payload_primitives::PayloadBuilderAttributes; use reth_payload_util::{NoopPayloadTransactions, PayloadTransactions}; @@ -36,7 +41,7 @@ use reth_primitives::{ use reth_primitives_traits::{block::Block as _, proofs, RecoveredBlock}; use reth_provider::{ HashedPostStateProvider, ProviderError, StateProofProvider, StateProviderFactory, - StateRootProvider, + StateRootProvider, StorageRootProvider, }; use reth_revm::{ cancelled::Cancelled, database::StateProviderDatabase, witness::ExecutionWitnessRecord, @@ -330,7 +335,7 @@ where Txs: PayloadTransactions, { /// Executes the payload and returns the outcome. - pub fn execute( + pub fn execute( self, state: &mut State, ctx: &OpPayloadBuilderCtx, @@ -339,7 +344,8 @@ where N: OpPayloadPrimitives, Txs: PayloadTransactions, EvmConfig: ConfigureEvmFor, - DB: Database, + DB: Database + AsRef

, + P: StorageRootProvider, { let Self { best } = self; debug!(target: "payload_builder", id=%ctx.payload_id(), parent_header = ?ctx.parent().hash(), parent_number = ctx.parent().number, "building new payload"); @@ -367,13 +373,28 @@ where } } - let withdrawals_root = ctx.commit_withdrawals(state)?; - // merge all transitions into bundle state, this would apply the withdrawal balance changes // and 4788 contract call state.merge_transitions(BundleRetention::Reverts); - Ok(BuildOutcomeKind::Better { payload: ExecutedPayload { info, withdrawals_root } }) + let withdrawals_root = if ctx.is_isthmus_active() { + // withdrawals root field in block header is used for storage root of L2 predeploy + // `l2tol1-message-passer` + Some( + state + .database + .as_ref() + .storage_root(ADDRESS_L2_TO_L1_MESSAGE_PASSER, Default::default())?, + ) + } else if ctx.is_canyon_active() { + Some(EMPTY_WITHDRAWALS) + } else { + None + }; + + let payload = ExecutedPayload { info, withdrawals_root }; + + Ok(BuildOutcomeKind::Better { payload }) } /// Builds the payload on top of the state. @@ -387,7 +408,7 @@ where N: OpPayloadPrimitives, Txs: PayloadTransactions, DB: Database + AsRef

, - P: StateRootProvider + HashedPostStateProvider, + P: StateRootProvider + HashedPostStateProvider + StorageRootProvider, { let ExecutedPayload { info, withdrawals_root } = match self.execute(&mut state, &ctx)? { BuildOutcomeKind::Better { payload } | BuildOutcomeKind::Freeze(payload) => payload, @@ -512,7 +533,7 @@ where N: OpPayloadPrimitives, Txs: PayloadTransactions, DB: Database + AsRef

, - P: StateProofProvider, + P: StateProofProvider + StorageRootProvider, { let _ = self.execute(state, ctx)?; let ExecutionWitnessRecord { hashed_state, codes, keys } = @@ -735,24 +756,16 @@ impl OpPayloadBuilderCtx bool { + self.chain_spec.is_isthmus_active_at_timestamp(self.attributes().timestamp()) + } + /// Returns true if the fees are higher than the previous payload. pub fn is_better_payload(&self, total_fees: U256) -> bool { is_better_payload(self.best_payload.as_ref(), total_fees) } - /// Commits the withdrawals from the payload attributes to the state. - pub fn commit_withdrawals(&self, db: &mut State) -> Result, ProviderError> - where - DB: Database, - { - commit_withdrawals( - db, - &self.chain_spec, - self.attributes().payload_attributes.timestamp, - &self.attributes().payload_attributes.withdrawals, - ) - } - /// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism /// blocks will always have at least a single transaction in them (the L1 info transaction), /// so we can safely assume that this will always be triggered upon the transition and that diff --git a/crates/optimism/primitives/src/lib.rs b/crates/optimism/primitives/src/lib.rs index 15d21dd61..77056420a 100644 --- a/crates/optimism/primitives/src/lib.rs +++ b/crates/optimism/primitives/src/lib.rs @@ -12,9 +12,11 @@ extern crate alloc; pub mod bedrock; -pub mod transaction; -use reth_primitives_traits::Block; +pub mod predeploys; +pub use predeploys::ADDRESS_L2_TO_L1_MESSAGE_PASSER; + +pub mod transaction; pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType}; mod receipt; @@ -24,7 +26,7 @@ pub use receipt::{DepositReceipt, OpReceipt}; pub type OpBlock = alloy_consensus::Block; /// Optimism-specific block body type. -pub type OpBlockBody = ::Body; +pub type OpBlockBody = ::Body; /// Primitive types for Optimism Node. #[derive(Debug, Default, Clone, PartialEq, Eq)] diff --git a/crates/optimism/primitives/src/predeploys.rs b/crates/optimism/primitives/src/predeploys.rs new file mode 100644 index 000000000..c29f72a0d --- /dev/null +++ b/crates/optimism/primitives/src/predeploys.rs @@ -0,0 +1,8 @@ +//! Addresses of OP pre-deploys. +// todo: move to op-alloy + +use alloy_primitives::{address, Address}; + +/// The L2 contract `L2ToL1MessagePasser`, stores commitments to withdrawal transactions. +pub const ADDRESS_L2_TO_L1_MESSAGE_PASSER: Address = + address!("4200000000000000000000000000000000000016");