From 2291146244cb98d486bf5321eb65b42aa38bb9b1 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Wed, 6 Mar 2024 11:09:07 +0000 Subject: [PATCH] fix: add missing copy event, keccak input, cell assignments, calldata.len=0 case --- .../src/circuit_input_builder/block.rs | 3 +- bus-mapping/src/evm/opcodes/begin_end_tx.rs | 27 +++++++- .../src/evm_circuit/execution/begin_tx.rs | 69 ++++++++++++++----- 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/block.rs b/bus-mapping/src/circuit_input_builder/block.rs index fa0abc6f41..219a844ce4 100644 --- a/bus-mapping/src/circuit_input_builder/block.rs +++ b/bus-mapping/src/circuit_input_builder/block.rs @@ -84,7 +84,8 @@ pub struct Block { pub block_steps: BlockSteps, /// Copy events in this block. pub copy_events: Vec, - /// Inputs to the SHA3 opcode + /// Inputs to the SHA3 opcode as well as data hashed during the EVM execution like init code + /// and address creation inputs. pub sha3_inputs: Vec>, /// Exponentiation events in the block. pub exp_events: Vec, diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index 1b6c79a5c8..a760b1850f 100644 --- a/bus-mapping/src/evm/opcodes/begin_end_tx.rs +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -1,6 +1,8 @@ use super::TxExecSteps; use crate::{ - circuit_input_builder::{Call, CircuitInputStateRef, ExecState, ExecStep}, + circuit_input_builder::{ + Call, CircuitInputStateRef, CopyDataType, CopyEvent, ExecState, ExecStep, NumberOrHash, + }, operation::{AccountField, AccountOp, CallContextField, TxReceiptField, TxRefundOp, RW}, state_db::CodeDB, Error, @@ -148,6 +150,29 @@ fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result 0 { + state.push_copy( + &mut exec_step, + CopyEvent { + src_addr: 0, + src_addr_end: state.tx.call_data.len() as u64, + src_type: CopyDataType::TxCalldata, + src_id: NumberOrHash::Number(state.tx.id as usize), + dst_addr: 0, + dst_type: CopyDataType::RlcAcc, + dst_id: NumberOrHash::Number(0), + log_id: None, + rw_counter_start: state.block_ctx.rwc, + bytes: state.tx.call_data.iter().map(|b| (*b, false)).collect(), + }, + ); + } + dbg!((state.tx.id, state.tx.call_data.len(), &state.tx.call_data)); } // There are 4 branches from here. diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index dc1ae145e4..5f19ad7bbe 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -12,9 +12,10 @@ use crate::{ }, is_precompiled, math_gadget::{ - ContractCreateGadget, IsEqualWordGadget, IsZeroWordGadget, RangeCheckGadget, + ContractCreateGadget, IsEqualWordGadget, IsZeroGadget, IsZeroWordGadget, + RangeCheckGadget, }, - not, or, + not, or, rlc, tx::{BeginTxHelperGadget, TxDataGadget}, AccountAddress, CachedRegion, Cell, StepRws, }, @@ -45,6 +46,9 @@ pub(crate) struct BeginTxGadget { code_hash: WordLoHiCell, is_empty_code_hash: IsEqualWordGadget>, WordLoHi>>, caller_nonce_hash_bytes: Word32Cell, + calldata_length: Cell, + calldata_length_is_zero: IsZeroGadget, + calldata_rlc: Cell, create: ContractCreateGadget, callee_not_exists: IsZeroWordGadget>, is_caller_callee_equal: Cell, @@ -184,6 +188,9 @@ impl ExecutionGadget for BeginTxGadget { ); let caller_nonce_hash_bytes = cb.query_word32(); + let calldata_length = cb.query_cell(); + let calldata_length_is_zero = cb.is_zero(calldata_length.expr()); + let calldata_rlc = cb.query_cell_phase2(); let create = ContractCreateGadget::construct(cb); cb.require_equal_word( "tx caller address equivalence", @@ -216,23 +223,36 @@ impl ExecutionGadget for BeginTxGadget { caller_nonce_hash_bytes.to_word(), ); - let length = cb.tx_context(tx_id.expr(), TxContextFieldTag::CallDataLength, None); - let rlc_acc = cb.query_cell_phase2(); - cb.copy_table_lookup( - WordLoHi::from_lo_unchecked(tx_id.expr()), - CopyDataType::TxCalldata.expr(), - WordLoHi::zero(), - CopyDataType::RlcAcc.expr(), - 0.expr(), - length.expr(), - 0.expr(), - length.expr(), - rlc_acc.expr(), - 0.expr(), + cb.tx_context_lookup( + tx_id.expr(), + TxContextFieldTag::CallDataLength, + None, + WordLoHi::from_lo_unchecked(calldata_length.expr()), ); + // If calldata_length > 0 we use the copy circuit to calculate the calldata_rlc for the + // keccack input. + cb.condition(not::expr(calldata_length_is_zero.expr()), |cb| { + cb.copy_table_lookup( + WordLoHi::from_lo_unchecked(tx_id.expr()), + CopyDataType::TxCalldata.expr(), + WordLoHi::zero(), + CopyDataType::RlcAcc.expr(), + 0.expr(), + calldata_length.expr(), + 0.expr(), + calldata_length.expr(), + calldata_rlc.expr(), + 0.expr(), + ) + }); + // If calldata_length == 0, the copy circuit will not contain any entry, so we skip the + // lookup and instead force calldata_rlc to be 0 for the keccack input. + cb.condition(calldata_length_is_zero.expr(), |cb| { + cb.require_equal("calldata_rlc = 0", calldata_rlc.expr(), 0.expr()); + }); cb.keccak_table_lookup( - rlc_acc.expr(), - length.expr(), + calldata_rlc.expr(), + calldata_length.expr(), cb.curr.state.code_hash.to_word(), ); @@ -454,6 +474,9 @@ impl ExecutionGadget for BeginTxGadget { code_hash, is_empty_code_hash, caller_nonce_hash_bytes, + calldata_length, + calldata_length_is_zero, + calldata_rlc, create, callee_not_exists, is_caller_callee_equal, @@ -554,6 +577,18 @@ impl ExecutionGadget for BeginTxGadget { offset, U256::from_big_endian(&untrimmed_contract_addr), )?; + self.calldata_length.assign( + region, + offset, + Value::known(F::from(tx.call_data.len() as u64)), + )?; + self.calldata_length_is_zero + .assign(region, offset, F::from(tx.call_data.len() as u64))?; + let calldata_rlc = region + .challenges() + .keccak_input() + .map(|randomness| rlc::value(tx.call_data.iter().rev(), randomness)); + self.calldata_rlc.assign(region, offset, calldata_rlc)?; self.create.assign( region, offset,