From 0bb9e6f5b6cb5e1e5488f36a509b8f5ebb87be8e Mon Sep 17 00:00:00 2001 From: kathy <22675649+anylots@users.noreply.github.com> Date: Thu, 27 Aug 2026 15:43:43 +0800 Subject: [PATCH 1/3] fix(prover): Add constraints on the storage trie within the circuit. --- .../crates/executor/client/src/types/input.rs | 28 +++++++++++++++--- prover/crates/primitives/src/predeployed.rs | 29 ------------------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/prover/crates/executor/client/src/types/input.rs b/prover/crates/executor/client/src/types/input.rs index 4ac2fd13b..b8c8ff08e 100644 --- a/prover/crates/executor/client/src/types/input.rs +++ b/prover/crates/executor/client/src/types/input.rs @@ -2,6 +2,7 @@ use alloy_primitives::{map::HashMap, U256}; use prover_mpt::EthereumState; use prover_primitives::{types::block::L2Block, Address}; use prover_storage_witness::TrieDB; +use reth_trie::{TrieAccount, EMPTY_ROOT_HASH}; use revm::{primitives::keccak256, state::Bytecode}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; @@ -30,12 +31,26 @@ pub struct BlockInput { } impl BlockInput { - pub fn witness_db(&self) -> Result, ClientError> { - // verify the state root + fn validate_parent_state(&self) -> Result<(), ClientError> { if self.current_block.prev_state_root != self.parent_state.state_root() { return Err(ClientError::InvalidHeaderStateRoot); } + for (hashed_address, storage_trie) in &self.parent_state.storage_tries { + let account = + self.parent_state.state_trie.get_rlp::(hashed_address.as_slice())?; + let storage_root = account.map_or(EMPTY_ROOT_HASH, |account| account.storage_root); + if storage_trie.hash() != storage_root { + return Err(ClientError::MismatchedStorageRoot); + } + } + + Ok(()) + } + + pub fn witness_db(&self) -> Result, ClientError> { + self.validate_parent_state()?; + let bytecodes_by_hash = self.bytecodes.iter().map(|code| (code.hash_slow(), code)).collect::>(); @@ -50,13 +65,18 @@ impl BlockInput { /// Get storage value of address at index. pub fn get_storage_value(&self, address: Address, index: U256) -> Result { let hashed_address = keccak256(address); - let hashed_address = hashed_address.as_slice(); let storage_trie = self .parent_state .storage_tries - .get(hashed_address) + .get(&hashed_address) .expect("A storage trie must be provided for each account"); + let account = + self.parent_state.state_trie.get_rlp::(hashed_address.as_slice())?; + let storage_root = account.map_or(EMPTY_ROOT_HASH, |account| account.storage_root); + if storage_trie.hash() != storage_root { + return Err(ClientError::MismatchedStorageRoot); + } Ok(storage_trie .get_rlp::(keccak256(index.to_be_bytes::<32>()).as_slice()) diff --git a/prover/crates/primitives/src/predeployed.rs b/prover/crates/primitives/src/predeployed.rs index dd5800071..3e8e5c5b1 100644 --- a/prover/crates/primitives/src/predeployed.rs +++ b/prover/crates/primitives/src/predeployed.rs @@ -1,32 +1,3 @@ -/// Predeployed Gas Price Oracle -pub mod l1_gas_price_oracle { - use alloy_primitives::{address, Address, U256}; - - /// L1GasPriceOracle predeployed address - pub const ADDRESS: Address = address!("5300000000000000000000000000000000000002"); - /// L1 base fee slot in L1GasPriceOracle - pub const BASE_FEE_SLOT: U256 = U256::from_limbs([1, 0, 0, 0]); - - /// The following 2 slots will be depreciated after curie fork - /// L1 overhead slot in L1GasPriceOracle - pub const OVERHEAD_SLOT: U256 = U256::from_limbs([2, 0, 0, 0]); - /// L1 scalar slot in L1GasPriceOracle - pub const SCALAR_SLOT: U256 = U256::from_limbs([3, 0, 0, 0]); - - /// THe following 3 slots plus `BASE_FEE_SLOT` will be used for l1 fee after curie fork - /// L1 BlobBaseFee slot in L1GasPriceOracle after Curie fork - pub const L1_BLOB_BASEFEE_SLOT: U256 = U256::from_limbs([5, 0, 0, 0]); - /// L1 commitScalar slot in L1GasPriceOracle after Curie fork - pub const COMMIT_SCALAR_SLOT: U256 = U256::from_limbs([6, 0, 0, 0]); - /// L1 blob_scalar slot in L1GasPriceOracle after Curie fork - pub const BLOB_SCALAR_SLOT: U256 = U256::from_limbs([7, 0, 0, 0]); - /// L1 isCurie slot in L1GasPriceOracle after Curie fork - pub const IS_CURIE_SLOT: U256 = U256::from_limbs([8, 0, 0, 0]); - /// Initial commit scalar after curie fork - pub const INITIAL_COMMIT_SCALAR: U256 = U256::from_limbs([230759955285, 0, 0, 0]); - /// Initial blob scalar after curie fork - pub const INITIAL_BLOB_SCALAR: U256 = U256::from_limbs([417565260, 0, 0, 0]); -} /// Predeployed L2ToL1Message pub mod l2_to_l1_message { From 9f50db1834ccc9c65cff12b6870cdf9d4d777b74 Mon Sep 17 00:00:00 2001 From: Kathy <22675649+anylots@users.noreply.github.com> Date: Thu, 27 Aug 2026 17:23:49 +0800 Subject: [PATCH 2/3] fix(prover): add block check --- contracts/src/deploy-config/holesky.ts | 2 +- contracts/src/deploy-config/hoodi.ts | 2 +- contracts/src/deploy-config/l1.ts | 2 +- contracts/src/deploy-config/qanetl1.ts | 2 +- contracts/src/deploy-config/sepolia.ts | 2 +- contracts/src/deploy-config/testnetl1.ts | 2 +- prover/bin/client/elf/verifier-client | Bin 6927120 -> 6925504 bytes prover/bin/server/src/queue.rs | 28 ++++++++++-------- prover/bin/shadow-prove/contracts/README.md | 2 +- prover/contracts/README.md | 2 +- .../crates/executor/client/src/types/error.rs | 2 ++ .../crates/executor/client/src/types/input.rs | 5 ++-- .../client/src/verifier/evm_verifier.rs | 28 +++++++++++++----- prover/crates/storage/witness-db/src/lib.rs | 8 +++-- 14 files changed, 54 insertions(+), 33 deletions(-) diff --git a/contracts/src/deploy-config/holesky.ts b/contracts/src/deploy-config/holesky.ts index f5a5a090f..b5407b027 100644 --- a/contracts/src/deploy-config/holesky.ts +++ b/contracts/src/deploy-config/holesky.ts @@ -14,7 +14,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x001fe18a35489f0e7ae203bc2b1f26b7696f00bafa8000518c94a479d29c4076', + programVkey: '0x00b450ec2a1b8dfba81ade90afbcc96842055548b814c991bb13bdca34980c63', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/hoodi.ts b/contracts/src/deploy-config/hoodi.ts index 15f50dda4..b95fa1434 100644 --- a/contracts/src/deploy-config/hoodi.ts +++ b/contracts/src/deploy-config/hoodi.ts @@ -17,7 +17,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x001fe18a35489f0e7ae203bc2b1f26b7696f00bafa8000518c94a479d29c4076', + programVkey: '0x00b450ec2a1b8dfba81ade90afbcc96842055548b814c991bb13bdca34980c63', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/l1.ts b/contracts/src/deploy-config/l1.ts index 680b89db7..6f09ba7eb 100644 --- a/contracts/src/deploy-config/l1.ts +++ b/contracts/src/deploy-config/l1.ts @@ -17,7 +17,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x001fe18a35489f0e7ae203bc2b1f26b7696f00bafa8000518c94a479d29c4076', + programVkey: '0x00b450ec2a1b8dfba81ade90afbcc96842055548b814c991bb13bdca34980c63', // rollup contract config // initialize config finalizationPeriodSeconds: 10, diff --git a/contracts/src/deploy-config/qanetl1.ts b/contracts/src/deploy-config/qanetl1.ts index c21ea93b6..b869fa25c 100644 --- a/contracts/src/deploy-config/qanetl1.ts +++ b/contracts/src/deploy-config/qanetl1.ts @@ -14,7 +14,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x001fe18a35489f0e7ae203bc2b1f26b7696f00bafa8000518c94a479d29c4076', + programVkey: '0x00b450ec2a1b8dfba81ade90afbcc96842055548b814c991bb13bdca34980c63', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/sepolia.ts b/contracts/src/deploy-config/sepolia.ts index 0facf9f99..d2db493cf 100644 --- a/contracts/src/deploy-config/sepolia.ts +++ b/contracts/src/deploy-config/sepolia.ts @@ -18,7 +18,7 @@ const config = { /** * ---to---legacy property */ - programVkey: '0x001fe18a35489f0e7ae203bc2b1f26b7696f00bafa8000518c94a479d29c4076', + programVkey: '0x00b450ec2a1b8dfba81ade90afbcc96842055548b814c991bb13bdca34980c63', rollupMinDeposit: 0.0001, rollupProofWindow: 86400, rollupGenesisBlockNumber: 0, diff --git a/contracts/src/deploy-config/testnetl1.ts b/contracts/src/deploy-config/testnetl1.ts index 501bb7b7f..a8d567ad9 100644 --- a/contracts/src/deploy-config/testnetl1.ts +++ b/contracts/src/deploy-config/testnetl1.ts @@ -13,7 +13,7 @@ const config = { sequencerWindowSize: 200, channelTimeout: 120, - programVkey: '0x001fe18a35489f0e7ae203bc2b1f26b7696f00bafa8000518c94a479d29c4076', + programVkey: '0x00b450ec2a1b8dfba81ade90afbcc96842055548b814c991bb13bdca34980c63', rollupMinDeposit: 1, rollupProofWindow: 100, rollupGenesisBlockNumber: 0, diff --git a/prover/bin/client/elf/verifier-client b/prover/bin/client/elf/verifier-client index 7541750725b7565bf132461f8e6eb0129ba6309d..d37f736a8c1b78bb730d5ca3337c1a5393a20c21 100755 GIT binary patch delta 1424794 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