Skip to content

Commit

Permalink
Prepare bytecode refactor (#1397)
Browse files Browse the repository at this point in the history
* add BytecodeLengthGadget BytecodeLookupGadget

* remove program_counter_offset

* update create/invalid_jump/precompile_fail

* update return_revert/stop/extcodecopy

* remove lookup

* add debug helper

* return code length in  BytecodeLengthGadget::assign

* fix clippy

* remove extra code_hash

* add algorithm

* more test

* fix clippy from upstream

* edge test for algorithm
  • Loading branch information
DreamWuGit authored Aug 17, 2024
1 parent 1d31ee8 commit 29b152a
Show file tree
Hide file tree
Showing 14 changed files with 347 additions and 146 deletions.
2 changes: 1 addition & 1 deletion aggregator/src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl ChunkInfo {
b.transactions
.iter()
.enumerate()
.filter(|(idx, tx)| !tx.is_l1_tx())
.filter(|(_idx, tx)| !tx.is_l1_tx())
.flat_map(|(idx, tx)| {
tx.to_eth_tx(
b.header.hash,
Expand Down
18 changes: 18 additions & 0 deletions bus-mapping/src/circuit_input_builder/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,24 @@ pub enum NumberOrHash {
Hash(H256),
}

impl NumberOrHash {
/// get hash value for NumberOrHash::Hash type
pub fn get_hash(&self) -> H256 {
match self {
Self::Hash(val) => *val,
_ => panic!("not a hash type"),
}
}

/// get number value for NumberOrHash::Number type
pub fn get_number(&self) -> usize {
match self {
Self::Number(val) => *val,
_ => panic!("not a number type"),
}
}
}

/// Represents all bytes related in one copy event.
///
/// - When the source is memory, `bytes` is the memory content, including masked areas. The
Expand Down
34 changes: 21 additions & 13 deletions zkevm-circuits/src/evm_circuit/execution/callop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use crate::{
step::ExecutionState,
util::{
and,
common_gadget::{CommonCallGadget, TransferGadget, TransferGadgetInfo},
common_gadget::{
BytecodeLookupGadget, CommonCallGadget, TransferGadget, TransferGadgetInfo,
},
constraint_builder::{
ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition,
Transition::{Delta, To},
Expand Down Expand Up @@ -42,7 +44,7 @@ use std::cmp::min;
#[derive(Clone, Debug)]

pub(crate) struct CallOpGadget<F> {
opcode: Cell<F>,
opcode_gadget: BytecodeLookupGadget<F>,
is_call: IsZeroGadget<F>,
is_callcode: IsZeroGadget<F>,
is_delegatecall: IsZeroGadget<F>,
Expand Down Expand Up @@ -91,14 +93,20 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
const EXECUTION_STATE: ExecutionState = ExecutionState::CALL_OP;

fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
let opcode = cb.query_cell();
cb.opcode_lookup(opcode.expr(), 1.expr());
let is_call = IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::CALL.expr());
let is_callcode = IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::CALLCODE.expr());
let is_delegatecall =
IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::DELEGATECALL.expr());
let is_staticcall =
IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::STATICCALL.expr());
let opcode_gadget = BytecodeLookupGadget::construct(cb);

let is_call =
IsZeroGadget::construct(cb, opcode_gadget.opcode.expr() - OpcodeId::CALL.expr());
let is_callcode =
IsZeroGadget::construct(cb, opcode_gadget.opcode.expr() - OpcodeId::CALLCODE.expr());
let is_delegatecall = IsZeroGadget::construct(
cb,
opcode_gadget.opcode.expr() - OpcodeId::DELEGATECALL.expr(),
);
let is_staticcall = IsZeroGadget::construct(
cb,
opcode_gadget.opcode.expr() - OpcodeId::STATICCALL.expr(),
);

// Use rw_counter of the step which triggers next call as its call_id.
let callee_call_id = cb.curr.state.rw_counter.clone();
Expand Down Expand Up @@ -708,7 +716,7 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
);

Self {
opcode,
opcode_gadget,
is_call,
is_callcode,
is_delegatecall,
Expand Down Expand Up @@ -841,8 +849,8 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
}
}

self.opcode
.assign(region, offset, Value::known(F::from(opcode.as_u64())))?;
self.opcode_gadget
.assign(region, offset, block, call, step)?;
self.is_call.assign(
region,
offset,
Expand Down
24 changes: 15 additions & 9 deletions zkevm-circuits/src/evm_circuit/execution/codecopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
param::{N_BYTES_MEMORY_WORD_SIZE, N_BYTES_U64},
step::ExecutionState,
util::{
common_gadget::{SameContextGadget, WordByteCapGadget},
common_gadget::{BytecodeLengthGadget, SameContextGadget, WordByteCapGadget},
constraint_builder::{
ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition,
},
Expand Down Expand Up @@ -46,6 +46,8 @@ pub(crate) struct CodeCopyGadget<F> {
/// RW inverse counter from the copy table at the start of related copy
/// steps.
copy_rwc_inc: Cell<F>,
/// Wraps the bytecode length and lookup.
code_len_gadget: BytecodeLengthGadget<F>,
}

impl<F: Field> ExecutionGadget<F> for CodeCopyGadget<F> {
Expand Down Expand Up @@ -73,9 +75,6 @@ impl<F: Field> ExecutionGadget<F> for CodeCopyGadget<F> {
// Fetch the hash of bytecode running in current environment.
let code_hash = cb.curr.state.code_hash.clone();

// Fetch the bytecode length from the bytecode table.
cb.bytecode_length(code_hash.expr(), code_size.expr());

// Calculate the next memory size and the gas cost for this memory
// access. This also accounts for the dynamic gas required to copy bytes to
// memory.
Expand Down Expand Up @@ -128,6 +127,14 @@ impl<F: Field> ExecutionGadget<F> for CodeCopyGadget<F> {
};
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition);

// Fetch the bytecode length from the bytecode table.
let code_len_gadget = BytecodeLengthGadget::construct(cb, cb.curr.state.code_hash.clone());
cb.require_equal(
"code_size == code_len_gadget::code_length",
code_size.expr(),
code_len_gadget.code_length.expr(),
);

Self {
same_context,
code_offset,
Expand All @@ -136,6 +143,7 @@ impl<F: Field> ExecutionGadget<F> for CodeCopyGadget<F> {
memory_expansion,
memory_copier_gas,
copy_rwc_inc,
code_len_gadget,
}
}

Expand All @@ -160,12 +168,10 @@ impl<F: Field> ExecutionGadget<F> for CodeCopyGadget<F> {
let [dest_offset, code_offset, size] =
[0, 1, 2].map(|i| block.rws[step.rw_indices[i]].stack_value());

let bytecode = block
.bytecodes
.get(&call.code_hash)
.expect("could not find current environment's bytecode");
let code_size = self
.code_len_gadget
.assign(region, offset, block, &call.code_hash)?;

let code_size = bytecode.bytes.len() as u64;
self.code_size
.assign(region, offset, Value::known(F::from(code_size)))?;

Expand Down
25 changes: 12 additions & 13 deletions zkevm-circuits/src/evm_circuit/execution/codesize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
evm_circuit::{
step::ExecutionState,
util::{
common_gadget::SameContextGadget,
common_gadget::{BytecodeLengthGadget, SameContextGadget},
constraint_builder::{
ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition,
},
Expand All @@ -24,7 +24,7 @@ use super::ExecutionGadget;
pub(crate) struct CodesizeGadget<F> {
same_context: SameContextGadget<F>,
codesize_bytes: [Cell<F>; 8],
codesize: Cell<F>,
code_len_gadget: BytecodeLengthGadget<F>,
}

impl<F: Field> ExecutionGadget<F> for CodesizeGadget<F> {
Expand All @@ -38,14 +38,6 @@ impl<F: Field> ExecutionGadget<F> for CodesizeGadget<F> {
let codesize_bytes = array_init(|_| cb.query_byte());

let code_hash = cb.curr.state.code_hash.clone();
let codesize = cb.query_cell();
cb.bytecode_length(code_hash.expr(), codesize.expr());

cb.require_equal(
"Constraint: bytecode length lookup == codesize",
from_bytes::expr(&codesize_bytes),
codesize.expr(),
);

cb.stack_push(cb.word_rlc(codesize_bytes.clone().map(|c| c.expr())));

Expand All @@ -57,11 +49,18 @@ impl<F: Field> ExecutionGadget<F> for CodesizeGadget<F> {
..Default::default()
};
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition);
let code_len_gadget = BytecodeLengthGadget::construct(cb, code_hash);

cb.require_equal(
"Constraint: bytecode length lookup == codesize",
from_bytes::expr(&codesize_bytes),
code_len_gadget.code_length.expr(),
);

Self {
same_context,
codesize_bytes,
codesize,
code_len_gadget,
}
}

Expand All @@ -87,8 +86,8 @@ impl<F: Field> ExecutionGadget<F> for CodesizeGadget<F> {
c.assign(region, offset, Value::known(F::from(*b as u64)))?;
}

self.codesize
.assign(region, offset, Value::known(F::from(codesize)))?;
self.code_len_gadget
.assign(region, offset, block, &call.code_hash)?;

Ok(())
}
Expand Down
15 changes: 7 additions & 8 deletions zkevm-circuits/src/evm_circuit/execution/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
},
step::ExecutionState,
util::{
common_gadget::{get_copy_bytes, TransferGadget},
common_gadget::{get_copy_bytes, BytecodeLookupGadget, TransferGadget},
constraint_builder::{
ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition,
Transition::{Delta, To},
Expand Down Expand Up @@ -41,7 +41,7 @@ use std::iter::once;
/// Gadget for CREATE and CREATE2 opcodes
#[derive(Clone, Debug)]
pub(crate) struct CreateGadget<F, const IS_CREATE2: bool, const S: ExecutionState> {
opcode: Cell<F>,
opcode_gadget: BytecodeLookupGadget<F>,
tx_id: Cell<F>,
reversion_info: ReversionInfo<F>,
depth: Cell<F>,
Expand Down Expand Up @@ -89,13 +89,12 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
const EXECUTION_STATE: ExecutionState = S;

fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
let opcode = cb.query_cell();
let copy_rw_increase = cb.query_cell();
let opcode_gadget = BytecodeLookupGadget::construct(cb);

cb.opcode_lookup(opcode.expr(), 1.expr());
cb.require_equal(
"Opcode is CREATE or CREATE2",
opcode.expr(),
opcode_gadget.opcode.expr(),
if IS_CREATE2 {
OpcodeId::CREATE2
} else {
Expand Down Expand Up @@ -535,7 +534,7 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
);

Self {
opcode,
opcode_gadget,
tx_id,
reversion_info,
depth,
Expand Down Expand Up @@ -578,9 +577,9 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
) -> Result<(), Error> {
let opcode = step.opcode.unwrap();
let is_create2 = opcode == OpcodeId::CREATE2;
self.opcode
.assign(region, offset, Value::known(F::from(opcode.as_u64())))?;

self.opcode_gadget
.assign(region, offset, block, call, step)?;
self.tx_id
.assign(region, offset, Value::known(tx.id.to_scalar().unwrap()))?;
self.depth.assign(
Expand Down
20 changes: 9 additions & 11 deletions zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
param::N_BYTES_PROGRAM_COUNTER,
step::ExecutionState,
util::{
common_gadget::{CommonErrorGadget, WordByteCapGadget},
common_gadget::{BytecodeLengthGadget, CommonErrorGadget, WordByteCapGadget},
constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder},
math_gadget::{IsEqualGadget, IsZeroGadget},
CachedRegion, Cell,
Expand All @@ -21,7 +21,6 @@ use halo2_proofs::{circuit::Value, plonk::Error};
pub(crate) struct ErrorInvalidJumpGadget<F> {
opcode: Cell<F>,
dest: WordByteCapGadget<F, N_BYTES_PROGRAM_COUNTER>,
code_len: Cell<F>,
value: Cell<F>,
is_code: Cell<F>,
push_rlc: Cell<F>,
Expand All @@ -30,6 +29,7 @@ pub(crate) struct ErrorInvalidJumpGadget<F> {
phase2_condition: Cell<F>,
is_condition_zero: IsZeroGadget<F>,
common_error_gadget: CommonErrorGadget<F>,
code_len_gadget: BytecodeLengthGadget<F>,
}

impl<F: Field> ExecutionGadget<F> for ErrorInvalidJumpGadget<F> {
Expand All @@ -38,8 +38,9 @@ impl<F: Field> ExecutionGadget<F> for ErrorInvalidJumpGadget<F> {
const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorInvalidJump;

fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
let code_len = cb.query_cell();
let dest = WordByteCapGadget::construct(cb, code_len.expr());
// Look up bytecode length
let code_len_gadget = BytecodeLengthGadget::construct(cb, cb.curr.state.code_hash.clone());
let dest = WordByteCapGadget::construct(cb, code_len_gadget.code_length.expr());

let opcode = cb.query_cell();
let value = cb.query_cell();
Expand Down Expand Up @@ -71,9 +72,6 @@ impl<F: Field> ExecutionGadget<F> for ErrorInvalidJumpGadget<F> {
cb.require_zero("condition is not zero", is_condition_zero.expr());
});

// Look up bytecode length
cb.bytecode_length(cb.curr.state.code_hash.expr(), code_len.expr());

// If destination is in valid range, lookup for the value.
cb.condition(dest.lt_cap(), |cb| {
cb.bytecode_lookup(
Expand All @@ -95,7 +93,6 @@ impl<F: Field> ExecutionGadget<F> for ErrorInvalidJumpGadget<F> {
Self {
opcode,
dest,
code_len,
value,
is_code,
push_rlc,
Expand All @@ -104,6 +101,7 @@ impl<F: Field> ExecutionGadget<F> for ErrorInvalidJumpGadget<F> {
phase2_condition,
is_condition_zero,
common_error_gadget,
code_len_gadget,
}
}

Expand Down Expand Up @@ -132,9 +130,9 @@ impl<F: Field> ExecutionGadget<F> for ErrorInvalidJumpGadget<F> {
.bytecodes
.get(&call.code_hash)
.expect("could not find current environment's bytecode");
let code_len = code.bytes.len() as u64;
self.code_len
.assign(region, offset, Value::known(F::from(code_len)))?;
let code_len = self
.code_len_gadget
.assign(region, offset, block, &call.code_hash)?;

let dest = block.rws[step.rw_indices[0]].stack_value();
self.dest.assign(region, offset, dest, F::from(code_len))?;
Expand Down
Loading

0 comments on commit 29b152a

Please sign in to comment.