Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion crates/executor/host/src/host_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ impl<C: ConfigureEvm, CS> HostExecutor<C, CS> {
let chain_id: u64 = (&genesis).try_into().unwrap();
tracing::debug!("chain id: {}", chain_id);

let is_goat_testnet = is_goat_testnet(chain_id);

// Fetch the current block and the previous block from the provider.
tracing::info!("[{}] fetching the current block and the previous block", block_number);
let rpc_block = provider
Expand Down Expand Up @@ -105,6 +107,7 @@ impl<C: ConfigureEvm, CS> HostExecutor<C, CS> {
debug_provider,
block_number - 1,
previous_block.header().state_root(),
is_goat_testnet,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does only the GOAT testnet require special handling, or does the GOAT mainnet also require it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently unsure what the RPC return value on mainnet is

)
.await
.map_err(HostError::RpcDbError)?;
Expand Down Expand Up @@ -149,7 +152,7 @@ impl<C: ConfigureEvm, CS> HostExecutor<C, CS> {
&block,
self.chain_spec.clone(),
&execution_output,
is_goat_testnet(chain_id),
is_goat_testnet,
)?;

// Accumulate the logs bloom.
Expand Down
7 changes: 3 additions & 4 deletions crates/mpt/src/execution_witness.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use alloy_primitives::{keccak256, map::HashMap, B256};
use alloy_primitives::{keccak256, map::HashMap, Bytes, B256};
use alloy_rlp::Decodable;
use alloy_rpc_types_debug::ExecutionWitness;
use reth_trie::TrieAccount;

use crate::mpt::{resolve_nodes, MptNode, MptNodeData, MptNodeReference};
Expand All @@ -10,7 +9,7 @@ use crate::mpt::{resolve_nodes, MptNode, MptNodeData, MptNodeReference};
// NOTE: This method should be called outside zkVM! In general you construct tries, then
// validate them inside zkVM.
pub(crate) fn build_validated_tries(
witness: &ExecutionWitness,
state: &Vec<Bytes>,
pre_state_root: B256,
) -> Result<(MptNode, HashMap<B256, MptNode>), String> {
// Step 1: Decode all RLP-encoded trie nodes and index by hash
Expand All @@ -19,7 +18,7 @@ pub(crate) fn build_validated_tries(
let mut node_by_hash: HashMap<B256, MptNode> = HashMap::default();
let mut root_node: Option<MptNode> = None;

for encoded in &witness.state {
for encoded in state {
let node = MptNode::decode(encoded).expect("Valid MPT node in witness");
let hash = keccak256(encoded);
if hash == pre_state_root {
Expand Down
11 changes: 3 additions & 8 deletions crates/mpt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]

use alloy_primitives::{keccak256, map::HashMap, Address, B256};
use alloy_primitives::{keccak256, map::HashMap, Address, Bytes, B256};
use alloy_rpc_types::EIP1186AccountProofResponse;
use reth_trie::{AccountProof, HashedPostState, HashedStorage, TrieAccount};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -73,12 +71,9 @@ impl EthereumState {
}

#[cfg(feature = "execution-witness")]
pub fn from_execution_witness(
witness: &alloy_rpc_types_debug::ExecutionWitness,
pre_state_root: B256,
) -> Self {
pub fn from_execution_witness(state: &Vec<Bytes>, pre_state_root: B256) -> Self {
let (state_trie, storage_tries) =
execution_witness::build_validated_tries(witness, pre_state_root).unwrap();
execution_witness::build_validated_tries(state, pre_state_root).unwrap();

Self { state_trie, storage_tries }
}
Expand Down
3 changes: 2 additions & 1 deletion crates/storage/rpc-db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ async-trait.workspace = true
tokio.workspace = true
thiserror.workspace = true
tracing.workspace = true
serde.workspace = true

mpt.workspace = true
primitives.workspace = true
Expand All @@ -33,7 +34,7 @@ alloy-trie = { workspace = true, optional = true, features = ["ethereum"] }
[features]
default = ["execution-witness"]
execution-witness = [
"dep:alloy-consensus",
"dep:alloy-consensus",
"dep:alloy-rlp",
"dep:alloy-trie",
"alloy-provider/debug-api"
Expand Down
62 changes: 44 additions & 18 deletions crates/storage/rpc-db/src/execution_witness.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::marker::PhantomData;

use alloy_consensus::Header;
use alloy_primitives::{map::HashMap, Address, B256};
use alloy_consensus::{private::alloy_eips::BlockNumberOrTag, Header};
use alloy_primitives::{map::HashMap, Address, Bytes, B256};
use alloy_provider::{ext::DebugApi, Network, Provider};
use alloy_rlp::Decodable;
use alloy_trie::TrieAccount;
Expand All @@ -11,9 +11,18 @@ use reth_storage_errors::ProviderError;
use revm_database::{BundleState, DatabaseRef};
use revm_primitives::{keccak256, ruint::aliases::U256, StorageKey, StorageValue};
use revm_state::{AccountInfo, Bytecode};
use serde::{Deserialize, Serialize};

use crate::{RpcDb, RpcDbError};

#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExecutionWitnessGoat {
pub state: Vec<Bytes>,
pub codes: Vec<Bytes>,
pub keys: Option<Vec<Bytes>>,
pub headers: Vec<Header>,
}

#[derive(Debug)]
pub struct ExecutionWitnessRpcDb<P, N> {
/// The provider which fetches data.
Expand All @@ -30,23 +39,40 @@ pub struct ExecutionWitnessRpcDb<P, N> {

impl<P: Provider<N> + Clone, N: Network> ExecutionWitnessRpcDb<P, N> {
/// Create a new [`ExecutionWitnessRpcDb`].
pub async fn new(provider: P, block_number: u64, state_root: B256) -> Result<Self, RpcDbError> {
let execution_witness = provider.debug_execution_witness((block_number + 1).into()).await?;

let state = EthereumState::from_execution_witness(&execution_witness, state_root);

let codes = execution_witness
.codes
.iter()
.map(|encoded| (keccak256(encoded), Bytecode::new_raw(encoded.clone())))
.collect();

let ancestor_headers = execution_witness
.headers
.iter()
.map(|encoded| Header::decode(&mut encoded.as_ref()).unwrap())
.map(|h| (h.number, h))
pub async fn new(
provider: P,
block_number: u64,
state_root: B256,
is_goat_testnet: bool,
) -> Result<Self, RpcDbError> {
let (state, codes, headers) = if is_goat_testnet {
let execution_witness: ExecutionWitnessGoat = provider
.raw_request(
"debug_executionWitness".into(),
(BlockNumberOrTag::Number(block_number + 1),),
)
.await?;

(execution_witness.state, execution_witness.codes, execution_witness.headers)
} else {
let execution_witness =
provider.debug_execution_witness((block_number + 1).into()).await?;
let headers = execution_witness
.headers
.iter()
.map(|encoded| Header::decode(&mut encoded.as_ref()).unwrap())
.collect();

(execution_witness.state, execution_witness.codes, headers)
};
tracing::info!("fetch execution witness for block {}", block_number + 1);

let state = EthereumState::from_execution_witness(&state, state_root);
let codes = codes
.into_iter()
.map(|encoded| (keccak256(&encoded), Bytecode::new_raw(encoded)))
.collect();
let ancestor_headers = headers.into_iter().map(|h| (h.number, h)).collect();

let db = Self { provider, state, codes, ancestor_headers, phantom: PhantomData };

Expand Down