diff --git a/bus-mapping/src/evm/opcodes/sstore.rs b/bus-mapping/src/evm/opcodes/sstore.rs index 2e4c97b77e..bf093613d6 100644 --- a/bus-mapping/src/evm/opcodes/sstore.rs +++ b/bus-mapping/src/evm/opcodes/sstore.rs @@ -33,6 +33,15 @@ impl Opcode for Sstore { value: Word::from(state.tx_ctx.id()), }, ); + state.push_op( + &mut exec_step, + RW::READ, + CallContextOp { + call_id: state.call()?.call_id, + field: CallContextField::IsStatic, + value: Word::from(state.call()?.is_static as u8), + }, + ); state.push_op( &mut exec_step, RW::READ, @@ -187,7 +196,44 @@ mod sstore_tests { .unwrap(); assert_eq!( - [4, 5] + [0, 1, 2, 3, 4] + .map(|idx| &builder.block.container.call_context + [step.bus_mapping_instance[idx].as_usize()]) + .map(|operation| (operation.rw(), operation.op())), + [ + ( + RW::READ, + &CallContextOp::new(1, CallContextField::TxId, Word::from(0x01)), + ), + ( + RW::READ, + &CallContextOp::new(1, CallContextField::IsStatic, Word::from(0x00)), + ), + ( + RW::READ, + &CallContextOp::new( + 1, + CallContextField::RwCounterEndOfReversion, + Word::from(0x00) + ), + ), + ( + RW::READ, + &CallContextOp::new(1, CallContextField::IsPersistent, Word::from(0x01)), + ), + ( + RW::READ, + &CallContextOp::new( + 1, + CallContextField::CalleeAddress, + MOCK_ACCOUNTS[0].to_word(), + ), + ), + ] + ); + + assert_eq!( + [5, 6] .map(|idx| &builder.block.container.stack[step.bus_mapping_instance[idx].as_usize()]) .map(|operation| (operation.rw(), operation.op())), [ @@ -202,7 +248,7 @@ mod sstore_tests { ] ); - let storage_op = &builder.block.container.storage[step.bus_mapping_instance[6].as_usize()]; + let storage_op = &builder.block.container.storage[step.bus_mapping_instance[7].as_usize()]; assert_eq!( (storage_op.rw(), storage_op.op()), ( @@ -217,7 +263,7 @@ mod sstore_tests { ) ) ); - let refund_op = &builder.block.container.tx_refund[step.bus_mapping_instance[8].as_usize()]; + let refund_op = &builder.block.container.tx_refund[step.bus_mapping_instance[9].as_usize()]; assert_eq!( (refund_op.rw(), refund_op.op()), ( diff --git a/bus-mapping/src/operation.rs b/bus-mapping/src/operation.rs index 0b7058a610..8e24f7ef2c 100644 --- a/bus-mapping/src/operation.rs +++ b/bus-mapping/src/operation.rs @@ -220,7 +220,7 @@ impl fmt::Debug for StackOp { } impl StackOp { - /// Create a new instance of a `MemoryOp` from it's components. + /// Create a new instance of a `StackOp` from it's components. pub const fn new(call_id: usize, address: StackAddress, value: Word) -> StackOp { StackOp { call_id, @@ -734,6 +734,32 @@ impl Op for CallContextOp { } } +impl CallContextOp { + /// Create a new instance of a `CallContextOp` from it's components. + pub const fn new(call_id: usize, field: CallContextField, value: Word) -> CallContextOp { + CallContextOp { + call_id, + field, + value, + } + } + + /// Returns the [`Target`] (operation type) of this operation. + pub const fn target(&self) -> Target { + Target::CallContext + } + + /// Returns the call id associated to this Operation. + pub const fn call_id(&self) -> usize { + self.call_id + } + + /// Returns the [`Word`] read or written by this operation. + pub const fn value(&self) -> &Word { + &self.value + } +} + /// Generic enum that wraps over all the operation types possible. /// In particular [`StackOp`], [`MemoryOp`] and [`StorageOp`]. #[derive(Debug, Clone)] diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index 3a8b760381..f91fa767d5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -26,6 +26,7 @@ use halo2_proofs::{ pub(crate) struct SstoreGadget { same_context: SameContextGadget, tx_id: Cell, + is_static: Cell, reversion_info: ReversionInfo, callee_address: Cell, key: Cell, @@ -47,6 +48,11 @@ impl ExecutionGadget for SstoreGadget { let opcode = cb.query_cell(); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); + + // constrain not in static call + let is_static = cb.call_context(None, CallContextFieldTag::IsStatic); + cb.require_zero("is_static is false", is_static.expr()); + let mut reversion_info = cb.reversion_info(None); let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); @@ -104,7 +110,7 @@ impl ExecutionGadget for SstoreGadget { ); let step_state_transition = StepStateTransition { - rw_counter: Delta(9.expr()), + rw_counter: Delta(10.expr()), program_counter: Delta(1.expr()), stack_pointer: Delta(2.expr()), reversible_write_counter: Delta(3.expr()), @@ -116,6 +122,7 @@ impl ExecutionGadget for SstoreGadget { Self { same_context, tx_id, + is_static, reversion_info, callee_address, key, @@ -142,6 +149,8 @@ impl ExecutionGadget for SstoreGadget { self.tx_id .assign(region, offset, Some(F::from(tx.id as u64)))?; + self.is_static + .assign(region, offset, Some(F::from(call.is_static as u64)))?; self.reversion_info.assign( region, offset, @@ -152,7 +161,7 @@ impl ExecutionGadget for SstoreGadget { .assign(region, offset, call.callee_address.to_scalar())?; let [key, value] = - [step.rw_indices[4], step.rw_indices[5]].map(|idx| block.rws[idx].stack_value()); + [step.rw_indices[5], step.rw_indices[6]].map(|idx| block.rws[idx].stack_value()); self.key.assign( region, offset, @@ -170,7 +179,7 @@ impl ExecutionGadget for SstoreGadget { )), )?; - let (_, value_prev, _, original_value) = block.rws[step.rw_indices[6]].storage_value_aux(); + let (_, value_prev, _, original_value) = block.rws[step.rw_indices[7]].storage_value_aux(); self.value_prev.assign( region, offset, @@ -188,11 +197,11 @@ impl ExecutionGadget for SstoreGadget { )), )?; - let (_, is_warm) = block.rws[step.rw_indices[7]].tx_access_list_value_pair(); + let (_, is_warm) = block.rws[step.rw_indices[8]].tx_access_list_value_pair(); self.is_warm .assign(region, offset, Some(F::from(is_warm as u64)))?; - let (tx_refund, tx_refund_prev) = block.rws[step.rw_indices[8]].tx_refund_value_pair(); + let (tx_refund, tx_refund_prev) = block.rws[step.rw_indices[9]].tx_refund_value_pair(); self.tx_refund_prev .assign(region, offset, Some(F::from(tx_refund_prev)))?;