From d1b59e9ba588f072b08b1b6d52140f593b8e443b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Rodr=C3=ADguez?= Date: Thu, 26 Sep 2024 13:28:25 -0300 Subject: [PATCH] feat: return actual gas charged to the transaction caller for zkVM transactions (#592) --- crates/cheatcodes/src/inspector.rs | 104 ++++++++++++++------------- crates/zksync/core/src/vm/inspect.rs | 16 +++-- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index ce7dc31ae..2ae18a78f 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -990,9 +990,7 @@ impl Cheatcodes { gas_limit: input.gas_limit(), }; - // We currently exhaust the entire gas for the call as zkEVM returns a very high - // amount of gas that OOGs revm. - let gas = Gas::new(input.gas_limit()); + let mut gas = Gas::new(input.gas_limit()); match foundry_zksync_core::vm::create::<_, DatabaseError>( &create_inputs, zk_contract, @@ -1034,32 +1032,38 @@ impl Cheatcodes { } match result.execution_result { - ExecutionResult::Success { output, .. } => match output { - Output::Create(bytes, address) => Some(CreateOutcome { - result: InterpreterResult { - result: InstructionResult::Return, - output: bytes, - gas, - }, - address, - }), - _ => Some(CreateOutcome { + ExecutionResult::Success { output, gas_used, .. } => { + let _ = gas.record_cost(gas_used); + match output { + Output::Create(bytes, address) => Some(CreateOutcome { + result: InterpreterResult { + result: InstructionResult::Return, + output: bytes, + gas, + }, + address, + }), + _ => Some(CreateOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: Bytes::new(), + gas, + }, + address: None, + }), + } + } + ExecutionResult::Revert { output, gas_used, .. } => { + let _ = gas.record_cost(gas_used); + Some(CreateOutcome { result: InterpreterResult { result: InstructionResult::Revert, - output: Bytes::new(), + output, gas, }, address: None, - }), - }, - ExecutionResult::Revert { output, .. } => Some(CreateOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output, - gas, - }, - address: None, - }), + }) + } ExecutionResult::Halt { .. } => Some(CreateOutcome { result: InterpreterResult { result: InstructionResult::Revert, @@ -1575,9 +1579,7 @@ impl Cheatcodes { paymaster_data: self.paymaster_params.take(), }; - // We currently exhaust the entire gas for the call as zkEVM returns a very high amount - // of gas that OOGs revm. - let gas = Gas::new(call.gas_limit); + let mut gas = Gas::new(call.gas_limit); match foundry_zksync_core::vm::call::<_, DatabaseError>(call, factory_deps, ecx, ccx) { Ok(result) => { // append console logs from zkEVM to the current executor's LogTracer @@ -1616,32 +1618,38 @@ impl Cheatcodes { } match result.execution_result { - ExecutionResult::Success { output, .. } => match output { - Output::Call(bytes) => Some(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Return, - output: bytes, - gas, - }, - memory_offset: call.return_memory_offset.clone(), - }), - _ => Some(CallOutcome { + ExecutionResult::Success { output, gas_used, .. } => { + let _ = gas.record_cost(gas_used); + match output { + Output::Call(bytes) => Some(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Return, + output: bytes, + gas, + }, + memory_offset: call.return_memory_offset.clone(), + }), + _ => Some(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: Bytes::new(), + gas, + }, + memory_offset: call.return_memory_offset.clone(), + }), + } + } + ExecutionResult::Revert { output, gas_used, .. } => { + let _ = gas.record_cost(gas_used); + Some(CallOutcome { result: InterpreterResult { result: InstructionResult::Revert, - output: Bytes::new(), + output, gas, }, memory_offset: call.return_memory_offset.clone(), - }), - }, - ExecutionResult::Revert { output, .. } => Some(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output, - gas, - }, - memory_offset: call.return_memory_offset.clone(), - }), + }) + } ExecutionResult::Halt { .. } => Some(CallOutcome { result: InterpreterResult { result: InstructionResult::Revert, diff --git a/crates/zksync/core/src/vm/inspect.rs b/crates/zksync/core/src/vm/inspect.rs index d6e21089f..dc964e2de 100644 --- a/crates/zksync/core/src/vm/inspect.rs +++ b/crates/zksync/core/src/vm/inspect.rs @@ -171,7 +171,6 @@ where .map(|factory_deps| (*factory_deps).clone()) .unwrap_or_default(); - let env_tx_gas_limit = ecx.env.tx.gas_limit; let mut era_db = ZKVMData::new_with_system_contracts(ecx, chain_id) .with_extra_factory_deps(persisted_factory_deps) .with_storage_accesses(ccx.accesses.take()); @@ -199,7 +198,7 @@ where } = inspect_inner(tx, storage_ptr, chain_id, ccx, call_ctx); info!( - limit=?gas_usage.limit, execution=?gas_usage.execution, pubdata=?gas_usage.pubdata, refunded=?gas_usage.refunded, + reserved=?gas_usage.bootloader_debug.reserved_gas, limit=?gas_usage.limit, execution=?gas_usage.execution, pubdata=?gas_usage.pubdata, refunded=?gas_usage.refunded, "gas usage", ); @@ -260,7 +259,7 @@ where call_traces, execution_result: rExecutionResult::Success { reason: SuccessReason::Return, - gas_used: tx_result.statistics.gas_used, + gas_used: gas_usage.gas_used(), gas_refunded: tx_result.refunds.gas_refunded, logs, output, @@ -278,7 +277,7 @@ where logs, call_traces, execution_result: rExecutionResult::Revert { - gas_used: env_tx_gas_limit - tx_result.refunds.gas_refunded, + gas_used: gas_usage.gas_used(), output: Bytes::from(output), }, } @@ -295,7 +294,7 @@ where call_traces, execution_result: rExecutionResult::Halt { reason: mapped_reason, - gas_used: env_tx_gas_limit - tx_result.refunds.gas_refunded, + gas_used: gas_usage.gas_used(), }, } } @@ -391,6 +390,13 @@ struct ZkVmGasUsage { pub bootloader_debug: BootloaderDebug, } +impl ZkVmGasUsage { + pub fn gas_used(&self) -> u64 { + // Gas limit is capped by the environment so gas should never reach max u64 + self.execution.saturating_add(self.pubdata).as_u64() + } +} + struct InnerZkVmResult { tx_result: VmExecutionResultAndLogs, bytecodes: HashMap>,