From 68f78ae0a4c2b351f2fe36236164d07933d0d4d5 Mon Sep 17 00:00:00 2001 From: Wolfgang Welz Date: Thu, 12 Oct 2023 19:57:30 +0200 Subject: [PATCH] fix: Optimism execution (#789) * use l2 base fee * use optimism handler when activated * fix panic for eth execution with optimism flag * use is_none * address review comments --- crates/revm/src/evm_impl.rs | 43 +++++++++++------------ crates/revm/src/handler/optimism.rs | 9 +++-- crates/revm/src/optimism.rs | 54 +++++++++++++---------------- 3 files changed, 50 insertions(+), 56 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index f59aadcb3e..4a3dd68379 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -216,34 +216,23 @@ impl<'a, GSPEC: Spec + 'static, DB: Database> Transact for EVMImpl<'a let tx_data = env.tx.data.clone(); let tx_gas_limit = env.tx.gas_limit; + // the L1-cost fee is only computed for Optimism non-deposit transactions. #[cfg(feature = "optimism")] - let tx_l1_cost = { - let is_deposit = env.tx.optimism.source_hash.is_some(); - + let tx_l1_cost = if env.cfg.optimism && env.tx.optimism.source_hash.is_none() { let l1_block_info = - optimism::L1BlockInfo::try_fetch(self.data.db, self.data.env.cfg.optimism) - .map_err(EVMError::Database)?; - - // Perform this calculation optimistically to avoid cloning the enveloped tx. - let tx_l1_cost = l1_block_info.as_ref().map(|l1_block_info| { - env.tx - .optimism - .enveloped_tx - .as_ref() - .map(|enveloped_tx| { - l1_block_info.calculate_tx_l1_cost::(enveloped_tx, is_deposit) - }) - .unwrap_or(U256::ZERO) - }); - // storage l1 block info for later use. - self.data.l1_block_info = l1_block_info; + optimism::L1BlockInfo::try_fetch(self.data.db).map_err(EVMError::Database)?; - // - let Some(tx_l1_cost) = tx_l1_cost else { - panic!("[OPTIMISM] L1 Block Info could not be loaded from the DB.") + let Some(enveloped_tx) = &env.tx.optimism.enveloped_tx else { + panic!("[OPTIMISM] Failed to load enveloped transaction."); }; + let tx_l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx); + + // storage l1 block info for later use. + self.data.l1_block_info = Some(l1_block_info); tx_l1_cost + } else { + U256::ZERO }; let initial_gas_spend = initial_tx_gas::( @@ -444,6 +433,14 @@ impl<'a, GSPEC: Spec + 'static, DB: Database> EVMImpl<'a, GSPEC, DB> { } else { InstructionTables::Plain(Arc::new(make_instruction_table::())) }; + #[cfg(feature = "optimism")] + let handler = if env.cfg.optimism { + Handler::optimism::() + } else { + Handler::mainnet::() + }; + #[cfg(not(feature = "optimism"))] + let handler = Handler::mainnet::(); Self { data: EVMData { @@ -457,7 +454,7 @@ impl<'a, GSPEC: Spec + 'static, DB: Database> EVMImpl<'a, GSPEC, DB> { }, inspector, instruction_table, - handler: Handler::mainnet::(), + handler, _phantomdata: PhantomData {}, } } diff --git a/crates/revm/src/handler/optimism.rs b/crates/revm/src/handler/optimism.rs index b178157683..b5f6b305cc 100644 --- a/crates/revm/src/handler/optimism.rs +++ b/crates/revm/src/handler/optimism.rs @@ -112,7 +112,7 @@ pub fn reward_beneficiary( panic!("[OPTIMISM] Failed to load enveloped transaction."); }; - let l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx, is_deposit); + let l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx); // Send the L1 cost of the transaction to the L1 Fee Vault. let Ok((l1_fee_vault_account, _)) = data @@ -132,8 +132,11 @@ pub fn reward_beneficiary( panic!("[OPTIMISM] Failed to load Base Fee Vault account"); }; base_fee_vault_account.mark_touch(); - base_fee_vault_account.info.balance += - l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); + base_fee_vault_account.info.balance += data + .env + .block + .basefee + .mul(U256::from(gas.spend() - gas_refund)); } Ok(()) } diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 09323d8a25..e6d1f093c8 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -41,23 +41,17 @@ pub struct L1BlockInfo { } impl L1BlockInfo { - pub fn try_fetch( - db: &mut DB, - is_optimism: bool, - ) -> Result, DB::Error> { - is_optimism - .then(|| { - let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; - let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; - let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; - - Ok(L1BlockInfo { - l1_base_fee, - l1_fee_overhead, - l1_fee_scalar, - }) - }) - .map_or(Ok(None), |v| v.map(Some)) + /// Try to fetch the L1 block info from the database. + pub fn try_fetch(db: &mut DB) -> Result { + let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; + let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; + + Ok(L1BlockInfo { + l1_base_fee, + l1_fee_overhead, + l1_fee_scalar, + }) } /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero @@ -83,19 +77,18 @@ impl L1BlockInfo { } /// Calculate the gas cost of a transaction based on L1 block data posted on L2 - pub fn calculate_tx_l1_cost(&self, input: &Bytes, is_deposit: bool) -> U256 { - let rollup_data_gas_cost = self.data_gas::(input); - - if is_deposit || rollup_data_gas_cost == U256::ZERO { + pub fn calculate_tx_l1_cost(&self, input: &Bytes) -> U256 { + // If the input is not a deposit transaction, the default value is zero. + if input.is_empty() || input.first() == Some(&0x7F) { return U256::ZERO; } + let rollup_data_gas_cost = self.data_gas::(input); rollup_data_gas_cost .saturating_add(self.l1_fee_overhead) .saturating_mul(self.l1_base_fee) .saturating_mul(self.l1_fee_scalar) - .checked_div(U256::from(1_000_000)) - .unwrap_or_default() + / U256::from(1_000_000) } } @@ -160,17 +153,18 @@ mod tests { l1_fee_scalar: U256::from(1_000), }; - // The gas cost here should be zero since the tx is a deposit let input = bytes!("FACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, true); - assert_eq!(gas_cost, U256::ZERO); - - let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, false); + let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input); assert_eq!(gas_cost, U256::from(1048)); - // Zero rollup data gas cost should result in zero for non-deposits + // Zero rollup data gas cost should result in zero let input = bytes!(""); - let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, false); + let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input); + assert_eq!(gas_cost, U256::ZERO); + + // Deposit transactions with the EIP-2718 type of 0x7F should result in zero + let input = bytes!("7FFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input); assert_eq!(gas_cost, U256::ZERO); } }