diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index a7dba642d9..dfa8483de2 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -14,7 +14,7 @@ mod sload; mod stackonlyop; mod stop; mod swap; - +mod timestamp; use crate::circuit_input_builder::CircuitInputStateRef; use crate::evm::OpcodeId; use crate::Error; @@ -23,7 +23,6 @@ use eth_types::GethExecStep; use log::warn; use self::push::Push; -use coinbase::Coinbase; use dup::Dup; use jump::Jump; use jumpdest::Jumpdest; @@ -65,155 +64,157 @@ type FnGenAssociatedOps = fn( next_steps: &[GethExecStep], ) -> Result<(), Error>; -fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps { - match opcode_id { - OpcodeId::STOP => Stop::gen_associated_ops, - OpcodeId::ADD => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::MUL => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SUB => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::DIV => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SDIV => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::MOD => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SMOD => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::ADDMOD => StackOnlyOpcode::<3>::gen_associated_ops, - OpcodeId::MULMOD => StackOnlyOpcode::<3>::gen_associated_ops, - OpcodeId::EXP => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SIGNEXTEND => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::LT => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::GT => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SLT => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SGT => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::EQ => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::ISZERO => StackOnlyOpcode::<1>::gen_associated_ops, - OpcodeId::AND => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::OR => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::XOR => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::NOT => StackOnlyOpcode::<1>::gen_associated_ops, - OpcodeId::BYTE => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SHL => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SHR => StackOnlyOpcode::<2>::gen_associated_ops, - OpcodeId::SAR => StackOnlyOpcode::<2>::gen_associated_ops, - // OpcodeId::SHA3 => {}, - // OpcodeId::ADDRESS => {}, - // OpcodeId::BALANCE => {}, - // OpcodeId::ORIGIN => {}, - // OpcodeId::CALLER => {}, - // OpcodeId::CALLVALUE => {}, - // OpcodeId::CALLDATALOAD => {}, - // OpcodeId::CALLDATASIZE => {}, - // OpcodeId::CALLDATACOPY => {}, - // OpcodeId::CODESIZE => {}, - // OpcodeId::CODECOPY => {}, - // OpcodeId::GASPRICE => {}, - // OpcodeId::EXTCODESIZE => {}, - // OpcodeId::EXTCODECOPY => {}, - // OpcodeId::RETURNDATASIZE => {}, - // OpcodeId::RETURNDATACOPY => {}, - // OpcodeId::EXTCODEHASH => {}, - // OpcodeId::BLOCKHASH => {}, - OpcodeId::COINBASE => Coinbase::gen_associated_ops, - // OpcodeId::TIMESTAMP => {}, - // OpcodeId::NUMBER => {}, - // OpcodeId::DIFFICULTY => {}, - // OpcodeId::GASLIMIT => {}, - // OpcodeId::CHAINID => {}, - // OpcodeId::SELFBALANCE => {}, - // OpcodeId::BASEFEE => {}, - OpcodeId::POP => Pop::gen_associated_ops, - OpcodeId::MLOAD => Mload::gen_associated_ops, - OpcodeId::MSTORE => Mstore::::gen_associated_ops, - OpcodeId::MSTORE8 => Mstore::::gen_associated_ops, - OpcodeId::SLOAD => Sload::gen_associated_ops, - // OpcodeId::SSTORE => {}, - OpcodeId::JUMP => Jump::gen_associated_ops, - OpcodeId::JUMPI => Jumpi::gen_associated_ops, - OpcodeId::PC => Pc::gen_associated_ops, - OpcodeId::MSIZE => Msize::gen_associated_ops, - // OpcodeId::GAS => {}, - OpcodeId::JUMPDEST => Jumpdest::gen_associated_ops, - OpcodeId::PUSH1 => Push::<1>::gen_associated_ops, - OpcodeId::PUSH2 => Push::<2>::gen_associated_ops, - OpcodeId::PUSH3 => Push::<3>::gen_associated_ops, - OpcodeId::PUSH4 => Push::<4>::gen_associated_ops, - OpcodeId::PUSH5 => Push::<5>::gen_associated_ops, - OpcodeId::PUSH6 => Push::<6>::gen_associated_ops, - OpcodeId::PUSH7 => Push::<7>::gen_associated_ops, - OpcodeId::PUSH8 => Push::<8>::gen_associated_ops, - OpcodeId::PUSH9 => Push::<9>::gen_associated_ops, - OpcodeId::PUSH10 => Push::<10>::gen_associated_ops, - OpcodeId::PUSH11 => Push::<11>::gen_associated_ops, - OpcodeId::PUSH12 => Push::<12>::gen_associated_ops, - OpcodeId::PUSH13 => Push::<13>::gen_associated_ops, - OpcodeId::PUSH14 => Push::<14>::gen_associated_ops, - OpcodeId::PUSH15 => Push::<15>::gen_associated_ops, - OpcodeId::PUSH16 => Push::<16>::gen_associated_ops, - OpcodeId::PUSH17 => Push::<17>::gen_associated_ops, - OpcodeId::PUSH18 => Push::<18>::gen_associated_ops, - OpcodeId::PUSH19 => Push::<19>::gen_associated_ops, - OpcodeId::PUSH20 => Push::<20>::gen_associated_ops, - OpcodeId::PUSH21 => Push::<21>::gen_associated_ops, - OpcodeId::PUSH22 => Push::<22>::gen_associated_ops, - OpcodeId::PUSH23 => Push::<23>::gen_associated_ops, - OpcodeId::PUSH24 => Push::<24>::gen_associated_ops, - OpcodeId::PUSH25 => Push::<25>::gen_associated_ops, - OpcodeId::PUSH26 => Push::<26>::gen_associated_ops, - OpcodeId::PUSH27 => Push::<27>::gen_associated_ops, - OpcodeId::PUSH28 => Push::<28>::gen_associated_ops, - OpcodeId::PUSH29 => Push::<29>::gen_associated_ops, - OpcodeId::PUSH30 => Push::<30>::gen_associated_ops, - OpcodeId::PUSH31 => Push::<31>::gen_associated_ops, - OpcodeId::PUSH32 => Push::<32>::gen_associated_ops, - OpcodeId::DUP1 => Dup::<1>::gen_associated_ops, - OpcodeId::DUP2 => Dup::<2>::gen_associated_ops, - OpcodeId::DUP3 => Dup::<3>::gen_associated_ops, - OpcodeId::DUP4 => Dup::<4>::gen_associated_ops, - OpcodeId::DUP5 => Dup::<5>::gen_associated_ops, - OpcodeId::DUP6 => Dup::<6>::gen_associated_ops, - OpcodeId::DUP7 => Dup::<7>::gen_associated_ops, - OpcodeId::DUP8 => Dup::<8>::gen_associated_ops, - OpcodeId::DUP9 => Dup::<9>::gen_associated_ops, - OpcodeId::DUP10 => Dup::<10>::gen_associated_ops, - OpcodeId::DUP11 => Dup::<11>::gen_associated_ops, - OpcodeId::DUP12 => Dup::<12>::gen_associated_ops, - OpcodeId::DUP13 => Dup::<13>::gen_associated_ops, - OpcodeId::DUP14 => Dup::<14>::gen_associated_ops, - OpcodeId::DUP15 => Dup::<15>::gen_associated_ops, - OpcodeId::DUP16 => Dup::<16>::gen_associated_ops, - OpcodeId::SWAP1 => Swap::<1>::gen_associated_ops, - OpcodeId::SWAP2 => Swap::<2>::gen_associated_ops, - OpcodeId::SWAP3 => Swap::<3>::gen_associated_ops, - OpcodeId::SWAP4 => Swap::<4>::gen_associated_ops, - OpcodeId::SWAP5 => Swap::<5>::gen_associated_ops, - OpcodeId::SWAP6 => Swap::<6>::gen_associated_ops, - OpcodeId::SWAP7 => Swap::<7>::gen_associated_ops, - OpcodeId::SWAP8 => Swap::<8>::gen_associated_ops, - OpcodeId::SWAP9 => Swap::<9>::gen_associated_ops, - OpcodeId::SWAP10 => Swap::<10>::gen_associated_ops, - OpcodeId::SWAP11 => Swap::<11>::gen_associated_ops, - OpcodeId::SWAP12 => Swap::<12>::gen_associated_ops, - OpcodeId::SWAP13 => Swap::<13>::gen_associated_ops, - OpcodeId::SWAP14 => Swap::<14>::gen_associated_ops, - OpcodeId::SWAP15 => Swap::<15>::gen_associated_ops, - OpcodeId::SWAP16 => Swap::<16>::gen_associated_ops, - // OpcodeId::LOG0 => {}, - // OpcodeId::LOG1 => {}, - // OpcodeId::LOG2 => {}, - // OpcodeId::LOG3 => {}, - // OpcodeId::LOG4 => {}, - // OpcodeId::CREATE => {}, - // OpcodeId::CALL => {}, - // OpcodeId::CALLCODE => {}, - // OpcodeId::RETURN => {}, - // OpcodeId::DELEGATECALL => {}, - // OpcodeId::CREATE2 => {}, - // OpcodeId::STATICCALL => {}, - // OpcodeId::REVERT => {}, - // OpcodeId::SELFDESTRUCT => {}, - // _ => panic!("Opcode {:?} gen_associated_ops not implemented", - // self), - _ => { - warn!("Using dummy gen_associated_ops for opcode {:?}", opcode_id); - dummy_gen_associated_ops +impl OpcodeId { + fn fn_gen_associated_ops(&self) -> FnGenAssociatedOps { + match *self { + OpcodeId::STOP => Stop::gen_associated_ops, + OpcodeId::ADD => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::MUL => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SUB => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::DIV => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SDIV => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::MOD => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SMOD => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::ADDMOD => StackOnlyOpcode::<3>::gen_associated_ops, + OpcodeId::MULMOD => StackOnlyOpcode::<3>::gen_associated_ops, + OpcodeId::EXP => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SIGNEXTEND => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::LT => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::GT => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SLT => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SGT => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::EQ => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::ISZERO => StackOnlyOpcode::<1>::gen_associated_ops, + OpcodeId::AND => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::OR => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::XOR => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::NOT => StackOnlyOpcode::<1>::gen_associated_ops, + OpcodeId::BYTE => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SHL => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SHR => StackOnlyOpcode::<2>::gen_associated_ops, + OpcodeId::SAR => StackOnlyOpcode::<2>::gen_associated_ops, + // OpcodeId::SHA3 => {}, + // OpcodeId::ADDRESS => {}, + // OpcodeId::BALANCE => {}, + // OpcodeId::ORIGIN => {}, + // OpcodeId::CALLER => {}, + // OpcodeId::CALLVALUE => {}, + // OpcodeId::CALLDATALOAD => {}, + // OpcodeId::CALLDATASIZE => {}, + // OpcodeId::CALLDATACOPY => {}, + // OpcodeId::CODESIZE => {}, + // OpcodeId::CODECOPY => {}, + // OpcodeId::GASPRICE => {}, + // OpcodeId::EXTCODESIZE => {}, + // OpcodeId::EXTCODECOPY => {}, + // OpcodeId::RETURNDATASIZE => {}, + // OpcodeId::RETURNDATACOPY => {}, + // OpcodeId::EXTCODEHASH => {}, + // OpcodeId::BLOCKHASH => {}, + OpcodeId::COINBASE => StackOnlyOpcode::<0>::gen_associated_ops, + OpcodeId::TIMESTAMP => StackOnlyOpcode::<0>::gen_associated_ops, + // OpcodeId::NUMBER => {}, + // OpcodeId::DIFFICULTY => {}, + // OpcodeId::GASLIMIT => {}, + // OpcodeId::CHAINID => {}, + // OpcodeId::SELFBALANCE => {}, + // OpcodeId::BASEFEE => {}, + OpcodeId::POP => Pop::gen_associated_ops, + OpcodeId::MLOAD => Mload::gen_associated_ops, + OpcodeId::MSTORE => Mstore::::gen_associated_ops, + OpcodeId::MSTORE8 => Mstore::::gen_associated_ops, + OpcodeId::SLOAD => Sload::gen_associated_ops, + // OpcodeId::SSTORE => {}, + OpcodeId::JUMP => Jump::gen_associated_ops, + OpcodeId::JUMPI => Jumpi::gen_associated_ops, + OpcodeId::PC => Pc::gen_associated_ops, + OpcodeId::MSIZE => Msize::gen_associated_ops, + // OpcodeId::GAS => {}, + OpcodeId::JUMPDEST => Jumpdest::gen_associated_ops, + OpcodeId::PUSH1 => Push::<1>::gen_associated_ops, + OpcodeId::PUSH2 => Push::<2>::gen_associated_ops, + OpcodeId::PUSH3 => Push::<3>::gen_associated_ops, + OpcodeId::PUSH4 => Push::<4>::gen_associated_ops, + OpcodeId::PUSH5 => Push::<5>::gen_associated_ops, + OpcodeId::PUSH6 => Push::<6>::gen_associated_ops, + OpcodeId::PUSH7 => Push::<7>::gen_associated_ops, + OpcodeId::PUSH8 => Push::<8>::gen_associated_ops, + OpcodeId::PUSH9 => Push::<9>::gen_associated_ops, + OpcodeId::PUSH10 => Push::<10>::gen_associated_ops, + OpcodeId::PUSH11 => Push::<11>::gen_associated_ops, + OpcodeId::PUSH12 => Push::<12>::gen_associated_ops, + OpcodeId::PUSH13 => Push::<13>::gen_associated_ops, + OpcodeId::PUSH14 => Push::<14>::gen_associated_ops, + OpcodeId::PUSH15 => Push::<15>::gen_associated_ops, + OpcodeId::PUSH16 => Push::<16>::gen_associated_ops, + OpcodeId::PUSH17 => Push::<17>::gen_associated_ops, + OpcodeId::PUSH18 => Push::<18>::gen_associated_ops, + OpcodeId::PUSH19 => Push::<19>::gen_associated_ops, + OpcodeId::PUSH20 => Push::<20>::gen_associated_ops, + OpcodeId::PUSH21 => Push::<21>::gen_associated_ops, + OpcodeId::PUSH22 => Push::<22>::gen_associated_ops, + OpcodeId::PUSH23 => Push::<23>::gen_associated_ops, + OpcodeId::PUSH24 => Push::<24>::gen_associated_ops, + OpcodeId::PUSH25 => Push::<25>::gen_associated_ops, + OpcodeId::PUSH26 => Push::<26>::gen_associated_ops, + OpcodeId::PUSH27 => Push::<27>::gen_associated_ops, + OpcodeId::PUSH28 => Push::<28>::gen_associated_ops, + OpcodeId::PUSH29 => Push::<29>::gen_associated_ops, + OpcodeId::PUSH30 => Push::<30>::gen_associated_ops, + OpcodeId::PUSH31 => Push::<31>::gen_associated_ops, + OpcodeId::PUSH32 => Push::<32>::gen_associated_ops, + OpcodeId::DUP1 => Dup::<1>::gen_associated_ops, + OpcodeId::DUP2 => Dup::<2>::gen_associated_ops, + OpcodeId::DUP3 => Dup::<3>::gen_associated_ops, + OpcodeId::DUP4 => Dup::<4>::gen_associated_ops, + OpcodeId::DUP5 => Dup::<5>::gen_associated_ops, + OpcodeId::DUP6 => Dup::<6>::gen_associated_ops, + OpcodeId::DUP7 => Dup::<7>::gen_associated_ops, + OpcodeId::DUP8 => Dup::<8>::gen_associated_ops, + OpcodeId::DUP9 => Dup::<9>::gen_associated_ops, + OpcodeId::DUP10 => Dup::<10>::gen_associated_ops, + OpcodeId::DUP11 => Dup::<11>::gen_associated_ops, + OpcodeId::DUP12 => Dup::<12>::gen_associated_ops, + OpcodeId::DUP13 => Dup::<13>::gen_associated_ops, + OpcodeId::DUP14 => Dup::<14>::gen_associated_ops, + OpcodeId::DUP15 => Dup::<15>::gen_associated_ops, + OpcodeId::DUP16 => Dup::<16>::gen_associated_ops, + OpcodeId::SWAP1 => Swap::<1>::gen_associated_ops, + OpcodeId::SWAP2 => Swap::<2>::gen_associated_ops, + OpcodeId::SWAP3 => Swap::<3>::gen_associated_ops, + OpcodeId::SWAP4 => Swap::<4>::gen_associated_ops, + OpcodeId::SWAP5 => Swap::<5>::gen_associated_ops, + OpcodeId::SWAP6 => Swap::<6>::gen_associated_ops, + OpcodeId::SWAP7 => Swap::<7>::gen_associated_ops, + OpcodeId::SWAP8 => Swap::<8>::gen_associated_ops, + OpcodeId::SWAP9 => Swap::<9>::gen_associated_ops, + OpcodeId::SWAP10 => Swap::<10>::gen_associated_ops, + OpcodeId::SWAP11 => Swap::<11>::gen_associated_ops, + OpcodeId::SWAP12 => Swap::<12>::gen_associated_ops, + OpcodeId::SWAP13 => Swap::<13>::gen_associated_ops, + OpcodeId::SWAP14 => Swap::<14>::gen_associated_ops, + OpcodeId::SWAP15 => Swap::<15>::gen_associated_ops, + OpcodeId::SWAP16 => Swap::<16>::gen_associated_ops, + // OpcodeId::LOG0 => {}, + // OpcodeId::LOG1 => {}, + // OpcodeId::LOG2 => {}, + // OpcodeId::LOG3 => {}, + // OpcodeId::LOG4 => {}, + // OpcodeId::CREATE => {}, + // OpcodeId::CALL => {}, + // OpcodeId::CALLCODE => {}, + // OpcodeId::RETURN => {}, + // OpcodeId::DELEGATECALL => {}, + // OpcodeId::CREATE2 => {}, + // OpcodeId::STATICCALL => {}, + // OpcodeId::REVERT => {}, + // OpcodeId::SELFDESTRUCT => {}, + // _ => panic!("Opcode {:?} gen_associated_ops not implemented", + // self), + _ => { + warn!("Using dummy gen_associated_ops for opcode {:?}", self); + dummy_gen_associated_ops + } } } } diff --git a/bus-mapping/src/evm/opcodes/coinbase.rs b/bus-mapping/src/evm/opcodes/coinbase.rs index db5f7be1fc..6b20cc00ab 100644 --- a/bus-mapping/src/evm/opcodes/coinbase.rs +++ b/bus-mapping/src/evm/opcodes/coinbase.rs @@ -1,38 +1,11 @@ -use super::Opcode; -use crate::circuit_input_builder::CircuitInputStateRef; -use crate::{operation::RW, Error}; -use eth_types::GethExecStep; - -/// Placeholder structure used to implement [`Opcode`] trait over it -/// corresponding to the [`OpcodeId::PC`](crate::evm::OpcodeId::PC) `OpcodeId`. -#[derive(Debug, Copy, Clone)] -pub(crate) struct Coinbase; - -impl Opcode for Coinbase { - fn gen_associated_ops( - state: &mut CircuitInputStateRef, - steps: &[GethExecStep], - ) -> Result<(), Error> { - let step = &steps[0]; - // Get value result from next step and do stack write - let value = steps[1].stack.last()?; - state.push_stack_op( - RW::WRITE, - step.stack.last_filled().map(|a| a - 1), - value, - ); - - Ok(()) - } -} - #[cfg(test)] mod coinbase_tests { - use super::*; use crate::{ bytecode, circuit_input_builder::{ExecStep, TransactionContext}, mock, + operation::RW, + Error, }; use eth_types::evm_types::StackAddress; use eth_types::ToWord; diff --git a/bus-mapping/src/evm/opcodes/stackonlyop.rs b/bus-mapping/src/evm/opcodes/stackonlyop.rs index 088cf0d64e..1ce0a7eee9 100644 --- a/bus-mapping/src/evm/opcodes/stackonlyop.rs +++ b/bus-mapping/src/evm/opcodes/stackonlyop.rs @@ -31,7 +31,7 @@ impl Opcode for StackOnlyOpcode { let result_value = steps[1].stack.last()?; state.push_stack_op( RW::WRITE, - step.stack.nth_last_filled(N - 1), + step.stack.last_filled().map(|a| a - 1 + N), result_value, ); diff --git a/bus-mapping/src/evm/opcodes/timestamp.rs b/bus-mapping/src/evm/opcodes/timestamp.rs new file mode 100644 index 0000000000..6759bbd30e --- /dev/null +++ b/bus-mapping/src/evm/opcodes/timestamp.rs @@ -0,0 +1,63 @@ +#[cfg(test)] +mod timestamp_tests { + use crate::{ + bytecode, + circuit_input_builder::{ExecStep, TransactionContext}, + evm::StackAddress, + mock, + operation::RW, + Error, + }; + use pretty_assertions::assert_eq; + + #[test] + fn timestamp_opcode_impl() -> Result<(), Error> { + let code = bytecode! { + #[start] + TIMESTAMP + STOP + }; + + // Get the execution steps from the external tracer + let block = + mock::BlockData::new_single_tx_trace_code_at_start(&code).unwrap(); + + let mut builder = block.new_circuit_input_builder(); + builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap(); + + let mut test_builder = block.new_circuit_input_builder(); + let mut tx = test_builder.new_tx(&block.eth_tx).unwrap(); + let mut tx_ctx = TransactionContext::new(&block.eth_tx); + + // Generate step corresponding to TIMESTAMP + let mut step = ExecStep::new( + &block.geth_trace.struct_logs[0], + 0, + test_builder.block_ctx.rwc, + 0, + ); + let mut state_ref = + test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step); + + // Add the last Stack write + state_ref.push_stack_op( + RW::WRITE, + StackAddress::from(1024 - 1), + block.b_constant.timestamp, + ); + + tx.steps_mut().push(step); + test_builder.block.txs_mut().push(tx); + + // Compare first step bus mapping instance + assert_eq!( + builder.block.txs()[0].steps()[0].bus_mapping_instance, + test_builder.block.txs()[0].steps()[0].bus_mapping_instance, + ); + + // Compare containers + assert_eq!(builder.block.container, test_builder.block.container); + + Ok(()) + } +} diff --git a/bus-mapping/src/mock.rs b/bus-mapping/src/mock.rs index 6e7cdb09e6..b0a4a6a80d 100644 --- a/bus-mapping/src/mock.rs +++ b/bus-mapping/src/mock.rs @@ -32,7 +32,7 @@ pub fn new_block() -> eth_types::Block<()> { hash: Some(Hash::zero()), parent_hash: Hash::zero(), uncles_hash: Hash::zero(), - author: Address::zero(), + author: *COINBASE, state_root: Hash::zero(), transactions_root: Hash::zero(), receipts_root: Hash::zero(), diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 76c4e8a6a8..3226eedcb0 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -37,6 +37,7 @@ mod signed_comparator; mod signextend; mod stop; mod swap; +mod timestamp; use add::AddGadget; use begin_tx::BeginTxGadget; @@ -59,6 +60,7 @@ use signed_comparator::SignedComparatorGadget; use signextend::SignextendGadget; use stop::StopGadget; use swap::SwapGadget; +use timestamp::TimestampGadget; pub(crate) trait ExecutionGadget { const NAME: &'static str; @@ -105,6 +107,7 @@ pub(crate) struct ExecutionConfig { swap_gadget: SwapGadget, msize_gadget: MsizeGadget, coinbase_gadget: CoinbaseGadget, + timestamp_gadget: TimestampGadget, } impl ExecutionConfig { @@ -234,6 +237,7 @@ impl ExecutionConfig { swap_gadget: configure_gadget!(), msize_gadget: configure_gadget!(), coinbase_gadget: configure_gadget!(), + timestamp_gadget: configure_gadget!(), step: step_curr, presets_map, }; @@ -510,6 +514,9 @@ impl ExecutionConfig { ExecutionState::DUP => assign_exec_step!(self.dup_gadget), ExecutionState::SWAP => assign_exec_step!(self.swap_gadget), ExecutionState::COINBASE => assign_exec_step!(self.coinbase_gadget), + ExecutionState::TIMESTAMP => { + assign_exec_step!(self.timestamp_gadget) + } ExecutionState::ErrorOutOfGasPureMemory => { assign_exec_step!(self.error_oog_pure_memory_gadget) } diff --git a/zkevm-circuits/src/evm_circuit/execution/timestamp.rs b/zkevm-circuits/src/evm_circuit/execution/timestamp.rs new file mode 100644 index 0000000000..ad52a1f6a5 --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/execution/timestamp.rs @@ -0,0 +1,111 @@ +use crate::evm_circuit::param::NUM_BYTES_U64; +use crate::{ + evm_circuit::{ + execution::ExecutionGadget, + step::ExecutionState, + table::BlockContextFieldTag, + util::{ + common_gadget::SameContextGadget, + constraint_builder::{ + ConstraintBuilder, StepStateTransition, Transition::Delta, + }, + from_bytes, RandomLinearCombination, + }, + witness::{Block, Call, ExecStep, Transaction}, + }, + util::Expr, +}; +use array_init::array_init; +use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; +use std::convert::TryFrom; + +#[derive(Clone, Debug)] +pub(crate) struct TimestampGadget { + same_context: SameContextGadget, + value: RandomLinearCombination, +} + +impl ExecutionGadget for TimestampGadget { + const NAME: &'static str = "TIMESTAMP"; + + const EXECUTION_STATE: ExecutionState = ExecutionState::TIMESTAMP; + + fn configure(cb: &mut ConstraintBuilder) -> Self { + let timestamp = array_init(|_| cb.query_cell()); + + // Lookup block table with timestamp + cb.block_lookup( + BlockContextFieldTag::Time.expr(), + None, + from_bytes::expr(×tamp), + ); + + let value = + RandomLinearCombination::new(timestamp, cb.power_of_randomness()); + cb.stack_push(value.expr()); + + // State transition + let opcode = cb.query_cell(); + let step_state_transition = StepStateTransition { + rw_counter: Delta(1.expr()), + program_counter: Delta(1.expr()), + stack_pointer: Delta((-1).expr()), + ..Default::default() + }; + let same_context = SameContextGadget::construct( + cb, + opcode, + step_state_transition, + None, + ); + + Self { + same_context, + value, + } + } + + fn assign_exec_step( + &self, + region: &mut Region<'_, F>, + offset: usize, + block: &Block, + _: &Transaction, + _: &Call, + step: &ExecStep, + ) -> Result<(), Error> { + self.same_context.assign_exec_step(region, offset, step)?; + + let timestamp = block.rws[step.rw_indices[0]].stack_value(); + + self.value.assign( + region, + offset, + Some(u64::try_from(timestamp).unwrap().to_le_bytes()), + )?; + + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::evm_circuit::{ + test::run_test_circuit_incomplete_fixed_table, witness, + }; + use bus_mapping::bytecode; + + fn test_ok() { + let bytecode = bytecode! { + #[start] + TIMESTAMP + STOP + }; + let block = witness::build_block_from_trace_code_at_start(&bytecode); + assert_eq!(run_test_circuit_incomplete_fixed_table(block), Ok(())); + } + #[test] + fn timestamp_gadget_test() { + test_ok(); + } +} diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 62fbf9698b..d4dcd04ee6 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -473,7 +473,7 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { // Rw /// Add a Lookup::Rw without increasing the rw_counter_offset, which is - /// useful for state reversion or dummuy lookup. + /// useful for state reversion or dummy lookup. fn rw_lookup_with_counter( &mut self, name: &'static str, diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 774f461c20..16ec7329a9 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -592,6 +592,7 @@ impl From<&bus_mapping::circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::PC => ExecutionState::PC, OpcodeId::MSIZE => ExecutionState::MSIZE, OpcodeId::COINBASE => ExecutionState::COINBASE, + OpcodeId::TIMESTAMP => ExecutionState::TIMESTAMP, _ => unimplemented!("unimplemented opcode {:?}", step.op), } } @@ -685,6 +686,7 @@ pub fn block_convert( // converting to block context let context = BlockContext { coinbase: b.block_const.coinbase, + time: b.block_const.timestamp.try_into().unwrap(), ..Default::default() };