From 2d5a806257bc4ffcee79e2f796bfa03f6c8fe1e1 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Mon, 16 Sep 2024 17:56:47 -0400 Subject: [PATCH 1/8] Add pre-execution rules --- .../src/cpu/kernel/asm/beacon_roots.asm | 1 - .../src/cpu/kernel/constants/mod.rs | 26 +-- trace_decoder/Cargo.toml | 8 +- trace_decoder/src/core.rs | 178 ++++++++++++++++-- trace_decoder/src/interface.rs | 5 + trace_decoder/src/typed_mpt.rs | 12 +- 6 files changed, 191 insertions(+), 39 deletions(-) diff --git a/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm b/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm index 17ade9e86..265d61b90 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm @@ -18,7 +18,6 @@ global set_beacon_root: %slot_to_storage_key // stack: timestamp_slot_key, timestamp, retdest PUSH @BEACON_ROOTS_CONTRACT_STATE_KEY - %addr_to_state_key %parent_beacon_block_root // stack: calldata, state_key, timestamp_slot_key, timestamp, retdest PUSH @HISTORY_BUFFER_LENGTH diff --git a/evm_arithmetization/src/cpu/kernel/constants/mod.rs b/evm_arithmetization/src/cpu/kernel/constants/mod.rs index 348c5b2c6..c738bb582 100644 --- a/evm_arithmetization/src/cpu/kernel/constants/mod.rs +++ b/evm_arithmetization/src/cpu/kernel/constants/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ethereum_types::{H256, U256}; +use ethereum_types::{Address, H160, H256, U256}; use hex_literal::hex; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; @@ -93,8 +93,8 @@ pub(crate) fn evm_constants() -> HashMap { U256::from(global_exit_root::GLOBAL_EXIT_ROOT_STORAGE_POS.1), ); c.insert( - global_exit_root::ADDRESS_SCALABLE_L2.0.into(), - U256::from_big_endian(&global_exit_root::ADDRESS_SCALABLE_L2.1), + "ADDRESS_SCALABLE_L2".into(), + U256::from_big_endian(&global_exit_root::ADDRESS_SCALABLE_L2.to_fixed_bytes()), ); c.insert( global_exit_root::ADDRESS_SCALABLE_L2_STATE_KEY.0.into(), @@ -403,7 +403,6 @@ const LINKED_LISTS_CONSTANTS: [(&str, u16); 5] = [ /// See and /// . pub mod cancun_constants { - use ethereum_types::{Address, H160}; use super::*; @@ -443,9 +442,9 @@ pub mod cancun_constants { "37d65eaa92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e42" )); - pub const BEACON_ROOTS_CONTRACT_STATE_KEY: (&str, [u8; 20]) = ( + pub const BEACON_ROOTS_CONTRACT_STATE_KEY: (&str, [u8; 32]) = ( "BEACON_ROOTS_CONTRACT_STATE_KEY", - *BEACON_ROOTS_CONTRACT_ADDRESS.as_fixed_bytes(), + *BEACON_ROOTS_CONTRACT_ADDRESS_HASHED.as_fixed_bytes(), ); pub const BEACON_ROOTS_CONTRACT_CODE: [u8; 97] = hex!("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500"); pub const BEACON_ROOTS_CONTRACT_CODE_HASH: [u8; 32] = @@ -476,8 +475,10 @@ pub mod global_exit_root { /// Taken from https://github.com/0xPolygonHermez/cdk-erigon/blob/61f0b6912055c73f6879ea7e9b5bac22ea5fc85c/zk/utils/global_exit_root.go#L16. pub const GLOBAL_EXIT_ROOT_MANAGER_L2: (&str, [u8; 20]) = ( "GLOBAL_EXIT_ROOT_MANAGER_L2", - hex!("a40D5f56745a118D0906a34E69aeC8C0Db1cB8fA"), + GLOBAL_EXIT_ROOT_ADDRESS.to_fixed_bytes(), ); + pub const GLOBAL_EXIT_ROOT_ADDRESS: Address = + H160(hex!("a40D5f56745a118D0906a34E69aeC8C0Db1cB8fA")); pub const GLOBAL_EXIT_ROOT_ADDRESS_HASHED: H256 = H256(hex!( "1d5e9c22b4b1a781d0ef63e9c1293c2a45fee966809019aa9804b5e7148b0ca9" )); @@ -486,13 +487,12 @@ pub mod global_exit_root { GLOBAL_EXIT_ROOT_ADDRESS_HASHED.to_fixed_bytes(), ); /// Taken from https://github.com/0xPolygonHermez/cdk-erigon/blob/dc3cbcc59a95769626056c7bc70aade501e7741d/core/state/intra_block_state_zkevm.go#L20. - pub const ADDRESS_SCALABLE_L2: (&str, [u8; 20]) = ( - "ADDRESS_SCALABLE_L2", - hex!("000000000000000000000000000000005ca1ab1e"), - ); + pub const ADDRESS_SCALABLE_L2: Address = H160(hex!("000000000000000000000000000000005ca1ab1e")); + pub const ADDRESS_SCALABLE_L2_ADDRESS_HASHED: H256 = H256(hex!( "4bff39c4f33dafcd90c45c9a0a1f2e72949b200788587b306eda5dd84aa87577" )); + pub const ADDRESS_SCALABLE_L2_STATE_KEY: (&str, [u8; 32]) = ( "ADDRESS_SCALABLE_L2_STATE_KEY", ADDRESS_SCALABLE_L2_ADDRESS_HASHED.to_fixed_bytes(), @@ -524,11 +524,11 @@ pub mod global_exit_root { #[test] fn hashed() { assert_eq!( - keccak_hash::keccak(GLOBAL_EXIT_ROOT_MANAGER_L2.1), + keccak_hash::keccak(GLOBAL_EXIT_ROOT_ADDRESS), GLOBAL_EXIT_ROOT_ADDRESS_HASHED ); assert_eq!( - keccak_hash::keccak(ADDRESS_SCALABLE_L2.1), + keccak_hash::keccak(ADDRESS_SCALABLE_L2), ADDRESS_SCALABLE_L2_ADDRESS_HASHED ); } diff --git a/trace_decoder/Cargo.toml b/trace_decoder/Cargo.toml index 7b9aa83e2..8f6a63159 100644 --- a/trace_decoder/Cargo.toml +++ b/trace_decoder/Cargo.toml @@ -54,16 +54,16 @@ glob = "0.3.1" libtest-mimic = "0.7.3" plonky2_maybe_rayon = { workspace = true } pretty_assertions = "1.4.0" -zero = { workspace = true, features = ["eth_mainnet"] } +zero = { workspace = true } pretty_env_logger = { workspace = true } serde_json = { workspace = true } serde_path_to_error = { workspace = true } [features] default = ["eth_mainnet"] -eth_mainnet = ["evm_arithmetization/eth_mainnet"] -cdk_erigon = ["evm_arithmetization/cdk_erigon"] -polygon_pos = ["evm_arithmetization/polygon_pos"] +eth_mainnet = ["evm_arithmetization/eth_mainnet", "zero/eth_mainnet"] +cdk_erigon = ["evm_arithmetization/cdk_erigon", "zero/cdk_erigon"] +polygon_pos = ["evm_arithmetization/polygon_pos", "zero/polygon_pos"] [[bench]] name = "block_processing" diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index 64c0dc2ee..d24991c65 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -10,8 +10,7 @@ use anyhow::{anyhow, bail, ensure, Context as _}; use ethereum_types::{Address, U256}; use evm_arithmetization::{ generation::{mpt::AccountRlp, TrieInputs}, - proof::TrieRoots, - testing_utils::{BEACON_ROOTS_CONTRACT_ADDRESS, HISTORY_BUFFER_LENGTH}, + proof::{BlockMetadata, TrieRoots}, GenerationInputs, }; use itertools::Itertools as _; @@ -53,6 +52,7 @@ pub fn entrypoint( checkpoint_state_trie_root, checkpoint_consolidated_hash, burn_addr, + ger_data, } = other; for (_, amt) in &mut withdrawals { @@ -64,8 +64,8 @@ pub fn entrypoint( storage, batch(txn_info, batch_size_hint), &mut code, - b_meta.block_timestamp, - b_meta.parent_beacon_block_root, + &b_meta, + ger_data, withdrawals, )?; @@ -96,7 +96,7 @@ pub fn entrypoint( }, signed_txns: byte_code.into_iter().map(Into::into).collect(), withdrawals, - ger_data: None, + ger_data, tries: TrieInputs { state_trie: state.into(), transactions_trie: transaction.into(), @@ -278,8 +278,8 @@ fn middle( // all batches SHOULD not be empty batches: Vec>>, code: &mut Hash2Code, - block_timestamp: U256, - parent_beacon_block_root: H256, + block: &BlockMetadata, + ger_data: Option<(H256, H256)>, // added to final batch mut withdrawals: Vec<(Address, U256)>, ) -> anyhow::Result>> { @@ -326,11 +326,11 @@ fn middle( let mut state_mask = BTreeSet::new(); if txn_ix == 0 { - do_beacon_hook( - block_timestamp, + do_pre_execution( + block, + ger_data, &mut storage_tries, &mut storage_masks, - parent_beacon_block_root, &mut state_mask, &mut state_trie, )?; @@ -533,10 +533,147 @@ fn middle( Ok(out) } +#[allow(unused_variables)] +/// Performs all the pre-txn execution rules of the targeted network. +fn do_pre_execution( + block: &BlockMetadata, + ger_data: Option<(H256, H256)>, + storage: &mut BTreeMap, + trim_storage: &mut BTreeMap>, + trim_state: &mut BTreeSet, + state_trie: &mut StateTrieT, +) -> anyhow::Result<()> { + // Ethereum mainnet: EIP-4788 + #[cfg(feature = "eth_mainnet")] + do_beacon_hook( + block.block_timestamp, + storage, + trim_storage, + block.parent_beacon_block_root, + trim_state, + state_trie, + )?; + + #[cfg(feature = "cdk_erigon")] + do_scalable_hook( + block, + ger_data, + storage, + trim_storage, + trim_state, + state_trie, + )?; + + Ok(()) +} + +#[cfg(feature = "cdk_erigon")] +/// Updates the storage of the Scalable and GER contracts, according to +/// . +/// +/// This is Polygon-CDK-specific, and runs at the start of the block, +/// before any transactions (as per the Etrog specification). +fn do_scalable_hook( + block: &BlockMetadata, + ger_data: Option<(H256, H256)>, + storage: &mut BTreeMap, + trim_storage: &mut BTreeMap>, + trim_state: &mut BTreeSet, + state_trie: &mut StateTrieT, +) -> anyhow::Result<()> { + use evm_arithmetization::testing_utils::{ + ADDRESS_SCALABLE_L2, ADDRESS_SCALABLE_L2_ADDRESS_HASHED, GLOBAL_EXIT_ROOT_ADDRESS, + GLOBAL_EXIT_ROOT_ADDRESS_HASHED, GLOBAL_EXIT_ROOT_STORAGE_POS, LAST_BLOCK_STORAGE_POS, + STATE_ROOT_STORAGE_POS, TIMESTAMP_STORAGE_POS, + }; + + if block.block_number.is_zero() { + return Err(anyhow!("Attempted to prove the Genesis block!")); + } + let scalable_storage = storage + .get_mut(&ADDRESS_SCALABLE_L2_ADDRESS_HASHED) + .context("missing scalable contract storage trie")?; + let scalable_trim = trim_storage.entry(ADDRESS_SCALABLE_L2).or_default(); + + let timestamp_slot_key = TrieKey::from_marker_slot(U256::from(TIMESTAMP_STORAGE_POS.1)); + + let timestamp = scalable_storage + .get(×tamp_slot_key) + .map(rlp::decode::) + .unwrap_or(Ok(0.into()))?; + let timestamp = core::cmp::max(timestamp, block.block_timestamp); + + // Store block number and largest timestamp + + for (ix, u) in [ + (U256::from(LAST_BLOCK_STORAGE_POS.1), block.block_number), + (U256::from(TIMESTAMP_STORAGE_POS.1), timestamp), + ] { + let slot = TrieKey::from_marker_slot(ix); + scalable_trim.insert(slot); + + // These values are never 0. + scalable_storage.insert(slot, alloy::rlp::encode(u.compat()))?; + scalable_trim.insert(slot); + } + + // Store previous block root hash + + let prev_block_root_hash = state_trie.root(); + let mut arr = [0; 64]; + (block.block_number - 1).to_big_endian(&mut arr[0..32]); + U256::from(STATE_ROOT_STORAGE_POS.1).to_big_endian(&mut arr[32..64]); + let slot = TrieKey::from_hash(keccak_hash::keccak(&arr)); + + scalable_storage.insert(slot, alloy::rlp::encode(prev_block_root_hash.compat()))?; + scalable_trim.insert(slot); + + trim_state.insert(TrieKey::from_address(ADDRESS_SCALABLE_L2)); + let mut scalable_acct = state_trie + .get_by_address(ADDRESS_SCALABLE_L2) + .context("missing scalable contract address")?; + scalable_acct.storage_root = scalable_storage.root(); + state_trie + .insert_by_address(ADDRESS_SCALABLE_L2, scalable_acct) + // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/275 + // Add an entry API + .expect("insert must succeed with the same key as a successful `get`"); + + // Update GER contract's storage if necessary + if let Some((root, l1blockhash)) = ger_data { + let ger_storage = storage + .get_mut(&GLOBAL_EXIT_ROOT_ADDRESS_HASHED) + .context("missing GER contract storage trie")?; + let ger_trim = trim_storage.entry(GLOBAL_EXIT_ROOT_ADDRESS).or_default(); + + let mut arr = [0; 64]; + arr[0..32].copy_from_slice(&root.0); + U256::from(GLOBAL_EXIT_ROOT_STORAGE_POS.1).to_big_endian(&mut arr[32..64]); + let slot = TrieKey::from_hash(keccak_hash::keccak(&arr)); + + ger_storage.insert(slot, alloy::rlp::encode(l1blockhash.compat()))?; + ger_trim.insert(slot); + + trim_state.insert(TrieKey::from_address(GLOBAL_EXIT_ROOT_ADDRESS)); + let mut ger_acct = state_trie + .get_by_address(GLOBAL_EXIT_ROOT_ADDRESS) + .context("missing GER contract address")?; + ger_acct.storage_root = ger_storage.root(); + state_trie + .insert_by_address(GLOBAL_EXIT_ROOT_ADDRESS, ger_acct) + // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/275 + // Add an entry API + .expect("insert must succeed with the same key as a successful `get`"); + } + + Ok(()) +} + +#[cfg(feature = "eth_mainnet")] /// Updates the storage of the beacon block root contract, /// according to /// -/// This is cancun-specific, and runs at the start of the block, +/// This is Cancun-specific, and runs at the start of the block, /// before any transactions (as per the EIP). fn do_beacon_hook( block_timestamp: U256, @@ -546,24 +683,27 @@ fn do_beacon_hook( trim_state: &mut BTreeSet, state_trie: &mut StateTrieT, ) -> anyhow::Result<()> { - let history_timestamp = block_timestamp % HISTORY_BUFFER_LENGTH.value; - let history_timestamp_next = history_timestamp + HISTORY_BUFFER_LENGTH.value; + use evm_arithmetization::testing_utils::{ + BEACON_ROOTS_CONTRACT_ADDRESS, BEACON_ROOTS_CONTRACT_ADDRESS_HASHED, HISTORY_BUFFER_LENGTH, + }; + + let timestamp_idx = block_timestamp % HISTORY_BUFFER_LENGTH.value; + let root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH.value; let beacon_storage = storage - .get_mut(&keccak_hash::keccak(BEACON_ROOTS_CONTRACT_ADDRESS)) + .get_mut(&BEACON_ROOTS_CONTRACT_ADDRESS_HASHED) .context("missing beacon contract storage trie")?; let beacon_trim = trim_storage .entry(BEACON_ROOTS_CONTRACT_ADDRESS) .or_default(); + for (ix, u) in [ - (history_timestamp, block_timestamp), + (timestamp_idx, block_timestamp), ( - history_timestamp_next, + root_idx, U256::from_big_endian(parent_beacon_block_root.as_bytes()), ), ] { - let mut h = [0; 32]; - ix.to_big_endian(&mut h); - let slot = TrieKey::from_hash(keccak_hash::keccak(H256::from_slice(&h))); + let slot = TrieKey::from_marker_slot(ix); beacon_trim.insert(slot); match u.is_zero() { diff --git a/trace_decoder/src/interface.rs b/trace_decoder/src/interface.rs index 901fef89a..ef2e64486 100644 --- a/trace_decoder/src/interface.rs +++ b/trace_decoder/src/interface.rs @@ -178,6 +178,11 @@ pub struct OtherBlockData { /// /// Only used if the `cfg_erigon` feature is activated. pub burn_addr: Option
, + /// The global exit root along with the l1blockhash to write to the GER + /// manager. + /// + /// Only used if the `cfg_erigon` feature is activated. + pub ger_data: Option<(H256, H256)>, } /// Data that is specific to a block and is constant for all txns in a given diff --git a/trace_decoder/src/typed_mpt.rs b/trace_decoder/src/typed_mpt.rs index 28a03aa33..389b215ea 100644 --- a/trace_decoder/src/typed_mpt.rs +++ b/trace_decoder/src/typed_mpt.rs @@ -4,7 +4,7 @@ use core::fmt; use std::{collections::BTreeMap, marker::PhantomData}; use copyvec::CopyVec; -use ethereum_types::{Address, H256}; +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}; @@ -126,6 +126,11 @@ impl TrieKey { pub fn from_address(address: Address) -> Self { Self::from_hash(keccak_hash::keccak(address)) } + pub fn from_marker_slot(slot: U256) -> Self { + let mut bytes = [0; 32]; + slot.to_big_endian(&mut bytes); + Self::from_hash(keccak_hash::keccak(bytes)) + } pub fn from_hash(H256(bytes): H256) -> Self { Self::new(AsNibbles(bytes)).expect("32 bytes is 64 nibbles, which fits") } @@ -422,8 +427,11 @@ impl StorageTrie { untyped: HashedPartialTrie::new_with_strategy(Node::Empty, strategy), } } + pub fn get(&mut self, key: &TrieKey) -> Option<&[u8]> { + self.untyped.get(key.into_nibbles()) + } pub fn insert(&mut self, key: TrieKey, value: Vec) -> anyhow::Result>> { - let prev = self.untyped.get(key.into_nibbles()).map(Vec::from); + let prev = self.get(&key).map(Vec::from); self.untyped.insert(key.into_nibbles(), value)?; Ok(prev) } From 235d3f3cd91ec39e09e1e2fb5f02371e983a3b7a Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 17 Sep 2024 09:29:49 -0400 Subject: [PATCH 2/8] Tweak precompile inclusion --- trace_decoder/src/core.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index d24991c65..07f5b4143 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -7,7 +7,7 @@ use std::{ use alloy::primitives::address; use alloy_compat::Compat as _; use anyhow::{anyhow, bail, ensure, Context as _}; -use ethereum_types::{Address, U256}; +use ethereum_types::{Address, H160, U256}; use evm_arithmetization::{ generation::{mpt::AccountRlp, TrieInputs}, proof::{BlockMetadata, TrieRoots}, @@ -462,10 +462,24 @@ fn middle( state_mask.extend(state_trie.reporting_remove(addr)?) } - let precompiled_addresses = address!("0000000000000000000000000000000000000001") - ..address!("000000000000000000000000000000000000000a"); + fn is_precompile(addr: H160) -> bool { + let precompiled_addresses = if cfg!(feature = "eth_mainnet") { + address!("0000000000000000000000000000000000000001") + ..address!("000000000000000000000000000000000000000a") + } else { + // Remove KZG Peval for non-Eth mainnet networks + address!("0000000000000000000000000000000000000001") + ..address!("0000000000000000000000000000000000000009") + }; + + precompiled_addresses.contains(&addr.compat()) + || (cfg!(feature = "polygon_pos") + // Include P256Verify for Polygon PoS + && addr.compat() + == address!("0000000000000000000000000000000000000001")) + } - if !precompiled_addresses.contains(&addr.compat()) { + if !is_precompile(addr) { // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/pull/613 // masking like this SHOULD be a space-saving optimization, // BUT if it's omitted, we actually get state root mismatches From 530550499cd7b4c93e77bda6163f3a1e456be5e0 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 17 Sep 2024 09:31:52 -0400 Subject: [PATCH 3/8] Add TODO for GER data --- zero/src/rpc/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/zero/src/rpc/mod.rs b/zero/src/rpc/mod.rs index cf8ec09cf..88be3e79e 100644 --- a/zero/src/rpc/mod.rs +++ b/zero/src/rpc/mod.rs @@ -312,6 +312,13 @@ where } else { None }, + ger_data: if cfg!(feature = "cdk_erigon") { + // TODO: https://github.com/0xPolygonZero/zk_evm/issues/565 + // Retrieve the actual GER data from `cdk-erigon`. + None + } else { + None + }, }; Ok(other_data) } From 037516302c1b23669ac3917a18136ca32358f7f2 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 17 Sep 2024 09:38:01 -0400 Subject: [PATCH 4/8] Tweaks --- trace_decoder/src/core.rs | 12 ++++++------ trace_decoder/src/typed_mpt.rs | 4 ++-- zero/src/rpc/native/state.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index 07f5b4143..e7a813ddd 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -476,7 +476,7 @@ fn middle( || (cfg!(feature = "polygon_pos") // Include P256Verify for Polygon PoS && addr.compat() - == address!("0000000000000000000000000000000000000001")) + == address!("0000000000000000000000000000000000000100")) } if !is_precompile(addr) { @@ -609,7 +609,7 @@ fn do_scalable_hook( .context("missing scalable contract storage trie")?; let scalable_trim = trim_storage.entry(ADDRESS_SCALABLE_L2).or_default(); - let timestamp_slot_key = TrieKey::from_marker_slot(U256::from(TIMESTAMP_STORAGE_POS.1)); + let timestamp_slot_key = TrieKey::from_slot_position(U256::from(TIMESTAMP_STORAGE_POS.1)); let timestamp = scalable_storage .get(×tamp_slot_key) @@ -623,7 +623,7 @@ fn do_scalable_hook( (U256::from(LAST_BLOCK_STORAGE_POS.1), block.block_number), (U256::from(TIMESTAMP_STORAGE_POS.1), timestamp), ] { - let slot = TrieKey::from_marker_slot(ix); + let slot = TrieKey::from_slot_position(ix); scalable_trim.insert(slot); // These values are never 0. @@ -637,7 +637,7 @@ fn do_scalable_hook( let mut arr = [0; 64]; (block.block_number - 1).to_big_endian(&mut arr[0..32]); U256::from(STATE_ROOT_STORAGE_POS.1).to_big_endian(&mut arr[32..64]); - let slot = TrieKey::from_hash(keccak_hash::keccak(&arr)); + let slot = TrieKey::from_hash(keccak_hash::keccak(arr)); scalable_storage.insert(slot, alloy::rlp::encode(prev_block_root_hash.compat()))?; scalable_trim.insert(slot); @@ -663,7 +663,7 @@ fn do_scalable_hook( let mut arr = [0; 64]; arr[0..32].copy_from_slice(&root.0); U256::from(GLOBAL_EXIT_ROOT_STORAGE_POS.1).to_big_endian(&mut arr[32..64]); - let slot = TrieKey::from_hash(keccak_hash::keccak(&arr)); + let slot = TrieKey::from_hash(keccak_hash::keccak(arr)); ger_storage.insert(slot, alloy::rlp::encode(l1blockhash.compat()))?; ger_trim.insert(slot); @@ -717,7 +717,7 @@ fn do_beacon_hook( U256::from_big_endian(parent_beacon_block_root.as_bytes()), ), ] { - let slot = TrieKey::from_marker_slot(ix); + let slot = TrieKey::from_slot_position(ix); beacon_trim.insert(slot); match u.is_zero() { diff --git a/trace_decoder/src/typed_mpt.rs b/trace_decoder/src/typed_mpt.rs index 389b215ea..34b1b9312 100644 --- a/trace_decoder/src/typed_mpt.rs +++ b/trace_decoder/src/typed_mpt.rs @@ -126,9 +126,9 @@ impl TrieKey { pub fn from_address(address: Address) -> Self { Self::from_hash(keccak_hash::keccak(address)) } - pub fn from_marker_slot(slot: U256) -> Self { + pub fn from_slot_position(pos: U256) -> Self { let mut bytes = [0; 32]; - slot.to_big_endian(&mut bytes); + pos.to_big_endian(&mut bytes); Self::from_hash(keccak_hash::keccak(bytes)) } pub fn from_hash(H256(bytes): H256) -> Self { diff --git a/zero/src/rpc/native/state.rs b/zero/src/rpc/native/state.rs index 579c3f5a6..e2d64e4df 100644 --- a/zero/src/rpc/native/state.rs +++ b/zero/src/rpc/native/state.rs @@ -97,7 +97,7 @@ fn insert_beacon_roots_update( ) -> anyhow::Result<()> { use alloy::primitives::U256; use evm_arithmetization::testing_utils::{ - BEACON_ROOTS_CONTRACT_STATE_KEY, HISTORY_BUFFER_LENGTH, + BEACON_ROOTS_CONTRACT_ADDRESS, HISTORY_BUFFER_LENGTH, }; let timestamp = U256::from(block.header.timestamp); @@ -107,7 +107,7 @@ fn insert_beacon_roots_update( (timestamp % chunk).into(), // timestamp_idx ((timestamp % chunk) + chunk).into(), // root_idx ]); - state_access.insert(BEACON_ROOTS_CONTRACT_STATE_KEY.1.into(), keys); + state_access.insert(BEACON_ROOTS_CONTRACT_ADDRESS.0.into(), keys); Ok(()) } From 2a86e73624187196f8528f2d7341ab73897c2c1f Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 17 Sep 2024 10:05:50 -0400 Subject: [PATCH 5/8] Tweak --- trace_decoder/src/typed_mpt.rs | 2 +- zero/src/rpc/native/state.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/trace_decoder/src/typed_mpt.rs b/trace_decoder/src/typed_mpt.rs index 34b1b9312..dc56d54a1 100644 --- a/trace_decoder/src/typed_mpt.rs +++ b/trace_decoder/src/typed_mpt.rs @@ -129,7 +129,7 @@ impl TrieKey { pub fn from_slot_position(pos: U256) -> Self { let mut bytes = [0; 32]; pos.to_big_endian(&mut bytes); - Self::from_hash(keccak_hash::keccak(bytes)) + Self::from_hash(keccak_hash::keccak(H256::from_slice(&bytes))) } pub fn from_hash(H256(bytes): H256) -> Self { Self::new(AsNibbles(bytes)).expect("32 bytes is 64 nibbles, which fits") diff --git a/zero/src/rpc/native/state.rs b/zero/src/rpc/native/state.rs index e2d64e4df..833bb9070 100644 --- a/zero/src/rpc/native/state.rs +++ b/zero/src/rpc/native/state.rs @@ -107,7 +107,7 @@ fn insert_beacon_roots_update( (timestamp % chunk).into(), // timestamp_idx ((timestamp % chunk) + chunk).into(), // root_idx ]); - state_access.insert(BEACON_ROOTS_CONTRACT_ADDRESS.0.into(), keys); + state_access.insert(BEACON_ROOTS_CONTRACT_ADDRESS.as_fixed_bytes().into(), keys); Ok(()) } From 6ad07494d398bf553ddc2a42dee1c4111db92a9e Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 17 Sep 2024 10:17:50 -0400 Subject: [PATCH 6/8] Add missing feature --- zero/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zero/Cargo.toml b/zero/Cargo.toml index 7086ecbd6..3f8023313 100644 --- a/zero/Cargo.toml +++ b/zero/Cargo.toml @@ -61,9 +61,9 @@ vergen-git2 = { version = "1.0.0", features = ["build"] } [features] default = ["eth_mainnet"] -eth_mainnet = ["evm_arithmetization/eth_mainnet", "proof_gen/eth_mainnet"] -cdk_erigon = ["evm_arithmetization/cdk_erigon", "proof_gen/cdk_erigon"] -polygon_pos = ["evm_arithmetization/polygon_pos", "proof_gen/polygon_pos"] +eth_mainnet = ["evm_arithmetization/eth_mainnet", "proof_gen/eth_mainnet", "trace_decoder/eth_mainnet"] +cdk_erigon = ["evm_arithmetization/cdk_erigon", "proof_gen/cdk_erigon", "trace_decoder/cdk_erigon"] +polygon_pos = ["evm_arithmetization/polygon_pos", "proof_gen/polygon_pos", "trace_decoder/polygon_pos"] [lints] workspace = true From 6e4f070b348af603435a398958516e8645cecae1 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Wed, 18 Sep 2024 14:54:29 -0400 Subject: [PATCH 7/8] Remove duplicate --- trace_decoder/src/core.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index e7a813ddd..5442b0611 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -624,7 +624,6 @@ fn do_scalable_hook( (U256::from(TIMESTAMP_STORAGE_POS.1), timestamp), ] { let slot = TrieKey::from_slot_position(ix); - scalable_trim.insert(slot); // These values are never 0. scalable_storage.insert(slot, alloy::rlp::encode(u.compat()))?; From 63e03656b47542ae78faa2befc7304ca8b9ec161 Mon Sep 17 00:00:00 2001 From: 0xaatif Date: Thu, 19 Sep 2024 10:56:54 +0100 Subject: [PATCH 8/8] discuss: no cfg --- trace_decoder/src/core.rs | 76 +++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index 5442b0611..0c13d724c 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -31,6 +31,7 @@ pub fn entrypoint( trace: BlockTrace, other: OtherBlockData, batch_size_hint: usize, + pre_execution: Option, ) -> anyhow::Result>> { ensure!(batch_size_hint != 0); @@ -67,6 +68,7 @@ pub fn entrypoint( &b_meta, ger_data, withdrawals, + pre_execution, )?; let mut running_gas_used = 0; @@ -269,6 +271,7 @@ struct IntraBlockTries { } /// Does the main work mentioned in the [module documentation](super). +#[allow(clippy::too_many_arguments)] // TODO(0xaatif): break this out into a `struct MiddleArgs` fn middle( // state at the beginning of the block mut state_trie: StateTrieT, @@ -282,6 +285,7 @@ fn middle( ger_data: Option<(H256, H256)>, // added to final batch mut withdrawals: Vec<(Address, U256)>, + pre_execution: Option, ) -> anyhow::Result>> { // Initialise the storage tries. for (haddr, acct) in state_trie.iter() { @@ -326,14 +330,25 @@ fn middle( let mut state_mask = BTreeSet::new(); if txn_ix == 0 { - do_pre_execution( - block, - ger_data, - &mut storage_tries, - &mut storage_masks, - &mut state_mask, - &mut state_trie, - )?; + match pre_execution { + Some(PreExecution::Beacon) => beacon_pre_execution( + block.block_timestamp, + &mut storage_tries, + &mut storage_masks, + block.parent_beacon_block_root, + &mut state_mask, + &mut state_trie, + )?, + Some(PreExecution::Scalable) => scalable_pre_execution( + block, + ger_data, + &mut storage_tries, + &mut storage_masks, + &mut state_mask, + &mut state_trie, + )?, + None => {} + } } for txn in batch { @@ -547,47 +562,21 @@ fn middle( Ok(out) } -#[allow(unused_variables)] -/// Performs all the pre-txn execution rules of the targeted network. -fn do_pre_execution( - block: &BlockMetadata, - ger_data: Option<(H256, H256)>, - storage: &mut BTreeMap, - trim_storage: &mut BTreeMap>, - trim_state: &mut BTreeSet, - state_trie: &mut StateTrieT, -) -> anyhow::Result<()> { - // Ethereum mainnet: EIP-4788 - #[cfg(feature = "eth_mainnet")] - do_beacon_hook( - block.block_timestamp, - storage, - trim_storage, - block.parent_beacon_block_root, - trim_state, - state_trie, - )?; - - #[cfg(feature = "cdk_erigon")] - do_scalable_hook( - block, - ger_data, - storage, - trim_storage, - trim_state, - state_trie, - )?; - - Ok(()) +/// What pre-execution procedure to perform. +#[derive(Debug)] +pub enum PreExecution { + /// See [`beacon_pre_execution`]. + Beacon, + /// See [`scalable_pre_execution`]. + Scalable, } -#[cfg(feature = "cdk_erigon")] /// Updates the storage of the Scalable and GER contracts, according to /// . /// /// This is Polygon-CDK-specific, and runs at the start of the block, /// before any transactions (as per the Etrog specification). -fn do_scalable_hook( +fn scalable_pre_execution( block: &BlockMetadata, ger_data: Option<(H256, H256)>, storage: &mut BTreeMap, @@ -682,13 +671,12 @@ fn do_scalable_hook( Ok(()) } -#[cfg(feature = "eth_mainnet")] /// Updates the storage of the beacon block root contract, /// according to /// /// This is Cancun-specific, and runs at the start of the block, /// before any transactions (as per the EIP). -fn do_beacon_hook( +fn beacon_pre_execution( block_timestamp: U256, storage: &mut BTreeMap, trim_storage: &mut BTreeMap>,