Skip to content

Commit 86fac3b

Browse files
committed
impl create_access_list
1 parent c99886f commit 86fac3b

File tree

17 files changed

+394
-171
lines changed

17 files changed

+394
-171
lines changed

Cargo.lock

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

common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ alloy.workspace = true
88
serde.workspace = true
99
serde_json.workspace = true
1010
revm.workspace = true
11+
eyre.workspace = true

common/src/types.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use std::collections::HashMap;
22
use std::fmt::Display;
33

4-
use alloy::primitives::{B256, U256};
4+
use alloy::{
5+
eips::{BlockId, BlockNumberOrTag},
6+
primitives::{B256, U256},
7+
};
8+
use eyre::{eyre, Report, Result};
59
use serde::{de::Error, Deserialize, Serialize};
610

711
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
@@ -61,3 +65,27 @@ impl<'de> Deserialize<'de> for BlockTag {
6165
Ok(block_tag)
6266
}
6367
}
68+
69+
impl Into<BlockId> for BlockTag {
70+
fn into(self) -> BlockId {
71+
match self {
72+
BlockTag::Latest => BlockId::latest(),
73+
BlockTag::Finalized => BlockId::finalized(),
74+
BlockTag::Number(num) => BlockId::Number(num.into()),
75+
}
76+
}
77+
}
78+
79+
impl TryFrom<BlockId> for BlockTag {
80+
type Error = Report;
81+
82+
fn try_from(block_id: BlockId) -> Result<Self, Self::Error> {
83+
match block_id {
84+
BlockId::Number(BlockNumberOrTag::Number(num)) => Ok(BlockTag::Number(num)),
85+
BlockId::Number(BlockNumberOrTag::Latest) => Ok(BlockTag::Latest),
86+
BlockId::Number(BlockNumberOrTag::Finalized) => Ok(BlockTag::Finalized),
87+
BlockId::Number(other) => Err(eyre!("BlockId::Number({other}) is not supported")),
88+
BlockId::Hash(_) => Err(eyre!("BlockId::Hash is not supported")),
89+
}
90+
}
91+
}

core/src/execution/evm.rs

Lines changed: 8 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
use std::{borrow::BorrowMut, collections::HashMap, sync::Arc};
22

3-
use alloy::{
4-
consensus::BlockHeader,
5-
network::{primitives::HeaderResponse, BlockResponse, TransactionBuilder},
6-
};
3+
use alloy::network::{primitives::HeaderResponse, BlockResponse};
74
use eyre::{Report, Result};
8-
use futures::future::join_all;
9-
use helios_verifiable_api_client::VerifiableApi;
105
use revm::{
116
primitives::{
12-
address, AccessListItem, AccountInfo, Address, Bytecode, Bytes, Env, ExecutionResult,
13-
ResultAndState, B256, U256,
7+
address, AccountInfo, Address, Bytecode, Bytes, Env, ExecutionResult, ResultAndState, B256,
8+
U256,
149
},
1510
Database, Evm as Revm,
1611
};
1712
use tracing::trace;
1813

1914
use helios_common::{fork_schedule::ForkSchedule, network_spec::NetworkSpec, types::BlockTag};
15+
use helios_verifiable_api_client::VerifiableApi;
2016

2117
use crate::execution::{
22-
constants::PARALLEL_QUERY_BATCH_SIZE,
2318
errors::{EvmError, ExecutionError},
2419
rpc::ExecutionRpc,
2520
ExecutionClient,
@@ -237,70 +232,12 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> EvmState<N, R, A>
237232
}
238233

