diff --git a/crates/executor/host/src/lib.rs b/crates/executor/host/src/lib.rs index 7e190f5..43b8568 100644 --- a/crates/executor/host/src/lib.rs +++ b/crates/executor/host/src/lib.rs @@ -150,7 +150,7 @@ impl + Clone> HostExecutor, proofs: &HashMap, ) -> Result { - proofs_to_tries(state_root, parent_proofs, proofs).map_err(|err| eyre::eyre!("{}", err)) + transition_proofs_to_tries(state_root, parent_proofs, proofs) + .map_err(|err| eyre::eyre!("{}", err)) + } + + /// Builds Ethereum state tries from relevant proofs from a given state. + pub fn from_proofs(state_root: B256, proofs: &HashMap) -> Result { + proofs_to_tries(state_root, proofs).map_err(|err| eyre::eyre!("{}", err)) } /// Mutates state based on diffs provided in [`HashedPostState`]. diff --git a/crates/mpt/src/mpt.rs b/crates/mpt/src/mpt.rs index fbddb4e..8790edd 100644 --- a/crates/mpt/src/mpt.rs +++ b/crates/mpt/src/mpt.rs @@ -962,6 +962,71 @@ pub fn shorten_node_path(node: &MptNode) -> Vec { } pub fn proofs_to_tries( + state_root: B256, + proofs: &HashMap, +) -> Result { + // if no addresses are provided, return the trie only consisting of the state root + if proofs.is_empty() { + return Ok(EthereumState { + state_trie: node_from_digest(state_root), + storage_tries: HashMap::new(), + }); + } + + let mut storage: HashMap = HashMap::with_capacity(proofs.len()); + + let mut state_nodes = HashMap::new(); + let mut state_root_node = MptNode::default(); + for (address, proof) in proofs { + let proof_nodes = parse_proof(&proof.proof).unwrap(); + mpt_from_proof(&proof_nodes).unwrap(); + + // the first node in the proof is the root + if let Some(node) = proof_nodes.first() { + state_root_node = node.clone(); + } + + proof_nodes.into_iter().for_each(|node| { + state_nodes.insert(node.reference(), node); + }); + + // if no slots are provided, return the trie only consisting of the storage root + let storage_root = proof.storage_root; + if proof.storage_proofs.is_empty() { + let storage_root_node = node_from_digest(storage_root); + storage.insert(B256::from(&keccak(address)), storage_root_node); + continue; + } + + let mut storage_nodes = HashMap::new(); + let mut storage_root_node = MptNode::default(); + for storage_proof in &proof.storage_proofs { + let proof_nodes = parse_proof(&storage_proof.proof).unwrap(); + mpt_from_proof(&proof_nodes).unwrap(); + + // the first node in the proof is the root + if let Some(node) = proof_nodes.first() { + storage_root_node = node.clone(); + } + + proof_nodes.into_iter().for_each(|node| { + storage_nodes.insert(node.reference(), node); + }); + } + + // create the storage trie, from all the relevant nodes + let storage_trie = resolve_nodes(&storage_root_node, &storage_nodes); + assert_eq!(storage_trie.hash(), storage_root); + + storage.insert(B256::from(&keccak(address)), storage_trie); + } + let state_trie = resolve_nodes(&state_root_node, &state_nodes); + assert_eq!(state_trie.hash(), state_root); + + Ok(EthereumState { state_trie, storage_tries: storage }) +} + +pub fn transition_proofs_to_tries( state_root: B256, parent_proofs: &HashMap, proofs: &HashMap,