From ccea4a036266c5d5c77a475ab00a5b97be11b1d3 Mon Sep 17 00:00:00 2001 From: garwah Date: Sun, 25 Aug 2024 19:17:52 +1000 Subject: [PATCH 01/13] init --- .../ethereum/engine-primitives/src/payload.rs | 59 -------------- crates/ethereum/payload/src/lib.rs | 77 +++++++++++++++---- crates/optimism/payload/src/builder.rs | 53 +++++++++++++ crates/payload/basic/src/lib.rs | 17 +--- crates/payload/primitives/src/traits.rs | 15 ---- examples/custom-engine-types/src/main.rs | 30 +------- 6 files changed, 118 insertions(+), 133 deletions(-) diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index 45514d4d4415..00d66170565b 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -234,65 +234,6 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes { fn withdrawals(&self) -> &Withdrawals { &self.withdrawals } - - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - // configure evm env based on parent block - let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); - - // ensure we're not missing any timestamp based hardforks - let spec_id = revm_spec_by_timestamp_after_merge(chain_spec, self.timestamp()); - - // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is - // cancun now, we need to set the excess blob gas to the default value - let blob_excess_gas_and_price = parent - .next_block_excess_blob_gas() - .or_else(|| { - if spec_id == SpecId::CANCUN { - // default excess blob gas is zero - Some(0) - } else { - None - } - }) - .map(BlobExcessGasAndPrice::new); - - let mut basefee = - parent.next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())); - - let mut gas_limit = U256::from(parent.gas_limit); - - // If we are on the London fork boundary, we need to multiply the parent's gas limit by the - // elasticity multiplier to get the new gas limit. - if chain_spec.fork(EthereumHardfork::London).transitions_at_block(parent.number + 1) { - let elasticity_multiplier = - chain_spec.base_fee_params_at_timestamp(self.timestamp()).elasticity_multiplier; - - // multiply the gas limit by the elasticity multiplier - gas_limit *= U256::from(elasticity_multiplier); - - // set the base fee to the initial base fee from the EIP-1559 spec - basefee = Some(EIP1559_INITIAL_BASE_FEE) - } - - let block_env = BlockEnv { - number: U256::from(parent.number + 1), - coinbase: self.suggested_fee_recipient(), - timestamp: U256::from(self.timestamp()), - difficulty: U256::ZERO, - prevrandao: Some(self.prev_randao()), - gas_limit, - // calculate basefee based on parent block's gas usage - basefee: basefee.map(U256::from).unwrap_or_default(), - // calculate excess gas based on parent block's blob gas usage - blob_excess_gas_and_price, - }; - - (CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env) - } } /// Generates the payload id for the configured payload from the [`PayloadAttributes`]. diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index e853cb1ad12c..8d2be9102557 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -87,14 +87,7 @@ where config: PayloadConfig, ) -> Result { let extra_data = config.extra_data(); - let PayloadConfig { - initialized_block_env, - parent_block, - attributes, - chain_spec, - initialized_cfg, - .. - } = config; + let PayloadConfig { parent_block, attributes, chain_spec, .. } = config; debug!(target: "payload_builder", parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building empty payload"); @@ -244,6 +237,65 @@ where Ok(EthBuiltPayload::new(attributes.payload_id(), sealed_block, U256::ZERO)) } + + fn cfg_and_block_env( + &self, + chain_spec: &ChainSpec, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + // configure evm env based on parent block + let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); + + // ensure we're not missing any timestamp based hardforks + let spec_id = revm_spec_by_timestamp_after_merge(chain_spec, self.timestamp()); + + // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is + // cancun now, we need to set the excess blob gas to the default value + let blob_excess_gas_and_price = parent + .next_block_excess_blob_gas() + .or_else(|| { + if spec_id == SpecId::CANCUN { + // default excess blob gas is zero + Some(0) + } else { + None + } + }) + .map(BlobExcessGasAndPrice::new); + + let mut basefee = + parent.next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())); + + let mut gas_limit = U256::from(parent.gas_limit); + + // If we are on the London fork boundary, we need to multiply the parent's gas limit by the + // elasticity multiplier to get the new gas limit. + if chain_spec.fork(EthereumHardfork::London).transitions_at_block(parent.number + 1) { + let elasticity_multiplier = + chain_spec.base_fee_params_at_timestamp(self.timestamp()).elasticity_multiplier; + + // multiply the gas limit by the elasticity multiplier + gas_limit *= U256::from(elasticity_multiplier); + + // set the base fee to the initial base fee from the EIP-1559 spec + basefee = Some(EIP1559_INITIAL_BASE_FEE) + } + + let block_env = BlockEnv { + number: U256::from(parent.number + 1), + coinbase: self.suggested_fee_recipient(), + timestamp: U256::from(self.timestamp()), + difficulty: U256::ZERO, + prevrandao: Some(self.prev_randao()), + gas_limit, + // calculate basefee based on parent block's gas usage + basefee: basefee.map(U256::from).unwrap_or_default(), + // calculate excess gas based on parent block's blob gas usage + blob_excess_gas_and_price, + }; + + (CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env) + } } /// Constructs an Ethereum transaction payload using the best transactions from the pool. @@ -268,14 +320,7 @@ where let mut db = State::builder().with_database_ref(cached_reads.as_db(state)).with_bundle_update().build(); let extra_data = config.extra_data(); - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - attributes, - chain_spec, - .. - } = config; + let PayloadConfig { parent_block, attributes, chain_spec, .. } = config; debug!(target: "payload_builder", id=%attributes.id, parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); let mut cumulative_gas_used = 0; diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 7ae7d107baa8..bd57fa685428 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -220,6 +220,59 @@ where None, )) } + + fn cfg_and_block_env( + &self, + chain_spec: &ChainSpec, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + // configure evm env based on parent block + let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); + + // ensure we're not missing any timestamp based hardforks + let spec_id = revm_spec_by_timestamp_after_bedrock(chain_spec, self.timestamp()); + + // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is + // cancun now, we need to set the excess blob gas to the default value + let blob_excess_gas_and_price = parent + .next_block_excess_blob_gas() + .or_else(|| { + if spec_id.is_enabled_in(SpecId::CANCUN) { + // default excess blob gas is zero + Some(0) + } else { + None + } + }) + .map(BlobExcessGasAndPrice::new); + + let block_env = BlockEnv { + number: U256::from(parent.number + 1), + coinbase: self.suggested_fee_recipient(), + timestamp: U256::from(self.timestamp()), + difficulty: U256::ZERO, + prevrandao: Some(self.prev_randao()), + gas_limit: U256::from(parent.gas_limit), + // calculate basefee based on parent block's gas usage + basefee: U256::from( + parent + .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())) + .unwrap_or_default(), + ), + // calculate excess gas based on parent block's blob gas usage + blob_excess_gas_and_price, + }; + + let cfg_with_handler_cfg; + { + cfg_with_handler_cfg = CfgEnvWithHandlerCfg { + cfg_env: cfg, + handler_cfg: HandlerCfg { spec_id, is_optimism: true }, + }; + } + + (cfg_with_handler_cfg, block_env) + } } /// Constructs an Ethereum transaction payload from the transactions sent through the diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 5df63fe4b71e..cf09693e3b44 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -673,10 +673,6 @@ impl Drop for Cancelled { /// Static config for how to build a payload. #[derive(Clone, Debug)] pub struct PayloadConfig { - /// Pre-configured block environment. - pub initialized_block_env: BlockEnv, - /// Configuration for the environment. - pub initialized_cfg: CfgEnvWithHandlerCfg, /// The parent block. pub parent_block: Arc, /// Block extra data. @@ -705,18 +701,7 @@ where attributes: Attributes, chain_spec: Arc, ) -> Self { - // configure evm env based on parent block - let (initialized_cfg, initialized_block_env) = - attributes.cfg_and_block_env(&chain_spec, &parent_block); - - Self { - initialized_block_env, - initialized_cfg, - parent_block, - extra_data, - attributes, - chain_spec, - } + Self { parent_block, extra_data, attributes, chain_spec } } /// Returns the payload id. diff --git a/crates/payload/primitives/src/traits.rs b/crates/payload/primitives/src/traits.rs index cbb990c46582..c173b09c013e 100644 --- a/crates/payload/primitives/src/traits.rs +++ b/crates/payload/primitives/src/traits.rs @@ -69,21 +69,6 @@ pub trait PayloadBuilderAttributes: Send + Sync + std::fmt::Debug { /// Returns the withdrawals for the running payload job. fn withdrawals(&self) -> &Withdrawals; - - /// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the targeted payload - /// (that has the `parent` as its parent). - /// - /// The `chain_spec` is used to determine the correct chain id and hardfork for the payload - /// based on its timestamp. - /// - /// Block related settings are derived from the `parent` block and the configured attributes. - /// - /// NOTE: This is only intended for beacon consensus (after merge). - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv); } /// The execution payload attribute type the CL node emits via the engine API. diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index f1f83c55d49c..7d0b5eba45c0 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -150,14 +150,6 @@ impl PayloadBuilderAttributes for CustomPayloadBuilderAttributes { fn withdrawals(&self) -> &Withdrawals { &self.0.withdrawals } - - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - self.0.cfg_and_block_env(chain_spec, parent) - } } /// Custom engine types - uses a custom payload attributes RPC type, but uses the default @@ -285,14 +277,7 @@ where args: BuildArguments, ) -> Result, PayloadBuilderError> { let BuildArguments { client, pool, cached_reads, config, cancel, best_payload } = args; - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - extra_data, - attributes, - chain_spec, - } = config; + let PayloadConfig { parent_block, extra_data, attributes, chain_spec } = config; // This reuses the default EthereumPayloadBuilder to build the payload // but any custom logic can be implemented here @@ -301,8 +286,6 @@ where pool, cached_reads, config: PayloadConfig { - initialized_block_env, - initialized_cfg, parent_block, extra_data, attributes: attributes.0, @@ -318,16 +301,9 @@ where client: &Client, config: PayloadConfig, ) -> Result { - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - extra_data, - attributes, - chain_spec, - } = config; + let PayloadConfig { parent_block, extra_data, attributes, chain_spec } = config; >::build_empty_payload(&reth_ethereum_payload_builder::EthereumPayloadBuilder::default(),client, - PayloadConfig { initialized_block_env, initialized_cfg, parent_block, extra_data, attributes: attributes.0, chain_spec }) + PayloadConfig { parent_block, extra_data, attributes: attributes.0, chain_spec }) } } From 86411acc5c7c8f20bcc75bb019caf7d8a76ac017 Mon Sep 17 00:00:00 2001 From: garwah Date: Sun, 25 Aug 2024 21:02:50 +1000 Subject: [PATCH 02/13] port cfg_and_block_env --- .../ethereum/engine-primitives/src/payload.rs | 13 ---- crates/ethereum/payload/src/lib.rs | 63 +++++-------------- crates/optimism/payload/src/builder.rs | 55 ++++------------ crates/optimism/payload/src/payload.rs | 53 ---------------- crates/payload/basic/src/lib.rs | 17 ++++- crates/payload/primitives/src/traits.rs | 5 +- 6 files changed, 43 insertions(+), 163 deletions(-) diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index 00d66170565b..943eff01bdca 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -339,18 +339,5 @@ mod tests { let chainspec = ChainSpec::from(genesis); let payload_builder_attributes = EthPayloadBuilderAttributes::new(chainspec.genesis_hash(), attributes); - - // use cfg_and_block_env - let cfg_and_block_env = - payload_builder_attributes.cfg_and_block_env(&chainspec, &chainspec.genesis_header()); - - // ensure the base fee is non zero - assert_eq!(cfg_and_block_env.1.basefee, U256::from(EIP1559_INITIAL_BASE_FEE)); - - // ensure the gas limit is double the previous block's gas limit - assert_eq!( - cfg_and_block_env.1.gas_limit, - U256::from(chainspec.genesis_header().gas_limit * 2) - ); } } diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 8d2be9102557..ea56566cb1b2 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -13,6 +13,7 @@ use reth_basic_payload_builder::{ commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder, PayloadConfig, WithdrawalsOutcome, }; +use reth_chainspec::ChainSpec; use reth_errors::RethError; use reth_evm::{ system_calls::{ @@ -31,6 +32,7 @@ use reth_primitives::{ }, eip4844::calculate_excess_blob_gas, proofs::{self, calculate_requests_root}, + revm_primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, Block, EthereumHardforks, Header, IntoRecoveredTransaction, Receipt, EMPTY_OMMER_ROOT_HASH, U256, }; @@ -243,58 +245,21 @@ where chain_spec: &ChainSpec, parent: &Header, ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - // configure evm env based on parent block - let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); - - // ensure we're not missing any timestamp based hardforks - let spec_id = revm_spec_by_timestamp_after_merge(chain_spec, self.timestamp()); - - // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is - // cancun now, we need to set the excess blob gas to the default value - let blob_excess_gas_and_price = parent - .next_block_excess_blob_gas() - .or_else(|| { - if spec_id == SpecId::CANCUN { - // default excess blob gas is zero - Some(0) - } else { - None - } - }) - .map(BlobExcessGasAndPrice::new); - - let mut basefee = - parent.next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())); - - let mut gas_limit = U256::from(parent.gas_limit); - - // If we are on the London fork boundary, we need to multiply the parent's gas limit by the - // elasticity multiplier to get the new gas limit. - if chain_spec.fork(EthereumHardfork::London).transitions_at_block(parent.number + 1) { - let elasticity_multiplier = - chain_spec.base_fee_params_at_timestamp(self.timestamp()).elasticity_multiplier; - - // multiply the gas limit by the elasticity multiplier - gas_limit *= U256::from(elasticity_multiplier); + let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); + let mut block_env = BlockEnv::default(); - // set the base fee to the initial base fee from the EIP-1559 spec - basefee = Some(EIP1559_INITIAL_BASE_FEE) - } + // TODO (garwah): Change this to a reasonable default or take from somewhere. + let total_difficulty = U256::ZERO; - let block_env = BlockEnv { - number: U256::from(parent.number + 1), - coinbase: self.suggested_fee_recipient(), - timestamp: U256::from(self.timestamp()), - difficulty: U256::ZERO, - prevrandao: Some(self.prev_randao()), - gas_limit, - // calculate basefee based on parent block's gas usage - basefee: basefee.map(U256::from).unwrap_or_default(), - // calculate excess gas based on parent block's blob gas usage - blob_excess_gas_and_price, - }; + self.evm_config.fill_cfg_and_block_env( + &mut cfg_env, + &mut block_env, + &chain_spec, + &parent, + total_difficulty, + ); - (CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env) + (cfg_env, block_env) } } diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index bd57fa685428..7c53d769e8fb 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -226,52 +226,21 @@ where chain_spec: &ChainSpec, parent: &Header, ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - // configure evm env based on parent block - let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); - - // ensure we're not missing any timestamp based hardforks - let spec_id = revm_spec_by_timestamp_after_bedrock(chain_spec, self.timestamp()); - - // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is - // cancun now, we need to set the excess blob gas to the default value - let blob_excess_gas_and_price = parent - .next_block_excess_blob_gas() - .or_else(|| { - if spec_id.is_enabled_in(SpecId::CANCUN) { - // default excess blob gas is zero - Some(0) - } else { - None - } - }) - .map(BlobExcessGasAndPrice::new); + let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); + let mut block_env = BlockEnv::default(); - let block_env = BlockEnv { - number: U256::from(parent.number + 1), - coinbase: self.suggested_fee_recipient(), - timestamp: U256::from(self.timestamp()), - difficulty: U256::ZERO, - prevrandao: Some(self.prev_randao()), - gas_limit: U256::from(parent.gas_limit), - // calculate basefee based on parent block's gas usage - basefee: U256::from( - parent - .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())) - .unwrap_or_default(), - ), - // calculate excess gas based on parent block's blob gas usage - blob_excess_gas_and_price, - }; + // TODO (garwah): Change this to a reasonable default or take from somewhere. + let total_difficulty = U256::ZERO; - let cfg_with_handler_cfg; - { - cfg_with_handler_cfg = CfgEnvWithHandlerCfg { - cfg_env: cfg, - handler_cfg: HandlerCfg { spec_id, is_optimism: true }, - }; - } + self.evm_config.fill_cfg_and_block_env( + &mut cfg_env, + &mut block_env, + &chain_spec, + &parent, + total_difficulty, + ); - (cfg_with_handler_cfg, block_env) + (cfg_env, block_env) } } diff --git a/crates/optimism/payload/src/payload.rs b/crates/optimism/payload/src/payload.rs index 82c33f8f9ff5..9b856acf96ff 100644 --- a/crates/optimism/payload/src/payload.rs +++ b/crates/optimism/payload/src/payload.rs @@ -106,59 +106,6 @@ impl PayloadBuilderAttributes for OptimismPayloadBuilderAttributes { fn withdrawals(&self) -> &Withdrawals { &self.payload_attributes.withdrawals } - - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - // configure evm env based on parent block - let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); - - // ensure we're not missing any timestamp based hardforks - let spec_id = revm_spec_by_timestamp_after_bedrock(chain_spec, self.timestamp()); - - // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is - // cancun now, we need to set the excess blob gas to the default value - let blob_excess_gas_and_price = parent - .next_block_excess_blob_gas() - .or_else(|| { - if spec_id.is_enabled_in(SpecId::CANCUN) { - // default excess blob gas is zero - Some(0) - } else { - None - } - }) - .map(BlobExcessGasAndPrice::new); - - let block_env = BlockEnv { - number: U256::from(parent.number + 1), - coinbase: self.suggested_fee_recipient(), - timestamp: U256::from(self.timestamp()), - difficulty: U256::ZERO, - prevrandao: Some(self.prev_randao()), - gas_limit: U256::from(parent.gas_limit), - // calculate basefee based on parent block's gas usage - basefee: U256::from( - parent - .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())) - .unwrap_or_default(), - ), - // calculate excess gas based on parent block's blob gas usage - blob_excess_gas_and_price, - }; - - let cfg_with_handler_cfg; - { - cfg_with_handler_cfg = CfgEnvWithHandlerCfg { - cfg_env: cfg, - handler_cfg: HandlerCfg { spec_id, is_optimism: true }, - }; - } - - (cfg_with_handler_cfg, block_env) - } } /// Contains the built payload. diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index cf09693e3b44..9582526ffe5e 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -19,7 +19,7 @@ use reth_payload_builder::{ use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ constants::{EMPTY_WITHDRAWALS, RETH_CLIENT_VERSION, SLOT_DURATION}, - proofs, BlockNumberOrTag, Bytes, SealedBlock, Withdrawals, B256, U256, + proofs, BlockNumberOrTag, Bytes, Header, SealedBlock, Withdrawals, B256, U256, }; use reth_provider::{ BlockReaderIdExt, BlockSource, CanonStateNotification, ProviderError, StateProviderFactory, @@ -813,6 +813,21 @@ pub trait PayloadBuilder: Send + Sync + Clone { client: &Client, config: PayloadConfig, ) -> Result; + + /// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the targeted payload + /// (that has the `parent` as its parent). + /// + /// The `chain_spec` is used to determine the correct chain id and hardfork for the payload + /// based on its timestamp. + /// + /// Block related settings are derived from the `parent` block and the configured attributes. + /// + /// NOTE: This is only intended for beacon consensus (after merge). + fn cfg_and_block_env( + &self, + chain_spec: &ChainSpec, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv); } /// Tells the payload builder how to react to payload request if there's no payload available yet. diff --git a/crates/payload/primitives/src/traits.rs b/crates/payload/primitives/src/traits.rs index c173b09c013e..b1fcc9e55b17 100644 --- a/crates/payload/primitives/src/traits.rs +++ b/crates/payload/primitives/src/traits.rs @@ -1,9 +1,6 @@ use reth_chain_state::ExecutedBlock; use reth_chainspec::ChainSpec; -use reth_primitives::{ - revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Address, Header, SealedBlock, Withdrawals, B256, U256, -}; +use reth_primitives::{Address, SealedBlock, Withdrawals, B256, U256}; use reth_rpc_types::{ engine::{OptimismPayloadAttributes, PayloadAttributes as EthPayloadAttributes, PayloadId}, Withdrawal, From 6f960975bf106a787c948cc4c201fb168a006bd1 Mon Sep 17 00:00:00 2001 From: garwah Date: Sun, 25 Aug 2024 21:17:08 +1000 Subject: [PATCH 03/13] tidy --- crates/ethereum/payload/src/lib.rs | 2 -- crates/optimism/payload/src/builder.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index ea56566cb1b2..fa1dc2d127cd 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -247,8 +247,6 @@ where ) -> (CfgEnvWithHandlerCfg, BlockEnv) { let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); let mut block_env = BlockEnv::default(); - - // TODO (garwah): Change this to a reasonable default or take from somewhere. let total_difficulty = U256::ZERO; self.evm_config.fill_cfg_and_block_env( diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 7c53d769e8fb..e5a0f76e2ad4 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -228,8 +228,6 @@ where ) -> (CfgEnvWithHandlerCfg, BlockEnv) { let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); let mut block_env = BlockEnv::default(); - - // TODO (garwah): Change this to a reasonable default or take from somewhere. let total_difficulty = U256::ZERO; self.evm_config.fill_cfg_and_block_env( From a4c6945944fbdcf3c3fea93af5cd37baf3eda310 Mon Sep 17 00:00:00 2001 From: garwah Date: Tue, 27 Aug 2024 21:44:22 +1000 Subject: [PATCH 04/13] fix imports --- Cargo.lock | 1 + crates/ethereum/payload/Cargo.toml | 1 + crates/optimism/payload/src/builder.rs | 6 ++---- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3c40d8afe9a..47cef41bdcb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7256,6 +7256,7 @@ name = "reth-ethereum-payload-builder" version = "1.0.5" dependencies = [ "reth-basic-payload-builder", + "reth-chainspec", "reth-errors", "reth-evm", "reth-evm-ethereum", diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index e41c8a407c33..01ca0a2928d4 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -23,6 +23,7 @@ reth-basic-payload-builder.workspace = true reth-evm.workspace = true reth-evm-ethereum.workspace = true reth-errors.workspace = true +reth-chainspec.workspace = true # ethereum revm.workspace = true diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index e5a0f76e2ad4..ae03919ef7ac 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -4,6 +4,7 @@ use crate::{ error::OptimismPayloadBuilderError, payload::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes}, }; +use reth_chainspec::ChainSpec; use reth_basic_payload_builder::*; use reth_chain_state::ExecutedBlock; use reth_chainspec::{EthereumHardforks, OptimismHardfork}; @@ -11,6 +12,7 @@ use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm}; use reth_execution_types::ExecutionOutcome; use reth_payload_builder::error::PayloadBuilderError; use reth_primitives::{ + revm_primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, constants::{BEACON_NONCE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS}, eip4844::calculate_excess_blob_gas, proofs, Block, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, U256, @@ -93,11 +95,9 @@ where ) -> Result { let extra_data = config.extra_data(); let PayloadConfig { - initialized_block_env, parent_block, attributes, chain_spec, - initialized_cfg, .. } = config; @@ -269,8 +269,6 @@ where State::builder().with_database_ref(cached_reads.as_db(state)).with_bundle_update().build(); let extra_data = config.extra_data(); let PayloadConfig { - initialized_block_env, - initialized_cfg, parent_block, attributes, chain_spec, From 05ccf34c312b6f3f8b008450915b990208600ff0 Mon Sep 17 00:00:00 2001 From: garwah Date: Thu, 29 Aug 2024 22:50:12 +1000 Subject: [PATCH 05/13] default handler_cfg.isoptimism to true in OptimismEvmConfig --- crates/optimism/evm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index b721a1d49250..7ec329b5a9d2 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -106,7 +106,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig { cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; cfg_env.handler_cfg.spec_id = spec_id; - cfg_env.handler_cfg.is_optimism = chain_spec.is_optimism(); + cfg_env.handler_cfg.is_optimism = true; } } From 688d78016867f8d80793132c4c3f9200d4ca121b Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 6 Sep 2024 14:57:56 +0200 Subject: [PATCH 06/13] cleanup crate --- Cargo.lock | 2 -- crates/ethereum/engine-primitives/Cargo.toml | 2 -- crates/ethereum/engine-primitives/src/lib.rs | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 884b38542ed7..79f4e15c2231 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7092,12 +7092,10 @@ dependencies = [ "alloy-rlp", "reth-chainspec", "reth-engine-primitives", - "reth-evm-ethereum", "reth-payload-primitives", "reth-primitives", "reth-rpc-types", "reth-rpc-types-compat", - "revm-primitives", "serde", "serde_json", "sha2 0.10.8", diff --git a/crates/ethereum/engine-primitives/Cargo.toml b/crates/ethereum/engine-primitives/Cargo.toml index 8a1f25808937..bbac8bf6ff93 100644 --- a/crates/ethereum/engine-primitives/Cargo.toml +++ b/crates/ethereum/engine-primitives/Cargo.toml @@ -13,13 +13,11 @@ workspace = true [dependencies] # reth reth-chainspec.workspace = true -reth-evm-ethereum.workspace = true reth-primitives.workspace = true reth-engine-primitives.workspace = true reth-payload-primitives.workspace = true reth-rpc-types.workspace = true reth-rpc-types-compat.workspace = true -revm-primitives.workspace = true alloy-rlp.workspace = true # misc diff --git a/crates/ethereum/engine-primitives/src/lib.rs b/crates/ethereum/engine-primitives/src/lib.rs index fe4a050fa41b..5554beea316f 100644 --- a/crates/ethereum/engine-primitives/src/lib.rs +++ b/crates/ethereum/engine-primitives/src/lib.rs @@ -1,4 +1,4 @@ -//! Ethereum specific +//! Ethereum specific engine API types and impls. #![doc( html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", From ba7679589128cb8fb9e54f0714a86592f52a189f Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 6 Sep 2024 15:02:51 +0200 Subject: [PATCH 07/13] fn --- crates/ethereum/payload/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 8a4cb5dd7506..6c761d2dd776 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -69,6 +69,8 @@ impl Default for EthereumPayloadBuilder { } } +impl EthereumPayloadBuilder where EvmConfig: ConfigureEvm {} + // Default implementation of [PayloadBuilder] for unit type impl PayloadBuilder for EthereumPayloadBuilder where From bdfa489fb9a0d7d582a7b1009c0c7c4b9a8d88dc Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 10 Sep 2024 13:00:49 +0200 Subject: [PATCH 08/13] lock --- Cargo.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c9a5a8545f0..b1eacf22256f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7102,12 +7102,10 @@ dependencies = [ "reth-chain-state", "reth-chainspec", "reth-engine-primitives", - "reth-evm-ethereum", "reth-payload-primitives", "reth-primitives", "reth-rpc-types", "reth-rpc-types-compat", - "revm-primitives", "serde", "serde_json", "sha2 0.10.8", @@ -7138,6 +7136,7 @@ version = "1.0.6" dependencies = [ "reth-basic-payload-builder", "reth-chain-state", + "reth-chainspec", "reth-errors", "reth-evm", "reth-evm-ethereum", From 6c4a0e9e90c8d47e03b79d307c2cb2e89d436521 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 17 Sep 2024 12:57:51 +0200 Subject: [PATCH 09/13] feat: rm cfg_and_block_env from trait and move to impl --- Cargo.lock | 1 + .../ethereum/engine-primitives/src/payload.rs | 6 +- crates/ethereum/payload/Cargo.toml | 1 + crates/ethereum/payload/src/lib.rs | 128 +++++++++++++----- crates/evm/src/lib.rs | 7 +- crates/optimism/payload/src/builder.rs | 115 +++++++++++----- crates/optimism/payload/src/payload.rs | 6 +- crates/payload/basic/src/lib.rs | 22 +-- 8 files changed, 186 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3379ccb7c6a0..b93a294ef9ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7169,6 +7169,7 @@ dependencies = [ "reth-evm-ethereum", "reth-execution-types", "reth-payload-builder", + "reth-payload-primitives", "reth-primitives", "reth-provider", "reth-revm", diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index c7e344c0442e..c3edab111f85 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -2,12 +2,8 @@ use alloy_rlp::Encodable; use reth_chain_state::ExecutedBlock; -use reth_chainspec::ChainSpec; -use reth_evm_ethereum::revm_spec_by_timestamp_after_merge; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; -use reth_primitives::{ - Address, BlobTransactionSidecar, Receipt, SealedBlock, Withdrawals, B256, U256, -}; +use reth_primitives::{Address, BlobTransactionSidecar, SealedBlock, Withdrawals, B256, U256}; use reth_rpc_types::engine::{ ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, ExecutionPayloadV1, PayloadAttributes, PayloadId, diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index 0c648c4304b2..82919e73f1a1 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -18,6 +18,7 @@ reth-revm.workspace = true reth-transaction-pool.workspace = true reth-provider.workspace = true reth-payload-builder.workspace = true +reth-payload-primitives.workspace = true reth-execution-types.workspace = true reth-basic-payload-builder.workspace = true reth-evm.workspace = true diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index b8daef7167f7..07bd53c35f3c 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -14,6 +14,7 @@ use reth_basic_payload_builder::{ PayloadConfig, WithdrawalsOutcome, }; use reth_chain_state::ExecutedBlock; +use reth_chainspec::EthereumHardfork; use reth_errors::RethError; use reth_evm::{ system_calls::{ @@ -23,13 +24,16 @@ use reth_evm::{ }, ConfigureEvm, }; -use reth_evm_ethereum::{eip6110::parse_deposits_from_receipts, EthEvmConfig}; +use reth_evm_ethereum::{ + eip6110::parse_deposits_from_receipts, revm_spec_by_timestamp_after_merge, EthEvmConfig, +}; use reth_execution_types::ExecutionOutcome; use reth_payload_builder::{ error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, }; +use reth_payload_primitives::PayloadBuilderAttributes; use reth_primitives::{ - constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, + constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE, EIP1559_INITIAL_BASE_FEE}, eip4844::calculate_excess_blob_gas, proofs::{self, calculate_requests_root}, revm_primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, @@ -44,7 +48,9 @@ use reth_transaction_pool::{ use reth_trie::HashedPostState; use revm::{ db::states::bundle_state::BundleRetention, - primitives::{EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState}, + primitives::{ + BlobExcessGasAndPrice, EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState, + }, DatabaseCommit, State, }; use std::sync::Arc; @@ -64,6 +70,84 @@ impl EthereumPayloadBuilder { } } +impl EthereumPayloadBuilder +where + EvmConfig: ConfigureEvm, +{ + /// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the targeted payload + /// (that has the `parent` as its parent). + /// + /// The `chain_spec` is used to determine the correct chain id and hardfork for the payload + /// based on its timestamp. + /// + /// Block related settings are derived from the `parent` block and the configured attributes. + /// + /// NOTE: This is only intended for beacon consensus (after merge). + fn cfg_and_block_env( + &self, + config: &PayloadConfig, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + // configure evm env based on parent block + let cfg = CfgEnv::default(); + + // ensure we're not missing any timestamp based hardforks + let spec_id = + revm_spec_by_timestamp_after_merge(&config.chain_spec, config.attributes.timestamp()); + + // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is + // cancun now, we need to set the excess blob gas to the default value + let blob_excess_gas_and_price = parent + .next_block_excess_blob_gas() + .or_else(|| { + if spec_id == SpecId::CANCUN { + // default excess blob gas is zero + Some(0) + } else { + None + } + }) + .map(BlobExcessGasAndPrice::new); + + let mut basefee = parent.next_block_base_fee( + config.chain_spec.base_fee_params_at_timestamp(config.attributes.timestamp()), + ); + + let mut gas_limit = U256::from(parent.gas_limit); + + // If we are on the London fork boundary, we need to multiply the parent's gas limit by the + // elasticity multiplier to get the new gas limit. + if config.chain_spec.fork(EthereumHardfork::London).transitions_at_block(parent.number + 1) + { + let elasticity_multiplier = config + .chain_spec + .base_fee_params_at_timestamp(config.attributes.timestamp()) + .elasticity_multiplier; + + // multiply the gas limit by the elasticity multiplier + gas_limit *= U256::from(elasticity_multiplier); + + // set the base fee to the initial base fee from the EIP-1559 spec + basefee = Some(EIP1559_INITIAL_BASE_FEE) + } + + let block_env = BlockEnv { + number: U256::from(parent.number + 1), + coinbase: config.attributes.suggested_fee_recipient(), + timestamp: U256::from(config.attributes.timestamp()), + difficulty: U256::ZERO, + prevrandao: Some(config.attributes.prev_randao()), + gas_limit, + // calculate basefee based on parent block's gas usage + basefee: basefee.map(U256::from).unwrap_or_default(), + // calculate excess gas based on parent block's blob gas usage + blob_excess_gas_and_price, + }; + + (CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env) + } +} + // Default implementation of [PayloadBuilder] for unit type impl PayloadBuilder for EthereumPayloadBuilder where @@ -78,7 +162,8 @@ where &self, args: BuildArguments, ) -> Result, PayloadBuilderError> { - default_ethereum_payload(self.evm_config.clone(), args) + let (cfg_env, block_env) = self.cfg_and_block_env(&args.config, &args.config.parent_block); + default_ethereum_payload(self.evm_config.clone(), args, cfg_env, block_env) } fn build_empty_payload( @@ -95,30 +180,11 @@ where cancel: Default::default(), best_payload: None, }; - default_ethereum_payload(self.evm_config.clone(), args)? + let (cfg_env, block_env) = self.cfg_and_block_env(&args.config, &args.config.parent_block); + default_ethereum_payload(self.evm_config.clone(), args, cfg_env, block_env)? .into_payload() .ok_or_else(|| PayloadBuilderError::MissingPayload) } - - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); - let mut block_env = BlockEnv::default(); - let total_difficulty = U256::ZERO; - - self.evm_config.fill_cfg_and_block_env( - &mut cfg_env, - &mut block_env, - &chain_spec, - &parent, - total_difficulty, - ); - - (cfg_env, block_env) - } } /// Constructs an Ethereum transaction payload using the best transactions from the pool. @@ -130,6 +196,8 @@ where pub fn default_ethereum_payload( evm_config: EvmConfig, args: BuildArguments, + initialized_cfg: CfgEnvWithHandlerCfg, + initialized_block_env: BlockEnv, ) -> Result, PayloadBuilderError> where EvmConfig: ConfigureEvm, @@ -142,15 +210,7 @@ where let state = StateProviderDatabase::new(state_provider); let mut db = State::builder().with_database_ref(cached_reads.as_db(state)).with_bundle_update().build(); - let extra_data = config.extra_data(); - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - attributes, - chain_spec, - .. - } = config; + let PayloadConfig { parent_block, extra_data, attributes, chain_spec } = config; debug!(target: "payload_builder", id=%attributes.id, parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); let mut cumulative_gas_used = 0; diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 2c8e26cd7cfb..62dc8807f17b 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -127,7 +127,10 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { data: Bytes, ); - /// Fill [`CfgEnvWithHandlerCfg`] fields according to the chain spec and given header + /// Fill [`CfgEnvWithHandlerCfg`] fields according to the chain spec and given header. + /// + /// This must set the corresponding spec id in the handler cfg, based on timestamp or total + /// difficulty fn fill_cfg_env( &self, cfg_env: &mut CfgEnvWithHandlerCfg, @@ -158,6 +161,8 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { /// Convenience function to call both [`fill_cfg_env`](ConfigureEvmEnv::fill_cfg_env) and /// [`ConfigureEvmEnv::fill_block_env`]. + /// + /// Note: Implementors should ensure that all fields are required fields are filled. fn fill_cfg_and_block_env( &self, cfg: &mut CfgEnvWithHandlerCfg, diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 3dfc63a94550..ac52a5e17f45 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -7,16 +7,18 @@ use crate::{ use alloy_primitives::U256; use reth_basic_payload_builder::*; use reth_chain_state::ExecutedBlock; -use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardfork}; +use reth_chainspec::{EthereumHardforks, OptimismHardfork}; use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm}; +use reth_evm_optimism::revm_spec_by_timestamp_after_bedrock; use reth_execution_types::ExecutionOutcome; use reth_payload_builder::error::PayloadBuilderError; +use reth_payload_primitives::PayloadBuilderAttributes; use reth_primitives::{ - constants::{BEACON_NONCE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS}, + constants::BEACON_NONCE, eip4844::calculate_excess_blob_gas, proofs, revm_primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, - Block, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, U256, + Block, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, }; use reth_provider::StateProviderFactory; use reth_revm::database::StateProviderDatabase; @@ -26,7 +28,10 @@ use reth_transaction_pool::{ use reth_trie::HashedPostState; use revm::{ db::states::bundle_state::BundleRetention, - primitives::{EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState}, + primitives::{ + BlobExcessGasAndPrice, EVMError, EnvWithHandlerCfg, HandlerCfg, InvalidTransaction, + ResultAndState, + }, DatabaseCommit, State, }; use std::sync::Arc; @@ -63,6 +68,64 @@ impl OptimismPayloadBuilder { pub const fn is_compute_pending_block(&self) -> bool { self.compute_pending_block } + + fn cfg_and_block_env( + &self, + config: &PayloadConfig, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + // configure evm env based on parent block + let cfg = CfgEnv::default(); + + // ensure we're not missing any timestamp based hardforks + let spec_id = + revm_spec_by_timestamp_after_bedrock(&config.chain_spec, config.attributes.timestamp()); + + // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is + // cancun now, we need to set the excess blob gas to the default value + let blob_excess_gas_and_price = parent + .next_block_excess_blob_gas() + .or_else(|| { + if spec_id.is_enabled_in(SpecId::CANCUN) { + // default excess blob gas is zero + Some(0) + } else { + None + } + }) + .map(BlobExcessGasAndPrice::new); + + let block_env = BlockEnv { + number: U256::from(parent.number + 1), + coinbase: config.attributes.suggested_fee_recipient(), + timestamp: U256::from(config.attributes.timestamp()), + difficulty: U256::ZERO, + prevrandao: Some(config.attributes.prev_randao()), + gas_limit: U256::from(parent.gas_limit), + // calculate basefee based on parent block's gas usage + basefee: U256::from( + parent + .next_block_base_fee( + config + .chain_spec + .base_fee_params_at_timestamp(config.attributes.timestamp()), + ) + .unwrap_or_default(), + ), + // calculate excess gas based on parent block's blob gas usage + blob_excess_gas_and_price, + }; + + let cfg_with_handler_cfg; + { + cfg_with_handler_cfg = CfgEnvWithHandlerCfg { + cfg_env: cfg, + handler_cfg: HandlerCfg { spec_id, is_optimism: true }, + }; + } + + (cfg_with_handler_cfg, block_env) + } } /// Implementation of the [`PayloadBuilder`] trait for [`OptimismPayloadBuilder`]. @@ -79,7 +142,14 @@ where &self, args: BuildArguments, ) -> Result, PayloadBuilderError> { - optimism_payload(self.evm_config.clone(), args, self.compute_pending_block) + let (cfg_env, block_env) = self.cfg_and_block_env(&args.config, &args.config.parent_block); + optimism_payload( + self.evm_config.clone(), + args, + cfg_env, + block_env, + self.compute_pending_block, + ) } fn on_missing_payload( @@ -107,30 +177,11 @@ where cancel: Default::default(), best_payload: None, }; - optimism_payload(self.evm_config.clone(), args, false)? + let (cfg_env, block_env) = self.cfg_and_block_env(&args.config, &args.config.parent_block); + optimism_payload(self.evm_config.clone(), args, cfg_env, block_env, false)? .into_payload() .ok_or_else(|| PayloadBuilderError::MissingPayload) } - - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); - let mut block_env = BlockEnv::default(); - let total_difficulty = U256::ZERO; - - self.evm_config.fill_cfg_and_block_env( - &mut cfg_env, - &mut block_env, - &chain_spec, - &parent, - total_difficulty, - ); - - (cfg_env, block_env) - } } /// Constructs an Ethereum transaction payload from the transactions sent through the @@ -145,6 +196,8 @@ where pub(crate) fn optimism_payload( evm_config: EvmConfig, args: BuildArguments, + initialized_cfg: CfgEnvWithHandlerCfg, + initialized_block_env: BlockEnv, _compute_pending_block: bool, ) -> Result, PayloadBuilderError> where @@ -158,15 +211,7 @@ where let state = StateProviderDatabase::new(state_provider); let mut db = State::builder().with_database_ref(cached_reads.as_db(state)).with_bundle_update().build(); - let extra_data = config.extra_data(); - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - attributes, - chain_spec, - .. - } = config; + let PayloadConfig { parent_block, attributes, chain_spec, extra_data } = config; debug!(target: "payload_builder", id=%attributes.payload_attributes.payload_id(), parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); diff --git a/crates/optimism/payload/src/payload.rs b/crates/optimism/payload/src/payload.rs index 61fde7d69631..2acf875a56e2 100644 --- a/crates/optimism/payload/src/payload.rs +++ b/crates/optimism/payload/src/payload.rs @@ -6,13 +6,10 @@ use alloy_primitives::{Address, B256, U256}; use alloy_rlp::Encodable; use reth_chain_state::ExecutedBlock; use reth_chainspec::{ChainSpec, EthereumHardforks}; -use reth_evm_optimism::revm_spec_by_timestamp_after_bedrock; use reth_payload_builder::EthPayloadBuilderAttributes; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ - revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, - transaction::WithEncoded, - BlobTransactionSidecar, Header, SealedBlock, TransactionSigned, Withdrawals, + transaction::WithEncoded, BlobTransactionSidecar, SealedBlock, TransactionSigned, Withdrawals, }; /// Re-export for use in downstream arguments. pub use reth_rpc_types::optimism::OptimismPayloadAttributes; @@ -24,7 +21,6 @@ use reth_rpc_types_compat::engine::payload::{ block_to_payload_v1, block_to_payload_v3, block_to_payload_v4, convert_block_to_payload_field_v2, }; -use revm::primitives::HandlerCfg; use std::sync::Arc; /// Optimism Payload Builder Attributes diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index dcbff01bb71e..6c17157547bc 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -19,7 +19,7 @@ use reth_payload_builder::{ use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ constants::{EMPTY_WITHDRAWALS, RETH_CLIENT_VERSION, SLOT_DURATION}, - proofs, BlockNumberOrTag, Bytes, Header, SealedBlock, Withdrawals, B256, U256, + proofs, BlockNumberOrTag, Bytes, SealedBlock, Withdrawals, B256, U256, }; use reth_provider::{ BlockReaderIdExt, BlockSource, CanonStateNotification, ProviderError, StateProviderFactory, @@ -27,10 +27,7 @@ use reth_provider::{ use reth_revm::state_change::post_block_withdrawals_balance_increments; use reth_tasks::TaskSpawner; use reth_transaction_pool::TransactionPool; -use revm::{ - primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Database, State, -}; +use revm::{Database, State}; use std::{ fmt, future::Future, @@ -852,21 +849,6 @@ pub trait PayloadBuilder: Send + Sync + Clone { client: &Client, config: PayloadConfig, ) -> Result; - - /// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the targeted payload - /// (that has the `parent` as its parent). - /// - /// The `chain_spec` is used to determine the correct chain id and hardfork for the payload - /// based on its timestamp. - /// - /// Block related settings are derived from the `parent` block and the configured attributes. - /// - /// NOTE: This is only intended for beacon consensus (after merge). - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv); } /// Tells the payload builder how to react to payload request if there's no payload available yet. From bcd225bb4438785fb319772a5b9afaaac4b6bef4 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 17 Sep 2024 12:59:59 +0200 Subject: [PATCH 10/13] lint --- crates/payload/basic/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 6c17157547bc..b565e37fe39d 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -692,7 +692,7 @@ where Attributes: PayloadBuilderAttributes, { /// Create new payload config. - pub fn new( + pub const fn new( parent_block: Arc, extra_data: Bytes, attributes: Attributes, From 3ec7405c4a52e152afc97a375326bb0a002b117b Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 17 Sep 2024 13:01:10 +0200 Subject: [PATCH 11/13] spelling --- crates/evm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 62dc8807f17b..04f476143ed3 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -162,7 +162,7 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { /// Convenience function to call both [`fill_cfg_env`](ConfigureEvmEnv::fill_cfg_env) and /// [`ConfigureEvmEnv::fill_block_env`]. /// - /// Note: Implementors should ensure that all fields are required fields are filled. + /// Note: Implementers should ensure that all fields are required fields are filled. fn fill_cfg_and_block_env( &self, cfg: &mut CfgEnvWithHandlerCfg, From 8bb6206004a6148ac351b0a6b4de126a4b478ecb Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 17 Sep 2024 13:08:01 +0200 Subject: [PATCH 12/13] fix issues --- examples/custom-engine-types/src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index 10cbe799837c..b6bccd2beb1d 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -30,7 +30,6 @@ use reth::{ node::{NodeTypes, NodeTypesWithEngine}, BuilderContext, FullNodeTypes, Node, NodeBuilder, PayloadBuilderConfig, }, - primitives::revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, providers::{CanonStateSubscriptions, StateProviderFactory}, tasks::TaskManager, transaction_pool::TransactionPool, @@ -56,7 +55,7 @@ use reth_payload_builder::{ error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle, PayloadBuilderService, }; -use reth_primitives::{Address, Header, Withdrawals, B256}; +use reth_primitives::{Address, Withdrawals, B256}; use reth_rpc_types::{ engine::{ ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, @@ -314,7 +313,7 @@ where config: PayloadConfig, ) -> Result { let PayloadConfig { parent_block, extra_data, attributes, chain_spec } = config; - >::build_empty_payload(&reth_ethereum_payload_builder::EthereumPayloadBuilder::default(),client, + >::build_empty_payload(&reth_ethereum_payload_builder::EthereumPayloadBuilder::new(EthEvmConfig::new(chain_spec.clone())),client, PayloadConfig { parent_block, extra_data, attributes: attributes.0, chain_spec }) } } From 76216a423dc1ce768511da1fe35207aec0e3613c Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 17 Sep 2024 13:32:20 +0200 Subject: [PATCH 13/13] fix chain id issue --- crates/ethereum/payload/src/lib.rs | 2 +- crates/optimism/payload/src/builder.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 07bd53c35f3c..bc32c445311d 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -89,7 +89,7 @@ where parent: &Header, ) -> (CfgEnvWithHandlerCfg, BlockEnv) { // configure evm env based on parent block - let cfg = CfgEnv::default(); + let cfg = CfgEnv::default().with_chain_id(config.chain_spec.chain().id()); // ensure we're not missing any timestamp based hardforks let spec_id = diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index ac52a5e17f45..a949e99916dd 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -75,7 +75,7 @@ impl OptimismPayloadBuilder { parent: &Header, ) -> (CfgEnvWithHandlerCfg, BlockEnv) { // configure evm env based on parent block - let cfg = CfgEnv::default(); + let cfg = CfgEnv::default().with_chain_id(config.chain_spec.chain().id()); // ensure we're not missing any timestamp based hardforks let spec_id =