239234
pub async fn prefetch_state(&mut self, tx: &N::TransactionRequest) -> Result<()> {
240-
let mut list = self
241-
.execution
242-
.rpc
243-
.create_access_list(tx, self.block)
244-
.await
245-
.map_err(EvmError::RpcError)?
246-
.0;
247-
248-
let from_access_entry = AccessListItem {
249-
address: tx.from().unwrap_or_default(),
250-
storage_keys: Vec::default(),
251-
};
252-
253-
let to_access_entry = AccessListItem {
254-
address: tx.to().unwrap_or_default(),
255-
storage_keys: Vec::default(),
256-
};
257-
258-
let coinbase = self
235+
let block_id = Some(self.block.into());
236+
let account_map = self
259237
.execution
260-
.get_block(self.block, false)
238+
.create_access_list(tx, block_id)
261239
.await
262-
.ok_or(ExecutionError::BlockNotFound(self.block))?
263-
.header()
264-
.beneficiary();
265-
let producer_access_entry = AccessListItem {
266-
address: coinbase,
267-
storage_keys: Vec::default(),
268-
};
269-
270-
let list_addresses = list.iter().map(|elem| elem.address).collect::<Vec<_>>();
271-
272-
if !list_addresses.contains(&from_access_entry.address) {
273-
list.push(from_access_entry)
274-
}
275-
276-
if !list_addresses.contains(&to_access_entry.address) {
277-
list.push(to_access_entry)
278-
}
279-
280-
if !list_addresses.contains(&producer_access_entry.address) {
281-
list.push(producer_access_entry)
282-
}
283-
284-
let mut account_map = HashMap::new();
285-
for chunk in list.chunks(PARALLEL_QUERY_BATCH_SIZE) {
286-
let account_chunk_futs = chunk.iter().map(|account| {
287-
let account_fut = self.execution.get_account(
288-
account.address,
289-
Some(account.storage_keys.as_slice()),
290-
self.block,
291-
);
292-
async move { (account.address, account_fut.await) }
293-
});
294-
295-
let account_chunk = join_all(account_chunk_futs).await;
296-
297-
account_chunk
298-
.into_iter()
299-
.filter(|i| i.1.is_ok())
300-
.for_each(|(key, value)| {
301-
account_map.insert(key, value.ok().unwrap());
302-
});
303-
}
240+
.map_err(EvmError::RpcError)?;
304241

305242
for (address, account) in account_map {
306243
self.basic.insert(

core/src/execution/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::HashMap;
12
use std::marker::PhantomData;
23

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

340341
Ok(filter_id)
341342
}
343+
344+
pub async fn create_access_list(
345+
&self,
346+
tx: &N::TransactionRequest,
347+
block: Option<BlockId>,
348+
) -> Result<HashMap<Address, Account>> {
349+
self.verified_methods
350+
.client()
351+
.create_access_list(tx, block)
352+
.await
353+
}
342354
}

core/src/execution/rpc/http_rpc.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use eyre::{eyre, Result};
1313
use reqwest::Client;
1414
use revm::primitives::AccessList;
1515

16-
use helios_common::{network_spec::NetworkSpec, types::BlockTag};
16+
use helios_common::network_spec::NetworkSpec;
1717

1818
use crate::errors::RpcError;
1919

@@ -72,14 +72,8 @@ impl<N: NetworkSpec> ExecutionRpc<N> for HttpRpc<N> {
7272
async fn create_access_list(
7373
&self,
7474
tx: &N::TransactionRequest,
75-
block: BlockTag,
75+
block: BlockId,
7676
) -> Result<AccessList> {
77-
let block = match block {
78-
BlockTag::Latest => BlockId::latest(),
79-
BlockTag::Finalized => BlockId::finalized(),
80-
BlockTag::Number(num) => BlockId::number(num),
81-
};
82-
8377
let list = self
8478
.provider
8579
.create_access_list(tx)

core/src/execution/rpc/mock_rpc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use alloy::rpc::types::{
99
use async_trait::async_trait;
1010
use eyre::{eyre, Result};
1111

12-
use helios_common::{network_spec::NetworkSpec, types::BlockTag};
12+
use helios_common::network_spec::NetworkSpec;
1313

1414
use super::ExecutionRpc;
1515

@@ -39,7 +39,7 @@ impl<N: NetworkSpec> ExecutionRpc<N> for MockRpc {
3939
async fn create_access_list(
4040
&self,
4141
_opts: &N::TransactionRequest,
42-
_block: BlockTag,
42+
_block: BlockId,
4343
) -> Result<AccessList> {
4444
Err(eyre!("not implemented"))
4545
}

core/src/execution/rpc/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use alloy::rpc::types::{
77
use async_trait::async_trait;
88
use eyre::Result;
99

10-
use helios_common::{network_spec::NetworkSpec, types::BlockTag};
10+
use helios_common::network_spec::NetworkSpec;
1111

1212
pub mod http_rpc;
1313
pub mod mock_rpc;
@@ -29,7 +29,7 @@ pub trait ExecutionRpc<N: NetworkSpec>: Send + Clone + Sync + 'static {
2929
async fn create_access_list(
3030
&self,
3131
tx: &N::TransactionRequest,
32-
block: BlockTag,
32+
block: BlockId,
3333
) -> Result<AccessList>;
3434

3535
async fn get_code(&self, address: Address, block: u64) -> Result<Vec<u8>>;

core/src/execution/verified_client/api.rs

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -51,49 +51,9 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> VerifiableMethods<
5151
.ok_or(ExecutionError::BlockNotFound(tag))?;
5252
let block_id = BlockId::number(block.header().number());
5353

54-
let AccountResponse {
55-
account,
56-
code,
57-
account_proof,
58-
storage_proof,
59-
} = self.api.get_account(address, slots, Some(block_id)).await?;
54+
let account_response = self.api.get_account(address, slots, Some(block_id)).await?;
6055

61-
// Verify the account proof
62-
let proof = EIP1186AccountProofResponse {
63-
address,
64-
balance: account.balance,
65-
code_hash: account.code_hash,
66-
nonce: account.nonce,
67-
storage_hash: account.storage_root,
68-
account_proof,
69-
storage_proof,
70-
};
71-
verify_account_proof(&proof, block.header().state_root())?;
72-
// Verify the storage proofs, collecting the slot values
73-
let slot_map = verify_storage_proof(&proof)?;
74-
// Verify the code hash
75-
let code = if proof.code_hash == KECCAK_EMPTY || proof.code_hash == B256::ZERO {
76-
Vec::new()
77-
} else {
78-
let code_hash = keccak256(&code);
79-
80-
if proof.code_hash != code_hash {
81-
return Err(
82-
ExecutionError::CodeHashMismatch(address, code_hash, proof.code_hash).into(),
83-
);
84-
}
85-
86-
code.into()
87-
};
88-
89-
Ok(Account {
90-
balance: account.balance,
91-
nonce: account.nonce,
92-
code_hash: account.code_hash,
93-
code,
94-
storage_hash: account.storage_root,
95-
slots: slot_map,
96-
})
56+
self.verify_account_response(address, account_response, &block)
9757
}
9858

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

162122
Ok(logs)
163123
}
124+
125+
async fn create_access_list(
126+
&self,
127+
tx: &N::TransactionRequest,
128+
block: Option<BlockId>,
129+
) -> Result<HashMap<Address, Account>> {
130+
let block_id = block.unwrap_or(BlockId::latest());
131+
let tag = BlockTag::try_from(block_id)?;
132+
let block = self
133+
.state
134+
.get_block(tag)
135+
.await
136+
.ok_or(ExecutionError::BlockNotFound(tag))?;
137+
let block_id = BlockId::Number(block.header().number().into());
138+
139+
let AccessListResponse { accounts } = self
140+
.api
141+
.create_access_list(tx.clone(), Some(block_id))
142+
.await?;
143+
144+
let account_map = accounts
145+
.into_iter()
146+
.map(|(address, account_response)| {
147+
self.verify_account_response(address, account_response, &block)
148+
.map(|account| (address, account))
149+
})
150+
.collect::<Result<HashMap<_, _>>>()?;
151+
152+
Ok(account_map)
153+
}
164154
}
165155

166156
impl<N: NetworkSpec, R: ExecutionRpc<N>, A: VerifiableApi<N>> VerifiableMethodsApi<N, R, A> {
157+
fn verify_account_response(
158+
&self,
159+
address: Address,
160+
account: AccountResponse,
161+
block: &N::BlockResponse,
162+
) -> Result<Account> {
163+
let proof = EIP1186AccountProofResponse {
164+
address,
165+
balance: account.account.balance,
166+
code_hash: account.account.code_hash,
167+
nonce: account.account.nonce,
168+
storage_hash: account.account.storage_root,
169+
account_proof: account.account_proof,
170+
storage_proof: account.storage_proof,
171+
};
172+
// Verify the account proof
173+
verify_account_proof(&proof, block.header().state_root())?;
174+
// Verify the storage proofs, collecting the slot values
175+
let slot_map = verify_storage_proof(&proof)?;
176+
// Verify the code hash
177+
let code = if proof.code_hash == KECCAK_EMPTY || proof.code_hash == B256::ZERO {
178+
Vec::new()
179+
} else {
180+
let code_hash = keccak256(&account.code);
181+
182+
if proof.code_hash != code_hash {
183+
return Err(
184+
ExecutionError::CodeHashMismatch(address, code_hash, proof.code_hash).into(),
185+
);
186+
}
187+
188+
account.code.into()
189+
};
190+
191+
Ok(Account {
192+
balance: proof.balance,
193+
nonce: proof.nonce,
194+
code_hash: proof.code_hash,
195+
code,
196+
storage_hash: proof.storage_hash,
197+
slots: slot_map,
198+
})
199+
}
200+
167201
async fn verify_logs_and_receipts(
168202
&self,
169203
logs: &[Log],

core/src/execution/verified_client/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::collections::HashMap;
2+
3+
use alloy::eips::BlockId;
14
use alloy::primitives::{Address, B256, U256};
25
use alloy::rpc::types::{Filter, FilterChanges, Log};
36
use async_trait::async_trait;
@@ -30,6 +33,11 @@ pub trait VerifiableMethods<N: NetworkSpec, R: ExecutionRpc<N>> {
3033
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>>;
3134
async fn get_filter_changes(&self, filter_id: U256) -> Result<FilterChanges>;
3235
async fn get_filter_logs(&self, filter_id: U256) -> Result<Vec<Log>>;
36+
async fn create_access_list(
37+
&self,
38+
tx: &N::TransactionRequest,
39+
block: Option<BlockId>,
40+
) -> Result<HashMap<Address, Account>>;
3341
}
3442

3543
#[derive(Clone)]

0 commit comments

Comments
 (0)