diff --git a/prover/.gitignore b/prover/.gitignore index 8f82cd087..62bb18875 100644 --- a/prover/.gitignore +++ b/prover/.gitignore @@ -24,4 +24,6 @@ shadow-proving contracts/cache contracts out -lib \ No newline at end of file +lib + +proof \ No newline at end of file diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 9c6ad0956..cfa4bfbea 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -5459,6 +5459,7 @@ dependencies = [ name = "sbv-core" version = "2.0.0" dependencies = [ + "cfg-if 1.0.0", "ctor", "hex", "once_cell", diff --git a/prover/bin/challenge/src/external_sign.rs b/prover/bin/challenge/src/external_sign.rs index 8cbfa2212..fb4a28fa2 100644 --- a/prover/bin/challenge/src/external_sign.rs +++ b/prover/bin/challenge/src/external_sign.rs @@ -86,7 +86,7 @@ impl ExternalSign { let req_data = self.craft_req_data(data, tx_info)?; let rt = self.do_request(&self.url, &req_data).await?; - log::debug!("ext_sign response: {:?}", rt); + log::info!("ext_sign rt: {:?}", rt); let response: Response = serde_json::from_str(&rt)?; if response.result.sign_datas.is_empty() { @@ -97,6 +97,7 @@ impl ExternalSign { return Err("ext_sign response sign data invalid".into()); } + let sig = hex::decode(&response.result.sign_datas[0].sign[2..])?; let signed_tx: Bytes = tx.rlp_signed(&Signature::try_from(sig.as_slice())?); Ok(signed_tx) @@ -139,8 +140,13 @@ impl ExternalSign { async fn do_request(&self, url: &str, payload: &ReqData) -> Result> { log::debug!("===payload: {:?}", serde_json::to_string(payload).unwrap()); let response: reqwest::Response = self.client.post(url).json(&payload).send().await?; - if !response.status().is_success() { - return Err(format!("ext_sign response status not ok: {:?}", response.status()).into()); + log::info!("===do_request response: {:?}", response); + + let status = response.status(); + if !status.is_success() { + let text = response.text().await?; + log::info!("===do_request response text: {:?}", &text); + return Err(format!("ext_sign response status not ok: {:?}", status).into()); } Ok(response.text().await?) } diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index cdb8ea429..44763205f 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -12,7 +12,6 @@ use eyre::anyhow; use serde::{Deserialize, Serialize}; use std::env::var; use std::error::Error; -use std::ops::Mul; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; @@ -175,6 +174,7 @@ impl ChallengeHandler { if !batch_proof.proof_data.is_empty() { log::info!("query proof and prove state: {:#?}", batch_index); let batch_header = batch_info.fill_ext(batch_proof.batch_header.clone()).encode(); + sleep(Duration::from_secs(600)).await; self.prove_state(batch_index, batch_header, batch_proof, l1_rollup).await; continue; } @@ -462,6 +462,8 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat let withdrawal_root: [u8; 32] = param.batch_data_input.withdrawal_root; let last_block_number: u64 = param.batch_data_input.last_block_number; let num_l1_messages = param.batch_data_input.num_l1_messages; + log::info!("======> batch inspect: decode tx.input, version = {:#?}", version); + log::info!("======> batch inspect: decode tx.input, param = {:#?}", param); let mut batch_info = BatchInfo { version, @@ -574,4 +576,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:?}", e) }; error_msg -} +} \ No newline at end of file diff --git a/prover/bin/host/build.rs b/prover/bin/host/build.rs deleted file mode 100644 index 8d530f6bd..000000000 --- a/prover/bin/host/build.rs +++ /dev/null @@ -1,15 +0,0 @@ -use morph_executor_utils::read_env_var; -use sp1_helper::{build_program_with_args, BuildArgs}; - -fn main() { - if read_env_var("DEVNET", false) { - build_program_with_args( - "../client", - BuildArgs { - ignore_rust_version: true, - output_directory: "bin/client/elf".to_string(), - ..Default::default() - }, - ); - } -} diff --git a/prover/bin/host/src/lib.rs b/prover/bin/host/src/lib.rs index 7c8147173..91f0c6c52 100644 --- a/prover/bin/host/src/lib.rs +++ b/prover/bin/host/src/lib.rs @@ -34,7 +34,7 @@ pub fn prove( // Prepare input. // Convert the traces' format to reduce conversion costs in the client. - blocks.iter_mut().for_each(|blobk| blobk.flatten()); + blocks.iter_mut().for_each(|block| block.flatten()); let client_input = ClientInput { l2_traces: blocks.clone(), blob_info: get_blob_info(blocks).unwrap() }; diff --git a/prover/bin/server/src/queue.rs b/prover/bin/server/src/queue.rs index b82e1bffc..974bffffb 100644 --- a/prover/bin/server/src/queue.rs +++ b/prover/bin/server/src/queue.rs @@ -86,7 +86,10 @@ impl Prover { if read_env_var("SAVE_TRACE", false) { save_trace(batch_index, block_traces); } - save_batch_header(block_traces, batch_index); + if !save_batch_header(block_traces, batch_index) { + save_trace(batch_index, block_traces); + continue; + } // Step3. Generate evm proof log::info!("Generate evm proof"); @@ -113,24 +116,40 @@ impl Prover { } } -fn save_batch_header(blocks: &mut Vec, batch_index: u64) { - blocks.iter_mut().for_each(|blobk| blobk.flatten()); - let batch_info = EVMVerifier::verify(blocks).unwrap(); - let blob_info = morph_executor_host::get_blob_info(blocks).unwrap(); - let (versioned_hash, _) = BlobVerifier::verify(&blob_info, blocks.len()).unwrap(); - - // Save batch_header - // | batch_data_hash | versioned_hash | sequencer_root | - // |-----------------|----------------|----------------| - // | bytes32 | bytes32 | bytes32 | - let mut batch_header: Vec = Vec::with_capacity(96); - batch_header.extend_from_slice(&batch_info.data_hash().0); - batch_header.extend_from_slice(&versioned_hash.0); - batch_header.extend_from_slice(&batch_info.sequencer_root().0); +fn save_batch_header(blocks: &mut Vec, batch_index: u64) -> bool { let proof_dir = PROVER_PROOF_DIR.to_string() + format!("/batch_{}", batch_index).as_str(); std::fs::create_dir_all(&proof_dir).expect("failed to create proof path"); - let mut batch_file = File::create(format!("{}/batch_header.data", proof_dir)).unwrap(); - batch_file.write_all(&batch_header[..]).expect("failed to batch_header"); + blocks.iter_mut().for_each(|block| block.flatten()); + let verify_result = EVMVerifier::verify(blocks); + + if let Ok(batch_info) = verify_result { + let blob_info = morph_executor_host::get_blob_info(blocks).unwrap(); + let (versioned_hash, _) = BlobVerifier::verify(&blob_info, blocks.len()).unwrap(); + + // Save batch_header + // | batch_data_hash | versioned_hash | sequencer_root | + // |-----------------|----------------|----------------| + // | bytes32 | bytes32 | bytes32 | + let mut batch_header: Vec = Vec::with_capacity(96); + batch_header.extend_from_slice(&batch_info.data_hash().0); + batch_header.extend_from_slice(&versioned_hash.0); + batch_header.extend_from_slice(&batch_info.sequencer_root().0); + let mut batch_file = File::create(format!("{}/batch_header.data", proof_dir)).unwrap(); + batch_file.write_all(&batch_header[..]).expect("failed to batch_header"); + true + } else { + let e = verify_result.unwrap_err(); + let error_data = serde_json::json!({ + "error_code": "EVM_EXECUTE_NOT_EXPECTED", + "error_msg": e.to_string() + }); + let mut batch_file = File::create(format!("{}/execute_result.json", proof_dir)).unwrap(); + batch_file + .write_all(serde_json::to_string_pretty(&error_data).unwrap().as_bytes()) + .expect("failed to write error"); + log::error!("EVM verification failed for batch {}: {}", batch_index, e); + false + } } fn save_proof(batch_index: u64, proof: EvmProofFixture) { @@ -191,3 +210,19 @@ fn save_trace(batch_index: u64, chunk_traces: &Vec) { serde_json::to_writer_pretty(writer, &chunk_traces).unwrap(); log::info!("chunk_traces of batch_index = {:#?} saved", batch_index); } + +#[test] +fn test_save_execute() { + let batch_index = 102u64; + + let mut blocks = load_trace("../../testdata/viridian/eip7702_traces.json"); + println!("blocks.len(): {:?}", blocks.len()); + let traces = blocks.first_mut().unwrap(); + + if !save_batch_header(traces, batch_index) { + save_trace(batch_index, traces); + println!("save_batch_header error"); + } else { + println!("save_batch_header success"); + } +} diff --git a/prover/bin/server/src/server.rs b/prover/bin/server/src/server.rs index 4fbbd2a87..411f01eb2 100644 --- a/prover/bin/server/src/server.rs +++ b/prover/bin/server/src/server.rs @@ -224,6 +224,31 @@ async fn query_proof(batch_index: String) -> ProveResult { .unwrap_or("nothing") .ends_with(format!("batch_{}", batch_index.trim()).as_str()) { + // execute_result + let prove_result_path = path.join("execute_result.json"); + if prove_result_path.exists() { + match fs::File::open(prove_result_path) { + Ok(file) => { + let reader = BufReader::new(file); + let prove_result: serde_json::Value = + serde_json::from_reader(reader).unwrap_or_default(); + if let Some(error_code) = prove_result.get("error_code") { + result.error_code = error_code.as_str().unwrap_or("").to_string(); + } + if let Some(error_msg) = prove_result.get("error_msg") { + result.error_msg = error_msg.as_str().unwrap_or("").to_string(); + } + } + Err(e) => { + log::error!("Failed to load prove_result: {:#?}", e); + result.error_msg = String::from("Failed to load prove_result"); + } + } + } + if !result.error_code.is_empty() { + return result; + } + //pi_batch_agg.data let proof_path = path.join("plonk_proof.json"); if !proof_path.exists() { @@ -261,7 +286,7 @@ async fn query_proof(batch_index: String) -> ProveResult { break; } } - if result.proof_data.is_empty() { + if result.proof_data.is_empty() && result.error_msg.is_empty() { result.error_msg = String::from("No proof was found"); } result diff --git a/prover/bin/shadow-prove/src/main.rs b/prover/bin/shadow-prove/src/main.rs index dc8302b4e..df12d4118 100644 --- a/prover/bin/shadow-prove/src/main.rs +++ b/prover/bin/shadow-prove/src/main.rs @@ -72,7 +72,7 @@ async fn main() { ); loop { - sleep(Duration::from_secs(12)).await; + sleep(Duration::from_secs(30)).await; // Sync & Prove let result = match batch_syncer.sync_batch().await { Ok(Some(batch)) => shadow_prover.prove(batch).await, diff --git a/prover/bin/shadow-prove/src/shadow_prove.rs b/prover/bin/shadow-prove/src/shadow_prove.rs index 12e950fd8..b6f9b2d06 100644 --- a/prover/bin/shadow-prove/src/shadow_prove.rs +++ b/prover/bin/shadow-prove/src/shadow_prove.rs @@ -110,6 +110,10 @@ async fn handle_with_prover( // Query existing proof if let Some(prove_result) = query_proof(batch_index).await { + if !prove_result.error_code.is_empty() { + log::error!("query proof and prove state error, batch_index: {:?}, prove_result.error_code: {:?}, prove_result.error_msg: {:?}", batch_index, prove_result.error_code, prove_result.error_msg); + break; + } if !prove_result.proof_data.is_empty() { log::info!("query proof and prove state: {:?}", batch_index); prove_state(batch_index, l1_shadow_rollup).await; @@ -160,6 +164,10 @@ async fn handle_with_prover( max_waiting_time -= 300; // Query results every 5 minutes. match query_proof(batch_index).await { Some(prove_result) => { + if !prove_result.error_code.is_empty() { + log::error!("query proof and prove state error, batch_index: {:?}, prove_result.error_code: {:?}, prove_result.error_msg: {:?}", batch_index, prove_result.error_code, prove_result.error_msg); + return; + } log::debug!("query proof and prove state: {:#?}", batch_index); if !prove_result.proof_data.is_empty() { prove_state(batch_index, l1_shadow_rollup).await; diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index 6c41d8488..5685b7cac 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -71,7 +71,7 @@ where // Batch should not have been verified yet. if is_prove_success(batch_info.batch_index, &self.l1_shadow_rollup).await.unwrap_or(true) { - log::debug!("batch of {:?} already prove state successful", batch_info.batch_index); + log::info!("batch of {:?} already prove state successful", batch_info.batch_index); return Ok(None); }; @@ -208,7 +208,7 @@ where None => return Err(String::from("batch_blocks_inspect none")), }; - if blocks.0 <= blocks.1 { + if blocks.0 >= blocks.1 { return Err(String::from("blocks is empty")); } @@ -228,11 +228,11 @@ where // A rollup commit_batch_input contains prev batch_header. let next_tx_hash = match logs.last() { Some(log) => log.transaction_hash.unwrap_or_default(), - None => { return Err("find commit_batch log error".to_string()); } }; + let batch_header = batch_header_inspect(l1_provider, next_tx_hash) .await .ok_or_else(|| "Failed to inspect batch header".to_string())?; diff --git a/prover/crates/core/Cargo.toml b/prover/crates/core/Cargo.toml index 053ac0ebb..f10947bc9 100644 --- a/prover/crates/core/Cargo.toml +++ b/prover/crates/core/Cargo.toml @@ -21,6 +21,7 @@ tiny-keccak.workspace = true sbv-primitives.workspace = true sbv-utils.workspace = true +cfg-if = { workspace = true } [dev-dependencies] ctor.workspace = true diff --git a/prover/crates/core/src/database.rs b/prover/crates/core/src/database.rs index 1db47d33e..82ddae1d9 100644 --- a/prover/crates/core/src/database.rs +++ b/prover/crates/core/src/database.rs @@ -193,12 +193,10 @@ impl DatabaseRef for ReadOnlyDB { // then the upcoming trace contains code (meaning the code is used in this new block), // we can't directly update the CacheDB, so we offer the code by hash here. // However, if the code still cannot be found, this is an error. - self.code_db.get(&hash).cloned().ok_or_else(|| { - unreachable!( - "Code is either loaded or not needed (like EXTCODESIZE), code hash: {:?}", - hash - ); - }) + Ok(self.code_db.get(&hash).cloned().unwrap_or_else(|| { + println!("---------------->code_by_hash_ref error: {:?}", hash); + Bytecode::default() + })) } /// Get storage value of address at index. diff --git a/prover/crates/core/src/executor/mod.rs b/prover/crates/core/src/executor/mod.rs index 94178f6ef..392832d8f 100644 --- a/prover/crates/core/src/executor/mod.rs +++ b/prover/crates/core/src/executor/mod.rs @@ -92,6 +92,12 @@ impl EvmExecutor<'_> { }; for (idx, tx) in l2_trace.transactions().enumerate() { + cfg_if::cfg_if! { + if #[cfg(not(target_os = "zkvm"))] { + println!("handle block: {:?}, handle tx: {:?}th", l2_trace.number(), idx); + } + } + cycle_tracker_start!("handle tx {}", idx); dev_trace!("handle {idx}th tx"); @@ -277,9 +283,11 @@ impl EvmExecutor<'_> { poseidon_code_hash.0, ]; cycle_track!( - zktrie - .update_account(addr.as_slice(), &acc_data) - .unwrap_or_else(|_| panic!("failed to update account: {}", addr)), + zktrie.update_account(addr.as_slice(), &acc_data).unwrap_or_else(|e| println!( + "---------------->failed to update account: {:?}, address: {:?}", + addr, + e.to_string() + )), "Zktrie::update_account" ); diff --git a/prover/crates/primitives/src/types/tx.rs b/prover/crates/primitives/src/types/tx.rs index f12f9ccbf..6cdebe357 100644 --- a/prover/crates/primitives/src/types/tx.rs +++ b/prover/crates/primitives/src/types/tx.rs @@ -107,6 +107,7 @@ pub struct TransactionTrace { pub(crate) access_list: AccessList, /// authorization list #[serde(rename = "authorizationList")] + #[serde(default)] #[serde_as(as = "DefaultOnNull")] pub(crate) authorization_list: AuthorizationList, /// signature v @@ -552,20 +553,3 @@ impl Decodable for TypedTransaction { Ok(TypedTransaction::Enveloped(TxEnvelope::decode_2718(buf).unwrap())) } } - -#[cfg(test)] -mod tests { - use super::*; - - const TRACE: &str = include_str!("../../../../testdata/dev.json"); - - #[test] - fn test_transaction_trace_deserialize() { - let trace = serde_json::from_str::(TRACE).unwrap()["result"].clone(); - let txs = trace["transactions"].clone(); - for tx in txs.as_array().unwrap() { - let tx: TransactionTrace = serde_json::from_value(tx.clone()).unwrap(); - let _ = tx.try_build_typed_tx().unwrap(); - } - } -} diff --git a/prover/tests/algebra/host/build.rs b/prover/tests/algebra/host/build.rs deleted file mode 100644 index 5b62505c7..000000000 --- a/prover/tests/algebra/host/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -use sp1_helper::{build_program_with_args, BuildArgs}; - -fn main() { - build_program_with_args( - "../client", - BuildArgs { - ignore_rust_version: true, - output_directory: "tests/algebra/client/elf".to_string(), - ..Default::default() - }, - ) -} diff --git a/prover/tests/bls12381/host/build.rs b/prover/tests/bls12381/host/build.rs deleted file mode 100644 index a68444b99..000000000 --- a/prover/tests/bls12381/host/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -use sp1_helper::{build_program_with_args, BuildArgs}; - -fn main() { - build_program_with_args( - "../client", - BuildArgs { - ignore_rust_version: true, - output_directory: "tests/bls12381/client/elf".to_string(), - ..Default::default() - }, - ) -} diff --git a/prover/tests/keccak256/host/build.rs b/prover/tests/keccak256/host/build.rs deleted file mode 100644 index 370dce295..000000000 --- a/prover/tests/keccak256/host/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -use sp1_helper::{build_program_with_args, BuildArgs}; - -fn main() { - build_program_with_args( - "../client", - BuildArgs { - ignore_rust_version: true, - output_directory: "tests/keccak256/client/elf".to_string(), - ..Default::default() - }, - ) -} diff --git a/prover/tests/zstd/host/build.rs b/prover/tests/zstd/host/build.rs deleted file mode 100644 index d0a9bbbd4..000000000 --- a/prover/tests/zstd/host/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -use sp1_helper::{build_program_with_args, BuildArgs}; - -fn main() { - build_program_with_args( - "../client", - BuildArgs { - ignore_rust_version: true, - output_directory: "tests/zstd/client/elf".to_string(), - ..Default::default() - }, - ) -}