From f74796293b0bd36030e131079d9642edabc34efb Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 14 Apr 2023 14:21:41 +0100 Subject: [PATCH 1/2] feat: copy circuit maintains accumulator value and value RLC for memory to bytecode --- mock/src/test_ctx.rs | 2 +- zkevm-circuits/src/copy_circuit.rs | 123 +++++++++++------- .../evm_circuit/execution/return_revert.rs | 23 ++-- zkevm-circuits/src/evm_circuit/util.rs | 13 ++ zkevm-circuits/src/table.rs | 32 ++--- 5 files changed, 121 insertions(+), 72 deletions(-) diff --git a/mock/src/test_ctx.rs b/mock/src/test_ctx.rs index 5da3907901..67eb88b439 100644 --- a/mock/src/test_ctx.rs +++ b/mock/src/test_ctx.rs @@ -76,7 +76,7 @@ pub use external_tracer::LoggerConfig; /// // Now we can start generating the traces and items we need to inspect /// // the behaviour of the generated env. /// ``` -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TestContext { /// chain id pub chain_id: Word, diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 57a83fded2..d7bc433088 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -47,6 +47,8 @@ pub struct CopyCircuitConfig { pub is_last: Column, /// The value copied in this copy step. pub value: Column, + /// Random linear combination accumulator value. + pub value_acc: Column, /// Whether the row is padding. pub is_pad: Column, /// In case of a bytecode tag, this denotes whether or not the copied byte @@ -105,6 +107,7 @@ impl SubCircuitConfig for CopyCircuitConfig { let q_step = meta.complex_selector(); let is_last = meta.advice_column(); let value = meta.advice_column_in(SecondPhase); + let value_acc = meta.advice_column_in(SecondPhase); let is_code = meta.advice_column(); let is_pad = meta.advice_column(); let is_first = copy_table.is_first; @@ -222,23 +225,48 @@ impl SubCircuitConfig for CopyCircuitConfig { rw_diff, ); }); - cb.condition( - and::expr([ - meta.query_advice(is_last, Rotation::cur()), - tag.value_equals(CopyDataType::RlcAcc, Rotation::cur())(meta), - ]), - |cb| { - cb.require_equal( - "value == rlc_acc at the last row for RlcAcc", - meta.query_advice(value, Rotation::cur()), - meta.query_advice(rlc_acc, Rotation::cur()), - ); - }, - ); cb.gate(meta.query_fixed(q_enable, Rotation::cur())) }); + meta.create_gate( + "Last Step (check value accumulator) Memory => Bytecode", + |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_equal( + "value_acc == rlc_acc on the last row", + meta.query_advice(value_acc, Rotation::next()), + meta.query_advice(rlc_acc, Rotation::next()), + ); + + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(is_last, Rotation::next()), + and::expr([ + tag.value_equals(CopyDataType::Memory, Rotation::cur())(meta), + tag.value_equals(CopyDataType::Bytecode, Rotation::next())(meta), + ]), + ])) + }, + ); + + meta.create_gate("Last Step (check value accumulator) RlcAcc", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_equal( + "value_acc == rlc_acc on the last row", + meta.query_advice(value_acc, Rotation::next()), + meta.query_advice(rlc_acc, Rotation::next()), + ); + + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(is_last, Rotation::next()), + tag.value_equals(CopyDataType::RlcAcc, Rotation::next())(meta), + ])) + }); + meta.create_gate("verify step (q_step == 1)", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -262,25 +290,30 @@ impl SubCircuitConfig for CopyCircuitConfig { ); }, ); + cb.require_equal( + "write value == read value", + meta.query_advice(value, Rotation::cur()), + meta.query_advice(value, Rotation::next()), + ); + cb.require_equal( + "value_acc is same for read-write rows", + meta.query_advice(value_acc, Rotation::cur()), + meta.query_advice(value_acc, Rotation::next()), + ); cb.condition( - not::expr(tag.value_equals(CopyDataType::RlcAcc, Rotation::next())( - meta, - )), + and::expr([ + not::expr(meta.query_advice(is_last, Rotation::next())), + not::expr(meta.query_advice(is_pad, Rotation::cur())), + ]), |cb| { cb.require_equal( - "write value == read value (if not rlc acc)", - meta.query_advice(value, Rotation::cur()), - meta.query_advice(value, Rotation::next()), + "value_acc(2) == value_acc(0) * r + value(2)", + meta.query_advice(value_acc, Rotation(2)), + meta.query_advice(value_acc, Rotation::cur()) * challenges.keccak_input() + + meta.query_advice(value, Rotation(2)), ); }, ); - cb.condition(meta.query_advice(is_first, Rotation::cur()), |cb| { - cb.require_equal( - "write value == read value (is_first == 1)", - meta.query_advice(value, Rotation::cur()), - meta.query_advice(value, Rotation::next()), - ); - }); cb.require_zero( "value == 0 when is_pad == 1 for read", and::expr([ @@ -298,25 +331,9 @@ impl SubCircuitConfig for CopyCircuitConfig { meta.query_advice(is_pad, Rotation::next()), ); - cb.gate(meta.query_selector(q_step)) - }); - - meta.create_gate("verify_step (q_step == 0)", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_equal( - "rows[2].value == rows[0].value * r + rows[1].value", - meta.query_advice(value, Rotation(2)), - meta.query_advice(value, Rotation::cur()) * challenges.keccak_input() - + meta.query_advice(value, Rotation::next()), - ); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_selector(q_step)), - not::expr(meta.query_advice(is_last, Rotation::cur())), - tag.value_equals(CopyDataType::RlcAcc, Rotation::cur())(meta), - not::expr(meta.query_advice(is_pad, Rotation::cur())), + meta.query_selector(q_step), ])) }); @@ -402,6 +419,7 @@ impl SubCircuitConfig for CopyCircuitConfig { q_step, is_last, value, + value_acc, is_pad, is_code, q_enable, @@ -463,9 +481,15 @@ impl CopyCircuitConfig { )?; // is_last, value, is_pad, is_code - for (column, &(value, label)) in [self.is_last, self.value, self.is_pad, self.is_code] - .iter() - .zip_eq(circuit_row) + for (column, &(value, label)) in [ + self.is_last, + self.value, + self.value_acc, + self.is_pad, + self.is_code, + ] + .iter() + .zip_eq(circuit_row) { region.assign_advice( || format!("{} at row: {}", label, *offset), @@ -616,6 +640,13 @@ impl CopyCircuitConfig { *offset, || Value::known(F::zero()), )?; + // value_acc + region.assign_advice( + || format!("assign value_acc {}", *offset), + self.value_acc, + *offset, + || Value::known(F::zero()), + )?; // rlc_acc region.assign_advice( || format!("assign rlc_acc {}", *offset), diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index d417a3590f..8d118ed06f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -27,6 +27,7 @@ pub(crate) struct ReturnRevertGadget { opcode: Cell, range: MemoryAddressGadget, + init_code_rlc: Cell, is_success: Cell, restore_context: RestoreContextGadget, @@ -94,11 +95,12 @@ impl ExecutionGadget for ReturnRevertGadget { let is_contract_deployment = is_create.clone() * is_success.expr() * not::expr(copy_rw_increase_is_zero.expr()); - let (caller_id, address, reversion_info, code_hash) = + let (caller_id, address, reversion_info, code_hash, init_code_rlc) = cb.condition(is_contract_deployment.clone(), |cb| { // We don't need to place any additional constraints on code_hash because the // copy circuit enforces that it is the hash of the bytes in the copy lookup. let code_hash = cb.query_cell_phase2(); + let init_code_rlc = cb.query_cell_phase2(); cb.copy_table_lookup( cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), @@ -108,7 +110,7 @@ impl ExecutionGadget for ReturnRevertGadget { range.address(), 0.expr(), range.length(), - 0.expr(), + init_code_rlc.expr(), copy_rw_increase.expr(), ); @@ -127,7 +129,7 @@ impl ExecutionGadget for ReturnRevertGadget { Some(&mut reversion_info), ); - (caller_id, address, reversion_info, code_hash) + (caller_id, address, reversion_info, code_hash, init_code_rlc) }); // Case B in the specs. @@ -218,6 +220,7 @@ impl ExecutionGadget for ReturnRevertGadget { Self { opcode, range, + init_code_rlc, is_success, copy_length, copy_rw_increase, @@ -276,6 +279,11 @@ impl ExecutionGadget for ReturnRevertGadget { let values: Vec<_> = (3..3 + length.as_usize()) .map(|i| block.rws[step.rw_indices[i]].memory_value()) .collect(); + self.init_code_rlc.assign( + region, + offset, + region.keccak_rlc(&values.iter().rev().cloned().collect::>()), + )?; let mut code_hash = CodeDB::hash(&values).to_fixed_bytes(); code_hash.reverse(); self.code_hash.assign( @@ -617,10 +625,8 @@ mod test { PUSH1(0) // dest offset RETURNDATACOPY }); - - let block: GethData = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode.clone()) - .unwrap() - .into(); + let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode.clone()).unwrap(); + let block: GethData = test_ctx.clone().into(); // collect return opcode, retrieve next step, assure both contract create // successfully @@ -651,7 +657,6 @@ mod test { .iter() .for_each(|size| assert_eq!(size, &Word::zero())); - let text_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(); - CircuitTestBuilder::new_from_test_ctx(text_ctx).run(); + CircuitTestBuilder::new_from_test_ctx(test_ctx).run(); } } diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 6749480939..4936bfc924 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -195,10 +195,23 @@ impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> { .evm_word() .map(|r| rlc::value(&n.to_le_bytes(), r)) } + + pub fn keccak_rlc(&self, le_bytes: &[u8]) -> Value { + self.challenges + .keccak_input() + .map(|r| rlc::value(le_bytes, r)) + } + pub fn empty_code_hash_rlc(&self) -> Value { self.word_rlc(CodeDB::empty_code_hash().to_word()) } + pub fn code_hash(&self, n: U256) -> Value { + self.challenges + .evm_word() + .map(|r| rlc::value(&n.to_le_bytes(), r)) + } + /// Constrains a cell to have a constant value. /// /// Returns an error if the cell is in a column where equality has not been diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index c1eddcbb83..4dec7a36b6 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1044,7 +1044,7 @@ pub struct CopyTable { } type CopyTableRow = [(Value, &'static str); 8]; -type CopyCircuitRow = [(Value, &'static str); 4]; +type CopyCircuitRow = [(Value, &'static str); 5]; impl CopyTable { /// Construct a new CopyTable @@ -1069,7 +1069,7 @@ impl CopyTable { ) -> Vec<(CopyDataType, CopyTableRow, CopyCircuitRow)> { let mut assignments = Vec::new(); // rlc_acc - let rlc_acc = if copy_event.dst_type == CopyDataType::RlcAcc { + let rlc_acc = { let values = copy_event .bytes .iter() @@ -1078,8 +1078,6 @@ impl CopyTable { challenges .keccak_input() .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) - } else { - Value::known(F::zero()) }; let mut value_acc = Value::known(F::zero()); for (step_idx, (is_read_step, copy_step)) in copy_event @@ -1154,17 +1152,11 @@ impl CopyTable { // bytes_left let bytes_left = u64::try_from(copy_event.bytes.len() * 2 - step_idx).unwrap() / 2; // value - let value = if copy_event.dst_type == CopyDataType::RlcAcc { - if is_read_step { - Value::known(F::from(copy_step.value as u64)) - } else { - value_acc = value_acc * challenges.keccak_input() - + Value::known(F::from(copy_step.value as u64)); - value_acc - } - } else { - Value::known(F::from(copy_step.value as u64)) - }; + let value = Value::known(F::from(copy_step.value as u64)); + // value_acc + if is_read_step { + value_acc = value_acc * challenges.keccak_input() + value; + } // is_pad let is_pad = Value::known(F::from( is_read_step && copy_step_addr >= copy_event.src_addr_end, @@ -1184,7 +1176,14 @@ impl CopyTable { "src_addr_end", ), (Value::known(F::from(bytes_left)), "bytes_left"), - (rlc_acc, "rlc_acc"), + ( + match (copy_event.src_type, copy_event.dst_type) { + (CopyDataType::Memory, CopyDataType::Bytecode) => rlc_acc, + (_, CopyDataType::RlcAcc) => rlc_acc, + _ => Value::known(F::zero()), + }, + "rlc_acc", + ), ( Value::known(F::from(copy_event.rw_counter(step_idx))), "rw_counter", @@ -1197,6 +1196,7 @@ impl CopyTable { [ (is_last, "is_last"), (value, "value"), + (value_acc, "value_acc"), (is_pad, "is_pad"), (is_code, "is_code"), ], From 65f72e4ded5aa907da0a4da5b33f9f8bd6e91549 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 14 Apr 2023 14:47:49 +0100 Subject: [PATCH 2/2] feat: insuff balance and nonce overflow related errors --- .../circuit_input_builder/input_state_ref.rs | 50 ++++++++++++++++++- .../src/circuit_input_builder/tracer_tests.rs | 6 ++- bus-mapping/src/error.rs | 28 +++++++++-- bus-mapping/src/evm/opcodes.rs | 23 +++++++-- zkevm-circuits/src/witness/step.rs | 14 ++++-- 5 files changed, 108 insertions(+), 13 deletions(-) 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 9258676eab..125d5937f6 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -6,7 +6,7 @@ use super::{ TransactionContext, }; use crate::{ - error::{get_step_reported_error, ExecError}, + error::{get_step_reported_error, ExecError, InsufficientBalanceError, NonceUintOverflowError}, exec_trace::OperationRef, operation::{ AccountField, AccountOp, CallContextField, CallContextOp, MemoryOp, Op, OpEnum, Operation, @@ -434,6 +434,24 @@ impl<'a> CircuitInputStateRef<'a> { Ok(()) } + /// Add address to access list for the current transaction. + pub fn tx_access_list_write( + &mut self, + step: &mut ExecStep, + address: Address, + ) -> Result<(), Error> { + let is_warm = self.sdb.check_account_in_access_list(&address); + self.push_op_reversible( + step, + TxAccessListAccountOp { + tx_id: self.tx_ctx.id(), + address, + is_warm: true, + is_warm_prev: is_warm, + }, + ) + } + /// Push a write type [`TxAccessListAccountOp`] into the /// [`OperationContainer`](crate::operation::OperationContainer) with the /// next [`RWCounter`](crate::operation::RWCounter), and then @@ -688,6 +706,18 @@ impl<'a> CircuitInputStateRef<'a> { )) } + pub(crate) fn reversion_info_read(&mut self, step: &mut ExecStep, call: &Call) { + for (field, value) in [ + ( + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.to_word(), + ), + (CallContextField::IsPersistent, call.is_persistent.to_word()), + ] { + self.call_context_read(step, call.call_id, field, value); + } + } + /// Check if address is a precompiled or not. pub fn is_precompiled(&self, address: &Address) -> bool { address.0[0..19] == [0u8; 19] && (1..=9).contains(&address.0[19]) @@ -1299,7 +1329,23 @@ impl<'a> CircuitInputStateRef<'a> { return Err(Error::AccountNotFound(sender)); } if account.balance < value { - return Ok(Some(ExecError::InsufficientBalance)); + return Ok(Some(ExecError::InsufficientBalance(match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => InsufficientBalanceError::Call, + OpcodeId::CREATE => InsufficientBalanceError::Create, + OpcodeId::CREATE2 => InsufficientBalanceError::Create2, + op => { + unreachable!("insufficient balance error unexpected for opcode: {:?}", op) + } + }))); + } + + // Nonce Uint overflow + if account.nonce >= u64::MAX.into() { + return Ok(Some(ExecError::NonceUintOverflow(match step.op { + OpcodeId::CREATE => NonceUintOverflowError::Create, + OpcodeId::CREATE2 => NonceUintOverflowError::Create2, + op => unreachable!("Nonce Uint overflow error unexpected for opcode: {:?}", op), + }))); } // Address collision diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 39dc4fbeb0..d89453934f 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -1,7 +1,7 @@ use super::*; use crate::{ circuit_input_builder::access::gen_state_access_trace, - error::{ExecError, OogError}, + error::{ExecError, InsufficientBalanceError, OogError}, geth_errors::{ GETH_ERR_GAS_UINT_OVERFLOW, GETH_ERR_OUT_OF_GAS, GETH_ERR_STACK_OVERFLOW, GETH_ERR_STACK_UNDERFLOW, @@ -288,7 +288,9 @@ fn tracer_err_insufficient_balance() { let mut builder = CircuitInputBuilderTx::new(&block, step); assert_eq!( builder.state_ref().get_step_err(step, next_step).unwrap(), - Some(ExecError::InsufficientBalance) + Some(ExecError::InsufficientBalance( + InsufficientBalanceError::Call + )) ); } diff --git a/bus-mapping/src/error.rs b/bus-mapping/src/error.rs index 8fe916ce33..b35edfc1fc 100644 --- a/bus-mapping/src/error.rs +++ b/bus-mapping/src/error.rs @@ -100,6 +100,26 @@ pub enum OogError { SelfDestruct, } +/// Insufficient balance errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum InsufficientBalanceError { + /// Insufficient balance during CALL/CALLCODE opcode. + Call, + /// Insufficient balance during CREATE opcode. + Create, + /// Insufficient balance during CREATE2 opcode. + Create2, +} + +/// Nonce uint overflow errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonceUintOverflowError { + /// Nonce uint overflow during CREATE opcode. + Create, + /// Nonce uint overflow during CREATE2 opcode. + Create2, +} + /// EVM Execution Error #[derive(Clone, Debug, PartialEq, Eq)] pub enum ExecError { @@ -116,9 +136,9 @@ pub enum ExecError { WriteProtection, /// For CALL, CALLCODE, DELEGATECALL, STATICCALL Depth, - /// For CALL, CALLCODE - InsufficientBalance, - /// For CREATE, CREATE2 + /// For CALL, CALLCODE, CREATE, CREATE2 + InsufficientBalance(InsufficientBalanceError), + /// For CREATE2 ContractAddressCollision, /// contract must not begin with 0xef due to EIP #3541 EVM Object Format /// (EOF) @@ -131,6 +151,8 @@ pub enum ExecError { CodeStoreOutOfGas, /// For RETURN in a CREATE, CREATE2 MaxCodeSizeExceeded, + /// For CREATE, CREATE2 + NonceUintOverflow(NonceUintOverflowError), } // TODO: Move to impl block. diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 8e558fb189..70e1327ffe 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -1,7 +1,7 @@ //! Definition of each opcode of the EVM. use crate::{ circuit_input_builder::{CircuitInputStateRef, ExecStep}, - error::{ExecError, OogError}, + error::{ExecError, InsufficientBalanceError, NonceUintOverflowError, OogError}, evm::OpcodeId, operation::{ AccountField, AccountOp, CallContextField, TxAccessListAccountOp, TxReceiptField, @@ -278,8 +278,25 @@ fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option Some(OOGSloadSstore::gen_associated_ops), ExecError::StackOverflow => Some(ErrorSimple::gen_associated_ops), ExecError::StackUnderflow => Some(ErrorSimple::gen_associated_ops), - // call & callcode can encounter InsufficientBalance error, Use pop-7 generic CallOpcode - ExecError::InsufficientBalance => Some(CallOpcode::<7>::gen_associated_ops), + ExecError::InsufficientBalance(InsufficientBalanceError::Call) => { + Some(CallOpcode::<7>::gen_associated_ops) + } + // create & create2 can encounter insufficient balance. + ExecError::InsufficientBalance(InsufficientBalanceError::Create) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::InsufficientBalance(InsufficientBalanceError::Create2) => { + Some(DummyCreate::::gen_associated_ops) + } + // only create2 may cause ContractAddressCollision error, so use DummyCreate::. + ExecError::ContractAddressCollision => Some(DummyCreate::::gen_associated_ops), + // create & create2 can encounter nonce uint overflow. + ExecError::NonceUintOverflow(NonceUintOverflowError::Create) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::NonceUintOverflow(NonceUintOverflowError::Create2) => { + Some(DummyCreate::::gen_associated_ops) + } ExecError::WriteProtection => Some(ErrorWriteProtection::gen_associated_ops), ExecError::ReturnDataOutOfBounds => Some(ErrorReturnDataOutOfBound::gen_associated_ops), diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index bcc8e3bd37..afa66d34e1 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -1,6 +1,6 @@ use bus_mapping::{ circuit_input_builder, - error::{ExecError, OogError}, + error::{ExecError, InsufficientBalanceError, NonceUintOverflowError, OogError}, evm::OpcodeId, operation, }; @@ -65,8 +65,16 @@ impl From<&ExecError> for ExecutionState { ExecError::StackOverflow | ExecError::StackUnderflow => ExecutionState::ErrorStack, ExecError::WriteProtection => ExecutionState::ErrorWriteProtection, ExecError::Depth => ExecutionState::ErrorDepth, - ExecError::InsufficientBalance => ExecutionState::ErrorInsufficientBalance, - ExecError::ContractAddressCollision => ExecutionState::ErrorContractAddressCollision, + ExecError::InsufficientBalance(insuff_balance_err) => match insuff_balance_err { + InsufficientBalanceError::Call => ExecutionState::CALL_OP, + InsufficientBalanceError::Create => ExecutionState::CREATE, + InsufficientBalanceError::Create2 => ExecutionState::CREATE2, + }, + ExecError::ContractAddressCollision => ExecutionState::CREATE2, + ExecError::NonceUintOverflow(nonce_overflow_err) => match nonce_overflow_err { + NonceUintOverflowError::Create => ExecutionState::CREATE, + NonceUintOverflowError::Create2 => ExecutionState::CREATE2, + }, ExecError::InvalidCreationCode => ExecutionState::ErrorInvalidCreationCode, ExecError::InvalidJump => ExecutionState::ErrorInvalidJump, ExecError::ReturnDataOutOfBounds => ExecutionState::ErrorReturnDataOutOfBound,