Skip to content

Commit 5dc4763

Browse files
authored
Merge d68ce59 into beb31d8
2 parents beb31d8 + d68ce59 commit 5dc4763

File tree

6 files changed

+73
-39
lines changed

6 files changed

+73
-39
lines changed

cmd/ethrex_replay/src/cli.rs

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,28 @@ use ethrex_storage::{
2323
};
2424
#[cfg(feature = "l2")]
2525
use ethrex_storage_rollup::EngineTypeRollup;
26-
use ethrex_trie::{InMemoryTrieDB, Node, NodeHash, NodeRef, node::LeafNode};
26+
use ethrex_trie::{
27+
InMemoryTrieDB, Node,
28+
node::{BranchNode, LeafNode},
29+
};
2730
use reqwest::Url;
2831
#[cfg(feature = "l2")]
2932
use std::path::Path;
3033
use std::{
3134
cmp::max,
32-
collections::HashSet,
3335
io::Write,
3436
sync::{Arc, RwLock},
3537
time::{Instant, SystemTime},
3638
};
3739
use tracing::info;
3840

39-
use crate::bench::run_and_measure;
4041
use crate::fetcher::get_blockdata;
4142
#[cfg(not(feature = "l2"))]
4243
use crate::fetcher::get_rangedata;
4344
#[cfg(not(feature = "l2"))]
4445
use crate::plot_composition::plot;
4546
use crate::run::{exec, prove, run_tx};
47+
use crate::{bench::run_and_measure, helpers::get_referenced_hashes};
4648
use crate::{
4749
block_run_report::{BlockRunReport, ReplayerMode},
4850
cache::Cache,
@@ -463,7 +465,7 @@ async fn replay_no_zkvm(cache: Cache, opts: &EthrexReplayOptions) -> eyre::Resul
463465
let guest_program = GuestProgramState::try_from(witness.clone())?;
464466

465467
// This will contain all code hashes with the corresponding bytecode
466-
// For the code hashes that we don't have we'll will it with <CodeHash, Bytes::new()>
468+
// For the code hashes that we don't have we'll fill it with <CodeHash, Bytes::new()>
467469
let mut all_codes_hashed = guest_program.codes_hashed.clone();
468470

469471
let in_memory_store = InMemoryStore::new();
@@ -479,42 +481,16 @@ async fn replay_no_zkvm(cache: Cache, opts: &EthrexReplayOptions) -> eyre::Resul
479481
// 2. Get all code hashes that exist in the accounts that we have so that if we don't have the code we set it to empty bytes.
480482
// We do these things because sometimes the witness may be incomplete and in those cases we don't want failures for missing data.
481483
// This only applies when we use the InMemoryDatabase and not when we use the ExecutionWitness as database, that's because in the latter failures are dismissed and we fall back to default values.
482-
let mut nodes = state_trie_nodes.lock().unwrap();
483-
let mut referenced_node_hashes: HashSet<NodeHash> = HashSet::new(); // All hashes referenced in the trie (by Branch or Ext nodes).
484-
485-
for (_node_hash, node_rlp) in nodes.iter() {
486-
let node = Node::decode(node_rlp)?;
487-
match node {
488-
Node::Branch(node) => {
489-
for choice in &node.choices {
490-
let NodeRef::Hash(hash) = *choice else {
491-
unreachable!()
492-
};
493-
494-
referenced_node_hashes.insert(hash);
495-
}
496-
}
497-
Node::Extension(node) => {
498-
let NodeRef::Hash(hash) = node.child else {
499-
unreachable!()
500-
};
501-
502-
referenced_node_hashes.insert(hash);
503-
}
504-
Node::Leaf(node) => {
505-
let info = AccountState::decode(&node.value)?;
506-
all_codes_hashed.entry(info.code_hash).or_insert(vec![]);
507-
}
508-
}
509-
}
484+
let mut state_nodes = state_trie_nodes.lock().unwrap();
485+
let referenced_node_hashes = get_referenced_hashes(&state_nodes)?;
510486

487+
let dummy_leaf = Node::from(LeafNode::default()).encode_to_vec();
511488
// Insert arbitrary leaf nodes to state trie.
512489
for hash in referenced_node_hashes {
513-
let dummy_leaf: Node = LeafNode::default().into();
514-
nodes.entry(hash).or_insert(dummy_leaf.encode_to_vec());
490+
state_nodes.entry(hash).or_insert(dummy_leaf.clone());
515491
}
516492

517-
drop(nodes);
493+
drop(state_nodes);
518494

519495
let mut inner_store = in_memory_store.inner()?;
520496

@@ -541,13 +517,33 @@ async fn replay_no_zkvm(cache: Cache, opts: &EthrexReplayOptions) -> eyre::Resul
541517
continue;
542518
};
543519

