From 4aa516540a23afcb02754de6d978d53aa4d73d87 Mon Sep 17 00:00:00 2001 From: Dream Wu Date: Tue, 5 Jul 2022 11:26:13 +0800 Subject: [PATCH] add ErrorOutOfGasConstant gadget --- .../circuit_input_builder/input_state_ref.rs | 10 +- bus-mapping/src/evm/opcodes/stackonlyop.rs | 42 ++++-- zkevm-circuits/src/evm_circuit/execution.rs | 7 + .../execution/error_oog_constant.rs | 123 ++++++++++++++++++ 4 files changed, 167 insertions(+), 15 deletions(-) create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index babcbebb62..b7383043d7 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -76,7 +76,15 @@ impl<'a> CircuitInputStateRef<'a> { .expect("steps should have at least one BeginTx step"); ExecStep { exec_state: ExecState::EndTx, - gas_left: Gas(prev_step.gas_left.0 - prev_step.gas_cost.0), + gas_left: if prev_step.error.is_none() { + // no error + Gas(prev_step.gas_left.0 - prev_step.gas_cost.0) + }else{ + // if error happend, consume all gas + Gas(0u64) + //prev_step.gas_left + }, + rwc: self.block_ctx.rwc, // For tx without code execution reversible_write_counter: if let Some(call_ctx) = self.tx_ctx.calls().last() { diff --git a/bus-mapping/src/evm/opcodes/stackonlyop.rs b/bus-mapping/src/evm/opcodes/stackonlyop.rs index 6701e4e844..622c1d3269 100644 --- a/bus-mapping/src/evm/opcodes/stackonlyop.rs +++ b/bus-mapping/src/evm/opcodes/stackonlyop.rs @@ -1,6 +1,10 @@ use super::Opcode; use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; use crate::Error; +use crate::{ + error::{get_step_reported_error, ExecError}, +}; + use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it @@ -20,21 +24,31 @@ impl Opcode for StackOnlyOpcode { block_ctx_u160_gadget: BlockCtxU160Gadget, block_ctx_u256_gadget: BlockCtxU256Gadget, // error gadgets + error_oog_constant: ErrorOOGConstantGadget, error_oog_static_memory_gadget: ErrorOOGStaticMemoryGadget, } @@ -405,6 +408,7 @@ impl ExecutionConfig { block_ctx_u256_gadget: configure_gadget!(), // error gadgets error_oog_static_memory_gadget: configure_gadget!(), + error_oog_constant: configure_gadget!(), // step and presets step: step_curr, height_map, @@ -846,6 +850,9 @@ impl ExecutionConfig { ExecutionState::STOP => assign_exec_step!(self.stop_gadget), ExecutionState::SWAP => assign_exec_step!(self.swap_gadget), // errors + ExecutionState::ErrorOutOfGasConstant => { + assign_exec_step!(self.error_oog_constant) + } ExecutionState::ErrorOutOfGasStaticMemoryExpansion => { assign_exec_step!(self.error_oog_static_memory_gadget) } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs new file mode 100644 index 0000000000..4dc2751fb2 --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -0,0 +1,123 @@ +use crate::{ + evm_circuit::{ + execution::ExecutionGadget, + param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, + step::ExecutionState, + util::{ + constraint_builder::ConstraintBuilder, + math_gadget::{IsEqualGadget, IsZeroGadget, RangeCheckGadget}, + memory_gadget::{address_high, address_low, MemoryExpansionGadget}, + CachedRegion, Cell, Word, + }, + witness::{Block, Call, ExecStep, Transaction}, + }, + util::Expr, +}; +use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use halo2_proofs::plonk::Error; + +#[derive(Clone, Debug)] +pub(crate) struct ErrorOOGConstantGadget { + opcode: Cell, + // constrain gas left is less than required + gas_required: Cell, + insufficient_gas: RangeCheckGadget, +} + +impl ExecutionGadget for ErrorOOGConstantGadget { + const NAME: &'static str = "ErrorOutOfGasConstant"; + + const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasConstant; + + // Support other OOG due to pure memory including CREATE, RETURN and REVERT + fn configure(cb: &mut ConstraintBuilder) -> Self { + let opcode = cb.query_cell(); + let gas_required = cb.query_cell(); + + // Check if the amount of gas available is less than the amount of gas + // required + let insufficient_gas = RangeCheckGadget::construct( + cb, + gas_required.expr() - cb.curr.state.gas_left.expr(), + ); + + // TODO: Use ContextSwitchGadget to switch call context to caller's and + // consume all gas_left. + + Self { + opcode, + gas_required, + insufficient_gas, + } + } + + fn assign_exec_step( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + block: &Block, + _tx: &Transaction, + _call: &Call, + step: &ExecStep, + ) -> Result<(), Error> { + let opcode = step.opcode.unwrap(); + + // Inputs/Outputs + self.gas_required.assign(region, offset, Some(F::from(step.gas_cost)))?; + // Gas insufficient check + // Get `gas_available` variable here once it's available + self.insufficient_gas + .assign(region, offset, F::from(step.gas_cost - step.gas_left))?; + + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::{evm_circuit::test::rand_bytes, test_util::run_test_circuits}; + use eth_types::bytecode; + use eth_types::evm_types::OpcodeId; + use mock::TestContext; + + fn test_ok(opcode: OpcodeId, bytes: &[u8]) { + assert!(bytes.len() as u8 == opcode.as_u8() - OpcodeId::PUSH1.as_u8() + 1,); + + let mut bytecode = bytecode! { + .write_op(opcode) + }; + for b in bytes { + bytecode.write(*b); + } + bytecode.write_op(OpcodeId::STOP); + + assert_eq!( + run_test_circuits( + TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), + None + ), + Ok(()) + ); + } + + #[test] + fn push_gadget_simple() { + test_ok(OpcodeId::PUSH1, &[1]); + // test_ok(OpcodeId::PUSH2, &[1, 2]); + // test_ok( + // OpcodeId::PUSH31, + // &[ + // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + // 24, 25, 26, 27, 28, 29, 30, 31, + // ], + // ); + // test_ok( + // OpcodeId::PUSH32, + // &[ + // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + // 24, 25, 26, 27, 28, 29, 30, 31, 32, + // ], + // ); + } + +}