Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
Merged
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
7 changes: 3 additions & 4 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod sload;
mod stackonlyop;
mod stop;
mod swap;

mod timestamp;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::evm::OpcodeId;
use crate::Error;
Expand All @@ -24,7 +24,6 @@ use eth_types::GethExecStep;
use log::warn;

use self::push::Push;
use coinbase::Coinbase;
use dup::Dup;
use gas::Gas;
use jump::Jump;
Expand Down Expand Up @@ -111,8 +110,8 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
// OpcodeId::RETURNDATACOPY => {},
// OpcodeId::EXTCODEHASH => {},
// OpcodeId::BLOCKHASH => {},
OpcodeId::COINBASE => Coinbase::gen_associated_ops,
// OpcodeId::TIMESTAMP => {},
OpcodeId::COINBASE => StackOnlyOpcode::<0>::gen_associated_ops,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! :)

OpcodeId::TIMESTAMP => StackOnlyOpcode::<0>::gen_associated_ops,
// OpcodeId::NUMBER => {},
// OpcodeId::DIFFICULTY => {},
// OpcodeId::GASLIMIT => {},
Expand Down
38 changes: 9 additions & 29 deletions bus-mapping/src/evm/opcodes/coinbase.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,14 @@
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::circuit_input_builder::{ExecStep, TransactionContext};
use crate::{
circuit_input_builder::{ExecStep, TransactionContext},
mock::BlockData,
operation::RW,
Error,
};
use eth_types::evm_types::StackAddress;
use eth_types::{bytecode, ToWord};
use mock::new_single_tx_trace_code_at_start;
use pretty_assertions::assert_eq;

#[test]
Expand All @@ -39,9 +20,8 @@ mod coinbase_tests {
};

// Get the execution steps from the external tracer
let block = crate::mock::BlockData::new_from_geth_data(
mock::new_single_tx_trace_code_at_start(&code).unwrap(),
);
let block =
BlockData::new_from_geth_data(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();
Expand Down
6 changes: 5 additions & 1 deletion bus-mapping/src/evm/opcodes/stackonlyop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ impl<const N: usize> Opcode for StackOnlyOpcode<N> {

// Get operator result from next step and do stack write
let result_value = steps[1].stack.last()?;
state.push_stack_op(RW::WRITE, step.stack.nth_last_filled(N - 1), result_value);
state.push_stack_op(
RW::WRITE,
step.stack.last_filled().map(|a| a - 1 + N),
result_value,
);

Ok(())
}
Expand Down
62 changes: 62 additions & 0 deletions bus-mapping/src/evm/opcodes/timestamp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#[cfg(test)]
mod timestamp_tests {
use crate::{
circuit_input_builder::{ExecStep, TransactionContext},
mock::BlockData,
operation::RW,
Error,
};
use eth_types::{bytecode, evm_types::StackAddress};
use mock::new_single_tx_trace_code_at_start;
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 =
BlockData::new_from_geth_data(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(())
}
}
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 @@ -38,6 +38,7 @@ mod signed_comparator;
mod signextend;
mod stop;
mod swap;
mod timestamp;

use add::AddGadget;
use begin_tx::BeginTxGadget;
Expand All @@ -61,6 +62,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 @@ -108,6 +110,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 @@ -235,6 +238,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 @@ -482,6 +486,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
97 changes: 97 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution/timestamp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use crate::evm_circuit::param::N_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 halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
use std::convert::TryFrom;

#[derive(Clone, Debug)]
pub(crate) struct TimestampGadget<F> {
same_context: SameContextGadget<F>,
timestamp: RandomLinearCombination<F, N_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 = cb.query_rlc();
cb.stack_push(timestamp.expr());

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

// 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,
timestamp,
}
}

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.timestamp.assign(
region,
offset,
Some(u64::try_from(timestamp).unwrap().to_le_bytes()),
)?;

Ok(())
}
}

#[cfg(test)]
mod test {
use crate::test_util::run_test_circuits;
use eth_types::bytecode;

fn test_ok() {
let bytecode = bytecode! {
#[start]
TIMESTAMP
STOP
};
assert_eq!(run_test_circuits(bytecode), 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 @@ -439,7 +439,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 @@ -594,6 +594,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,
OpcodeId::GAS => ExecutionState::GAS,
_ => unimplemented!("unimplemented opcode {:?}", step.op),
}
Expand Down Expand Up @@ -686,6 +687,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