From e0b2f185519b12b46464c714e6cd71ea6ba1fbbe Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Wed, 6 Nov 2024 16:09:35 -0500 Subject: [PATCH 1/4] Add Hasher trait to World --- smt_trie/src/code.rs | 8 +++---- smt_trie/src/utils.rs | 9 +++++++- trace_decoder/src/type2.rs | 4 ++-- trace_decoder/src/world.rs | 46 ++++++++++++++++++++++++++++++++------ 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/smt_trie/src/code.rs b/smt_trie/src/code.rs index dd6b142b9..2d1a98661 100644 --- a/smt_trie/src/code.rs +++ b/smt_trie/src/code.rs @@ -1,11 +1,11 @@ /// Functions to hash contract bytecode using Poseidon. /// See `hashContractBytecode()` in https://github.com/0xPolygonHermez/zkevm-commonjs/blob/main/src/smt-utils.js for reference implementation. -use ethereum_types::U256; +use ethereum_types::H256; use plonky2::field::types::Field; use plonky2::hash::poseidon::{self, Poseidon}; use crate::smt::{HashOut, F}; -use crate::utils::hashout2u; +use crate::utils::hashout2h; pub fn hash_contract_bytecode(mut code: Vec) -> HashOut { poseidon_pad_byte_vec(&mut code); @@ -43,8 +43,8 @@ pub fn poseidon_pad_byte_vec(bytes: &mut Vec) { *bytes.last_mut().unwrap() |= 0x80; } -pub fn hash_bytecode_u256(code: Vec) -> U256 { - hashout2u(hash_contract_bytecode(code)) +pub fn hash_bytecode_h256(code: &[u8]) -> H256 { + hashout2h(hash_contract_bytecode(code.to_vec())) } #[cfg(test)] diff --git a/smt_trie/src/utils.rs b/smt_trie/src/utils.rs index 267b6b8e9..6b30b8972 100644 --- a/smt_trie/src/utils.rs +++ b/smt_trie/src/utils.rs @@ -1,4 +1,4 @@ -use ethereum_types::U256; +use ethereum_types::{H256, U256}; use plonky2::field::types::{Field, PrimeField64}; use plonky2::hash::poseidon::Poseidon; @@ -49,6 +49,13 @@ pub fn hashout2u(h: HashOut) -> U256 { key2u(Key(h.elements)) } +/// Convert a `HashOut` to a `H256`. +pub fn hashout2h(h: HashOut) -> H256 { + let mut it = [0; 32]; + hashout2u(h).to_big_endian(&mut it); + H256(it) +} + /// Convert a `Key` to a `U256`. pub fn key2u(key: Key) -> U256 { U256(key.0.map(|x| x.to_canonical_u64())) diff --git a/trace_decoder/src/type2.rs b/trace_decoder/src/type2.rs index 845260d47..4a380bc70 100644 --- a/trace_decoder/src/type2.rs +++ b/trace_decoder/src/type2.rs @@ -155,8 +155,8 @@ fn visit( collated.nonce = Some(value) } SmtLeafType::Code => { - ensure!(collated.code.is_none()); - collated.code = Some(value) + ensure!(collated.code_hash.is_none()); + collated.code_hash = Some(value) } SmtLeafType::Storage(slot) => { ensure!(slot.len() <= 32); diff --git a/trace_decoder/src/world.rs b/trace_decoder/src/world.rs index fa68854e4..6738ac31c 100644 --- a/trace_decoder/src/world.rs +++ b/trace_decoder/src/world.rs @@ -5,9 +5,30 @@ use anyhow::{ensure, Context as _}; use either::Either; use ethereum_types::{Address, BigEndianHash as _, U256}; use keccak_hash::H256; +use smt_trie::code::hash_bytecode_h256; use crate::tries::{MptKey, SmtKey, StateMpt, StorageTrie}; +/// Utility trait to leverage a specific hash function. +pub(crate) trait Hasher { + fn hash(bytes: &[u8]) -> H256; +} + +pub(crate) struct PoseidonHash; +pub(crate) struct KeccakHash; + +impl Hasher for PoseidonHash { + fn hash(bytes: &[u8]) -> H256 { + hash_bytecode_h256(&bytes) + } +} + +impl Hasher for KeccakHash { + fn hash(bytes: &[u8]) -> H256 { + keccak_hash::keccak(bytes) + } +} + /// The [core](crate::core) of this crate is agnostic over state and storage /// representations. /// @@ -18,6 +39,9 @@ pub(crate) trait World { /// This type is a key which may identify a subtrie. type SubtriePath; + /// Hasher to use for contract bytecode. + type CodeHasher: Hasher; + ////////////////////// /// Account operations ////////////////////// @@ -148,6 +172,8 @@ impl Type1World { impl World for Type1World { type SubtriePath = MptKey; + type CodeHasher = KeccakHash; + fn contains(&mut self, address: Address) -> anyhow::Result { Ok(self.state.get(keccak_hash::keccak(address)).is_some()) } @@ -170,7 +196,7 @@ impl World for Type1World { fn set_code(&mut self, address: Address, code: Either<&[u8], H256>) -> anyhow::Result<()> { let key = keccak_hash::keccak(address); let mut acct = self.state.get(key).unwrap_or_default(); - acct.code_hash = code.right_or_else(keccak_hash::keccak); + acct.code_hash = code.right_or_else(Self::CodeHasher::hash); self.state.insert(key, acct) } fn reporting_destroy(&mut self, address: Address) -> anyhow::Result> { @@ -248,6 +274,8 @@ impl World for Type1World { impl World for Type2World { type SubtriePath = SmtKey; + type CodeHasher = PoseidonHash; + fn contains(&mut self, address: Address) -> anyhow::Result { Ok(self.accounts.contains_key(&address)) } @@ -269,10 +297,14 @@ impl World for Type2World { let acct = self.accounts.entry(address).or_default(); match code { Either::Left(bytes) => { - acct.code = Some(keccak_hash::keccak(bytes).into_uint()); - acct.code_length = Some(U256::from(bytes.len())) + acct.code_length = Some(U256::from(bytes.len())); + if bytes.is_empty() { + acct.code_hash = None; + } else { + acct.code_hash = Some(Self::CodeHasher::hash(bytes).into_uint()); + } } - Either::Right(hash) => acct.code = Some(hash.into_uint()), + Either::Right(hash) => acct.code_hash = Some(hash.into_uint()), }; Ok(()) } @@ -349,7 +381,7 @@ impl World for Type2World { pub struct Type2Entry { pub balance: Option, pub nonce: Option, - pub code: Option, + pub code_hash: Option, pub code_length: Option, pub storage: BTreeMap, } @@ -383,7 +415,7 @@ impl Type2World { Type2Entry { balance, nonce, - code, + code_hash, code_length, storage, }, @@ -394,7 +426,7 @@ impl Type2World { for (value, key_fn) in [ (balance, key_balance as fn(_) -> _), (nonce, key_nonce), - (code, key_code), + (code_hash, key_code), (code_length, key_code_length), ] { if let Some(value) = value { From b49b14f15a318a0dbb44f671f9de57d66fa575b6 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Wed, 6 Nov 2024 16:56:45 -0500 Subject: [PATCH 2/4] Use dedicated code hasher in processing --- trace_decoder/src/core.rs | 87 +++++++++++++++++++++----------------- trace_decoder/src/lib.rs | 23 ++++++++++ trace_decoder/src/type1.rs | 6 ++- trace_decoder/src/world.rs | 26 ++---------- 4 files changed, 80 insertions(+), 62 deletions(-) diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index 8093098c1..b34117911 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -1,6 +1,7 @@ use std::{ cmp, collections::{BTreeMap, BTreeSet, HashMap}, + marker::PhantomData, mem, }; @@ -21,6 +22,7 @@ use zk_evm_common::gwei_to_wei; use crate::{ observer::{DummyObserver, Observer}, world::Type2World, + Hasher, KeccakHash, PoseidonHash, }; use crate::{ tries::{MptKey, ReceiptTrie, StateMpt, StorageTrie, TransactionTrie}, @@ -61,9 +63,7 @@ pub fn entrypoint( BlockTraceTriePreImages::Separate(_) => FatalMissingCode(true), BlockTraceTriePreImages::Combined(_) => FatalMissingCode(false), }; - let (world, mut code) = start(trie_pre_images, wire_disposition)?; - - code.extend(code_db); + let start = start(trie_pre_images, wire_disposition)?; let OtherBlockData { b_data: @@ -82,22 +82,26 @@ pub fn entrypoint( *amt = gwei_to_wei(*amt) } - let batches = match world { - Either::Left(type1world) => Either::Left( - middle( - type1world, - batch(txn_info, batch_size_hint), - &mut code, - &b_meta, - ger_data, - withdrawals, - fatal_missing_code, - observer, - )? - .into_iter() - .map(|it| it.map(Either::Left)), - ), - Either::Right(type2world) => { + let batches = match start { + Either::Left((type1world, mut code)) => { + code.extend(code_db); + Either::Left( + middle( + type1world, + batch(txn_info, batch_size_hint), + &mut code, + &b_meta, + ger_data, + withdrawals, + fatal_missing_code, + observer, + )? + .into_iter() + .map(|it| it.map(Either::Left)), + ) + } + Either::Right((type2world, mut code)) => { + code.extend(code_db); Either::Right( middle( type2world, @@ -134,6 +138,7 @@ pub fn entrypoint( withdrawals, }| { let (state, storage) = world + .clone() .expect_left("TODO(0xaatif): evm_arithemetization accepts an SMT") .into_state_and_storage(); GenerationInputs { @@ -157,7 +162,10 @@ pub fn entrypoint( checkpoint_consolidated_hash, contract_code: contract_code .into_iter() - .map(|it| (keccak_hash::keccak(&it), it)) + .map(|it| match &world { + Either::Left(_type1) => (KeccakHash::hash(&it), it), + Either::Right(_type2) => (PoseidonHash::hash(&it), it), + }) .collect(), block_metadata: b_meta.clone(), block_hashes: b_hashes.clone(), @@ -177,7 +185,9 @@ pub fn entrypoint( fn start( pre_images: BlockTraceTriePreImages, wire_disposition: WireDisposition, -) -> anyhow::Result<(Either, Hash2Code)> { +) -> anyhow::Result< + Either<(Type1World, Hash2Code), (Type2World, Hash2Code)>, +> { Ok(match pre_images { // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/401 // refactor our convoluted input types @@ -224,10 +234,7 @@ fn start( .map(|v| (k, v)) }) .collect::>()?; - ( - Either::Left(Type1World::new(state, storage)?), - Hash2Code::new(), - ) + Either::Left((Type1World::new(state, storage)?, Hash2Code::new())) } BlockTraceTriePreImages::Combined(CombinedPreImages { compact }) => { let instructions = crate::wire::parse(&compact) @@ -239,18 +246,20 @@ fn start( storage, code, } = crate::type1::frontend(instructions)?; - ( - Either::Left(Type1World::new(state, storage)?), + + Either::Left(( + Type1World::new(state, storage)?, Hash2Code::from_iter(code.into_iter().map(NonEmpty::into_vec)), - ) + )) } WireDisposition::Type2 => { let crate::type2::Frontend { world: trie, code } = crate::type2::frontend(instructions)?; - ( - Either::Right(trie), + + Either::Right(( + trie, Hash2Code::from_iter(code.into_iter().map(NonEmpty::into_vec)), - ) + )) } } } @@ -388,7 +397,7 @@ fn middle( // None represents a dummy transaction that should not increment the transaction index // all batches SHOULD not be empty batches: Vec>>, - code: &mut Hash2Code, + code: &mut Hash2Code, block: &BlockMetadata, ger_data: Option<(H256, H256)>, // added to final batch @@ -787,15 +796,17 @@ fn map_receipt_bytes(bytes: Vec) -> anyhow::Result> { /// trace. /// If there are any txns that create contracts, then they will also /// get added here as we process the deltas. -struct Hash2Code { - /// Key must always be [`hash`](keccak_hash) of value. +struct Hash2Code { + /// Key must always be [`hash`](World::CodeHasher) of value. inner: HashMap>, + _phantom: PhantomData, } -impl Hash2Code { +impl Hash2Code { pub fn new() -> Self { let mut this = Self { inner: HashMap::new(), + _phantom: PhantomData, }; this.insert(vec![]); this @@ -804,11 +815,11 @@ impl Hash2Code { self.inner.get(&hash).cloned() } pub fn insert(&mut self, code: Vec) { - self.inner.insert(keccak_hash::keccak(&code), code); + self.inner.insert(H::hash(&code), code); } } -impl Extend> for Hash2Code { +impl Extend> for Hash2Code { fn extend>>(&mut self, iter: II) { for it in iter { self.insert(it) @@ -816,7 +827,7 @@ impl Extend> for Hash2Code { } } -impl FromIterator> for Hash2Code { +impl FromIterator> for Hash2Code { fn from_iter>>(iter: II) -> Self { let mut this = Self::new(); this.extend(iter); diff --git a/trace_decoder/src/lib.rs b/trace_decoder/src/lib.rs index 1f1c87888..b89332e5f 100644 --- a/trace_decoder/src/lib.rs +++ b/trace_decoder/src/lib.rs @@ -62,6 +62,8 @@ const _DEVELOPER_DOCS: () = (); mod interface; pub use interface::*; +use keccak_hash::H256; +use smt_trie::code::hash_bytecode_h256; mod tries; mod type1; @@ -101,6 +103,27 @@ mod hex { } } +/// Utility trait to leverage a specific hash function across Type1 and Type2 +/// zkEVM variants. +pub(crate) trait Hasher { + fn hash(bytes: &[u8]) -> H256; +} + +pub(crate) struct PoseidonHash; +pub(crate) struct KeccakHash; + +impl Hasher for PoseidonHash { + fn hash(bytes: &[u8]) -> H256 { + hash_bytecode_h256(bytes) + } +} + +impl Hasher for KeccakHash { + fn hash(bytes: &[u8]) -> H256 { + keccak_hash::keccak(bytes) + } +} + #[cfg(test)] #[derive(serde::Deserialize)] struct Case { diff --git a/trace_decoder/src/type1.rs b/trace_decoder/src/type1.rs index c982a1ab3..072bdbe3c 100644 --- a/trace_decoder/src/type1.rs +++ b/trace_decoder/src/type1.rs @@ -14,6 +14,8 @@ use u4::U4; use crate::tries::{MptKey, StateMpt, StorageTrie}; use crate::wire::{Instruction, SmtLeaf}; +use crate::world::{Type1World, World}; +use crate::Hasher as _; #[derive(Debug, Clone, Default)] pub struct Frontend { @@ -85,11 +87,11 @@ fn visit( match code { Some(Either::Left(Hash { raw_hash })) => raw_hash.into(), Some(Either::Right(Code { code })) => { - let hash = keccak_hash::keccak(&code); + let hash = ::CodeHasher::hash(&code); frontend.code.insert(code); hash } - None => keccak_hash::keccak([]), + None => ::CodeHasher::hash(&[]), } }, }; diff --git a/trace_decoder/src/world.rs b/trace_decoder/src/world.rs index 6738ac31c..463914c53 100644 --- a/trace_decoder/src/world.rs +++ b/trace_decoder/src/world.rs @@ -5,29 +5,11 @@ use anyhow::{ensure, Context as _}; use either::Either; use ethereum_types::{Address, BigEndianHash as _, U256}; use keccak_hash::H256; -use smt_trie::code::hash_bytecode_h256; -use crate::tries::{MptKey, SmtKey, StateMpt, StorageTrie}; - -/// Utility trait to leverage a specific hash function. -pub(crate) trait Hasher { - fn hash(bytes: &[u8]) -> H256; -} - -pub(crate) struct PoseidonHash; -pub(crate) struct KeccakHash; - -impl Hasher for PoseidonHash { - fn hash(bytes: &[u8]) -> H256 { - hash_bytecode_h256(&bytes) - } -} - -impl Hasher for KeccakHash { - fn hash(bytes: &[u8]) -> H256 { - keccak_hash::keccak(bytes) - } -} +use crate::{ + tries::{MptKey, SmtKey, StateMpt, StorageTrie}, + Hasher, KeccakHash, PoseidonHash, +}; /// The [core](crate::core) of this crate is agnostic over state and storage /// representations. From c6581aafef0e056a5e917962234ee09d151e6542 Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Fri, 8 Nov 2024 04:07:01 +0900 Subject: [PATCH 3/4] Move `World` trait and related into `evm_arithmetization` crate (#783) * Move world into evm_arithmetization * Rustdoc --- Cargo.lock | 6 +++ Cargo.toml | 4 +- evm_arithmetization/Cargo.toml | 10 ++++- evm_arithmetization/src/lib.rs | 2 + .../src/tries.rs | 3 +- .../src/world.rs | 38 ++++++++++++++----- trace_decoder/Cargo.toml | 6 +-- trace_decoder/src/core.rs | 13 +++---- trace_decoder/src/lib.rs | 28 +------------- trace_decoder/src/observer.rs | 2 +- trace_decoder/src/type1.rs | 5 +-- trace_decoder/src/type2.rs | 12 +++--- 12 files changed, 68 insertions(+), 61 deletions(-) rename {trace_decoder => evm_arithmetization}/src/tries.rs (99%) rename {trace_decoder => evm_arithmetization}/src/world.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index 7fb230d98..5fd6a45bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2030,9 +2030,14 @@ dependencies = [ name = "evm_arithmetization" version = "0.4.0" dependencies = [ + "alloy", + "alloy-compat", "anyhow", + "bitvec", "bytes", + "copyvec", "criterion", + "either", "env_logger 0.11.5", "ethereum-types", "hashbrown", @@ -2068,6 +2073,7 @@ dependencies = [ "tokio", "tower-lsp", "tracing", + "u4", "url", "zk_evm_common", "zk_evm_proc_macro", diff --git a/Cargo.toml b/Cargo.toml index c56be95a0..f8c6be0f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,8 @@ bytes = "1.6.0" ciborium = "0.2.2" ciborium-io = "0.2.2" clap = { version = "4.5.7", features = ["derive", "env"] } -compat = { path = "compat" } +alloy-compat = "0.1.0" +copyvec = "0.2.0" criterion = "0.5.1" dotenvy = "0.15.7" either = "1.12.0" @@ -104,6 +105,7 @@ url = "2.5.2" winnow = "0.6.13" # local dependencies +compat = { path = "compat" } evm_arithmetization = { path = "evm_arithmetization", version = "0.4.0", default-features = false } mpt_trie = { path = "mpt_trie", version = "0.4.1" } smt_trie = { path = "smt_trie", version = "0.1.1" } diff --git a/evm_arithmetization/Cargo.toml b/evm_arithmetization/Cargo.toml index f5dfec2f2..22a40013f 100644 --- a/evm_arithmetization/Cargo.toml +++ b/evm_arithmetization/Cargo.toml @@ -15,8 +15,13 @@ homepage.workspace = true keywords.workspace = true [dependencies] +alloy.workspace = true +alloy-compat.workspace = true anyhow.workspace = true +bitvec.workspace = true bytes.workspace = true +copyvec.workspace = true +either.workspace = true env_logger.workspace = true ethereum-types.workspace = true hashbrown.workspace = true @@ -43,7 +48,7 @@ serde = { workspace = true, features = ["derive"] } serde-big-array.workspace = true serde_json.workspace = true sha2.workspace = true -smt_trie = { workspace = true, optional = true } +smt_trie = { workspace = true } starky = { workspace = true, features = ["parallel"] } static_assertions.workspace = true thiserror.workspace = true @@ -51,6 +56,7 @@ tiny-keccak.workspace = true tokio.workspace = true tower-lsp = "0.20.0" tracing.workspace = true +u4.workspace = true url.workspace = true zk_evm_common.workspace = true zk_evm_proc_macro.workspace = true @@ -64,7 +70,7 @@ ripemd.workspace = true default = ["eth_mainnet"] asmtools = ["hex"] polygon_pos = [] -cdk_erigon = ["smt_trie"] +cdk_erigon = [] eth_mainnet = [] [[bin]] diff --git a/evm_arithmetization/src/lib.rs b/evm_arithmetization/src/lib.rs index 41b7f093a..9bc6021e2 100644 --- a/evm_arithmetization/src/lib.rs +++ b/evm_arithmetization/src/lib.rs @@ -284,7 +284,9 @@ pub mod witness; pub mod curve_pairings; pub mod extension_tower; pub mod testing_utils; +pub mod tries; pub mod util; +pub mod world; // Public definitions and re-exports mod public_types; diff --git a/trace_decoder/src/tries.rs b/evm_arithmetization/src/tries.rs similarity index 99% rename from trace_decoder/src/tries.rs rename to evm_arithmetization/src/tries.rs index 7da8d2cfa..61531a1ef 100644 --- a/trace_decoder/src/tries.rs +++ b/evm_arithmetization/src/tries.rs @@ -7,10 +7,11 @@ use anyhow::ensure; use bitvec::{array::BitArray, slice::BitSlice}; use copyvec::CopyVec; use ethereum_types::{Address, H256, U256}; -use evm_arithmetization::generation::mpt::AccountRlp; use mpt_trie::partial_trie::{HashedPartialTrie, Node, OnOrphanedHashNode, PartialTrie as _}; use u4::{AsNibbles, U4}; +use crate::generation::mpt::AccountRlp; + /// Bounded sequence of [`U4`], /// used as a key for [MPT](HashedPartialTrie) types in this module. /// diff --git a/trace_decoder/src/world.rs b/evm_arithmetization/src/world.rs similarity index 95% rename from trace_decoder/src/world.rs rename to evm_arithmetization/src/world.rs index 463914c53..d01e7ef26 100644 --- a/trace_decoder/src/world.rs +++ b/evm_arithmetization/src/world.rs @@ -5,18 +5,36 @@ use anyhow::{ensure, Context as _}; use either::Either; use ethereum_types::{Address, BigEndianHash as _, U256}; use keccak_hash::H256; +use smt_trie::code::hash_bytecode_h256; -use crate::{ - tries::{MptKey, SmtKey, StateMpt, StorageTrie}, - Hasher, KeccakHash, PoseidonHash, -}; +/// Utility trait to leverage a specific hash function across Type1 and Type2 +/// zkEVM variants. +pub trait Hasher { + fn hash(bytes: &[u8]) -> H256; +} + +pub struct PoseidonHash; +pub struct KeccakHash; + +impl Hasher for PoseidonHash { + fn hash(bytes: &[u8]) -> H256 { + hash_bytecode_h256(bytes) + } +} + +impl Hasher for KeccakHash { + fn hash(bytes: &[u8]) -> H256 { + keccak_hash::keccak(bytes) + } +} + +use crate::tries::{MptKey, SmtKey, StateMpt, StorageTrie}; -/// The [core](crate::core) of this crate is agnostic over state and storage -/// representations. +/// The `core` module of the `trace_decoder` crate is agnostic over state and +/// storage representations. /// /// This is the common interface to those data structures. -/// See also [crate::_DEVELOPER_DOCS]. -pub(crate) trait World { +pub trait World { /// (State) subtries may be _hashed out. /// This type is a key which may identify a subtrie. type SubtriePath; @@ -50,8 +68,8 @@ pub(crate) trait World { /// Creates a new account at `address` if it does not exist. fn set_code(&mut self, address: Address, code: Either<&[u8], H256>) -> anyhow::Result<()>; - /// The [core](crate::core) of this crate tracks required subtries for - /// proving. + /// The `core` module of the `trace_decoder` crate tracks required subtries + /// for proving. /// /// In case of a state delete, it may be that certain parts of the subtrie /// must be retained. If so, it will be returned as [`Some`]. diff --git a/trace_decoder/Cargo.toml b/trace_decoder/Cargo.toml index 4b8d8e7bc..da9394823 100644 --- a/trace_decoder/Cargo.toml +++ b/trace_decoder/Cargo.toml @@ -11,14 +11,14 @@ keywords.workspace = true [dependencies] alloy.workspace = true -alloy-compat = "0.1.0" +alloy-compat.workspace = true anyhow.workspace = true bitflags.workspace = true bitvec.workspace = true bytes.workspace = true ciborium.workspace = true ciborium-io.workspace = true -copyvec = "0.2.0" +copyvec.workspace = true either.workspace = true enum-as-inner.workspace = true ethereum-types.workspace = true @@ -43,7 +43,7 @@ zk_evm_common.workspace = true [dev-dependencies] alloy.workspace = true -alloy-compat = "0.1.0" +alloy-compat.workspace = true assert2 = "0.3.15" camino = "1.1.9" clap.workspace = true diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index b34117911..3f63f7004 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -11,6 +11,8 @@ use ethereum_types::{Address, BigEndianHash as _, U256}; use evm_arithmetization::{ generation::TrieInputs, proof::{BlockMetadata, TrieRoots}, + tries::{MptKey, ReceiptTrie, StateMpt, StorageTrie, TransactionTrie}, + world::{Hasher, KeccakHash, PoseidonHash, Type1World, Type2World, World}, GenerationInputs, }; use itertools::Itertools as _; @@ -19,14 +21,8 @@ use mpt_trie::partial_trie::PartialTrie as _; use nunny::NonEmpty; use zk_evm_common::gwei_to_wei; +use crate::observer::{DummyObserver, Observer}; use crate::{ - observer::{DummyObserver, Observer}, - world::Type2World, - Hasher, KeccakHash, PoseidonHash, -}; -use crate::{ - tries::{MptKey, ReceiptTrie, StateMpt, StorageTrie, TransactionTrie}, - world::{Type1World, World}, BlockLevelData, BlockTrace, BlockTraceTriePreImages, CombinedPreImages, ContractCodeUsage, OtherBlockData, SeparateStorageTriesPreImage, SeparateTriePreImage, SeparateTriePreImages, TxnInfo, TxnMeta, TxnTrace, @@ -180,7 +176,8 @@ pub fn entrypoint( /// [`HashedPartialTrie`](mpt_trie::partial_trie::HashedPartialTrie), /// or a [`wire`](crate::wire)-encoded representation of one. /// -/// Turn either of those into our [internal representations](crate::tries). +/// Turn either of those into our [internal +/// representations](evm_arithmetization::tries). #[allow(clippy::type_complexity)] fn start( pre_images: BlockTraceTriePreImages, diff --git a/trace_decoder/src/lib.rs b/trace_decoder/src/lib.rs index b89332e5f..4bd68bc11 100644 --- a/trace_decoder/src/lib.rs +++ b/trace_decoder/src/lib.rs @@ -56,20 +56,17 @@ /// we can continue to do the main work of "executing" the transactions. /// /// The core of this library is agnostic over the (combined) -/// state and storage representation - see [`world::World`] for more. +/// state and storage representation - see [`evm_arithmetization::world::World`] +/// for more. const _DEVELOPER_DOCS: () = (); mod interface; pub use interface::*; -use keccak_hash::H256; -use smt_trie::code::hash_bytecode_h256; -mod tries; mod type1; mod type2; mod wire; -mod world; pub use core::{entrypoint, WireDisposition}; @@ -103,27 +100,6 @@ mod hex { } } -/// Utility trait to leverage a specific hash function across Type1 and Type2 -/// zkEVM variants. -pub(crate) trait Hasher { - fn hash(bytes: &[u8]) -> H256; -} - -pub(crate) struct PoseidonHash; -pub(crate) struct KeccakHash; - -impl Hasher for PoseidonHash { - fn hash(bytes: &[u8]) -> H256 { - hash_bytecode_h256(bytes) - } -} - -impl Hasher for KeccakHash { - fn hash(bytes: &[u8]) -> H256 { - keccak_hash::keccak(bytes) - } -} - #[cfg(test)] #[derive(serde::Deserialize)] struct Case { diff --git a/trace_decoder/src/observer.rs b/trace_decoder/src/observer.rs index 428cac086..3d19c700d 100644 --- a/trace_decoder/src/observer.rs +++ b/trace_decoder/src/observer.rs @@ -1,9 +1,9 @@ use std::marker::PhantomData; use ethereum_types::U256; +use evm_arithmetization::tries::{ReceiptTrie, TransactionTrie}; use crate::core::IntraBlockTries; -use crate::tries::{ReceiptTrie, TransactionTrie}; /// Observer API for the trace decoder. /// Observer is used to collect various debugging and metadata info diff --git a/trace_decoder/src/type1.rs b/trace_decoder/src/type1.rs index 072bdbe3c..2d9e293d5 100644 --- a/trace_decoder/src/type1.rs +++ b/trace_decoder/src/type1.rs @@ -7,15 +7,14 @@ use std::collections::{BTreeMap, BTreeSet}; use anyhow::{bail, ensure, Context as _}; use either::Either; use evm_arithmetization::generation::mpt::AccountRlp; +use evm_arithmetization::tries::{MptKey, StateMpt, StorageTrie}; +use evm_arithmetization::world::{Hasher as _, Type1World, World}; use keccak_hash::H256; use mpt_trie::partial_trie::OnOrphanedHashNode; use nunny::NonEmpty; use u4::U4; -use crate::tries::{MptKey, StateMpt, StorageTrie}; use crate::wire::{Instruction, SmtLeaf}; -use crate::world::{Type1World, World}; -use crate::Hasher as _; #[derive(Debug, Clone, Default)] pub struct Frontend { diff --git a/trace_decoder/src/type2.rs b/trace_decoder/src/type2.rs index 4a380bc70..87af8a464 100644 --- a/trace_decoder/src/type2.rs +++ b/trace_decoder/src/type2.rs @@ -5,16 +5,16 @@ use std::collections::{BTreeMap, HashSet}; use anyhow::{bail, ensure, Context as _}; use ethereum_types::{Address, U256}; +use evm_arithmetization::{ + tries::SmtKey, + world::{Type2Entry, Type2World}, +}; use itertools::EitherOrBoth; use keccak_hash::H256; use nunny::NonEmpty; use stackstack::Stack; -use crate::{ - tries::SmtKey, - wire::{Instruction, SmtLeaf, SmtLeafType}, - world::{Type2Entry, Type2World}, -}; +use crate::wire::{Instruction, SmtLeaf, SmtLeafType}; pub struct Frontend { pub world: Type2World, @@ -175,7 +175,7 @@ fn visit( #[test] fn test_tries() { - use crate::world::World as _; + use evm_arithmetization::world::World as _; for (ix, case) in serde_json::from_str::>(include_str!("cases/hermez_cdk_erigon.json")) .unwrap() From 6c4ebafdb52fab730ba5f4e48a3ef93c0d32b957 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 7 Nov 2024 14:10:09 -0500 Subject: [PATCH 4/4] Apply suggestion --- trace_decoder/src/core.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index 3f63f7004..cd2bcfa6e 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -159,8 +159,12 @@ pub fn entrypoint( contract_code: contract_code .into_iter() .map(|it| match &world { - Either::Left(_type1) => (KeccakHash::hash(&it), it), - Either::Right(_type2) => (PoseidonHash::hash(&it), it), + Either::Left(_type1) => { + (::CodeHasher::hash(&it), it) + } + Either::Right(_type2) => { + (::CodeHasher::hash(&it), it) + } }) .collect(), block_metadata: b_meta.clone(),