Skip to content

Commit ed360e9

Browse files
authored
Merge f1aef37 into bbd8e76
2 parents bbd8e76 + f1aef37 commit ed360e9

File tree

7 files changed

+84
-6
lines changed

7 files changed

+84
-6
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/ef_tests/blockchain/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ ethrex-common.workspace = true
99
ethrex-storage.workspace = true
1010
ethrex-rlp.workspace = true
1111
ethrex-vm.workspace = true
12+
ethrex-prover = { path = "../../../crates/l2/prover", default-features = false, optional = true }
13+
zkvm_interface = { path = "../../../crates/l2/prover/zkvm/interface", default-features = false, optional = true }
1214

1315
serde.workspace = true
1416
serde_json.workspace = true
1517
bytes.workspace = true
1618
hex.workspace = true
1719
lazy_static.workspace = true
18-
tokio = { workspace = true , features = ["full"] }
20+
tokio = { workspace = true, features = ["full"] }
1921

2022
[dev-dependencies]
2123
datatest-stable = "0.2.9"
@@ -28,6 +30,7 @@ default = ["c-kzg", "blst"]
2830
blst = ["ethrex-vm/blst"]
2931
c-kzg = ["ethrex-blockchain/c-kzg"]
3032
levm = []
33+
stateless = ["dep:ethrex-prover", "dep:zkvm_interface"]
3134

3235
[[test]]
3336
name = "cancun"

cmd/ef_tests/blockchain/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ test-levm: $(SPECTEST_VECTORS_DIR) ## 🧪 Run blockchain tests with LEVM
2929
test-revm: $(SPECTEST_VECTORS_DIR) ## 🧪 Run blockchain tests with REVM
3030
cargo test --release
3131

32+
test-stateless: $(SPECTEST_VECTORS_DIR) ## 🧪 Run blockchain tests with LEVM with stateless execution
33+
cargo test --release --features levm,stateless
34+
3235
test: $(SPECTEST_VECTORS_DIR) ## 🧪 Run blockchain tests with both VMs
3336
$(MAKE) test-levm
3437
$(MAKE) test-revm

cmd/ef_tests/blockchain/test_runner.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use ethrex_common::types::{
1111
use ethrex_rlp::decode::RLPDecode;
1212
use ethrex_storage::{EngineType, Store};
1313
use ethrex_vm::EvmEngine;
14+
#[cfg(feature = "stateless")]
15+
use zkvm_interface::io::ProgramInput;
1416

1517
pub fn parse_and_execute(path: &Path, evm: EvmEngine, skipped_tests: Option<&[&str]>) {
1618
let rt = tokio::runtime::Runtime::new().unwrap();
@@ -64,7 +66,7 @@ pub async fn run_ef_test(test_key: &str, test: &TestUnit, evm: EvmEngine) {
6466
"Transaction execution unexpectedly failed on test: {}, with error {}",
6567
test_key, error
6668
);
67-
return;
69+
break;
6870
}
6971
Ok(_) => {
7072
assert!(
@@ -77,7 +79,9 @@ pub async fn run_ef_test(test_key: &str, test: &TestUnit, evm: EvmEngine) {
7779
}
7880
}
7981
}
80-
check_poststate_against_db(test_key, test, &store).await
82+
check_poststate_against_db(test_key, test, &store).await;
83+
#[cfg(feature = "stateless")]
84+
re_run_stateless(blockchain, test, genesis_block_header).await;
8185
}
8286

