From 4cb7931b2c0ae031a032200c1ae550eda59b3e2c Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 4 Dec 2025 15:41:30 +0100 Subject: [PATCH] Etherlink/Kernel: fix sub block entrypoints to avoid discrepancies - Fix gas limit of the block. - Fix indexes of transaction objects and receipts. - Fix gas used in transaction objects and receipts. - Clean receipts and objects in-between blocks. --- .../kernel_latest/kernel/src/sub_block.rs | 89 +++++++++++-------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/etherlink/kernel_latest/kernel/src/sub_block.rs b/etherlink/kernel_latest/kernel/src/sub_block.rs index 75a8c3adc4bf..a05c687e0f60 100644 --- a/etherlink/kernel_latest/kernel/src/sub_block.rs +++ b/etherlink/kernel_latest/kernel/src/sub_block.rs @@ -5,6 +5,7 @@ use crate::{ apply::{pure_fa_deposit, revm_run_transaction}, + block::GAS_LIMIT, block_storage, bridge::{execute_etherlink_deposit, DepositResult}, chains::{ChainConfigTrait, EvmChainConfig, ETHERLINK_SAFE_STORAGE_ROOT_PATH}, @@ -38,9 +39,9 @@ use tezos_ethereum::{ }, }; use tezos_evm_logging::__trace_kernel_add_attrs; -use tezos_evm_runtime::{runtime::Runtime, safe_storage::SafeStorage}; +use tezos_evm_runtime::runtime::Runtime; use tezos_smart_rollup::{host::RuntimeError, types::Timestamp}; -use tezos_smart_rollup_host::path::{OwnedPath, RefPath}; +use tezos_smart_rollup_host::path::RefPath; use tezos_tracing::trace_kernel; const SINGLE_TX_EXECUTION_INPUT: RefPath = @@ -142,30 +143,26 @@ fn get_evm_config(host: &mut Host) -> Result( - host: &'a mut Host, - config: &EvmChainConfig, -) -> SafeStorage<&'a mut Host> { - SafeStorage { - host, - world_state: OwnedPath::from(&config.storage_root_path()), - } -} - struct IterReceiptData { last_log: usize, current_cumulative_gas: U256, } fn get_iter_receipt_data(receipts: &[TransactionReceipt]) -> IterReceiptData { - let mut current_cumulative_gas = U256::zero(); let mut last_log = 0; for receipt in receipts { - current_cumulative_gas += receipt.cumulative_gas_used; last_log += receipt.logs.len(); } + let current_cumulative_gas = match receipts.last() { + Some(TransactionReceipt { + cumulative_gas_used, + .. + }) => *cumulative_gas_used, + None => U256::zero(), + }; + IterReceiptData { last_log, current_cumulative_gas, @@ -277,6 +274,15 @@ fn handle_receipt( ) -> Result<(), Error> { let mut receipts = get_current_transaction_receipts(host)?; + // We might be handling a new block since last execution. + // In this case, we need to empty the receipts before adding the + // new one. + if !receipts.is_empty() + && receipts.first().unwrap().block_number != input_data.block_number + { + receipts = vec![]; + } + let IterReceiptData { last_log, current_cumulative_gas, @@ -307,7 +313,8 @@ fn handle_receipt( let receipt = TransactionReceipt { hash: input_data.tx.tx_hash, - index: (receipts.len() + 1) + index: receipts + .len() .try_into() .map_err(|_| Error::InvalidConversion)?, block_number: input_data.block_number, @@ -334,20 +341,30 @@ fn handle_transaction_object( from: H160, input_data: &SingleTxExecutionInput, gas_price: U256, - result_data: &ResultData, + gas: U256, ) -> Result<(), Error> { let mut txs_objects = get_current_transactions_objects(host)?; + // We might be handling a new block since last execution. + // In this case, we need to empty the txs objects before adding the + // new one. + if !txs_objects.is_empty() + && txs_objects.first().unwrap().block_number != input_data.block_number + { + txs_objects = vec![]; + } + let tx_object = TransactionObject { block_number: input_data.block_number, from, - gas_used: result_data.gas_used.into(), + gas_used: gas, gas_price, hash: input_data.tx.tx_hash, input: input_data.tx.data(), nonce: input_data.tx.nonce(), to: input_data.tx.to()?, - index: (txs_objects.len() + 1) + index: txs_objects + .len() .try_into() .map_err(|_| Error::InvalidConversion)?, value: input_data.tx.value(), @@ -375,7 +392,7 @@ fn block_constants( number, coinbase, timestamp: timestamp.as_u64().into(), - gas_limit: config.get_limits().maximum_gas_limit, + gas_limit: GAS_LIMIT, block_fees, chain_id: config.get_chain_id(), prevrandao: None, @@ -386,6 +403,7 @@ struct RunOutcome { result: ExecutionResult, caller: H160, receipt_data: ReceiptData, + gas: Option, } #[trace_kernel] @@ -415,28 +433,20 @@ pub fn handle_run_transaction( __trace_kernel_add_attrs!(host, __attrs); let config = get_evm_config(host)?; - // Safe storage isn't necessary as it can be managed by the node - // but using it on kernel allow us to make cache and in-memory in it. - // See !19515. - let mut safe_host = get_evm_safe_host(host, &config); - safe_host.start()?; - let block_constants = block_constants( - &mut safe_host, - &config, - input_data.timestamp, - input_data.block_number, - )?; + let block_constants = + block_constants(host, &config, input_data.timestamp, input_data.block_number)?; let RunOutcome { result, caller, receipt_data, + gas, } = match &input_data.tx.content { TransactionContent::Ethereum(ethx) | TransactionContent::EthereumDelayed(ethx) => { let caller = ethx.caller().map_err(|_| Error::InvalidSignatureCheck)?; let ExecutionOutcome { result, .. } = revm_run_transaction( - &mut safe_host, + host, &block_constants, Some(input_data.tx.tx_hash), caller, @@ -465,11 +475,12 @@ pub fn handle_run_transaction( to: ethx.to, type_: ethx.type_, }, + gas: Some(ethx.gas_limit_with_fees().into()), } } TransactionContent::Deposit(deposit) => { - let DepositResult { outcome, .. } = - execute_etherlink_deposit(&mut safe_host, deposit).map_err(|e| { + let DepositResult { outcome, .. } = execute_etherlink_deposit(host, deposit) + .map_err(|e| { Error::InvalidRunTransaction(revm_etherlink::Error::Custom( e.to_string(), )) @@ -486,11 +497,12 @@ pub fn handle_run_transaction( to: Some(receiver), type_: TransactionType::Legacy, }, + gas: None, } } TransactionContent::FaDeposit(fa_deposit) => { let outcome = pure_fa_deposit( - &mut safe_host, + host, fa_deposit, &block_constants, input_data.tx.tx_hash, @@ -506,6 +518,7 @@ pub fn handle_run_transaction( to: Some(fa_deposit.receiver), type_: TransactionType::Legacy, }, + gas: None, } } }; @@ -516,6 +529,7 @@ pub fn handle_run_transaction( .tx .content .fee_updates(&block_constants.block_fees, result_data.gas_used.into()); + fee_updates .apply(host, caller, Some(block_constants.coinbase)) .map_err(|_| { @@ -524,8 +538,6 @@ pub fn handle_run_transaction( )) })?; - // Don't pass `safe_host` because we don't want this to be cached - // but we still want it to be accessible by the node. handle_receipt( host, &input_data, @@ -540,7 +552,10 @@ pub fn handle_run_transaction( caller, &input_data, block_constants.base_fee_per_gas(), - &result_data, + match gas { + Some(gas) => gas, + None => fee_updates.overall_gas_used, + }, ) } -- GitLab