From 6f8610682a0e5d798d6b3970215f58ef80ea7443 Mon Sep 17 00:00:00 2001 From: Brechtpd Date: Mon, 13 May 2024 04:06:43 +0200 Subject: [PATCH] add tracer support --- .github/workflows/ci.yml | 2 + Cargo.lock | 110 +++++++++++++++++++++++++++++++++---- README.md | 11 +++- lib/Cargo.toml | 5 ++ lib/src/builder/execute.rs | 72 +++++++++++++++++++++++- 5 files changed, 187 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eeef21ae..0e592c39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,8 @@ jobs: run: make build - name: Test native prover run: make test + - name: Build with tracer + run: cargo build --features tracer build-test-risc0: name: Build and test risc0 diff --git a/Cargo.lock b/Cargo.lock index 66abad74..3be99b0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2255,6 +2255,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + [[package]] name = "enum-as-inner" version = "0.6.0" @@ -2382,8 +2400,8 @@ dependencies = [ "const-hex", "ethers-contract-abigen", "ethers-contract-derive", - "ethers-core", - "ethers-providers", + "ethers-core 2.0.10", + "ethers-providers 2.0.10", "futures-util", "once_cell", "pin-project", @@ -2400,7 +2418,7 @@ dependencies = [ "Inflector", "const-hex", "dunce", - "ethers-core", + "ethers-core 2.0.10", "eyre", "prettyplease", "proc-macro2", @@ -2421,7 +2439,7 @@ dependencies = [ "Inflector", "const-hex", "ethers-contract-abigen", - "ethers-core", + "ethers-core 2.0.10", "proc-macro2", "quote", "serde_json", @@ -2457,6 +2475,33 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum 0.7.2", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum 0.26.2", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + [[package]] name = "ethers-providers" version = "2.0.10" @@ -2467,8 +2512,46 @@ dependencies = [ "base64 0.21.7", "bytes", "const-hex", - "enr", - "ethers-core", + "enr 0.9.1", + "ethers-core 2.0.10", + "futures-channel", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http 0.2.12", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-providers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr 0.10.0", + "ethers-core 2.0.14", "futures-channel", "futures-core", "futures-timer", @@ -4963,7 +5046,7 @@ dependencies = [ "cfg-if", "clap 4.5.4", "env_logger", - "ethers-core", + "ethers-core 2.0.10", "flate2", "hyper 0.14.28", "lazy_static", @@ -5011,6 +5094,7 @@ dependencies = [ "anyhow", "bincode", "c-kzg-taiko", + "cfg-if", "chrono", "flate2", "hex", @@ -5093,7 +5177,7 @@ dependencies = [ "clap 4.5.4", "dirs", "env_logger", - "ethers-core", + "ethers-core 2.0.10", "flate2", "hyper 0.14.28", "lazy_static", @@ -5390,10 +5474,13 @@ dependencies = [ "auto_impl", "cfg-if", "dyn-clone", + "ethers-core 2.0.14", + "ethers-providers 2.0.14", "revm-interpreter", "revm-precompile", "serde", "serde_json", + "tokio", ] [[package]] @@ -5609,8 +5696,8 @@ dependencies = [ "bytemuck", "cfg-if", "ethers-contract", - "ethers-core", - "ethers-providers", + "ethers-core 2.0.10", + "ethers-providers 2.0.10", "hex", "log", "once_cell", @@ -6908,6 +6995,9 @@ name = "strum" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] [[package]] name = "strum_macros" diff --git a/README.md b/README.md index b462255b..920da765 100644 --- a/README.md +++ b/README.md @@ -99,4 +99,13 @@ If your CPU doesn't support SGX, you can still run the SGX code through gramine ```console $ MOCK=1 TARGET=sgx make run -``` \ No newline at end of file +``` + +### Execution Trace + +You can generate an execution trace for the block that is being proven by enabling the `tracer` feature: +```console +$ cargo run --features tracer +``` + +A folder called `traces` will be generated inside the root directory. This folder will contain json files with the trace of each valid transaction in the block. \ No newline at end of file diff --git a/lib/Cargo.toml b/lib/Cargo.toml index c2c6fb1a..ba43e96f 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -26,6 +26,7 @@ url = { workspace = true } hex = { workspace = true } c-kzg-taiko = { workspace = true } sha2 = { workspace = true } +cfg-if = { workspace = true } # [target.'cfg(feature = "std")'.dependencies] thiserror = { workspace = true, optional = true } @@ -57,3 +58,7 @@ std = [ sgx = [] sp1 = [] risc0 = [] +tracer = [ + "revm/serde-json", + "revm/ethersdb", +] \ No newline at end of file diff --git a/lib/src/builder/execute.rs b/lib/src/builder/execute.rs index b42ca1b1..260f2498 100644 --- a/lib/src/builder/execute.rs +++ b/lib/src/builder/execute.rs @@ -32,6 +32,12 @@ use revm::{ }, taiko, Database, DatabaseCommit, Evm, JournaledState, }; +cfg_if::cfg_if! { + if #[cfg(feature = "tracer")] { + use std::{fs::{OpenOptions, File}, io::{BufWriter, Write}, sync::{Arc, Mutex}}; + use revm::{inspector_handle_register, inspectors::TracerEip3155}; + } +} use super::{OptimisticDatabase, TxExecStrategy}; use crate::{ @@ -92,8 +98,10 @@ impl TxExecStrategy for TkoTxExecStrategy { ); // Setup the EVM environment - let evm = Evm::builder() - .with_db(block_builder.db.take().unwrap()) + let evm = Evm::builder().with_db(block_builder.db.take().unwrap()); + #[cfg(feature = "tracer")] + let evm = evm.with_external_context(TracerEip3155::new(Box::new(std::io::stdout()))); + let evm = evm .with_handler_cfg(HandlerCfg::new_with_taiko(spec_id, is_taiko)) .modify_cfg_env(|cfg_env| { // set the EVM configuration @@ -117,6 +125,8 @@ impl TxExecStrategy for TkoTxExecStrategy { } else { evm }; + #[cfg(feature = "tracer")] + let evm = evm.append_handler_register(inspector_handle_register); let mut evm = evm.build(); // Set the beacon block root in the EVM @@ -166,6 +176,14 @@ impl TxExecStrategy for TkoTxExecStrategy { for (tx_no, tx) in take(&mut transactions).into_iter().enumerate() { inplace_print(&format!("\rprocessing tx {tx_no}/{num_transactions}...")); + #[cfg(feature = "tracer")] + let inner = set_trace_writer( + &mut evm.context.external, + chain_id, + block_builder.input.block_number, + actual_tx_no, + ); + // anchor transaction always the first transaction let is_anchor = is_taiko && tx_no == 0; @@ -266,6 +284,10 @@ impl TxExecStrategy for TkoTxExecStrategy { #[cfg(feature = "std")] debug!(" Ok: {result:?}"); + #[cfg(feature = "tracer")] + // Flush the trace file writer + inner.lock().unwrap().flush().expect("Error flushing trace"); + tx_transact_duration.add_assign(start.elapsed()); let start = Instant::now(); @@ -455,3 +477,49 @@ where Ok(()) } + +#[cfg(feature = "tracer")] +fn set_trace_writer( + tracer: &mut TracerEip3155, + chain_id: u64, + block_number: u64, + tx_no: usize, +) -> Arc>> { + struct FlushWriter { + writer: Arc>>, + } + impl FlushWriter { + fn new(writer: Arc>>) -> Self { + Self { writer } + } + } + impl Write for FlushWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + //println!("writing"); + self.writer.lock().unwrap().write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + //println!("flushing"); + self.writer.lock().unwrap().flush() + } + } + + // Create the traces directory if it doesn't exist + std::fs::create_dir_all("traces").expect("Failed to create traces directory"); + + // Construct the file writer to write the trace to + let file_name = format!("traces/{}_{}_{}.json", chain_id, block_number, tx_no); + let write = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(file_name); + let inner = Arc::new(Mutex::new(BufWriter::new( + write.expect("Failed to open file"), + ))); + let writer = FlushWriter::new(Arc::clone(&inner)); + tracer.set_writer(Box::new(writer)); + + inner +}