Skip to content

Commit dcb57ad

Browse files
authored
[feat] refactor and use trace v2 (#17)
* upgrade revm to v37 * suppress log * bps counter * fix * less log * noticeable log * short hash * upgrade revm and rust toolchain * remove legacy feature gate * upgrade to v40 * refactor and use trace v2 * do this later
1 parent 2c05bd8 commit dcb57ad

File tree

7 files changed

+238
-116
lines changed

7 files changed

+238
-116
lines changed

src/bin/trace-verifier/utils.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use eth_types::l2_types::BlockTrace;
1+
use eth_types::l2_types::{BlockTrace, BlockTraceV2};
22
use eth_types::ToWord;
3-
use stateless_block_verifier::{EvmExecutor, HardforkConfig};
3+
use stateless_block_verifier::{utils, EvmExecutorBuilder, HardforkConfig};
44
use std::sync::atomic::AtomicUsize;
55
use std::sync::{LazyLock, Mutex};
66
use std::time::Instant;
@@ -17,6 +17,8 @@ pub fn verify(
1717
trace!("{:#?}", l2_trace);
1818
let root_after = l2_trace.storage_trace.root_after.to_word();
1919

20+
let v2_trace = BlockTraceV2::from(l2_trace.clone());
21+
2022
let now = Instant::now();
2123

2224
#[cfg(feature = "profiling")]
@@ -26,8 +28,17 @@ pub fn verify(
2628
.build()
2729
.unwrap();
2830

29-
let mut executor = EvmExecutor::new(&l2_trace, &fork_config, disable_checks);
30-
let revm_root_after = executor.handle_block(&l2_trace).to_word();
31+
let mut executor = EvmExecutorBuilder::new()
32+
.hardfork_config(*fork_config)
33+
.with_execute_hooks(|hooks| {
34+
if !disable_checks {
35+
hooks.add_post_tx_execution_handler(move |executor, tx_id| {
36+
utils::post_check(executor.db(), &l2_trace.execution_results[tx_id]);
37+
})
38+
}
39+
})
40+
.build(&v2_trace);
41+
let revm_root_after = executor.handle_block(&v2_trace).to_word();
3142

3243
#[cfg(feature = "profiling")]
3344
if let Ok(report) = guard.report().build() {

src/database.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::utils::{collect_account_proofs, collect_storage_proofs};
22
use eth_types::{
3-
l2_types::{trace::collect_codes, BlockTrace},
3+
l2_types::BlockTraceV2,
44
state_db::{self, CodeDB, StateDB},
55
ToWord, H160,
66
};
@@ -20,7 +20,7 @@ pub struct ReadOnlyDB {
2020

2121
impl ReadOnlyDB {
2222
/// Initialize an EVM database from a block trace.
23-
pub fn new(l2_trace: &BlockTrace) -> Self {
23+
pub fn new(l2_trace: &BlockTraceV2) -> Self {
2424
let mut sdb = StateDB::new();
2525
for parsed in
2626
ZktrieState::parse_account_from_proofs(collect_account_proofs(&l2_trace.storage_trace))
@@ -39,8 +39,11 @@ impl ReadOnlyDB {
3939
}
4040

4141
let mut code_db = CodeDB::new();
42-
for (hash, code) in collect_codes(l2_trace, Some(&sdb)).unwrap() {
43-
code_db.insert_with_hash(hash, code);
42+
for code_trace in l2_trace.codes.iter() {
43+
// FIXME: use this later
44+
// let hash = code_db.insert(code_trace.code.to_vec());
45+
// assert_eq!(hash, code_trace.hash);
46+
code_db.insert_with_hash(code_trace.hash, code_trace.code.to_vec());
4447
}
4548

4649
ReadOnlyDB { code_db, sdb }

src/executor/builder.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use crate::executor::hooks::ExecuteHooks;
2+
use crate::utils::{collect_account_proofs, collect_storage_proofs};
3+
use crate::{EvmExecutor, HardforkConfig, ReadOnlyDB};
4+
use eth_types::l2_types::{BlockTrace, BlockTraceV2};
5+
use mpt_zktrie::ZktrieState;
6+
use revm::db::CacheDB;
7+
8+
/// Builder for EVM executor.
9+
#[derive(Debug)]
10+
pub struct EvmExecutorBuilder<H> {
11+
hardfork_config: H,
12+
execute_hooks: ExecuteHooks,
13+
}
14+
15+
impl Default for EvmExecutorBuilder<()> {
16+
fn default() -> Self {
17+
Self::new()
18+
}
19+
}
20+
21+
impl EvmExecutorBuilder<()> {
22+
/// Create a new builder.
23+
pub fn new() -> Self {
24+
Self {
25+
hardfork_config: (),
26+
execute_hooks: ExecuteHooks::default(),
27+
}
28+
}
29+
}
30+
31+
impl<H1> EvmExecutorBuilder<H1> {
32+
/// Set hardfork config.
33+
pub fn hardfork_config<H2>(self, hardfork_config: H2) -> EvmExecutorBuilder<H2> {
34+
EvmExecutorBuilder {
35+
hardfork_config,
36+
execute_hooks: self.execute_hooks,
37+
}
38+
}
39+
40+
/// Modify execute hooks.
41+
pub fn with_execute_hooks(mut self, modify: impl FnOnce(&mut ExecuteHooks)) -> Self {
42+
modify(&mut self.execute_hooks);
43+
self
44+
}
45+
}
46+
47+
impl EvmExecutorBuilder<HardforkConfig> {
48+
/// Initialize an EVM executor from a legacy block trace as the initial state.
49+
pub fn build_legacy(self, l2_trace: &BlockTrace) -> EvmExecutor {
50+
let v2_trace = BlockTraceV2::from(l2_trace.clone());
51+
self.build(&v2_trace)
52+
}
53+
54+
/// Initialize an EVM executor from a block trace as the initial state.
55+
pub fn build(self, l2_trace: &BlockTraceV2) -> EvmExecutor {
56+
let block_number = l2_trace.header.number.unwrap().as_u64();
57+
let spec_id = self.hardfork_config.get_spec_id(block_number);
58+
trace!("use spec id {:?}", spec_id);
59+
60+
let mut db = CacheDB::new(ReadOnlyDB::new(l2_trace));
61+
self.hardfork_config.migrate(block_number, &mut db).unwrap();
62+
63+
let old_root = l2_trace.storage_trace.root_before;
64+
let zktrie_state = ZktrieState::from_trace_with_additional(
65+
old_root,
66+
collect_account_proofs(&l2_trace.storage_trace),
67+
collect_storage_proofs(&l2_trace.storage_trace),
68+
l2_trace
69+
.storage_trace
70+
.deletion_proofs
71+
.iter()
72+
.map(|s| s.as_ref()),
73+
)
74+
.unwrap();
75+
let root = *zktrie_state.root();
76+
debug!("building partial statedb done, root {}", hex::encode(root));
77+
78+
let mem_db = zktrie_state.into_inner();
79+
let zktrie = mem_db.new_trie(&root).unwrap();
80+
81+
EvmExecutor {
82+
db,
83+
zktrie,
84+
spec_id,
85+
hooks: self.execute_hooks,
86+
}
87+
}
88+
}

src/executor/hooks.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use crate::EvmExecutor;
2+
use std::fmt::{Debug, Formatter};
3+
4+
/// Post transaction execution handler.
5+
pub type PostTxExecutionHandler = dyn Fn(&EvmExecutor, usize) + Send + Sync + 'static;
6+
7+
/// Hooks for the EVM executor.
8+
#[derive(Default)]
9+
pub struct ExecuteHooks {
10+
post_tx_execution_handlers: Vec<Box<PostTxExecutionHandler>>,
11+
}
12+
13+
impl ExecuteHooks {
14+
/// Create a new hooks.
15+
pub fn new() -> Self {
16+
Self::default()
17+
}
18+
19+
/// Add a post transaction execution handler.
20+
pub fn add_post_tx_execution_handler<F>(&mut self, handler: F)
21+
where
22+
F: Fn(&EvmExecutor, usize) + Send + Sync + 'static,
23+
{
24+
self.post_tx_execution_handlers.push(Box::new(handler));
25+
}
26+
27+
pub(crate) fn post_tx_execution(&self, executor: &EvmExecutor, tx_index: usize) {
28+
for handler in &self.post_tx_execution_handlers {
29+
handler(executor, tx_index);
30+
}
31+
}
32+
}
33+
34+
impl Debug for ExecuteHooks {
35+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
36+
f.debug_struct("ExecuteHooks")
37+
.field(
38+
"post_tx_execution_handlers",
39+
&self.post_tx_execution_handlers.len(),
40+
)
41+
.finish()
42+
}
43+
}

src/executor.rs renamed to src/executor/mod.rs

Lines changed: 14 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,33 @@
1-
use crate::{
2-
database::ReadOnlyDB,
3-
utils::{collect_account_proofs, collect_storage_proofs},
4-
HardforkConfig,
5-
};
6-
use eth_types::{
7-
geth_types::TxType,
8-
l2_types::{BlockTrace, ExecutionResult},
9-
H160, H256, U256,
10-
};
11-
use log::Level;
12-
use mpt_zktrie::{AccountData, ZktrieState};
1+
use crate::database::ReadOnlyDB;
2+
use eth_types::{geth_types::TxType, l2_types::BlockTraceV2, H160, H256, U256};
3+
use mpt_zktrie::AccountData;
134
use revm::{
145
db::CacheDB,
156
primitives::{AccountInfo, BlockEnv, Env, SpecId, TxEnv},
16-
DatabaseRef,
177
};
188
use std::fmt::Debug;
199
use zktrie::ZkTrie;
2010

11+
mod builder;
12+
/// Execute hooks
13+
pub mod hooks;
14+
pub use builder::EvmExecutorBuilder;
15+
2116
/// EVM executor that handles the block.
2217
pub struct EvmExecutor {
2318
db: CacheDB<ReadOnlyDB>,
2419
zktrie: ZkTrie,
2520
spec_id: SpecId,
26-
disable_checks: bool,
21+
hooks: hooks::ExecuteHooks,
2722
}
2823
impl EvmExecutor {
29-
/// Initialize an EVM executor from a block trace as the initial state.
30-
pub fn new(l2_trace: &BlockTrace, fork_config: &HardforkConfig, disable_checks: bool) -> Self {
31-
let block_number = l2_trace.header.number.unwrap().as_u64();
32-
let spec_id = fork_config.get_spec_id(block_number);
33-
trace!("use spec id {:?}", spec_id);
34-
35-
let mut db = CacheDB::new(ReadOnlyDB::new(l2_trace));
36-
fork_config.migrate(block_number, &mut db).unwrap();
37-
38-
let old_root = l2_trace.storage_trace.root_before;
39-
let zktrie_state = ZktrieState::from_trace_with_additional(
40-
old_root,
41-
collect_account_proofs(&l2_trace.storage_trace),
42-
collect_storage_proofs(&l2_trace.storage_trace),
43-
l2_trace
44-
.storage_trace
45-
.deletion_proofs
46-
.iter()
47-
.map(|s| s.as_ref()),
48-
)
49-
.unwrap();
50-
let root = *zktrie_state.root();
51-
debug!("building partial statedb done, root {}", hex::encode(root));
52-
53-
let mem_db = zktrie_state.into_inner();
54-
let zktrie = mem_db.new_trie(&root).unwrap();
55-
56-
Self {
57-
db,
58-
zktrie,
59-
spec_id,
60-
disable_checks,
61-
}
24+
/// Get reference to the DB
25+
pub fn db(&self) -> &CacheDB<ReadOnlyDB> {
26+
&self.db
6227
}
6328

6429
/// Handle a block.
65-
pub fn handle_block(&mut self, l2_trace: &BlockTrace) -> H256 {
30+
pub fn handle_block(&mut self, l2_trace: &BlockTraceV2) -> H256 {
6631
debug!("handle block {:?}", l2_trace.header.number.unwrap());
6732
let mut env = Box::<Env>::default();
6833
env.cfg.chain_id = l2_trace.chain_id;
@@ -100,14 +65,8 @@ impl EvmExecutor {
10065
let result = revm.transact_commit().unwrap(); // TODO: handle error
10166
trace!("{result:#?}");
10267
}
68+
self.hooks.post_tx_execution(self, idx);
10369
debug!("handle {idx}th tx done");
104-
105-
if !self.disable_checks {
106-
if let Some(exec) = l2_trace.execution_results.get(idx) {
107-
debug!("post check {idx}th tx");
108-
self.post_check(exec);
109-
}
110-
}
11170
}
11271
self.commit_changes();
11372
H256::from(self.zktrie.root())
@@ -256,56 +215,6 @@ impl EvmExecutor {
256215
}
257216
}
258217
}
259-
260-
fn post_check(&mut self, exec: &ExecutionResult) {
261-
for account_post_state in exec.account_after.iter() {
262-
let local_acc = self
263-
.db
264-
.basic_ref(account_post_state.address.0.into())
265-
.unwrap()
266-
.unwrap();
267-
if log_enabled!(Level::Trace) {
268-
let mut local_acc = local_acc.clone();
269-
local_acc.code = None;
270-
trace!("local acc {local_acc:?}, trace acc {account_post_state:?}");
271-
}
272-
let local_balance = U256(*local_acc.balance.as_limbs());
273-
if local_balance != account_post_state.balance {
274-
let post = account_post_state.balance;
275-
error!(
276-
"incorrect balance, local {:#x} {} post {:#x} (diff {}{:#x})",
277-
local_balance,
278-
if local_balance < post { "<" } else { ">" },
279-
post,
280-
if local_balance < post { "-" } else { "+" },
281-
if local_balance < post {
282-
post - local_balance
283-
} else {
284-
local_balance - post
285-
}
286-
)
287-
}
288-
if local_acc.nonce != account_post_state.nonce {
289-
error!("incorrect nonce")
290-
}
291-
let p_hash = account_post_state.poseidon_code_hash;
292-
if p_hash.is_zero() {
293-
if !local_acc.is_empty() {
294-
error!("incorrect poseidon_code_hash")
295-
}
296-
} else if local_acc.code_hash.0 != p_hash.0 {
297-
error!("incorrect poseidon_code_hash")
298-
}
299-
let k_hash = account_post_state.keccak_code_hash;
300-
if k_hash.is_zero() {
301-
if !local_acc.is_empty() {
302-
error!("incorrect keccak_code_hash")
303-
}
304-
} else if local_acc.keccak_code_hash.0 != k_hash.0 {
305-
error!("incorrect keccak_code_hash")
306-
}
307-
}
308-
}
309218
}
310219

311220
impl Debug for EvmExecutor {

src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ extern crate log;
77
mod database;
88
mod executor;
99
mod hardfork;
10-
mod utils;
10+
/// Utilities
11+
pub mod utils;
1112

1213
pub use database::ReadOnlyDB;
13-
pub use executor::EvmExecutor;
14+
pub use executor::{hooks, EvmExecutor, EvmExecutorBuilder};
1415
pub use hardfork::HardforkConfig;

0 commit comments

Comments
 (0)