Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 152 additions & 151 deletions bus-mapping/src/evm/opcodes.rs

Large diffs are not rendered by default.

31 changes: 2 additions & 29 deletions bus-mapping/src/evm/opcodes/coinbase.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion bus-mapping/src/evm/opcodes/stackonlyop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl<const N: usize> Opcode for StackOnlyOpcode<N> {
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,
);

Expand Down
63 changes: 63 additions & 0 deletions bus-mapping/src/evm/opcodes/timestamp.rs
Original file line number Diff line number Diff line change
@@ -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(())
}
}
2 changes: 1 addition & 1 deletion bus-mapping/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
7 changes: 7 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod signed_comparator;
mod signextend;
mod stop;
mod swap;
mod timestamp;

use add::AddGadget;
use begin_tx::BeginTxGadget;
Expand All @@ -59,6 +60,7 @@ use signed_comparator::SignedComparatorGadget;
use signextend::SignextendGadget;
use stop::StopGadget;
use swap::SwapGadget;
use timestamp::TimestampGadget;

pub(crate) trait ExecutionGadget<F: FieldExt> {
const NAME: &'static str;
Expand Down Expand Up @@ -105,6 +107,7 @@ pub(crate) struct ExecutionConfig<F> {
swap_gadget: SwapGadget<F>,
msize_gadget: MsizeGadget<F>,
coinbase_gadget: CoinbaseGadget<F>,
timestamp_gadget: TimestampGadget<F>,
}

impl<F: FieldExt> ExecutionConfig<F> {
Expand Down Expand Up @@ -234,6 +237,7 @@ impl<F: FieldExt> ExecutionConfig<F> {
swap_gadget: configure_gadget!(),
msize_gadget: configure_gadget!(),
coinbase_gadget: configure_gadget!(),
timestamp_gadget: configure_gadget!(),
step: step_curr,
presets_map,
};
Expand Down Expand Up @@ -510,6 +514,9 @@ impl<F: FieldExt> ExecutionConfig<F> {
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)
}
Expand Down
111 changes: 111 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution/timestamp.rs
Original file line number Diff line number Diff line change
@@ -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<F> {
same_context: SameContextGadget<F>,
value: RandomLinearCombination<F, { NUM_BYTES_U64 }>,
}

impl<F: FieldExt> ExecutionGadget<F> for TimestampGadget<F> {
const NAME: &'static str = "TIMESTAMP";

const EXECUTION_STATE: ExecutionState = ExecutionState::TIMESTAMP;

fn configure(cb: &mut ConstraintBuilder<F>) -> Self {
let timestamp = array_init(|_| cb.query_cell());

// Lookup block table with timestamp
cb.block_lookup(
BlockContextFieldTag::Time.expr(),
None,
from_bytes::expr(&timestamp),
);

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<F>,
_: &Transaction<F>,
_: &Call<F>,
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();
}
}
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/util/constraint_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions zkevm-circuits/src/evm_circuit/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
Expand Down Expand Up @@ -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()
};

Expand Down