From cb0ba3195fb1733acd6363ddc6420955607034f4 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 4 May 2023 23:53:59 +0800 Subject: [PATCH 01/37] prune bytecode --- eth-types/src/bytecode.rs | 9 +- .../src/bytecode_circuit/circuit.rs | 4 +- zkevm-circuits/src/copy_circuit/test.rs | 2 +- .../src/evm_circuit/execution/codecopy.rs | 2 +- .../execution/error_invalid_jump.rs | 16 +- .../src/evm_circuit/execution/extcodecopy.rs | 3 +- .../src/evm_circuit/execution/stop.rs | 4 +- zkevm-circuits/src/witness.rs | 2 +- zkevm-circuits/src/witness/block.rs | 6 +- zkevm-circuits/src/witness/bytecode.rs | 149 ++++++++++-------- 10 files changed, 112 insertions(+), 85 deletions(-) diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index a72b30c682..7e5802b1af 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -1,6 +1,6 @@ //! EVM byte code generator - use crate::{evm_types::OpcodeId, Bytes, ToWord, Word}; +use sha3::{Digest, Keccak256}; use std::{collections::HashMap, str::FromStr}; /// Error type for Bytecode related failures @@ -26,6 +26,7 @@ pub struct Bytecode { pub code: Vec, num_opcodes: usize, markers: HashMap, + hash: Word, } impl From for Bytes { @@ -51,6 +52,7 @@ impl Bytecode { .collect(), markers: HashMap::new(), num_opcodes: 0, + hash: Word::from_big_endian(Keccak256::digest(&input).as_slice()), } } @@ -59,6 +61,11 @@ impl Bytecode { self.code.iter().map(|b| b.value).collect() } + /// Get the code hash + pub fn hash(&self) -> Word { + self.hash + } + /// Get the bytecode element at an index. pub fn get(&self, index: usize) -> Option { self.code.get(index).cloned() diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index cae9ec27c4..9be02126d9 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -809,7 +809,7 @@ impl BytecodeCircuit { let bytecodes: Vec> = block .bytecodes .values() - .map(|b| unroll(b.bytes.clone())) + .map(|b| unroll(b.code().clone())) .collect(); Self::new(bytecodes, bytecode_size) } @@ -835,7 +835,7 @@ impl SubCircuit for BytecodeCircuit { block .bytecodes .values() - .map(|bytecode| bytecode.bytes.len() + 1) + .map(|bytecode| bytecode.table_len()) .sum(), block.circuits_params.max_bytecode, ) diff --git a/zkevm-circuits/src/copy_circuit/test.rs b/zkevm-circuits/src/copy_circuit/test.rs index 825febe790..ff0de79fe3 100644 --- a/zkevm-circuits/src/copy_circuit/test.rs +++ b/zkevm-circuits/src/copy_circuit/test.rs @@ -54,7 +54,7 @@ pub fn test_copy_circuit_from_block( txs: block.txs, max_rws: block.circuits_params.max_rws, rws: block.rws, - bytecodes: block.bytecodes, + bytecodes: block.bytecodes.clone(), }, ) } diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index c95902b885..72d9ed284a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -162,7 +162,7 @@ impl ExecutionGadget for CodeCopyGadget { .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); - let code_size = bytecode.bytes.len() as u64; + let code_size = bytecode.code_size() as u64; self.code_size .assign(region, offset, Value::known(F::from(code_size)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 8edb48b549..5cd0f7db00 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -130,7 +130,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { .bytecodes .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); - let code_len = code.bytes.len() as u64; + let code_len = code.code_size() as u64; self.code_len .assign(region, offset, Value::known(F::from(code_len)))?; @@ -138,21 +138,17 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { self.dest.assign(region, offset, dest, F::from(code_len))?; // set default value in case can not find value, is_code from bytecode table - let dest = u64::try_from(dest).unwrap_or(code_len); - let mut code_pair = [0u8, 0u8]; - if dest < code_len { - // get real value from bytecode table - code_pair = code.get(dest as usize); - } + let dest = usize::try_from(dest).unwrap_or(code.code_size()); + let code_pair = code.get(dest).unwrap_or((0, false)); self.value - .assign(region, offset, Value::known(F::from(code_pair[0] as u64)))?; + .assign(region, offset, Value::known(F::from(code_pair.0 as u64)))?; self.is_code - .assign(region, offset, Value::known(F::from(code_pair[1] as u64)))?; + .assign(region, offset, Value::known(F::from(code_pair.1.into())))?; self.is_jump_dest.assign( region, offset, - F::from(code_pair[0] as u64), + F::from(code_pair.0 as u64), F::from(OpcodeId::JUMPDEST.as_u64()), )?; diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 25543d8419..fcea4b1d91 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -211,8 +211,7 @@ impl ExecutionGadget for ExtcodecopyGadget { .bytecodes .get(&code_hash) .expect("could not find external bytecode") - .bytes - .len() as u64 + .code_size() as u64 }; self.code_size .assign(region, offset, Value::known(F::from(code_size)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 464b936f74..2258fa5ad6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -113,13 +113,13 @@ impl ExecutionGadget for StopGadget { self.code_length.assign( region, offset, - Value::known(F::from(code.bytes.len() as u64)), + Value::known(F::from(code.code_size() as u64)), )?; self.is_out_of_range.assign( region, offset, - F::from(code.bytes.len() as u64) - F::from(step.pc), + F::from(code.code_size() as u64) - F::from(step.program_counter()), )?; let opcode = step.opcode().unwrap(); diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 8a1211e3fc..ea69f9b0c8 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -5,7 +5,7 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; -pub use bytecode::Bytecode; +pub use bytecode::BytecodeUnroller as Bytecode; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index f2d93faaf7..e15b20da4b 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -89,7 +89,7 @@ impl Block { let num_rows_required_for_bytecode_table: usize = self .bytecodes .values() - .map(|bytecode| bytecode.bytes.len() + 1) + .map(|bytecode| bytecode.table_len()) .sum(); let num_rows_required_for_copy_table: usize = self.copy_events.iter().map(|c| c.bytes.len() * 2).sum(); @@ -256,8 +256,8 @@ pub fn block_convert( .0 .values() .map(|v| { - let bytecode = Bytecode::new(v.clone()); - (bytecode.hash, bytecode) + let bytecode = Bytecode::from(v.clone()); + (bytecode.hash(), bytecode) }) .collect(), copy_events: block.copy_events.clone(), diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index c3531629d2..e6cb8a0374 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -1,87 +1,112 @@ use bus_mapping::evm::OpcodeId; use eth_types::{Field, Word}; +use std::marker::PhantomData; + use halo2_proofs::circuit::Value; -use sha3::{Digest, Keccak256}; +use itertools::Itertools; use crate::{table::BytecodeFieldTag, util::word}; /// Bytecode #[derive(Clone, Debug)] -pub struct Bytecode { - /// Hash of bytecode - pub hash: Word, - /// Raw bytes - pub bytes: Vec, +pub struct BytecodeUnroller { + /// We assume the is_code field is properly set. + b: eth_types::Bytecode, } -impl Bytecode { - /// Construct from bytecode bytes - pub fn new(bytes: Vec) -> Self { - let hash = Word::from_big_endian(Keccak256::digest(&bytes).as_slice()); - Self { hash, bytes } - } - +impl BytecodeUnroller { /// Assignments for bytecode table pub fn table_assignments(&self) -> Vec<[Value; 6]> { - let n = 1 + self.bytes.len(); - let mut rows = Vec::with_capacity(n); + self.into_iter() + .map(|row| { + [ + hash, + Value::known(word::Word::from(self.hash).lo()), + Value::known(word::Word::from(self.hash).hi()), + Value::known(F::from(BytecodeFieldTag::Byte as u64)), + Value::known(F::from(idx as u64)), + Value::known(F::from(byte.is_code.into())), + Value::known(F::from(byte.value.into())), + ] + }) + .collect_vec() + } - rows.push([ - Value::known(word::Word::from(self.hash).lo()), - Value::known(word::Word::from(self.hash).hi()), - Value::known(F::from(BytecodeFieldTag::Header as u64)), - Value::known(F::ZERO), - Value::known(F::ZERO), - Value::known(F::from(self.bytes.len() as u64)), - ]); + /// get byte value and is_code pair + pub fn get(&self, dest: usize) -> Option<(u8, bool)> { + self.b.code.get(dest).map(|b| (b.value, b.is_code)) + } - let mut push_data_left = 0; - for (idx, byte) in self.bytes.iter().enumerate() { - let is_code = push_data_left == 0; + /// The length of the bytecode + pub fn code_size(&self) -> usize { + self.b.code.len() + } - push_data_left = if is_code { - // push_data_left will be > 0 only if it is a push opcode - OpcodeId::from(*byte).data_len() - } else { - push_data_left - 1 - }; + /// The length of the bytecode table + pub fn table_len(&self) -> usize { + self.b.code.len() + 1 + } - rows.push([ - Value::known(word::Word::from(self.hash).lo()), - Value::known(word::Word::from(self.hash).hi()), - Value::known(F::from(BytecodeFieldTag::Byte as u64)), - Value::known(F::from(idx as u64)), - Value::known(F::from(is_code as u64)), - Value::known(F::from(*byte as u64)), - ]) - } - rows + /// The code hash + pub fn hash(&self) -> Word { + self.b.hash() } - /// get byte value and is_code pair - pub fn get(&self, dest: usize) -> [u8; 2] { - let mut push_data_left = 0; - for (idx, byte) in self.bytes.iter().enumerate() { - let mut is_code = true; - if push_data_left > 0 { - is_code = false; - push_data_left -= 1; - } else if (OpcodeId::PUSH1.as_u8()..=OpcodeId::PUSH32.as_u8()).contains(byte) { - push_data_left = *byte as usize - (OpcodeId::PUSH1.as_u8() - 1) as usize; - } + /// The code in bytes + pub fn code(&self) -> Vec { + self.b.code() + } +} - if idx == dest { - return [*byte, is_code as u8]; - } - } +impl From<ð_types::bytecode::Bytecode> for BytecodeUnroller { + fn from(b: ð_types::bytecode::Bytecode) -> Self { + Self { b: b.clone() } + } +} - // here dest > bytecodes len - panic!("can not find byte in the bytecodes list") +impl From> for BytecodeUnroller { + fn from(b: Vec) -> Self { + b.into() } } -impl From<ð_types::bytecode::Bytecode> for Bytecode { - fn from(b: ð_types::bytecode::Bytecode) -> Self { - Bytecode::new(b.to_vec()) +/// Public data for the bytecode +#[derive(Clone, Debug, PartialEq)] +pub struct BytecodeRow { + pub code_hash: Word, + pub tag: BytecodeFieldTag, + pub index: usize, + pub is_code: bool, + pub value: u64, +} + +impl IntoIterator for BytecodeUnroller { + type Item = BytecodeRow; + type IntoIter = std::vec::IntoIter; + + /// We turn the bytecode in to the circuit row for Bytecode circuit or bytecode table to use. + fn into_iter(self) -> Self::IntoIter { + std::iter::once(Self::Item { + code_hash: self.hash(), + tag: BytecodeFieldTag::Header, + index: 0, + is_code: false, + value: self.code_size().try_into().unwrap(), + }) + .chain( + self.b + .code + .iter() + .enumerate() + .map(|(index, code)| Self::Item { + code_hash: self.hash(), + tag: BytecodeFieldTag::Byte, + index, + is_code: code.is_code, + value: code.value.into(), + }), + ) + .collect_vec() + .into_iter() } } From c1c8df423c4ad4469973ca0510e7f90f8c7e7767 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 5 May 2023 23:54:07 +0800 Subject: [PATCH 02/37] replace with bytecodeCollection --- bus-mapping/src/circuit_input_builder.rs | 2 +- .../circuit_input_builder/input_state_ref.rs | 7 +- .../src/circuit_input_builder/tracer_tests.rs | 24 +- bus-mapping/src/evm/opcodes/codecopy.rs | 2 +- bus-mapping/src/evm/opcodes/create.rs | 6 +- bus-mapping/src/evm/opcodes/extcodecopy.rs | 7 +- bus-mapping/src/evm/opcodes/return_revert.rs | 16 +- bus-mapping/src/mock.rs | 2 +- bus-mapping/src/state_db.rs | 12 +- eth-types/src/bytecode.rs | 76 ++----- zkevm-circuits/src/bin/stats/helpers.rs | 2 +- .../src/bytecode_circuit/bytecode_unroller.rs | 1 + .../src/bytecode_circuit/circuit.rs | 27 +-- zkevm-circuits/src/bytecode_circuit/dev.rs | 8 +- zkevm-circuits/src/bytecode_circuit/test.rs | 8 +- zkevm-circuits/src/copy_circuit.rs | 28 ++- zkevm-circuits/src/copy_circuit/dev.rs | 2 +- zkevm-circuits/src/evm_circuit.rs | 2 +- .../src/evm_circuit/execution/codecopy.rs | 2 +- .../execution/error_invalid_jump.rs | 4 +- .../evm_circuit/execution/error_oog_log.rs | 4 +- .../execution/error_write_protection.rs | 2 +- .../src/evm_circuit/execution/extcodecopy.rs | 2 +- .../src/evm_circuit/execution/stop.rs | 4 +- zkevm-circuits/src/table.rs | 4 +- zkevm-circuits/src/table/bytecode_table.rs | 13 +- zkevm-circuits/src/witness.rs | 2 +- zkevm-circuits/src/witness/block.rs | 23 +- zkevm-circuits/src/witness/bytecode.rs | 210 ++++++++++++------ 29 files changed, 255 insertions(+), 247 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 2bc6318a52..2392ca7c69 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -575,7 +575,7 @@ pub fn build_state_code_db( ) } - let mut code_db = CodeDB::new(); + let mut code_db = CodeDB::default(); for (_address, code) in codes { code_db.insert(code.clone()); } diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 5b110b9d1a..aceea9a31a 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -1448,12 +1448,7 @@ impl<'a> CircuitInputStateRef<'a> { let mut copy_steps = Vec::with_capacity(bytes_left as usize); for idx in 0..bytes_left { let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); - let step = if addr < src_addr_end { - let code = bytecode.code.get(addr as usize).unwrap(); - (code.value, code.is_code) - } else { - (0, false) - }; + let step = bytecode.get(addr as usize).unwrap_or_default(); copy_steps.push(step); self.memory_write(exec_step, (dst_addr + idx).into(), step.0)?; } diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 69c0aaf006..b076581694 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -365,9 +365,9 @@ fn tracer_err_address_collision() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) @@ -487,9 +487,9 @@ fn tracer_create_collision_free() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) @@ -622,9 +622,9 @@ fn tracer_err_code_store_out_of_gas() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0..(32 - len % 32) as u8) @@ -770,9 +770,9 @@ fn tracer_err_invalid_code_for_create_opcode() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) @@ -922,9 +922,9 @@ fn tracer_err_max_code_size_exceeded() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) @@ -1060,9 +1060,9 @@ fn tracer_create_stop() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) diff --git a/bus-mapping/src/evm/opcodes/codecopy.rs b/bus-mapping/src/evm/opcodes/codecopy.rs index 937f06c04f..5dfe8a3cb6 100644 --- a/bus-mapping/src/evm/opcodes/codecopy.rs +++ b/bus-mapping/src/evm/opcodes/codecopy.rs @@ -77,7 +77,7 @@ fn gen_copy_event( let code_hash = state.call()?.code_hash; let bytecode: Bytecode = state.code(code_hash)?.into(); - let code_size = bytecode.code.len() as u64; + let code_size = bytecode.codesize() as u64; // Get low Uint64 of offset to generate copy steps. Since offset could be // Uint64 overflow if length is zero. diff --git a/bus-mapping/src/evm/opcodes/create.rs b/bus-mapping/src/evm/opcodes/create.rs index cdfa4fe554..7ccb4704f5 100644 --- a/bus-mapping/src/evm/opcodes/create.rs +++ b/bus-mapping/src/evm/opcodes/create.rs @@ -292,11 +292,7 @@ fn handle_copy( ) -> Result<(Vec, H256), Error> { let initialization_bytes = state.caller_ctx()?.memory.0[offset..(offset + length)].to_vec(); let code_hash = CodeDB::hash(&initialization_bytes); - let bytes: Vec<_> = Bytecode::from(initialization_bytes.clone()) - .code - .iter() - .map(|element| (element.value, element.is_code)) - .collect(); + let bytes = Bytecode::from(initialization_bytes.clone()).code_vec(); let rw_counter_start = state.block_ctx.rwc; for (i, (byte, _)) in bytes.iter().enumerate() { diff --git a/bus-mapping/src/evm/opcodes/extcodecopy.rs b/bus-mapping/src/evm/opcodes/extcodecopy.rs index ed1b109127..1a60102e94 100644 --- a/bus-mapping/src/evm/opcodes/extcodecopy.rs +++ b/bus-mapping/src/evm/opcodes/extcodecopy.rs @@ -133,7 +133,7 @@ fn gen_copy_event( } else { Bytecode::default() }; - let code_size = bytecode.code.len() as u64; + let code_size = bytecode.codesize() as u64; // Get low Uint64 of offset to generate copy steps. Since offset could be // Uint64 overflow if length is zero. @@ -436,10 +436,9 @@ mod extcodecopy_tests { assert_eq!(copy_events[0].dst_type, CopyDataType::Memory); assert!(copy_events[0].log_id.is_none()); - for (idx, (value, is_code)) in copy_events[0].bytes.iter().enumerate() { + for (idx, &(value, is_code)) in copy_events[0].bytes.iter().enumerate() { let bytecode_element = bytecode_ext.get(idx).unwrap_or_default(); - assert_eq!(*value, bytecode_element.value); - assert_eq!(*is_code, bytecode_element.is_code); + assert_eq!((value, is_code), bytecode_element); } } diff --git a/bus-mapping/src/evm/opcodes/return_revert.rs b/bus-mapping/src/evm/opcodes/return_revert.rs index 69c7fc5656..82b47e795c 100644 --- a/bus-mapping/src/evm/opcodes/return_revert.rs +++ b/bus-mapping/src/evm/opcodes/return_revert.rs @@ -206,17 +206,13 @@ fn handle_create( step: &mut ExecStep, source: Source, ) -> Result { - let values = state.call_ctx()?.memory.0[source.offset..source.offset + source.length].to_vec(); - let code_hash = CodeDB::hash(&values); + let raw_bytes = + state.call_ctx()?.memory.0[source.offset..source.offset + source.length].to_vec(); + let bytecode = Bytecode::from(raw_bytes); + let code_hash = bytecode.hash_h256(); let dst_id = NumberOrHash::Hash(code_hash); - let bytes: Vec<_> = Bytecode::from(values) - .code - .iter() - .map(|element| (element.value, element.is_code)) - .collect(); - let rw_counter_start = state.block_ctx.rwc; - for (i, (byte, _)) in bytes.iter().enumerate() { + for (i, byte) in bytecode.code().iter().enumerate() { state.push_op( step, RW::READ, @@ -236,7 +232,7 @@ fn handle_create( dst_id, dst_addr: 0, log_id: None, - bytes, + bytes: bytecode.code_vec(), }, ); diff --git a/bus-mapping/src/mock.rs b/bus-mapping/src/mock.rs index d6621ebe33..4e06367dbe 100644 --- a/bus-mapping/src/mock.rs +++ b/bus-mapping/src/mock.rs @@ -50,7 +50,7 @@ impl BlockData { fn init_dbs(geth_data: &GethData) -> (StateDB, CodeDB) { let mut sdb = StateDB::new(); - let mut code_db = CodeDB::new(); + let mut code_db = CodeDB::default(); let access_set = get_state_accesses(&geth_data.eth_block, &geth_data.geth_traces) .expect("state accesses"); diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index b306127281..90dac3e7f1 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -21,20 +21,10 @@ lazy_static! { const VALUE_ZERO: Word = Word::zero(); /// Memory storage for contract code by code hash. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct CodeDB(pub HashMap>); -impl Default for CodeDB { - fn default() -> Self { - Self::new() - } -} - impl CodeDB { - /// Create a new empty Self. - pub fn new() -> Self { - Self(HashMap::new()) - } /// Insert code indexed by code hash, and return the code hash. pub fn insert(&mut self, code: Vec) -> Hash { let hash = Self::hash(&code); diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index 7e5802b1af..0c7ade61ce 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -1,6 +1,5 @@ //! EVM byte code generator -use crate::{evm_types::OpcodeId, Bytes, ToWord, Word}; -use sha3::{Digest, Keccak256}; +use crate::{evm_types::OpcodeId, keccak256, Bytes, Hash, ToBigEndian, ToWord, Word}; use std::{collections::HashMap, str::FromStr}; /// Error type for Bytecode related failures @@ -12,30 +11,25 @@ pub enum Error { /// Helper struct that represents a single element in a bytecode. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct BytecodeElement { +struct BytecodeElement { /// The byte value of the element. - pub value: u8, + value: u8, /// Whether the element is an opcode or push data byte. - pub is_code: bool, + is_code: bool, } /// EVM Bytecode #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct Bytecode { /// Vector for bytecode elements. - pub code: Vec, + code: Vec, num_opcodes: usize, markers: HashMap, - hash: Word, } impl From for Bytes { fn from(code: Bytecode) -> Self { - code.code - .iter() - .map(|e| e.value) - .collect::>() - .into() + code.code().into() } } @@ -52,7 +46,6 @@ impl Bytecode { .collect(), markers: HashMap::new(), num_opcodes: 0, - hash: Word::from_big_endian(Keccak256::digest(&input).as_slice()), } } @@ -61,19 +54,29 @@ impl Bytecode { self.code.iter().map(|b| b.value).collect() } + /// Get the code and is_code + pub fn code_vec(&self) -> Vec<(u8, bool)> { + self.code.iter().map(|b| (b.value, b.is_code)).collect() + } + + /// Geth the code size + pub fn codesize(&self) -> usize { + self.code.len() + } + /// Get the code hash pub fn hash(&self) -> Word { - self.hash + Word::from_big_endian(&keccak256(&self.code())) } - /// Get the bytecode element at an index. - pub fn get(&self, index: usize) -> Option { - self.code.get(index).cloned() + /// Get the code hash + pub fn hash_h256(&self) -> Hash { + Hash::from_slice(&self.hash().to_be_bytes()) } - /// Get the generated code - pub fn to_vec(&self) -> Vec { - self.code.iter().map(|e| e.value).collect() + /// Get the bytecode element at an index. + pub fn get(&self, index: usize) -> Option<(u8, bool)> { + self.code.get(index).map(|elem| (elem.value, elem.is_code)) } /// Append @@ -156,16 +159,6 @@ impl Bytecode { self } - /// Generate the diassembly - pub fn disasm(&self) -> String { - let mut asm = String::new(); - for op in self.iter() { - asm.push_str(&op.to_string()); - asm.push('\n'); - } - asm - } - /// Append asm pub fn append_asm(&mut self, op: &str) -> Result<(), Error> { match OpcodeWithData::from_str(op)? { @@ -538,9 +531,7 @@ impl_other_opcodes! { #[cfg(test)] mod tests { - use super::*; use crate::Bytecode; - use std::str::FromStr; #[test] fn test_bytecode_roundtrip() { @@ -557,25 +548,6 @@ mod tests { POP STOP }; - assert_eq!(Bytecode::try_from(code.to_vec()).unwrap(), code); - } - - #[test] - fn test_asm_disasm() { - let code = bytecode! { - PUSH1(5) - PUSH2(0xa) - MUL - STOP - }; - let mut code2 = Bytecode::default(); - code.iter() - .map(|op| op.to_string()) - .map(|op| OpcodeWithData::from_str(&op).unwrap()) - .for_each(|op| { - code2.append_op(op); - }); - - assert_eq!(code.code, code2.code); + assert_eq!(Bytecode::try_from(code.code()).unwrap(), code); } } diff --git a/zkevm-circuits/src/bin/stats/helpers.rs b/zkevm-circuits/src/bin/stats/helpers.rs index 6f91a8c129..12432c9661 100644 --- a/zkevm-circuits/src/bin/stats/helpers.rs +++ b/zkevm-circuits/src/bin/stats/helpers.rs @@ -167,7 +167,7 @@ pub(crate) fn print_circuit_stats_by_states( let bytecode_prefix_op = fn_bytecode_prefix_op(opcode); code.append(&bytecode_prefix_op); code.write_op(opcode); - let opcode_pc = code.code.len() - 1; + let opcode_pc = code.codesize() - 1; // let opcode_step_index = (proxy_code.num_opcodes - 1 + code.num_opcodes) - 1; code.op_stop(); let block: GethData = TestContext::<10, 1>::new( diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 6c4fb174fc..755e8fb9cd 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -22,6 +22,7 @@ pub struct UnrolledBytecode { pub(crate) rows: Vec>, } +#[deprecated] /// Get unrolled bytecode from raw bytes pub fn unroll(bytes: Vec) -> UnrolledBytecode { let code_hash = keccak(&bytes[..]); diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 9be02126d9..1901f6cba3 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -10,7 +10,7 @@ use crate::{ word::{empty_code_hash_word_value, Word, Word32, WordExpr}, Challenges, Expr, SubCircuit, SubCircuitConfig, }, - witness, + witness::{self, BytecodeCollection}, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; use eth_types::Field; @@ -22,6 +22,7 @@ use halo2_proofs::{ }, poly::Rotation, }; +use itertools::Itertools; use log::trace; use std::vec; @@ -787,7 +788,7 @@ impl BytecodeCircuitConfig { #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { /// Unrolled bytecodes - pub bytecodes: Vec>, + pub bytecodes: BytecodeCollection, /// Circuit size pub size: usize, /// Overwrite @@ -796,7 +797,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester - pub fn new(bytecodes: Vec>, size: usize) -> Self { + pub fn new(bytecodes: BytecodeCollection, size: usize) -> Self { BytecodeCircuit { bytecodes, size, @@ -806,12 +807,7 @@ impl BytecodeCircuit { /// Creates bytecode circuit from block and bytecode_size. pub fn new_from_block_sized(block: &witness::Block, bytecode_size: usize) -> Self { - let bytecodes: Vec> = block - .bytecodes - .values() - .map(|b| unroll(b.code().clone())) - .collect(); - Self::new(bytecodes, bytecode_size) + Self::new(block.bytecodes.clone(), bytecode_size) } } @@ -832,11 +828,7 @@ impl SubCircuit for BytecodeCircuit { /// Return the minimum number of rows required to prove the block fn min_num_rows_block(block: &witness::Block) -> (usize, usize) { ( - block - .bytecodes - .values() - .map(|bytecode| bytecode.table_len()) - .sum(), + block.bytecodes.num_rows_required_for_bytecode_table(), block.circuits_params.max_bytecode, ) } @@ -852,7 +844,12 @@ impl SubCircuit for BytecodeCircuit { config.assign_internal( layouter, self.size, - &self.bytecodes, + &self + .bytecodes + .clone() + .into_iter() + .map(|b| unroll(b.code())) + .collect_vec(), &self.overwrite, challenges, false, diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index 178aecc90d..9810a07873 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -47,11 +47,9 @@ impl Circuit for BytecodeCircuit { ) -> Result<(), Error> { let challenges = challenges.values(&mut layouter); - config.keccak_table.dev_load( - &mut layouter, - self.bytecodes.iter().map(|b| &b.bytes), - &challenges, - )?; + config + .keccak_table + .dev_load(&mut layouter, &self.bytecodes.to_raw(), &challenges)?; self.synthesize_sub(&config, &challenges, &mut layouter)?; Ok(()) } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 349b1544c1..5fec41b007 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -2,6 +2,7 @@ use crate::{ bytecode_circuit::{bytecode_unroller::*, circuit::BytecodeCircuit}, table::BytecodeFieldTag, util::{is_push, keccak, unusable_rows, SubCircuit}, + witness::BytecodeCollection, }; use bus_mapping::evm::OpcodeId; use eth_types::{Bytecode, Field, Word}; @@ -19,11 +20,10 @@ fn bytecode_circuit_unusable_rows() { impl BytecodeCircuit { /// Verify that the selected bytecode fulfills the circuit pub fn verify_raw(k: u32, bytecodes: Vec>) { - let unrolled: Vec<_> = bytecodes.iter().map(|b| unroll(b.clone())).collect(); - Self::verify(k, unrolled, true); + Self::verify(k, BytecodeCollection::from_raw(bytecodes), true); } - pub(crate) fn verify(k: u32, bytecodes: Vec>, success: bool) { + pub(crate) fn verify(k: u32, bytecodes: BytecodeCollection, success: bool) { let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); @@ -40,7 +40,7 @@ impl BytecodeCircuit { /// Test bytecode circuit with unrolled bytecode pub fn test_bytecode_circuit_unrolled( k: u32, - bytecodes: Vec>, + bytecodes: BytecodeCollection, success: bool, ) { let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 08b4dd7b02..cd90be883b 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -10,12 +10,21 @@ mod test; #[cfg(feature = "test-circuits")] pub use dev::CopyCircuit as TestCopyCircuit; +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{ + BytecodeFieldTag, BytecodeTable, CopyTable, LookupTable, RwTable, TxContextFieldTag, + TxTable, + }, + util::{Challenges, SubCircuit, SubCircuitConfig}, + witness, + witness::{BytecodeCollection, RwMap, Transaction}, +}; use bus_mapping::{ circuit_input_builder::{CopyDataType, CopyEvent}, operation::Target, }; -use eth_types::{Field, Word}; - +use eth_types::Field; use gadgets::{ binary_number::BinaryNumberChip, less_than::{LtChip, LtConfig, LtInstruction}, @@ -27,18 +36,7 @@ use halo2_proofs::{ poly::Rotation, }; use itertools::Itertools; -use std::{collections::HashMap, marker::PhantomData}; - -use crate::{ - evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - table::{ - BytecodeFieldTag, BytecodeTable, CopyTable, LookupTable, RwTable, TxContextFieldTag, - TxTable, - }, - util::{Challenges, SubCircuit, SubCircuitConfig}, - witness, - witness::{Bytecode, RwMap, Transaction}, -}; +use std::marker::PhantomData; /// The rw table shared between evm circuit and state circuit #[derive(Clone, Debug)] @@ -754,7 +752,7 @@ pub struct ExternalData { /// StateCircuit -> rws pub rws: RwMap, /// BytecodeCircuit -> bytecodes - pub bytecodes: HashMap, + pub bytecodes: BytecodeCollection, } /// Copy Circuit diff --git a/zkevm-circuits/src/copy_circuit/dev.rs b/zkevm-circuits/src/copy_circuit/dev.rs index 85f0f71b04..cd5b4c2a5c 100644 --- a/zkevm-circuits/src/copy_circuit/dev.rs +++ b/zkevm-circuits/src/copy_circuit/dev.rs @@ -68,7 +68,7 @@ impl Circuit for CopyCircuit { config .0 .bytecode_table - .load(&mut layouter, self.external_data.bytecodes.values())?; + .load(&mut layouter, self.external_data.bytecodes.clone())?; self.synthesize_sub(&config.0, &challenge_values, &mut layouter) } } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index f9f9de0333..7c5edf8b53 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -420,7 +420,7 @@ impl Circuit for EvmCircuit { )?; config .bytecode_table - .load(&mut layouter, block.bytecodes.values())?; + .load(&mut layouter, block.bytecodes.clone())?; config.block_table.load(&mut layouter, &block.context)?; config.copy_table.load(&mut layouter, block, &challenges)?; config diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index 72d9ed284a..0d4cfa1316 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -162,7 +162,7 @@ impl ExecutionGadget for CodeCopyGadget { .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); - let code_size = bytecode.code_size() as u64; + let code_size = bytecode.codesize() as u64; self.code_size .assign(region, offset, Value::known(F::from(code_size)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 5cd0f7db00..7867a67be7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -130,7 +130,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { .bytecodes .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); - let code_len = code.code_size() as u64; + let code_len = code.codesize() as u64; self.code_len .assign(region, offset, Value::known(F::from(code_len)))?; @@ -138,7 +138,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { self.dest.assign(region, offset, dest, F::from(code_len))?; // set default value in case can not find value, is_code from bytecode table - let dest = usize::try_from(dest).unwrap_or(code.code_size()); + let dest = usize::try_from(dest).unwrap_or(code.codesize()); let code_pair = code.get(dest).unwrap_or((0, false)); self.value diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index 8d3db42960..4926bf9816 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -255,7 +255,7 @@ mod test { Account { address: Address::repeat_byte(0xfe), balance: Word::from(10).pow(20.into()), - code: bytecode.to_vec().into(), + code: bytecode.code().into(), ..Default::default() } } @@ -284,7 +284,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - let code = code.to_vec(); + let code = code.code_vec(); let is_empty = code.is_empty(); Account { address: Address::repeat_byte(0xff), diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index 91a1181878..2131b7f9c3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -149,7 +149,7 @@ mod test { use mock::TestContext; fn callee(code: Bytecode) -> Account { - let code = code.to_vec(); + let code = code.code_vec(); let is_empty = code.is_empty(); Account { diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index fcea4b1d91..094687ff0f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -211,7 +211,7 @@ impl ExecutionGadget for ExtcodecopyGadget { .bytecodes .get(&code_hash) .expect("could not find external bytecode") - .code_size() as u64 + .codesize() as u64 }; self.code_size .assign(region, offset, Value::known(F::from(code_size)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 2258fa5ad6..6d2d248510 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -113,13 +113,13 @@ impl ExecutionGadget for StopGadget { self.code_length.assign( region, offset, - Value::known(F::from(code.code_size() as u64)), + Value::known(F::from(code.codesize() as u64)), )?; self.is_out_of_range.assign( region, offset, - F::from(code.code_size() as u64) - F::from(step.program_counter()), + F::from(code.codesize() as u64) - F::from(step.pc), )?; let opcode = step.opcode().unwrap(); diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 2d64b58750..38ae3ab5f3 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -9,9 +9,7 @@ use crate::{ word::{self, Word}, Challenges, }, - witness::{ - Block, BlockContext, Bytecode, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction, - }, + witness::{Block, BlockContext, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction}, }; use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent, CopyStep}; use core::iter::once; diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index d96443deb7..9f242ef2f8 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -1,3 +1,5 @@ +use crate::witness::{Bytecode, BytecodeCollection}; + use super::*; /// Tag to identify the field in a Bytecode Table row @@ -44,7 +46,7 @@ impl BytecodeTable { pub fn load<'a, F: Field>( &self, layouter: &mut impl Layouter, - bytecodes: impl IntoIterator + Clone, + bytecodes: BytecodeCollection, ) -> Result<(), Error> { layouter.assign_region( || "bytecode table", @@ -62,14 +64,15 @@ impl BytecodeTable { let bytecode_table_columns = >::advice_columns(self); - for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments::() { - for (&column, value) in bytecode_table_columns.iter().zip_eq(row) { + for bytecode in bytecodes.clone().into_iter() { + let unroller: Bytecode = (&bytecode).into(); + for row in unroller.to_rows().iter() { + for (&column, value) in bytecode_table_columns.iter().zip_eq(row.to_vec()) { region.assign_advice( || format!("bytecode table row {}", offset), column, offset, - || value, + || Value::known(value), )?; } offset += 1; diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index ea69f9b0c8..abb3d19a1d 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -5,7 +5,7 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; -pub use bytecode::BytecodeUnroller as Bytecode; +pub use bytecode::{BytecodeCollection, BytecodeUnroller as Bytecode}; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index e15b20da4b..4edb4f875d 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -1,5 +1,4 @@ -use std::collections::HashMap; - +use super::{BytecodeCollection, ExecStep, Rw, RwMap, Transaction}; use crate::{ evm_circuit::{detect_fixed_table_tags, EvmCircuit}, exp_circuit::param::OFFSET_INCREMENT, @@ -14,8 +13,6 @@ use bus_mapping::{ use eth_types::{Address, Field, ToScalar, Word}; use halo2_proofs::circuit::Value; -use super::{Bytecode, ExecStep, Rw, RwMap, Transaction}; - // TODO: Remove fields that are duplicated in`eth_block` /// Block is the struct used by all circuits, which contains all the needed /// data for witness generation. @@ -33,7 +30,7 @@ pub struct Block { /// Read write events in the RwTable pub rws: RwMap, /// Bytecode used in the block - pub bytecodes: HashMap, + pub bytecodes: BytecodeCollection, /// The block context pub context: BlockContext, /// Copy events for the copy circuit's table. @@ -86,11 +83,8 @@ impl Block { .iter() .map(|tag| tag.build::().count()) .sum(); - let num_rows_required_for_bytecode_table: usize = self - .bytecodes - .values() - .map(|bytecode| bytecode.table_len()) - .sum(); + let num_rows_required_for_bytecode_table = + self.bytecodes.num_rows_required_for_bytecode_table(); let num_rows_required_for_copy_table: usize = self.copy_events.iter().map(|c| c.bytes.len() * 2).sum(); let num_rows_required_for_keccak_table: usize = self.keccak_inputs.len(); @@ -252,14 +246,7 @@ pub fn block_convert( txs: block.txs().to_vec(), end_block_not_last: block.block_steps.end_block_not_last.clone(), end_block_last: block.block_steps.end_block_last.clone(), - bytecodes: code_db - .0 - .values() - .map(|v| { - let bytecode = Bytecode::from(v.clone()); - (bytecode.hash(), bytecode) - }) - .collect(), + bytecodes: BytecodeCollection::from_codedb(code_db), copy_events: block.copy_events.clone(), exp_events: block.exp_events.clone(), sha3_inputs: block.sha3_inputs.clone(), diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index e6cb8a0374..fb058e4bd4 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -1,112 +1,190 @@ -use bus_mapping::evm::OpcodeId; -use eth_types::{Field, Word}; -use std::marker::PhantomData; - -use halo2_proofs::circuit::Value; +use crate::{table::BytecodeFieldTag, util}; +use bus_mapping::state_db::CodeDB; +use eth_types::{Bytecode, Field, Word}; use itertools::Itertools; +use std::collections::HashMap; + +/// A collection of bytecode to prove +#[derive(Clone, Debug, Default)] +pub struct BytecodeCollection { + codes: HashMap, +} + +impl BytecodeCollection { + /// Construct from codedb + pub fn from_codedb(code_db: &CodeDB) -> Self { + Self { + codes: code_db + .0 + .values() + .map(|v| { + let bytecode = Bytecode::from(v.clone()); + (bytecode.hash(), bytecode) + }) + .collect(), + } + } + + /// Construct from raw bytes + pub fn from_raw(bytecodes: Vec>) -> Self { + Self { + codes: HashMap::from_iter(bytecodes.iter().map(|bytecode| { + let code = Bytecode::from(bytecode.clone()); + (code.hash(), code) + })), + } + } -use crate::{table::BytecodeFieldTag, util::word}; + /// Compute number of rows required for bytecode table. + pub fn num_rows_required_for_bytecode_table(&self) -> usize { + self.codes + .values() + .map(|bytecode| bytecode.codesize() + 1) + .sum() + } + /// Query code by hash + pub fn get(&self, codehash: &Word) -> Option { + self.codes.get(codehash).cloned() + } + + /// Get raw bytes + #[deprecated()] + pub fn to_raw(&self) -> Vec> { + self.codes.values().map(|code| code.code()).collect_vec() + } +} + +impl IntoIterator for BytecodeCollection { + type Item = Bytecode; + type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.codes.values().cloned().collect_vec().into_iter() + } +} /// Bytecode #[derive(Clone, Debug)] -pub struct BytecodeUnroller { +pub struct BytecodeUnroller { /// We assume the is_code field is properly set. - b: eth_types::Bytecode, + bytecode: Bytecode, + rows: Vec>, } -impl BytecodeUnroller { - /// Assignments for bytecode table - pub fn table_assignments(&self) -> Vec<[Value; 6]> { - self.into_iter() - .map(|row| { - [ - hash, - Value::known(word::Word::from(self.hash).lo()), - Value::known(word::Word::from(self.hash).hi()), - Value::known(F::from(BytecodeFieldTag::Byte as u64)), - Value::known(F::from(idx as u64)), - Value::known(F::from(byte.is_code.into())), - Value::known(F::from(byte.value.into())), - ] - }) +impl BytecodeUnroller { + pub(crate) fn to_rows(&self) -> Vec> { + let code_hash = self.bytecode.hash(); + std::iter::once(BytecodeRow::head(code_hash, self.bytecode.codesize())) + .chain( + self.bytecode + .code_vec() + .iter() + .enumerate() + .map(|(index, &(byte, is_code))| { + BytecodeRow::body(code_hash, index, is_code, byte) + }), + ) .collect_vec() } + #[deprecated()] /// get byte value and is_code pair pub fn get(&self, dest: usize) -> Option<(u8, bool)> { - self.b.code.get(dest).map(|b| (b.value, b.is_code)) + self.bytecode.get(dest) } + #[deprecated()] /// The length of the bytecode - pub fn code_size(&self) -> usize { - self.b.code.len() + pub fn codesize(&self) -> usize { + self.bytecode.codesize() } /// The length of the bytecode table pub fn table_len(&self) -> usize { - self.b.code.len() + 1 + self.rows.len() } + #[deprecated()] /// The code hash pub fn hash(&self) -> Word { - self.b.hash() + self.bytecode.hash() } + #[deprecated()] /// The code in bytes pub fn code(&self) -> Vec { - self.b.code() + self.bytecode.code() } } -impl From<ð_types::bytecode::Bytecode> for BytecodeUnroller { - fn from(b: ð_types::bytecode::Bytecode) -> Self { - Self { b: b.clone() } +impl From<&Bytecode> for BytecodeUnroller { + fn from(bytecode: &Bytecode) -> Self { + let s = Self { + bytecode: bytecode.clone(), + rows: vec![], + }; + Self { + bytecode: bytecode.clone(), + rows: s.to_rows(), + } } } -impl From> for BytecodeUnroller { +impl From> for BytecodeUnroller { fn from(b: Vec) -> Self { b.into() } } +impl IntoIterator for BytecodeUnroller { + type Item = BytecodeRow; + + type IntoIter = std::vec::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + self.rows.into_iter() + } +} + /// Public data for the bytecode #[derive(Clone, Debug, PartialEq)] -pub struct BytecodeRow { - pub code_hash: Word, - pub tag: BytecodeFieldTag, - pub index: usize, - pub is_code: bool, - pub value: u64, +pub struct BytecodeRow { + /// We don't assign it now + code_hash: Word, + pub tag: F, + pub index: F, + pub is_code: F, + pub value: F, } -impl IntoIterator for BytecodeUnroller { - type Item = BytecodeRow; - type IntoIter = std::vec::IntoIter; +impl BytecodeRow { + pub(crate) fn to_vec(&self) -> [F; 6] { + let code_hash: util::word::Word = util::word::Word::from(self.code_hash); + [ + code_hash.lo(), + code_hash.hi(), + self.tag, + self.index, + self.is_code, + self.value, + ] + } - /// We turn the bytecode in to the circuit row for Bytecode circuit or bytecode table to use. - fn into_iter(self) -> Self::IntoIter { - std::iter::once(Self::Item { - code_hash: self.hash(), - tag: BytecodeFieldTag::Header, - index: 0, - is_code: false, - value: self.code_size().try_into().unwrap(), - }) - .chain( - self.b - .code - .iter() - .enumerate() - .map(|(index, code)| Self::Item { - code_hash: self.hash(), - tag: BytecodeFieldTag::Byte, - index, - is_code: code.is_code, - value: code.value.into(), - }), - ) - .collect_vec() - .into_iter() + pub fn head(code_hash: Word, code_size: usize) -> Self { + Self { + code_hash, + tag: F::from(BytecodeFieldTag::Header as u64), + index: F::ZERO, + is_code: F::ZERO, + value: F::from(code_size as u64), + } + } + pub fn body(code_hash: Word, index: usize, is_code: bool, value: u8) -> Self { + Self { + code_hash, + tag: F::from(BytecodeFieldTag::Byte as u64), + index: F::from(index as u64), + is_code: F::from(is_code.into()), + value: F::from(value.into()), + } } } From 1419cd27bb93095372fc40d952490ccdeaa60449 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 7 Jul 2023 18:34:22 +0800 Subject: [PATCH 03/37] mino --- bus-mapping/src/evm/opcodes/codesize.rs | 2 +- bus-mapping/src/evm/opcodes/extcodecopy.rs | 6 +----- eth-types/src/bytecode.rs | 5 +++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/codesize.rs b/bus-mapping/src/evm/opcodes/codesize.rs index 2c5dd5e8d0..a190254623 100644 --- a/bus-mapping/src/evm/opcodes/codesize.rs +++ b/bus-mapping/src/evm/opcodes/codesize.rs @@ -67,7 +67,7 @@ mod codesize_tests { STOP }; code.append(&tail); - let codesize = code.to_vec().len(); + let codesize = code.codesize(); let block: GethData = TestContext::<2, 1>::new( None, diff --git a/bus-mapping/src/evm/opcodes/extcodecopy.rs b/bus-mapping/src/evm/opcodes/extcodecopy.rs index 1a60102e94..3e70cad6c3 100644 --- a/bus-mapping/src/evm/opcodes/extcodecopy.rs +++ b/bus-mapping/src/evm/opcodes/extcodecopy.rs @@ -410,11 +410,7 @@ mod extcodecopy_tests { MemoryOp::new( expected_call_id, MemoryAddress::from(memory_offset + idx), - if data_offset + idx < bytecode_ext.to_vec().len() { - bytecode_ext.to_vec()[data_offset + idx] - } else { - 0 - }, + bytecode_ext.get_byte(data_offset + idx).unwrap_or(0), ), ) }) diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index 0c7ade61ce..e78eecfe3b 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -79,6 +79,11 @@ impl Bytecode { self.code.get(index).map(|elem| (elem.value, elem.is_code)) } + /// Get the bytecode element at an index. + pub fn get_byte(&self, index: usize) -> Option { + self.code.get(index).map(|elem| elem.value) + } + /// Append pub fn append(&mut self, other: &Bytecode) { self.code.extend_from_slice(&other.code); From 937bffbdcb763156fe366a7afd9a10fb7bdb7de1 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 7 Jul 2023 22:55:06 +0800 Subject: [PATCH 04/37] get some more sense --- .../src/bytecode_circuit/circuit.rs | 2 +- zkevm-circuits/src/table/bytecode_table.rs | 15 ++++- zkevm-circuits/src/witness.rs | 1 + zkevm-circuits/src/witness/bytecode.rs | 65 +++---------------- 4 files changed, 24 insertions(+), 59 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 1901f6cba3..fb1d44c6e2 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -798,7 +798,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester pub fn new(bytecodes: BytecodeCollection, size: usize) -> Self { - BytecodeCircuit { + Self { bytecodes, size, overwrite: Default::default(), diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index 9f242ef2f8..3928d976a3 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -1,4 +1,4 @@ -use crate::witness::{Bytecode, BytecodeCollection}; +use crate::witness::{BytecodeCollection, BytecodeRow}; use super::*; @@ -65,8 +65,17 @@ impl BytecodeTable { let bytecode_table_columns = >::advice_columns(self); for bytecode in bytecodes.clone().into_iter() { - let unroller: Bytecode = (&bytecode).into(); - for row in unroller.to_rows().iter() { + let rows = { + let code_hash = bytecode.hash(); + std::iter::once(BytecodeRow::::head(code_hash, bytecode.codesize())) + .chain(bytecode.code_vec().iter().enumerate().map( + |(index, &(byte, is_code))| { + BytecodeRow::::body(code_hash, index, is_code, byte) + }, + )) + .collect_vec() + }; + for row in rows.iter() { for (&column, value) in bytecode_table_columns.iter().zip_eq(row.to_vec()) { region.assign_advice( || format!("bytecode table row {}", offset), diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index abb3d19a1d..04ddbfb40a 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -5,6 +5,7 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; +pub(crate) use bytecode::BytecodeRow; pub use bytecode::{BytecodeCollection, BytecodeUnroller as Bytecode}; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index fb058e4bd4..579ea9c97f 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -64,28 +64,12 @@ impl IntoIterator for BytecodeCollection { } /// Bytecode #[derive(Clone, Debug)] -pub struct BytecodeUnroller { +pub struct BytecodeUnroller { /// We assume the is_code field is properly set. bytecode: Bytecode, - rows: Vec>, } -impl BytecodeUnroller { - pub(crate) fn to_rows(&self) -> Vec> { - let code_hash = self.bytecode.hash(); - std::iter::once(BytecodeRow::head(code_hash, self.bytecode.codesize())) - .chain( - self.bytecode - .code_vec() - .iter() - .enumerate() - .map(|(index, &(byte, is_code))| { - BytecodeRow::body(code_hash, index, is_code, byte) - }), - ) - .collect_vec() - } - +impl BytecodeUnroller { #[deprecated()] /// get byte value and is_code pair pub fn get(&self, dest: usize) -> Option<(u8, bool)> { @@ -100,7 +84,7 @@ impl BytecodeUnroller { /// The length of the bytecode table pub fn table_len(&self) -> usize { - self.rows.len() + self.bytecode.codesize() + 1 } #[deprecated()] @@ -116,44 +100,15 @@ impl BytecodeUnroller { } } -impl From<&Bytecode> for BytecodeUnroller { - fn from(bytecode: &Bytecode) -> Self { - let s = Self { - bytecode: bytecode.clone(), - rows: vec![], - }; - Self { - bytecode: bytecode.clone(), - rows: s.to_rows(), - } - } -} - -impl From> for BytecodeUnroller { - fn from(b: Vec) -> Self { - b.into() - } -} - -impl IntoIterator for BytecodeUnroller { - type Item = BytecodeRow; - - type IntoIter = std::vec::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - self.rows.into_iter() - } -} - /// Public data for the bytecode #[derive(Clone, Debug, PartialEq)] -pub struct BytecodeRow { +pub(crate) struct BytecodeRow { /// We don't assign it now code_hash: Word, - pub tag: F, - pub index: F, - pub is_code: F, - pub value: F, + pub(crate) tag: F, + pub(crate) index: F, + pub(crate) is_code: F, + pub(crate) value: F, } impl BytecodeRow { @@ -169,7 +124,7 @@ impl BytecodeRow { ] } - pub fn head(code_hash: Word, code_size: usize) -> Self { + pub(crate) fn head(code_hash: Word, code_size: usize) -> Self { Self { code_hash, tag: F::from(BytecodeFieldTag::Header as u64), @@ -178,7 +133,7 @@ impl BytecodeRow { value: F::from(code_size as u64), } } - pub fn body(code_hash: Word, index: usize, is_code: bool, value: u8) -> Self { + pub(crate) fn body(code_hash: Word, index: usize, is_code: bool, value: u8) -> Self { Self { code_hash, tag: F::from(BytecodeFieldTag::Byte as u64), From b1c7b2225b3c4fd2dc4a143c6de1bcd307b318ad Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 7 Jul 2023 23:17:41 +0800 Subject: [PATCH 05/37] proper API call --- .../src/circuit_input_builder/tracer_tests.rs | 8 +++--- bus-mapping/src/evm/opcodes/codecopy.rs | 22 +++++---------- eth-types/src/geth_types.rs | 27 +++++++++++++++++-- zkevm-circuits/src/bytecode_circuit/test.rs | 10 +++---- .../src/evm_circuit/execution/callop.rs | 25 +++-------------- .../execution/error_invalid_jump.rs | 19 +++---------- .../evm_circuit/execution/error_oog_call.rs | 20 +++----------- .../execution/error_oog_constant.rs | 19 +++---------- .../evm_circuit/execution/error_oog_log.rs | 19 +++---------- .../src/evm_circuit/execution/error_stack.rs | 18 ++----------- .../execution/error_write_protection.rs | 20 +++----------- 11 files changed, 61 insertions(+), 146 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index b076581694..a4303a5451 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -1761,9 +1761,9 @@ fn create2_address() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) @@ -1854,9 +1854,9 @@ fn create_address() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) diff --git a/bus-mapping/src/evm/opcodes/codecopy.rs b/bus-mapping/src/evm/opcodes/codecopy.rs index 5dfe8a3cb6..5a6e844f6e 100644 --- a/bus-mapping/src/evm/opcodes/codecopy.rs +++ b/bus-mapping/src/evm/opcodes/codecopy.rs @@ -129,7 +129,6 @@ mod codecopy_tests { circuit_input_builder::{CopyDataType, ExecState, NumberOrHash}, mock::BlockData, operation::{MemoryOp, StackOp, RW}, - state_db::CodeDB, }; #[test] @@ -202,11 +201,7 @@ mod codecopy_tests { MemoryOp::new( 1, MemoryAddress::from(dst_offset + idx), - if code_offset + idx < code.to_vec().len() { - code.to_vec()[code_offset + idx] - } else { - 0 - }, + code.get_byte(code_offset + idx).unwrap_or(0), ), ) }) @@ -216,12 +211,9 @@ mod codecopy_tests { let copy_events = builder.block.copy_events.clone(); assert_eq!(copy_events.len(), 1); assert_eq!(copy_events[0].bytes.len(), size); - assert_eq!( - copy_events[0].src_id, - NumberOrHash::Hash(CodeDB::hash(&code.to_vec())) - ); + assert_eq!(copy_events[0].src_id, NumberOrHash::Hash(code.hash_h256())); assert_eq!(copy_events[0].src_addr as usize, code_offset); - assert_eq!(copy_events[0].src_addr_end as usize, code.to_vec().len()); + assert_eq!(copy_events[0].src_addr_end as usize, code.codesize()); assert_eq!(copy_events[0].src_type, CopyDataType::Bytecode); assert_eq!( copy_events[0].dst_id, @@ -231,10 +223,10 @@ mod codecopy_tests { assert_eq!(copy_events[0].dst_type, CopyDataType::Memory); assert!(copy_events[0].log_id.is_none()); - for (idx, (value, is_code)) in copy_events[0].bytes.iter().enumerate() { - let bytecode_element = code.get(code_offset + idx).unwrap_or_default(); - assert_eq!(*value, bytecode_element.value); - assert_eq!(*is_code, bytecode_element.is_code); + for (idx, &(value, is_code)) in copy_events[0].bytes.iter().enumerate() { + let (true_value, true_is_code) = code.get(code_offset + idx).unwrap_or_default(); + assert_eq!(value, true_value); + assert_eq!(is_code, true_is_code); } } } diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index 5b1a893a90..b362e1c96d 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -3,8 +3,8 @@ use crate::{ keccak256, sign_types::{biguint_to_32bytes_le, ct_option_ok_or, recover_pk, SignData, SECP256K1_Q}, - AccessList, Address, Block, Bytes, Error, GethExecTrace, Hash, ToBigEndian, ToLittleEndian, - ToWord, Word, U64, + AccessList, Address, Block, Bytecode, Bytes, Error, GethExecTrace, Hash, ToBigEndian, + ToLittleEndian, ToWord, Word, U64, }; use ethers_core::{ types::{transaction::response, NameOrAddress, TransactionRequest}, @@ -44,6 +44,29 @@ impl Account { && self.code.is_empty() && self.storage.is_empty() } + + #[deprecated] + /// Generate an account that has either code or balance + pub fn mock_code_or_balance(code: Bytecode) -> Self { + let is_empty = code.codesize() == 0; + Self { + address: Address::repeat_byte(0xff), + code: code.into(), + nonce: U64::from(!is_empty as u64), + balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), + ..Default::default() + } + } + #[deprecated] + /// Generate an account that has 100 ETH + pub fn mock_100_ether(code: Bytecode) -> Self { + Self { + address: Address::repeat_byte(0xfe), + balance: Word::from(10).pow(20.into()), + code: code.into(), + ..Default::default() + } + } } fn serde_account_storage( diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 5fec41b007..33b59c9ce5 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -1,7 +1,7 @@ use crate::{ bytecode_circuit::{bytecode_unroller::*, circuit::BytecodeCircuit}, table::BytecodeFieldTag, - util::{is_push, keccak, unusable_rows, SubCircuit}, + util::{is_push, unusable_rows, SubCircuit}, witness::BytecodeCollection, }; use bus_mapping::evm::OpcodeId; @@ -100,7 +100,7 @@ fn bytecode_unrolling() { } } // Set the code_hash of the complete bytecode in the rows - let code_hash = keccak(&bytecode.to_vec()[..]); + let code_hash: eth_types::U256 = bytecode.hash(); for row in rows.iter_mut() { row.code_hash = code_hash; } @@ -111,15 +111,15 @@ fn bytecode_unrolling() { tag: Fr::from(BytecodeFieldTag::Header as u64), index: Fr::ZERO, is_code: Fr::ZERO, - value: Fr::from(bytecode.to_vec().len() as u64), + value: Fr::from(bytecode.codesize() as u64), }, ); // Unroll the bytecode - let unrolled = unroll(bytecode.to_vec()); + let unrolled = unroll(bytecode.code()); // Check if the bytecode was unrolled correctly assert_eq!( UnrolledBytecode { - bytes: bytecode.to_vec(), + bytes: bytecode.code(), rows, }, unrolled, diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index fc556ad0d9..8f52711a60 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -640,7 +640,6 @@ mod test { use bus_mapping::circuit_input_builder::FixedCParams; use eth_types::{ address, bytecode, evm_types::OpcodeId, geth_types::Account, word, Address, ToWord, Word, - U64, }; use itertools::Itertools; @@ -780,15 +779,7 @@ mod test { } fn callee(code: bytecode::Bytecode) -> Account { - let code = code.to_vec(); - let is_empty = code.is_empty(); - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } fn caller(opcode: &OpcodeId, stack: Stack, caller_is_success: bool) -> Account { @@ -830,12 +821,7 @@ mod test { .write_op(terminator) }); - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: bytecode.to_vec().into(), - ..Default::default() - } + Account::mock_100_ether(bytecode) } fn caller_for_insufficient_balance(opcode: &OpcodeId, stack: Stack) -> Account { @@ -995,12 +981,7 @@ mod test { STOP }); test_ok( - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: caller_bytecode.into(), - ..Default::default() - }, + Account::mock_100_ether(caller_bytecode), callee(callee_bytecode), ); } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 7867a67be7..5e760877a7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -182,7 +182,7 @@ mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ address, bytecode, bytecode::Bytecode, evm_types::OpcodeId, geth_types::Account, Address, - ToWord, Word, U64, + ToWord, Word, }; use mock::TestContext; @@ -240,15 +240,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - let code = code.to_vec(); - let is_empty = code.is_empty(); - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } // jump or jumpi error happen in internal call @@ -305,12 +297,7 @@ mod test { STOP }); test_ok( - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: caller_bytecode.into(), - ..Default::default() - }, + Account::mock_100_ether(caller_bytecode), callee(callee_bytecode), ); } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index 41dad3a55f..0044e4eb20 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -223,7 +223,7 @@ mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ address, bytecode, bytecode::Bytecode, evm_types::OpcodeId, geth_types::Account, Address, - ToWord, Word, U64, + ToWord, Word, }; use mock::TestContext; use std::default::Default; @@ -269,25 +269,11 @@ mod test { fn caller(opcode: OpcodeId, stack: Stack) -> Account { let bytecode = call_bytecode(opcode, Address::repeat_byte(0xff), stack); - - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: bytecode.to_vec().into(), - ..Default::default() - } + Account::mock_100_ether(bytecode) } fn callee(code: Bytecode) -> Account { - let code = code.to_vec(); - let is_empty = code.is_empty(); - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } fn test_oog(caller: &Account, callee: &Account, is_root: bool) { diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs index 90bfd06163..d367a2c39e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -94,7 +94,7 @@ mod test { use bus_mapping::evm::OpcodeId; use eth_types::{ self, address, bytecode, bytecode::Bytecode, evm_types::GasCost, geth_types::Account, - Address, ToWord, Word, U64, + Address, ToWord, Word, }; use mock::{ @@ -211,12 +211,7 @@ mod test { .write_op(terminator) }; - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: bytecode.to_vec().into(), - ..Default::default() - } + Account::mock_100_ether(bytecode) } fn oog_constant_internal_call(caller: Account, callee: Account) { @@ -243,15 +238,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - let code = code.to_vec(); - let is_empty = code.is_empty(); - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } #[test] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index 4926bf9816..4af29dbef0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -145,7 +145,7 @@ mod test { use bus_mapping::evm::OpcodeId; use eth_types::{ self, address, bytecode, bytecode::Bytecode, evm_types::GasCost, geth_types::Account, - Address, ToWord, Word, U64, + Address, ToWord, Word, }; use mock::{ @@ -252,12 +252,7 @@ mod test { .write_op(terminator) }; - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: bytecode.code().into(), - ..Default::default() - } + Account::mock_100_ether(bytecode) } fn oog_log_internal_call(caller: Account, callee: Account) { @@ -284,15 +279,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - let code = code.code_vec(); - let is_empty = code.is_empty(); - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } #[test] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs index e74cb392f7..dfc9a537b0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs @@ -75,7 +75,6 @@ mod test { use bus_mapping::{circuit_input_builder::FixedCParams, evm::OpcodeId}; use eth_types::{ self, address, bytecode, bytecode::Bytecode, geth_types::Account, Address, ToWord, Word, - U64, }; use mock::TestContext; @@ -185,12 +184,7 @@ mod test { .write_op(terminator) }; - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: bytecode.to_vec().into(), - ..Default::default() - } + Account::mock_100_ether(bytecode) } fn stack_error_internal_call(caller: Account, callee: Account) { @@ -217,15 +211,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - let code = code.to_vec(); - let is_empty = code.is_empty(); - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } // internal call error test diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index 2131b7f9c3..e83986e7b3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -144,21 +144,12 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ - address, bytecode, bytecode::Bytecode, geth_types::Account, Address, ToWord, Word, U64, + address, bytecode, bytecode::Bytecode, geth_types::Account, Address, ToWord, Word, }; use mock::TestContext; fn callee(code: Bytecode) -> Account { - let code = code.code_vec(); - let is_empty = code.is_empty(); - - Account { - address: Address::repeat_byte(0xff), - code: code.into(), - nonce: U64::from(!is_empty as u64), - balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), - ..Default::default() - } + Account::mock_code_or_balance(code) } #[test] @@ -213,12 +204,7 @@ mod test { } test_ok( - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(20.into()), - code: caller_bytecode.into(), - ..Default::default() - }, + Account::mock_100_ether(caller_bytecode), callee(callee_bytecode), ); } From 59b11f3589b4c9672fc0e47fa917120415126626 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 7 Jul 2023 23:41:00 +0800 Subject: [PATCH 06/37] from codedb --- zkevm-circuits/src/witness/block.rs | 2 +- zkevm-circuits/src/witness/bytecode.rs | 29 +++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index 4edb4f875d..74967512a6 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -246,7 +246,7 @@ pub fn block_convert( txs: block.txs().to_vec(), end_block_not_last: block.block_steps.end_block_not_last.clone(), end_block_last: block.block_steps.end_block_last.clone(), - bytecodes: BytecodeCollection::from_codedb(code_db), + bytecodes: code_db.into(), copy_events: block.copy_events.clone(), exp_events: block.exp_events.clone(), sha3_inputs: block.sha3_inputs.clone(), diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 579ea9c97f..eb27ddc155 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -11,20 +11,6 @@ pub struct BytecodeCollection { } impl BytecodeCollection { - /// Construct from codedb - pub fn from_codedb(code_db: &CodeDB) -> Self { - Self { - codes: code_db - .0 - .values() - .map(|v| { - let bytecode = Bytecode::from(v.clone()); - (bytecode.hash(), bytecode) - }) - .collect(), - } - } - /// Construct from raw bytes pub fn from_raw(bytecodes: Vec>) -> Self { Self { @@ -54,6 +40,21 @@ impl BytecodeCollection { } } +impl From<&CodeDB> for BytecodeCollection { + fn from(code_db: &CodeDB) -> Self { + Self { + codes: code_db + .0 + .values() + .map(|v| { + let bytecode = Bytecode::from(v.clone()); + (bytecode.hash(), bytecode) + }) + .collect(), + } + } +} + impl IntoIterator for BytecodeCollection { type Item = Bytecode; type IntoIter = std::vec::IntoIter; From 32c49cde458ac871d66eb92247a33fd6cbfe9cd0 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sat, 8 Jul 2023 00:44:28 +0800 Subject: [PATCH 07/37] WIP new idea on bytecode circuit --- .../src/bytecode_circuit/circuit.rs | 19 +++---- zkevm-circuits/src/bytecode_circuit/test.rs | 38 ++++++------- zkevm-circuits/src/witness.rs | 2 +- zkevm-circuits/src/witness/bytecode.rs | 57 +++++++++++++++---- 4 files changed, 70 insertions(+), 46 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index fb1d44c6e2..4c181300d4 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -10,7 +10,7 @@ use crate::{ word::{empty_code_hash_word_value, Word, Word32, WordExpr}, Challenges, Expr, SubCircuit, SubCircuitConfig, }, - witness::{self, BytecodeCollection}, + witness::{self, BytecodeCollection, BytecodeTableAssignment}, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; use eth_types::Field; @@ -485,7 +485,7 @@ impl BytecodeCircuitConfig { &self, layouter: &mut impl Layouter, size: usize, - witness: &[UnrolledBytecode], + witness: &BytecodeTableAssignment, overwrite: &UnrolledBytecode, challenges: &Challenges>, fail_fast: bool, @@ -788,7 +788,7 @@ impl BytecodeCircuitConfig { #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { /// Unrolled bytecodes - pub bytecodes: BytecodeCollection, + pub bytecodes: BytecodeTableAssignment, /// Circuit size pub size: usize, /// Overwrite @@ -797,9 +797,9 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester - pub fn new(bytecodes: BytecodeCollection, size: usize) -> Self { + pub fn new(bytecodes: &BytecodeTableAssignment, size: usize) -> Self { Self { - bytecodes, + bytecodes: bytecodes.clone(), size, overwrite: Default::default(), } @@ -807,7 +807,7 @@ impl BytecodeCircuit { /// Creates bytecode circuit from block and bytecode_size. pub fn new_from_block_sized(block: &witness::Block, bytecode_size: usize) -> Self { - Self::new(block.bytecodes.clone(), bytecode_size) + Self::new(&block.bytecodes.into(), bytecode_size) } } @@ -844,12 +844,7 @@ impl SubCircuit for BytecodeCircuit { config.assign_internal( layouter, self.size, - &self - .bytecodes - .clone() - .into_iter() - .map(|b| unroll(b.code())) - .collect_vec(), + &self.bytecodes, &self.overwrite, challenges, false, diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 33b59c9ce5..2415bc8606 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -2,7 +2,7 @@ use crate::{ bytecode_circuit::{bytecode_unroller::*, circuit::BytecodeCircuit}, table::BytecodeFieldTag, util::{is_push, unusable_rows, SubCircuit}, - witness::BytecodeCollection, + witness::{BytecodeCollection, BytecodeTableAssignment}, }; use bus_mapping::evm::OpcodeId; use eth_types::{Bytecode, Field, Word}; @@ -18,12 +18,7 @@ fn bytecode_circuit_unusable_rows() { } impl BytecodeCircuit { - /// Verify that the selected bytecode fulfills the circuit - pub fn verify_raw(k: u32, bytecodes: Vec>) { - Self::verify(k, BytecodeCollection::from_raw(bytecodes), true); - } - - pub(crate) fn verify(k: u32, bytecodes: BytecodeCollection, success: bool) { + pub(crate) fn verify(k: u32, bytecodes: &impl Into>, success: bool) { let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); @@ -40,7 +35,7 @@ impl BytecodeCircuit { /// Test bytecode circuit with unrolled bytecode pub fn test_bytecode_circuit_unrolled( k: u32, - bytecodes: BytecodeCollection, + bytecodes: &impl Into>, success: bool, ) { let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); @@ -132,13 +127,13 @@ fn bytecode_unrolling() { #[test] fn bytecode_empty() { let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![])], true); + test_bytecode_circuit_unrolled::(k, vec![vec![]], true); } #[test] fn bytecode_simple() { let k = 9; - let bytecodes = vec![unroll(vec![7u8]), unroll(vec![6u8]), unroll(vec![5u8])]; + let bytecodes = vec![vec![7u8], vec![6u8], vec![5u8]]; test_bytecode_circuit_unrolled::(k, bytecodes, true); } @@ -146,21 +141,21 @@ fn bytecode_simple() { #[test] fn bytecode_full() { let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 8])], true); + test_bytecode_circuit_unrolled::(k, vec![vec![7u8; 2usize.pow(k) - 8]], true); } #[test] fn bytecode_last_row_with_byte() { let k = 9; // Last row must be a padding row, so we have one row less for actual bytecode - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 7])], false); + test_bytecode_circuit_unrolled::(k, vec![vec![7u8; 2usize.pow(k) - 7]], false); } /// Tests a circuit with incomplete bytecode #[test] fn bytecode_incomplete() { let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) + 1])], false); + test_bytecode_circuit_unrolled::(k, vec![vec![7u8; 2usize.pow(k) + 1]], false); } /// Tests multiple bytecodes in a single circuit @@ -170,15 +165,15 @@ fn bytecode_push() { test_bytecode_circuit_unrolled::( k, vec![ - unroll(vec![]), - unroll(vec![OpcodeId::PUSH32.as_u8()]), - unroll(vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()]), - unroll(vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()]), - unroll(vec![ + vec![], + vec![OpcodeId::PUSH32.as_u8()], + vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()], + vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()], + vec![ OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8(), - ]), + ], ], true, ); @@ -189,11 +184,10 @@ fn bytecode_push() { fn bytecode_invalid_hash_data() { let k = 9; let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + test_bytecode_circuit_unrolled::(k, vec![bytecode.clone()], true); // Change the code_hash on the first position (header row) { - let mut invalid = unrolled; + let mut invalid = bytecode; invalid.rows[0].code_hash += Word::one(); log::trace!("bytecode_invalid_hash_data: Change the code_hash on the first position"); test_bytecode_circuit_unrolled::(k, vec![invalid], false); diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 04ddbfb40a..84e3b4eacb 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -5,8 +5,8 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; -pub(crate) use bytecode::BytecodeRow; pub use bytecode::{BytecodeCollection, BytecodeUnroller as Bytecode}; +pub(crate) use bytecode::{BytecodeRow, BytecodeTableAssignment}; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index eb27ddc155..2cef8003ab 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -2,7 +2,7 @@ use crate::{table::BytecodeFieldTag, util}; use bus_mapping::state_db::CodeDB; use eth_types::{Bytecode, Field, Word}; use itertools::Itertools; -use std::collections::HashMap; +use std::{collections::HashMap, ops::Deref}; /// A collection of bytecode to prove #[derive(Clone, Debug, Default)] @@ -11,16 +11,6 @@ pub struct BytecodeCollection { } impl BytecodeCollection { - /// Construct from raw bytes - pub fn from_raw(bytecodes: Vec>) -> Self { - Self { - codes: HashMap::from_iter(bytecodes.iter().map(|bytecode| { - let code = Bytecode::from(bytecode.clone()); - (code.hash(), code) - })), - } - } - /// Compute number of rows required for bytecode table. pub fn num_rows_required_for_bytecode_table(&self) -> usize { self.codes @@ -55,6 +45,17 @@ impl From<&CodeDB> for BytecodeCollection { } } +impl From>> for BytecodeCollection { + fn from(bytecodes: Vec>) -> Self { + Self { + codes: HashMap::from_iter(bytecodes.iter().map(|bytecode| { + let code = Bytecode::from(bytecode.clone()); + (code.hash(), code) + })), + } + } +} + impl IntoIterator for BytecodeCollection { type Item = Bytecode; type IntoIter = std::vec::IntoIter; @@ -144,3 +145,37 @@ impl BytecodeRow { } } } + +#[derive(Clone, Debug)] +pub(crate) struct BytecodeTableAssignment(Vec>); + +impl From for BytecodeTableAssignment { + fn from(collection: BytecodeCollection) -> Self { + let mut rows = Vec::with_capacity(collection.num_rows_required_for_bytecode_table()); + for bytecode in collection.clone().into_iter() { + let code_hash = bytecode.hash(); + let head = BytecodeRow::::head(code_hash, bytecode.codesize()); + rows.push(head); + for (index, &(byte, is_code)) in bytecode.code_vec().iter().enumerate() { + let body = BytecodeRow::::body(code_hash, index, is_code, byte); + rows.push(body); + } + } + Self(rows) + } +} + +impl From>> for BytecodeTableAssignment { + fn from(codes: Vec>) -> Self { + let collections: BytecodeCollection = codes.into(); + collections.into() + } +} + +impl Deref for BytecodeTableAssignment { + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} From d7a961404ce170e0aa4e80f63a5bca9773aac22d Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Tue, 11 Jul 2023 23:13:19 +0800 Subject: [PATCH 08/37] simplify padding row --- .../src/bytecode_circuit/circuit.rs | 39 +++++++------------ zkevm-circuits/src/witness/bytecode.rs | 2 +- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 4c181300d4..89bb372e7f 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -10,7 +10,7 @@ use crate::{ word::{empty_code_hash_word_value, Word, Word32, WordExpr}, Challenges, Expr, SubCircuit, SubCircuitConfig, }, - witness::{self, BytecodeCollection, BytecodeTableAssignment}, + witness::{self, BytecodeTableAssignment}, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; use eth_types::Field; @@ -22,11 +22,10 @@ use halo2_proofs::{ }, poly::Rotation, }; -use itertools::Itertools; use log::trace; use std::vec; -use super::bytecode_unroller::{unroll, UnrolledBytecode}; +use super::bytecode_unroller::UnrolledBytecode; const PUSH_TABLE_WIDTH: usize = 2; @@ -46,6 +45,17 @@ pub struct BytecodeCircuitRow { push_data_size: F, } impl BytecodeCircuitRow { + fn pad(offset: usize, last_row_offset: usize) -> Self { + Self { + offset, + last_row_offset, + code_hash: empty_code_hash_word_value(), + tag: F::from(BytecodeFieldTag::Header as u64), + value_rlc: Value::known(F::ZERO), + ..Default::default() + } + } + /// enable selector if we are within the range of table size. pub fn enable(&self) -> bool { self.offset <= self.last_row_offset @@ -521,7 +531,7 @@ impl BytecodeCircuitConfig { // Padding for idx in offset..=last_row_offset { - self.set_padding_row(&mut region, idx, last_row_offset)?; + self.set_row(&mut region, BytecodeCircuitRow::pad(idx, last_row_offset))?; } // Overwrite the witness assignment by using the values in the `overwrite` @@ -636,32 +646,13 @@ impl BytecodeCircuitConfig { push_data_left = next_push_data_left } if *offset == last_row_offset { - self.set_padding_row(region, *offset, last_row_offset)?; + self.set_row(region, BytecodeCircuitRow::pad(*offset, last_row_offset))?; } } Ok(()) } - fn set_padding_row( - &self, - region: &mut Region<'_, F>, - offset: usize, - last_row_offset: usize, - ) -> Result<(), Error> { - self.set_row( - region, - BytecodeCircuitRow { - offset, - last_row_offset, - code_hash: empty_code_hash_word_value(), - tag: F::from(BytecodeFieldTag::Header as u64), - value_rlc: Value::known(F::ZERO), - ..Default::default() - }, - ) - } - fn set_row(&self, region: &mut Region<'_, F>, row: BytecodeCircuitRow) -> Result<(), Error> { let offset = row.offset; // q_enable diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 2cef8003ab..d80e996c18 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -146,7 +146,7 @@ impl BytecodeRow { } } -#[derive(Clone, Debug)] +#[derive(Clone, Default, Debug)] pub(crate) struct BytecodeTableAssignment(Vec>); impl From for BytecodeTableAssignment { From 95efabe62e4441b605873e34a36701c58d676cc6 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 12 Jul 2023 00:43:46 +0800 Subject: [PATCH 09/37] simplify bytecode assignment --- .../src/bytecode_circuit/circuit.rs | 154 +++++++++--------- 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 89bb372e7f..93e4b04a38 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -6,14 +6,14 @@ use crate::{ }, table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, util::{ - get_push_size, + self, get_push_size, word::{empty_code_hash_word_value, Word, Word32, WordExpr}, Challenges, Expr, SubCircuit, SubCircuitConfig, }, - witness::{self, BytecodeTableAssignment}, + witness::{self, BytecodeCollection}, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; -use eth_types::Field; +use eth_types::{Bytecode, Field}; use gadgets::is_zero::{IsZeroChip, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region, Value}, @@ -495,7 +495,7 @@ impl BytecodeCircuitConfig { &self, layouter: &mut impl Layouter, size: usize, - witness: &BytecodeTableAssignment, + witness: &BytecodeCollection, overwrite: &UnrolledBytecode, challenges: &Challenges>, fail_fast: bool, @@ -518,10 +518,10 @@ impl BytecodeCircuitConfig { self.annotate_circuit(&mut region); let mut offset = 0; - for bytecode in witness.iter() { + for bytecode in witness.clone().into_iter() { self.assign_bytecode( &mut region, - bytecode, + &bytecode, challenges, &mut offset, last_row_offset, @@ -531,7 +531,7 @@ impl BytecodeCircuitConfig { // Padding for idx in offset..=last_row_offset { - self.set_row(&mut region, BytecodeCircuitRow::pad(idx, last_row_offset))?; + self.set_row(&mut region, &BytecodeCircuitRow::pad(idx, last_row_offset))?; } // Overwrite the witness assignment by using the values in the `overwrite` @@ -579,81 +579,87 @@ impl BytecodeCircuitConfig { fn assign_bytecode( &self, region: &mut Region<'_, F>, - bytecode: &UnrolledBytecode, + bytecode: &Bytecode, challenges: &Challenges>, offset: &mut usize, last_row_offset: usize, fail_fast: bool, ) -> Result<(), Error> { - // Run over all the bytes + let code_size = bytecode.codesize(); + if fail_fast && *offset + code_size + 1 > last_row_offset { + log::error!( + "Bytecode Circuit: offset={} + (code_size+1)={} > last_row_offset={}", + offset, + code_size + 1, + last_row_offset + ); + return Err(Error::Synthesis); + } + let code_hash = util::word::Word::from(bytecode.hash()).into_value(); + // set Header + let header = BytecodeCircuitRow { + offset: *offset, + last_row_offset, + code_hash, + tag: F::from(BytecodeFieldTag::Header as u64), + index: F::ZERO, + is_code: F::ZERO, + value: F::from(code_size as u64), + push_data_left: 0, + value_rlc: Value::known(F::ZERO), + length: F::from(code_size as u64), + push_data_size: F::ZERO, + }; + self.set_row(region, &header)?; + *offset += 1; + + // set body let mut push_data_left = 0; - let mut next_push_data_left = 0; - let mut push_data_size = 0; - let mut value_rlc = challenges.keccak_input().map(|_| F::ZERO); - let length = F::from(bytecode.bytes.len() as u64); - - let code_hash = Word::from(bytecode.rows[0].code_hash).into_value(); - - for (idx, row) in bytecode.rows.iter().enumerate() { - if fail_fast && *offset > last_row_offset { - log::error!( - "Bytecode Circuit: offset={} > last_row_offset={}", - offset, - last_row_offset - ); - return Err(Error::Synthesis); - } - - // Track which byte is an opcode and which is push - // data - if idx > 0 { - let is_code = push_data_left == 0; - - push_data_size = get_push_size(row.value.get_lower_128() as u8); - - next_push_data_left = if is_code { - push_data_size - } else { - push_data_left - 1 - }; - - value_rlc - .as_mut() - .zip(challenges.keccak_input()) - .map(|(value_rlc, challenge)| *value_rlc = *value_rlc * challenge + row.value); - } - - // Set the data for this row - if *offset < last_row_offset { - let row = BytecodeCircuitRow { - offset: *offset, - last_row_offset, - code_hash, - tag: row.tag, - index: row.index, - is_code: row.is_code, - value: row.value, - push_data_left, - value_rlc, - length, - push_data_size: F::from(push_data_size), - }; - self.set_row(region, row.clone())?; - - trace!("bytecode.set_row({:?})", row); - - *offset += 1; - push_data_left = next_push_data_left - } - if *offset == last_row_offset { - self.set_row(region, BytecodeCircuitRow::pad(*offset, last_row_offset))?; - } + let mut value_rlc = Value::known(F::ZERO); + + for (index, &(value, is_code)) in bytecode.code_vec().iter().enumerate() { + let push_data_size = get_push_size(value); + let value = F::from(value.into()); + + push_data_left = if is_code { + push_data_size + } else { + push_data_left - 1 + }; + + value_rlc + .as_mut() + .zip(challenges.keccak_input()) + .map(|(value_rlc, challenge)| *value_rlc = *value_rlc * challenge + value); + + let body = BytecodeCircuitRow { + offset: *offset, + last_row_offset, + code_hash, + tag: F::from(BytecodeFieldTag::Byte as u64), + index: F::from(index as u64), + is_code: F::from(is_code.into()), + value, + push_data_left, + value_rlc, + length: F::from(code_size as u64), + push_data_size: F::from(push_data_size), + }; + self.set_row(region, &body)?; + + trace!("bytecode.set_row({:?})", body); + + *offset += 1; } Ok(()) } - fn set_row(&self, region: &mut Region<'_, F>, row: BytecodeCircuitRow) -> Result<(), Error> { + fn set_row( + &self, + region: &mut Region<'_, F>, + row: &BytecodeCircuitRow, + ) -> Result<(), Error> { let offset = row.offset; // q_enable region.assign_fixed( @@ -779,7 +785,7 @@ impl BytecodeCircuitConfig { #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { /// Unrolled bytecodes - pub bytecodes: BytecodeTableAssignment, + pub bytecodes: BytecodeCollection, /// Circuit size pub size: usize, /// Overwrite @@ -788,7 +794,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester - pub fn new(bytecodes: &BytecodeTableAssignment, size: usize) -> Self { + pub fn new(bytecodes: &BytecodeCollection, size: usize) -> Self { Self { bytecodes: bytecodes.clone(), size, @@ -798,7 +804,7 @@ impl BytecodeCircuit { /// Creates bytecode circuit from block and bytecode_size. pub fn new_from_block_sized(block: &witness::Block, bytecode_size: usize) -> Self { - Self::new(&block.bytecodes.into(), bytecode_size) + Self::new(&block.bytecodes, bytecode_size) } } From 58e81de23ac79a744e80549ac04f8ba0a0b48412 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 12 Jul 2023 02:15:01 +0800 Subject: [PATCH 10/37] WIP in the middle of no where --- .../src/bytecode_circuit/circuit.rs | 250 +++++++----------- zkevm-circuits/src/bytecode_circuit/test.rs | 107 ++++---- zkevm-circuits/src/witness.rs | 2 +- zkevm-circuits/src/witness/bytecode.rs | 36 +-- 4 files changed, 155 insertions(+), 240 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 93e4b04a38..d72ce18892 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -13,7 +13,7 @@ use crate::{ witness::{self, BytecodeCollection}, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; -use eth_types::{Bytecode, Field}; +use eth_types::Field; use gadgets::is_zero::{IsZeroChip, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region, Value}, @@ -23,22 +23,20 @@ use halo2_proofs::{ poly::Rotation, }; use log::trace; -use std::vec; - -use super::bytecode_unroller::UnrolledBytecode; +use std::{ops::Deref, vec}; const PUSH_TABLE_WIDTH: usize = 2; #[derive(Debug, Clone, Default)] /// Row for assignment -pub struct BytecodeCircuitRow { +pub(crate) struct BytecodeCircuitRow { offset: usize, last_row_offset: usize, - code_hash: Word>, + pub(crate) code_hash: Word>, tag: F, - index: F, - is_code: F, - value: F, + pub(crate) index: F, + pub(crate) is_code: F, + pub(crate) value: F, push_data_left: u64, value_rlc: Value, length: F, @@ -77,6 +75,79 @@ impl BytecodeCircuitRow { } } +#[derive(Clone, Default, Debug)] +pub(crate) struct BytecodeTableAssignment(pub(crate) Vec>); + +impl From for BytecodeTableAssignment { + fn from(collection: BytecodeCollection) -> Self { + let mut offset = 0; + let mut rows = Vec::with_capacity(collection.num_rows_required_for_bytecode_table()); + for bytecode in collection.into_iter() { + let code_hash = util::word::Word::from(bytecode.hash()).into_value(); + let code_size = bytecode.codesize(); + let head = BytecodeCircuitRow { + offset, + last_row_offset: 0, + code_hash, + tag: F::from(BytecodeFieldTag::Header as u64), + index: F::ZERO, + is_code: F::ZERO, + value: F::from(code_size as u64), + push_data_left: 0, + value_rlc: Value::known(F::ZERO), + length: F::from(code_size as u64), + push_data_size: F::ZERO, + }; + rows.push(head); + offset += 1; + let mut push_data_left = 0; + + for (index, &(value, is_code)) in bytecode.code_vec().iter().enumerate() { + let push_data_size = get_push_size(value); + let value = F::from(value.into()); + + push_data_left = if is_code { + push_data_size + } else { + push_data_left - 1 + }; + + let body = BytecodeCircuitRow { + offset, + last_row_offset: 0, + code_hash, + tag: F::from(BytecodeFieldTag::Byte as u64), + index: F::from(index as u64), + is_code: F::from(is_code.into()), + value, + push_data_left, + value_rlc: Value::unknown(), + length: F::from(code_size as u64), + push_data_size: F::from(push_data_size), + }; + rows.push(body); + offset += 1; + } + } + Self(rows) + } +} + +impl From>> for BytecodeTableAssignment { + fn from(codes: Vec>) -> Self { + let collections: BytecodeCollection = codes.into(); + collections.into() + } +} + +impl Deref for BytecodeTableAssignment { + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + #[derive(Clone, Debug)] /// Bytecode circuit configuration pub struct BytecodeCircuitConfig { @@ -495,10 +566,8 @@ impl BytecodeCircuitConfig { &self, layouter: &mut impl Layouter, size: usize, - witness: &BytecodeCollection, - overwrite: &UnrolledBytecode, + witness: &BytecodeTableAssignment, challenges: &Challenges>, - fail_fast: bool, ) -> Result<(), Error> { // Subtract the unusable rows from the size assert!(size > self.minimum_rows); @@ -510,6 +579,7 @@ impl BytecodeCircuitConfig { self.minimum_rows, last_row_offset ); + assert!(witness.len() < last_row_offset); layouter.assign_region( || "assign bytecode", @@ -517,144 +587,31 @@ impl BytecodeCircuitConfig { // annotate columns self.annotate_circuit(&mut region); - let mut offset = 0; - for bytecode in witness.clone().into_iter() { - self.assign_bytecode( - &mut region, - &bytecode, - challenges, - &mut offset, - last_row_offset, - fail_fast, - )?; - } - - // Padding - for idx in offset..=last_row_offset { - self.set_row(&mut region, &BytecodeCircuitRow::pad(idx, last_row_offset))?; - } - - // Overwrite the witness assignment by using the values in the `overwrite` - // parameter. This is used to explicitly set intermediate witness values for - // negative tests. - let mut value_rlc = challenges.keccak_input().map(|_| F::ZERO); - for (offset, row) in overwrite.rows.iter().enumerate() { - for (name, column, value) in [ - ("tag", self.bytecode_table.tag, row.tag), - ("index", self.bytecode_table.index, row.index), - ("is_code", self.bytecode_table.is_code, row.is_code), - ("value", self.bytecode_table.value, row.value), - ("length", self.length, F::from(overwrite.bytes.len() as u64)), - ] { - region.assign_advice( - || format!("assign {} {}", name, offset), - column, - offset, - || Value::known(value), - )?; - } - - if row.tag == F::ONE { + let mut value_rlc = Value::known(F::ZERO); + for row in witness.iter() { + let mut row = row.clone(); + if row.tag == F::from(BytecodeFieldTag::Byte as u64) { value_rlc.as_mut().zip(challenges.keccak_input()).map( |(value_rlc, challenge)| { *value_rlc = *value_rlc * challenge + row.value }, ); } else { - value_rlc = challenges.keccak_input().map(|_| F::ZERO); + value_rlc = Value::known(F::ZERO); } + row.value_rlc = value_rlc; + self.set_row(&mut region, &row)?; + } - region.assign_advice( - || format!("assign value_rlc {}", offset), - self.value_rlc, - offset, - || value_rlc, - )?; + // Padding + for idx in witness.len()..=last_row_offset { + self.set_row(&mut region, &BytecodeCircuitRow::pad(idx, last_row_offset))?; } Ok(()) }, ) } - fn assign_bytecode( - &self, - region: &mut Region<'_, F>, - bytecode: &Bytecode, - challenges: &Challenges>, - offset: &mut usize, - last_row_offset: usize, - fail_fast: bool, - ) -> Result<(), Error> { - let code_size = bytecode.codesize(); - if fail_fast && *offset + code_size + 1 > last_row_offset { - log::error!( - "Bytecode Circuit: offset={} + (code_size+1)={} > last_row_offset={}", - offset, - code_size + 1, - last_row_offset - ); - return Err(Error::Synthesis); - } - let code_hash = util::word::Word::from(bytecode.hash()).into_value(); - // set Header - let header = BytecodeCircuitRow { - offset: *offset, - last_row_offset, - code_hash, - tag: F::from(BytecodeFieldTag::Header as u64), - index: F::ZERO, - is_code: F::ZERO, - value: F::from(code_size as u64), - push_data_left: 0, - value_rlc: Value::known(F::ZERO), - length: F::from(code_size as u64), - push_data_size: F::ZERO, - }; - self.set_row(region, &header)?; - *offset += 1; - - // set body - let mut push_data_left = 0; - let mut value_rlc = Value::known(F::ZERO); - - for (index, &(value, is_code)) in bytecode.code_vec().iter().enumerate() { - let push_data_size = get_push_size(value); - let value = F::from(value.into()); - - push_data_left = if is_code { - push_data_size - } else { - push_data_left - 1 - }; - - value_rlc - .as_mut() - .zip(challenges.keccak_input()) - .map(|(value_rlc, challenge)| *value_rlc = *value_rlc * challenge + value); - - let body = BytecodeCircuitRow { - offset: *offset, - last_row_offset, - code_hash, - tag: F::from(BytecodeFieldTag::Byte as u64), - index: F::from(index as u64), - is_code: F::from(is_code.into()), - value, - push_data_left, - value_rlc, - length: F::from(code_size as u64), - push_data_size: F::from(push_data_size), - }; - self.set_row(region, &body)?; - - trace!("bytecode.set_row({:?})", body); - - *offset += 1; - } - - Ok(()) - } - fn set_row( &self, region: &mut Region<'_, F>, @@ -785,27 +742,19 @@ impl BytecodeCircuitConfig { #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { /// Unrolled bytecodes - pub bytecodes: BytecodeCollection, + pub bytecodes: BytecodeTableAssignment, /// Circuit size pub size: usize, - /// Overwrite - pub overwrite: UnrolledBytecode, } impl BytecodeCircuit { /// new BytecodeCircuitTester - pub fn new(bytecodes: &BytecodeCollection, size: usize) -> Self { + pub fn new(bytecodes: &impl Into>, size: usize) -> Self { Self { - bytecodes: bytecodes.clone(), + bytecodes: (*bytecodes).into(), size, - overwrite: Default::default(), } } - - /// Creates bytecode circuit from block and bytecode_size. - pub fn new_from_block_sized(block: &witness::Block, bytecode_size: usize) -> Self { - Self::new(&block.bytecodes, bytecode_size) - } } impl SubCircuit for BytecodeCircuit { @@ -818,8 +767,7 @@ impl SubCircuit for BytecodeCircuit { } fn new_from_block(block: &witness::Block) -> Self { - let bytecode_size = block.circuits_params.max_bytecode; - Self::new_from_block_sized(block, bytecode_size) + Self::new(&block.bytecodes, block.circuits_params.max_bytecode) } /// Return the minimum number of rows required to prove the block @@ -841,10 +789,8 @@ impl SubCircuit for BytecodeCircuit { config.assign_internal( layouter, self.size, - &self.bytecodes, - &self.overwrite, + &(self.bytecodes.clone().into()), challenges, - false, ) } } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 2415bc8606..4892925fae 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -1,8 +1,11 @@ use crate::{ - bytecode_circuit::{bytecode_unroller::*, circuit::BytecodeCircuit}, + bytecode_circuit::{ + bytecode_unroller::*, + circuit::{BytecodeCircuit, BytecodeTableAssignment}, + }, table::BytecodeFieldTag, util::{is_push, unusable_rows, SubCircuit}, - witness::{BytecodeCollection, BytecodeTableAssignment}, + witness::BytecodeCollection, }; use bus_mapping::evm::OpcodeId; use eth_types::{Bytecode, Field, Word}; @@ -95,7 +98,7 @@ fn bytecode_unrolling() { } } // Set the code_hash of the complete bytecode in the rows - let code_hash: eth_types::U256 = bytecode.hash(); + let code_hash = bytecode.hash(); for row in rows.iter_mut() { row.code_hash = code_hash; } @@ -120,42 +123,42 @@ fn bytecode_unrolling() { unrolled, ); // Verify the unrolling in the circuit - test_bytecode_circuit_unrolled::(k, vec![unrolled], true); + test_bytecode_circuit_unrolled::(k, &vec![bytecode.code()], true); } /// Tests a fully empty circuit #[test] fn bytecode_empty() { let k = 9; - test_bytecode_circuit_unrolled::(k, vec![vec![]], true); + test_bytecode_circuit_unrolled::(k, &vec![vec![]], true); } #[test] fn bytecode_simple() { let k = 9; let bytecodes = vec![vec![7u8], vec![6u8], vec![5u8]]; - test_bytecode_circuit_unrolled::(k, bytecodes, true); + test_bytecode_circuit_unrolled::(k, &bytecodes, true); } /// Tests a fully full circuit #[test] fn bytecode_full() { let k = 9; - test_bytecode_circuit_unrolled::(k, vec![vec![7u8; 2usize.pow(k) - 8]], true); + test_bytecode_circuit_unrolled::(k, &vec![vec![7u8; 2usize.pow(k) - 8]], true); } #[test] fn bytecode_last_row_with_byte() { let k = 9; // Last row must be a padding row, so we have one row less for actual bytecode - test_bytecode_circuit_unrolled::(k, vec![vec![7u8; 2usize.pow(k) - 7]], false); + test_bytecode_circuit_unrolled::(k, &vec![vec![7u8; 2usize.pow(k) - 7]], false); } /// Tests a circuit with incomplete bytecode #[test] fn bytecode_incomplete() { let k = 9; - test_bytecode_circuit_unrolled::(k, vec![vec![7u8; 2usize.pow(k) + 1]], false); + test_bytecode_circuit_unrolled::(k, &vec![vec![7u8; 2usize.pow(k) + 1]], false); } /// Tests multiple bytecodes in a single circuit @@ -164,7 +167,7 @@ fn bytecode_push() { let k = 9; test_bytecode_circuit_unrolled::( k, - vec![ + &vec![ vec![], vec![OpcodeId::PUSH32.as_u8()], vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()], @@ -183,14 +186,17 @@ fn bytecode_push() { #[test] fn bytecode_invalid_hash_data() { let k = 9; - let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - test_bytecode_circuit_unrolled::(k, vec![bytecode.clone()], true); + let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; + test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Change the code_hash on the first position (header row) { - let mut invalid = bytecode; - invalid.rows[0].code_hash += Word::one(); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + let code_hash = invalid.0[0].code_hash; + // Add 1 to both limbs + invalid.0[0].code_hash = code_hash.map(|limb| limb.map(|limb| limb + Fr::one())); + log::trace!("bytecode_invalid_hash_data: Change the code_hash on the first position"); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + test_bytecode_circuit_unrolled::(k, &invalid, false); } // TODO: other rows code_hash are ignored by the witness generation, to // test other rows invalid code_hash, we would need to inject an evil @@ -202,22 +208,21 @@ fn bytecode_invalid_hash_data() { #[ignore] fn bytecode_invalid_index() { let k = 9; - let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; + test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Start the index at 1 { - let mut invalid = unrolled.clone(); - for row in invalid.rows.iter_mut() { + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + for row in invalid.0.iter_mut() { row.index += Fr::ONE; } - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + test_bytecode_circuit_unrolled::(k, &invalid, false); } // Don't increment an index once { - let mut invalid = unrolled; - invalid.rows.last_mut().unwrap().index -= Fr::ONE; - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0.last_mut().unwrap().index -= Fr::ONE; + test_bytecode_circuit_unrolled::(k, &invalid, false); } } @@ -225,26 +230,25 @@ fn bytecode_invalid_index() { #[test] fn bytecode_invalid_byte_data() { let k = 9; - let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; + test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Change the first byte { - let mut invalid = unrolled.clone(); - invalid.rows[1].value = Fr::from(9u64); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0[1].value = Fr::from(9u64); + test_bytecode_circuit_unrolled::(k, &invalid, false); } // Change a byte on another position { - let mut invalid = unrolled.clone(); - invalid.rows[5].value = Fr::from(6u64); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0[5].value = Fr::from(6u64); + test_bytecode_circuit_unrolled::(k, &invalid, false); } // Set a byte value out of range { - let mut invalid = unrolled; - invalid.rows[3].value = Fr::from(256u64); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0[3].value = Fr::from(256u64); + test_bytecode_circuit_unrolled::(k, &invalid, false); } } @@ -252,7 +256,7 @@ fn bytecode_invalid_byte_data() { #[test] fn bytecode_invalid_is_code() { let k = 9; - let bytecode = vec![ + let bytecodes = vec![vec![ OpcodeId::ADD.as_u8(), OpcodeId::PUSH1.as_u8(), OpcodeId::PUSH1.as_u8(), @@ -260,26 +264,25 @@ fn bytecode_invalid_is_code() { OpcodeId::PUSH7.as_u8(), OpcodeId::ADD.as_u8(), OpcodeId::PUSH6.as_u8(), - ]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + ]]; + test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Mark the 3rd byte as code (is push data from the first PUSH1) { - let mut invalid = unrolled.clone(); - invalid.rows[3].is_code = Fr::ONE; - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0[3].is_code = Fr::ONE; + test_bytecode_circuit_unrolled::(k, &invalid, false); } // Mark the 4rd byte as data (is code) { - let mut invalid = unrolled.clone(); - invalid.rows[4].is_code = Fr::ZERO; - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0[4].is_code = Fr::ZERO; + test_bytecode_circuit_unrolled::(k, &invalid, false); } // Mark the 7th byte as code (is data for the PUSH7) { - let mut invalid = unrolled; - invalid.rows[7].is_code = Fr::ONE; - test_bytecode_circuit_unrolled::(k, vec![invalid], false); + let mut invalid: BytecodeTableAssignment = bytecodes.into(); + invalid.0[7].is_code = Fr::ONE; + test_bytecode_circuit_unrolled::(k, &invalid, false); } } @@ -290,9 +293,9 @@ fn bytecode_soundness_bug_1() { let k = 9; let bytecode = vec![1, 2, 3, 4]; let bytecode_len = bytecode.len(); - let unrolled = unroll(bytecode); - let unrolled_len = unrolled.rows.len(); - let code_hash = unrolled.rows[0].code_hash.clone(); + let unrolled: BytecodeTableAssignment = vec![bytecode].into(); + let unrolled_len = unrolled.0.len(); + let code_hash = unrolled.0[0].code_hash.clone(); let mut index = bytecode_len as u64; let size = 100; let minimum_rows = 8; diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 84e3b4eacb..04ddbfb40a 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -5,8 +5,8 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; +pub(crate) use bytecode::BytecodeRow; pub use bytecode::{BytecodeCollection, BytecodeUnroller as Bytecode}; -pub(crate) use bytecode::{BytecodeRow, BytecodeTableAssignment}; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index d80e996c18..36391577cf 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -2,7 +2,7 @@ use crate::{table::BytecodeFieldTag, util}; use bus_mapping::state_db::CodeDB; use eth_types::{Bytecode, Field, Word}; use itertools::Itertools; -use std::{collections::HashMap, ops::Deref}; +use std::collections::HashMap; /// A collection of bytecode to prove #[derive(Clone, Debug, Default)] @@ -145,37 +145,3 @@ impl BytecodeRow { } } } - -#[derive(Clone, Default, Debug)] -pub(crate) struct BytecodeTableAssignment(Vec>); - -impl From for BytecodeTableAssignment { - fn from(collection: BytecodeCollection) -> Self { - let mut rows = Vec::with_capacity(collection.num_rows_required_for_bytecode_table()); - for bytecode in collection.clone().into_iter() { - let code_hash = bytecode.hash(); - let head = BytecodeRow::::head(code_hash, bytecode.codesize()); - rows.push(head); - for (index, &(byte, is_code)) in bytecode.code_vec().iter().enumerate() { - let body = BytecodeRow::::body(code_hash, index, is_code, byte); - rows.push(body); - } - } - Self(rows) - } -} - -impl From>> for BytecodeTableAssignment { - fn from(codes: Vec>) -> Self { - let collections: BytecodeCollection = codes.into(); - collections.into() - } -} - -impl Deref for BytecodeTableAssignment { - type Target = Vec>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} From 6d863a02a132de1a163bf3e29ae1ab552bed80ec Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 12 Jul 2023 15:38:25 +0800 Subject: [PATCH 11/37] getting somewhere --- .../src/bytecode_circuit/circuit.rs | 41 +++++-- zkevm-circuits/src/bytecode_circuit/dev.rs | 2 +- zkevm-circuits/src/bytecode_circuit/test.rs | 111 +++--------------- zkevm-circuits/src/evm_circuit.rs | 4 +- .../src/evm_circuit/execution/callop.rs | 7 +- 5 files changed, 51 insertions(+), 114 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index d72ce18892..09eb160828 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -43,6 +43,30 @@ pub(crate) struct BytecodeCircuitRow { push_data_size: F, } impl BytecodeCircuitRow { + #[cfg(test)] + pub(crate) fn new( + offset: usize, + code_hash: Word>, + tag: F, + index: F, + is_code: F, + value: F, + ) -> Self { + Self { + offset, + last_row_offset: 0, + code_hash, + tag, + index, + is_code, + value, + push_data_left: 0, + value_rlc: Value::known(F::ZERO), + length: F::ZERO, + push_data_size: F::ZERO, + } + } + fn pad(offset: usize, last_row_offset: usize) -> Self { Self { offset, @@ -64,11 +88,6 @@ impl BytecodeCircuitRow { self.offset == self.last_row_offset } - /// Get offset - pub fn offset(&self) -> usize { - self.offset - } - /// Witness to IsZero chip to determine if we are at the last row of a bytecode instance pub fn diff(&self) -> F { self.index + F::ONE - self.length @@ -742,18 +761,16 @@ impl BytecodeCircuitConfig { #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { /// Unrolled bytecodes - pub bytecodes: BytecodeTableAssignment, + pub(crate) bytecodes: BytecodeTableAssignment, /// Circuit size pub size: usize, } impl BytecodeCircuit { /// new BytecodeCircuitTester - pub fn new(bytecodes: &impl Into>, size: usize) -> Self { - Self { - bytecodes: (*bytecodes).into(), - size, - } + pub(crate) fn new(bytecodes: impl Into>, size: usize) -> Self { + let bytecodes = bytecodes.into(); + Self { bytecodes, size } } } @@ -767,7 +784,7 @@ impl SubCircuit for BytecodeCircuit { } fn new_from_block(block: &witness::Block) -> Self { - Self::new(&block.bytecodes, block.circuits_params.max_bytecode) + Self::new(block.bytecodes.clone(), block.circuits_params.max_bytecode) } /// Return the minimum number of rows required to prove the block diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index 9810a07873..48b65651cd 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -49,7 +49,7 @@ impl Circuit for BytecodeCircuit { config .keccak_table - .dev_load(&mut layouter, &self.bytecodes.to_raw(), &challenges)?; + .dev_load(&mut layouter, &self.bytecodes.iter(), &challenges)?; self.synthesize_sub(&config, &challenges, &mut layouter)?; Ok(()) } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 4892925fae..5f03f6d115 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -1,17 +1,14 @@ use crate::{ - bytecode_circuit::{ - bytecode_unroller::*, - circuit::{BytecodeCircuit, BytecodeTableAssignment}, - }, - table::BytecodeFieldTag, - util::{is_push, unusable_rows, SubCircuit}, - witness::BytecodeCollection, + bytecode_circuit::circuit::{BytecodeCircuit, BytecodeTableAssignment}, + util::{unusable_rows, SubCircuit}, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Bytecode, Field, Word}; +use eth_types::Field; use halo2_proofs::{arithmetic::Field as Halo2Field, dev::MockProver, halo2curves::bn256::Fr}; use log::error; +use super::circuit::BytecodeCircuitRow; + #[test] fn bytecode_circuit_unusable_rows() { assert_eq!( @@ -21,7 +18,7 @@ fn bytecode_circuit_unusable_rows() { } impl BytecodeCircuit { - pub(crate) fn verify(k: u32, bytecodes: &impl Into>, success: bool) { + pub(crate) fn verify(k: u32, bytecodes: impl Into>, success: bool) { let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); @@ -41,7 +38,7 @@ pub fn test_bytecode_circuit_unrolled( bytecodes: &impl Into>, success: bool, ) { - let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); + let circuit = BytecodeCircuit::::new(*bytecodes, 2usize.pow(k)); let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); let result = prover.verify_par(); @@ -54,78 +51,6 @@ pub fn test_bytecode_circuit_unrolled( assert_eq!(result.is_ok(), success, "proof must be {}", error_msg); } -/// Verify unrolling code -#[test] -fn bytecode_unrolling() { - let k = 10; - let mut rows = vec![]; - let mut bytecode = Bytecode::default(); - // First add all non-push bytes, which should all be seen as code - for byte in 0u8..=255u8 { - if !is_push(byte) { - bytecode.write(byte, true); - rows.push(BytecodeRow { - code_hash: Word::zero(), - tag: Fr::from(BytecodeFieldTag::Byte as u64), - index: Fr::from(rows.len() as u64), - is_code: Fr::from(true as u64), - value: Fr::from(byte as u64), - }); - } - } - // Now add the different push ops - for n in 1..=32 { - let data_byte = OpcodeId::PUSH32.as_u8(); - bytecode.push( - n, - Word::from_little_endian(&vec![data_byte; n as usize][..]), - ); - rows.push(BytecodeRow { - code_hash: Word::zero(), - tag: Fr::from(BytecodeFieldTag::Byte as u64), - index: Fr::from(rows.len() as u64), - is_code: Fr::from(true as u64), - value: Fr::from(OpcodeId::PUSH1.as_u64() + ((n - 1) as u64)), - }); - for _ in 0..n { - rows.push(BytecodeRow { - code_hash: Word::zero(), - tag: Fr::from(BytecodeFieldTag::Byte as u64), - index: Fr::from(rows.len() as u64), - is_code: Fr::from(false as u64), - value: Fr::from(data_byte as u64), - }); - } - } - // Set the code_hash of the complete bytecode in the rows - let code_hash = bytecode.hash(); - for row in rows.iter_mut() { - row.code_hash = code_hash; - } - rows.insert( - 0, - BytecodeRow { - code_hash, - tag: Fr::from(BytecodeFieldTag::Header as u64), - index: Fr::ZERO, - is_code: Fr::ZERO, - value: Fr::from(bytecode.codesize() as u64), - }, - ); - // Unroll the bytecode - let unrolled = unroll(bytecode.code()); - // Check if the bytecode was unrolled correctly - assert_eq!( - UnrolledBytecode { - bytes: bytecode.code(), - rows, - }, - unrolled, - ); - // Verify the unrolling in the circuit - test_bytecode_circuit_unrolled::(k, &vec![bytecode.code()], true); -} - /// Tests a fully empty circuit #[test] fn bytecode_empty() { @@ -300,22 +225,22 @@ fn bytecode_soundness_bug_1() { let size = 100; let minimum_rows = 8; - let mut overwrite = unrolled.clone(); + let mut overwrite = unrolled.0.clone(); for i in 0..size - minimum_rows + 3 { if i >= unrolled_len { - overwrite.rows.push(BytecodeRow { - code_hash: code_hash.clone(), - tag: Fr::ONE, - index: Fr::from(index), - is_code: Fr::ONE, - value: Fr::from((i % 10 + 1) as u64), - }); + overwrite.push(BytecodeCircuitRow::new( + i, + code_hash.clone(), + Fr::ONE, + Fr::from(index), + Fr::ONE, + Fr::from((i % 10 + 1) as u64), + )); index += 1; } } - let mut circuit = BytecodeCircuit::::new(vec![unrolled], size); - circuit.overwrite = overwrite; - + let overwrite = BytecodeTableAssignment { 0: overwrite }; + let mut circuit = BytecodeCircuit::::new(overwrite, size); let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); prover.assert_satisfied_par(); } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 7c5edf8b53..e330550eb7 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -183,7 +183,7 @@ impl EvmCircuit { fixed_table_tags: FixedTableTag::iter().collect(), } } - #[cfg(feature = "test-circuits")] + #[cfg(any(test, feature = "test-circuits"))] /// Construct the EvmCircuit with only subset of Fixed table tags required by tests to save /// testing time pub(crate) fn get_test_circuit_from_block(block: Block) -> Self { @@ -193,7 +193,7 @@ impl EvmCircuit { fixed_table_tags, } } - #[cfg(feature = "test-circuits")] + #[cfg(any(test, feature = "test-circuits"))] /// Calculate which rows are "actually" used in the circuit pub(crate) fn get_active_rows(block: &Block) -> (Vec, Vec) { let max_offset = Self::get_num_rows_required(block); diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 8f52711a60..2c6b176745 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -844,12 +844,7 @@ mod test { .write_op(terminator) }); - Account { - address: Address::repeat_byte(0xfe), - balance: Word::from(10).pow(18.into()), - code: bytecode.to_vec().into(), - ..Default::default() - } + Account::mock_100_ether(bytecode) } fn test_nested(opcode: &OpcodeId) { From ee348cbd612e7f8917c2a14e617f8e0fb4e7a2a2 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 12 Jul 2023 17:11:51 +0800 Subject: [PATCH 12/37] testing style --- .../src/bytecode_circuit/circuit.rs | 27 ++- zkevm-circuits/src/bytecode_circuit/dev.rs | 2 +- zkevm-circuits/src/bytecode_circuit/test.rs | 203 +++++++++--------- 3 files changed, 118 insertions(+), 114 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 09eb160828..cfb25bd41e 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -598,7 +598,12 @@ impl BytecodeCircuitConfig { self.minimum_rows, last_row_offset ); - assert!(witness.len() < last_row_offset); + assert!( + witness.len() <= last_row_offset + 1, + "the witness has size {}, but last_row_offset + 1 is {}", + witness.len(), + last_row_offset + 1 + ); layouter.assign_region( || "assign bytecode", @@ -760,17 +765,22 @@ impl BytecodeCircuitConfig { /// BytecodeCircuit #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { + pub(crate) bytecodes: BytecodeCollection, /// Unrolled bytecodes - pub(crate) bytecodes: BytecodeTableAssignment, + pub(crate) rows: BytecodeTableAssignment, /// Circuit size pub size: usize, } impl BytecodeCircuit { /// new BytecodeCircuitTester - pub(crate) fn new(bytecodes: impl Into>, size: usize) -> Self { - let bytecodes = bytecodes.into(); - Self { bytecodes, size } + pub(crate) fn new(bytecodes: BytecodeCollection, size: usize) -> Self { + let rows = bytecodes.clone().into(); + Self { + bytecodes, + rows, + size, + } } } @@ -803,11 +813,6 @@ impl SubCircuit for BytecodeCircuit { layouter: &mut impl Layouter, ) -> Result<(), Error> { config.load_aux_tables(layouter)?; - config.assign_internal( - layouter, - self.size, - &(self.bytecodes.clone().into()), - challenges, - ) + config.assign_internal(layouter, self.size, &self.rows, challenges) } } diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index 48b65651cd..9810a07873 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -49,7 +49,7 @@ impl Circuit for BytecodeCircuit { config .keccak_table - .dev_load(&mut layouter, &self.bytecodes.iter(), &challenges)?; + .dev_load(&mut layouter, &self.bytecodes.to_raw(), &challenges)?; self.synthesize_sub(&config, &challenges, &mut layouter)?; Ok(()) } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 5f03f6d115..07ff091601 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -1,6 +1,7 @@ use crate::{ - bytecode_circuit::circuit::{BytecodeCircuit, BytecodeTableAssignment}, - util::{unusable_rows, SubCircuit}, + bytecode_circuit::circuit::BytecodeCircuit, + util::{log2_ceil, unusable_rows, SubCircuit}, + witness::BytecodeCollection, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -18,81 +19,69 @@ fn bytecode_circuit_unusable_rows() { } impl BytecodeCircuit { - pub(crate) fn verify(k: u32, bytecodes: impl Into>, success: bool) { - let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); + fn mut_rows(&mut self, mut mut_func: impl FnMut(&mut Vec>)) -> Self { + mut_func(&mut self.rows.0); + self.clone() + } + + fn from_bytes(bytecodes: impl Into, k: u32) -> Self { + Self::new(bytecodes.into(), 2usize.pow(k)) + } - let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); - let result = prover.verify(); + fn verify(&self, success: bool) { + let prover = MockProver::::run(log2_ceil(self.size), self, Vec::new()).unwrap(); + let result = prover.verify_par(); if let Err(failures) = &result { for failure in failures.iter() { error!("{}", failure); } } - assert_eq!(result.is_ok(), success); - } -} - -/// Test bytecode circuit with unrolled bytecode -pub fn test_bytecode_circuit_unrolled( - k: u32, - bytecodes: &impl Into>, - success: bool, -) { - let circuit = BytecodeCircuit::::new(*bytecodes, 2usize.pow(k)); - - let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); - let result = prover.verify_par(); - if let Err(failures) = &result { - for failure in failures.iter() { - error!("{}", failure); - } + let error_msg = if success { "valid" } else { "invalid" }; + assert_eq!(result.is_ok(), success, "proof must be {}", error_msg); } - let error_msg = if success { "valid" } else { "invalid" }; - assert_eq!(result.is_ok(), success, "proof must be {}", error_msg); } /// Tests a fully empty circuit #[test] fn bytecode_empty() { let k = 9; - test_bytecode_circuit_unrolled::(k, &vec![vec![]], true); + BytecodeCircuit::::from_bytes(vec![vec![]], k).verify(true); } #[test] fn bytecode_simple() { let k = 9; let bytecodes = vec![vec![7u8], vec![6u8], vec![5u8]]; - test_bytecode_circuit_unrolled::(k, &bytecodes, true); + BytecodeCircuit::::from_bytes(bytecodes, k).verify(true); } /// Tests a fully full circuit #[test] fn bytecode_full() { let k = 9; - test_bytecode_circuit_unrolled::(k, &vec![vec![7u8; 2usize.pow(k) - 8]], true); + BytecodeCircuit::::from_bytes(vec![vec![7u8; 2usize.pow(k) - 8]], k).verify(true); } #[test] fn bytecode_last_row_with_byte() { let k = 9; // Last row must be a padding row, so we have one row less for actual bytecode - test_bytecode_circuit_unrolled::(k, &vec![vec![7u8; 2usize.pow(k) - 7]], false); + BytecodeCircuit::::from_bytes(vec![vec![7u8; 2usize.pow(k) - 7]], k).verify(false); } /// Tests a circuit with incomplete bytecode #[test] fn bytecode_incomplete() { let k = 9; - test_bytecode_circuit_unrolled::(k, &vec![vec![7u8; 2usize.pow(k) + 1]], false); + BytecodeCircuit::::from_bytes(vec![vec![7u8; 2usize.pow(k) + 1]], k).verify(false); } /// Tests multiple bytecodes in a single circuit #[test] fn bytecode_push() { let k = 9; - test_bytecode_circuit_unrolled::( - k, - &vec![ + BytecodeCircuit::::from_bytes( + vec![ vec![], vec![OpcodeId::PUSH32.as_u8()], vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()], @@ -103,8 +92,9 @@ fn bytecode_push() { OpcodeId::ADD.as_u8(), ], ], - true, - ); + k, + ) + .verify(true); } /// Test invalid code_hash data @@ -112,16 +102,17 @@ fn bytecode_push() { fn bytecode_invalid_hash_data() { let k = 9; let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; - test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Change the code_hash on the first position (header row) { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - let code_hash = invalid.0[0].code_hash; - // Add 1 to both limbs - invalid.0[0].code_hash = code_hash.map(|limb| limb.map(|limb| limb + Fr::one())); - - log::trace!("bytecode_invalid_hash_data: Change the code_hash on the first position"); - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes, k) + .mut_rows(|rows| { + let code_hash = rows[0].code_hash; + rows[0].code_hash = code_hash.map(|limb| limb.map(|limb| limb + Fr::one())); + log::trace!( + "bytecode_invalid_hash_data: Change the code_hash on the first position" + ); + }) + .verify(false); } // TODO: other rows code_hash are ignored by the witness generation, to // test other rows invalid code_hash, we would need to inject an evil @@ -134,20 +125,23 @@ fn bytecode_invalid_hash_data() { fn bytecode_invalid_index() { let k = 9; let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; - test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Start the index at 1 { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - for row in invalid.0.iter_mut() { - row.index += Fr::ONE; - } - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes.clone(), k) + .mut_rows(|rows| { + for row in rows.iter_mut() { + row.index += Fr::ONE; + } + }) + .verify(false); } // Don't increment an index once { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0.last_mut().unwrap().index -= Fr::ONE; - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes, k) + .mut_rows(|rows| { + rows.last_mut().unwrap().index -= Fr::ONE; + }) + .verify(false); } } @@ -156,24 +150,29 @@ fn bytecode_invalid_index() { fn bytecode_invalid_byte_data() { let k = 9; let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; - test_bytecode_circuit_unrolled::(k, &bytecodes, true); // Change the first byte { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0[1].value = Fr::from(9u64); - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes.clone(), k) + .mut_rows(|rows| { + rows[1].value = Fr::from(9u64); + }) + .verify(false); } // Change a byte on another position { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0[5].value = Fr::from(6u64); - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes.clone(), k) + .mut_rows(|rows| { + rows[5].value = Fr::from(6u64); + }) + .verify(false); } // Set a byte value out of range { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0[3].value = Fr::from(256u64); - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes, k) + .mut_rows(|rows| { + rows[3].value = Fr::from(256u64); + }) + .verify(false); } } @@ -190,57 +189,57 @@ fn bytecode_invalid_is_code() { OpcodeId::ADD.as_u8(), OpcodeId::PUSH6.as_u8(), ]]; - test_bytecode_circuit_unrolled::(k, &bytecodes, true); + BytecodeCircuit::::from_bytes(bytecodes.clone(), k).verify(true); // Mark the 3rd byte as code (is push data from the first PUSH1) { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0[3].is_code = Fr::ONE; - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes.clone(), k) + .mut_rows(|rows| { + rows[3].is_code = Fr::ONE; + }) + .verify(false); } // Mark the 4rd byte as data (is code) { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0[4].is_code = Fr::ZERO; - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes.clone(), k) + .mut_rows(|rows| { + rows[4].is_code = Fr::ZERO; + }) + .verify(false); } // Mark the 7th byte as code (is data for the PUSH7) { - let mut invalid: BytecodeTableAssignment = bytecodes.into(); - invalid.0[7].is_code = Fr::ONE; - test_bytecode_circuit_unrolled::(k, &invalid, false); + BytecodeCircuit::::from_bytes(bytecodes, k) + .mut_rows(|rows| { + rows[7].is_code = Fr::ONE; + }) + .verify(false); } } #[test] -#[should_panic] -#[allow(clippy::clone_on_copy)] fn bytecode_soundness_bug_1() { let k = 9; - let bytecode = vec![1, 2, 3, 4]; - let bytecode_len = bytecode.len(); - let unrolled: BytecodeTableAssignment = vec![bytecode].into(); - let unrolled_len = unrolled.0.len(); - let code_hash = unrolled.0[0].code_hash.clone(); - let mut index = bytecode_len as u64; - let size = 100; - let minimum_rows = 8; - - let mut overwrite = unrolled.0.clone(); - for i in 0..size - minimum_rows + 3 { - if i >= unrolled_len { - overwrite.push(BytecodeCircuitRow::new( - i, - code_hash.clone(), - Fr::ONE, - Fr::from(index), - Fr::ONE, - Fr::from((i % 10 + 1) as u64), - )); - index += 1; - } - } - let overwrite = BytecodeTableAssignment { 0: overwrite }; - let mut circuit = BytecodeCircuit::::new(overwrite, size); - let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); - prover.assert_satisfied_par(); + let bytecodes = vec![vec![1, 2, 3, 4]]; + + let bytecode_len = bytecodes[0].len(); + BytecodeCircuit::::from_bytes(bytecodes, k) + .mut_rows(|rows| { + let code_hash = rows[0].code_hash.clone(); + let mut index = bytecode_len as u64; + let size = 100; + let minimum_rows = 8; + let unrolled_len = rows.len(); + for i in unrolled_len..size - minimum_rows + 3 { + rows.push(BytecodeCircuitRow::new( + i, + code_hash.clone(), + Fr::ONE, + Fr::from(index), + Fr::ONE, + Fr::from((i % 10 + 1) as u64), + )); + index += 1; + } + }) + .verify(false); } From ed2cdc147b84bee6ae8201a1d8039f050e034d6e Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 12 Jul 2023 17:18:02 +0800 Subject: [PATCH 13/37] offset fixed --- .../src/bytecode_circuit/circuit.rs | 46 ++++++------------- zkevm-circuits/src/bytecode_circuit/test.rs | 1 - 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index cfb25bd41e..70a7d392af 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -30,8 +30,6 @@ const PUSH_TABLE_WIDTH: usize = 2; #[derive(Debug, Clone, Default)] /// Row for assignment pub(crate) struct BytecodeCircuitRow { - offset: usize, - last_row_offset: usize, pub(crate) code_hash: Word>, tag: F, pub(crate) index: F, @@ -45,7 +43,6 @@ pub(crate) struct BytecodeCircuitRow { impl BytecodeCircuitRow { #[cfg(test)] pub(crate) fn new( - offset: usize, code_hash: Word>, tag: F, index: F, @@ -53,8 +50,6 @@ impl BytecodeCircuitRow { value: F, ) -> Self { Self { - offset, - last_row_offset: 0, code_hash, tag, index, @@ -67,10 +62,8 @@ impl BytecodeCircuitRow { } } - fn pad(offset: usize, last_row_offset: usize) -> Self { + fn pad() -> Self { Self { - offset, - last_row_offset, code_hash: empty_code_hash_word_value(), tag: F::from(BytecodeFieldTag::Header as u64), value_rlc: Value::known(F::ZERO), @@ -78,16 +71,6 @@ impl BytecodeCircuitRow { } } - /// enable selector if we are within the range of table size. - pub fn enable(&self) -> bool { - self.offset <= self.last_row_offset - } - - /// Determine if we are at last row of the bytecode table. - pub fn last(&self) -> bool { - self.offset == self.last_row_offset - } - /// Witness to IsZero chip to determine if we are at the last row of a bytecode instance pub fn diff(&self) -> F { self.index + F::ONE - self.length @@ -99,14 +82,11 @@ pub(crate) struct BytecodeTableAssignment(pub(crate) Vec From for BytecodeTableAssignment { fn from(collection: BytecodeCollection) -> Self { - let mut offset = 0; let mut rows = Vec::with_capacity(collection.num_rows_required_for_bytecode_table()); for bytecode in collection.into_iter() { let code_hash = util::word::Word::from(bytecode.hash()).into_value(); let code_size = bytecode.codesize(); let head = BytecodeCircuitRow { - offset, - last_row_offset: 0, code_hash, tag: F::from(BytecodeFieldTag::Header as u64), index: F::ZERO, @@ -118,7 +98,6 @@ impl From for BytecodeTableAssignment { push_data_size: F::ZERO, }; rows.push(head); - offset += 1; let mut push_data_left = 0; for (index, &(value, is_code)) in bytecode.code_vec().iter().enumerate() { @@ -132,8 +111,6 @@ impl From for BytecodeTableAssignment { }; let body = BytecodeCircuitRow { - offset, - last_row_offset: 0, code_hash, tag: F::from(BytecodeFieldTag::Byte as u64), index: F::from(index as u64), @@ -145,7 +122,6 @@ impl From for BytecodeTableAssignment { push_data_size: F::from(push_data_size), }; rows.push(body); - offset += 1; } } Self(rows) @@ -612,7 +588,7 @@ impl BytecodeCircuitConfig { self.annotate_circuit(&mut region); let mut value_rlc = Value::known(F::ZERO); - for row in witness.iter() { + for (offset, row) in witness.iter().enumerate() { let mut row = row.clone(); if row.tag == F::from(BytecodeFieldTag::Byte as u64) { value_rlc.as_mut().zip(challenges.keccak_input()).map( @@ -624,12 +600,17 @@ impl BytecodeCircuitConfig { value_rlc = Value::known(F::ZERO); } row.value_rlc = value_rlc; - self.set_row(&mut region, &row)?; + self.set_row(&mut region, offset, last_row_offset, &row)?; } // Padding - for idx in witness.len()..=last_row_offset { - self.set_row(&mut region, &BytecodeCircuitRow::pad(idx, last_row_offset))?; + for offset in witness.len()..=last_row_offset { + self.set_row( + &mut region, + offset, + last_row_offset, + &BytecodeCircuitRow::pad(), + )?; } Ok(()) }, @@ -639,15 +620,16 @@ impl BytecodeCircuitConfig { fn set_row( &self, region: &mut Region<'_, F>, + offset: usize, + last_row_offset: usize, row: &BytecodeCircuitRow, ) -> Result<(), Error> { - let offset = row.offset; // q_enable region.assign_fixed( || format!("assign q_enable {}", offset), self.q_enable, offset, - || Value::known(F::from(row.enable().into())), + || Value::known(F::from((offset <= last_row_offset).into())), )?; // q_first @@ -663,7 +645,7 @@ impl BytecodeCircuitConfig { || format!("assign q_last {}", offset), self.q_last, offset, - || Value::known(F::from(row.last().into())), + || Value::known(F::from((offset == last_row_offset).into())), )?; // Advices diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 07ff091601..5ae5a59e93 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -231,7 +231,6 @@ fn bytecode_soundness_bug_1() { let unrolled_len = rows.len(); for i in unrolled_len..size - minimum_rows + 3 { rows.push(BytecodeCircuitRow::new( - i, code_hash.clone(), Fr::ONE, Fr::from(index), From 4648764abbc5da645dbf3d18d67a7e9e247c5a38 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 01:16:14 +0800 Subject: [PATCH 14/37] fixed most of the tests --- .../src/bytecode_circuit/circuit.rs | 98 +++++++++++-------- zkevm-circuits/src/bytecode_circuit/test.rs | 12 +-- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 70a7d392af..43487d7046 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -13,7 +13,7 @@ use crate::{ witness::{self, BytecodeCollection}, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; -use eth_types::Field; +use eth_types::{Bytecode, Field}; use gadgets::is_zero::{IsZeroChip, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region, Value}, @@ -22,8 +22,9 @@ use halo2_proofs::{ }, poly::Rotation, }; +use itertools::Itertools; use log::trace; -use std::{ops::Deref, vec}; +use std::{iter, ops::Deref, vec}; const PUSH_TABLE_WIDTH: usize = 2; @@ -42,13 +43,7 @@ pub(crate) struct BytecodeCircuitRow { } impl BytecodeCircuitRow { #[cfg(test)] - pub(crate) fn new( - code_hash: Word>, - tag: F, - index: F, - is_code: F, - value: F, - ) -> Self { + pub(crate) fn new(code_hash: Word>, tag: F, index: F, is_code: F, value: F) -> Self { Self { code_hash, tag, @@ -62,6 +57,7 @@ impl BytecodeCircuitRow { } } + /// Padding must be a header, acording to the q_last constraints fn pad() -> Self { Self { code_hash: empty_code_hash_word_value(), @@ -72,7 +68,7 @@ impl BytecodeCircuitRow { } /// Witness to IsZero chip to determine if we are at the last row of a bytecode instance - pub fn diff(&self) -> F { + fn diff(&self) -> F { self.index + F::ONE - self.length } } @@ -80,10 +76,10 @@ impl BytecodeCircuitRow { #[derive(Clone, Default, Debug)] pub(crate) struct BytecodeTableAssignment(pub(crate) Vec>); -impl From for BytecodeTableAssignment { - fn from(collection: BytecodeCollection) -> Self { - let mut rows = Vec::with_capacity(collection.num_rows_required_for_bytecode_table()); - for bytecode in collection.into_iter() { +impl From> for BytecodeTableAssignment { + fn from(codes: Vec) -> Self { + let mut rows = vec![]; + for bytecode in codes.iter() { let code_hash = util::word::Word::from(bytecode.hash()).into_value(); let code_size = bytecode.codesize(); let head = BytecodeCircuitRow { @@ -104,12 +100,6 @@ impl From for BytecodeTableAssignment { let push_data_size = get_push_size(value); let value = F::from(value.into()); - push_data_left = if is_code { - push_data_size - } else { - push_data_left - 1 - }; - let body = BytecodeCircuitRow { code_hash, tag: F::from(BytecodeFieldTag::Byte as u64), @@ -122,16 +112,32 @@ impl From for BytecodeTableAssignment { push_data_size: F::from(push_data_size), }; rows.push(body); + push_data_left = if is_code { + push_data_size + } else { + push_data_left - 1 + }; } } Self(rows) } } +impl From for BytecodeTableAssignment { + fn from(collection: BytecodeCollection) -> Self { + // BytecodeCollection use hash maps, so the bytecodes will be reordered. + collection.into_iter().collect_vec().into() + } +} + impl From>> for BytecodeTableAssignment { fn from(codes: Vec>) -> Self { - let collections: BytecodeCollection = codes.into(); - collections.into() + // We don't go through BytecodeCollection struct to preserve bytecode order. + codes + .iter() + .map(|bytes| Bytecode::from(bytes.clone())) + .collect_vec() + .into() } } @@ -566,6 +572,7 @@ impl BytecodeCircuitConfig { ) -> Result<(), Error> { // Subtract the unusable rows from the size assert!(size > self.minimum_rows); + let last_row_offset = size - self.minimum_rows + 1; trace!( @@ -574,13 +581,15 @@ impl BytecodeCircuitConfig { self.minimum_rows, last_row_offset ); - assert!( - witness.len() <= last_row_offset + 1, - "the witness has size {}, but last_row_offset + 1 is {}", - witness.len(), - last_row_offset + 1 - ); - + if witness.len() > last_row_offset { + // The last_row_offset-th row must be reserved for padding. + // so we have "last_row_offset rows" usable + log::error!( + "the witness has size {}, but only {} rows usable. Some witness will not be assigned", + witness.len(), + last_row_offset + ); + } layouter.assign_region( || "assign bytecode", |mut region| { @@ -588,8 +597,18 @@ impl BytecodeCircuitConfig { self.annotate_circuit(&mut region); let mut value_rlc = Value::known(F::ZERO); - for (offset, row) in witness.iter().enumerate() { + // Chain the witness rows with as many padding rows as we like. + // We take only the first "last_row_offset" rows. + for (offset, row) in witness + .iter() + .chain(iter::repeat(&BytecodeCircuitRow::pad())) + .take(last_row_offset) + .enumerate() + { let mut row = row.clone(); + // unfortunately this is the only place we can set the RLC. + // The RLC of the padding rows are unaffected. As they are always with the + // Header tag, the RLC value for them are always zero. if row.tag == F::from(BytecodeFieldTag::Byte as u64) { value_rlc.as_mut().zip(challenges.keccak_input()).map( |(value_rlc, challenge)| { @@ -603,15 +622,14 @@ impl BytecodeCircuitConfig { self.set_row(&mut region, offset, last_row_offset, &row)?; } - // Padding - for offset in witness.len()..=last_row_offset { - self.set_row( - &mut region, - offset, - last_row_offset, - &BytecodeCircuitRow::pad(), - )?; - } + // Last row must be a padding row + self.set_row( + &mut region, + last_row_offset, + last_row_offset, + &BytecodeCircuitRow::pad(), + )?; + Ok(()) }, ) @@ -757,7 +775,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester pub(crate) fn new(bytecodes: BytecodeCollection, size: usize) -> Self { - let rows = bytecodes.clone().into(); + let rows: BytecodeTableAssignment = bytecodes.clone().into(); Self { bytecodes, rows, diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 5ae5a59e93..d5fcf9d8ca 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -31,9 +31,11 @@ impl BytecodeCircuit { fn verify(&self, success: bool) { let prover = MockProver::::run(log2_ceil(self.size), self, Vec::new()).unwrap(); let result = prover.verify_par(); - if let Err(failures) = &result { - for failure in failures.iter() { - error!("{}", failure); + if success { + if let Err(failures) = &result { + for failure in failures.iter() { + error!("{}", failure); + } } } let error_msg = if success { "valid" } else { "invalid" }; @@ -121,7 +123,6 @@ fn bytecode_invalid_hash_data() { /// Test invalid index #[test] -#[ignore] fn bytecode_invalid_index() { let k = 9; let bytecodes = vec![vec![8u8, 2, 3, 8, 9, 7, 128]]; @@ -228,8 +229,7 @@ fn bytecode_soundness_bug_1() { let mut index = bytecode_len as u64; let size = 100; let minimum_rows = 8; - let unrolled_len = rows.len(); - for i in unrolled_len..size - minimum_rows + 3 { + for i in rows.len()..size - minimum_rows + 3 { rows.push(BytecodeCircuitRow::new( code_hash.clone(), Fr::ONE, From b2101fdcdffca15e8d01ce1677a6307b07b243d7 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 02:59:21 +0800 Subject: [PATCH 15/37] clippy fix --- bus-mapping/src/circuit_input_builder/tracer_tests.rs | 4 ++-- eth-types/src/geth_types.rs | 3 +-- zkevm-circuits/src/bytecode_circuit/test.rs | 4 ++-- zkevm-circuits/src/copy_circuit/test.rs | 2 +- zkevm-circuits/src/table/bytecode_table.rs | 2 +- zkevm-circuits/src/witness/bytecode.rs | 1 - 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index a4303a5451..900e231ab0 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -2169,9 +2169,9 @@ fn test_gen_access_trace_create_push_call_stack() { let mut code_b = Bytecode::default(); // pad code_creator to multiple of 32 bytes - let len = code_creator.to_vec().len(); + let len = code_creator.codesize(); let code_creator: Vec = code_creator - .to_vec() + .code() .iter() .cloned() .chain(0u8..((32 - len % 32) as u8)) diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index b362e1c96d..e7d25696d1 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -45,7 +45,6 @@ impl Account { && self.storage.is_empty() } - #[deprecated] /// Generate an account that has either code or balance pub fn mock_code_or_balance(code: Bytecode) -> Self { let is_empty = code.codesize() == 0; @@ -57,7 +56,7 @@ impl Account { ..Default::default() } } - #[deprecated] + /// Generate an account that has 100 ETH pub fn mock_100_ether(code: Bytecode) -> Self { Self { diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index d5fcf9d8ca..74689e9d21 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -225,13 +225,13 @@ fn bytecode_soundness_bug_1() { let bytecode_len = bytecodes[0].len(); BytecodeCircuit::::from_bytes(bytecodes, k) .mut_rows(|rows| { - let code_hash = rows[0].code_hash.clone(); + let code_hash = rows[0].code_hash; let mut index = bytecode_len as u64; let size = 100; let minimum_rows = 8; for i in rows.len()..size - minimum_rows + 3 { rows.push(BytecodeCircuitRow::new( - code_hash.clone(), + code_hash, Fr::ONE, Fr::from(index), Fr::ONE, diff --git a/zkevm-circuits/src/copy_circuit/test.rs b/zkevm-circuits/src/copy_circuit/test.rs index ff0de79fe3..825febe790 100644 --- a/zkevm-circuits/src/copy_circuit/test.rs +++ b/zkevm-circuits/src/copy_circuit/test.rs @@ -54,7 +54,7 @@ pub fn test_copy_circuit_from_block( txs: block.txs, max_rws: block.circuits_params.max_rws, rws: block.rws, - bytecodes: block.bytecodes.clone(), + bytecodes: block.bytecodes, }, ) } diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index 3928d976a3..3f94f8eafc 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -43,7 +43,7 @@ impl BytecodeTable { /// Assign the `BytecodeTable` from a list of bytecodes, followig the same /// table layout that the Bytecode Circuit uses. - pub fn load<'a, F: Field>( + pub fn load( &self, layouter: &mut impl Layouter, bytecodes: BytecodeCollection, diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 36391577cf..7c599ff327 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -24,7 +24,6 @@ impl BytecodeCollection { } /// Get raw bytes - #[deprecated()] pub fn to_raw(&self) -> Vec> { self.codes.values().map(|code| code.code()).collect_vec() } From 408f1106ca5f6882f8a9abc4a1a7a3495a414fd5 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 03:09:39 +0800 Subject: [PATCH 16/37] minor --- bus-mapping/src/evm/opcodes/create.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/create.rs b/bus-mapping/src/evm/opcodes/create.rs index 7ccb4704f5..3c085cfddc 100644 --- a/bus-mapping/src/evm/opcodes/create.rs +++ b/bus-mapping/src/evm/opcodes/create.rs @@ -291,8 +291,10 @@ fn handle_copy( length: usize, ) -> Result<(Vec, H256), Error> { let initialization_bytes = state.caller_ctx()?.memory.0[offset..(offset + length)].to_vec(); - let code_hash = CodeDB::hash(&initialization_bytes); - let bytes = Bytecode::from(initialization_bytes.clone()).code_vec(); + + let initialization = Bytecode::from(initialization_bytes.clone()); + let code_hash = initialization.hash_h256(); + let bytes = initialization.code_vec(); let rw_counter_start = state.block_ctx.rwc; for (i, (byte, _)) in bytes.iter().enumerate() { From 2c6cfd893c2f455512535e607e75cfd228502bc9 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 03:26:00 +0800 Subject: [PATCH 17/37] bytecode unroller can go --- zkevm-circuits/src/witness.rs | 2 +- zkevm-circuits/src/witness/bytecode.rs | 37 -------------------------- 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 04ddbfb40a..a1e80f30d2 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -5,8 +5,8 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; +pub use bytecode::BytecodeCollection; pub(crate) use bytecode::BytecodeRow; -pub use bytecode::{BytecodeCollection, BytecodeUnroller as Bytecode}; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 7c599ff327..99f4d64766 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -63,43 +63,6 @@ impl IntoIterator for BytecodeCollection { self.codes.values().cloned().collect_vec().into_iter() } } -/// Bytecode -#[derive(Clone, Debug)] -pub struct BytecodeUnroller { - /// We assume the is_code field is properly set. - bytecode: Bytecode, -} - -impl BytecodeUnroller { - #[deprecated()] - /// get byte value and is_code pair - pub fn get(&self, dest: usize) -> Option<(u8, bool)> { - self.bytecode.get(dest) - } - - #[deprecated()] - /// The length of the bytecode - pub fn codesize(&self) -> usize { - self.bytecode.codesize() - } - - /// The length of the bytecode table - pub fn table_len(&self) -> usize { - self.bytecode.codesize() + 1 - } - - #[deprecated()] - /// The code hash - pub fn hash(&self) -> Word { - self.bytecode.hash() - } - - #[deprecated()] - /// The code in bytes - pub fn code(&self) -> Vec { - self.bytecode.code() - } -} /// Public data for the bytecode #[derive(Clone, Debug, PartialEq)] From 63c9919831aff0efd4c7a7a2dd199e6dc22f929e Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 14:49:26 +0800 Subject: [PATCH 18/37] minor --- bus-mapping/src/evm/opcodes/return_revert.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/return_revert.rs b/bus-mapping/src/evm/opcodes/return_revert.rs index 82b47e795c..30b9636146 100644 --- a/bus-mapping/src/evm/opcodes/return_revert.rs +++ b/bus-mapping/src/evm/opcodes/return_revert.rs @@ -206,13 +206,13 @@ fn handle_create( step: &mut ExecStep, source: Source, ) -> Result { - let raw_bytes = - state.call_ctx()?.memory.0[source.offset..source.offset + source.length].to_vec(); - let bytecode = Bytecode::from(raw_bytes); + let values = state.call_ctx()?.memory.0[source.offset..source.offset + source.length].to_vec(); + let bytecode = Bytecode::from(values); let code_hash = bytecode.hash_h256(); + let bytes = bytecode.code_vec(); let dst_id = NumberOrHash::Hash(code_hash); let rw_counter_start = state.block_ctx.rwc; - for (i, byte) in bytecode.code().iter().enumerate() { + for (i, (byte, _)) in bytes.iter().enumerate() { state.push_op( step, RW::READ, @@ -232,7 +232,7 @@ fn handle_create( dst_id, dst_addr: 0, log_id: None, - bytes: bytecode.code_vec(), + bytes, }, ); From aeb16f6f978115bb812906ebb760fcea6b64dbe1 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 19:03:35 +0800 Subject: [PATCH 19/37] deduplication of storing code to mem --- .../src/circuit_input_builder/tracer_tests.rs | 115 +++--------------- eth-types/src/bytecode.rs | 16 +++ 2 files changed, 31 insertions(+), 100 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 900e231ab0..6012b0e3c4 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -364,17 +364,8 @@ fn tracer_err_address_collision() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes + code_b.store_code_to_mem(&code_creator); let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } let code_b_end = bytecode! { PUSH3(0x123456) // salt PUSH1(len) // length @@ -486,17 +477,8 @@ fn tracer_create_collision_free() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes + code_b.store_code_to_mem(&code_creator); let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } let code_b_end = bytecode! { PUSH1(len) // length PUSH1(0x00) // offset @@ -621,19 +603,9 @@ fn tracer_err_code_store_out_of_gas() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes - let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0..(32 - len % 32) as u8) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } + code_b.store_code_to_mem(&code_creator); let code_b_end = bytecode! { - PUSH32(len) // length + PUSH32(code_creator.codesize()) // length PUSH1(0x00) // offset PUSH1(0x00) // value CREATE @@ -769,17 +741,8 @@ fn tracer_err_invalid_code_for_create_opcode() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes + code_b.store_code_to_mem(&code_creator); let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } let code_b_end = bytecode! { PUSH1(len) // length PUSH1(0x00) // offset @@ -921,19 +884,9 @@ fn tracer_err_max_code_size_exceeded() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes - let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } + code_b.store_code_to_mem(&code_creator); let code_b_end = bytecode! { - PUSH32(len) // length + PUSH32(code_creator.codesize()) // length PUSH1(0x00) // offset PUSH1(0x00) // value CREATE @@ -1059,19 +1012,9 @@ fn tracer_create_stop() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes - let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } + code_b.store_code_to_mem(&code_creator); let code_b_end = bytecode! { - PUSH1(len) // length + PUSH1(code_creator.codesize()) // length PUSH1(0x00) // offset PUSH1(0x00) // value CREATE @@ -1760,20 +1703,10 @@ fn create2_address() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes - let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } + code_b.store_code_to_mem(&code_creator); let code_b_end = bytecode! { PUSH3(0x123456) // salt - PUSH1(len) // length + PUSH1(code_creator.codesize()) // length PUSH1(0x00) // offset PUSH1(0x00) // value CREATE2 @@ -1853,17 +1786,8 @@ fn create_address() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes + code_b.store_code_to_mem(&code_creator); let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } // We do CREATE 2 times to use a nonce != 0 in the second one. let code_b_end = bytecode! { PUSH1(len) // length @@ -2168,19 +2092,10 @@ fn test_gen_access_trace_create_push_call_stack() { }; let mut code_b = Bytecode::default(); - // pad code_creator to multiple of 32 bytes - let len = code_creator.codesize(); - let code_creator: Vec = code_creator - .code() - .iter() - .cloned() - .chain(0u8..((32 - len % 32) as u8)) - .collect(); - for (index, word) in code_creator.chunks(32).enumerate() { - code_b.op_mstore(index * 32, Word::from_big_endian(word)); - } + code_b.store_code_to_mem(&code_creator); + let code_b_end = bytecode! { - PUSH1(len) // length + PUSH1(code_creator.codesize()) // length PUSH1(0x00) // offset PUSH1(0x00) // value CREATE diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index e78eecfe3b..6a304315ff 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -196,6 +196,22 @@ impl Bytecode { self.write_op(OpcodeId::JUMPDEST); self.code.len() } + + /// Store another code to memory + pub fn store_code_to_mem(&mut self, code: &Self) { + let len = code.codesize(); + // pad to multiple of 32 bytes + let code: Vec = code + .code() + .iter() + .cloned() + .chain(0u8..((32 - len % 32) as u8)) + .collect(); + + for (index, word) in code.chunks(32).enumerate() { + self.op_mstore(index * 32, Word::from_big_endian(word)); + } + } } /// An ASM entry From 25752549a282d9ac108a8902a728f55e4e92cb69 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 19:09:37 +0800 Subject: [PATCH 20/37] deadcode --- eth-types/src/bytecode.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index 6a304315ff..b31935fb89 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -164,15 +164,6 @@ impl Bytecode { self } - /// Append asm - pub fn append_asm(&mut self, op: &str) -> Result<(), Error> { - match OpcodeWithData::from_str(op)? { - OpcodeWithData::Opcode(op) => self.write_op(op), - OpcodeWithData::Push(n, value) => self.push(n, value), - }; - Ok(()) - } - /// Append an opcode pub fn append_op(&mut self, op: OpcodeWithData) -> &mut Self { match op { From 7a094e56b800800e1c6bbdb719258a20933d3670 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 22:48:53 +0800 Subject: [PATCH 21/37] fixed circuit benchmark --- circuit-benchmarks/src/bytecode_circuit.rs | 29 +++++++------------ .../src/bytecode_circuit/circuit.rs | 2 +- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/circuit-benchmarks/src/bytecode_circuit.rs b/circuit-benchmarks/src/bytecode_circuit.rs index 42ca583f35..58eb1f4cc7 100644 --- a/circuit-benchmarks/src/bytecode_circuit.rs +++ b/circuit-benchmarks/src/bytecode_circuit.rs @@ -4,7 +4,6 @@ mod tests { use ark_std::{end_timer, start_timer}; use bus_mapping::evm::OpcodeId; - use eth_types::Field; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, @@ -22,13 +21,9 @@ mod tests { }; use rand::SeedableRng; use rand_xorshift::XorShiftRng; - use std::env::var; + use std::{env::var, iter}; use zkevm_circuits::{ - bytecode_circuit::{ - bytecode_unroller::{unroll, UnrolledBytecode}, - TestBytecodeCircuit, - }, - util::SubCircuit, + bytecode_circuit::TestBytecodeCircuit, util::SubCircuit, witness::BytecodeCollection, }; #[cfg_attr(not(feature = "benches"), ignore)] @@ -127,10 +122,7 @@ mod tests { } /// fill bytecodes_num * bytecode_len bytes to the witness table - fn fillup_codebytes( - bytecodes_num: usize, - bytecode_len: usize, - ) -> Vec> { + fn fillup_codebytes(bytecodes_num: usize, bytecode_len: usize) -> BytecodeCollection { fn valid_or(base: OpcodeId, or: OpcodeId) -> OpcodeId { match base { OpcodeId::INVALID(_) => or, @@ -138,14 +130,13 @@ mod tests { } } - let mut codebytes = vec![]; - (0..bytecodes_num).for_each(|_| { - let bytecodes = (0..bytecode_len) + let codebytes = iter::repeat( + (0..bytecode_len) .map(|v| valid_or(OpcodeId::from(v as u8), OpcodeId::STOP).as_u8()) - .collect::>(); - let unrolled_bytes = unroll::(bytecodes); - codebytes.push(unrolled_bytes); - }); - codebytes + .collect::>(), + ) + .take(bytecodes_num) + .collect::>>(); + BytecodeCollection::from(codebytes) } } diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 43487d7046..d8366f09be 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -774,7 +774,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester - pub(crate) fn new(bytecodes: BytecodeCollection, size: usize) -> Self { + pub fn new(bytecodes: BytecodeCollection, size: usize) -> Self { let rows: BytecodeTableAssignment = bytecodes.clone().into(); Self { bytecodes, From 407fbc7e5087bfba1428764d4953e96fefb7c8dd Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 22:51:37 +0800 Subject: [PATCH 22/37] bytecode unroller can go --- zkevm-circuits/src/bytecode_circuit.rs | 2 - .../src/bytecode_circuit/bytecode_unroller.rs | 56 ------------------- 2 files changed, 58 deletions(-) delete mode 100644 zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs diff --git a/zkevm-circuits/src/bytecode_circuit.rs b/zkevm-circuits/src/bytecode_circuit.rs index 97ce348718..715e9f0add 100644 --- a/zkevm-circuits/src/bytecode_circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit.rs @@ -1,7 +1,5 @@ //! The bytecode circuit implementation. -/// Bytecode unroller -pub mod bytecode_unroller; /// Bytecode circuit pub mod circuit; diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs deleted file mode 100644 index 755e8fb9cd..0000000000 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{ - table::BytecodeFieldTag, - util::{get_push_size, keccak}, -}; -use eth_types::{Field, Word}; -use std::vec; - -/// Public data for the bytecode -#[derive(Clone, Debug, PartialEq)] -pub(crate) struct BytecodeRow { - pub(crate) code_hash: Word, - pub(crate) tag: F, - pub(crate) index: F, - pub(crate) is_code: F, - pub(crate) value: F, -} - -/// Unrolled bytecode -#[derive(Clone, Debug, PartialEq, Default)] -pub struct UnrolledBytecode { - pub(crate) bytes: Vec, - pub(crate) rows: Vec>, -} - -#[deprecated] -/// Get unrolled bytecode from raw bytes -pub fn unroll(bytes: Vec) -> UnrolledBytecode { - let code_hash = keccak(&bytes[..]); - let mut rows = vec![BytecodeRow:: { - code_hash, - tag: F::from(BytecodeFieldTag::Header as u64), - index: F::ZERO, - is_code: F::ZERO, - value: F::from(bytes.len() as u64), - }]; - // Run over all the bytes - let mut push_rindex = 0; - for (index, byte) in bytes.iter().enumerate() { - // Track which byte is an opcode and which is push data - let is_code = push_rindex == 0; - push_rindex = if is_code { - get_push_size(*byte) - } else { - push_rindex - 1 - }; - - rows.push(BytecodeRow:: { - code_hash, - tag: F::from(BytecodeFieldTag::Byte as u64), - index: F::from(index as u64), - is_code: F::from(is_code as u64), - value: F::from(*byte as u64), - }); - } - UnrolledBytecode { bytes, rows } -} From d2b0532217aae07e6eb84d99dda39c5c280dcddf Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 23:00:19 +0800 Subject: [PATCH 23/37] bytecode table rows can go --- zkevm-circuits/src/table/bytecode_table.rs | 32 ++++++++++----- zkevm-circuits/src/witness.rs | 1 - zkevm-circuits/src/witness/bytecode.rs | 47 +--------------------- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index 3f94f8eafc..4a7ad96161 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -1,4 +1,4 @@ -use crate::witness::{BytecodeCollection, BytecodeRow}; +use crate::{util, witness::BytecodeCollection}; use super::*; @@ -66,14 +66,28 @@ impl BytecodeTable { >::advice_columns(self); for bytecode in bytecodes.clone().into_iter() { let rows = { - let code_hash = bytecode.hash(); - std::iter::once(BytecodeRow::::head(code_hash, bytecode.codesize())) - .chain(bytecode.code_vec().iter().enumerate().map( - |(index, &(byte, is_code))| { - BytecodeRow::::body(code_hash, index, is_code, byte) - }, - )) - .collect_vec() + let code_hash = util::word::Word::from(bytecode.hash()); + std::iter::once([ + code_hash.lo(), + code_hash.hi(), + F::from(BytecodeFieldTag::Header as u64), + F::ZERO, + F::ZERO, + F::from(bytecode.codesize() as u64), + ]) + .chain(bytecode.code_vec().iter().enumerate().map( + |(index, &(byte, is_code))| { + [ + code_hash.lo(), + code_hash.hi(), + F::from(BytecodeFieldTag::Byte as u64), + F::from(index as u64), + F::from(is_code.into()), + F::from(byte.into()), + ] + }, + )) + .collect_vec() }; for row in rows.iter() { for (&column, value) in bytecode_table_columns.iter().zip_eq(row.to_vec()) { diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index a1e80f30d2..6b0b2d2bd0 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -6,7 +6,6 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; pub use bytecode::BytecodeCollection; -pub(crate) use bytecode::BytecodeRow; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 99f4d64766..788918a5c3 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -1,6 +1,5 @@ -use crate::{table::BytecodeFieldTag, util}; use bus_mapping::state_db::CodeDB; -use eth_types::{Bytecode, Field, Word}; +use eth_types::{Bytecode, Word}; use itertools::Itertools; use std::collections::HashMap; @@ -63,47 +62,3 @@ impl IntoIterator for BytecodeCollection { self.codes.values().cloned().collect_vec().into_iter() } } - -/// Public data for the bytecode -#[derive(Clone, Debug, PartialEq)] -pub(crate) struct BytecodeRow { - /// We don't assign it now - code_hash: Word, - pub(crate) tag: F, - pub(crate) index: F, - pub(crate) is_code: F, - pub(crate) value: F, -} - -impl BytecodeRow { - pub(crate) fn to_vec(&self) -> [F; 6] { - let code_hash: util::word::Word = util::word::Word::from(self.code_hash); - [ - code_hash.lo(), - code_hash.hi(), - self.tag, - self.index, - self.is_code, - self.value, - ] - } - - pub(crate) fn head(code_hash: Word, code_size: usize) -> Self { - Self { - code_hash, - tag: F::from(BytecodeFieldTag::Header as u64), - index: F::ZERO, - is_code: F::ZERO, - value: F::from(code_size as u64), - } - } - pub(crate) fn body(code_hash: Word, index: usize, is_code: bool, value: u8) -> Self { - Self { - code_hash, - tag: F::from(BytecodeFieldTag::Byte as u64), - index: F::from(index as u64), - is_code: F::from(is_code.into()), - value: F::from(value.into()), - } - } -} From 2d6e2622558e630639c453a149f2b63f6561071d Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 23:02:20 +0800 Subject: [PATCH 24/37] rename BytecodeCircuitAssignment --- zkevm-circuits/src/bytecode_circuit/circuit.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index d8366f09be..a0b05088c0 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -74,9 +74,9 @@ impl BytecodeCircuitRow { } #[derive(Clone, Default, Debug)] -pub(crate) struct BytecodeTableAssignment(pub(crate) Vec>); +pub(crate) struct BytecodeCircuitAssignment(pub(crate) Vec>); -impl From> for BytecodeTableAssignment { +impl From> for BytecodeCircuitAssignment { fn from(codes: Vec) -> Self { let mut rows = vec![]; for bytecode in codes.iter() { @@ -123,14 +123,14 @@ impl From> for BytecodeTableAssignment { } } -impl From for BytecodeTableAssignment { +impl From for BytecodeCircuitAssignment { fn from(collection: BytecodeCollection) -> Self { // BytecodeCollection use hash maps, so the bytecodes will be reordered. collection.into_iter().collect_vec().into() } } -impl From>> for BytecodeTableAssignment { +impl From>> for BytecodeCircuitAssignment { fn from(codes: Vec>) -> Self { // We don't go through BytecodeCollection struct to preserve bytecode order. codes @@ -141,7 +141,7 @@ impl From>> for BytecodeTableAssignment { } } -impl Deref for BytecodeTableAssignment { +impl Deref for BytecodeCircuitAssignment { type Target = Vec>; fn deref(&self) -> &Self::Target { @@ -567,7 +567,7 @@ impl BytecodeCircuitConfig { &self, layouter: &mut impl Layouter, size: usize, - witness: &BytecodeTableAssignment, + witness: &BytecodeCircuitAssignment, challenges: &Challenges>, ) -> Result<(), Error> { // Subtract the unusable rows from the size @@ -767,7 +767,7 @@ impl BytecodeCircuitConfig { pub struct BytecodeCircuit { pub(crate) bytecodes: BytecodeCollection, /// Unrolled bytecodes - pub(crate) rows: BytecodeTableAssignment, + pub(crate) rows: BytecodeCircuitAssignment, /// Circuit size pub size: usize, } @@ -775,7 +775,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester pub fn new(bytecodes: BytecodeCollection, size: usize) -> Self { - let rows: BytecodeTableAssignment = bytecodes.clone().into(); + let rows: BytecodeCircuitAssignment = bytecodes.clone().into(); Self { bytecodes, rows, From 4e0c12ffa4c9ff1554001e94fa963c0b27f7c205 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 23:20:44 +0800 Subject: [PATCH 25/37] make codedb the same --- bus-mapping/src/state_db.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 90dac3e7f1..c269fcdf26 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -1,8 +1,9 @@ //! Implementation of an in-memory key-value database to represent the //! Ethereum State Trie. -use eth_types::{geth_types, Address, Hash, Word, H256, U256}; +use eth_types::{geth_types, Address, BigEndianHash, Bytecode, Hash, Word, H256, U256}; use ethers_core::utils::keccak256; +use itertools::Itertools; use lazy_static::lazy_static; use std::collections::{HashMap, HashSet}; @@ -41,6 +42,23 @@ impl CodeDB { pub fn empty_code_hash() -> Hash { *EMPTY_CODE_HASH } + + /// Compute number of rows required for bytecode table. + pub fn num_rows_required_for_bytecode_table(&self) -> usize { + self.0.values().map(|bytecode| bytecode.len() + 1).sum() + } + /// Query code by hash + pub fn get(&self, codehash: &Word) -> Option { + self.0 + .get(&H256::from_uint(codehash)) + .cloned() + .map(|code| code.into()) + } + + /// Get raw bytes + pub fn to_raw(&self) -> Vec> { + self.0.values().into_iter().cloned().collect_vec() + } } /// Account of the Ethereum State Trie, which contains an in-memory key-value From 830e5d1174b78b5872df15a0af8fc459fc3433cc Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 23:36:23 +0800 Subject: [PATCH 26/37] codedb visibility control --- bus-mapping/src/circuit_input_builder.rs | 4 ++-- .../src/circuit_input_builder/input_state_ref.rs | 1 - bus-mapping/src/state_db.rs | 12 +++++++++--- testool/src/statetest/executor.rs | 8 ++++++-- zkevm-circuits/src/witness/bytecode.rs | 13 ++----------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 2392ca7c69..babebbee8d 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -367,7 +367,7 @@ impl CircuitInputBuilder { // Compute subcircuits parameters let c_params = { let max_txs = eth_block.transactions.len(); - let max_bytecode = self.code_db.0.values().fold(0, |acc, a| acc + a.len() + 1); + let max_bytecode = self.code_db.num_rows_required_for_bytecode_table(); let max_calldata = eth_block .transactions @@ -437,7 +437,7 @@ pub fn keccak_inputs(block: &Block, code_db: &CodeDB) -> Result>, Er let txs: Vec = block.txs.iter().map(|tx| tx.deref().clone()).collect(); keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit(&txs, block.chain_id.as_u64())?); // Bytecode Circuit - for bytecode in code_db.0.values() { + for bytecode in code_db.to_raw() { keccak_inputs.push(bytecode.clone()); } // EVM Circuit diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index aceea9a31a..eb62e37785 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -614,7 +614,6 @@ impl<'a> CircuitInputStateRef<'a> { /// Fetch and return code for the given code hash from the code DB. pub fn code(&self, code_hash: H256) -> Result, Error> { self.code_db - .0 .get(&code_hash) .cloned() .ok_or(Error::CodeNotFound(code_hash)) diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index c269fcdf26..63f138d9d8 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -23,7 +23,7 @@ const VALUE_ZERO: Word = Word::zero(); /// Memory storage for contract code by code hash. #[derive(Debug, Clone, Default)] -pub struct CodeDB(pub HashMap>); +pub struct CodeDB(HashMap>); impl CodeDB { /// Insert code indexed by code hash, and return the code hash. @@ -47,8 +47,14 @@ impl CodeDB { pub fn num_rows_required_for_bytecode_table(&self) -> usize { self.0.values().map(|bytecode| bytecode.len() + 1).sum() } + + /// Query code by hash + pub fn get(&self, codehash: &H256) -> Option<&Vec> { + self.0.get(codehash) + } + /// Query code by hash - pub fn get(&self, codehash: &Word) -> Option { + pub fn get_from_word(&self, codehash: &Word) -> Option { self.0 .get(&H256::from_uint(codehash)) .cloned() @@ -57,7 +63,7 @@ impl CodeDB { /// Get raw bytes pub fn to_raw(&self) -> Vec> { - self.0.values().into_iter().cloned().collect_vec() + self.0.values().cloned().collect_vec() } } diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 7dae91d8a0..c676b6bc3c 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -78,9 +78,13 @@ fn check_post( if let Some(expected_code) = &expected.code { let actual_code = if actual.code_hash.is_zero() { - std::borrow::Cow::Owned(Vec::new()) + vec![] } else { - std::borrow::Cow::Borrowed(&builder.code_db.0[&actual.code_hash]) + builder + .code_db + .get(&actual.code_hash) + .cloned() + .expect("code exists") }; if &actual_code as &[u8] != expected_code.0 { return Err(StateTestError::CodeMismatch { diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 788918a5c3..0eadcfce90 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -29,17 +29,8 @@ impl BytecodeCollection { } impl From<&CodeDB> for BytecodeCollection { - fn from(code_db: &CodeDB) -> Self { - Self { - codes: code_db - .0 - .values() - .map(|v| { - let bytecode = Bytecode::from(v.clone()); - (bytecode.hash(), bytecode) - }) - .collect(), - } + fn from(_code_db: &CodeDB) -> Self { + todo!() } } From e23801cdc032a79fa51ac269460c828b4f0129ab Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 13 Jul 2023 23:59:49 +0800 Subject: [PATCH 27/37] replace bytecodecollection with codedb --- bus-mapping/src/state_db.rs | 39 +++++++++++-- circuit-benchmarks/src/bytecode_circuit.rs | 10 ++-- .../src/bytecode_circuit/circuit.rs | 16 +++--- zkevm-circuits/src/bytecode_circuit/test.rs | 5 +- zkevm-circuits/src/copy_circuit.rs | 5 +- .../src/evm_circuit/execution/codecopy.rs | 4 +- .../execution/error_invalid_jump.rs | 4 +- .../src/evm_circuit/execution/extcodecopy.rs | 2 +- .../src/evm_circuit/execution/stop.rs | 4 +- zkevm-circuits/src/table/bytecode_table.rs | 6 +- zkevm-circuits/src/witness.rs | 2 - zkevm-circuits/src/witness/block.rs | 7 ++- zkevm-circuits/src/witness/bytecode.rs | 55 ------------------- 13 files changed, 65 insertions(+), 94 deletions(-) delete mode 100644 zkevm-circuits/src/witness/bytecode.rs diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 63f138d9d8..e884063340 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -48,17 +48,19 @@ impl CodeDB { self.0.values().map(|bytecode| bytecode.len() + 1).sum() } - /// Query code by hash + /// Query code in raw bytes by H256 pub fn get(&self, codehash: &H256) -> Option<&Vec> { self.0.get(codehash) } - /// Query code by hash + /// Query Bytecode by H256 + pub fn get_bytecode(&self, codehash: &H256) -> Option { + self.0.get(codehash).cloned().map(|code| code.into()) + } + + /// Query Bytecode by U256 pub fn get_from_word(&self, codehash: &Word) -> Option { - self.0 - .get(&H256::from_uint(codehash)) - .cloned() - .map(|code| code.into()) + self.get_bytecode(&H256::from_uint(codehash)) } /// Get raw bytes @@ -67,6 +69,31 @@ impl CodeDB { } } +impl From>> for CodeDB { + fn from(bytecodes: Vec>) -> Self { + Self(HashMap::from_iter( + bytecodes + .iter() + .cloned() + .map(|bytecode| (Self::hash(&bytecode), bytecode)), + )) + } +} + +impl IntoIterator for CodeDB { + type Item = Bytecode; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0 + .values() + .cloned() + .map(Bytecode::from) + .collect_vec() + .into_iter() + } +} + /// Account of the Ethereum State Trie, which contains an in-memory key-value /// database that represents the Account Storage Trie. #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/circuit-benchmarks/src/bytecode_circuit.rs b/circuit-benchmarks/src/bytecode_circuit.rs index 58eb1f4cc7..b145bbb834 100644 --- a/circuit-benchmarks/src/bytecode_circuit.rs +++ b/circuit-benchmarks/src/bytecode_circuit.rs @@ -3,7 +3,7 @@ #[cfg(test)] mod tests { use ark_std::{end_timer, start_timer}; - use bus_mapping::evm::OpcodeId; + use bus_mapping::{evm::OpcodeId, state_db::CodeDB}; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, @@ -22,9 +22,7 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::{env::var, iter}; - use zkevm_circuits::{ - bytecode_circuit::TestBytecodeCircuit, util::SubCircuit, witness::BytecodeCollection, - }; + use zkevm_circuits::{bytecode_circuit::TestBytecodeCircuit, util::SubCircuit}; #[cfg_attr(not(feature = "benches"), ignore)] #[test] @@ -122,7 +120,7 @@ mod tests { } /// fill bytecodes_num * bytecode_len bytes to the witness table - fn fillup_codebytes(bytecodes_num: usize, bytecode_len: usize) -> BytecodeCollection { + fn fillup_codebytes(bytecodes_num: usize, bytecode_len: usize) -> CodeDB { fn valid_or(base: OpcodeId, or: OpcodeId) -> OpcodeId { match base { OpcodeId::INVALID(_) => or, @@ -137,6 +135,6 @@ mod tests { ) .take(bytecodes_num) .collect::>>(); - BytecodeCollection::from(codebytes) + CodeDB::from(codebytes) } } diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index a0b05088c0..1ac7bda665 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -10,9 +10,9 @@ use crate::{ word::{empty_code_hash_word_value, Word, Word32, WordExpr}, Challenges, Expr, SubCircuit, SubCircuitConfig, }, - witness::{self, BytecodeCollection}, + witness::{self}, }; -use bus_mapping::state_db::EMPTY_CODE_HASH_LE; +use bus_mapping::state_db::{CodeDB, EMPTY_CODE_HASH_LE}; use eth_types::{Bytecode, Field}; use gadgets::is_zero::{IsZeroChip, IsZeroInstruction}; use halo2_proofs::{ @@ -123,10 +123,10 @@ impl From> for BytecodeCircuitAssignment { } } -impl From for BytecodeCircuitAssignment { - fn from(collection: BytecodeCollection) -> Self { - // BytecodeCollection use hash maps, so the bytecodes will be reordered. - collection.into_iter().collect_vec().into() +impl From for BytecodeCircuitAssignment { + fn from(code_db: CodeDB) -> Self { + // CodeDB use hash maps, so the bytecodes will be reordered. + code_db.to_raw().into() } } @@ -765,7 +765,7 @@ impl BytecodeCircuitConfig { /// BytecodeCircuit #[derive(Clone, Default, Debug)] pub struct BytecodeCircuit { - pub(crate) bytecodes: BytecodeCollection, + pub(crate) bytecodes: CodeDB, /// Unrolled bytecodes pub(crate) rows: BytecodeCircuitAssignment, /// Circuit size @@ -774,7 +774,7 @@ pub struct BytecodeCircuit { impl BytecodeCircuit { /// new BytecodeCircuitTester - pub fn new(bytecodes: BytecodeCollection, size: usize) -> Self { + pub fn new(bytecodes: CodeDB, size: usize) -> Self { let rows: BytecodeCircuitAssignment = bytecodes.clone().into(); Self { bytecodes, diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 74689e9d21..77a8178046 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -1,9 +1,8 @@ use crate::{ bytecode_circuit::circuit::BytecodeCircuit, util::{log2_ceil, unusable_rows, SubCircuit}, - witness::BytecodeCollection, }; -use bus_mapping::evm::OpcodeId; +use bus_mapping::{evm::OpcodeId, state_db::CodeDB}; use eth_types::Field; use halo2_proofs::{arithmetic::Field as Halo2Field, dev::MockProver, halo2curves::bn256::Fr}; use log::error; @@ -24,7 +23,7 @@ impl BytecodeCircuit { self.clone() } - fn from_bytes(bytecodes: impl Into, k: u32) -> Self { + fn from_bytes(bytecodes: impl Into, k: u32) -> Self { Self::new(bytecodes.into(), 2usize.pow(k)) } diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index cd90be883b..ebea1507b7 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -18,11 +18,12 @@ use crate::{ }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness, - witness::{BytecodeCollection, RwMap, Transaction}, + witness::{RwMap, Transaction}, }; use bus_mapping::{ circuit_input_builder::{CopyDataType, CopyEvent}, operation::Target, + state_db::CodeDB, }; use eth_types::Field; use gadgets::{ @@ -752,7 +753,7 @@ pub struct ExternalData { /// StateCircuit -> rws pub rws: RwMap, /// BytecodeCircuit -> bytecodes - pub bytecodes: BytecodeCollection, + pub bytecodes: CodeDB, } /// Copy Circuit diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index 0d4cfa1316..d1c1860d52 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -1,5 +1,5 @@ use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{evm_types::GasCost, Field, ToScalar, ToWord}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; use crate::{ @@ -159,7 +159,7 @@ impl ExecutionGadget for CodeCopyGadget { let bytecode = block .bytecodes - .get(&call.code_hash.to_word()) + .get_bytecode(&call.code_hash) .expect("could not find current environment's bytecode"); let code_size = bytecode.codesize() as u64; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 5e760877a7..e21861d5de 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -16,7 +16,7 @@ use crate::{ Expr, }, }; -use eth_types::{evm_types::OpcodeId, Field, ToWord, U256}; +use eth_types::{evm_types::OpcodeId, Field, U256}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -128,7 +128,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { let code = block .bytecodes - .get(&call.code_hash.to_word()) + .get_bytecode(&call.code_hash) .expect("could not find current environment's bytecode"); let code_len = code.codesize() as u64; self.code_len diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 094687ff0f..060ca78f3d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -209,7 +209,7 @@ impl ExecutionGadget for ExtcodecopyGadget { } else { block .bytecodes - .get(&code_hash) + .get_from_word(&code_hash) .expect("could not find external bytecode") .codesize() as u64 }; diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 6d2d248510..e2d4cbe88d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -20,7 +20,7 @@ use crate::{ }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToWord}; +use eth_types::Field; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] @@ -108,7 +108,7 @@ impl ExecutionGadget for StopGadget { ) -> Result<(), Error> { let code = block .bytecodes - .get(&call.code_hash.to_word()) + .get_bytecode(&call.code_hash) .expect("could not find current environment's bytecode"); self.code_length.assign( region, diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index 4a7ad96161..abfb6ac5cc 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -1,4 +1,6 @@ -use crate::{util, witness::BytecodeCollection}; +use bus_mapping::state_db::CodeDB; + +use crate::util; use super::*; @@ -46,7 +48,7 @@ impl BytecodeTable { pub fn load( &self, layouter: &mut impl Layouter, - bytecodes: BytecodeCollection, + bytecodes: CodeDB, ) -> Result<(), Error> { layouter.assign_region( || "bytecode table", diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 6b0b2d2bd0..bcf731dd6a 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -4,8 +4,6 @@ mod block; pub use block::{block_convert, Block, BlockContext}; -mod bytecode; -pub use bytecode::BytecodeCollection; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index 74967512a6..540f801900 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -1,4 +1,4 @@ -use super::{BytecodeCollection, ExecStep, Rw, RwMap, Transaction}; +use super::{ExecStep, Rw, RwMap, Transaction}; use crate::{ evm_circuit::{detect_fixed_table_tags, EvmCircuit}, exp_circuit::param::OFFSET_INCREMENT, @@ -8,6 +8,7 @@ use crate::{ }; use bus_mapping::{ circuit_input_builder::{self, CopyEvent, ExpEvent, FixedCParams}, + state_db::CodeDB, Error, }; use eth_types::{Address, Field, ToScalar, Word}; @@ -30,7 +31,7 @@ pub struct Block { /// Read write events in the RwTable pub rws: RwMap, /// Bytecode used in the block - pub bytecodes: BytecodeCollection, + pub bytecodes: CodeDB, /// The block context pub context: BlockContext, /// Copy events for the copy circuit's table. @@ -246,7 +247,7 @@ pub fn block_convert( txs: block.txs().to_vec(), end_block_not_last: block.block_steps.end_block_not_last.clone(), end_block_last: block.block_steps.end_block_last.clone(), - bytecodes: code_db.into(), + bytecodes: code_db.clone(), copy_events: block.copy_events.clone(), exp_events: block.exp_events.clone(), sha3_inputs: block.sha3_inputs.clone(), diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs deleted file mode 100644 index 0eadcfce90..0000000000 --- a/zkevm-circuits/src/witness/bytecode.rs +++ /dev/null @@ -1,55 +0,0 @@ -use bus_mapping::state_db::CodeDB; -use eth_types::{Bytecode, Word}; -use itertools::Itertools; -use std::collections::HashMap; - -/// A collection of bytecode to prove -#[derive(Clone, Debug, Default)] -pub struct BytecodeCollection { - codes: HashMap, -} - -impl BytecodeCollection { - /// Compute number of rows required for bytecode table. - pub fn num_rows_required_for_bytecode_table(&self) -> usize { - self.codes - .values() - .map(|bytecode| bytecode.codesize() + 1) - .sum() - } - /// Query code by hash - pub fn get(&self, codehash: &Word) -> Option { - self.codes.get(codehash).cloned() - } - - /// Get raw bytes - pub fn to_raw(&self) -> Vec> { - self.codes.values().map(|code| code.code()).collect_vec() - } -} - -impl From<&CodeDB> for BytecodeCollection { - fn from(_code_db: &CodeDB) -> Self { - todo!() - } -} - -impl From>> for BytecodeCollection { - fn from(bytecodes: Vec>) -> Self { - Self { - codes: HashMap::from_iter(bytecodes.iter().map(|bytecode| { - let code = Bytecode::from(bytecode.clone()); - (code.hash(), code) - })), - } - } -} - -impl IntoIterator for BytecodeCollection { - type Item = Bytecode; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.codes.values().cloned().collect_vec().into_iter() - } -} From 4565ce0dee4c37854659180ef4212a3a494ed225 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 14 Jul 2023 00:08:57 +0800 Subject: [PATCH 28/37] minor --- .../src/evm_circuit/execution/error_invalid_jump.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index e21861d5de..451844e9bf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -139,16 +139,16 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { // set default value in case can not find value, is_code from bytecode table let dest = usize::try_from(dest).unwrap_or(code.codesize()); - let code_pair = code.get(dest).unwrap_or((0, false)); + let (value, is_code) = code.get(dest).unwrap_or((0, false)); self.value - .assign(region, offset, Value::known(F::from(code_pair.0 as u64)))?; + .assign(region, offset, Value::known(F::from(value.into())))?; self.is_code - .assign(region, offset, Value::known(F::from(code_pair.1.into())))?; + .assign(region, offset, Value::known(F::from(is_code.into())))?; self.is_jump_dest.assign( region, offset, - F::from(code_pair.0 as u64), + F::from(value.into()), F::from(OpcodeId::JUMPDEST.as_u64()), )?; From 12708286c7d12140bbb6a841860ddd88d38172aa Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 14 Jul 2023 00:43:12 +0800 Subject: [PATCH 29/37] minor --- zkevm-circuits/src/table/bytecode_table.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index abfb6ac5cc..3599180297 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -1,8 +1,6 @@ -use bus_mapping::state_db::CodeDB; - -use crate::util; - use super::*; +use crate::util; +use bus_mapping::state_db::CodeDB; /// Tag to identify the field in a Bytecode Table row #[derive(Clone, Copy, Debug)] From f51adcc9e48a297c2c394b0fda93d68ac53053a9 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 14 Jul 2023 01:10:00 +0800 Subject: [PATCH 30/37] fixed mock 1 Ether --- zkevm-circuits/src/evm_circuit/execution/callop.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 2c6b176745..24cbca9417 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -844,7 +844,12 @@ mod test { .write_op(terminator) }); - Account::mock_100_ether(bytecode) + Account { + address: Address::repeat_byte(0xfe), + balance: Word::from(10).pow(18.into()), // 1 Ether + code: bytecode.into(), + ..Default::default() + } } fn test_nested(opcode: &OpcodeId) { From a518f8cca6156ded01a69f543ca62d68f8ed1ffb Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 21 Jul 2023 12:18:37 +0200 Subject: [PATCH 31/37] rm to_raw --- bus-mapping/src/circuit_input_builder.rs | 4 ++-- bus-mapping/src/state_db.rs | 5 ----- zkevm-circuits/src/bytecode_circuit/circuit.rs | 2 +- zkevm-circuits/src/bytecode_circuit/dev.rs | 14 +++++++++++--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index babebbee8d..6f83e6d13e 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -437,8 +437,8 @@ pub fn keccak_inputs(block: &Block, code_db: &CodeDB) -> Result>, Er let txs: Vec = block.txs.iter().map(|tx| tx.deref().clone()).collect(); keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit(&txs, block.chain_id.as_u64())?); // Bytecode Circuit - for bytecode in code_db.to_raw() { - keccak_inputs.push(bytecode.clone()); + for bytecode in code_db.clone().into_iter() { + keccak_inputs.push(bytecode.code()); } // EVM Circuit keccak_inputs.extend_from_slice(&block.sha3_inputs); diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index e884063340..58a5ab1754 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -62,11 +62,6 @@ impl CodeDB { pub fn get_from_word(&self, codehash: &Word) -> Option { self.get_bytecode(&H256::from_uint(codehash)) } - - /// Get raw bytes - pub fn to_raw(&self) -> Vec> { - self.0.values().cloned().collect_vec() - } } impl From>> for CodeDB { diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 1ac7bda665..5a645c282f 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -126,7 +126,7 @@ impl From> for BytecodeCircuitAssignment { impl From for BytecodeCircuitAssignment { fn from(code_db: CodeDB) -> Self { // CodeDB use hash maps, so the bytecodes will be reordered. - code_db.to_raw().into() + code_db.into_iter().collect_vec().into() } } diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index 9810a07873..71ccb42c00 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -10,6 +10,7 @@ use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, plonk::{Circuit, ConstraintSystem, Error}, }; +use itertools::Itertools; impl Circuit for BytecodeCircuit { type Config = (BytecodeCircuitConfig, Challenges); @@ -47,9 +48,16 @@ impl Circuit for BytecodeCircuit { ) -> Result<(), Error> { let challenges = challenges.values(&mut layouter); - config - .keccak_table - .dev_load(&mut layouter, &self.bytecodes.to_raw(), &challenges)?; + config.keccak_table.dev_load( + &mut layouter, + &self + .bytecodes + .clone() + .into_iter() + .map(|b| b.code()) + .collect_vec(), + &challenges, + )?; self.synthesize_sub(&config, &challenges, &mut layouter)?; Ok(()) } From 4c1b6d3e144499874139219f0ed3e742c59d5831 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Fri, 21 Jul 2023 12:52:31 +0200 Subject: [PATCH 32/37] prevent double copy --- testool/src/statetest/executor.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index c676b6bc3c..86100dc018 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -77,19 +77,19 @@ fn check_post( } if let Some(expected_code) = &expected.code { - let actual_code = if actual.code_hash.is_zero() { - vec![] - } else { - builder - .code_db - .get(&actual.code_hash) - .cloned() - .expect("code exists") - }; - if &actual_code as &[u8] != expected_code.0 { + let actual_code = (!actual.code_hash.is_zero()) + .then(|| { + builder + .code_db + .get(&actual.code_hash) + .cloned() + .expect("code exists") + }) + .unwrap_or_default(); + if actual_code != expected_code.0 { return Err(StateTestError::CodeMismatch { expected: expected_code.clone(), - found: Bytes::from(actual_code.to_vec()), + found: Bytes::from(actual_code), }); } } From 4d5ade22d90c97adc664abb8a71ee804bf2d97c7 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Mon, 24 Jul 2023 16:08:42 +0200 Subject: [PATCH 33/37] rename to get_from_u256 and get_from_h256 --- bus-mapping/src/state_db.rs | 6 +++--- zkevm-circuits/src/evm_circuit/execution/codecopy.rs | 2 +- .../src/evm_circuit/execution/error_invalid_jump.rs | 2 +- zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs | 2 +- zkevm-circuits/src/evm_circuit/execution/stop.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 58a5ab1754..cee238dbda 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -54,13 +54,13 @@ impl CodeDB { } /// Query Bytecode by H256 - pub fn get_bytecode(&self, codehash: &H256) -> Option { + pub fn get_from_h256(&self, codehash: &H256) -> Option { self.0.get(codehash).cloned().map(|code| code.into()) } /// Query Bytecode by U256 - pub fn get_from_word(&self, codehash: &Word) -> Option { - self.get_bytecode(&H256::from_uint(codehash)) + pub fn get_from_u256(&self, codehash: &Word) -> Option { + self.get_from_h256(&H256::from_uint(codehash)) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index d1c1860d52..f0c192852d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -159,7 +159,7 @@ impl ExecutionGadget for CodeCopyGadget { let bytecode = block .bytecodes - .get_bytecode(&call.code_hash) + .get_from_h256(&call.code_hash) .expect("could not find current environment's bytecode"); let code_size = bytecode.codesize() as u64; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 451844e9bf..44c4b6759b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -128,7 +128,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { let code = block .bytecodes - .get_bytecode(&call.code_hash) + .get_from_h256(&call.code_hash) .expect("could not find current environment's bytecode"); let code_len = code.codesize() as u64; self.code_len diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 060ca78f3d..803a9fc050 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -209,7 +209,7 @@ impl ExecutionGadget for ExtcodecopyGadget { } else { block .bytecodes - .get_from_word(&code_hash) + .get_from_u256(&code_hash) .expect("could not find external bytecode") .codesize() as u64 }; diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index e2d4cbe88d..d29a9c23c5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -108,7 +108,7 @@ impl ExecutionGadget for StopGadget { ) -> Result<(), Error> { let code = block .bytecodes - .get_bytecode(&call.code_hash) + .get_from_h256(&call.code_hash) .expect("could not find current environment's bytecode"); self.code_length.assign( region, From dc2a85be0c5bcd268593782f3d164981aeb120cc Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Mon, 24 Jul 2023 16:14:51 +0200 Subject: [PATCH 34/37] rm get --- bus-mapping/src/circuit_input_builder/input_state_ref.rs | 4 ++-- bus-mapping/src/state_db.rs | 5 ----- testool/src/statetest/executor.rs | 4 ++-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index eb62e37785..6ddc4d0f3b 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -614,8 +614,8 @@ impl<'a> CircuitInputStateRef<'a> { /// Fetch and return code for the given code hash from the code DB. pub fn code(&self, code_hash: H256) -> Result, Error> { self.code_db - .get(&code_hash) - .cloned() + .get_from_h256(&code_hash) + .map(|bytecode| bytecode.code()) .ok_or(Error::CodeNotFound(code_hash)) } diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index cee238dbda..eb47ba787d 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -48,11 +48,6 @@ impl CodeDB { self.0.values().map(|bytecode| bytecode.len() + 1).sum() } - /// Query code in raw bytes by H256 - pub fn get(&self, codehash: &H256) -> Option<&Vec> { - self.0.get(codehash) - } - /// Query Bytecode by H256 pub fn get_from_h256(&self, codehash: &H256) -> Option { self.0.get(codehash).cloned().map(|code| code.into()) diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 86100dc018..e46dbdcfeb 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -81,8 +81,8 @@ fn check_post( .then(|| { builder .code_db - .get(&actual.code_hash) - .cloned() + .get_from_h256(&actual.code_hash) + .map(|bytecode| bytecode.code()) .expect("code exists") }) .unwrap_or_default(); From 6b5574b4088e6af0203ef7eb4305e1395de09c98 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Mon, 24 Jul 2023 16:31:31 +0200 Subject: [PATCH 35/37] rm +3 --- zkevm-circuits/src/bytecode_circuit/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 77a8178046..68fc65a212 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -228,7 +228,8 @@ fn bytecode_soundness_bug_1() { let mut index = bytecode_len as u64; let size = 100; let minimum_rows = 8; - for i in rows.len()..size - minimum_rows + 3 { + let len = rows.len(); + for i in len..size - minimum_rows { rows.push(BytecodeCircuitRow::new( code_hash, Fr::ONE, From 3abae63164b50f50dc986a2c7735e149891fa433 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Mon, 24 Jul 2023 16:38:25 +0200 Subject: [PATCH 36/37] doc store_code_to_mem and pad only zeros --- eth-types/src/bytecode.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index b31935fb89..d822a22230 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -1,6 +1,6 @@ //! EVM byte code generator use crate::{evm_types::OpcodeId, keccak256, Bytes, Hash, ToBigEndian, ToWord, Word}; -use std::{collections::HashMap, str::FromStr}; +use std::{collections::HashMap, iter, str::FromStr}; /// Error type for Bytecode related failures #[derive(Debug)] @@ -188,7 +188,7 @@ impl Bytecode { self.code.len() } - /// Store another code to memory + /// Append the instructions to store another code to memory pub fn store_code_to_mem(&mut self, code: &Self) { let len = code.codesize(); // pad to multiple of 32 bytes @@ -196,7 +196,7 @@ impl Bytecode { .code() .iter() .cloned() - .chain(0u8..((32 - len % 32) as u8)) + .chain(iter::repeat(0).take(32 - len % 32)) .collect(); for (index, word) in code.chunks(32).enumerate() { From 2228e4deddf92d028661343e05c4af08285eda04 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Mon, 24 Jul 2023 16:45:30 +0200 Subject: [PATCH 37/37] rename mock_code_balance --- eth-types/src/geth_types.rs | 4 ++-- zkevm-circuits/src/evm_circuit/execution/callop.rs | 2 +- .../src/evm_circuit/execution/error_invalid_jump.rs | 2 +- zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs | 2 +- .../src/evm_circuit/execution/error_oog_constant.rs | 2 +- zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs | 2 +- zkevm-circuits/src/evm_circuit/execution/error_stack.rs | 2 +- .../src/evm_circuit/execution/error_write_protection.rs | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index e7d25696d1..66323c04d7 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -45,8 +45,8 @@ impl Account { && self.storage.is_empty() } - /// Generate an account that has either code or balance - pub fn mock_code_or_balance(code: Bytecode) -> Self { + /// Generate an account that is either empty or has code, balance, and non-zero nonce + pub fn mock_code_balance(code: Bytecode) -> Self { let is_empty = code.codesize() == 0; Self { address: Address::repeat_byte(0xff), diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 24cbca9417..3258fe88fe 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -779,7 +779,7 @@ mod test { } fn callee(code: bytecode::Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } fn caller(opcode: &OpcodeId, stack: Stack, caller_is_success: bool) -> Account { diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 44c4b6759b..0d4eb1e9fd 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -240,7 +240,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } // jump or jumpi error happen in internal call diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index 0044e4eb20..f2f884e293 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -273,7 +273,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } fn test_oog(caller: &Account, callee: &Account, is_root: bool) { diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs index d367a2c39e..01e12c3a00 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -238,7 +238,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } #[test] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index 4af29dbef0..dd4ef88ad0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -279,7 +279,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } #[test] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs index dfc9a537b0..60235e8fce 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs @@ -211,7 +211,7 @@ mod test { } fn callee(code: Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } // internal call error test diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index e83986e7b3..6182e413d5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -149,7 +149,7 @@ mod test { use mock::TestContext; fn callee(code: Bytecode) -> Account { - Account::mock_code_or_balance(code) + Account::mock_code_balance(code) } #[test]