diff --git a/bus-mapping/src/evm/opcodes/sload.rs b/bus-mapping/src/evm/opcodes/sload.rs index aa04230f93..764fa98784 100644 --- a/bus-mapping/src/evm/opcodes/sload.rs +++ b/bus-mapping/src/evm/opcodes/sload.rs @@ -1,10 +1,10 @@ use super::Opcode; use crate::circuit_input_builder::CircuitInputStateRef; use crate::{ - operation::{StorageOp, RW}, + operation::{CallContextField, CallContextOp, StorageOp, TxAccessListAccountStorageOp, RW}, Error, }; -use eth_types::GethExecStep; +use eth_types::{GethExecStep, ToWord, Word}; /// Placeholder structure used to implement [`Opcode`] trait over it /// corresponding to the [`OpcodeId::SLOAD`](crate::evm::OpcodeId::SLOAD) @@ -19,6 +19,39 @@ impl Opcode for Sload { ) -> Result<(), Error> { let step = &steps[0]; + state.push_op( + RW::READ, + CallContextOp { + call_id: state.call().call_id, + field: CallContextField::TxId, + value: Word::from(state.tx_ctx.id()), + }, + ); + state.push_op( + RW::READ, + CallContextOp { + call_id: state.call().call_id, + field: CallContextField::RwCounterEndOfReversion, + value: Word::from(state.call().rw_counter_end_of_reversion), + }, + ); + state.push_op( + RW::READ, + CallContextOp { + call_id: state.call().call_id, + field: CallContextField::IsPersistent, + value: Word::from(state.call().is_persistent as u8), + }, + ); + state.push_op( + RW::READ, + CallContextOp { + call_id: state.call().call_id, + field: CallContextField::CalleeAddress, + value: state.call().address.to_word(), + }, + ); + // First stack read let stack_value_read = step.stack.last()?; let stack_position = step.stack.last_filled(); @@ -35,12 +68,25 @@ impl Opcode for Sload { stack_value_read, storage_value_read, storage_value_read, + state.tx_ctx.id(), + storage_value_read, // TODO: committed_value ), ); // First stack write state.push_stack_op(RW::WRITE, stack_position, storage_value_read); + state.push_op_reversible( + RW::WRITE, + TxAccessListAccountStorageOp { + tx_id: state.tx_ctx.id(), + address: state.call().address, + key: stack_value_read, + value: true, + value_prev: false, // TODO: + }, + ); + Ok(()) } } @@ -49,6 +95,10 @@ impl Opcode for Sload { mod sload_tests { use super::*; use crate::circuit_input_builder::{ExecStep, TransactionContext}; + use crate::{ + operation::{CallContextField, CallContextOp, StorageOp, TxAccessListAccountStorageOp, RW}, + Error, + }; use eth_types::evm_types::StackAddress; use eth_types::{bytecode, Address, Word}; use pretty_assertions::assert_eq; @@ -90,6 +140,40 @@ mod sload_tests { 0, ); let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step); + + state_ref.push_op( + RW::READ, + CallContextOp { + call_id: state_ref.call().call_id, + field: CallContextField::TxId, + value: Word::from(state_ref.tx_ctx.id()), + }, + ); + state_ref.push_op( + RW::READ, + CallContextOp { + call_id: state_ref.call().call_id, + field: CallContextField::RwCounterEndOfReversion, + value: Word::from(state_ref.call().rw_counter_end_of_reversion), + }, + ); + state_ref.push_op( + RW::READ, + CallContextOp { + call_id: state_ref.call().call_id, + field: CallContextField::IsPersistent, + value: Word::from(state_ref.call().is_persistent as u8), + }, + ); + state_ref.push_op( + RW::READ, + CallContextOp { + call_id: state_ref.call().call_id, + field: CallContextField::CalleeAddress, + value: state_ref.call().address.to_word(), + }, + ); + // Add StackOp associated to the stack pop. state_ref.push_stack_op(RW::READ, StackAddress::from(1023), Word::from(0x0u32)); // Add StorageOp associated to the storage read. @@ -100,10 +184,23 @@ mod sload_tests { Word::from(0x0u32), Word::from(0x6fu32), Word::from(0x6fu32), + 1usize, + Word::from(0x6fu32), ), ); // Add StackOp associated to the stack push. state_ref.push_stack_op(RW::WRITE, StackAddress::from(1023), Word::from(0x6fu32)); + state_ref.push_op_reversible( + RW::WRITE, + TxAccessListAccountStorageOp { + tx_id: state_ref.tx_ctx.id(), + address: Address::from([0u8; 20]), + key: Word::from(0x0u32), + value: true, + value_prev: false, // TODO: + }, + ); + tx.steps_mut().push(step); test_builder.block.txs_mut().push(tx); diff --git a/bus-mapping/src/operation.rs b/bus-mapping/src/operation.rs index ecb430b267..b833c4d089 100644 --- a/bus-mapping/src/operation.rs +++ b/bus-mapping/src/operation.rs @@ -286,14 +286,18 @@ pub struct StorageOp { pub value: Word, /// Storage Value before the operation pub value_prev: Word, + /// Transaction ID: Transaction index in the block starting at 1. + pub tx_id: usize, + /// Storage Value before the transaction + pub committed_value: Word, } impl fmt::Debug for StorageOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("StorageOp { ")?; f.write_fmt(format_args!( - "addr: {:?}, key: {:?}, val_prev: 0x{:x}, val: 0x{:x}", - self.address, self.key, self.value_prev, self.value, + "tx_id: {:?}, addr: {:?}, key: {:?}, committed_val: 0x{:x}, val_prev: 0x{:x}, val: 0x{:x}", + self.tx_id, self.address, self.key, self.committed_value, self.value_prev, self.value ))?; f.write_str(" }") } @@ -301,12 +305,21 @@ impl fmt::Debug for StorageOp { impl StorageOp { /// Create a new instance of a `StorageOp` from it's components. - pub const fn new(address: Address, key: Word, value: Word, value_prev: Word) -> StorageOp { + pub const fn new( + address: Address, + key: Word, + value: Word, + value_prev: Word, + tx_id: usize, + committed_value: Word, + ) -> StorageOp { StorageOp { address, key, value, value_prev, + tx_id, + committed_value, } } diff --git a/bus-mapping/src/operation/container.rs b/bus-mapping/src/operation/container.rs index d0aee67445..8d4c473833 100644 --- a/bus-mapping/src/operation/container.rs +++ b/bus-mapping/src/operation/container.rs @@ -191,6 +191,8 @@ mod container_test { Word::default(), Word::from(0x1), Word::default(), + 1usize, + Word::default(), ), ); let stack_ref = operation_container.insert(stack_operation.clone()); diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 6d40cca137..9cb4c5a45b 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -44,6 +44,7 @@ mod selfbalance; mod signed_comparator; mod signextend; mod stop; +mod storage; mod swap; mod timestamp; @@ -74,6 +75,7 @@ use selfbalance::SelfbalanceGadget; use signed_comparator::SignedComparatorGadget; use signextend::SignextendGadget; use stop::StopGadget; +use storage::SloadGadget; use swap::SwapGadget; use timestamp::TimestampGadget; @@ -130,6 +132,7 @@ pub(crate) struct ExecutionConfig { coinbase_gadget: CoinbaseGadget, timestamp_gadget: TimestampGadget, selfbalance_gadget: SelfbalanceGadget, + sload_gadget: SloadGadget, } impl ExecutionConfig { @@ -264,6 +267,7 @@ impl ExecutionConfig { msize_gadget: configure_gadget!(), coinbase_gadget: configure_gadget!(), timestamp_gadget: configure_gadget!(), + sload_gadget: configure_gadget!(), step: step_curr, presets_map, }; @@ -519,6 +523,7 @@ impl ExecutionConfig { assign_exec_step!(self.timestamp_gadget) } ExecutionState::SELFBALANCE => assign_exec_step!(self.selfbalance_gadget), + ExecutionState::SLOAD => assign_exec_step!(self.sload_gadget), ExecutionState::CALLDATACOPY => { assign_exec_step!(self.calldatacopy_gadget) } diff --git a/zkevm-circuits/src/evm_circuit/execution/storage.rs b/zkevm-circuits/src/evm_circuit/execution/storage.rs new file mode 100644 index 0000000000..b93c20808e --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/execution/storage.rs @@ -0,0 +1,3 @@ +mod sload; + +pub(crate) use sload::SloadGadget; diff --git a/zkevm-circuits/src/evm_circuit/execution/storage/sload.rs b/zkevm-circuits/src/evm_circuit/execution/storage/sload.rs new file mode 100644 index 0000000000..0e96cf8b7f --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/execution/storage/sload.rs @@ -0,0 +1,425 @@ +use crate::{ + evm_circuit::{ + execution::ExecutionGadget, + step::ExecutionState, + table::CallContextFieldTag, + util::{ + common_gadget::SameContextGadget, + constraint_builder::{ + ConstraintBuilder, StepStateTransition, + Transition::{Delta, To}, + }, + select, Cell, Word, + }, + witness::{Block, Call, ExecStep, Transaction}, + }, + util::Expr, +}; +use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use halo2_proofs::{ + circuit::Region, + plonk::{Error, Expression}, +}; + +#[derive(Clone, Debug)] +pub(crate) struct SloadGadget { + same_context: SameContextGadget, + tx_id: Cell, + rw_counter_end_of_reversion: Cell, + is_persistent: Cell, + callee_address: Cell, + key: Word, + value: Word, + committed_value: Word, + is_warm: Cell, +} + +impl ExecutionGadget for SloadGadget { + const NAME: &'static str = "SLOAD"; + + const EXECUTION_STATE: ExecutionState = ExecutionState::SLOAD; + + fn configure(cb: &mut ConstraintBuilder) -> Self { + let opcode = cb.query_cell(); + + let [tx_id, rw_counter_end_of_reversion, is_persistent, callee_address] = [ + CallContextFieldTag::TxId, + CallContextFieldTag::RwCounterEndOfReversion, + CallContextFieldTag::IsPersistent, + CallContextFieldTag::CalleeAddress, + ] + .map(|field_tag| cb.call_context(None, field_tag)); + + let key = cb.query_word(); + // Pop the key from the stack + cb.stack_pop(key.expr()); + + let value = cb.query_word(); + let committed_value = cb.query_word(); + cb.account_storage_read( + callee_address.expr(), + key.expr(), + value.expr(), + tx_id.expr(), + committed_value.expr(), + ); + + cb.stack_push(value.expr()); + + let is_warm = cb.query_bool(); + cb.account_storage_access_list_write_with_reversion( + tx_id.expr(), + callee_address.expr(), + key.expr(), + true.expr(), + is_warm.expr(), + is_persistent.expr(), + rw_counter_end_of_reversion.expr(), + ); + + let step_state_transition = StepStateTransition { + rw_counter: Delta(8.expr()), + program_counter: Delta(1.expr()), + state_write_counter: To(1.expr()), + ..Default::default() + }; + let gas_cost = SloadGasGadget::construct(cb, is_warm.expr()); + let same_context = + SameContextGadget::construct(cb, opcode, step_state_transition, Some(gas_cost.expr())); + + Self { + same_context, + tx_id, + rw_counter_end_of_reversion, + is_persistent, + callee_address, + key, + value, + committed_value, + is_warm, + } + } + + fn assign_exec_step( + &self, + region: &mut Region<'_, F>, + offset: usize, + block: &Block, + tx: &Transaction, + call: &Call, + step: &ExecStep, + ) -> Result<(), Error> { + self.same_context.assign_exec_step(region, offset, step)?; + + self.tx_id + .assign(region, offset, Some(F::from(tx.id as u64)))?; + self.rw_counter_end_of_reversion.assign( + region, + offset, + Some(F::from(call.rw_counter_end_of_reversion as u64)), + )?; + self.is_persistent + .assign(region, offset, Some(F::from(call.is_persistent as u64)))?; + self.callee_address + .assign(region, offset, call.callee_address.to_scalar())?; + + let [key, value] = + [step.rw_indices[4], step.rw_indices[6]].map(|idx| block.rws[idx].stack_value()); + self.key.assign(region, offset, Some(key.to_le_bytes()))?; + self.value + .assign(region, offset, Some(value.to_le_bytes()))?; + + let (_, committed_value) = block.rws[step.rw_indices[5]].aux_pair(); + self.committed_value + .assign(region, offset, Some(committed_value.to_le_bytes()))?; + + let (_, is_warm) = block.rws[step.rw_indices[7]].tx_access_list_value_pair(); + self.is_warm + .assign(region, offset, Some(F::from(is_warm as u64)))?; + + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub(crate) struct SloadGasGadget { + is_warm: Expression, + gas_cost: Expression, +} + +impl SloadGasGadget { + pub(crate) fn construct(_cb: &mut ConstraintBuilder, is_warm: Expression) -> Self { + let gas_cost = select::expr( + is_warm.expr(), + GasCost::WARM_STORAGE_READ_COST.expr(), + GasCost::COLD_SLOAD_COST.expr(), + ); + + Self { is_warm, gas_cost } + } + + pub(crate) fn expr(&self) -> Expression { + // Return the gas cost + self.gas_cost.clone() + } +} + +#[cfg(test)] +mod test { + use crate::evm_circuit::{ + param::STACK_CAPACITY, + step::ExecutionState, + table::{CallContextFieldTag, RwTableTag}, + test::{rand_fp, rand_word, run_test_circuit_incomplete_fixed_table}, + witness::{Block, Bytecode, Call, CodeSource, ExecStep, Rw, RwMap, Transaction}, + }; + use crate::test_util::run_test_circuits; + + use bus_mapping::evm::OpcodeId; + use eth_types::{address, bytecode, evm_types::GasCost, ToWord, Word}; + use std::convert::TryInto; + + fn test_ok( + tx: eth_types::Transaction, + key: Word, + value: Word, + is_warm: bool, + is_persistent: bool, + ) { + let rw_counter_end_of_reversion = if is_persistent { 0 } else { 19 }; + + let call_data_gas_cost = tx + .input + .0 + .iter() + .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }); + + let randomness = rand_fp(); + let bytecode = Bytecode::from(&bytecode! { + PUSH32(key) + #[start] + SLOAD + STOP + }); + let block = Block { + randomness, + txs: vec![Transaction { + id: 1, + nonce: tx.nonce.try_into().unwrap(), + gas: tx.gas.try_into().unwrap(), + gas_price: tx.gas_price.unwrap_or_else(Word::zero), + caller_address: tx.from, + callee_address: tx.to.unwrap(), + is_create: tx.to.is_none(), + value: tx.value, + call_data: tx.input.to_vec(), + call_data_length: tx.input.0.len(), + call_data_gas_cost, + calls: vec![Call { + id: 1, + is_root: true, + is_create: false, + code_source: CodeSource::Account(bytecode.hash), + rw_counter_end_of_reversion, + is_persistent, + is_success: is_persistent, + callee_address: tx.to.unwrap(), + ..Default::default() + }], + steps: vec![ + ExecStep { + rw_indices: [ + vec![ + (RwTableTag::CallContext, 0), + (RwTableTag::CallContext, 1), + (RwTableTag::CallContext, 2), + (RwTableTag::CallContext, 3), + (RwTableTag::Stack, 0), + (RwTableTag::AccountStorage, 0), + (RwTableTag::Stack, 1), + (RwTableTag::TxAccessListAccountStorage, 0), + ], + if is_persistent { + vec![] + } else { + vec![(RwTableTag::TxAccessListAccountStorage, 1)] + }, + ] + .concat(), + execution_state: ExecutionState::SLOAD, + rw_counter: 9, + program_counter: 33, + stack_pointer: STACK_CAPACITY, + gas_left: if is_warm { + GasCost::WARM_STORAGE_READ_COST.as_u64() + } else { + GasCost::COLD_SLOAD_COST.as_u64() + }, + gas_cost: if is_warm { + GasCost::WARM_STORAGE_READ_COST.as_u64() + } else { + GasCost::COLD_SLOAD_COST.as_u64() + }, + opcode: Some(OpcodeId::SLOAD), + ..Default::default() + }, + ExecStep { + execution_state: ExecutionState::STOP, + rw_counter: 17, + program_counter: 34, + stack_pointer: STACK_CAPACITY, + gas_left: 0, + opcode: Some(OpcodeId::STOP), + state_write_counter: 1, + ..Default::default() + }, + ], + }], + rws: RwMap( + [ + ( + RwTableTag::Stack, + vec![ + Rw::Stack { + rw_counter: 13, + is_write: false, + call_id: 1, + stack_pointer: STACK_CAPACITY, + value: key, + }, + Rw::Stack { + rw_counter: 15, + is_write: true, + call_id: 1, + stack_pointer: STACK_CAPACITY, + value, + }, + ], + ), + ( + RwTableTag::AccountStorage, + vec![Rw::AccountStorage { + rw_counter: 14, + is_write: false, + account_address: tx.to.unwrap(), + storage_key: key, + value, + value_prev: value, + tx_id: 1, + committed_value: Word::zero(), + }], + ), + ( + RwTableTag::TxAccessListAccountStorage, + [ + vec![Rw::TxAccessListAccountStorage { + rw_counter: 16, + is_write: true, + tx_id: 1, + account_address: tx.to.unwrap(), + storage_key: key, + value: true, + value_prev: is_warm, + }], + if is_persistent { + vec![] + } else { + vec![Rw::TxAccessListAccountStorage { + rw_counter: rw_counter_end_of_reversion, + is_write: true, + tx_id: 1usize, + account_address: tx.to.unwrap(), + storage_key: key, + value: is_warm, + value_prev: true, + }] + }, + ] + .concat(), + ), + ( + RwTableTag::CallContext, + vec![ + Rw::CallContext { + rw_counter: 9, + is_write: false, + call_id: 1, + field_tag: CallContextFieldTag::TxId, + value: Word::one(), + }, + Rw::CallContext { + rw_counter: 10, + is_write: false, + call_id: 1, + field_tag: CallContextFieldTag::RwCounterEndOfReversion, + value: Word::from(rw_counter_end_of_reversion), + }, + Rw::CallContext { + rw_counter: 11, + is_write: false, + call_id: 1, + field_tag: CallContextFieldTag::IsPersistent, + value: Word::from(is_persistent as u64), + }, + Rw::CallContext { + rw_counter: 12, + is_write: false, + call_id: 1, + field_tag: CallContextFieldTag::CalleeAddress, + value: tx.to.unwrap().to_word(), + }, + ], + ), + ] + .into(), + ), + bytecodes: vec![bytecode], + ..Default::default() + }; + + assert_eq!(run_test_circuit_incomplete_fixed_table(block), Ok(())); + } + + fn mock_tx() -> eth_types::Transaction { + let from = address!("0x00000000000000000000000000000000000000fe"); + let to = address!("0x00000000000000000000000000000000000000ff"); + eth_types::Transaction { + from, + to: Some(to), + ..Default::default() + } + } + + #[test] + fn sload_gadget_simple() { + test_ok(mock_tx(), 0x030201.into(), 0x060504.into(), true, true); + test_ok(mock_tx(), 0x030201.into(), 0x060504.into(), true, false); + test_ok(mock_tx(), 0x030201.into(), 0x060504.into(), false, true); + test_ok(mock_tx(), 0x030201.into(), 0x060504.into(), false, false); + } + + #[test] + fn sload_gadget_rand() { + let key = rand_word(); + let value = rand_word(); + test_ok(mock_tx(), key, value, true, true); + test_ok(mock_tx(), key, value, true, false); + test_ok(mock_tx(), key, value, false, true); + test_ok(mock_tx(), key, value, false, false); + } + + fn test_with_busmapping(key: Word) { + let bytecode = bytecode! { + PUSH32(key) + #[start] + SLOAD + STOP + }; + assert_eq!(run_test_circuits(bytecode), Ok(())); + } + + #[test] + fn sload_gadget_simple_with_busmapping() { + test_with_busmapping(0x030201.into()); + } +} diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index cb639d3ffb..74acbea7d9 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -676,6 +676,34 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { value - value_prev } + #[allow(clippy::too_many_arguments)] + pub(crate) fn account_storage_access_list_write_with_reversion( + &mut self, + tx_id: Expression, + account_address: Expression, + key: Expression, + value: Expression, + value_prev: Expression, + is_persistent: Expression, + rw_counter_end_of_reversion: Expression, + ) { + self.state_write_with_reversion( + "account_storage_access_list_write_with_reversion", + RwTableTag::TxAccessListAccountStorage, + [ + tx_id, + account_address, + key, + value, + value_prev, + 0.expr(), + 0.expr(), + ], + is_persistent, + rw_counter_end_of_reversion, + ); + } + // Account pub(crate) fn account_read( @@ -749,6 +777,32 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { ); } + // Account Storage + + pub(crate) fn account_storage_read( + &mut self, + account_address: Expression, + key: Expression, + value: Expression, + tx_id: Expression, + committed_value: Expression, + ) { + self.rw_lookup( + "account_storage_read", + false.expr(), + RwTableTag::AccountStorage, + [ + account_address, + key, + 0.expr(), + value.clone(), + value, + tx_id, + committed_value, + ], + ); + } + // Call context pub(crate) fn call_context( diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 84198fed79..194158317d 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -483,6 +483,8 @@ pub enum Rw { storage_key: Word, value: Word, value_prev: Word, + tx_id: usize, + committed_value: Word, }, AccountDestructed { rw_counter: usize, @@ -567,6 +569,17 @@ impl Rw { } } + pub fn aux_pair(&self) -> (usize, Word) { + match self { + Self::AccountStorage { + tx_id, + committed_value, + .. + } => (*tx_id, *committed_value), + _ => unreachable!(), + } + } + pub fn call_context_value(&self) -> Word { match self { Self::CallContext { value, .. } => *value, @@ -621,7 +634,7 @@ impl Rw { } => [ F::from(*rw_counter as u64), F::from(*is_write as u64), - F::from(RwTableTag::TxAccessListAccount as u64), + F::from(RwTableTag::TxAccessListAccountStorage as u64), F::from(*tx_id as u64), account_address.to_scalar().unwrap(), RandomLinearCombination::random_linear_combine( @@ -736,6 +749,8 @@ impl Rw { storage_key, value, value_prev, + tx_id, + committed_value, } => [ F::from(*rw_counter as u64), F::from(*is_write as u64), @@ -751,8 +766,11 @@ impl Rw { value_prev.to_le_bytes(), randomness, ), - F::zero(), // TODO: txid - F::zero(), // TODO: committed_value + F::from(*tx_id as u64), + RandomLinearCombination::random_linear_combine( + committed_value.to_le_bytes(), + randomness, + ), ] .into(), _ => unimplemented!(), @@ -854,6 +872,8 @@ impl From<&operation::OperationContainer> for RwMap { storage_key: op.op().key, value: op.op().value, value_prev: op.op().value_prev, + tx_id: op.op().tx_id, + committed_value: op.op().committed_value, }) .collect(), ); @@ -1032,6 +1052,7 @@ impl From<&bus_mapping::circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::TIMESTAMP => ExecutionState::TIMESTAMP, OpcodeId::GAS => ExecutionState::GAS, OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE, + OpcodeId::SLOAD => ExecutionState::SLOAD, _ => unimplemented!("unimplemented opcode {:?}", step.op), } } diff --git a/zkevm-circuits/src/state_circuit/state.rs b/zkevm-circuits/src/state_circuit/state.rs index 4f9b6172b6..fb2dbaa87f 100644 --- a/zkevm-circuits/src/state_circuit/state.rs +++ b/zkevm-circuits/src/state_circuit/state.rs @@ -199,7 +199,7 @@ impl< let q_target = meta.query_fixed(q_target, Rotation::cur()); generate_lagrange_base_polynomial(q_target, STACK_TAG, EMPTY_TAG..=STORAGE_TAG) }; - let q_storage_first = |meta: &mut VirtualCells| { + let _q_storage_first = |meta: &mut VirtualCells| { let q_target_cur = meta.query_fixed(q_target, Rotation::cur()); let q_target_next = meta.query_fixed(q_target, Rotation::next()); generate_lagrange_base_polynomial(q_target_cur, START_TAG, EMPTY_TAG..=STORAGE_TAG) @@ -416,6 +416,8 @@ impl< storage_key_diff_inv, ); + // TODO: consider enabling this after implement `sstore` bus_mapping + /* meta.create_gate("First storage row operation", |meta| { let q_storage_first = q_storage_first(meta); @@ -427,6 +429,7 @@ impl< * write (flag = 1) */ ] }); + */ meta.create_gate("Storage operation", |meta| { let q_storage_not_first = q_storage_not_first(meta); @@ -1199,6 +1202,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_1 = Operation::new( @@ -1209,6 +1214,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(32), + 1usize, + Word::from(32), ), ); let storage_op_2 = Operation::new( @@ -1219,6 +1226,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(32), + 1usize, + Word::from(32), ), ); @@ -1357,6 +1366,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_1 = Operation::new( @@ -1369,6 +1380,8 @@ mod tests { Word::from(0x41), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); @@ -1384,6 +1397,8 @@ mod tests { have two conditions met. */ Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); @@ -1578,6 +1593,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_1 = Operation::new( @@ -1588,6 +1605,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_2 = Operation::new( @@ -1601,6 +1620,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_3 = Operation::new( @@ -1613,6 +1634,8 @@ mod tests { Word::from(0x41), Word::from(32), Word::from(32), + 1usize, + Word::from(32), ), ); @@ -1627,6 +1650,8 @@ mod tests { Word::from(0x41), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); @@ -1719,6 +1744,8 @@ mod tests { Word::from(0x40), Word::from(32), Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_1 = Operation::new( @@ -1732,6 +1759,8 @@ mod tests { * value as in the previous * row. */ Word::from(0), + 1usize, + Word::from(0), ), ); let storage_op_2 = Operation::new( @@ -1744,6 +1773,8 @@ mod tests { Word::from(0), /* Fails because not the same * as value in the previous row - note: this * is WRITE. */ + 1usize, + Word::from(0), ), ); let storage_op_3 = Operation::new( @@ -1756,6 +1787,8 @@ mod tests { Word::from(1), /* Fails because not the same * as value_prev in the previous row - note: * this is READ. */ + 1usize, + Word::from(1), ), );