diff --git a/Cargo.lock b/Cargo.lock index 6446d433c..6bacd1111 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "aggregator" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "ark-std", "env_logger 0.10.0", @@ -418,7 +418,7 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bus-mapping" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "eth-types", "ethers-core 0.17.0", @@ -1118,7 +1118,7 @@ dependencies = [ [[package]] name = "eth-types" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "ethers-core 0.17.0", "ethers-signers", @@ -1384,7 +1384,7 @@ dependencies = [ [[package]] name = "external-tracer" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "eth-types", "geth-utils", @@ -1597,7 +1597,7 @@ dependencies = [ [[package]] name = "gadgets" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "digest 0.7.6", "eth-types", @@ -1637,7 +1637,7 @@ dependencies = [ [[package]] name = "geth-utils" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "env_logger 0.9.3", "gobuild 0.1.0-alpha.2 (git+https://github.com/scroll-tech/gobuild.git)", @@ -2243,7 +2243,7 @@ dependencies = [ [[package]] name = "keccak256" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "env_logger 0.9.3", "eth-types", @@ -2443,7 +2443,7 @@ dependencies = [ [[package]] name = "mock" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "eth-types", "ethers-core 0.17.0", @@ -2458,7 +2458,7 @@ dependencies = [ [[package]] name = "mpt-zktrie" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "bus-mapping", "eth-types", @@ -4703,7 +4703,7 @@ checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" [[package]] name = "zkevm-circuits" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#5ae54f4b9c38951a12fbaf5a18a7ae1ef72df14a" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#f12d26ce378aa04e6c137e7b2197ddd5abb74132" dependencies = [ "array-init", "bus-mapping", diff --git a/bin/src/mock_testnet.rs b/bin/src/mock_testnet.rs index 422e04869..9212ea4c4 100644 --- a/bin/src/mock_testnet.rs +++ b/bin/src/mock_testnet.rs @@ -1,12 +1,11 @@ +#![allow(dead_code)] use anyhow::Result; use ethers_providers::{Http, Provider}; -use itertools::Itertools; use prover::{ inner::Prover, utils::init_env_and_log, zkevm::circuit::{ block_traces_to_witness_block, calculate_row_usage_of_witness_block, SuperCircuit, - SUB_CIRCUIT_NAMES, }, }; use reqwest::Url; @@ -32,118 +31,117 @@ async fn main() { for i in setting.begin_batch..=setting.end_batch { log::info!("mock-testnet: requesting block traces of batch {i}"); - let block_traces = match setting.prove_type { - ProveType::Batch => get_traces_by_batch_api(&provider, &setting, i).await, - ProveType::Block => get_traces_by_block_api(&provider, &setting, i).await, - }; - - let block_traces = block_traces - .unwrap_or_else(|_| panic!("mock-testnet: failed to request API with batch-{i}")); - - if let Some(block_traces) = block_traces { - let rows_only = true; - let result = (|| { - if rows_only { - let gas_total: u64 = block_traces - .iter() - .map(|b| b.header.gas_used.as_u64()) - .sum(); - let witness_block = block_traces_to_witness_block(&block_traces)?; - let rows = calculate_row_usage_of_witness_block(&witness_block)?; - log::info!( - "rows of batch {}(block range {:?} to {:?}):", - i, - block_traces.first().and_then(|b| b.header.number), - block_traces.last().and_then(|b| b.header.number), - ); - for (c, r) in SUB_CIRCUIT_NAMES.iter().zip_eq(rows.iter()) { - log::info!("rows of {}: {}", c, r); + let chunks = get_traces_by_block_api(&setting, i).await; + + let chunks = + chunks.unwrap_or_else(|_| panic!("mock-testnet: failed to request API with batch-{i}")); + + match chunks { + None => { + log::info!("mock-testnet: finished to prove at batch-{i}"); + break; + } + Some(chunks) => { + for chunk in chunks { + let ii = chunk.index; + log::info!("chunk {:?}", chunk); + + // fetch traces + let mut block_traces: Vec = vec![]; + for i in chunk.start_block_number..=chunk.end_block_number { + log::info!("mock-testnet: requesting trace of block {i}"); + + let trace = provider + .request("scroll_getBlockTraceByNumberOrHash", [format!("{i:#x}")]) + .await + .unwrap(); + block_traces.push(trace); + } + + // mock prove or estimate rows + let rows_only = true; + let result = (|| { + if rows_only { + let gas_total: u64 = block_traces + .iter() + .map(|b| b.header.gas_used.as_u64()) + .sum(); + let witness_block = block_traces_to_witness_block(&block_traces)?; + let rows = calculate_row_usage_of_witness_block(&witness_block)?; + log::info!( + "rows of batch {}(block range {:?} to {:?}):", + i, + block_traces.first().and_then(|b| b.header.number), + block_traces.last().and_then(|b| b.header.number), + ); + for r in &rows { + log::info!("rows of {}: {}", r.name, r.row_num_real); + } + let row_num = rows.iter().map(|x| x.row_num_real).max().unwrap(); + log::info!( + "final rows of chunk {}: row {}, gas {}, gas/row {:.2}", + ii, + row_num, + gas_total, + gas_total as f64 / row_num as f64 + ); + Ok(()) + } else { + Prover::::mock_prove_target_circuit_batch(&block_traces) + } + })(); + match result { + Ok(_) => { + log::info!( + "mock-testnet: succeeded to prove {ii}th chunk inside batch {i}" + ) + } + Err(err) => log::error!( + "mock-testnet: failed to prove {ii}th chunk inside batch {i}:\n{err:?}" + ), } - let row_num = rows.iter().max().unwrap(); - log::info!( - "final rows of batch {}: row {}, gas {}, gas/row {:.2}", - i, - row_num, - gas_total, - gas_total as f64 / *row_num as f64 - ); - Ok(()) - } else { - Prover::::mock_prove_target_circuit_batch(&block_traces) } - })(); - match result { - Ok(_) => log::info!("mock-testnet: succeeded to prove batch-{i}"), - Err(err) => log::error!("mock-testnet: failed to prove batch-{i}:\n{err:?}"), } - } else { - log::info!("mock-testnet: finished to prove at batch-{i}"); - break; } } log::info!("mock-testnet: end"); } -/// Request block traces by API `l2_getTracesByBatchIndex`. Return None for no more batches. -async fn get_traces_by_batch_api( - provider: &Provider, - _setting: &Setting, - batch_index: i64, -) -> Result>> { - // TODO: need to test this API. - Ok(Some( - provider - .request("l2_getTracesByBatchIndex", [format!("{batch_index:#x}")]) - .await?, - )) -} - -/// Request block traces by API `scroll_getBlockTraceByNumberOrHash`. Return None for no more -/// batches. +/// Request block traces by first using rollup API to get chunk info, then fetching blocks from +/// l2geth. Return None if no more batches. async fn get_traces_by_block_api( - provider: &Provider, setting: &Setting, batch_index: i64, -) -> Result>> { +) -> Result>> { let url = Url::parse_with_params( &setting.rollupscan_api_url, - &[("index", batch_index.to_string())], + &[("batch_index", batch_index.to_string())], )?; let resp: RollupscanResponse = reqwest::get(url).await?.json().await?; - - Ok(if let Some(batch) = resp.batch { - let mut traces = vec![]; - for i in batch.start_block_number..=batch.end_block_number { - log::info!("mock-testnet: requesting trace of block {i}"); - - let trace = provider - .request("scroll_getBlockTraceByNumberOrHash", [format!("{i:#x}")]) - .await?; - traces.push(trace); - } - - Some(traces) - } else { - None - }) + log::info!("handling batch {}", resp.batch_index); + Ok(resp.chunks) } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] struct RollupscanResponse { - batch: Option, + batch_index: usize, + chunks: Option>, } -#[derive(Deserialize)] -struct RollupscanBatch { +#[derive(Deserialize, Debug)] +struct ChunkInfo { + index: i64, + created_at: String, + total_tx_num: i64, + hash: String, start_block_number: i64, end_block_number: i64, } #[derive(Debug)] struct Setting { - prove_type: ProveType, begin_batch: i64, end_batch: i64, l2geth_api_url: String, @@ -154,13 +152,9 @@ impl Setting { pub fn new() -> Self { let l2geth_api_url = env::var("L2GETH_API_URL").expect("mock-testnet: Must set env L2GETH_API_URL"); - let prove_type = env::var("PROVE_TYPE").ok().unwrap_or_default().into(); let rollupscan_api_url = env::var("ROLLUPSCAN_API_URL"); - let rollupscan_api_url = match prove_type { - ProveType::Batch => rollupscan_api_url.unwrap_or_default(), - ProveType::Block => rollupscan_api_url - .expect("mock-testnet: Must set env ROLLUPSCAN_API_URL for block type"), - }; + let rollupscan_api_url = + rollupscan_api_url.unwrap_or_else(|_| "http://10.0.3.119:8560/api/chunks".to_string()); let begin_batch = env::var("PROVE_BEGIN_BATCH") .ok() .and_then(|n| n.parse().ok()) @@ -171,7 +165,6 @@ impl Setting { .unwrap_or(DEFAULT_END_BATCH); Self { - prove_type, begin_batch, end_batch, l2geth_api_url, @@ -179,18 +172,3 @@ impl Setting { } } } - -#[derive(Debug)] -enum ProveType { - Batch, - Block, -} - -impl From for ProveType { - fn from(s: String) -> Self { - match s.as_str() { - "batch" => Self::Batch, - _ => Self::Block, - } - } -} diff --git a/prover/src/aggregator/prover.rs b/prover/src/aggregator/prover.rs index bf064a246..a39533bee 100644 --- a/prover/src/aggregator/prover.rs +++ b/prover/src/aggregator/prover.rs @@ -2,7 +2,7 @@ use crate::{ common, config::{AGG_DEGREES, LAYER3_DEGREE, LAYER4_DEGREE}, zkevm::circuit::storage_trace_to_padding_witness_block, - ChunkProof, Proof, + BatchProof, ChunkProof, }; use aggregator::{ChunkHash, MAX_AGG_SNARKS}; use anyhow::Result; @@ -32,7 +32,7 @@ impl Prover { chunk_hashes_proofs: Vec<(ChunkHash, ChunkProof)>, name: Option<&str>, output_dir: Option<&str>, - ) -> Result { + ) -> Result { let name = name.map_or_else( || { chunk_hashes_proofs @@ -60,11 +60,12 @@ impl Prover { )?; log::info!("Got final compression thin EVM proof (layer-4): {name}"); + let batch_proof = BatchProof::from(evm_proof.proof); if let Some(output_dir) = output_dir { - evm_proof.dump(output_dir, "agg")?; + batch_proof.dump(output_dir, "agg")?; } - Ok(evm_proof.proof) + Ok(batch_proof) } // Generate previous snark before the final one. diff --git a/prover/src/aggregator/verifier.rs b/prover/src/aggregator/verifier.rs index 42fe91749..df8996c50 100644 --- a/prover/src/aggregator/verifier.rs +++ b/prover/src/aggregator/verifier.rs @@ -1,4 +1,4 @@ -use crate::{common, config::LAYER4_DEGREE, io::read_all, utils::read_env_var, Proof}; +use crate::{common, config::LAYER4_DEGREE, io::read_all, utils::read_env_var, BatchProof}; use aggregator::CompressionCircuit; use halo2_proofs::{ halo2curves::bn256::{Bn256, G1Affine}, @@ -53,8 +53,8 @@ impl Verifier { } } - pub fn verify_agg_evm_proof(&self, proof: &Proof) -> bool { + pub fn verify_agg_evm_proof(&self, batch_proof: BatchProof) -> bool { self.inner - .verify_evm_proof(self.deployment_code.clone(), proof) + .verify_evm_proof(self.deployment_code.clone(), &batch_proof.proof_to_verify()) } } diff --git a/prover/src/inner/prover.rs b/prover/src/inner/prover.rs index 44f31775f..d56108765 100644 --- a/prover/src/inner/prover.rs +++ b/prover/src/inner/prover.rs @@ -51,7 +51,7 @@ impl Prover { let result = self .inner .gen_inner_snark::(id, rng, &witness_block) - .and_then(|snark| { + .map(|snark| { let raw_vk = serialize_vk(self.inner.pk(id).unwrap().get_vk()); Proof::from_snark(snark, raw_vk) }); diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 8d3bcb335..3bf0d4865 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -11,34 +11,5 @@ pub mod zkevm; pub use common::ChunkHash; pub use evm_verifier::EvmVerifier; -pub use proof::{ChunkProof, EvmProof, Proof}; +pub use proof::{BatchProof, ChunkProof, EvmProof, Proof}; pub use snark_verifier_sdk::Snark; - -// Terminology used throughout this library. -// -// - Inner Circuit / Target Circuit / Super Circuit: they all mean the same thing. -// The first circuit. It takes inputs from block traces, and produces proofs pi_1 that are NOT -// verified on chain. -// -// - Target Circuit proof: proof for the Inner circuit. -// -// - Aggregation Circuit. -// The second circuit. It takes pi_1 from previous section, and produces proofs pi_2 that are -// verified on chain. -// -// - AggCircuitProof: proof for the aggregation circuit. -// -// - Prover: the prover that is responsible for the whole process. -// I.e., aggregation prover that takes in a list of traces, produces -// a proof that can be verified on chain - -// pub mod proof { -// use crate::zkevm::AggCircuitProof; -// use serde_derive::{Deserialize, Serialize}; - -// #[derive(Serialize, Deserialize, Debug)] -// pub struct ZkProof { -// pub id: u64, -// pub agg_proof: AggCircuitProof, -// } -// } diff --git a/prover/src/proof.rs b/prover/src/proof.rs index aae72c86a..95ef1440f 100644 --- a/prover/src/proof.rs +++ b/prover/src/proof.rs @@ -1,6 +1,4 @@ -use crate::io::{ - deserialize_fr_matrix, deserialize_vk, serialize_fr_matrix, serialize_vk, write_file, -}; +use crate::io::{deserialize_fr, deserialize_vk, serialize_fr_vec, serialize_vk, write_file}; use anyhow::{bail, Result}; use halo2_proofs::{ halo2curves::bn256::{Fr, G1Affine}, @@ -21,13 +19,15 @@ use std::{ }; use types::base64; +mod batch; mod chunk; mod evm; +pub use batch::BatchProof; pub use chunk::ChunkProof; pub use evm::EvmProof; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Proof { #[serde(with = "base64")] proof: Vec, @@ -38,34 +38,29 @@ pub struct Proof { } impl Proof { - pub fn new( - proof: Vec, - instances: &[Vec], - pk: Option<&ProvingKey>, - ) -> Result { - let instances = serde_json::to_vec(&serialize_fr_matrix(instances))?; + pub fn new(proof: Vec, instances: &[Vec], pk: Option<&ProvingKey>) -> Self { + let instances = serialize_instances(instances); let vk = pk.map_or_else(Vec::new, |pk| serialize_vk(pk.get_vk())); - Ok(Self { + Self { proof, instances, vk, - }) + } } pub fn from_json_file(dir: &str, filename: &str) -> Result { from_json_file(dir, filename) } - pub fn from_snark(snark: Snark, vk: Vec) -> Result { - let instances = serialize_fr_matrix(snark.instances.as_slice()); - let instances = serde_json::to_vec(&instances)?; + pub fn from_snark(snark: Snark, vk: Vec) -> Self { + let instances = serialize_instances(&snark.instances); - Ok(Proof { + Proof { proof: snark.proof, vk, instances, - }) + } } pub fn dump(&self, dir: &str, filename: &str) -> Result<()> { @@ -75,9 +70,13 @@ impl Proof { } pub fn instances(&self) -> Vec> { - let buf: Vec>> = serde_json::from_reader(self.instances.as_slice()).unwrap(); + let instance: Vec = self + .instances + .chunks(32) + .map(|bytes| deserialize_fr(bytes.to_vec())) + .collect(); - deserialize_fr_matrix(buf) + vec![instance] } pub fn proof(&self) -> &[u8] { @@ -111,13 +110,12 @@ pub fn dump_as_json(dir: &str, filename: &str, proof: &P) - Ok(()) } +pub fn dump_data(dir: &str, filename: &str, data: &[u8]) { + write_file(&mut PathBuf::from(dir), filename, data); +} + pub fn dump_vk(dir: &str, filename: &str, raw_vk: &[u8]) { - // Write vk as bytes. - write_file( - &mut PathBuf::from(dir), - &format!("vk_{filename}.vkey"), - raw_vk, - ); + dump_data(dir, &format!("vk_{filename}.vkey"), raw_vk); } pub fn from_json_file<'de, P: serde::Deserialize<'de>>(dir: &str, filename: &str) -> Result

{ @@ -135,7 +133,7 @@ pub fn from_json_file<'de, P: serde::Deserialize<'de>>(dir: &str, filename: &str } fn dump_proof_path(dir: &str, filename: &str) -> String { - format!("{dir}/proof_{filename}.json") + format!("{dir}/full_proof_{filename}.json") } fn dummy_protocol() -> Protocol { @@ -164,3 +162,15 @@ fn dummy_protocol() -> Protocol { accumulator_indices: Default::default(), } } + +fn serialize_instance(instance: &[Fr]) -> Vec { + let bytes: Vec<_> = serialize_fr_vec(instance).into_iter().flatten().collect(); + assert_eq!(bytes.len() % 32, 0); + + bytes +} + +fn serialize_instances(instances: &[Vec]) -> Vec { + assert_eq!(instances.len(), 1); + serialize_instance(&instances[0]) +} diff --git a/prover/src/proof/batch.rs b/prover/src/proof/batch.rs new file mode 100644 index 000000000..9d94ffcb4 --- /dev/null +++ b/prover/src/proof/batch.rs @@ -0,0 +1,85 @@ +use super::{dump_as_json, dump_data, dump_vk, from_json_file, serialize_instance, Proof}; +use crate::io::serialize_fr_vec; +use anyhow::Result; +use serde_derive::{Deserialize, Serialize}; + +const ACC_LEN: usize = 12; +const PI_LEN: usize = 32; + +const ACC_BYTES: usize = ACC_LEN * 32; +const PI_BYTES: usize = PI_LEN * 32; + +#[derive(Debug, Deserialize, Serialize)] +pub struct BatchProof { + #[serde(flatten)] + raw: Proof, +} + +impl From for BatchProof { + fn from(proof: Proof) -> Self { + let instances = proof.instances(); + assert_eq!(instances.len(), 1); + assert_eq!(instances[0].len(), ACC_LEN + PI_LEN); + + let vk = proof.vk; + let proof = proof + .proof + .into_iter() + .chain( + serialize_fr_vec(&instances[0][..ACC_LEN]) + .into_iter() + .flatten(), + ) + .collect(); + + let instances = serialize_instance(&instances[0][ACC_LEN..]); + + Self { + raw: Proof { + proof, + instances, + vk, + }, + } + } +} + +impl BatchProof { + pub fn from_json_file(dir: &str, name: &str) -> Result { + from_json_file(dir, &dump_filename(name)) + } + + pub fn dump(&self, dir: &str, name: &str) -> Result<()> { + let filename = dump_filename(name); + + dump_data(dir, &format!("pi_{filename}.data"), &self.raw.instances); + dump_data(dir, &format!("proof_{filename}.data"), &self.raw.proof); + + dump_vk(dir, &filename, &self.raw.vk); + + dump_as_json(dir, &filename, &self) + } + + pub fn proof_to_verify(self) -> Proof { + assert!(self.raw.proof.len() > ACC_BYTES); + assert_eq!(self.raw.instances.len(), PI_BYTES); + + let proof_len = self.raw.proof.len() - ACC_BYTES; + + let mut proof = self.raw.proof; + let mut instances = proof.split_off(proof_len); + instances.extend(self.raw.instances); + + let vk = self.raw.vk; + + Proof { + proof, + instances, + vk, + } + } +} + +fn dump_filename(name: &str) -> String { + format!("batch_{name}") +} diff --git a/prover/src/proof/chunk.rs b/prover/src/proof/chunk.rs index 3504c262a..01d5db033 100644 --- a/prover/src/proof/chunk.rs +++ b/prover/src/proof/chunk.rs @@ -24,7 +24,7 @@ impl ChunkProof { ) -> Result { let storage_trace = serde_json::to_vec(&storage_trace)?; let protocol = serde_json::to_vec(&snark.protocol)?; - let proof = Proof::new(snark.proof, &snark.instances, pk)?; + let proof = Proof::new(snark.proof, &snark.instances, pk); Ok(Self { storage_trace, diff --git a/prover/src/proof/evm.rs b/prover/src/proof/evm.rs index 0a84ca232..bca95e1ae 100644 --- a/prover/src/proof/evm.rs +++ b/prover/src/proof/evm.rs @@ -19,7 +19,7 @@ impl EvmProof { num_instance: Vec, pk: Option<&ProvingKey>, ) -> Result { - let proof = Proof::new(proof, instances, pk)?; + let proof = Proof::new(proof, instances, pk); Ok(Self { proof, diff --git a/prover/src/zkevm/capacity_checker.rs b/prover/src/zkevm/capacity_checker.rs index 9ff7d09c5..a966b93f9 100644 --- a/prover/src/zkevm/capacity_checker.rs +++ b/prover/src/zkevm/capacity_checker.rs @@ -1,6 +1,6 @@ use super::circuit::{ block_traces_to_witness_block_with_updated_state, calculate_row_usage_of_witness_block, - fill_zktrie_state_from_proofs, SUB_CIRCUIT_NAMES, + fill_zktrie_state_from_proofs, }; use crate::config::INNER_DEGREE; use itertools::Itertools; @@ -116,11 +116,12 @@ impl CircuitCapacityChecker { let witness_block = block_traces_to_witness_block_with_updated_state(traces, state, self.light_mode)?; let rows = calculate_row_usage_of_witness_block(&witness_block)?; - let row_usage_details: Vec = SUB_CIRCUIT_NAMES + let row_usage_details: Vec = rows .into_iter() - .map(|s| s.to_string()) - .zip_eq(rows.into_iter()) - .map(|(name, row_number)| SubCircuitRowUsage { name, row_number }) + .map(|x| SubCircuitRowUsage { + name: x.name, + row_number: x.row_num_real, + }) .collect_vec(); let tx_row_usage = RowUsage::from_row_usage_details(row_usage_details); self.row_usages.push(tx_row_usage.clone()); diff --git a/prover/src/zkevm/circuit.rs b/prover/src/zkevm/circuit.rs index 35574113e..53a2cb6e8 100644 --- a/prover/src/zkevm/circuit.rs +++ b/prover/src/zkevm/circuit.rs @@ -17,16 +17,8 @@ pub use self::builder::{ normalize_withdraw_proof, storage_trace_to_padding_witness_block, SUB_CIRCUIT_NAMES, }; -////// params for degree = 19 //////////// -/* -pub static DEGREE: Lazy = Lazy::new(|| read_env_var("DEGREE", 19)); -const MAX_INNER_BLOCKS: usize = 100; -const MAX_CALLDATA: usize = 400_000; -const MAX_RWS: usize = 500_000; -const MAX_KECCAK_ROWS: usize = 524_000; -const MAX_EXP_STEPS: usize = 10_000; -*/ - +// TODO: more smart row capacity checking rather than max_of(row_usage_details) > 1<<20 - 256 +// Need to compare with real row nums like MAX_MPT_ROWS/MAX_KECCAK_ROWS etc. ////// params for degree = 20 //////////// const MAX_TXS: usize = 32; const MAX_INNER_BLOCKS: usize = 100; diff --git a/prover/src/zkevm/circuit/builder.rs b/prover/src/zkevm/circuit/builder.rs index 827f80c9a..01fc46f1a 100644 --- a/prover/src/zkevm/circuit/builder.rs +++ b/prover/src/zkevm/circuit/builder.rs @@ -34,19 +34,22 @@ pub const SUB_CIRCUIT_NAMES: [&str; 14] = [ ]; // TODO: optimize it later -pub fn calculate_row_usage_of_trace(block_trace: &BlockTrace) -> Result> { +pub fn calculate_row_usage_of_trace( + block_trace: &BlockTrace, +) -> Result> { let witness_block = block_traces_to_witness_block(std::slice::from_ref(block_trace))?; calculate_row_usage_of_witness_block(&witness_block) } -pub fn calculate_row_usage_of_witness_block(witness_block: &Block) -> Result> { +pub fn calculate_row_usage_of_witness_block( + witness_block: &Block, +) -> Result> { let rows = ::Inner::min_num_rows_block_subcircuits( witness_block, - ) - .0; + ); log::debug!( - "row usage of block {:?}, tx num {:?}, tx len sum {}, rows needed {:?}", + "row usage of block {:?}, tx num {:?}, tx calldata len sum {}, rows needed {:?}", witness_block.context.first_or_default().number, witness_block.txs.len(), witness_block @@ -54,7 +57,7 @@ pub fn calculate_row_usage_of_witness_block(witness_block: &Block) -> Result .iter() .map(|t| t.call_data_length) .sum::(), - SUB_CIRCUIT_NAMES.iter().zip_eq(rows.iter()) + rows, ); Ok(rows) } @@ -88,32 +91,34 @@ pub fn check_batch_capacity(block_traces: &mut Vec) -> Result<()> { } let t = Instant::now(); - let mut acc = Vec::new(); + let mut acc: Vec = Vec::new(); let mut n_txs = 0; let mut truncate_idx = block_traces.len(); for (idx, block) in block_traces.iter().enumerate() { - let usage = calculate_row_usage_of_trace(block)?; + let usage = calculate_row_usage_of_trace(block)? + .into_iter() + .map(|x| crate::zkevm::SubCircuitRowUsage { + name: x.name, + row_number: x.row_num_real, + }) + .collect_vec(); if acc.is_empty() { - acc = usage; + acc = usage.clone(); } else { acc.iter_mut().zip(usage.iter()).for_each(|(acc, usage)| { - *acc += usage; + acc.row_number += usage.row_number; }); } - let rows = itertools::max(&acc).unwrap(); - let rows_and_names: Vec<(_, _)> = SUB_CIRCUIT_NAMES - .iter() - .zip_eq(acc.iter()) - .collect::>(); + let rows: usize = itertools::max(acc.iter().map(|x| x.row_number)).unwrap(); log::debug!( "row usage after block {}({:?}): {}, {:?}", idx, block.header.number, rows, - rows_and_names + usage ); n_txs += block.transactions.len(); - if *rows > (1 << *INNER_DEGREE) - 256 || n_txs > MAX_TXS { + if rows > (1 << *INNER_DEGREE) - 256 || n_txs > MAX_TXS { log::warn!( "truncate blocks [{}..{}), n_txs {}, rows {}", idx, @@ -193,9 +198,23 @@ pub fn fill_zktrie_state_from_proofs( } pub fn block_traces_to_witness_block(block_traces: &[BlockTrace]) -> Result> { - log::debug!( - "block_traces_to_witness_block, input len {:?}", - block_traces.len() + let block_num = block_traces.len(); + let total_tx_num = block_traces + .iter() + .map(|b| b.transactions.len()) + .sum::(); + if total_tx_num > MAX_TXS { + bail!( + "tx num overflow {}, block range {} to {}", + total_tx_num, + block_traces[0].header.number.unwrap(), + block_traces[block_num - 1].header.number.unwrap() + ); + } + log::info!( + "block_traces_to_witness_block, block num {}, tx num {}", + block_num, + total_tx_num, ); let old_root = if block_traces.is_empty() { eth_types::Hash::zero() diff --git a/prover/tests/aggregation_tests.rs b/prover/tests/aggregation_tests.rs index cf9f3ea9c..f89a846a3 100644 --- a/prover/tests/aggregation_tests.rs +++ b/prover/tests/aggregation_tests.rs @@ -5,7 +5,7 @@ use prover::{ config::LAYER4_DEGREE, test_util::{load_block_traces_for_test, PARAMS_DIR}, utils::{chunk_trace_to_witness_block, init_env_and_log}, - zkevm, ChunkHash, ChunkProof, EvmProof, Proof, + zkevm, BatchProof, ChunkHash, ChunkProof, EvmProof, Proof, }; use snark_verifier_sdk::Snark; use std::env; @@ -19,13 +19,12 @@ fn test_agg_prove_verify() { let mut agg_prover = Prover::from_params_dir(PARAMS_DIR); log::info!("Constructed aggregation prover"); - let trace_paths: Vec<_> = (2..=3) - .map(|i| format!("./tests/traces/bridge/{i:02}.json")) - .collect(); - - let trace_paths = vec!["./tests/traces/erc20/10_transfer.json".to_string()]; + let trace_paths = vec![ + "./tests/traces/erc20/1_transfer.json".to_string(), + "./tests/traces/erc20/10_transfer.json".to_string(), + ]; - let chunk_hashes_proofs = gen_chunk_hashes_and_proofs(&output_dir, trace_paths.as_slice()); + let chunk_hashes_proofs = gen_chunk_hashes_and_proofs(&output_dir, &trace_paths); log::info!("Generated chunk hashes and proofs"); // Load or generate aggregation snark (layer-3). @@ -75,7 +74,10 @@ fn gen_and_verify_evm_proof( let verifier = Verifier::from_dirs(PARAMS_DIR, output_dir); log::info!("Constructed aggregator verifier"); - let success = verifier.verify_agg_evm_proof(&evm_proof.proof); + let batch_proof = BatchProof::from(evm_proof.proof.clone()); + batch_proof.dump(output_dir, "agg").unwrap(); + + let success = verifier.verify_agg_evm_proof(batch_proof); assert!(success); log::info!("Finished EVM verification"); @@ -103,7 +105,7 @@ fn gen_and_verify_normal_proof( .unwrap(); log::info!("Got compression thin snark (layer-4)"); - let proof = Proof::from_snark(layer4_snark, raw_vk).unwrap(); + let proof = Proof::from_snark(layer4_snark, raw_vk); log::info!("Got normal proof"); assert!(verifier.inner.verify_proof(proof)); diff --git a/utils.sh b/utils.sh index c24e2f80f..b166250af 100644 --- a/utils.sh +++ b/utils.sh @@ -18,8 +18,8 @@ function simple_tests() { } function replace_zkevm_circuits_branch() { - TO=feat/withdraw_proof - FROM=develop + FROM=feat/testing0801 + TO=develop sed -i 's#zkevm-circuits.git", branch = "'$FROM'#zkevm-circuits.git", branch = "'$TO'#' */Cargo.toml cargo update -p zkevm-circuits cargo update -p eth-types