Skip to content

Commit

Permalink
impl create_access_list
Browse files Browse the repository at this point in the history
  • Loading branch information
eshaan7 committed Feb 12, 2025
1 parent c99886f commit 86fac3b
Show file tree
Hide file tree
Showing 17 changed files with 394 additions and 171 deletions.
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.

1 change: 1 addition & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ alloy.workspace = true
serde.workspace = true
serde_json.workspace = true
revm.workspace = true
eyre.workspace = true
30 changes: 29 additions & 1 deletion common/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::collections::HashMap;
use std::fmt::Display;

use alloy::primitives::{B256, U256};
use alloy::{
eips::{BlockId, BlockNumberOrTag},
primitives::{B256, U256},
};
use eyre::{eyre, Report, Result};
use serde::{de::Error, Deserialize, Serialize};

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -61,3 +65,27 @@ impl<'de> Deserialize<'de> for BlockTag {
Ok(block_tag)
}
}

impl Into<BlockId> for BlockTag {

Check failure on line 69 in common/src/types.rs

View workflow job for this annotation

GitHub Actions / clippy

an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
fn into(self) -> BlockId {
match self {
BlockTag::Latest => BlockId::latest(),
BlockTag::Finalized => BlockId::finalized(),
BlockTag::Number(num) => BlockId::Number(num.into()),
}
}
}

impl TryFrom<BlockId> for BlockTag {
type Error = Report;

fn try_from(block_id: BlockId) -> Result<Self, Self::Error> {
match block_id {
BlockId::Number(BlockNumberOrTag::Number(num)) => Ok(BlockTag::Number(num)),
BlockId::Number(BlockNumberOrTag::Latest) => Ok(BlockTag::Latest),
BlockId::Number(BlockNumberOrTag::Finalized) => Ok(BlockTag::Finalized),
BlockId::Number(other) => Err(eyre!("BlockId::Number({other}) is not supported")),
BlockId::Hash(_) => Err(eyre!("BlockId::Hash is not supported")),
}
}
}
79 changes: 8 additions & 71 deletions core/src/execution/evm.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
use std::{borrow::BorrowMut, collections::HashMap, sync::Arc};

use alloy::{
consensus::BlockHeader,
network::{primitives::HeaderResponse, BlockResponse, TransactionBuilder},
};
use alloy::network::{primitives::HeaderResponse, BlockResponse};
use eyre::{Report, Result};
use futures::future::join_all;
use helios_verifiable_api_client::VerifiableApi;
use revm::{
primitives::{
address, AccessListItem, AccountInfo, Address, Bytecode, Bytes, Env, ExecutionResult,
ResultAndState, B256, U256,
address, AccountInfo, Address, Bytecode, Bytes, Env, ExecutionResult, ResultAndState, B256,
U256,
},
Database, Evm as Revm,
};
use tracing::trace;

use helios_common::{fork_schedule::ForkSchedule, network_spec::NetworkSpec, types::BlockTag};
use helios_verifiable_api_client::VerifiableApi;

use crate::execution::{
constants::PARALLEL_QUERY_BATCH_SIZE,
errors::{EvmError, ExecutionError},
rpc::ExecutionRpc,
ExecutionClient,
Expand Down Expand Up @@ -237,70 +232,12 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> EvmState<N, R, A>
}