8387
/// Tests the rlp decoding of a block
@@ -221,3 +225,47 @@ async fn check_poststate_against_db(test_key: &str, test: &TestUnit, db: &Store)
221225
assert!(last_block.is_some(), "Block hash is not stored in db");
222226
// State root was alredy validated by `add_block``
223227
}
228+
229+
#[cfg(feature = "stateless")]
230+
async fn re_run_stateless(
231+
blockchain: Blockchain,
232+
test: &TestUnit,
233+
genesis_header: CoreBlockHeader,
234+
) {
235+
let blocks = test
236+
.blocks
237+
.iter()
238+
.map(|block_fixture| block_fixture.block().unwrap().clone().into())
239+
.collect::<Vec<CoreBlock>>();
240+
241+
let test_should_fail = test.blocks.iter().any(|t| t.expect_exception.is_some());
242+
243+
let witness = blockchain
244+
.generate_witness_for_blocks(&blocks)
245+
.await
246+
.unwrap_or_else(|_| {
247+
use ethrex_common::types::block_execution_witness::ExecutionWitnessResult;
248+
if test_should_fail {
249+
ExecutionWitnessResult {
250+
state_trie_nodes: Some(Vec::new()),
251+
storage_trie_nodes: Some(HashMap::new()),
252+
..Default::default()
253+
}
254+
} else {
255+
panic!("Failed to create witness for a test that should not fail")
256+
}
257+
});
258+
259+
let program_input = ProgramInput {
260+
blocks,
261+
parent_block_header: genesis_header,
262+
db: witness,
263+
elasticity_multiplier: ethrex_common::types::ELASTICITY_MULTIPLIER,
264+
};
265+
266+
if let Err(e) = ethrex_prover_lib::execute(program_input) {
267+
assert!(test_should_fail, "Expected test to succeed failed with {e}")
268+
} else {
269+
assert!(!test_should_fail, "Expected test to fail succeeded")
270+
}
271+
}

crates/blockchain/blockchain.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,14 @@ impl Blockchain {
175175
.map_err(|_e| ChainError::Custom("Failed to get block hashes".to_string()))?
176176
.clone();
177177
block_hashes.extend(logger_block_hashes);
178-
178+
// Access all the accounts needed for withdrawals
179+
if let Some(withdrawals) = block.body.withdrawals.as_ref() {
180+
for withdrawal in withdrawals {
181+
let _ = trie.get(&hash_address(&withdrawal.address)).map_err(|_e| {
182+
ChainError::Custom("Failed to access account from trie".to_string())
183+
});
184+
}
185+
}
179186
// Access all the accounts from the initial trie
180187
// Record all the storage nodes for the initial state
181188
for (account, keys) in logger

crates/common/trie/trie.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,11 @@ impl Trie {
394394
}
395395

396396
pub fn root_node(&self) -> Result<Option<Node>, TrieError> {
397-
self.root.get_node(self.db.as_ref())
397+
if self.root.compute_hash().finalize() == *EMPTY_TRIE_HASH {
398+
self.root.get_node(self.db.as_ref())
399+
} else {
400+
Ok(None)
401+
}
398402
}
399403

400404
/// Creates a new Trie based on a temporary InMemory DB

crates/l2/prover/zkvm/interface/src/execution.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use crate::withdrawals::{get_block_withdrawals, get_withdrawals_merkle_root};
55

66
use crate::io::{ProgramInput, ProgramOutput};
77
use ethrex_blockchain::error::ChainError;
8-
use ethrex_blockchain::{validate_block, validate_gas_used};
8+
use ethrex_blockchain::{
9+
validate_block, validate_gas_used, validate_receipts_root, validate_requests_hash,
10+
};
911
use ethrex_common::{
1012
types::{block_execution_witness::ExecutionWitnessResult, Block, BlockHeader},
1113
H256,
@@ -22,6 +24,10 @@ pub enum StatelessExecutionError {
2224
BlockValidationError(ChainError),
2325
#[error("Gas validation error: {0}")]
2426
GasValidationError(ChainError),
27+
#[error("Withdrawals validation error: {0}")]
28+
RequestsRootValidationError(ChainError),
29+
#[error("Receipts validation error: {0}")]
30+
ReceiptsRootValidationError(ChainError),
2531
#[error("EVM error: {0}")]
2632
EvmError(EvmError),
2733
#[cfg(feature = "l2")]
@@ -190,6 +196,11 @@ fn execute_stateless(
190196

191197
validate_gas_used(&receipts, &block.header)
192198
.map_err(StatelessExecutionError::GasValidationError)?;
199+
validate_receipts_root(&block.header, &receipts)
200+
.map_err(StatelessExecutionError::ReceiptsRootValidationError)?;
201+
// validate_requests_hash doesn't do anything for l2 blocks as this verifies l1 requests (withdrawals, deposits and consolidations)
202+
validate_requests_hash(&block.header, &db.chain_config, &result.requests)
203+
.map_err(StatelessExecutionError::RequestsRootValidationError)?;
193204
parent_header = &block.header;
194205
acc_receipts.push(receipts);
195206
}

0 commit comments

Comments
 (0)