diff --git a/Cargo.lock b/Cargo.lock index 223cbc8a90..1b049f1007 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1426,6 +1426,7 @@ dependencies = [ "revm-primitives", "serde", "serde_json", + "serde_stacker", "serde_with", "sha3 0.10.8", "strum 0.25.0", diff --git a/bus-mapping/src/circuit_input_builder/l2.rs b/bus-mapping/src/circuit_input_builder/l2.rs index d2ad7544ed..aa2f0a1b26 100644 --- a/bus-mapping/src/circuit_input_builder/l2.rs +++ b/bus-mapping/src/circuit_input_builder/l2.rs @@ -5,9 +5,9 @@ use crate::{ }; use eth_types::{ self, - l2_types::{BlockTrace, StorageTrace}, + l2_types::{trace::collect_codes, BlockTrace, StorageTrace}, state_db::{self, CodeDB, StateDB}, - Address, EthBlock, ToWord, Word, + Address, EthBlock, ToWord, Word, H256, }; use ethers_core::types::Bytes; use mpt_zktrie::state::ZktrieState; @@ -86,7 +86,7 @@ impl CircuitInputBuilder { fn collect_storage_proofs( storage_trace: &StorageTrace, - ) -> impl Iterator)> + Clone { + ) -> impl Iterator)> + Clone { storage_trace.storage_proofs.iter().flat_map(|(k, kv_map)| { kv_map .iter() @@ -161,12 +161,17 @@ impl CircuitInputBuilder { &l2_trace.storage_trace, )) { let ((addr, key), val) = parsed.map_err(Error::IoError)?; + let key = key.to_word(); *sdb.get_storage_mut(&addr, &key).1 = val.into(); } let mut code_db = CodeDB::new(); code_db.insert(Vec::new()); - code_db.update_codedb(&sdb, &l2_trace)?; + + let codes = collect_codes(&l2_trace, Some(&sdb))?; + for (hash, code) in codes { + code_db.insert_with_hash(hash, code); + } let mut builder_block = circuit_input_builder::Blocks::init(chain_id, circuits_params); builder_block.prev_state_root = old_root.to_word(); @@ -219,7 +224,8 @@ impl CircuitInputBuilder { let new_storages = ZktrieState::parse_storage_from_proofs( Self::collect_storage_proofs(&l2_trace.storage_trace).filter(|(addr, key, _)| { - let (existed, _) = self.sdb.get_committed_storage(addr, key); + let key = key.to_word(); + let (existed, _) = self.sdb.get_committed_storage(addr, &key); !existed }), ) @@ -227,7 +233,7 @@ impl CircuitInputBuilder { HashMap::new(), |mut m, parsed| -> Result, Error> { let ((addr, key), val) = parsed.map_err(Error::IoError)?; - m.insert((addr, key), val.into()); + m.insert((addr, key.to_word()), val.into()); Ok(m) }, )?; @@ -236,7 +242,10 @@ impl CircuitInputBuilder { *self.sdb.get_storage_mut(&addr, &key).1 = val; } - self.code_db.update_codedb(&self.sdb, &l2_trace)?; + let codes = collect_codes(&l2_trace, Some(&self.sdb))?; + for (hash, code) in codes { + self.code_db.insert_with_hash(hash, code); + } self.apply_l2_trace(l2_trace)?; Ok(()) diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index 82904ec0b0..3c0de80323 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -12,7 +12,8 @@ halo2curves.workspace = true log.workspace = true regex.workspace = true serde.workspace = true -serde_json.workspace = true +serde_json = { workspace = true, features = ["unbounded_depth"] } +serde_stacker.workspace = true serde_with = "1.12" uint = "0.9.1" itertools.workspace = true diff --git a/eth-types/src/l2_types.rs b/eth-types/src/l2_types.rs index f8075dfbfc..b54b4c6cfa 100644 --- a/eth-types/src/l2_types.rs +++ b/eth-types/src/l2_types.rs @@ -3,14 +3,19 @@ use crate::{ evm_types::{Gas, GasCost, OpcodeId, ProgramCounter}, EthBlock, GethCallTrace, GethExecError, GethExecStep, GethExecTrace, GethPrestateTrace, Hash, - ToBigEndian, Transaction, Word, H256, + ToBigEndian, Transaction, H256, }; use ethers_core::types::{ transaction::eip2930::{AccessList, AccessListItem}, Address, Bytes, U256, U64, }; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use trace::collect_codes; + +/// Trace related helpers +pub mod trace; #[cfg(feature = "enable-memory")] use crate::evm_types::Memory; @@ -19,9 +24,64 @@ use crate::evm_types::Stack; #[cfg(feature = "enable-storage")] use crate::evm_types::Storage; +/// l2 block full trace +#[derive(Deserialize, Serialize, Default, Debug, Clone)] +pub struct BlockTraceV2 { + /// chain id + #[serde(rename = "chainID", default)] + pub chain_id: u64, + /// coinbase's status AFTER execution + pub coinbase: AccountProofWrapper, + /// block + pub header: EthBlock, + /// txs + pub transactions: Vec, + /// Accessed bytecodes with hashes + pub codes: Vec, + /// storage trace BEFORE execution + #[serde(rename = "storageTrace")] + pub storage_trace: StorageTrace, + /// l1 tx queue + #[serde(rename = "startL1QueueIndex", default)] + pub start_l1_queue_index: u64, +} + +impl From for BlockTraceV2 { + fn from(b: BlockTrace) -> Self { + let codes = collect_codes(&b, None) + .expect("collect codes should not fail") + .into_iter() + .map(|(hash, code)| BytecodeTrace { + hash, + code: code.into(), + }) + .collect_vec(); + BlockTraceV2 { + codes, + chain_id: b.chain_id, + coinbase: b.coinbase, + header: b.header, + transactions: b.transactions, + storage_trace: b.storage_trace, + start_l1_queue_index: b.start_l1_queue_index, + } + } +} + +/// Bytecode +#[derive(Deserialize, Serialize, Default, Debug, Clone)] +pub struct BytecodeTrace { + /// poseidon code hash + pub hash: H256, + /// bytecode + pub code: Bytes, +} + /// l2 block full trace #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct BlockTrace { + /// Version string + pub version: String, /// chain id #[serde(rename = "chainID", default)] pub chain_id: u64, @@ -34,6 +94,9 @@ pub struct BlockTrace { /// execution results #[serde(rename = "executionResults")] pub execution_results: Vec, + /// Accessed bytecodes with hashes + #[serde(default)] + pub codes: Vec, /// storage trace BEFORE execution #[serde(rename = "storageTrace")] pub storage_trace: StorageTrace, @@ -87,6 +150,30 @@ impl From<&BlockTrace> for EthBlock { } } +impl From<&BlockTraceV2> for revm_primitives::BlockEnv { + fn from(block: &BlockTraceV2) -> Self { + revm_primitives::BlockEnv { + number: revm_primitives::U256::from(block.header.number.unwrap().as_u64()), + coinbase: block.coinbase.address.unwrap().0.into(), + timestamp: revm_primitives::U256::from_be_bytes(block.header.timestamp.to_be_bytes()), + gas_limit: revm_primitives::U256::from_be_bytes(block.header.gas_limit.to_be_bytes()), + basefee: revm_primitives::U256::from_be_bytes( + block + .header + .base_fee_per_gas + .unwrap_or_default() + .to_be_bytes(), + ), + difficulty: revm_primitives::U256::from_be_bytes(block.header.difficulty.to_be_bytes()), + prevrandao: block + .header + .mix_hash + .map(|h| revm_primitives::B256::from(h.to_fixed_bytes())), + blob_excess_gas_and_price: None, + } + } +} + impl From<&BlockTrace> for revm_primitives::BlockEnv { fn from(block: &BlockTrace) -> Self { revm_primitives::BlockEnv { @@ -247,7 +334,7 @@ impl From<&TransactionTrace> for revm_primitives::TxEnv { /// account trie proof in storage proof pub type AccountTrieProofs = HashMap>; /// storage trie proof in storage proof -pub type StorageTrieProofs = HashMap>>; +pub type StorageTrieProofs = HashMap>>; /// storage trace #[derive(Deserialize, Serialize, Default, Debug, Clone)] @@ -337,11 +424,11 @@ pub struct ExecStep { pub depth: isize, pub error: Option, #[cfg(feature = "enable-stack")] - pub stack: Option>, + pub stack: Option>, #[cfg(feature = "enable-memory")] - pub memory: Option>, + pub memory: Option>, #[cfg(feature = "enable-storage")] - pub storage: Option>, + pub storage: Option>, #[serde(rename = "extraData")] pub extra_data: Option, } @@ -402,6 +489,8 @@ pub struct AccountProofWrapper { pub keccak_code_hash: Option, #[serde(rename = "poseidonCodeHash")] pub poseidon_code_hash: Option, + #[serde(rename = "codeSize")] + pub code_size: u64, pub storage: Option, } @@ -412,3 +501,15 @@ pub struct StorageProofWrapper { pub key: Option, pub value: Option, } + +#[ignore] +#[test] +fn test_block_trace_convert() { + let trace_v1: BlockTrace = + crate::utils::from_json_file("src/testdata/trace_v1_5224657.json").expect("should load"); + let trace_v2: BlockTraceV2 = trace_v1.into(); + let mut fd = std::fs::File::create("src/testdata/trace_v2_5224657.json").unwrap(); + serde_json::to_writer_pretty(&mut fd, &trace_v2).unwrap(); + // then we can use this command to compare the traces: + // vimdiff <(jq -S "del(.executionResults)|del(.txStorageTraces)" src/testdata/trace_v1_5224657.json) <(jq -S . src/testdata/trace_v2_5224657.json) +} diff --git a/eth-types/src/l2_types/trace.rs b/eth-types/src/l2_types/trace.rs new file mode 100644 index 0000000000..aa7fb030de --- /dev/null +++ b/eth-types/src/l2_types/trace.rs @@ -0,0 +1,188 @@ +use crate::{ + evm_types::OpcodeId, + l2_types::BlockTrace, + state_db::{CodeDB, StateDB}, + utils::is_precompiled, + Address, Error, H256, +}; +use ethers_core::types::Bytes; +use itertools::Itertools; + +/// Update codedb from statedb and trace +pub fn collect_codes( + block: &BlockTrace, + sdb: Option<&StateDB>, +) -> Result)>, Error> { + if !block.codes.is_empty() { + log::debug!("codes available in trace, skip collecting"); + return Ok(block + .codes + .iter() + .map(|b| (b.hash, b.code.to_vec())) + .collect_vec()); + } + + log::debug!("collect_codes for block {:?}", block.header.number); + if sdb.is_none() { + log::warn!("collect_codes without sdb can be slow"); + } + let mut codes = Vec::new(); + for (er_idx, execution_result) in block.execution_results.iter().enumerate() { + if let Some(bytecode) = &execution_result.byte_code { + let bytecode = decode_bytecode(bytecode)?.to_vec(); + + let code_hash = execution_result + .to + .as_ref() + .and_then(|t| t.poseidon_code_hash) + .unwrap_or_else(|| CodeDB::hash(&bytecode)); + let code_hash = if code_hash.is_zero() { + CodeDB::hash(&bytecode) + } else { + code_hash + }; + codes.push((code_hash, bytecode)); + //log::debug!("inserted tx bytecode {:?} {:?}", code_hash, hash); + } + + // filter all precompile calls, empty calls and create + let mut call_trace = execution_result + .call_trace + .flatten_trace(&execution_result.prestate) + .into_iter() + .filter(|call| { + let is_call_to_precompile = call.to.as_ref().map(is_precompiled).unwrap_or(false); + let is_call_to_empty = call.gas_used.is_zero() + && !call.call_type.is_create() + && call.is_callee_code_empty; + !(is_call_to_precompile || is_call_to_empty || call.call_type.is_create()) + }) + .collect::>(); + //log::trace!("call_trace: {call_trace:?}"); + + for (idx, step) in execution_result.exec_steps.iter().enumerate().rev() { + if step.op.is_create() { + continue; + } + let call = if step.op.is_call_or_create() { + // filter call to empty/precompile/!precheck_ok + if let Some(next_step) = execution_result.exec_steps.get(idx + 1) { + // the call doesn't have inner steps, it could be: + // - a call to a precompiled contract + // - a call to an empty account + // - a call that !is_precheck_ok + if next_step.depth != step.depth + 1 { + log::trace!("skip call step due to no inner step, curr: {step:?}, next: {next_step:?}"); + continue; + } + } else { + // this is the final step, no inner steps + log::trace!("skip call step due this is the final step: {step:?}"); + continue; + } + let call = call_trace.pop(); + //log::trace!("call_trace pop: {call:?}, current step: {step:?}"); + call + } else { + None + }; + + if let Some(data) = &step.extra_data { + match step.op { + OpcodeId::CALL + | OpcodeId::CALLCODE + | OpcodeId::DELEGATECALL + | OpcodeId::STATICCALL => { + let call = call.unwrap(); + assert_eq!(call.call_type, step.op, "{call:?}"); + let code_idx = if block.transactions[er_idx].to.is_none() { + 0 + } else { + 1 + }; + let callee_code = data.get_code_at(code_idx); + let code_hash = match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => data.get_code_hash_at(1), + OpcodeId::STATICCALL => data.get_code_hash_at(0), + _ => None, + }; + let addr = call.to.unwrap(); + trace_code( + &mut codes, + code_hash, + callee_code.unwrap_or_default(), + Some(addr), + sdb, + ); + } + OpcodeId::EXTCODECOPY => { + let code = data.get_code_at(0); + if code.is_none() { + log::warn!("unable to fetch code from step. {step:?}"); + continue; + } + trace_code(&mut codes, None, code.unwrap(), None, sdb); + } + + _ => {} + } + } + } + } + + log::debug!("collect codes done"); + Ok(codes) +} + +fn trace_code( + codes: &mut Vec<(H256, Vec)>, + code_hash: Option, + code: Bytes, + addr: Option
, + // sdb is used to read codehash if available without recomputing + sdb: Option<&StateDB>, +) { + let code_hash = code_hash.or_else(|| { + let addr = addr?; + let sdb = sdb.as_ref()?; + let (_existed, acc_data) = sdb.get_account(&addr); + if acc_data.code_hash != CodeDB::empty_code_hash() && !code.is_empty() { + Some(acc_data.code_hash) + } else { + None + } + }); + let code_hash = match code_hash { + Some(code_hash) if !code_hash.is_zero() => code_hash, + _ => { + let hash = CodeDB::hash(&code); + log::debug!( + "hash_code done: addr {addr:?}, size {}, hash {hash:?}", + &code.len() + ); + hash + } + }; + codes.push((code_hash, code.to_vec())); + log::trace!( + "trace code addr {:?}, size {} hash {:?}", + addr, + &code.len(), + code_hash + ); +} + +fn decode_bytecode(bytecode: &str) -> Result, Error> { + let mut stripped = if let Some(stripped) = bytecode.strip_prefix("0x") { + stripped.to_string() + } else { + bytecode.to_string() + }; + + let bytecode_len = stripped.len() as u64; + if (bytecode_len & 1) != 0 { + stripped = format!("0{stripped}"); + } + + hex::decode(stripped).map_err(Error::HexError) +} diff --git a/eth-types/src/state_db.rs b/eth-types/src/state_db.rs index ff9ab78976..b08104ad0a 100644 --- a/eth-types/src/state_db.rs +++ b/eth-types/src/state_db.rs @@ -10,9 +10,6 @@ use std::{ sync::LazyLock, }; -#[cfg(feature = "scroll")] -mod l2; - static ACCOUNT_ZERO: LazyLock = LazyLock::new(Account::zero); /// Hash value for empty code hash. static EMPTY_CODE_HASH: LazyLock = LazyLock::new(|| CodeDB::hash(&[])); @@ -48,11 +45,14 @@ impl CodeDB { codedb.insert(Vec::new()); codedb } - /// Insert code indexed by code hash, and return the code hash. + /// Insert code along with code hash + pub fn insert_with_hash(&mut self, hash: H256, code: Vec) { + self.0.insert(hash, code); + } + /// Insert code to CodeDB, and return the code hash. pub fn insert(&mut self, code: Vec) -> Hash { let hash = Self::hash(&code); - - self.0.insert(hash, code); + self.insert_with_hash(hash, code); hash } /// Specify code hash for empty code (nil) diff --git a/eth-types/src/state_db/l2.rs b/eth-types/src/state_db/l2.rs deleted file mode 100644 index 93a089d5b7..0000000000 --- a/eth-types/src/state_db/l2.rs +++ /dev/null @@ -1,224 +0,0 @@ -use super::{CodeDB, StateDB}; -use crate::{ - evm_types::OpcodeId, - l2_types::{BlockTrace, ExecStep}, - utils::is_precompiled, - Address, Error, H256, -}; -use ethers_core::types::Bytes; -use std::collections::hash_map::Entry; - -impl CodeDB { - /// Update codedb from statedb and trace - pub fn update_codedb(&mut self, sdb: &StateDB, block: &BlockTrace) -> Result<(), Error> { - log::debug!("build_codedb for block {:?}", block.header.number); - for (er_idx, execution_result) in block.execution_results.iter().enumerate() { - if let Some(bytecode) = &execution_result.byte_code { - let bytecode = decode_bytecode(bytecode)?.to_vec(); - - let code_hash = execution_result - .to - .as_ref() - .and_then(|t| t.poseidon_code_hash) - .unwrap_or_else(|| CodeDB::hash(&bytecode)); - let code_hash = if code_hash.is_zero() { - CodeDB::hash(&bytecode) - } else { - code_hash - }; - if let Entry::Vacant(e) = self.0.entry(code_hash) { - e.insert(bytecode); - //log::debug!("inserted tx bytecode {:?} {:?}", code_hash, hash); - } - if execution_result.account_created.is_none() { - //assert_eq!(Some(hash), execution_result.code_hash); - } - } - - // filter all precompile calls, empty calls and create - let mut call_trace = execution_result - .call_trace - .flatten_trace(&execution_result.prestate) - .into_iter() - .filter(|call| { - let is_call_to_precompile = - call.to.as_ref().map(is_precompiled).unwrap_or(false); - let is_call_to_empty = call.gas_used.is_zero() - && !call.call_type.is_create() - && call.is_callee_code_empty; - !(is_call_to_precompile || is_call_to_empty || call.call_type.is_create()) - }) - .collect::>(); - //log::trace!("call_trace: {call_trace:?}"); - - for (idx, step) in execution_result.exec_steps.iter().enumerate().rev() { - if step.op.is_create() { - continue; - } - let call = if step.op.is_call_or_create() { - // filter call to empty/precompile/!precheck_ok - if let Some(next_step) = execution_result.exec_steps.get(idx + 1) { - // the call doesn't have inner steps, it could be: - // - a call to a precompiled contract - // - a call to an empty account - // - a call that !is_precheck_ok - if next_step.depth != step.depth + 1 { - log::trace!("skip call step due to no inner step, curr: {step:?}, next: {next_step:?}"); - continue; - } - } else { - // this is the final step, no inner steps - log::trace!("skip call step due this is the final step: {step:?}"); - continue; - } - let call = call_trace.pop(); - //log::trace!("call_trace pop: {call:?}, current step: {step:?}"); - call - } else { - None - }; - - if let Some(data) = &step.extra_data { - match step.op { - OpcodeId::CALL - | OpcodeId::CALLCODE - | OpcodeId::DELEGATECALL - | OpcodeId::STATICCALL => { - let call = call.unwrap(); - assert_eq!(call.call_type, step.op, "{call:?}"); - let code_idx = if block.transactions[er_idx].to.is_none() { - 0 - } else { - 1 - }; - let callee_code = data.get_code_at(code_idx); - // TODO: make nil code ("0x") is not None and assert None case - // assert!( - // callee_code.is_none(), - // "invalid trace: cannot get code of call: {step:?}" - // ); - let code_hash = match step.op { - OpcodeId::CALL | OpcodeId::CALLCODE => data.get_code_hash_at(1), - OpcodeId::STATICCALL => data.get_code_hash_at(0), - _ => None, - }; - let addr = call.to.unwrap(); - self.trace_code( - code_hash, - callee_code.unwrap_or_default(), - step, - Some(addr), - sdb, - ); - } - OpcodeId::CREATE | OpcodeId::CREATE2 => { - // notice we do not need to insert code for CREATE, - // bustmapping do this job - unreachable!() - } - OpcodeId::EXTCODECOPY => { - let code = data.get_code_at(0); - if code.is_none() { - log::warn!("unable to fetch code from step. {step:?}"); - continue; - } - self.trace_code(None, code.unwrap(), step, None, sdb); - } - - _ => {} - } - } - } - } - - log::debug!("updating codedb done"); - Ok(()) - } - - fn trace_code( - &mut self, - code_hash: Option, - code: Bytes, - step: &ExecStep, - addr: Option
, - sdb: &StateDB, - ) { - // first, try to read from sdb - // let stack = match step.stack.as_ref() { - // Some(stack) => stack, - // None => { - // log::error!("stack underflow, step {step:?}"); - // return; - // } - // }; - // if stack_pos >= stack.len() { - // log::error!("stack underflow, step {step:?}"); - // return; - // } - // let addr = stack[stack.len() - stack_pos - 1].to_address(); //stack N-stack_pos - // - let code_hash = code_hash.or_else(|| { - addr.and_then(|addr| { - let (_existed, acc_data) = sdb.get_account(&addr); - if acc_data.code_hash != CodeDB::empty_code_hash() && !code.is_empty() { - // they must be same - Some(acc_data.code_hash) - } else { - // let us re-calculate it - None - } - }) - }); - let code_hash = match code_hash { - Some(code_hash) => { - if code_hash.is_zero() { - CodeDB::hash(&code) - } else { - if log::log_enabled!(log::Level::Trace) { - assert_eq!( - code_hash, - CodeDB::hash(&code), - "bytecode len {:?}, step {:?}", - code.len(), - step - ); - } - code_hash - } - } - None => { - let hash = CodeDB::hash(&code); - log::debug!( - "hash_code done: addr {addr:?}, size {}, hash {hash:?}", - &code.len() - ); - hash - } - }; - - self.0.entry(code_hash).or_insert_with(|| { - log::trace!( - "trace code addr {:?}, size {} hash {:?}", - addr, - &code.len(), - code_hash - ); - code.to_vec() - }); - } -} - -fn decode_bytecode(bytecode: &str) -> Result, Error> { - let mut stripped = if let Some(stripped) = bytecode.strip_prefix("0x") { - stripped.to_string() - } else { - bytecode.to_string() - }; - - let bytecode_len = stripped.len() as u64; - if (bytecode_len & 1) != 0 { - stripped = format!("0{stripped}"); - } - - hex::decode(stripped).map_err(Error::HexError) -} diff --git a/eth-types/src/utils.rs b/eth-types/src/utils.rs index 7abac7598e..02fe1aaed5 100644 --- a/eth-types/src/utils.rs +++ b/eth-types/src/utils.rs @@ -1,8 +1,13 @@ //! Some handy helpers -use crate::{Address, Hash}; +use crate::Address; use revm_precompile::Precompiles; +mod io; +pub use io::*; +mod codehash; +pub use codehash::*; + /// Check if address is a precompiled or not. pub fn is_precompiled(address: &Address) -> bool { #[cfg(feature = "scroll")] @@ -11,101 +16,3 @@ pub fn is_precompiled(address: &Address) -> bool { let precompiles = Precompiles::berlin(); precompiles.get(address.as_fixed_bytes().into()).is_some() } - -/// Default number of bytes to pack into a field element. -pub const POSEIDON_HASH_BYTES_IN_FIELD: usize = 31; - -/// Default code hash -pub fn hash_code(code: &[u8]) -> Hash { - #[cfg(feature = "scroll")] - return hash_code_poseidon(code); - #[cfg(not(feature = "scroll"))] - return hash_code_keccak(code); -} - -/// Keccak code hash -pub fn hash_code_keccak(code: &[u8]) -> Hash { - crate::H256(ethers_core::utils::keccak256(code)) -} - -/// Poseidon code hash -pub fn hash_code_poseidon(code: &[u8]) -> Hash { - use crate::U256; - use halo2curves::{bn256::Fr, ff::PrimeField}; - use poseidon_base::hash::{Hashable, MessageHashable, HASHABLE_DOMAIN_SPEC}; - - let bytes_in_field = POSEIDON_HASH_BYTES_IN_FIELD; - let fls = (0..(code.len() / bytes_in_field)) - .map(|i| i * bytes_in_field) - .map(|i| { - let mut buf: [u8; 32] = [0; 32]; - U256::from_big_endian(&code[i..i + bytes_in_field]).to_little_endian(&mut buf); - Fr::from_bytes(&buf).unwrap() - }); - let msgs: Vec<_> = fls - .chain(if code.len() % bytes_in_field == 0 { - None - } else { - let last_code = &code[code.len() - code.len() % bytes_in_field..]; - // pad to bytes_in_field - let mut last_buf = vec![0u8; bytes_in_field]; - last_buf.as_mut_slice()[..last_code.len()].copy_from_slice(last_code); - let mut buf: [u8; 32] = [0; 32]; - U256::from_big_endian(&last_buf).to_little_endian(&mut buf); - Some(Fr::from_bytes(&buf).unwrap()) - }) - .collect(); - - let h = if msgs.is_empty() { - // the empty code hash is overlapped with simple hash on [0, 0] - // an issue in poseidon primitive prevent us calculate it from hash_msg - Fr::hash_with_domain([Fr::zero(), Fr::zero()], Fr::zero()) - } else { - Fr::hash_msg(&msgs, Some(code.len() as u128 * HASHABLE_DOMAIN_SPEC)) - }; - - let mut buf: [u8; 32] = [0; 32]; - U256::from_little_endian(h.to_repr().as_ref()).to_big_endian(&mut buf); - Hash::from_slice(&buf) -} - -#[test] -fn test_empty_code_hash() { - assert_eq!(*crate::POSEIDON_CODE_HASH_EMPTY, hash_code_poseidon(&[])); - assert_eq!(*crate::KECCAK_CODE_HASH_EMPTY, hash_code_keccak(&[])); -} - -#[cfg(feature = "scroll")] -#[test] -fn code_hashing() { - assert_eq!( - format!("{:?}", hash_code(&[])), - "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864" - ); - - let simple_byte: [u8; 1] = [0]; - assert_eq!( - format!("{:?}", hash_code(&simple_byte)), - "0x29f94b67ee4e78b2bb08da025f9943c1201a7af025a27600c2dd0a2e71c7cf8b" - ); - - let simple_byte: [u8; 2] = [0, 1]; - assert_eq!( - format!("{:?}", hash_code(&simple_byte)), - "0x1bd41d9cc3187305de467d841b6b999d1222260b7057cb6f63d2ae92c43a7322" - ); - - let byte32: [u8; 32] = [1; 32]; - assert_eq!( - format!("{:?}", hash_code(&byte32)), - "0x0b46d156183dffdbed8e6c6b0af139b95c058e735878ca7f4dca334e0ea8bd20" - ); - - let example = "6080604052600436106100a75760003560e01c80638431f5c1116100645780638431f5c114610177578063a93a4af91461018a578063c676ad291461019d578063e77772fe146101bd578063f887ea40146101dd578063f8c8765e146101fd57600080fd5b80633cb747bf146100ac57806354bbd59c146100e8578063575361b6146101215780636c07ea43146101365780637885ef0114610149578063797594b014610151575b600080fd5b3480156100b857600080fd5b506002546100cc906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b3480156100f457600080fd5b506100cc610103366004610d51565b6001600160a01b039081166000908152600460205260409020541690565b61013461012f366004610dbe565b61021d565b005b610134610144366004610e39565b610269565b6101346102a8565b34801561015d57600080fd5b506000546100cc906201000090046001600160a01b031681565b610134610185366004610e6e565b610303565b610134610198366004610f06565b6106ad565b3480156101a957600080fd5b506100cc6101b8366004610d51565b6106c0565b3480156101c957600080fd5b506005546100cc906001600160a01b031681565b3480156101e957600080fd5b506001546100cc906001600160a01b031681565b34801561020957600080fd5b50610134610218366004610f4c565b61073b565b61026186868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892506108b5915050565b505050505050565b6102a383338460005b6040519080825280601f01601f19166020018201604052801561029c576020820181803683370190505b50856108b5565b505050565b6002546001600160a01b031633146103015760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b60448201526064015b60405180910390fd5b565b6002546001600160a01b03163381146103585760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b60448201526064016102f8565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ba9190610fbe565b6000546201000090046001600160a01b0390811691161461041d5760405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063616c6c20627920636f6e7465727061727400000000000000000060448201526064016102f8565b341561045f5760405162461bcd60e51b81526020600482015260116024820152706e6f6e7a65726f206d73672e76616c756560781b60448201526064016102f8565b6005546040516361e98ca160e01b81523060048201526001600160a01b038a8116602483015260009216906361e98ca190604401602060405180830381865afa1580156104b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d49190610fbe565b9050806001600160a01b0316886001600160a01b03161461052b5760405162461bcd60e51b81526020600482015260116024820152700d86440e8ded6cadc40dad2e6dac2e8c6d607b1b60448201526064016102f8565b506001600160a01b03878116600090815260046020526040902054606091829116610593576001600160a01b03898116600090815260046020526040902080546001600160a01b031916918c1691909117905561058a8585018661108a565b925090506105cd565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b6001600160a01b0389163b6105e6576105e6828b610b23565b6040516340c10f1960e01b81526001600160a01b038881166004830152602482018890528a16906340c10f1990604401600060405180830381600087803b15801561063057600080fd5b505af1158015610644573d6000803e3d6000fd5b50505050876001600160a01b0316896001600160a01b03168b6001600160a01b03167f165ba69f6ab40c50cade6f65431801e5f9c7d7830b7545391920db039133ba348a8a8660405161069993929190611146565b60405180910390a450505050505050505050565b6106ba8484846000610272565b50505050565b6005546040516361e98ca160e01b81523060048201526001600160a01b03838116602483015260009216906361e98ca190604401602060405180830381865afa158015610711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107359190610fbe565b92915050565b600054610100900460ff166107565760005460ff161561075a565b303b155b6107bd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102f8565b600054610100900460ff161580156107df576000805461ffff19166101011790555b6001600160a01b03841661082b5760405162461bcd60e51b81526020600482015260136024820152727a65726f20726f75746572206164647265737360681b60448201526064016102f8565b610836858585610c29565b6001600160a01b0382166108815760405162461bcd60e51b81526020600482015260126024820152717a65726f20746f6b656e20666163746f727960701b60448201526064016102f8565b600580546001600160a01b0319166001600160a01b03841617905580156108ae576000805461ff00191690555b5050505050565b600083116108fc5760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b60448201526064016102f8565b60015433906001600160a01b031681141561092a578280602001905181019061092591906111a6565b935090505b6001600160a01b0380871660009081526004602052604090205416806109925760405162461bcd60e51b815260206004820152601960248201527f6e6f20636f72726573706f6e64696e67206c3120746f6b656e0000000000000060448201526064016102f8565b604051632770a7eb60e21b81526001600160a01b03838116600483015260248201879052881690639dc29fac90604401600060405180830381600087803b1580156109dc57600080fd5b505af11580156109f0573d6000803e3d6000fd5b5050505060006384bd13b060e01b8289858a8a8a604051602401610a1996959493929190611201565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600254600054925163b2267a7b60e01b81529193506001600160a01b039081169263b2267a7b923492610a8e926201000090041690839087908b90600401611250565b6000604051808303818588803b158015610aa757600080fd5b505af1158015610abb573d6000803e3d6000fd5b5050505050826001600160a01b0316886001600160a01b0316836001600160a01b03167fd8d3a3f4ab95694bef40475997598bcf8acd3ed9617a4c1013795429414c27e88a8a8a604051610b1193929190611146565b60405180910390a45050505050505050565b600554604051637bdbcbbf60e01b81523060048201526001600160a01b0383811660248301526000921690637bdbcbbf906044016020604051808303816000875af1158015610b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9a9190610fbe565b9050600080600085806020019051810190610bb591906112a8565b925092509250836001600160a01b031663c820f146838584308a6040518663ffffffff1660e01b8152600401610bef959493929190611326565b600060405180830381600087803b158015610c0957600080fd5b505af1158015610c1d573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b038316610c7f5760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e746572706172742061646472657373000000000000000060448201526064016102f8565b6001600160a01b038116610cce5760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b60448201526064016102f8565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600280546001600160a01b031916838316179055821615610d2f57600180546001600160a01b0319166001600160a01b0384161790555b5050600160035550565b6001600160a01b0381168114610d4e57600080fd5b50565b600060208284031215610d6357600080fd5b8135610d6e81610d39565b9392505050565b60008083601f840112610d8757600080fd5b50813567ffffffffffffffff811115610d9f57600080fd5b602083019150836020828501011115610db757600080fd5b9250929050565b60008060008060008060a08789031215610dd757600080fd5b8635610de281610d39565b95506020870135610df281610d39565b945060408701359350606087013567ffffffffffffffff811115610e1557600080fd5b610e2189828a01610d75565b979a9699509497949695608090950135949350505050565b600080600060608486031215610e4e57600080fd5b8335610e5981610d39565b95602085013595506040909401359392505050565b600080600080600080600060c0888a031215610e8957600080fd5b8735610e9481610d39565b96506020880135610ea481610d39565b95506040880135610eb481610d39565b94506060880135610ec481610d39565b93506080880135925060a088013567ffffffffffffffff811115610ee757600080fd5b610ef38a828b01610d75565b989b979a50959850939692959293505050565b60008060008060808587031215610f1c57600080fd5b8435610f2781610d39565b93506020850135610f3781610d39565b93969395505050506040820135916060013590565b60008060008060808587031215610f6257600080fd5b8435610f6d81610d39565b93506020850135610f7d81610d39565b92506040850135610f8d81610d39565b91506060850135610f9d81610d39565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215610fd057600080fd5b8151610d6e81610d39565b604051601f8201601f1916810167ffffffffffffffff8111828210171561100457611004610fa8565b604052919050565b600067ffffffffffffffff82111561102657611026610fa8565b50601f01601f191660200190565b600082601f83011261104557600080fd5b81356110586110538261100c565b610fdb565b81815284602083860101111561106d57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561109d57600080fd5b823567ffffffffffffffff808211156110b557600080fd5b6110c186838701611034565b935060208501359150808211156110d757600080fd5b506110e485828601611034565b9150509250929050565b60005b838110156111095781810151838201526020016110f1565b838111156106ba5750506000910152565b600081518084526111328160208601602086016110ee565b601f01601f19169290920160200192915050565b60018060a01b038416815282602082015260606040820152600061116d606083018461111a565b95945050505050565b60006111846110538461100c565b905082815283838301111561119857600080fd5b610d6e8360208301846110ee565b600080604083850312156111b957600080fd5b82516111c481610d39565b602084015190925067ffffffffffffffff8111156111e157600080fd5b8301601f810185136111f257600080fd5b6110e485825160208401611176565b6001600160a01b03878116825286811660208301528581166040830152841660608201526080810183905260c060a082018190526000906112449083018461111a565b98975050505050505050565b60018060a01b0385168152836020820152608060408201526000611277608083018561111a565b905082606083015295945050505050565b600082601f83011261129957600080fd5b610d6e83835160208501611176565b6000806000606084860312156112bd57600080fd5b835167ffffffffffffffff808211156112d557600080fd5b6112e187838801611288565b945060208601519150808211156112f757600080fd5b5061130486828701611288565b925050604084015160ff8116811461131b57600080fd5b809150509250925092565b60a08152600061133960a083018861111a565b828103602084015261134b818861111a565b60ff96909616604084015250506001600160a01b03928316606082015291166080909101529291505056fea2646970667358221220ecd187c94a71cff6b791b98b05df232b66ff286e240691cae5a392562812230864736f6c634300080a0033"; - let bytes = hex::decode(example).unwrap(); - - assert_eq!( - format!("{:?}", hash_code(&bytes)), - "0x26f706f949ff4faad54ee72308e9d30ece46e37cf8b9968bdb274e750a264937" - ); -} diff --git a/eth-types/src/utils/codehash.rs b/eth-types/src/utils/codehash.rs new file mode 100644 index 0000000000..7abac7598e --- /dev/null +++ b/eth-types/src/utils/codehash.rs @@ -0,0 +1,111 @@ +//! Some handy helpers + +use crate::{Address, Hash}; +use revm_precompile::Precompiles; + +/// Check if address is a precompiled or not. +pub fn is_precompiled(address: &Address) -> bool { + #[cfg(feature = "scroll")] + let precompiles = Precompiles::bernoulli(); + #[cfg(not(feature = "scroll"))] + let precompiles = Precompiles::berlin(); + precompiles.get(address.as_fixed_bytes().into()).is_some() +} + +/// Default number of bytes to pack into a field element. +pub const POSEIDON_HASH_BYTES_IN_FIELD: usize = 31; + +/// Default code hash +pub fn hash_code(code: &[u8]) -> Hash { + #[cfg(feature = "scroll")] + return hash_code_poseidon(code); + #[cfg(not(feature = "scroll"))] + return hash_code_keccak(code); +} + +/// Keccak code hash +pub fn hash_code_keccak(code: &[u8]) -> Hash { + crate::H256(ethers_core::utils::keccak256(code)) +} + +/// Poseidon code hash +pub fn hash_code_poseidon(code: &[u8]) -> Hash { + use crate::U256; + use halo2curves::{bn256::Fr, ff::PrimeField}; + use poseidon_base::hash::{Hashable, MessageHashable, HASHABLE_DOMAIN_SPEC}; + + let bytes_in_field = POSEIDON_HASH_BYTES_IN_FIELD; + let fls = (0..(code.len() / bytes_in_field)) + .map(|i| i * bytes_in_field) + .map(|i| { + let mut buf: [u8; 32] = [0; 32]; + U256::from_big_endian(&code[i..i + bytes_in_field]).to_little_endian(&mut buf); + Fr::from_bytes(&buf).unwrap() + }); + let msgs: Vec<_> = fls + .chain(if code.len() % bytes_in_field == 0 { + None + } else { + let last_code = &code[code.len() - code.len() % bytes_in_field..]; + // pad to bytes_in_field + let mut last_buf = vec![0u8; bytes_in_field]; + last_buf.as_mut_slice()[..last_code.len()].copy_from_slice(last_code); + let mut buf: [u8; 32] = [0; 32]; + U256::from_big_endian(&last_buf).to_little_endian(&mut buf); + Some(Fr::from_bytes(&buf).unwrap()) + }) + .collect(); + + let h = if msgs.is_empty() { + // the empty code hash is overlapped with simple hash on [0, 0] + // an issue in poseidon primitive prevent us calculate it from hash_msg + Fr::hash_with_domain([Fr::zero(), Fr::zero()], Fr::zero()) + } else { + Fr::hash_msg(&msgs, Some(code.len() as u128 * HASHABLE_DOMAIN_SPEC)) + }; + + let mut buf: [u8; 32] = [0; 32]; + U256::from_little_endian(h.to_repr().as_ref()).to_big_endian(&mut buf); + Hash::from_slice(&buf) +} + +#[test] +fn test_empty_code_hash() { + assert_eq!(*crate::POSEIDON_CODE_HASH_EMPTY, hash_code_poseidon(&[])); + assert_eq!(*crate::KECCAK_CODE_HASH_EMPTY, hash_code_keccak(&[])); +} + +#[cfg(feature = "scroll")] +#[test] +fn code_hashing() { + assert_eq!( + format!("{:?}", hash_code(&[])), + "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864" + ); + + let simple_byte: [u8; 1] = [0]; + assert_eq!( + format!("{:?}", hash_code(&simple_byte)), + "0x29f94b67ee4e78b2bb08da025f9943c1201a7af025a27600c2dd0a2e71c7cf8b" + ); + + let simple_byte: [u8; 2] = [0, 1]; + assert_eq!( + format!("{:?}", hash_code(&simple_byte)), + "0x1bd41d9cc3187305de467d841b6b999d1222260b7057cb6f63d2ae92c43a7322" + ); + + let byte32: [u8; 32] = [1; 32]; + assert_eq!( + format!("{:?}", hash_code(&byte32)), + "0x0b46d156183dffdbed8e6c6b0af139b95c058e735878ca7f4dca334e0ea8bd20" + ); + + let example = "6080604052600436106100a75760003560e01c80638431f5c1116100645780638431f5c114610177578063a93a4af91461018a578063c676ad291461019d578063e77772fe146101bd578063f887ea40146101dd578063f8c8765e146101fd57600080fd5b80633cb747bf146100ac57806354bbd59c146100e8578063575361b6146101215780636c07ea43146101365780637885ef0114610149578063797594b014610151575b600080fd5b3480156100b857600080fd5b506002546100cc906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b3480156100f457600080fd5b506100cc610103366004610d51565b6001600160a01b039081166000908152600460205260409020541690565b61013461012f366004610dbe565b61021d565b005b610134610144366004610e39565b610269565b6101346102a8565b34801561015d57600080fd5b506000546100cc906201000090046001600160a01b031681565b610134610185366004610e6e565b610303565b610134610198366004610f06565b6106ad565b3480156101a957600080fd5b506100cc6101b8366004610d51565b6106c0565b3480156101c957600080fd5b506005546100cc906001600160a01b031681565b3480156101e957600080fd5b506001546100cc906001600160a01b031681565b34801561020957600080fd5b50610134610218366004610f4c565b61073b565b61026186868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892506108b5915050565b505050505050565b6102a383338460005b6040519080825280601f01601f19166020018201604052801561029c576020820181803683370190505b50856108b5565b505050565b6002546001600160a01b031633146103015760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b60448201526064015b60405180910390fd5b565b6002546001600160a01b03163381146103585760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b60448201526064016102f8565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ba9190610fbe565b6000546201000090046001600160a01b0390811691161461041d5760405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063616c6c20627920636f6e7465727061727400000000000000000060448201526064016102f8565b341561045f5760405162461bcd60e51b81526020600482015260116024820152706e6f6e7a65726f206d73672e76616c756560781b60448201526064016102f8565b6005546040516361e98ca160e01b81523060048201526001600160a01b038a8116602483015260009216906361e98ca190604401602060405180830381865afa1580156104b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d49190610fbe565b9050806001600160a01b0316886001600160a01b03161461052b5760405162461bcd60e51b81526020600482015260116024820152700d86440e8ded6cadc40dad2e6dac2e8c6d607b1b60448201526064016102f8565b506001600160a01b03878116600090815260046020526040902054606091829116610593576001600160a01b03898116600090815260046020526040902080546001600160a01b031916918c1691909117905561058a8585018661108a565b925090506105cd565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b6001600160a01b0389163b6105e6576105e6828b610b23565b6040516340c10f1960e01b81526001600160a01b038881166004830152602482018890528a16906340c10f1990604401600060405180830381600087803b15801561063057600080fd5b505af1158015610644573d6000803e3d6000fd5b50505050876001600160a01b0316896001600160a01b03168b6001600160a01b03167f165ba69f6ab40c50cade6f65431801e5f9c7d7830b7545391920db039133ba348a8a8660405161069993929190611146565b60405180910390a450505050505050505050565b6106ba8484846000610272565b50505050565b6005546040516361e98ca160e01b81523060048201526001600160a01b03838116602483015260009216906361e98ca190604401602060405180830381865afa158015610711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107359190610fbe565b92915050565b600054610100900460ff166107565760005460ff161561075a565b303b155b6107bd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102f8565b600054610100900460ff161580156107df576000805461ffff19166101011790555b6001600160a01b03841661082b5760405162461bcd60e51b81526020600482015260136024820152727a65726f20726f75746572206164647265737360681b60448201526064016102f8565b610836858585610c29565b6001600160a01b0382166108815760405162461bcd60e51b81526020600482015260126024820152717a65726f20746f6b656e20666163746f727960701b60448201526064016102f8565b600580546001600160a01b0319166001600160a01b03841617905580156108ae576000805461ff00191690555b5050505050565b600083116108fc5760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b60448201526064016102f8565b60015433906001600160a01b031681141561092a578280602001905181019061092591906111a6565b935090505b6001600160a01b0380871660009081526004602052604090205416806109925760405162461bcd60e51b815260206004820152601960248201527f6e6f20636f72726573706f6e64696e67206c3120746f6b656e0000000000000060448201526064016102f8565b604051632770a7eb60e21b81526001600160a01b03838116600483015260248201879052881690639dc29fac90604401600060405180830381600087803b1580156109dc57600080fd5b505af11580156109f0573d6000803e3d6000fd5b5050505060006384bd13b060e01b8289858a8a8a604051602401610a1996959493929190611201565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600254600054925163b2267a7b60e01b81529193506001600160a01b039081169263b2267a7b923492610a8e926201000090041690839087908b90600401611250565b6000604051808303818588803b158015610aa757600080fd5b505af1158015610abb573d6000803e3d6000fd5b5050505050826001600160a01b0316886001600160a01b0316836001600160a01b03167fd8d3a3f4ab95694bef40475997598bcf8acd3ed9617a4c1013795429414c27e88a8a8a604051610b1193929190611146565b60405180910390a45050505050505050565b600554604051637bdbcbbf60e01b81523060048201526001600160a01b0383811660248301526000921690637bdbcbbf906044016020604051808303816000875af1158015610b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9a9190610fbe565b9050600080600085806020019051810190610bb591906112a8565b925092509250836001600160a01b031663c820f146838584308a6040518663ffffffff1660e01b8152600401610bef959493929190611326565b600060405180830381600087803b158015610c0957600080fd5b505af1158015610c1d573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b038316610c7f5760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e746572706172742061646472657373000000000000000060448201526064016102f8565b6001600160a01b038116610cce5760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b60448201526064016102f8565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600280546001600160a01b031916838316179055821615610d2f57600180546001600160a01b0319166001600160a01b0384161790555b5050600160035550565b6001600160a01b0381168114610d4e57600080fd5b50565b600060208284031215610d6357600080fd5b8135610d6e81610d39565b9392505050565b60008083601f840112610d8757600080fd5b50813567ffffffffffffffff811115610d9f57600080fd5b602083019150836020828501011115610db757600080fd5b9250929050565b60008060008060008060a08789031215610dd757600080fd5b8635610de281610d39565b95506020870135610df281610d39565b945060408701359350606087013567ffffffffffffffff811115610e1557600080fd5b610e2189828a01610d75565b979a9699509497949695608090950135949350505050565b600080600060608486031215610e4e57600080fd5b8335610e5981610d39565b95602085013595506040909401359392505050565b600080600080600080600060c0888a031215610e8957600080fd5b8735610e9481610d39565b96506020880135610ea481610d39565b95506040880135610eb481610d39565b94506060880135610ec481610d39565b93506080880135925060a088013567ffffffffffffffff811115610ee757600080fd5b610ef38a828b01610d75565b989b979a50959850939692959293505050565b60008060008060808587031215610f1c57600080fd5b8435610f2781610d39565b93506020850135610f3781610d39565b93969395505050506040820135916060013590565b60008060008060808587031215610f6257600080fd5b8435610f6d81610d39565b93506020850135610f7d81610d39565b92506040850135610f8d81610d39565b91506060850135610f9d81610d39565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215610fd057600080fd5b8151610d6e81610d39565b604051601f8201601f1916810167ffffffffffffffff8111828210171561100457611004610fa8565b604052919050565b600067ffffffffffffffff82111561102657611026610fa8565b50601f01601f191660200190565b600082601f83011261104557600080fd5b81356110586110538261100c565b610fdb565b81815284602083860101111561106d57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561109d57600080fd5b823567ffffffffffffffff808211156110b557600080fd5b6110c186838701611034565b935060208501359150808211156110d757600080fd5b506110e485828601611034565b9150509250929050565b60005b838110156111095781810151838201526020016110f1565b838111156106ba5750506000910152565b600081518084526111328160208601602086016110ee565b601f01601f19169290920160200192915050565b60018060a01b038416815282602082015260606040820152600061116d606083018461111a565b95945050505050565b60006111846110538461100c565b905082815283838301111561119857600080fd5b610d6e8360208301846110ee565b600080604083850312156111b957600080fd5b82516111c481610d39565b602084015190925067ffffffffffffffff8111156111e157600080fd5b8301601f810185136111f257600080fd5b6110e485825160208401611176565b6001600160a01b03878116825286811660208301528581166040830152841660608201526080810183905260c060a082018190526000906112449083018461111a565b98975050505050505050565b60018060a01b0385168152836020820152608060408201526000611277608083018561111a565b905082606083015295945050505050565b600082601f83011261129957600080fd5b610d6e83835160208501611176565b6000806000606084860312156112bd57600080fd5b835167ffffffffffffffff808211156112d557600080fd5b6112e187838801611288565b945060208601519150808211156112f757600080fd5b5061130486828701611288565b925050604084015160ff8116811461131b57600080fd5b809150509250925092565b60a08152600061133960a083018861111a565b828103602084015261134b818861111a565b60ff96909616604084015250506001600160a01b03928316606082015291166080909101529291505056fea2646970667358221220ecd187c94a71cff6b791b98b05df232b66ff286e240691cae5a392562812230864736f6c634300080a0033"; + let bytes = hex::decode(example).unwrap(); + + assert_eq!( + format!("{:?}", hash_code(&bytes)), + "0x26f706f949ff4faad54ee72308e9d30ece46e37cf8b9968bdb274e750a264937" + ); +} diff --git a/eth-types/src/utils/io.rs b/eth-types/src/utils/io.rs new file mode 100644 index 0000000000..9bbab7a3da --- /dev/null +++ b/eth-types/src/utils/io.rs @@ -0,0 +1,15 @@ +use std::{fs::File, path::Path}; + +/// Load struct from json file +pub fn from_json_file<'de, P: serde::Deserialize<'de>>(file_path: &str) -> std::io::Result

{ + if !Path::new(&file_path).exists() { + log::error!("File {file_path} doesn't exist"); + } + + let fd = File::open(file_path)?; + let mut deserializer = serde_json::Deserializer::from_reader(fd); + deserializer.disable_recursion_limit(); + let deserializer = serde_stacker::Deserializer::new(&mut deserializer); + + Ok(serde::Deserialize::deserialize(deserializer)?) +} diff --git a/prover/src/io.rs b/prover/src/io.rs index f7545eb857..1f46482774 100644 --- a/prover/src/io.rs +++ b/prover/src/io.rs @@ -13,19 +13,6 @@ use std::{ path::{Path, PathBuf}, }; -pub fn from_json_file<'de, P: serde::Deserialize<'de>>(file_path: &str) -> anyhow::Result

{ - if !Path::new(&file_path).exists() { - anyhow::bail!("File {file_path} doesn't exist"); - } - - let fd = File::open(file_path)?; - let mut deserializer = serde_json::Deserializer::from_reader(fd); - deserializer.disable_recursion_limit(); - let deserializer = serde_stacker::Deserializer::new(&mut deserializer); - - Ok(serde::Deserialize::deserialize(deserializer)?) -} - pub fn serialize_fr(f: &Fr) -> Vec { f.to_bytes().to_vec() } @@ -48,27 +35,12 @@ pub fn deserialize_fr_matrix(l3_buf: Vec>>) -> Vec> { l3_buf.into_iter().map(deserialize_fr_vec).collect() } -pub fn serialize_fr_tensor(t: &[Vec>]) -> Vec>>> { - t.iter() - .map(|m| serialize_fr_matrix(m.as_slice())) - .collect() -} - -pub fn deserialize_fr_tensor(l4_buf: Vec>>>) -> Vec>> { - l4_buf.into_iter().map(deserialize_fr_matrix).collect() -} - pub fn serialize_instance(instance: &[Vec]) -> Vec { let instances_for_serde = serialize_fr_matrix(instance); serde_json::to_vec(&instances_for_serde).unwrap() } -pub fn load_instance(buf: &[u8]) -> Vec>> { - let instances: Vec>>> = serde_json::from_reader(buf).unwrap(); - deserialize_fr_tensor(instances) -} - pub fn read_all(filename: &str) -> Vec { let mut buf = vec![]; let mut fd = std::fs::File::open(filename).unwrap(); diff --git a/prover/src/proof.rs b/prover/src/proof.rs index 91a483ae86..7d1d26d521 100644 --- a/prover/src/proof.rs +++ b/prover/src/proof.rs @@ -113,7 +113,7 @@ pub fn dump_vk(dir: &str, filename: &str, raw_vk: &[u8]) { pub fn from_json_file<'de, P: serde::Deserialize<'de>>(dir: &str, filename: &str) -> Result

{ let file_path = dump_proof_path(dir, filename); - crate::io::from_json_file(&file_path) + Ok(eth_types::utils::from_json_file(&file_path)?) } fn dump_proof_path(dir: &str, filename: &str) -> String { diff --git a/zkevm-circuits/src/witness/mpt/witness.rs b/zkevm-circuits/src/witness/mpt/witness.rs index c595d01c96..4023537fd2 100644 --- a/zkevm-circuits/src/witness/mpt/witness.rs +++ b/zkevm-circuits/src/witness/mpt/witness.rs @@ -505,10 +505,10 @@ use eth_types::Bytes; use serde::Deserialize; type AccountTrieProofs = HashMap>; -type StorageTrieProofs = HashMap>>; +type StorageTrieProofs = HashMap>>; type AccountDatas = HashMap; -type StorageDatas = HashMap<(Address, Word), StorageData>; +type StorageDatas = HashMap<(Address, H256), StorageData>; #[derive(Deserialize, Default, Debug, Clone)] struct StorageTrace { @@ -598,7 +598,7 @@ fn witgen_update_one() { assert_eq!( Some(U256::from(10u32)), storages - .get(&(target_addr, U256::zero())) + .get(&(target_addr, H256::zero())) .map(AsRef::as_ref) .copied() ); diff --git a/zktrie/src/state.rs b/zktrie/src/state.rs index 551ff3dc76..46dbbc5a03 100644 --- a/zktrie/src/state.rs +++ b/zktrie/src/state.rs @@ -1,5 +1,5 @@ //! Represent the storage state under zktrie as implement -use eth_types::{Address, Hash, Word}; +use eth_types::{Address, Hash, H256}; use std::{collections::HashSet, io::Error}; pub use zktrie::{Hash as ZkTrieHash, ZkMemoryDb, ZkTrie, ZkTrieNode}; @@ -17,7 +17,7 @@ pub struct ZktrieState { /// Trie root pub trie_root: ZkTrieHash, addr_cache: HashSet

, - storage_cache: HashSet<(Address, Word)>, + storage_cache: HashSet<(Address, H256)>, } //unsafe impl Send for ZktrieState {} @@ -99,16 +99,15 @@ impl ZktrieState { /// Helper for parsing storage value from external data pub fn parse_storage_from_proofs<'d: 'a, 'a, BYTES>( - storage_proofs: impl Iterator + 'd, - ) -> impl Iterator> + 'a + storage_proofs: impl Iterator + 'd, + ) -> impl Iterator> + 'a where BYTES: IntoIterator, { use builder::{BytesArray, StorageProof}; storage_proofs.map(|(&addr, &key, bytes)| { - let storage_key: (Address, Word) = (addr, key); - let mut key_buf = [0u8; 32]; - key.to_big_endian(key_buf.as_mut_slice()); + let storage_key: (Address, H256) = (addr, key); + let key_buf = key.to_fixed_bytes(); let bytes_array = BytesArray(bytes.into_iter()); let store_proof = builder::verify_proof_leaf(StorageProof::try_from(bytes_array)?, &key_buf); @@ -130,7 +129,7 @@ impl ZktrieState { pub fn update_from_trace<'d, BYTES1, BYTES2>( &mut self, account_proofs: impl Iterator, - storage_proofs: impl Iterator, + storage_proofs: impl Iterator, additional_proofs: impl Iterator, ) where BYTES1: IntoIterator, @@ -156,7 +155,7 @@ impl ZktrieState { pub fn from_trace_with_additional<'d, BYTES1, BYTES2>( state_root: Hash, account_proofs: impl Iterator, - storage_proofs: impl Iterator, + storage_proofs: impl Iterator, additional_proofs: impl Iterator, ) -> Result where