pub async fn prefetch_state(&mut self, tx: &N::TransactionRequest) -> Result<()> {
let mut list = self
.execution
.rpc
.create_access_list(tx, self.block)
.await
.map_err(EvmError::RpcError)?
.0;

let from_access_entry = AccessListItem {
address: tx.from().unwrap_or_default(),
storage_keys: Vec::default(),
};

let to_access_entry = AccessListItem {
address: tx.to().unwrap_or_default(),
storage_keys: Vec::default(),
};

let coinbase = self
let block_id = Some(self.block.into());
let account_map = self
.execution
.get_block(self.block, false)
.create_access_list(tx, block_id)
.await
.ok_or(ExecutionError::BlockNotFound(self.block))?
.header()
.beneficiary();
let producer_access_entry = AccessListItem {
address: coinbase,
storage_keys: Vec::default(),
};

let list_addresses = list.iter().map(|elem| elem.address).collect::<Vec<_>>();

if !list_addresses.contains(&from_access_entry.address) {
list.push(from_access_entry)
}

if !list_addresses.contains(&to_access_entry.address) {
list.push(to_access_entry)
}

if !list_addresses.contains(&producer_access_entry.address) {
list.push(producer_access_entry)
}

let mut account_map = HashMap::new();
for chunk in list.chunks(PARALLEL_QUERY_BATCH_SIZE) {
let account_chunk_futs = chunk.iter().map(|account| {
let account_fut = self.execution.get_account(
account.address,
Some(account.storage_keys.as_slice()),
self.block,
);
async move { (account.address, account_fut.await) }
});

let account_chunk = join_all(account_chunk_futs).await;

account_chunk
.into_iter()
.filter(|i| i.1.is_ok())
.for_each(|(key, value)| {
account_map.insert(key, value.ok().unwrap());
});
}
.map_err(EvmError::RpcError)?;

for (address, account) in account_map {
self.basic.insert(
Expand Down
12 changes: 12 additions & 0 deletions core/src/execution/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::marker::PhantomData;

use alloy::consensus::BlockHeader;
Expand Down Expand Up @@ -339,4 +340,15 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> ExecutionClient<N,

Ok(filter_id)
}

pub async fn create_access_list(
&self,
tx: &N::TransactionRequest,
block: Option<BlockId>,
) -> Result<HashMap<Address, Account>> {
self.verified_methods
.client()
.create_access_list(tx, block)
.await
}
}
10 changes: 2 additions & 8 deletions core/src/execution/rpc/http_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use eyre::{eyre, Result};
use reqwest::Client;
use revm::primitives::AccessList;

use helios_common::{network_spec::NetworkSpec, types::BlockTag};
use helios_common::network_spec::NetworkSpec;

use crate::errors::RpcError;

Expand Down Expand Up @@ -72,14 +72,8 @@ impl<N: NetworkSpec> ExecutionRpc<N> for HttpRpc<N> {
async fn create_access_list(
&self,
tx: &N::TransactionRequest,
block: BlockTag,
block: BlockId,
) -> Result<AccessList> {
let block = match block {
BlockTag::Latest => BlockId::latest(),
BlockTag::Finalized => BlockId::finalized(),
BlockTag::Number(num) => BlockId::number(num),
};

let list = self
.provider
.create_access_list(tx)
Expand Down
4 changes: 2 additions & 2 deletions core/src/execution/rpc/mock_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use alloy::rpc::types::{
use async_trait::async_trait;
use eyre::{eyre, Result};

use helios_common::{network_spec::NetworkSpec, types::BlockTag};
use helios_common::network_spec::NetworkSpec;

use super::ExecutionRpc;

Expand Down Expand Up @@ -39,7 +39,7 @@ impl<N: NetworkSpec> ExecutionRpc<N> for MockRpc {
async fn create_access_list(
&self,
_opts: &N::TransactionRequest,
_block: BlockTag,
_block: BlockId,
) -> Result<AccessList> {
Err(eyre!("not implemented"))
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/execution/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use alloy::rpc::types::{
use async_trait::async_trait;
use eyre::Result;

use helios_common::{network_spec::NetworkSpec, types::BlockTag};
use helios_common::network_spec::NetworkSpec;

pub mod http_rpc;
pub mod mock_rpc;
Expand All @@ -29,7 +29,7 @@ pub trait ExecutionRpc<N: NetworkSpec>: Send + Clone + Sync + 'static {
async fn create_access_list(
&self,
tx: &N::TransactionRequest,
block: BlockTag,
block: BlockId,
) -> Result<AccessList>;

async fn get_code(&self, address: Address, block: u64) -> Result<Vec<u8>>;
Expand Down
118 changes: 76 additions & 42 deletions core/src/execution/verified_client/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,49 +51,9 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> VerifiableMethods<
.ok_or(ExecutionError::BlockNotFound(tag))?;
let block_id = BlockId::number(block.header().number());

let AccountResponse {
account,
code,
account_proof,
storage_proof,
} = self.api.get_account(address, slots, Some(block_id)).await?;
let account_response = self.api.get_account(address, slots, Some(block_id)).await?;

// Verify the account proof
let proof = EIP1186AccountProofResponse {
address,
balance: account.balance,
code_hash: account.code_hash,
nonce: account.nonce,
storage_hash: account.storage_root,
account_proof,
storage_proof,
};
verify_account_proof(&proof, block.header().state_root())?;
// Verify the storage proofs, collecting the slot values
let slot_map = verify_storage_proof(&proof)?;
// Verify the code hash
let code = if proof.code_hash == KECCAK_EMPTY || proof.code_hash == B256::ZERO {
Vec::new()
} else {
let code_hash = keccak256(&code);

if proof.code_hash != code_hash {
return Err(
ExecutionError::CodeHashMismatch(address, code_hash, proof.code_hash).into(),
);
}

code.into()
};

Ok(Account {
balance: account.balance,
nonce: account.nonce,
code_hash: account.code_hash,
code,
storage_hash: account.storage_root,
slots: slot_map,
})
self.verify_account_response(address, account_response, &block)
}

async fn get_transaction_receipt(&self, tx_hash: B256) -> Result<Option<N::ReceiptResponse>> {
Expand Down Expand Up @@ -161,9 +121,83 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> VerifiableMethods<

Ok(logs)
}

async fn create_access_list(
&self,
tx: &N::TransactionRequest,
block: Option<BlockId>,
) -> Result<HashMap<Address, Account>> {
let block_id = block.unwrap_or(BlockId::latest());
let tag = BlockTag::try_from(block_id)?;
let block = self
.state
.get_block(tag)
.await
.ok_or(ExecutionError::BlockNotFound(tag))?;
let block_id = BlockId::Number(block.header().number().into());

let AccessListResponse { accounts } = self
.api
.create_access_list(tx.clone(), Some(block_id))
.await?;

let account_map = accounts
.into_iter()
.map(|(address, account_response)| {
self.verify_account_response(address, account_response, &block)
.map(|account| (address, account))
})
.collect::<Result<HashMap<_, _>>>()?;

Ok(account_map)
}
}

impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> VerifiableMethodsApi<N, R, A> {
fn verify_account_response(
&self,
address: Address,
account: AccountResponse,
block: &N::BlockResponse,
) -> Result<Account> {
let proof = EIP1186AccountProofResponse {
address,
balance: account.account.balance,
code_hash: account.account.code_hash,
nonce: account.account.nonce,
storage_hash: account.account.storage_root,
account_proof: account.account_proof,
storage_proof: account.storage_proof,
};
// Verify the account proof
verify_account_proof(&proof, block.header().state_root())?;
// Verify the storage proofs, collecting the slot values
let slot_map = verify_storage_proof(&proof)?;
// Verify the code hash
let code = if proof.code_hash == KECCAK_EMPTY || proof.code_hash == B256::ZERO {
Vec::new()
} else {
let code_hash = keccak256(&account.code);

if proof.code_hash != code_hash {
return Err(
ExecutionError::CodeHashMismatch(address, code_hash, proof.code_hash).into(),
);
}

account.code.into()
};

Ok(Account {
balance: proof.balance,
nonce: proof.nonce,
code_hash: proof.code_hash,
code,
storage_hash: proof.storage_hash,
slots: slot_map,
})
}

async fn verify_logs_and_receipts(
&self,
logs: &[Log],
Expand Down
8 changes: 8 additions & 0 deletions core/src/execution/verified_client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::collections::HashMap;

use alloy::eips::BlockId;
use alloy::primitives::{Address, B256, U256};
use alloy::rpc::types::{Filter, FilterChanges, Log};
use async_trait::async_trait;
Expand Down Expand Up @@ -30,6 +33,11 @@ pub trait VerifiableMethods<N: NetworkSpec, R: ExecutionRpc<N>> {
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>>;
async fn get_filter_changes(&self, filter_id: U256) -> Result<FilterChanges>;
async fn get_filter_logs(&self, filter_id: U256) -> Result<Vec<Log>>;
async fn create_access_list(
&self,
tx: &N::TransactionRequest,
block: Option<BlockId>,
) -> Result<HashMap<Address, Account>>;
}

#[derive(Clone)]
Expand Down
Loading

0 comments on commit 86fac3b

Please sign in to comment.