diff --git a/Cargo.lock b/Cargo.lock index 66cdebf359..081f43dc03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2168,7 +2168,6 @@ dependencies = [ "halo2_proofs", "hex", "lazy_static", - "log", "num-bigint", "poseidon-circuit", "rand", diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index f6e38ea202..b62598bed3 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -45,4 +45,4 @@ default = ["test"] test = ["mock", "rand"] scroll = ["eth-types/scroll"] # Enable shanghai feature of mock only if mock is enabled (by test). -shanghai = ["mock?/shanghai"] +shanghai = ["eth-types/shanghai", "mock?/shanghai"] diff --git a/bus-mapping/src/error.rs b/bus-mapping/src/error.rs index 3b12b7d440..6b1eed4fcf 100644 --- a/bus-mapping/src/error.rs +++ b/bus-mapping/src/error.rs @@ -70,8 +70,8 @@ pub enum OogError { /// Out of Gas for MLOAD, MSTORE, MSTORE8, which have static memory /// expansion gas cost StaticMemoryExpansion, - /// Out of Gas for CREATE, RETURN, REVERT, which have dynamic memory - /// expansion gas cost + /// Out of Gas for RETURN, REVERT, which have dynamic memory expansion gas + /// cost DynamicMemoryExpansion, /// Out of Gas for CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY, /// which copy a specified chunk of memory @@ -92,8 +92,8 @@ pub enum OogError { SloadSstore, /// Out of Gas for CALL, CALLCODE, DELEGATECALL and STATICCALL Call, - /// Out of Gas for CREATE2 - Create2, + /// Out of Gas for CREATE and CREATE2 + Create, /// Out of Gas for SELFDESTRUCT SelfDestruct, } @@ -183,9 +183,7 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError { OpcodeId::MLOAD | OpcodeId::MSTORE | OpcodeId::MSTORE8 => { OogError::StaticMemoryExpansion } - OpcodeId::CREATE | OpcodeId::RETURN | OpcodeId::REVERT => { - OogError::DynamicMemoryExpansion - } + OpcodeId::RETURN | OpcodeId::REVERT => OogError::DynamicMemoryExpansion, OpcodeId::CALLDATACOPY | OpcodeId::CODECOPY | OpcodeId::EXTCODECOPY @@ -202,7 +200,7 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError { OogError::Call } OpcodeId::SLOAD | OpcodeId::SSTORE => OogError::SloadSstore, - OpcodeId::CREATE2 => OogError::Create2, + OpcodeId::CREATE | OpcodeId::CREATE2 => OogError::Create, OpcodeId::SELFDESTRUCT => OogError::SelfDestruct, _ => OogError::Constant, }; diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index ccd2218b5b..af364420cd 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -65,7 +65,6 @@ mod error_invalid_creation_code; mod error_invalid_jump; mod error_oog_account_access; mod error_oog_call; -mod error_oog_dynamic_memory; mod error_oog_log; mod error_oog_memory_copy; mod error_oog_sload_sstore; @@ -95,7 +94,6 @@ use error_invalid_creation_code::ErrorCreationCode; use error_invalid_jump::InvalidJump; use error_oog_account_access::ErrorOOGAccountAccess; use error_oog_call::OOGCall; -use error_oog_dynamic_memory::OOGDynamicMemory; use error_oog_log::ErrorOOGLog; use error_oog_memory_copy::OOGMemoryCopy; use error_oog_sload_sstore::OOGSloadSstore; @@ -299,12 +297,14 @@ fn fn_gen_error_state_associated_ops( ExecError::OutOfGas(OogError::Constant) => { Some(StackOnlyOpcode::<0, 0, true>::gen_associated_ops) } - ExecError::OutOfGas(OogError::Create2) => { - Some(StackOnlyOpcode::<4, 0, true>::gen_associated_ops) - } + ExecError::OutOfGas(OogError::Create) => match geth_step.op { + OpcodeId::CREATE => Some(StackOnlyOpcode::<3, 0, true>::gen_associated_ops), + OpcodeId::CREATE2 => Some(StackOnlyOpcode::<4, 0, true>::gen_associated_ops), + op => unreachable!("OOG Create cannot occur in {op}"), + }, ExecError::OutOfGas(OogError::Log) => Some(ErrorOOGLog::gen_associated_ops), ExecError::OutOfGas(OogError::DynamicMemoryExpansion) => { - Some(OOGDynamicMemory::gen_associated_ops) + Some(StackOnlyOpcode::<2, 0, true>::gen_associated_ops) } ExecError::OutOfGas(OogError::StaticMemoryExpansion) => { Some(StackOnlyOpcode::<1, 0, true>::gen_associated_ops) @@ -443,7 +443,7 @@ pub fn gen_associated_ops( // For exceptions that already enter next call context, but fail immediately // (e.g. Depth, InsufficientBalance), we still need to parse the call. if geth_step.op.is_call_or_create() - && !matches!(exec_error, ExecError::OutOfGas(OogError::Create2)) + && !matches!(exec_error, ExecError::OutOfGas(OogError::Create)) { let call = state.parse_call(geth_step)?; state.push_call(call); diff --git a/bus-mapping/src/evm/opcodes/error_oog_dynamic_memory.rs b/bus-mapping/src/evm/opcodes/error_oog_dynamic_memory.rs deleted file mode 100644 index 011c70910b..0000000000 --- a/bus-mapping/src/evm/opcodes/error_oog_dynamic_memory.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::{ - circuit_input_builder::{CircuitInputStateRef, ExecStep}, - error::{ExecError, OogError}, - evm::Opcode, - Error, -}; -use eth_types::{evm_types::OpcodeId, GethExecStep}; - -#[derive(Clone, Copy, Debug)] -pub(crate) struct OOGDynamicMemory {} - -impl Opcode for OOGDynamicMemory { - fn gen_associated_ops( - state: &mut CircuitInputStateRef, - geth_steps: &[GethExecStep], - ) -> Result, Error> { - let geth_step = &geth_steps[0]; - debug_assert!( - [OpcodeId::CREATE, OpcodeId::RETURN, OpcodeId::REVERT].contains(&geth_step.op) - ); - - let mut exec_step = state.new_step(geth_step)?; - exec_step.error = Some(ExecError::OutOfGas(OogError::DynamicMemoryExpansion)); - - if geth_step.op == OpcodeId::CREATE { - state.stack_read( - &mut exec_step, - geth_step.stack.last_filled(), - geth_step.stack.last()?, - )?; - state.stack_read( - &mut exec_step, - geth_step.stack.nth_last_filled(1), - geth_step.stack.nth_last(1)?, - )?; - state.stack_read( - &mut exec_step, - geth_step.stack.nth_last_filled(2), - geth_step.stack.nth_last(2)?, - )?; - } else { - state.stack_read( - &mut exec_step, - geth_step.stack.last_filled(), - geth_step.stack.last()?, - )?; - state.stack_read( - &mut exec_step, - geth_step.stack.nth_last_filled(1), - geth_step.stack.nth_last(1)?, - )?; - } - - state.handle_return(&mut exec_step, geth_steps, true)?; - Ok(vec![exec_step]) - } -} diff --git a/circuit-benchmarks/src/bytecode_circuit.rs b/circuit-benchmarks/src/bytecode_circuit.rs index 42ca583f35..2996f21312 100644 --- a/circuit-benchmarks/src/bytecode_circuit.rs +++ b/circuit-benchmarks/src/bytecode_circuit.rs @@ -4,7 +4,7 @@ mod tests { use ark_std::{end_timer, start_timer}; use bus_mapping::evm::OpcodeId; - use eth_types::Field; + use eth_types::{evm_types::MAX_CODE_SIZE, Field}; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, @@ -45,12 +45,11 @@ mod tests { // Unique string used by bench results module for parsing the result const BENCHMARK_ID: &str = "Bytecode Circuit"; - // Contract code size exceeds 24576 bytes may not be deployable on Mainnet. - const MAX_BYTECODE_LEN: usize = 24576; - let num_rows = 1 << degree; let max_bytecode_row_num = num_rows - TestBytecodeCircuit::::unusable_rows(); - let bytecode_len = std::cmp::min(MAX_BYTECODE_LEN, max_bytecode_row_num); + + // Contract code size exceeds 24576 bytes may not be deployable on Mainnet. + let bytecode_len = std::cmp::min(MAX_CODE_SIZE as usize, max_bytecode_row_num); let bytecodes_num: usize = max_bytecode_row_num / bytecode_len; // Create the circuit diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index 3c6ff513c2..ec91236e36 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -28,4 +28,5 @@ poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git" [features] default = ["warn-unimplemented"] warn-unimplemented = [] +shanghai = [] scroll = [] diff --git a/eth-types/src/evm_types.rs b/eth-types/src/evm_types.rs index 1f9fe81962..8a6577eec7 100644 --- a/eth-types/src/evm_types.rs +++ b/eth-types/src/evm_types.rs @@ -60,6 +60,8 @@ impl fmt::Debug for Gas { } } +/// Maximum bytecode size to permit for a contract. +pub const MAX_CODE_SIZE: u64 = 24576; /// This constant ((2^32 - 1) * 32) is the highest number that can be used without overflowing the /// square operation of gas calculation. /// @@ -69,6 +71,38 @@ pub const MAX_REFUND_QUOTIENT_OF_GAS_USED: usize = 5; /// Gas stipend when CALL or CALLCODE is attached with value. pub const GAS_STIPEND_CALL_WITH_VALUE: u64 = 2300; +#[cfg(feature = "shanghai")] +mod gas_create { + // For EIP-3860, there are 2 special gas cost constraints in geth + // [gasCreate2Eip3860](https://github.com/ethereum/go-ethereum/blob/eb83e7c54021573eaceb14236af3a7a8c64f6027/core/vm/gas_table.go#L321) + // (similar for CREATE). + // 1. size <= 49152 (MaxInitCodeSize) + // 2. gasCost = memoryGasCost + (2 + 6) * ((size + 31) / 32) should not + // overflow for Uint64. + // No need to constrain the second condition, since the maximum gas cost + // cannot overflow for Uint64 (36028809887100925 calculated by + // `memorySize = 0x1FFFFFFFE0` and `size = 49152`) if the first condition is + // satisfied. + + /// Maximum init code size to permit in a creation transaction and create instructions. + pub const MAX_INIT_CODE_SIZE: u64 = 2 * super::MAX_CODE_SIZE; + /// Gas per init code word of CREATE when creating a contract. + pub const CREATE_GAS_PER_CODE_WORD: u64 = 2; + /// Gas per init code word of CREATE2 when creating a contract. + pub const CREATE2_GAS_PER_CODE_WORD: u64 = + CREATE_GAS_PER_CODE_WORD + super::GasCost::COPY_SHA3.0; +} +#[cfg(not(feature = "shanghai"))] +mod gas_create { + /// Maximum init code size (0x1FFFFFFFE0) if not EIP-3860. + pub use super::MAX_EXPANDED_MEMORY_ADDRESS as MAX_INIT_CODE_SIZE; + /// Gas per init code word of CREATE if not EIP-3860. + pub const CREATE_GAS_PER_CODE_WORD: u64 = 0; + /// Gas per init code word of CREATE2 if not EIP-3860. + pub const CREATE2_GAS_PER_CODE_WORD: u64 = super::GasCost::COPY_SHA3.0; +} +pub use gas_create::*; + /// Defines the gas consumption. #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct GasCost(pub u64); diff --git a/mock/Cargo.toml b/mock/Cargo.toml index 03df0a51c5..963519d4d2 100644 --- a/mock/Cargo.toml +++ b/mock/Cargo.toml @@ -17,4 +17,4 @@ rand = "0.8" [features] default = [] -shanghai = [] +shanghai = ["eth-types/shanghai"] diff --git a/testool/Cargo.toml b/testool/Cargo.toml index 065a48232d..e2fd353a1e 100644 --- a/testool/Cargo.toml +++ b/testool/Cargo.toml @@ -41,4 +41,4 @@ ctor = "0.1.22" default = ["ignore-test-docker", "skip-self-destruct"] ignore-test-docker = [] skip-self-destruct = [] -shanghai = [] +shanghai = ["eth-types/shanghai"] diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 9472d95064..60f7b75684 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -68,7 +68,7 @@ test = ["ethers-signers", "mock", "bus-mapping/test"] # while tests inside this repo should not enable "poseidon-codehash-lookup" feature. scroll = ["bus-mapping/scroll", "eth-types/scroll", "zktrie", "enable-sign-verify", "reject-eip2718", "poseidon-codehash"] # Enable shanghai feature of mock only if mock is enabled (by test). -shanghai = ["bus-mapping/shanghai", "mock?/shanghai"] +shanghai = ["bus-mapping/shanghai", "eth-types/shanghai", "mock?/shanghai"] poseidon-codehash-lookup = [] test-circuits = [] warn-unimplemented = ["eth-types/warn-unimplemented"] diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 4c10ab11d5..1ce21110a0 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -88,7 +88,7 @@ mod error_invalid_opcode; mod error_oog_account_access; mod error_oog_call; mod error_oog_constant; -mod error_oog_create2; +mod error_oog_create; mod error_oog_dynamic_memory; mod error_oog_exp; mod error_oog_log; @@ -170,7 +170,7 @@ use error_invalid_opcode::ErrorInvalidOpcodeGadget; use error_oog_account_access::ErrorOOGAccountAccessGadget; use error_oog_call::ErrorOOGCallGadget; use error_oog_constant::ErrorOOGConstantGadget; -use error_oog_create2::ErrorOOGCreate2Gadget; +use error_oog_create::ErrorOOGCreateGadget; use error_oog_dynamic_memory::ErrorOOGDynamicMemoryGadget; use error_oog_exp::ErrorOOGExpGadget; use error_oog_log::ErrorOOGLogGadget; @@ -334,7 +334,7 @@ pub(crate) struct ExecutionConfig { error_oog_log: Box>, error_oog_account_access: Box>, error_oog_sha3: Box>, - error_oog_create2: Box>, + error_oog_create: Box>, error_code_store: Box>, #[cfg(not(feature = "scroll"))] error_oog_self_destruct: @@ -596,7 +596,7 @@ impl ExecutionConfig { error_oog_account_access: configure_gadget!(), error_oog_sha3: configure_gadget!(), error_oog_exp: configure_gadget!(), - error_oog_create2: configure_gadget!(), + error_oog_create: configure_gadget!(), #[cfg(not(feature = "scroll"))] error_oog_self_destruct: configure_gadget!(), error_code_store: configure_gadget!(), @@ -1433,8 +1433,8 @@ impl ExecutionConfig { ExecutionState::ErrorOutOfGasEXP => { assign_exec_step!(self.error_oog_exp) } - ExecutionState::ErrorOutOfGasCREATE2 => { - assign_exec_step!(self.error_oog_create2) + ExecutionState::ErrorOutOfGasCREATE => { + assign_exec_step!(self.error_oog_create) } ExecutionState::ErrorOutOfGasSELFDESTRUCT => { #[cfg(not(feature = "scroll"))] diff --git a/zkevm-circuits/src/evm_circuit/execution/create.rs b/zkevm-circuits/src/evm_circuit/execution/create.rs index 2f58ded24e..13d4ef1f8e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/create.rs +++ b/zkevm-circuits/src/evm_circuit/execution/create.rs @@ -18,7 +18,7 @@ use crate::{ memory_gadget::{ CommonMemoryAddressGadget, MemoryAddressGadget, MemoryExpansionGadget, }, - not, select, CachedRegion, Cell, Word, + not, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -26,7 +26,10 @@ use crate::{ util::Expr, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId, state_db::CodeDB}; -use eth_types::{evm_types::GasCost, Field, ToBigEndian, ToLittleEndian, ToScalar, U256}; +use eth_types::{ + evm_types::{GasCost, CREATE2_GAS_PER_CODE_WORD, CREATE_GAS_PER_CODE_WORD, MAX_INIT_CODE_SIZE}, + Field, ToBigEndian, ToLittleEndian, ToScalar, U256, +}; use ethers_core::utils::keccak256; use gadgets::util::{and, expr_from_bytes}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -47,6 +50,10 @@ pub(crate) struct CreateGadget, init_code: MemoryAddressGadget, init_code_word_size: ConstantDivisionGadget, + // Init code size must be less than or equal to 49152 + // (maximum init code size) if Shanghai, otherwise should be less than or + // equal to 0x1FFFFFFFE0 (maximum value of offset + size). + init_code_size_not_overflow: LtGadget, init_code_rlc: Cell, memory_expansion: MemoryExpansionGadget, gas_left: ConstantDivisionGadget, @@ -80,11 +87,12 @@ impl ExecutionGadget< cb.require_equal( "Opcode is CREATE or CREATE2", opcode.expr(), - select::expr( - IS_CREATE2.expr(), - OpcodeId::CREATE2.expr(), - OpcodeId::CREATE.expr(), - ), + if IS_CREATE2 { + OpcodeId::CREATE2 + } else { + OpcodeId::CREATE + } + .expr(), ); let value = cb.query_word_rlc(); @@ -93,6 +101,16 @@ impl ExecutionGadget< let init_code_length = cb.query_word_rlc(); let init_code = MemoryAddressGadget::construct(cb, init_code_memory_offset, init_code_length); + let init_code_size_not_overflow = + LtGadget::construct(cb, init_code.length(), MAX_INIT_CODE_SIZE.expr() + 1.expr()); + + // Init code size overflow is checked before ErrDepth, ErrInsufficientBalance, + // ErrNonceUintOverflow and ErrContractAddressCollision. + cb.require_equal( + "Init code size must be not overflow", + init_code_size_not_overflow.expr(), + 1.expr(), + ); let keccak_output = cb.query_word_rlc(); let new_address_rlc = cb.word_rlc::( @@ -113,9 +131,9 @@ impl ExecutionGadget< cb.stack_pop(value.expr()); cb.stack_pop(init_code.offset_rlc()); cb.stack_pop(init_code.length_rlc()); - cb.condition(IS_CREATE2.expr(), |cb| { + if IS_CREATE2 { cb.stack_pop(create.salt_word_rlc(cb)); - }); + } cb.stack_push(callee_is_success.expr() * new_address_rlc); @@ -303,8 +321,13 @@ impl ExecutionGadget< init_code.length() + (N_BYTES_WORD - 1).expr(), N_BYTES_WORD as u64, ); - let keccak_gas_cost = - GasCost::COPY_SHA3.expr() * IS_CREATE2.expr() * init_code_word_size.quotient(); + let keccak_gas_cost = init_code_word_size.quotient() + * if IS_CREATE2 { + CREATE2_GAS_PER_CODE_WORD + } else { + CREATE_GAS_PER_CODE_WORD + } + .expr(); let gas_cost = GasCost::CREATE.expr() + memory_expansion.gas_cost() + keccak_gas_cost; let gas_remaining = cb.curr.state.gas_left.expr() - gas_cost.clone(); @@ -464,6 +487,7 @@ impl ExecutionGadget< gas_left, callee_is_success, init_code_word_size, + init_code_size_not_overflow, create, caller_balance, is_depth_in_range, @@ -516,6 +540,12 @@ impl ExecutionGadget< offset, region.keccak_rlc(&values.iter().rev().cloned().collect::>()), )?; + self.init_code_size_not_overflow.assign( + region, + offset, + F::from(init_code_length.as_u64()), + F::from(MAX_INIT_CODE_SIZE + 1), + )?; self.tx_id .assign(region, offset, Value::known(tx.id.to_scalar().unwrap()))?; @@ -626,14 +656,14 @@ impl ExecutionGadget< (31u64 + init_code_length.as_u64()).into(), )?; - let gas_left = step.gas_left - - GasCost::CREATE.as_u64() - - memory_expansion_gas_cost - - if is_create2 { - u64::try_from(init_code_word_size).unwrap() * GasCost::COPY_SHA3.as_u64() + let keccak_gas_cost = u64::try_from(init_code_word_size).unwrap() + * if IS_CREATE2 { + CREATE2_GAS_PER_CODE_WORD } else { - 0 + CREATE_GAS_PER_CODE_WORD }; + let gas_left = + step.gas_left - GasCost::CREATE.as_u64() - memory_expansion_gas_cost - keccak_gas_cost; self.gas_left.assign(region, offset, gas_left.into())?; self.callee_is_success.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_create.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_create.rs new file mode 100644 index 0000000000..e5ee25275e --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_create.rs @@ -0,0 +1,380 @@ +use crate::{ + evm_circuit::{ + execution::ExecutionGadget, + param::{N_BYTES_GAS, N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, + step::ExecutionState, + util::{ + common_gadget::CommonErrorGadget, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::{LtGadget, PairSelectGadget}, + memory_gadget::{ + CommonMemoryAddressGadget, MemoryExpandedAddressGadget, MemoryExpansionGadget, + MemoryWordSizeGadget, + }, + or, select, CachedRegion, Cell, Word, + }, + }, + witness::{Block, Call, ExecStep, Transaction}, +}; +use eth_types::{ + evm_types::{ + GasCost, OpcodeId, CREATE2_GAS_PER_CODE_WORD, CREATE_GAS_PER_CODE_WORD, MAX_INIT_CODE_SIZE, + }, + Field, ToLittleEndian, U256, +}; +use gadgets::util::Expr; +use halo2_proofs::{circuit::Value, plonk::Error}; + +#[derive(Clone, Debug)] +pub(crate) struct ErrorOOGCreateGadget { + opcode: Cell, + value: Word, + salt: Word, + is_create2: PairSelectGadget, + minimum_word_size: MemoryWordSizeGadget, + memory_address: MemoryExpandedAddressGadget, + memory_expansion: MemoryExpansionGadget, + // Init code size is overflow when it is greater than 49152 + // (maximum init code size) if Shanghai, otherwise when it is greater than + // 0x1FFFFFFFE0 (maximum value of offset + size). + // Uint64 overflow is checked in `memory_address` (offset + length). + init_code_size_overflow: LtGadget, + insufficient_gas: LtGadget, + common_error_gadget: CommonErrorGadget, +} + +impl ExecutionGadget for ErrorOOGCreateGadget { + const NAME: &'static str = "ErrorOutOfGasCREATE"; + + const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasCREATE; + + fn configure(cb: &mut EVMConstraintBuilder) -> Self { + let opcode = cb.query_cell(); + + let is_create2 = PairSelectGadget::construct( + cb, + opcode.expr(), + OpcodeId::CREATE2.expr(), + OpcodeId::CREATE.expr(), + ); + + let value = cb.query_word_rlc(); + let salt = cb.query_word_rlc(); + + let memory_address = MemoryExpandedAddressGadget::construct_self(cb); + + cb.stack_pop(value.expr()); + cb.stack_pop(memory_address.offset_rlc()); + cb.stack_pop(memory_address.length_rlc()); + cb.condition(is_create2.expr().0, |cb| cb.stack_pop(salt.expr())); + + let init_code_size_overflow = + LtGadget::construct(cb, MAX_INIT_CODE_SIZE.expr(), memory_address.length()); + + let minimum_word_size = MemoryWordSizeGadget::construct(cb, memory_address.length()); + let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); + + let keccak_gas_cost = minimum_word_size.expr() + * select::expr( + is_create2.expr().0, + CREATE2_GAS_PER_CODE_WORD.expr(), + CREATE_GAS_PER_CODE_WORD.expr(), + ); + let gas_cost = GasCost::CREATE.expr() + memory_expansion.gas_cost() + keccak_gas_cost; + let insufficient_gas = LtGadget::construct(cb, cb.curr.state.gas_left.expr(), gas_cost); + + cb.require_equal( + "Memory address is overflow, init code size is overflow, or gas left is less than cost", + or::expr([ + memory_address.overflow(), + init_code_size_overflow.expr(), + insufficient_gas.expr(), + ]), + 1.expr(), + ); + + let common_error_gadget = CommonErrorGadget::construct( + cb, + opcode.expr(), + select::expr(is_create2.expr().0, 6.expr(), 5.expr()), + ); + + Self { + opcode, + value, + salt, + is_create2, + minimum_word_size, + memory_address, + memory_expansion, + init_code_size_overflow, + insufficient_gas, + common_error_gadget, + } + } + + fn assign_exec_step( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + block: &Block, + _: &Transaction, + call: &Call, + step: &ExecStep, + ) -> Result<(), Error> { + log::debug!( + "ErrorOutOfGasCREATE: gas_cost = {}, gas_left = {}", + step.gas_cost, + step.gas_left, + ); + + let opcode = step.opcode.unwrap(); + let is_create2 = opcode == OpcodeId::CREATE2; + self.opcode + .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; + self.is_create2.assign( + region, + offset, + F::from(opcode.as_u64()), + F::from(OpcodeId::CREATE2.as_u64()), + F::from(OpcodeId::CREATE.as_u64()), + )?; + + let [value, memory_offset, memory_length] = + [0, 1, 2].map(|idx| block.rws[step.rw_indices[idx]].stack_value()); + let salt = if is_create2 { + block.rws[step.rw_indices[3]].stack_value() + } else { + U256::zero() + }; + + self.value + .assign(region, offset, Some(value.to_le_bytes()))?; + self.salt.assign(region, offset, Some(salt.to_le_bytes()))?; + + let memory_address = + self.memory_address + .assign(region, offset, memory_offset, memory_length)?; + + let init_code_size = + MemoryExpandedAddressGadget::::length_value(memory_offset, memory_length); + let minimum_word_size = self + .minimum_word_size + .assign(region, offset, init_code_size)?; + let memory_expansion_gas = self + .memory_expansion + .assign(region, offset, step.memory_word_size(), [memory_address])? + .1; + + self.init_code_size_overflow.assign( + region, + offset, + F::from(MAX_INIT_CODE_SIZE), + F::from(init_code_size), + )?; + + let keccak_gas_cost = minimum_word_size + * if is_create2 { + CREATE2_GAS_PER_CODE_WORD + } else { + CREATE_GAS_PER_CODE_WORD + }; + self.insufficient_gas.assign( + region, + offset, + F::from(step.gas_left), + F::from(GasCost::CREATE.as_u64() + memory_expansion_gas + keccak_gas_cost), + )?; + + self.common_error_gadget.assign( + region, + offset, + block, + call, + step, + if is_create2 { 6 } else { 5 }, + )?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_util::CircuitTestBuilder; + use eth_types::{bytecode, word, Bytecode, ToWord}; + use mock::{ + eth, + test_ctx::{helpers::account_0_code_account_1_no_code, LoggerConfig}, + TestContext, MOCK_ACCOUNTS, MOCK_BLOCK_GAS_LIMIT, + }; + + struct TestCase { + bytecode: Bytecode, + gas: u64, + } + + impl TestCase { + pub fn new(is_create2: bool, offset: U256, size: U256, gas: u64) -> Self { + let mut bytecode = Bytecode::default(); + if is_create2 { + bytecode.append(&bytecode! {PUSH1(0)}); // salt; + } + bytecode.append(&bytecode! { + PUSH32(size) // size + PUSH32(offset) // offset + PUSH1(0) // value + }); + bytecode.write_op(if is_create2 { + OpcodeId::CREATE2 + } else { + OpcodeId::CREATE + }); + + Self { bytecode, gas } + } + } + + #[test] + fn test_oog_create_simple() { + let mut cases = vec![]; + for is_create2 in [true, false] { + cases.push(TestCase::new( + is_create2, + 0xffffffff_u64.into(), + 0xff.into(), + 0xffff, + )); + + cases.push(TestCase::new(is_create2, U256::zero(), 4.into(), 0x7d08)); + } + + for case in cases.iter() { + test_root(case); + test_internal(case); + } + } + + #[test] + fn test_oog_create_max_expanded_address() { + for is_create2 in [true, false] { + // 0xffffffff1 + 0xffffffff0 = 0x1fffffffe1 + // > MAX_EXPANDED_MEMORY_ADDRESS (0x1fffffffe0) + let case = TestCase::new( + is_create2, + 0xffffffff1_u64.into(), + 0xffffffff0_u64.into(), + MOCK_BLOCK_GAS_LIMIT, + ); + + test_root(&case); + test_internal(&case); + } + } + + #[test] + fn test_oog_create_max_u64_address() { + for is_create2 in [true, false] { + let case = TestCase::new( + is_create2, + u64::MAX.into(), + u64::MAX.into(), + MOCK_BLOCK_GAS_LIMIT, + ); + + test_root(&case); + test_internal(&case); + } + } + + #[test] + fn test_oog_create_max_word_address() { + for is_create2 in [true, false] { + let case = TestCase::new(is_create2, U256::MAX, U256::MAX, MOCK_BLOCK_GAS_LIMIT); + + test_root(&case); + test_internal(&case); + } + } + + #[test] + fn test_oog_create_max_init_code_size() { + for is_create2 in [true, false] { + // For Shanghai, MAX_INIT_CODE_SIZE is 49152, it is constrained by + // `init_code_size_overflow`. + // For not Shanghai, MAX_INIT_CODE_SIZE is 0x1FFFFFFFE0, it is + // constrained by `memory_address.overflow()` + // (and `init_code_size_overflow`). + let case = TestCase::new( + is_create2, + U256::zero(), + (MAX_INIT_CODE_SIZE + 1).into(), + MOCK_BLOCK_GAS_LIMIT, + ); + + test_root(&case); + test_internal(&case); + } + } + + fn test_root(case: &TestCase) { + let ctx = TestContext::<2, 1>::new_with_logger_config( + None, + account_0_code_account_1_no_code(case.bytecode.clone()), + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .gas(case.gas.into()); + }, + |block, _tx| block, + LoggerConfig { + enable_memory: true, + ..Default::default() + }, + ) + .unwrap(); + + CircuitTestBuilder::new_from_test_ctx(ctx).run(); + } + + fn test_internal(case: &TestCase) { + let code_a = bytecode! { + PUSH1(0x00) // retLength + PUSH1(0x00) // retOffset + PUSH32(0x00) // argsLength + PUSH32(0x00) // argsOffset + PUSH1(0x00) // value + PUSH32(MOCK_ACCOUNTS[1].to_word()) // addr + PUSH32(case.gas) // gas + CALL + STOP + }; + + let ctx = TestContext::<3, 1>::new_with_logger_config( + None, + |accs| { + accs[0].address(MOCK_ACCOUNTS[0]).code(code_a); + accs[1] + .address(MOCK_ACCOUNTS[1]) + .code(case.bytecode.clone()); + accs[2].address(MOCK_ACCOUNTS[2]).balance(eth(1)); + }, + |mut txs, accs| { + txs[0] + .from(accs[2].address) + .to(accs[0].address) + .gas(word!("0xFFFFF")); + }, + |block, _tx| block, + LoggerConfig { + enable_memory: true, + ..Default::default() + }, + ) + .unwrap(); + + CircuitTestBuilder::new_from_test_ctx(ctx).run(); + } +} diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_create2.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_create2.rs deleted file mode 100644 index fca4746cf7..0000000000 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_create2.rs +++ /dev/null @@ -1,314 +0,0 @@ -use crate::{ - evm_circuit::{ - execution::ExecutionGadget, - param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, - step::ExecutionState, - util::{ - common_gadget::CommonErrorGadget, - constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - math_gadget::LtGadget, - memory_gadget::{ - CommonMemoryAddressGadget, MemoryExpandedAddressGadget, MemoryExpansionGadget, - MemoryWordSizeGadget, - }, - or, CachedRegion, Cell, Word, - }, - }, - witness::{Block, Call, ExecStep, Transaction}, -}; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use gadgets::util::Expr; -use halo2_proofs::{circuit::Value, plonk::Error}; - -#[derive(Clone, Debug)] -pub(crate) struct ErrorOOGCreate2Gadget { - opcode: Cell, - value: Word, - salt: Word, - minimum_word_size: MemoryWordSizeGadget, - memory_address: MemoryExpandedAddressGadget, - memory_expansion: MemoryExpansionGadget, - insufficient_gas: LtGadget, - common_error_gadget: CommonErrorGadget, -} - -impl ExecutionGadget for ErrorOOGCreate2Gadget { - const NAME: &'static str = "ErrorOutOfGasCREATE2"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasCREATE2; - - fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let opcode = cb.query_cell(); - - cb.require_equal( - "ErrorOutOfGasCREATE2 opcode must be CREATE2", - opcode.expr(), - OpcodeId::CREATE2.expr(), - ); - - let value = cb.query_word_rlc(); - let salt = cb.query_word_rlc(); - - let memory_address = MemoryExpandedAddressGadget::construct_self(cb); - - cb.stack_pop(value.expr()); - cb.stack_pop(memory_address.offset_rlc()); - cb.stack_pop(memory_address.length_rlc()); - cb.stack_pop(salt.expr()); - - let minimum_word_size = MemoryWordSizeGadget::construct(cb, memory_address.length()); - - let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); - - let insufficient_gas = LtGadget::construct( - cb, - cb.curr.state.gas_left.expr(), - OpcodeId::CREATE2.constant_gas_cost().expr() - + memory_expansion.gas_cost() - + 6.expr() * minimum_word_size.expr(), - ); - - cb.require_equal( - "Memory address is overflow or gas left is less than cost", - or::expr([memory_address.overflow(), insufficient_gas.expr()]), - 1.expr(), - ); - - let common_error_gadget = CommonErrorGadget::construct(cb, opcode.expr(), 6.expr()); - - Self { - opcode, - value, - salt, - minimum_word_size, - memory_address, - memory_expansion, - insufficient_gas, - common_error_gadget, - } - } - - fn assign_exec_step( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - block: &Block, - _: &Transaction, - call: &Call, - step: &ExecStep, - ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); - - self.opcode - .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - - self.value.assign( - region, - offset, - Some(block.rws[step.rw_indices[0]].stack_value().to_le_bytes()), - )?; - - let memory_offset = block.rws[step.rw_indices[1]].stack_value(); - let memory_length = block.rws[step.rw_indices[2]].stack_value(); - - let memory_address = - self.memory_address - .assign(region, offset, memory_offset, memory_length)?; - - self.salt.assign( - region, - offset, - Some(block.rws[step.rw_indices[3]].stack_value().to_le_bytes()), - )?; - - let minimum_word_size = self.minimum_word_size.assign( - region, - offset, - MemoryExpandedAddressGadget::::length_value(memory_offset, memory_length), - )?; - let memory_expansion_gas = self - .memory_expansion - .assign(region, offset, step.memory_word_size(), [memory_address])? - .1; - - let constant_gas_cost = opcode.constant_gas_cost().0; - - self.insufficient_gas.assign( - region, - offset, - F::from(step.gas_left), - F::from(6 * minimum_word_size + memory_expansion_gas + constant_gas_cost), - )?; - - self.common_error_gadget - .assign(region, offset, block, call, step, 6)?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::test_util::CircuitTestBuilder; - use eth_types::{bytecode, word, Bytecode, ToWord, Word, U256}; - use mock::{ - eth, - test_ctx::{helpers::account_0_code_account_1_no_code, LoggerConfig}, - TestContext, MOCK_ACCOUNTS, MOCK_BLOCK_GAS_LIMIT, - }; - - struct TestCase { - bytecode: Bytecode, - gas: Word, - } - - #[test] - fn test_oog_create2_simple() { - let cases = [ - TestCase { - bytecode: bytecode! { - PUSH8(0x0) // salt - PUSH8(0xFF) // size - PUSH32(word!("0xffffffff")) // offset - PUSH8(0x0) // value - CREATE2 - STOP - }, - gas: word!("0xFFFF"), - }, - TestCase { - bytecode: bytecode! { - PUSH1(2) // salt - PUSH1(4) // size - PUSH1(0x0) // offset - PUSH1(0x0) // value - CREATE2 - }, - gas: word!("0x7D0F"), - }, - ]; - - for case in cases.iter() { - test_root(case); - test_internal(case); - } - } - - #[test] - fn test_oog_create2_max_expanded_address() { - // 0xffffffff1 + 0xffffffff0 = 0x1fffffffe1 - // > MAX_EXPANDED_MEMORY_ADDRESS (0x1fffffffe0) - let case = TestCase { - bytecode: bytecode! { - PUSH8(0) // salt - PUSH32(0xffffffff0_u64) // size - PUSH32(0xffffffff1_u64) // offset - PUSH8(0) // value - CREATE2 - STOP - }, - gas: MOCK_BLOCK_GAS_LIMIT.into(), - }; - - test_root(&case); - test_internal(&case); - } - - #[test] - fn test_oog_create2_max_u64_address() { - let case = TestCase { - bytecode: bytecode! { - PUSH8(0) // salt - PUSH32(u64::MAX) // size - PUSH32(u64::MAX) // offset - PUSH8(0) // value - CREATE2 - STOP - }, - gas: MOCK_BLOCK_GAS_LIMIT.into(), - }; - - test_root(&case); - test_internal(&case); - } - - #[test] - fn test_oog_create2_max_word_address() { - let case = TestCase { - bytecode: bytecode! { - PUSH8(0) // salt - PUSH32(U256::MAX) // size - PUSH32(U256::MAX) // offset - PUSH8(0) // value - CREATE2 - STOP - }, - gas: MOCK_BLOCK_GAS_LIMIT.into(), - }; - - test_root(&case); - test_internal(&case); - } - - fn test_root(case: &TestCase) { - let ctx = TestContext::<2, 1>::new_with_logger_config( - None, - account_0_code_account_1_no_code(case.bytecode.clone()), - |mut txs, accs| { - txs[0] - .from(accs[1].address) - .to(accs[0].address) - .gas(case.gas); - }, - |block, _tx| block, - LoggerConfig { - enable_memory: true, - ..Default::default() - }, - ) - .unwrap(); - - log::debug!("{:?}", ctx.geth_traces[0]); - - CircuitTestBuilder::new_from_test_ctx(ctx).run(); - } - - fn test_internal(case: &TestCase) { - let code_a = bytecode! { - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(0x00) // argsLength - PUSH32(0x00) // argsOffset - PUSH1(0x00) // value - PUSH32(MOCK_ACCOUNTS[1].to_word()) // addr - PUSH32(case.gas) // gas - CALL - STOP - }; - - let ctx = TestContext::<3, 1>::new_with_logger_config( - None, - |accs| { - accs[0].address(MOCK_ACCOUNTS[0]).code(code_a); - accs[1] - .address(MOCK_ACCOUNTS[1]) - .code(case.bytecode.clone()); - accs[2].address(MOCK_ACCOUNTS[2]).balance(eth(1)); - }, - |mut txs, accs| { - txs[0] - .from(accs[2].address) - .to(accs[0].address) - .gas(word!("0xFFFFF")); - }, - |block, _tx| block, - LoggerConfig { - enable_memory: true, - ..Default::default() - }, - ) - .unwrap(); - - CircuitTestBuilder::new_from_test_ctx(ctx).run(); - } -} diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_dynamic_memory.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_dynamic_memory.rs index 932ef74500..94ab4d14c4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_dynamic_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_dynamic_memory.rs @@ -4,71 +4,46 @@ use crate::{ param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, util::{ - common_gadget::RestoreContextGadget, - constraint_builder::{ - ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, - Transition::{Delta, Same}, - }, - math_gadget::{IsEqualGadget, LtGadget}, + common_gadget::CommonErrorGadget, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::{LtGadget, PairSelectGadget}, memory_gadget::{ CommonMemoryAddressGadget, MemoryExpandedAddressGadget, MemoryExpansionGadget, }, - or, CachedRegion, Cell, Word, + or, CachedRegion, Cell, }, }, - table::CallContextFieldTag, witness::{Block, Call, ExecStep, Transaction}, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use gadgets::util::{not, select, Expr}; +use eth_types::{evm_types::OpcodeId, Field}; +use gadgets::util::{select, Expr}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ErrorOOGDynamicMemoryGadget { opcode: Cell, - is_create: IsEqualGadget, - is_return: IsEqualGadget, - value: Word, + is_return: PairSelectGadget, memory_address: MemoryExpandedAddressGadget, memory_expansion: MemoryExpansionGadget, insufficient_gas: LtGadget, - rw_counter_end_of_reversion: Cell, - restore_context: RestoreContextGadget, + common_error_gadget: CommonErrorGadget, } impl ExecutionGadget for ErrorOOGDynamicMemoryGadget { const NAME: &'static str = "ErrorOutOfGasDynamicMemoryExpansion"; const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasDynamicMemoryExpansion; - // Support other OOG due to pure memory including CREATE, RETURN and REVERT + // Support other OOG due to pure memory including RETURN and REVERT fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - cb.opcode_lookup(opcode.expr(), 1.expr()); - - let is_create = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::CREATE.expr()); - let is_return = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::RETURN.expr()); - - cb.require_equal( - "ErrorOutOfGasDynamicMemoryExpansion opcode must be CREATE or RETURN or REVERT", + let is_return = PairSelectGadget::construct( + cb, opcode.expr(), - select::expr( - is_create.expr(), - OpcodeId::CREATE.expr(), - select::expr( - is_return.expr(), - OpcodeId::RETURN.expr(), - OpcodeId::REVERT.expr(), - ), - ), + OpcodeId::RETURN.expr(), + OpcodeId::REVERT.expr(), ); let memory_address = MemoryExpandedAddressGadget::construct_self(cb); - - let value = cb.query_word_rlc(); - cb.condition(is_create.expr(), |cb| { - cb.stack_pop(value.expr()); - }); - cb.stack_pop(memory_address.offset_rlc()); cb.stack_pop(memory_address.length_rlc()); @@ -78,13 +53,9 @@ impl ExecutionGadget for ErrorOOGDynamicMemoryGadget { cb, cb.curr.state.gas_left.expr(), select::expr( - is_create.expr(), - OpcodeId::CREATE.constant_gas_cost().expr(), - select::expr( - is_return.expr(), - OpcodeId::RETURN.constant_gas_cost().expr(), - OpcodeId::REVERT.constant_gas_cost().expr(), - ), + is_return.expr().0, + OpcodeId::RETURN.constant_gas_cost().expr(), + OpcodeId::REVERT.constant_gas_cost().expr(), ) + memory_expansion.gas_cost(), ); @@ -94,48 +65,15 @@ impl ExecutionGadget for ErrorOOGDynamicMemoryGadget { 1.expr(), ); - // Current call must fail. - cb.call_context_lookup(false.expr(), None, CallContextFieldTag::IsSuccess, 0.expr()); - - let rw_counter_end_of_reversion = cb.query_cell(); - cb.call_context_lookup( - false.expr(), - None, - CallContextFieldTag::RwCounterEndOfReversion, - rw_counter_end_of_reversion.expr(), - ); - - cb.condition(cb.curr.state.is_root.expr(), |cb| { - cb.require_step_state_transition(StepStateTransition { - call_id: Same, - rw_counter: Delta( - 4.expr() + is_create.expr() + cb.curr.state.reversible_write_counter.expr(), - ), - ..StepStateTransition::any() - }); - }); - let restore_context = cb.condition(not::expr(cb.curr.state.is_root.expr()), |cb| { - RestoreContextGadget::construct( - cb, - 0.expr(), - 0.expr(), - 0.expr(), - 0.expr(), - 0.expr(), - 0.expr(), - ) - }); + let common_error_gadget = CommonErrorGadget::construct(cb, opcode.expr(), 4.expr()); Self { opcode, - is_create, is_return, - value, memory_address, memory_expansion, insufficient_gas, - rw_counter_end_of_reversion, - restore_context, + common_error_gadget, } } @@ -149,31 +87,18 @@ impl ExecutionGadget for ErrorOOGDynamicMemoryGadget { step: &ExecStep, ) -> Result<(), Error> { let opcode = step.opcode.unwrap(); - self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - self.is_create.assign( - region, - offset, - F::from(opcode.as_u64()), - F::from(OpcodeId::CREATE.as_u64()), - )?; self.is_return.assign( region, offset, F::from(opcode.as_u64()), F::from(OpcodeId::RETURN.as_u64()), + F::from(OpcodeId::REVERT.as_u64()), )?; - let mut rw_offset = 0; - if opcode == OpcodeId::CREATE { - let value = block.rws[step.rw_indices[rw_offset]].stack_value(); - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; - rw_offset += 1; - } - let memory_offset = block.rws[step.rw_indices[rw_offset]].stack_value(); - let memory_length = block.rws[step.rw_indices[rw_offset + 1]].stack_value(); + let [memory_offset, memory_length] = + [0, 1].map(|idx| block.rws[step.rw_indices[idx]].stack_value()); let memory_address = self.memory_address .assign(region, offset, memory_offset, memory_length)?; @@ -183,7 +108,6 @@ impl ExecutionGadget for ErrorOOGDynamicMemoryGadget { .assign(region, offset, step.memory_word_size(), [memory_address])? .1; let constant_gas_cost = opcode.constant_gas_cost().0; - self.insufficient_gas.assign( region, offset, @@ -191,20 +115,9 @@ impl ExecutionGadget for ErrorOOGDynamicMemoryGadget { F::from(memory_expansion_gas + constant_gas_cost), )?; - self.rw_counter_end_of_reversion.assign( - region, - offset, - Value::known(F::from(call.rw_counter_end_of_reversion as u64)), - )?; + self.common_error_gadget + .assign(region, offset, block, call, step, 4)?; - self.restore_context.assign( - region, - offset, - block, - call, - step, - if opcode == OpcodeId::CREATE { 5 } else { 4 }, - )?; Ok(()) } } @@ -313,13 +226,6 @@ mod tests { PUSH32(offset) REVERT }, - bytecode! { - PUSH32(size) - PUSH32(offset) - PUSH8(0) // value - CREATE - STOP - }, ] } } diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index caf2124d98..5af1d9c918 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -105,7 +105,7 @@ pub enum ExecutionState { ErrorOutOfGasSHA3, ErrorOutOfGasCall, ErrorOutOfGasSloadSstore, - ErrorOutOfGasCREATE2, + ErrorOutOfGasCREATE, ErrorOutOfGasSELFDESTRUCT, } @@ -150,7 +150,7 @@ impl ExecutionState { | Self::ErrorOutOfGasSHA3 | Self::ErrorOutOfGasCall | Self::ErrorOutOfGasSloadSstore - | Self::ErrorOutOfGasCREATE2 + | Self::ErrorOutOfGasCREATE | Self::ErrorOutOfGasSELFDESTRUCT ) } diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index 5267ba8341..c7fec70bc7 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -111,7 +111,7 @@ impl From<&ExecError> for ExecutionState { OogError::Sha3 => ExecutionState::ErrorOutOfGasSHA3, OogError::Call => ExecutionState::ErrorOutOfGasCall, OogError::SloadSstore => ExecutionState::ErrorOutOfGasSloadSstore, - OogError::Create2 => ExecutionState::ErrorOutOfGasCREATE2, + OogError::Create => ExecutionState::ErrorOutOfGasCREATE, OogError::SelfDestruct => ExecutionState::ErrorOutOfGasSELFDESTRUCT, }, }