544-
let storage_root = AccountState::decode(&account_state_rlp)?.storage_root;
520+
let account_state = AccountState::decode(&account_state_rlp)?;
545521

522+
// If code hash of account isn't present insert empty code so that if not found the execution doesn't break.
523+
let code_hash = account_state.code_hash;
524+
all_codes_hashed.entry(code_hash).or_insert(vec![]);
525+
526+
let storage_root = account_state.storage_root;
546527
let storage_trie = match InMemoryTrieDB::from_nodes(storage_root, all_nodes) {
547528
Ok(trie) => trie.inner,
548529
Err(_) => continue,
549530
};
550531

532+
// Fill storage trie with dummy branch nodes that have the hash of the missing nodes
533+
// This is useful for eth_getProofs when we want to restructure the trie after removing a node whose sibling isn't known
534+
// We assume the sibling is a branch node because we already covered the cases in which it's a Leaf or Extension node by injecting nodes in the witness.
535+
// For more info read: https://github.com/kkrt-labs/zk-pig/blob/v0.8.0/docs/modified-mpt.md
536+
{
537+
let mut storage_nodes = storage_trie.lock().unwrap();
538+
let dummy_branch = Node::from(BranchNode::default()).encode_to_vec();
539+
540+
let referenced_storage_node_hashes = get_referenced_hashes(&storage_nodes)?;
541+
542+
for hash in referenced_storage_node_hashes {
543+
storage_nodes.entry(hash).or_insert(dummy_branch.clone());
544+
}
545+
}
546+
551547
inner_store
552548
.storage_trie_nodes
553549
.insert(H256::from_slice(&hashed_address), storage_trie);

cmd/ethrex_replay/src/helpers.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use std::collections::{BTreeMap, HashSet};
2+
3+
use ethrex_rlp::decode::RLPDecode;
4+
use ethrex_trie::{Node, NodeHash, NodeRef};
5+
6+
/// Given a mapping of nodes with their corresponding hash get all hashes referenced by branch and extension nodes.
7+
pub fn get_referenced_hashes(
8+
nodes: &BTreeMap<NodeHash, Vec<u8>>,
9+
) -> eyre::Result<HashSet<NodeHash>> {
10+
let mut referenced_hashes: HashSet<NodeHash> = HashSet::new();
11+
12+
for (_node_hash, node_rlp) in nodes.iter() {
13+
let node = Node::decode(node_rlp)?;
14+
match node {
15+
Node::Branch(node) => {
16+
for choice in &node.choices {
17+
if let NodeRef::Hash(hash) = *choice {
18+
referenced_hashes.insert(hash);
19+
} else {
20+
return Err(eyre::eyre!("Branch node contains non-hash reference"));
21+
}
22+
}
23+
}
24+
Node::Extension(node) => {
25+
if let NodeRef::Hash(hash) = node.child {
26+
referenced_hashes.insert(hash);
27+
} else {
28+
return Err(eyre::eyre!("Extension node contains non-hash reference"));
29+
}
30+
}
31+
Node::Leaf(_node) => {}
32+
}
33+
}
34+
35+
Ok(referenced_hashes)
36+
}

cmd/ethrex_replay/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod block_run_report;
33
mod cache;
44
pub mod cli;
55
mod fetcher;
6+
mod helpers;
67
#[cfg(not(feature = "l2"))]
78
mod plot_composition;
89
pub mod rpc;

cmd/ethrex_replay/src/rpc/db.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,9 @@ pub fn get_potential_child_nodes(proof: &[NodeRLP], key: &PathRLP) -> Option<Vec
581581
}
582582

583583
let hash = if let Some(root) = proof.first() {
584-
H256::from_slice(&Keccak256::digest(root))
584+
let hash = H256::from_slice(&Keccak256::digest(root));
585+
state_nodes.insert(hash, root.clone());
586+
hash
585587
} else {
586588
*EMPTY_KECCACK_HASH
587589
};

crates/common/trie/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,3 @@ path = "./trie.rs"
4545
[[bench]]
4646
name = "trie_bench"
4747
harness = false
48-

crates/common/trie/node/branch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::{ExtensionNode, LeafNode, Node, NodeRef, ValueOrHash};
66

77
/// Branch Node of an an Ethereum Compatible Patricia Merkle Trie
88
/// Contains the node's value and the hash of its children nodes
9-
#[derive(Debug, Clone, PartialEq)]
9+
#[derive(Debug, Clone, PartialEq, Default)]
1010
pub struct BranchNode {
1111
pub choices: [NodeRef; 16],
1212
pub value: ValueRLP,

0 commit comments

Comments
 (0)