diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index 86015ff95..7519bdf36 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -35,7 +35,7 @@ jobs: - uses: actions/checkout@v3 with: submodules: true - - run: git config --system --add safe.directory /__w/scroll-zkevm/scroll-zkevm + - run: git config --system --add safe.directory /__w/scroll-prover/scroll-prover - uses: actions/setup-go@v3 with: go-version: '>=1.18.0' diff --git a/Cargo.lock b/Cargo.lock index 6a787aca3..748360255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,26 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "aggregator" +version = "0.1.0" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" +dependencies = [ + "ark-std", + "env_logger 0.10.0", + "eth-types", + "ethers-core 0.17.0", + "halo2_proofs", + "itertools", + "log", + "rand", + "serde", + "serde_json", + "snark-verifier", + "snark-verifier-sdk", + "zkevm-circuits", +] + [[package]] name = "ahash" version = "0.7.6" @@ -205,7 +225,7 @@ checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" [[package]] name = "bin" -version = "0.3.0" +version = "0.4.0" dependencies = [ "anyhow", "clap", @@ -398,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#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "eth-types", "ethers-core 0.17.0", @@ -1098,7 +1118,7 @@ dependencies = [ [[package]] name = "eth-types" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "ethers-core 0.17.0", "ethers-signers", @@ -1364,7 +1384,7 @@ dependencies = [ [[package]] name = "external-tracer" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "eth-types", "geth-utils", @@ -1417,7 +1437,7 @@ dependencies = [ [[package]] name = "ffi" -version = "0.3.0" +version = "0.4.0" dependencies = [ "libc", "log", @@ -1593,7 +1613,7 @@ dependencies = [ [[package]] name = "gadgets" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "digest 0.7.6", "eth-types", @@ -1633,7 +1653,7 @@ dependencies = [ [[package]] name = "geth-utils" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "env_logger 0.9.3", "gobuild 0.1.0-alpha.2 (git+https://github.com/scroll-tech/gobuild.git)", @@ -1731,7 +1751,7 @@ dependencies = [ [[package]] name = "halo2-base" version = "0.2.2" -source = "git+https://github.com/scroll-tech/halo2-lib?branch=develop#c2ea19569db5fedd85a7465ee3841f23be8e7b22" +source = "git+https://github.com/scroll-tech/halo2-lib?branch=develop#2c225864227e74b207d9f4b9e08c4d5f1afc69a1" dependencies = [ "ff", "halo2_proofs", @@ -1746,7 +1766,7 @@ dependencies = [ [[package]] name = "halo2-ecc" version = "0.2.2" -source = "git+https://github.com/scroll-tech/halo2-lib?branch=develop#c2ea19569db5fedd85a7465ee3841f23be8e7b22" +source = "git+https://github.com/scroll-tech/halo2-lib?branch=develop#2c225864227e74b207d9f4b9e08c4d5f1afc69a1" dependencies = [ "ff", "group", @@ -1765,7 +1785,7 @@ dependencies = [ [[package]] name = "halo2-mpt-circuits" version = "0.1.0" -source = "git+https://github.com/scroll-tech/mpt-circuit.git?branch=v0.4#85f6f96d1da2ddff5fb2d7cf4852b9f356b326a7" +source = "git+https://github.com/scroll-tech/mpt-circuit.git?branch=v0.4#9d129125bd792e906c30e56386424bc3ab5920ba" dependencies = [ "ethers-core 0.17.0", "halo2_proofs", @@ -1787,7 +1807,7 @@ dependencies = [ [[package]] name = "halo2_proofs" version = "0.2.0" -source = "git+https://github.com/scroll-tech/halo2.git?branch=develop#9bf3562083dd9bed8a19f651b52bc810f5e2235f" +source = "git+https://github.com/scroll-tech/halo2.git?branch=develop#aab39d5c107fdeec62ce7d2aeec6b72de681ba23" dependencies = [ "ark-std", "blake2b_simd", @@ -2223,7 +2243,7 @@ dependencies = [ [[package]] name = "keccak256" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "env_logger 0.9.3", "eth-types", @@ -2423,7 +2443,7 @@ dependencies = [ [[package]] name = "mock" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "eth-types", "ethers-core 0.17.0", @@ -2438,7 +2458,7 @@ dependencies = [ [[package]] name = "mpt-zktrie" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "bus-mapping", "eth-types", @@ -2932,16 +2952,11 @@ dependencies = [ "rustix 0.35.13", ] -[[package]] -name = "project-root" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bccbff07d5ed689c4087d20d7307a52ab6141edeedf487c3876a55b86cf63df" - [[package]] name = "prover" version = "0.4.0" dependencies = [ + "aggregator", "anyhow", "blake2", "bus-mapping", @@ -2962,7 +2977,6 @@ dependencies = [ "num-bigint", "once_cell", "procfs", - "project-root", "rand", "rand_xorshift", "serde", @@ -4669,7 +4683,7 @@ checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" [[package]] name = "zkevm-circuits" version = "0.1.0" -source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#236931675f3879ca3ec87ebc421ca9bc4674cca9" +source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#a79581529b79a6cc9f9f7bbf114e88c3a5359d01" dependencies = [ "array-init", "bus-mapping", diff --git a/Makefile b/Makefile index e0bf0369e..5eb57cb9c 100644 --- a/Makefile +++ b/Makefile @@ -26,9 +26,6 @@ bridge-test: cargo build --release ./target/release/prove --params=./test_params --trace=prover/tests/traces/bridge -test-inner-prove: ## Test inner circuit with real trace - cargo test --features prove_verify --release test_prove_verify - mock: @cargo test --features prove_verify --release test_mock_prove -- --exact --nocapture @@ -38,8 +35,17 @@ mock-debug: mock-testnet: @cargo run --bin mock_testnet --release +test-inner-prove: + @cargo test --features prove_verify --release test_inner_prove_verify + test-chunk-prove: - @cargo test --features prove_verify --release test_aggregation_api + @cargo test --features prove_verify --release test_chunk_prove_verify + +test-comp-prove: + @cargo test --features prove_verify --release test_comp_prove_verify + +test-agg-prove: + @cargo test --features prove_verify --release test_agg_prove_verify rows: @cargo test --features prove_verify --release estimate_circuit_rows diff --git a/README.md b/README.md index d29b1eb26..052e4ca0e 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,13 @@ git submodule init git submodule update --checkout ``` -Download setup params +Download all setup params, degree `20` and `25` are used in [config.rs](https://github.com/scroll-tech/scroll-prover/tree/main/prover/src/config.rs). +Could only download params of degree `25`, but it may affect performance (when dowsizing to `20`). ```shell -make download-setup +make download-setup -e degree=20 +make download-setup -e degree=25 ``` -Or specify degree and target directory to download +Or specify other degree and target directory to download. ```shell # As default `degree=25` and `params_dir=./prover/test_params`. make download-setup -e degree=DEGREE params_dir=PARAMS_DIR @@ -26,7 +28,7 @@ make download-setup -e degree=DEGREE params_dir=PARAMS_DIR `make test-chunk-prove` is the main testing entry point for the multi-level circuit constraint system of scroll-zkevm. Developers could understand how the system works by reading the codes of this test. -Besides it, `make test-inner-prove` could be used to test the first-level circuit. +Besides it, `make test-inner-prove` could be used to test the first-level circuit, and `make-comp-prove` could be used to test two-layers compression circuits. ### Binaries diff --git a/batch.sh b/batch.sh index b3ebcd2dc..98484e022 100644 --- a/batch.sh +++ b/batch.sh @@ -1,23 +1,33 @@ set -x set -u -#set -e +set -e set -o pipefail +#export RUST_LOG=debug export RUST_LOG=trace +function simple_tests() { + for mode in sushi multiple #nft dao native empty # pack + #for mode in native empty # pack + do + MODE=$mode make mock 2>&1 | tee /tmp/mock_${mode}.log + done +} + function check_batch() { TRACE_VER="0317-alpha" for d in $(ls ~/zip-traces/${TRACE_VER}/traces); do - export TRACE_PATH=$(realpath ~/zip-traces/${TRACE_VER}/traces/${d}/traces-data) + export TRACE_PATH=$(realpath ~/zip-traces/${TRACE_VER}/traces/${d}/traces-data) make mock 2>&1 | tee /tmp/mock_${d}.log done } function check_block() { for t in prover/tests/extra_traces/tx_storage_proof.json prover/tests/extra_traces/hash_precompile_2.json prover/tests/extra_traces/hash_precompile_1.json prover/tests/traces/sushi/sushi_chef-withdraw.json prover/tests/traces/erc20/erc20_10_transfer.json; do - TRACE_PATH=`realpath $t` make mock 2>&1 | tee /tmp/mock_`basename $t`.log + TRACE_PATH=$(realpath $t) make mock 2>&1 | tee /tmp/mock_$(basename $t).log done } -check_block +simple_tests +#check_block #check_batch diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 568c0c48d..3c0982ae4 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bin" -version = "0.3.0" +version = "0.4.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/bin/src/prove.rs b/bin/src/prove.rs index 5b5cd2d7a..f5d32422b 100644 --- a/bin/src/prove.rs +++ b/bin/src/prove.rs @@ -1,8 +1,8 @@ use clap::Parser; use log::info; use prover::{ - utils::{get_block_trace_from_file, init_env_and_log, load_or_download_params}, - zkevm::{circuit::AGG_DEGREE, Prover}, + utils::{get_block_trace_from_file, init_env_and_log}, + zkevm::Prover, }; use std::{fs, path::PathBuf, time::Instant}; @@ -26,10 +26,7 @@ fn main() { std::env::set_var("VERIFY_CONFIG", "./prover/configs/verify_circuit.config"); let args = Args::parse(); - let agg_params = load_or_download_params(&args.params_path, *AGG_DEGREE) - .expect("failed to load or create params"); - - let mut prover = Prover::from_params(agg_params); + let mut prover = Prover::from_params_dir(&args.params_path); let mut traces = Vec::new(); let trace_path = PathBuf::from(&args.trace_path); diff --git a/bin/src/verify.rs b/bin/src/verify.rs index 78f6a0583..159879371 100644 --- a/bin/src/verify.rs +++ b/bin/src/verify.rs @@ -1,13 +1,6 @@ use clap::Parser; use log::info; -use prover::{ - utils::{init_env_and_log, load_or_download_params}, - zkevm::{ - circuit::{AGG_DEGREE, DEGREE}, - Verifier, - }, - Proof, -}; +use prover::{utils::init_env_and_log, zkevm::Verifier, Proof}; use std::{fs::File, io::Read, path::PathBuf}; #[derive(Parser, Debug)] @@ -26,13 +19,8 @@ fn main() { std::env::set_var("VERIFY_CONFIG", "./prover/configs/verify_circuit.config"); let args = Args::parse(); - let params = load_or_download_params(&args.params_path, *DEGREE) - .expect("failed to load or create params"); - let agg_params = load_or_download_params(&args.params_path, *AGG_DEGREE) - .expect("failed to load or create params"); - let agg_vk = read_from_file(&args.vk_path); - - let v = Verifier::from_params(params, agg_params, Some(agg_vk)); + let chunk_vk = read_from_file(&args.vk_path); + let v = Verifier::from_params_dir(&args.params_path, Some(chunk_vk)); let proof_path = PathBuf::from("proof_data").join("chunk_full_proof.json"); let proof_vec = read_from_file(&proof_path.to_string_lossy()); diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index b128d9f59..b8de7144a 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ffi" -version = "0.3.0" +version = "0.4.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/ffi/src/prove.rs b/ffi/src/prove.rs index 495740648..3f8a5819b 100644 --- a/ffi/src/prove.rs +++ b/ffi/src/prove.rs @@ -12,7 +12,7 @@ pub unsafe extern "C" fn init_prover(params_path: *const c_char, _seed_path: *co init_env_and_log("ffi_prove"); let params_path = c_char_to_str(params_path); - let p = zkevm::Prover::from_param_dir(params_path); + let p = zkevm::Prover::from_params_dir(params_path); PROVER.set(p).unwrap(); } diff --git a/ffi/src/verify.rs b/ffi/src/verify.rs index 83522f23c..30b3f149b 100644 --- a/ffi/src/verify.rs +++ b/ffi/src/verify.rs @@ -16,7 +16,7 @@ pub unsafe extern "C" fn init_verifier(params_path: *const c_char, agg_vk_path: let mut agg_vk = vec![]; f.read_to_end(&mut agg_vk).unwrap(); - let v = Box::new(zkevm::Verifier::from_fpath(params_path, Some(agg_vk))); + let v = Box::new(zkevm::Verifier::from_params_dir(params_path, Some(agg_vk))); VERIFIER = Some(Box::leak(v)) } diff --git a/prover/Cargo.toml b/prover/Cargo.toml index dd246692b..f05894a67 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -6,16 +6,17 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +aggregator = { git = "https://github.com/scroll-tech/zkevm-circuits.git", branch = "develop" } bus-mapping = { git = "https://github.com/scroll-tech/zkevm-circuits.git", branch = "develop" } eth-types = { git = "https://github.com/scroll-tech/zkevm-circuits.git", branch = "develop" } zkevm-circuits = { git = "https://github.com/scroll-tech/zkevm-circuits.git", branch = "develop", default-features = false, features = ["test","scroll","scroll-trace"] } mpt-zktrie = { git = "https://github.com/scroll-tech/zkevm-circuits.git", branch = "develop" } mock = { git = "https://github.com/scroll-tech/zkevm-circuits", branch = "develop" } -snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" } -snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" } +snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" } +snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" } anyhow = "1.0" blake2 = "0.10.3" @@ -31,7 +32,6 @@ log = "0.4" log4rs = { version = "1.2.0", default_features = false, features = ["console_appender", "file_appender"] } num-bigint = "0.4.3" once_cell = "1.8.0" -project-root = "0.2.2" rand = "0.8" rand_xorshift = "0.3" serde = "1.0" @@ -50,4 +50,3 @@ procfs = "0.13.0" default = [] # default = ["prove_verify"] prove_verify = [] - diff --git a/prover/configs/agg_layer1.config b/prover/configs/agg_layer1.config new file mode 100644 index 000000000..688ce5d6b --- /dev/null +++ b/prover/configs/agg_layer1.config @@ -0,0 +1,14 @@ +{ + "strategy": "Simple", + "degree": 25, + "num_advice": [ + 8 + ], + "num_lookup_advice": [ + 1 + ], + "num_fixed": 1, + "lookup_bits": 20, + "limb_bits": 88, + "num_limbs": 3 +} diff --git a/prover/configs/agg_layer2.config b/prover/configs/agg_layer2.config new file mode 100644 index 000000000..83e53fe41 --- /dev/null +++ b/prover/configs/agg_layer2.config @@ -0,0 +1,14 @@ +{ + "strategy": "Simple", + "degree": 25, + "num_advice": [ + 1 + ], + "num_lookup_advice": [ + 1 + ], + "num_fixed": 1, + "lookup_bits": 20, + "limb_bits": 88, + "num_limbs": 3 +} diff --git a/prover/configs/agg_layer3.config b/prover/configs/agg_layer3.config new file mode 100644 index 000000000..943f0555e --- /dev/null +++ b/prover/configs/agg_layer3.config @@ -0,0 +1,14 @@ +{ + "strategy": "Simple", + "degree": 25, + "num_advice": [ + 4 + ], + "num_lookup_advice": [ + 1 + ], + "num_fixed": 1, + "lookup_bits": 20, + "limb_bits": 88, + "num_limbs": 3 +} diff --git a/prover/configs/agg_layer4.config b/prover/configs/agg_layer4.config new file mode 100644 index 000000000..83e53fe41 --- /dev/null +++ b/prover/configs/agg_layer4.config @@ -0,0 +1,14 @@ +{ + "strategy": "Simple", + "degree": 25, + "num_advice": [ + 1 + ], + "num_lookup_advice": [ + 1 + ], + "num_fixed": 1, + "lookup_bits": 20, + "limb_bits": 88, + "num_limbs": 3 +} diff --git a/prover/src/aggregator.rs b/prover/src/aggregator.rs index 96e9e1846..ac0279ed5 100644 --- a/prover/src/aggregator.rs +++ b/prover/src/aggregator.rs @@ -1,2 +1,4 @@ -pub mod prover; -pub mod verifier; +mod prover; +mod verifier; + +pub use self::{prover::Prover, verifier::Verifier}; diff --git a/prover/src/aggregator/prover.rs b/prover/src/aggregator/prover.rs index 8b1378917..023e5c0f4 100644 --- a/prover/src/aggregator/prover.rs +++ b/prover/src/aggregator/prover.rs @@ -1 +1,66 @@ +use crate::utils::{load_params, param_path_for_degree}; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, G1Affine}, + plonk::ProvingKey, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, +}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; +mod chunk; +mod common; +mod compression; + +#[derive(Debug)] +pub struct Prover { + // degree -> params (use BTreeMap to find proper degree for params downsize) + params_map: BTreeMap>, + // Cached id -> pk + pk_map: HashMap>, +} + +impl Prover { + pub fn from_params(params_map: BTreeMap>) -> Self { + Self { + params_map, + pk_map: HashMap::new(), + } + } + + pub fn from_params_dir(params_dir: &str, degrees: &[u32]) -> Self { + let degrees = BTreeSet::from_iter(degrees); + let max_degree = **degrees.last().unwrap(); + + // Downsize params if any params of degree doesn't exist. + let mut params_map = BTreeMap::new(); + for d in BTreeSet::from_iter(degrees).into_iter().rev() { + let params = match load_params(params_dir, *d, None) { + Ok(params) => params, + Err(_) => { + let params: &ParamsKZG<_> = params_map + .first_key_value() + .unwrap_or_else(|| { + panic!( + "File `{}` must exist", + param_path_for_degree(params_dir, max_degree) + ) + }) + .1; + + let mut params: ParamsKZG<_> = params.clone(); + params.downsize(*d); + + log::warn!("Optimization: download params{d} to params dir",); + + params + } + }; + + params_map.insert(*d, params); + } + + Self { + params_map, + pk_map: HashMap::new(), + } + } +} diff --git a/prover/src/aggregator/prover/chunk.rs b/prover/src/aggregator/prover/chunk.rs new file mode 100644 index 000000000..cd7715700 --- /dev/null +++ b/prover/src/aggregator/prover/chunk.rs @@ -0,0 +1,31 @@ +use super::Prover; +use crate::{ + utils::{gen_rng, metric_of_witness_block}, + zkevm::circuit::TargetCircuit, +}; +use anyhow::Result; +use halo2_proofs::halo2curves::bn256::Fr; +use snark_verifier_sdk::{gen_snark_shplonk, Snark}; +use zkevm_circuits::evm_circuit::witness::Block; + +impl Prover { + pub fn gen_chunk_snark( + &mut self, + witness_block: &Block, + ) -> Result { + log::info!( + "Proving the chunk: {:?}", + metric_of_witness_block(witness_block) + ); + + let (circuit, _instance) = C::from_witness_block(witness_block)?; + log::info!("Create {} proof", C::name()); + + let (params, pk) = self.inner_params_and_pk::(&C::dummy_inner_circuit())?; + + // Generate the SNARK proof for inner circuit. + let snark = gen_snark_shplonk(params, pk, circuit, &mut gen_rng(), None::); + + Ok(snark) + } +} diff --git a/prover/src/aggregator/prover/common.rs b/prover/src/aggregator/prover/common.rs new file mode 100644 index 000000000..139a2ae85 --- /dev/null +++ b/prover/src/aggregator/prover/common.rs @@ -0,0 +1,106 @@ +use super::Prover; +use crate::{config::INNER_DEGREE, utils::tick, zkevm::circuit::TargetCircuit, Proof}; +use anyhow::Result; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::{keygen_pk2, Circuit, ProvingKey}, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, +}; +use rand::Rng; +use snark_verifier_sdk::{gen_evm_proof_shplonk, gen_pk, gen_snark_shplonk, CircuitExt, Snark}; + +impl Prover { + pub fn gen_snark>( + &mut self, + id: &str, + degree: u32, + rng: &mut (impl Rng + Send), + circuit: C, + ) -> Snark { + let (params, pk) = self.outer_params_and_pk(id, &circuit, degree); + + gen_snark_shplonk(params, pk, circuit, rng, None::<&str>) + } + + pub fn gen_evm_proof>( + &mut self, + id: &str, + degree: u32, + rng: &mut (impl Rng + Send), + circuit: C, + ) -> Result { + let (params, pk) = self.outer_params_and_pk(id, &circuit, degree); + + let instances = circuit.instances(); + let num_instance = circuit.num_instance(); + let proof = gen_evm_proof_shplonk(params, pk, circuit, instances.clone(), rng); + + Proof::new(pk, proof, &instances, Some(num_instance)) + } + + // TODO: test if it could use `outer_params_and_pk`. + pub fn inner_params_and_pk( + &mut self, + circuit: &::Inner, + ) -> Result<(&ParamsKZG, &ProvingKey)> { + let id = C::name(); + + // Reuse pk. + if !self.pk_map.contains_key(&id) { + tick(&format!("Before generate inner pk of {}", &id)); + let pk = keygen_pk2(self.params(*INNER_DEGREE), circuit)?; + tick(&format!("After generate inner pk of {}", &id)); + + self.pk_map.insert(id.clone(), pk); + } + assert!(self.params_map.contains_key(&*INNER_DEGREE)); + + Ok((&self.params_map[&*INNER_DEGREE], &self.pk_map[&id])) + } + + pub fn params(&mut self, degree: u32) -> &ParamsKZG { + if self.params_map.contains_key(°ree) { + return &self.params_map[°ree]; + } + + log::warn!("Optimization: download params{degree} to params dir"); + + tick(&format!("Before generate params of {degree}")); + let mut new_params = self + .params_map + .range(degree..) + .next() + .unwrap_or_else(|| panic!("Must have params of degree-{degree}")) + .1 + .clone(); + new_params.downsize(degree); + tick(&format!("After generate params of {degree}")); + + self.params_map.insert(degree, new_params); + &self.params_map[°ree] + } + + pub fn pk(&self, id: &str) -> Option<&ProvingKey> { + self.pk_map.get(id) + } + + pub fn outer_params_and_pk>( + &mut self, + id: &str, + circuit: &C, + degree: u32, + ) -> (&ParamsKZG, &ProvingKey) { + // Reuse pk. + if self.pk_map.contains_key(id) { + return (&self.params_map[°ree], &self.pk_map[id]); + } + + tick(&format!("Before generate outer pk of {}", &id)); + let pk = gen_pk(self.params(degree), circuit, None); + tick(&format!("After generate outer pk of {}", &id)); + + self.pk_map.insert(id.to_string(), pk); + + (&self.params_map[°ree], &self.pk_map[id]) + } +} diff --git a/prover/src/aggregator/prover/compression.rs b/prover/src/aggregator/prover/compression.rs new file mode 100644 index 000000000..868475634 --- /dev/null +++ b/prover/src/aggregator/prover/compression.rs @@ -0,0 +1,36 @@ +use super::Prover; +use crate::Proof; +use aggregator::CompressionCircuit; +use anyhow::{anyhow, Result}; +use rand::Rng; +use snark_verifier_sdk::Snark; + +impl Prover { + pub fn gen_comp_snark( + &mut self, + id: &str, + is_fresh: bool, + degree: u32, + mut rng: impl Rng + Send, + prev_snark: Snark, + ) -> Result { + let circuit = CompressionCircuit::new(self.params(degree), prev_snark, is_fresh, &mut rng) + .map_err(|err| anyhow!("Failed to construct compression circuit: {err:?}"))?; + + Ok(self.gen_snark(id, degree, &mut rng, circuit)) + } + + pub fn gen_comp_evm_proof( + &mut self, + id: &str, + is_fresh: bool, + degree: u32, + mut rng: impl Rng + Send, + prev_snark: Snark, + ) -> Result { + let circuit = CompressionCircuit::new(self.params(degree), prev_snark, is_fresh, &mut rng) + .map_err(|err| anyhow!("Failed to construct compression circuit: {err:?}"))?; + + self.gen_evm_proof(id, degree, &mut rng, circuit) + } +} diff --git a/prover/src/aggregator/verifier.rs b/prover/src/aggregator/verifier.rs index 8b1378917..34b522355 100644 --- a/prover/src/aggregator/verifier.rs +++ b/prover/src/aggregator/verifier.rs @@ -1 +1,74 @@ +use crate::{utils::load_params, Proof}; +use aggregator::CompressionCircuit; +use anyhow::Result; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::VerifyingKey, + poly::kzg::commitment::ParamsKZG, + SerdeFormat, +}; +use snark_verifier::pcs::kzg::{Bdfg21, Kzg}; +use snark_verifier_sdk::{evm_verify, gen_evm_verifier, verify_snark_shplonk, CircuitExt}; +use std::{io::Cursor, path::Path}; +#[derive(Debug)] +pub struct Verifier { + params: ParamsKZG, + vk: Option>, +} + +impl Verifier { + pub fn new(params: ParamsKZG, vk: Option>) -> Self { + Self { params, vk } + } + + pub fn from_params(params: ParamsKZG, raw_vk: Option>) -> Self { + let vk = raw_vk.as_ref().map(|k| { + VerifyingKey::::read::<_, CompressionCircuit>( + &mut Cursor::new(&k), + SerdeFormat::Processed, + ) + .unwrap() + }); + + Self { params, vk } + } + + pub fn from_params_dir(params_dir: &str, degree: u32, vk: Option>) -> Self { + let params = load_params(params_dir, degree, None).unwrap(); + + Self::from_params(params, vk) + } + + pub fn verify_agg_proof(&self, proof: Proof) -> Result { + let vk = match &self.vk { + Some(vk) => vk, + None => panic!("Aggregation verification key is missing"), + }; + + Ok(verify_snark_shplonk::( + &self.params, + proof.to_snark(), + vk, + )) + } + + // Should panic if failed to verify. + pub fn evm_verify>(&self, proof: &Proof, yul_file_path: Option<&Path>) { + let vk = match &self.vk { + Some(vk) => vk, + None => panic!("Aggregation verification key is missing"), + }; + + let num_instance = proof.num_instance().expect("Not a EVM proof").clone(); + + let deployment_code = gen_evm_verifier::>( + &self.params, + vk, + num_instance, + yul_file_path, + ); + + evm_verify(deployment_code, proof.instances(), proof.proof().to_vec()); + } +} diff --git a/prover/src/config.rs b/prover/src/config.rs new file mode 100644 index 000000000..2b26fbe7c --- /dev/null +++ b/prover/src/config.rs @@ -0,0 +1,22 @@ +use crate::utils::read_env_var; +use once_cell::sync::Lazy; +use std::collections::HashSet; + +pub static INNER_DEGREE: Lazy = Lazy::new(|| read_env_var("INNER_DEGREE", 20)); +pub static CHUNK_DEGREE: Lazy = Lazy::new(|| read_env_var("CHUNK_DEGREE", 25)); + +pub static AGG_LAYER1_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER1_DEGREE", 25)); +pub static AGG_LAYER2_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER2_DEGREE", 25)); +pub static AGG_LAYER3_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER3_DEGREE", 25)); +pub static AGG_LAYER4_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER4_DEGREE", 25)); + +pub static ALL_AGG_DEGREES: Lazy> = Lazy::new(|| { + Vec::from_iter(HashSet::from([ + *INNER_DEGREE, + *CHUNK_DEGREE, + *AGG_LAYER1_DEGREE, + *AGG_LAYER2_DEGREE, + *AGG_LAYER3_DEGREE, + *AGG_LAYER4_DEGREE, + ])) +}); diff --git a/prover/src/evm_verifier.rs b/prover/src/evm_verifier.rs index d93723f8a..b6be9b673 100644 --- a/prover/src/evm_verifier.rs +++ b/prover/src/evm_verifier.rs @@ -18,7 +18,7 @@ impl EvmVerifier { /// Verifies the proof with EVM byte code. Panics if verification fails. pub fn verify_proof(&self, proof: Proof) { - let instances = proof.deserialize_instance(); - evm_verify(self.bytecode.clone(), instances, proof.proof) + let instances = proof.instances(); + evm_verify(self.bytecode.clone(), instances, proof.proof().to_vec()) } } diff --git a/prover/src/io.rs b/prover/src/io.rs index 5c57ca214..f185e696c 100644 --- a/prover/src/io.rs +++ b/prover/src/io.rs @@ -1,19 +1,17 @@ use anyhow; -use num_bigint::BigUint; -use std::{ - fs::File, - io::{Cursor, Read, Write}, - path::{Path, PathBuf}, -}; - use halo2_proofs::{ - halo2curves::bn256::{Bn256, Fq, Fr, G1Affine}, + halo2curves::bn256::{Fq, Fr, G1Affine}, plonk::VerifyingKey, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, SerdeFormat, }; +use num_bigint::BigUint; use snark_verifier::util::arithmetic::PrimeField; use snark_verifier_sdk::Snark; +use std::{ + fs::File, + io::{Cursor, Read, Write}, + path::{Path, PathBuf}, +}; pub fn serialize_fr(f: &Fr) -> Vec { f.to_bytes().to_vec() @@ -84,46 +82,6 @@ pub fn write_file(folder: &mut PathBuf, filename: &str, buf: &[u8]) { fd.write_all(buf).unwrap(); } -pub fn load_target_circuit_params(folder: &mut PathBuf) -> Vec { - read_file(folder, "sample_circuit.params") -} - -pub fn load_target_circuit_vk(folder: &mut PathBuf) -> Vec { - read_file(folder, "sample_circuit.vkey") -} - -pub fn load_target_circuit_instance(folder: &mut PathBuf, index: usize) -> Vec { - read_file(folder, &format!("sample_circuit_instance{index}.data")) -} - -pub fn load_target_circuit_proof(folder: &mut PathBuf, index: usize) -> Vec { - read_file(folder, &format!("sample_circuit_proof{index}.data")) -} - -pub fn load_verify_circuit_params(folder: &mut PathBuf) -> Vec { - read_file(folder, "verify_circuit.params") -} - -pub fn load_verify_circuit_vk(folder: &mut PathBuf) -> Vec { - read_file(folder, "verify_circuit.vkey") -} - -pub fn load_verify_circuit_instance(folder: &mut PathBuf) -> Vec { - read_file(folder, "verify_circuit_instance.data") -} - -pub fn load_verify_circuit_proof(folder: &mut PathBuf) -> Vec { - read_file(folder, "verify_circuit_proof.data") -} - -pub fn write_verify_circuit_params(folder: &mut PathBuf, verify_circuit_params: &ParamsKZG) { - folder.push("verify_circuit.params"); - let mut fd = std::fs::File::create(folder.as_path()).unwrap(); - folder.pop(); - - verify_circuit_params.write(&mut fd).unwrap(); -} - pub fn serialize_vk(vk: &VerifyingKey) -> Vec { let mut result = Vec::::new(); vk.write(&mut result, SerdeFormat::Processed).unwrap(); @@ -177,29 +135,6 @@ pub fn serialize_verify_circuit_final_pair(pair: &(G1Affine, G1Affine, Vec)) result } -pub fn write_verify_circuit_final_pair(folder: &mut PathBuf, buf: &[u8]) { - folder.push("verify_circuit_final_pair.data"); - let mut fd = std::fs::File::create(folder.as_path()).unwrap(); - folder.pop(); - fd.write_all(buf).unwrap() -} - -pub fn write_verify_circuit_instance(folder: &mut PathBuf, buf: &[u8]) { - write_file(folder, "verify_circuit_instance.data", buf) -} - -pub fn write_verify_circuit_proof(folder: &mut PathBuf, buf: &[u8]) { - write_file(folder, "verify_circuit_proof.data", buf) -} - -pub fn write_verify_circuit_proof_be(folder: &mut PathBuf, buf: &[u8]) { - write_file(folder, "verify_circuit_proof_be.data", buf) -} - -pub fn write_verify_circuit_solidity(folder: &mut PathBuf, buf: &[u8]) { - write_file(folder, "verifier.sol", buf) -} - pub fn write_snark(file_path: &str, snark: &Snark) { let mut fd = std::fs::File::create(file_path).unwrap(); serde_json::to_writer_pretty(&mut fd, snark).unwrap() diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 3e7318416..7c1191499 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -1,4 +1,5 @@ pub mod aggregator; +pub mod config; mod evm_verifier; pub mod io; pub mod proof; diff --git a/prover/src/proof.rs b/prover/src/proof.rs index 85be42ff3..5ef39567f 100644 --- a/prover/src/proof.rs +++ b/prover/src/proof.rs @@ -3,6 +3,7 @@ use anyhow::Result; use halo2_proofs::{ halo2curves::bn256::{Fr, G1Affine}, plonk::ProvingKey, + SerdeFormat, }; use serde_derive::{Deserialize, Serialize}; use snark_verifier::{ @@ -19,52 +20,56 @@ use std::{ }; use types::base64; -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Debug, Default, Deserialize, Serialize)] pub struct Proof { #[serde(with = "base64")] - pub proof: Vec, + proof: Vec, #[serde(with = "base64")] - pub instance: Vec, + vk: Vec, #[serde(with = "base64")] - pub vk: Vec, + instances: Vec, + // Only for EVM proof. + num_instance: Option>, } impl Proof { - pub fn from_snark(pk: &ProvingKey, snark: &Snark) -> anyhow::Result { - // Serialize instances - let instances = serialize_fr_matrix(snark.instances.as_slice()); - let instance_bytes = serde_json::to_vec(&instances)?; - - // Serialize vk - let vk_bytes = serialize_vk(pk.get_vk()); + pub fn new( + pk: &ProvingKey, + proof: Vec, + instances: &[Vec], + num_instance: Option>, + ) -> Result { + let vk = serialize_vk(pk.get_vk()); + let instances = serde_json::to_vec(&serialize_fr_matrix(instances))?; - Ok(Proof { - proof: snark.proof.clone(), - instance: instance_bytes, - vk: vk_bytes, + Ok(Self { + proof, + vk, + instances, + num_instance, }) } - pub fn to_snark(&self) -> Snark { - let instances = self.deserialize_instance(); - Snark { - protocol: dummy_protocol(), - instances, - proof: self.proof.clone(), + pub fn from_json_file(file_path: &str) -> Result> { + if !Path::new(file_path).exists() { + return Ok(None); } - } - pub fn deserialize_instance(&self) -> Vec> { - let l3_buf: Vec>> = serde_json::from_reader(self.instance.as_slice()).unwrap(); - deserialize_fr_matrix(l3_buf) + let fd = File::open(file_path)?; + let mut deserializer = serde_json::Deserializer::from_reader(fd); + deserializer.disable_recursion_limit(); + let deserializer = serde_stacker::Deserializer::new(&mut deserializer); + let proof = serde::Deserialize::deserialize(deserializer)?; + + Ok(Some(proof)) } pub fn dump(&self, dir: &mut PathBuf, name: &str) -> Result<()> { - write_file(dir, &format!("{name}_instance.data"), &self.instance); write_file(dir, &format!("{name}_proof.data"), &self.proof); - write_file(dir, &format!("{name}.vkey"), &self.proof); + write_file(dir, &format!("{name}.vkey"), &self.vk); + write_file(dir, &format!("{name}_instances.data"), &self.instances); - dir.push("{}_full_proof.json"); + dir.push(format!("{name}_full_proof.json")); let mut fd = std::fs::File::create(dir.as_path())?; dir.pop(); serde_json::to_writer_pretty(&mut fd, &self)?; @@ -72,17 +77,41 @@ impl Proof { Ok(()) } - pub fn load_from_json(file_path: &str) -> Result> { - if !Path::new(file_path).exists() { - return Ok(None); + pub fn from_snark(pk: &ProvingKey, snark: &Snark) -> Result { + let mut vk = Vec::::new(); + pk.get_vk().write(&mut vk, SerdeFormat::Processed)?; + + let instances = serialize_fr_matrix(snark.instances.as_slice()); + let instances = serde_json::to_vec(&instances)?; + + Ok(Proof { + proof: snark.proof.clone(), + vk, + instances, + num_instance: None, + }) + } + + pub fn to_snark(&self) -> Snark { + Snark { + protocol: dummy_protocol(), + proof: self.proof.clone(), + instances: self.instances(), } + } - let fd = File::open(file_path)?; - let mut deserializer = serde_json::Deserializer::from_reader(fd); - deserializer.disable_recursion_limit(); - let deserializer = serde_stacker::Deserializer::new(&mut deserializer); - let proof = serde::Deserialize::deserialize(deserializer)?; - Ok(Some(proof)) + pub fn proof(&self) -> &[u8] { + &self.proof + } + + pub fn instances(&self) -> Vec> { + let buf: Vec>> = serde_json::from_reader(self.instances.as_slice()).unwrap(); + + deserialize_fr_matrix(buf) + } + + pub fn num_instance(&self) -> Option<&Vec> { + self.num_instance.as_ref() } } diff --git a/prover/src/test_util.rs b/prover/src/test_util.rs index 5420caf11..ec9c9f020 100644 --- a/prover/src/test_util.rs +++ b/prover/src/test_util.rs @@ -2,13 +2,14 @@ use crate::utils::{get_block_trace_from_file, read_env_var}; use glob::glob; use types::eth::BlockTrace; +pub mod aggregator; pub mod mock_plonk; pub const PARAMS_DIR: &str = "./test_params"; pub fn parse_trace_path_from_mode(mode: &str) -> &'static str { let trace_path = match mode { - "empty" => "./tests/traces/empty.json", + "empty" => "./tests/traces/bridge/01.json", "greeter" => "./tests/traces/greeter/setValue.json", "single" => "./tests/traces/erc20/1_transfer.json", "multiple" => "./tests/traces/erc20/10_transfer.json", @@ -28,7 +29,7 @@ pub fn load_block_traces_for_test() -> (Vec, Vec) { // use mode let mode = read_env_var("MODE", "multiple".to_string()); if mode.to_lowercase() == "batch" || mode.to_lowercase() == "pack" { - (1..=22) + (1..=20) .map(|i| format!("tests/traces/bridge/{i:02}.json")) .collect() } else { diff --git a/prover/src/test_util/aggregator.rs b/prover/src/test_util/aggregator.rs new file mode 100644 index 000000000..8f58b7588 --- /dev/null +++ b/prover/src/test_util/aggregator.rs @@ -0,0 +1,70 @@ +use crate::{ + aggregator::Prover, + io::{load_snark, write_snark}, + utils::gen_rng, + zkevm::circuit::SuperCircuit, + Proof, +}; +use halo2_proofs::halo2curves::bn256::Fr; +use snark_verifier_sdk::Snark; +use std::{env::set_var, path::PathBuf}; +use zkevm_circuits::evm_circuit::witness::Block; + +pub fn gen_comp_evm_proof( + output_dir: &str, + id: &str, + is_fresh: bool, + degree: u32, + prover: &mut Prover, + prev_snark: Snark, +) -> Proof { + set_var("COMPRESSION_CONFIG", format!("./configs/{id}.config")); + + let rng = gen_rng(); + let proof = prover + .gen_comp_evm_proof(id, is_fresh, degree, rng, prev_snark) + .unwrap(); + proof.dump(&mut PathBuf::from(output_dir), id).unwrap(); + + proof +} + +pub fn load_or_gen_chunk_snark( + output_dir: &str, + id: &str, + prover: &mut Prover, + witness_block: Block, +) -> Snark { + let file_path = format!("{output_dir}/{id}_chunk_snark.json"); + + load_snark(&file_path).unwrap().unwrap_or_else(|| { + let snark = prover + .gen_chunk_snark::(&witness_block) + .unwrap(); + write_snark(&file_path, &snark); + + snark + }) +} + +pub fn load_or_gen_comp_snark( + output_dir: &str, + id: &str, + is_fresh: bool, + degree: u32, + prover: &mut Prover, + prev_snark: Snark, +) -> Snark { + set_var("COMPRESSION_CONFIG", format!("./configs/{id}.config")); + let file_path = format!("{output_dir}/{id}_snark.json"); + + load_snark(&file_path).unwrap().unwrap_or_else(|| { + let rng = gen_rng(); + let snark = prover + .gen_comp_snark(id, is_fresh, degree, rng, prev_snark) + .unwrap(); + write_snark(&file_path, &snark); + + snark + }) +} diff --git a/prover/src/utils.rs b/prover/src/utils.rs index 0cc087832..e9917b7cc 100644 --- a/prover/src/utils.rs +++ b/prover/src/utils.rs @@ -1,4 +1,5 @@ -use anyhow::Result; +use crate::zkevm::circuit::{block_traces_to_witness_block, check_batch_capacity}; +use anyhow::{bail, Result}; use chrono::Utc; use git_version::git_version; use halo2_proofs::{ @@ -14,66 +15,38 @@ use log4rs::{ }, config::{Appender, Config, Root}, }; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; use std::{ fs::{self, metadata, File}, io::{BufReader, Read}, path::{Path, PathBuf}, - process::{Command, Stdio}, str::FromStr, sync::Once, }; use types::eth::{BlockTrace, BlockTraceJsonRpcResult}; -use zkevm_circuits::witness; +use zkevm_circuits::evm_circuit::witness::Block; pub const DEFAULT_SERDE_FORMAT: SerdeFormat = SerdeFormat::RawBytesUnchecked; pub const GIT_VERSION: &str = git_version!(); pub static LOGGER: Once = Once::new(); -/// Get setup params by reading from a file or downloading a new one. -pub fn load_or_download_params(params_dir: &str, degree: usize) -> Result> { - match metadata(params_dir) { - Ok(md) => { - if md.is_file() { - panic!("{params_dir} should be folder"); - } - } - Err(_) => { - // Not exist - fs::create_dir_all(params_dir)?; - } - }; - - let params_path = param_path_for_degree(params_dir, degree); - log::info!("load_or_download_params {}", params_path); - - if Path::new(¶ms_path).exists() { - match load_params(¶ms_path, degree, DEFAULT_SERDE_FORMAT) { - Ok(r) => return Ok(r), - Err(e) => { - log::error!( - "An error occurred when loading setup params: {}. Re-downloading ...", - e - ) - } - } - } - - download_params(params_dir, degree) -} - /// Load setup params from a file. pub fn load_params( params_dir: &str, - degree: usize, - serde_format: SerdeFormat, + degree: u32, + serde_fmt: Option, ) -> Result> { - log::info!("start loading params with degree {}", degree); + log::info!("Start loading params with degree {}", degree); let params_path = if metadata(params_dir)?.is_dir() { // auto load param_path_for_degree(params_dir, degree) } else { params_dir.to_string() }; + if !Path::new(¶ms_path).exists() { + bail!("Need to download params by `make download-setup -e degree={degree}`"); + } let f = File::open(params_path)?; // check params file length: @@ -85,7 +58,9 @@ pub fn load_params( let file_size = f.metadata()?.len(); let g1_num = 2 * (1 << degree); let g2_num = 2; - let g1_bytes_len = match serde_format { + + let serde_fmt = serde_fmt.unwrap_or(DEFAULT_SERDE_FORMAT); + let g1_bytes_len = match serde_fmt { SerdeFormat::Processed => 32, SerdeFormat::RawBytes | SerdeFormat::RawBytesUnchecked => 64, }; @@ -95,7 +70,7 @@ pub fn load_params( return Err(anyhow::format_err!("invalid params file len {} for degree {}. check DEGREE or remove the invalid params file", file_size, degree)); } - let p = ParamsKZG::::read_custom::<_>(&mut BufReader::new(f), serde_format)?; + let p = ParamsKZG::::read_custom::<_>(&mut BufReader::new(f), serde_fmt)?; log::info!("load params successfully!"); Ok(p) } @@ -134,7 +109,7 @@ pub struct BatchMetric { pub num_step: usize, } -pub fn metric_of_witness_block(block: &witness::Block) -> BatchMetric { +pub fn metric_of_witness_block(block: &Block) -> BatchMetric { BatchMetric { num_block: block.context.ctxs.len(), num_tx: block.txs.len(), @@ -142,6 +117,17 @@ pub fn metric_of_witness_block(block: &witness::Block) -> BatchMetric { } } +pub fn chunk_trace_to_witness_block(mut chunk_trace: Vec) -> Result> { + if chunk_trace.is_empty() { + bail!("Empty chunk trace"); + } + + // Check if the trace exceeds the circuit capacity. + check_batch_capacity(&mut chunk_trace)?; + + block_traces_to_witness_block(&chunk_trace) +} + // Return the output dir. pub fn init_env_and_log(id: &str) -> String { dotenv::dotenv().ok(); @@ -197,35 +183,26 @@ fn create_output_dir(id: &str) -> String { output } -// Download setup params and write it into a file. -fn download_params(params_dir: &str, degree: usize) -> Result> { - log::warn!("Would be better to run `make download-setup` before any bins or tests"); - - log::info!("Start to download setup params"); - - let download_script_path = project_root::get_project_root()?.join("download_setup.sh"); - - Command::new("sh") - .stdout(Stdio::null()) - .args([ - download_script_path.to_string_lossy().as_ref(), - °ree.to_string(), - params_dir, - ]) - .status() - .unwrap_or_else(|e| { - panic!("Failed to download setup params with {degree} and {params_dir}: {e}") - }); - - log::info!("Finish downloading setup params"); - - load_params( - ¶m_path_for_degree(params_dir, degree), - degree, - DEFAULT_SERDE_FORMAT, - ) +pub fn param_path_for_degree(params_dir: &str, degree: u32) -> String { + format!("{params_dir}/params{degree}") +} + +pub fn gen_rng() -> impl Rng + Send { + let seed = [0u8; 16]; + XorShiftRng::from_seed(seed) } -fn param_path_for_degree(params_dir: &str, degree: usize) -> String { - format!("{params_dir}/params{degree}") +pub fn tick(desc: &str) { + #[cfg(target_os = "linux")] + let memory = match procfs::Meminfo::new() { + Ok(m) => m.mem_total - m.mem_free, + Err(_) => 0, + }; + #[cfg(not(target_os = "linux"))] + let memory = 0; + log::debug!( + "memory usage when {}: {:?}GB", + desc, + memory / 1024 / 1024 / 1024 + ); } diff --git a/prover/src/zkevm/capacity_checker.rs b/prover/src/zkevm/capacity_checker.rs index 1d2edc0e3..7f9fc2503 100644 --- a/prover/src/zkevm/capacity_checker.rs +++ b/prover/src/zkevm/capacity_checker.rs @@ -1,13 +1,13 @@ +use super::circuit::{ + block_traces_to_witness_block_with_updated_state, calculate_row_usage_of_witness_block, + update_state, SUB_CIRCUIT_NAMES, +}; +use crate::config::INNER_DEGREE; use itertools::Itertools; use mpt_zktrie::state::ZktrieState; use serde_derive::{Deserialize, Serialize}; use types::eth::BlockTrace; -use super::circuit::{ - block_traces_to_witness_block_with_updated_state, calculate_row_usage_of_witness_block, - update_state, DEGREE, SUB_CIRCUIT_NAMES, -}; - #[derive(Debug, Clone, Deserialize, Serialize)] pub struct RowUsage { pub is_ok: bool, @@ -34,7 +34,7 @@ impl RowUsage { Self { row_usage_details, row_number, - is_ok: row_number < (1 << *DEGREE) - 256, + is_ok: row_number < (1 << *INNER_DEGREE) - 256, } } pub fn add(&mut self, other: &RowUsage) { @@ -53,7 +53,7 @@ impl RowUsage { .map(|(_name, n)| n) .max() .unwrap(); - self.is_ok = self.row_number < (1 << *DEGREE) - 256; + self.is_ok = self.row_number < (1 << *INNER_DEGREE) - 256; } } diff --git a/prover/src/zkevm/circuit.rs b/prover/src/zkevm/circuit.rs index 6041a194e..5485a1685 100644 --- a/prover/src/zkevm/circuit.rs +++ b/prover/src/zkevm/circuit.rs @@ -27,7 +27,6 @@ const MAX_EXP_STEPS: usize = 10_000; */ ////// params for degree = 20 //////////// -pub static DEGREE: Lazy = Lazy::new(|| read_env_var("DEGREE", 20)); const MAX_TXS: usize = 32; const MAX_INNER_BLOCKS: usize = 100; const MAX_EXP_STEPS: usize = 10_000; @@ -37,9 +36,8 @@ const MAX_MPT_ROWS: usize = 400_000; const MAX_KECCAK_ROWS: usize = 524_000; const MAX_RWS: usize = 1_000_000; -pub static CHAIN_ID: Lazy = Lazy::new(|| read_env_var("CHAIN_ID", 0x82751)); -pub static AGG_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_DEGREE", 25)); -pub static AUTO_TRUNCATE: Lazy = Lazy::new(|| read_env_var("AUTO_TRUNCATE", true)); +static CHAIN_ID: Lazy = Lazy::new(|| read_env_var("CHAIN_ID", 0x82751)); +static AUTO_TRUNCATE: Lazy = Lazy::new(|| read_env_var("AUTO_TRUNCATE", true)); /// A target circuit trait is a wrapper of inner circuit, with convenient APIs for building /// circuits from traces. diff --git a/prover/src/zkevm/circuit/builder.rs b/prover/src/zkevm/circuit/builder.rs index 705e7b3a8..df300bf11 100644 --- a/prover/src/zkevm/circuit/builder.rs +++ b/prover/src/zkevm/circuit/builder.rs @@ -1,13 +1,14 @@ use super::{ - TargetCircuit, AUTO_TRUNCATE, CHAIN_ID, DEGREE, MAX_BYTECODE, MAX_CALLDATA, MAX_EXP_STEPS, + TargetCircuit, AUTO_TRUNCATE, CHAIN_ID, MAX_BYTECODE, MAX_CALLDATA, MAX_EXP_STEPS, MAX_INNER_BLOCKS, MAX_KECCAK_ROWS, MAX_MPT_ROWS, MAX_RWS, MAX_TXS, }; -use anyhow::bail; +use crate::config::INNER_DEGREE; +use anyhow::{bail, Result}; use bus_mapping::{ circuit_input_builder::{self, BlockHead, CircuitInputBuilder, CircuitsParams}, state_db::{Account, CodeDB, StateDB}, }; -use eth_types::{evm_types::OpcodeId, ToAddress}; +use eth_types::{evm_types::opcode_ids::OpcodeId, ToAddress}; use ethers_core::types::{Bytes, U256}; use halo2_proofs::halo2curves::bn256::Fr; use is_even::IsEven; @@ -25,14 +26,12 @@ pub const SUB_CIRCUIT_NAMES: [&str; 11] = [ ]; // TODO: optimize it later -pub fn calculate_row_usage_of_trace(block_trace: &BlockTrace) -> Result, anyhow::Error> { +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, anyhow::Error> { +pub fn calculate_row_usage_of_witness_block(witness_block: &Block) -> Result> { let rows = ::Inner::min_num_rows_block_subcircuits( witness_block, ) @@ -54,7 +53,7 @@ pub fn calculate_row_usage_of_witness_block( // FIXME: we need better API name for this. // This function also mutates the block trace. -pub fn check_batch_capacity(block_traces: &mut Vec) -> Result<(), anyhow::Error> { +pub fn check_batch_capacity(block_traces: &mut Vec) -> Result<()> { let block_traces_len = block_traces.len(); let total_tx_count = block_traces .iter() @@ -104,7 +103,7 @@ pub fn check_batch_capacity(block_traces: &mut Vec) -> Result<(), an rows, rows_and_names ); - if *rows >= (1 << *DEGREE) - 256 { + if *rows >= (1 << *INNER_DEGREE) - 256 { log::warn!("truncate blocks [{}..{})", idx, block_traces_len); truncate_idx = idx; break; @@ -127,9 +126,10 @@ pub fn update_state( zktrie_state: &mut ZktrieState, block_traces: &[BlockTrace], light_mode: bool, -) -> Result<(), anyhow::Error> { +) -> Result<()> { log::debug!("building partial statedb"); let account_proofs = block_traces.iter().rev().flat_map(|block| { + log::trace!("account proof for block {:?}:", block.header.number); block.storage_trace.proofs.iter().flat_map(|kv_map| { kv_map .iter() @@ -137,6 +137,7 @@ pub fn update_state( }) }); let storage_proofs = block_traces.iter().rev().flat_map(|block| { + log::trace!("storage proof for block {:?}:", block.header.number); block .storage_trace .storage_proofs @@ -148,6 +149,8 @@ pub fn update_state( }) }); let additional_proofs = block_traces.iter().rev().flat_map(|block| { + log::trace!("storage proof for block {:?}:", block.header.number); + log::trace!("additional proof for block {:?}:", block.header.number); block .storage_trace .deletion_proofs @@ -166,9 +169,11 @@ pub fn update_state( Ok(()) } -pub fn block_traces_to_witness_block( - block_traces: &[BlockTrace], -) -> Result, anyhow::Error> { +pub fn block_traces_to_witness_block(block_traces: &[BlockTrace]) -> Result> { + log::debug!( + "block_traces_to_witness_block, input len {:?}", + block_traces.len() + ); let old_root = if block_traces.is_empty() { eth_types::Hash::zero() } else { @@ -183,16 +188,16 @@ pub fn block_traces_to_witness_block_with_updated_state( block_traces: &[BlockTrace], zktrie_state: &mut ZktrieState, light_mode: bool, // light_mode used in row estimation -) -> Result, anyhow::Error> { +) -> Result> { let chain_ids = block_traces .iter() .map(|block_trace| block_trace.chain_id) - .collect::>(); + .collect::>(); let chain_id = if !chain_ids.is_empty() { chain_ids[0] } else { - (*CHAIN_ID).into() + *CHAIN_ID }; let mut state_db: StateDB = zktrie_state.state().clone(); @@ -217,7 +222,7 @@ pub fn block_traces_to_witness_block_with_updated_state( max_rlp_rows: MAX_CALLDATA, }; let mut builder_block = circuit_input_builder::Block::from_headers(&[], circuit_params); - builder_block.chain_id = chain_id.as_u64(); + builder_block.chain_id = chain_id; builder_block.prev_state_root = U256::from(zktrie_state.root()); let mut builder = CircuitInputBuilder::new(state_db.clone(), code_db, &builder_block); for (idx, block_trace) in block_traces.iter().enumerate() { @@ -229,7 +234,7 @@ pub fn block_traces_to_witness_block_with_updated_state( geth_trace.push(result.into()); } // TODO: Get the history_hashes. - let mut header = BlockHead::new(chain_id.as_u64(), Vec::new(), ð_block)?; + let mut header = BlockHead::new(chain_id, Vec::new(), ð_block)?; // override zeroed minder field with additional "coinbase" field in blocktrace if let Some(address) = block_trace.coinbase.address { header.coinbase = address; @@ -271,14 +276,16 @@ pub fn block_traces_to_witness_block_with_updated_state( ); if !light_mode && !block_traces.is_empty() { + log::debug!("block_apply_mpt_state"); block_apply_mpt_state(&mut witness_block, zktrie_state); + log::debug!("block_apply_mpt_state done"); } zktrie_state.set_state(builder.sdb.clone()); log::debug!("finish replay trie updates"); Ok(witness_block) } -pub fn decode_bytecode(bytecode: &str) -> Result, anyhow::Error> { +pub fn decode_bytecode(bytecode: &str) -> Result> { let mut stripped = if let Some(stripped) = bytecode.strip_prefix("0x") { stripped.to_string() } else { @@ -370,7 +377,7 @@ fn code_hashing() { /* fn get_account_deployed_codehash( execution_result: &ExecutionResult, -) -> Result { +) -> Result { let created_acc = execution_result .account_created .as_ref() @@ -385,7 +392,7 @@ fn get_account_deployed_codehash( } Err(anyhow!("can not find created address in account after")) } -fn get_account_created_codehash(step: &ExecStep) -> Result { +fn get_account_created_codehash(step: &ExecStep) -> Result { let extra_data = step .extra_data .as_ref() @@ -415,8 +422,9 @@ fn trace_code(cdb: &mut CodeDB, step: &ExecStep, sdb: &StateDB, code: Bytes, sta return; }; - log::debug!("trace code {:?}", addr); - let _hash = cdb.0.insert(data.code_hash, code.to_vec()); + let code = code.to_vec(); + log::debug!("trace code {:?}, size {}", addr, code.len()); + let _hash = cdb.0.insert(data.code_hash, code); log::debug!("trace code done {:?}", addr); // sanity check //assert_eq!( @@ -424,7 +432,7 @@ fn trace_code(cdb: &mut CodeDB, step: &ExecStep, sdb: &StateDB, code: Bytes, sta // "invalid codehash for existed account {addr:?}, {data:?}" //); } -pub fn build_codedb(sdb: &StateDB, blocks: &[BlockTrace]) -> Result { +pub fn build_codedb(sdb: &StateDB, blocks: &[BlockTrace]) -> Result { let mut cdb = CodeDB::new(); log::debug!("building codedb"); diff --git a/prover/src/zkevm/circuit/super_circuit.rs b/prover/src/zkevm/circuit/super_circuit.rs index ef0a4a728..74efa0485 100644 --- a/prover/src/zkevm/circuit/super_circuit.rs +++ b/prover/src/zkevm/circuit/super_circuit.rs @@ -1,6 +1,5 @@ -use super::{TargetCircuit, DEGREE}; - -use super::{MAX_CALLDATA, MAX_INNER_BLOCKS, MAX_TXS}; +use super::{TargetCircuit, MAX_CALLDATA, MAX_INNER_BLOCKS, MAX_TXS}; +use crate::config::INNER_DEGREE; use anyhow::bail; use halo2_proofs::halo2curves::bn256::Fr; use zkevm_circuits::{super_circuit::SuperCircuit as SuperCircuitTpl, util::SubCircuit, witness}; @@ -23,10 +22,10 @@ impl TargetCircuit for SuperCircuit { Self: Sized, { let (k, inner, instance) = Self::Inner::build_from_witness_block(witness_block.clone())?; - if k as usize > *DEGREE { + if k > *INNER_DEGREE { bail!( - "circuit not enough: DEGREE = {}, less than k needed: {}", - *DEGREE, + "circuit not enough: INNER_DEGREE = {}, less than k needed: {}", + *INNER_DEGREE, k ); } diff --git a/prover/src/zkevm/prover.rs b/prover/src/zkevm/prover.rs index dd309dd27..d0ac82e7a 100644 --- a/prover/src/zkevm/prover.rs +++ b/prover/src/zkevm/prover.rs @@ -1,4 +1,16 @@ -use anyhow::bail; +use super::circuit::{ + block_traces_to_witness_block, check_batch_capacity, SuperCircuit, TargetCircuit, +}; +use crate::{ + config::{CHUNK_DEGREE, INNER_DEGREE}, + utils::{load_params, metric_of_witness_block, read_env_var, tick}, + Proof, +}; +use anyhow::{bail, Result}; +use halo2_proofs::poly::{ + commitment::{Params, ParamsProver}, + kzg::commitment::ParamsVerifierKZG, +}; use log::info; use once_cell::sync::Lazy; use rand::SeedableRng; @@ -6,15 +18,6 @@ use rand_xorshift::XorShiftRng; use std::collections::HashMap; use types::eth::BlockTrace; -use super::circuit::{ - block_traces_to_witness_block, check_batch_capacity, SuperCircuit, TargetCircuit, DEGREE, -}; -use crate::{ - io::{serialize_fr_matrix, serialize_vk}, - proof::Proof, - utils::{metric_of_witness_block, read_env_var}, -}; - use halo2_proofs::{ dev::MockProver, halo2curves::bn256::{Bn256, Fr, G1Affine}, @@ -27,7 +30,6 @@ use snark_verifier_sdk::{ mod evm; mod mock; -mod util; #[cfg(target_os = "linux")] extern crate procfs; @@ -40,46 +42,85 @@ pub static MOCK_PROVE: Lazy = Lazy::new(|| read_env_var("MOCK_PROVE", fals // This is the aggregation prover that takes in a list of traces, produces // a proof that can be verified on chain. pub struct Prover { - pub zkevm_params: ParamsKZG, - pub agg_params: ParamsKZG, + pub inner_params: ParamsKZG, + pub chunk_params: ParamsKZG, /// We may have a list of public keys for different inner circuits. /// Those keys are stored as a hash map, and keyed by a `name` String. - pub target_circuit_pks: HashMap>, - pub agg_pk: Option>, + pub inner_pks: HashMap>, + pub chunk_pk: Option>, } impl Prover { - // Build a new Prover from parameters. - pub fn new(zkevm_params: ParamsKZG, agg_params: ParamsKZG) -> Self { + pub fn from_params(inner_params: ParamsKZG, chunk_params: ParamsKZG) -> Self { + assert!(inner_params.k() == *INNER_DEGREE); + assert!(chunk_params.k() == *CHUNK_DEGREE); + + // notice that `inner_k < chunk`_k which is not necessary the case in practice + log::info!( + "loaded parameters for degrees {} and {}", + *INNER_DEGREE, + *CHUNK_DEGREE + ); + + // this check can be skipped since the `params` is downsized? + { + let target_params_verifier: &ParamsVerifierKZG = inner_params.verifier_params(); + let agg_params_verifier: &ParamsVerifierKZG = chunk_params.verifier_params(); + log::info!( + "params g2 {:?} s_g2 {:?}", + target_params_verifier.g2(), + target_params_verifier.s_g2() + ); + debug_assert_eq!(target_params_verifier.s_g2(), agg_params_verifier.s_g2()); + debug_assert_eq!(target_params_verifier.g2(), agg_params_verifier.g2()); + } + Self { - zkevm_params, - agg_params, - target_circuit_pks: Default::default(), - agg_pk: None, + inner_params, + chunk_params, + inner_pks: Default::default(), + chunk_pk: None, } } + pub fn from_params_dir(params_dir: &str) -> Self { + let chunk_params = load_params(params_dir, *CHUNK_DEGREE, None).unwrap(); + let inner_params = load_params(params_dir, *INNER_DEGREE, None).unwrap_or_else(|_| { + assert!(*CHUNK_DEGREE >= *INNER_DEGREE); + log::warn!( + "Optimization: download params{} to params dir", + *INNER_DEGREE + ); + + let mut new_params = chunk_params.clone(); + new_params.downsize(*INNER_DEGREE); + new_params + }); + + Self::from_params(inner_params, chunk_params) + } + // Generate the chunk proof given the chunk trace using Poseidon hash for challenges. // The returned proof is expected to be verified by only rust verifier not solidity verifier. - pub fn gen_chunk_proof(&mut self, chunk_trace: &[BlockTrace]) -> anyhow::Result { - let inner_proof = self.gen_inner_proof::(chunk_trace)?; - // compress the inner proof using the aggregation proof - self.gen_agg_proof(vec![inner_proof]) + pub fn gen_chunk_proof(&mut self, chunk_trace: &[BlockTrace]) -> Result { + let inner_snark = self.gen_inner_snark::(chunk_trace)?; + // Compress the inner snark using the aggregation proof. + self.gen_agg_proof(vec![inner_snark]) } // Generate the chunk proof given the chunk trace using Keccak hash for challenges. // The returned proof can be efficiently verified by solidity verifier. - pub fn gen_chunk_evm_proof(&mut self, chunk_trace: &[BlockTrace]) -> anyhow::Result { - let inner_proof = self.gen_inner_proof::(chunk_trace)?; - // compress the inner proof using the aggregation proof - self.gen_agg_evm_proof(vec![inner_proof]) + pub fn gen_chunk_evm_proof(&mut self, chunk_trace: &[BlockTrace]) -> Result { + let inner_snark = self.gen_inner_snark::(chunk_trace)?; + // Compress the inner snark using the aggregation proof. + self.gen_agg_evm_proof(vec![inner_snark]) } - // Generate the proof of the inner circuit - pub fn gen_inner_proof( + // Generate the snark of the inner circuit + pub fn gen_inner_snark( &mut self, chunk_trace: &[BlockTrace], - ) -> anyhow::Result { + ) -> Result { if chunk_trace.is_empty() { bail!("Empty chunk trace"); } @@ -113,7 +154,7 @@ impl Prover { if *MOCK_PROVE { log::info!("mock prove {} start", C::name()); - let prover = MockProver::::run(*DEGREE as u32, &circuit, instance)?; + let prover = MockProver::::run(*INNER_DEGREE, &circuit, instance)?; if let Err(errs) = prover.verify_par() { log::error!("err num: {}", errs.len()); for err in &errs { @@ -124,74 +165,72 @@ impl Prover { log::info!("mock prove {} done", C::name()); } - if !self.target_circuit_pks.contains_key(&C::name()) { + if !self.inner_pks.contains_key(&C::name()) { self.gen_inner_pk::(&C::dummy_inner_circuit()); } - let pk = &self.target_circuit_pks[&C::name()]; + let pk = &self.inner_pks[&C::name()]; // Generate the SNARK proof for the inner circuit let snark_proof = - gen_snark_shplonk(&self.zkevm_params, pk, circuit, &mut rng, None::); + gen_snark_shplonk(&self.inner_params, pk, circuit, &mut rng, None::); Ok(snark_proof) } // Generate the aggregation proof given the proofs of inner circuit - pub fn gen_agg_proof(&mut self, snarks: Vec) -> anyhow::Result { + pub fn gen_agg_proof(&mut self, snarks: Vec) -> Result { // build the aggregation circuit inputs from the inner circuit outputs let seed = [0u8; 16]; let mut rng = XorShiftRng::from_seed(seed); - let agg_circuit = AggregationCircuit::new(&self.agg_params, snarks, &mut rng); - let agg_pk = self - .agg_pk - .get_or_insert_with(|| gen_pk(&self.agg_params, &agg_circuit, None)); + let agg_circuit = AggregationCircuit::new(&self.chunk_params, snarks, &mut rng); + let chunk_pk = self + .chunk_pk + .get_or_insert_with(|| gen_pk(&self.chunk_params, &agg_circuit, None)); let agg_proof = gen_snark_shplonk( - &self.agg_params, - agg_pk, + &self.chunk_params, + chunk_pk, agg_circuit, &mut rng, None::, ); - Proof::from_snark(agg_pk, &agg_proof) + Proof::from_snark(chunk_pk, &agg_proof) } // Generate the aggregation evm proof given the proofs of inner circuit - pub fn gen_agg_evm_proof(&mut self, snarks: Vec) -> anyhow::Result { + pub fn gen_agg_evm_proof(&mut self, snarks: Vec) -> Result { // build the aggregation circuit inputs from the inner circuit outputs let seed = [0u8; 16]; let mut rng = XorShiftRng::from_seed(seed); - let agg_circuit = AggregationCircuit::new(&self.agg_params, snarks, &mut rng); - let agg_pk = self - .agg_pk - .get_or_insert_with(|| gen_pk(&self.agg_params, &agg_circuit, None)); + let agg_circuit = AggregationCircuit::new(&self.chunk_params, snarks, &mut rng); + let chunk_pk = self + .chunk_pk + .get_or_insert_with(|| gen_pk(&self.chunk_params, &agg_circuit, None)); let agg_proof = gen_evm_proof_shplonk( - &self.agg_params, - agg_pk, + &self.chunk_params, + chunk_pk, agg_circuit.clone(), agg_circuit.instances(), &mut rng, ); - let instances = serialize_fr_matrix(agg_circuit.instances().as_slice()); - let instance_bytes = serde_json::to_vec(&instances)?; - - Ok(Proof { - proof: agg_proof, - instance: instance_bytes, - vk: serialize_vk(agg_pk.get_vk()), - }) + Proof::new( + chunk_pk, + agg_proof, + &agg_circuit.instances(), + Some(agg_circuit.num_instance()), + ) } // Initiates the public key for a given inner circuit. pub(crate) fn gen_inner_pk(&mut self, circuit: &::Inner) { - Self::tick(&format!("before init pk of {}", C::name())); - let pk = keygen_pk2(&self.zkevm_params, circuit) + tick(&format!("before init pk of {}", C::name())); + let pk = keygen_pk2(&self.inner_params, circuit) .unwrap_or_else(|e| panic!("failed to generate {} pk: {:?}", C::name(), e)); - self.target_circuit_pks.insert(C::name(), pk); - Self::tick(&format!("after init pk of {}", C::name())); + self.inner_pks.insert(C::name(), pk); + tick(&format!("after init pk of {}", C::name())); } } diff --git a/prover/src/zkevm/prover/evm.rs b/prover/src/zkevm/prover/evm.rs index cb7720274..1ec64d6a3 100644 --- a/prover/src/zkevm/prover/evm.rs +++ b/prover/src/zkevm/prover/evm.rs @@ -12,7 +12,7 @@ impl Prover { path: Option<&Path>, ) -> Vec { gen_evm_verifier_shplonk::( - &self.agg_params, + &self.chunk_params, agg_vk, agg_circuit.num_instance(), path, diff --git a/prover/src/zkevm/prover/mock.rs b/prover/src/zkevm/prover/mock.rs index ce153b9ce..b271ed6cd 100644 --- a/prover/src/zkevm/prover/mock.rs +++ b/prover/src/zkevm/prover/mock.rs @@ -1,8 +1,8 @@ use super::{ - super::circuit::{block_traces_to_witness_block, check_batch_capacity, TargetCircuit, DEGREE}, + super::circuit::{block_traces_to_witness_block, check_batch_capacity, TargetCircuit}, Prover, }; -use crate::utils::metric_of_witness_block; +use crate::{config::INNER_DEGREE, utils::metric_of_witness_block}; use anyhow::bail; use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use types::eth::BlockTrace; @@ -32,7 +32,7 @@ impl Prover { metric_of_witness_block(&witness_block) ); let (circuit, instance) = C::from_witness_block(&witness_block)?; - let prover = MockProver::::run(*DEGREE as u32, &circuit, instance)?; + let prover = MockProver::::run(*INNER_DEGREE, &circuit, instance)?; if let Err(errs) = prover.verify_par() { log::error!("err num: {}", errs.len()); for err in &errs { diff --git a/prover/src/zkevm/prover/util.rs b/prover/src/zkevm/prover/util.rs deleted file mode 100644 index 50b687238..000000000 --- a/prover/src/zkevm/prover/util.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Initialization and utility APIs for Prover. -use super::{ - super::circuit::{AGG_DEGREE, DEGREE}, - Prover, -}; -use crate::utils::{load_params, DEFAULT_SERDE_FORMAT}; -use halo2_proofs::{ - halo2curves::bn256::Bn256, - poly::{ - commitment::{Params, ParamsProver}, - kzg::commitment::{ParamsKZG, ParamsVerifierKZG}, - }, -}; - -impl Prover { - /// Memory usage tracker. - pub(crate) fn tick(desc: &str) { - #[cfg(target_os = "linux")] - let memory = match procfs::Meminfo::new() { - Ok(m) => m.mem_total - m.mem_free, - Err(_) => 0, - }; - #[cfg(not(target_os = "linux"))] - let memory = 0; - log::debug!( - "memory usage when {}: {:?}GB", - desc, - memory / 1024 / 1024 / 1024 - ); - } - - pub fn from_params(agg_params: ParamsKZG) -> Self { - assert!(agg_params.k() == *AGG_DEGREE as u32); - let mut params = agg_params.clone(); - params.downsize(*DEGREE as u32); - - // notice that k < k_agg which is not necessary the case in practice - log::info!( - "loaded parameters for degrees {} and {}", - *DEGREE, - *AGG_DEGREE - ); - - // this check can be skipped since the `params` is downsized? - { - let target_params_verifier: &ParamsVerifierKZG = params.verifier_params(); - let agg_params_verifier: &ParamsVerifierKZG = agg_params.verifier_params(); - log::info!( - "params g2 {:?} s_g2 {:?}", - target_params_verifier.g2(), - target_params_verifier.s_g2() - ); - debug_assert_eq!(target_params_verifier.s_g2(), agg_params_verifier.s_g2()); - debug_assert_eq!(target_params_verifier.g2(), agg_params_verifier.g2()); - } - - Self::new(params, agg_params) - } - - pub fn from_param_dir(params_fpath: &str) -> Self { - let agg_params = load_params(params_fpath, *AGG_DEGREE, DEFAULT_SERDE_FORMAT) - .expect("failed to init params"); - Self::from_params(agg_params) - } -} diff --git a/prover/src/zkevm/verifier.rs b/prover/src/zkevm/verifier.rs index 2efd6ab47..a49e9cc7f 100644 --- a/prover/src/zkevm/verifier.rs +++ b/prover/src/zkevm/verifier.rs @@ -1,118 +1,119 @@ -use anyhow::anyhow; -use itertools::Itertools; -use std::{collections::HashMap, io::Cursor}; - -use super::circuit::{TargetCircuit, AGG_DEGREE, DEGREE}; +use super::circuit::TargetCircuit; use crate::{ - proof::Proof, - utils::{load_params, DEFAULT_SERDE_FORMAT}, + config::{CHUNK_DEGREE, INNER_DEGREE}, + utils::load_params, + Proof, }; - +use anyhow::{bail, Result}; use halo2_proofs::{ halo2curves::bn256::{Bn256, G1Affine}, plonk::{keygen_vk, verify_proof, VerifyingKey}, poly::{ - commitment::ParamsProver, + commitment::{Params, ParamsProver}, kzg::{commitment::ParamsKZG, multiopen::VerifierSHPLONK, strategy::AccumulatorStrategy}, VerificationStrategy, }, transcript::TranscriptReadBuffer, + SerdeFormat, }; +use itertools::Itertools; use snark_verifier::system::halo2::transcript::evm::EvmTranscript; use snark_verifier_sdk::{verify_snark_shplonk, AggregationCircuit, Snark}; +use std::{collections::HashMap, io::Cursor}; pub struct Verifier { - zkevm_params: ParamsKZG, - agg_params: ParamsKZG, - agg_vk: Option>, - target_circuit_vks: HashMap>, + inner_params: ParamsKZG, + chunk_params: ParamsKZG, + chunk_vk: Option>, + inner_vks: HashMap>, } impl Verifier { - pub fn new( - zkevm_params: ParamsKZG, - agg_params: ParamsKZG, - raw_agg_vk: Option>, + pub fn from_params( + inner_params: ParamsKZG, + chunk_params: ParamsKZG, + raw_chunk_vk: Option>, ) -> Self { - let agg_vk = raw_agg_vk.as_ref().map(|k| { + let chunk_vk = raw_chunk_vk.as_ref().map(|k| { VerifyingKey::::read::<_, AggregationCircuit>( &mut Cursor::new(&k), - halo2_proofs::SerdeFormat::Processed, + SerdeFormat::Processed, ) .unwrap() }); Self { - zkevm_params, - agg_params, - agg_vk, - target_circuit_vks: Default::default(), + inner_params, + chunk_params, + chunk_vk, + inner_vks: Default::default(), } } - pub fn from_params( - params: ParamsKZG, - agg_params: ParamsKZG, - agg_vk: Option>, - ) -> Self { - Self::new(params, agg_params, agg_vk) - } + pub fn from_params_dir(params_dir: &str, chunk_vk: Option>) -> Self { + let chunk_params = load_params(params_dir, *CHUNK_DEGREE, None).unwrap(); + let inner_params = load_params(params_dir, *INNER_DEGREE, None).unwrap_or_else(|_| { + assert!(*CHUNK_DEGREE >= *INNER_DEGREE); + log::warn!( + "Optimization: download params{} to params dir", + *INNER_DEGREE + ); + + let mut new_params = chunk_params.clone(); + new_params.downsize(*INNER_DEGREE); + new_params + }); - pub fn from_fpath(params_path: &str, agg_vk: Option>) -> Self { - let params = - load_params(params_path, *DEGREE, DEFAULT_SERDE_FORMAT).expect("failed to init params"); - let agg_params = load_params(params_path, *AGG_DEGREE, DEFAULT_SERDE_FORMAT) - .expect("failed to init params"); - Self::from_params(params, agg_params, agg_vk) + Self::from_params(inner_params, chunk_params, chunk_vk) } - pub fn verify_chunk_proof(&self, proof: Proof) -> anyhow::Result { - let vk = match self.agg_vk.clone() { - Some(k) => k, - None => panic!("aggregation verification key is missing"), + pub fn verify_chunk_proof(&self, proof: Proof) -> Result { + let chunk_vk = match &self.chunk_vk { + Some(vk) => vk, + None => panic!("Chunk verification key is missing"), }; Ok(verify_snark_shplonk::( - &self.agg_params, + &self.chunk_params, proof.to_snark(), - &vk, + chunk_vk, )) } - pub fn verify_chunk_evm_proof(&self, proof: Proof) -> anyhow::Result { - let vk = match self.agg_vk.clone() { - Some(k) => k, - None => panic!("aggregation verification key is missing"), + pub fn verify_chunk_evm_proof(&self, proof: Proof) -> Result { + let chunk_vk = match &self.chunk_vk { + Some(vk) => vk, + None => panic!("Chunk verification key is missing"), }; - let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.proof.as_slice()); + let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.proof()); - // deserialize instances - let instances = proof.deserialize_instance(); + // Deserialize instances + let instances = proof.instances(); let instances = instances.iter().map(|ins| ins.as_slice()).collect_vec(); Ok(VerificationStrategy::<_, VerifierSHPLONK>::finalize( verify_proof::<_, VerifierSHPLONK, _, EvmTranscript<_, _, _, _>, _>( - &self.agg_params, - &vk, - AccumulatorStrategy::new(&self.zkevm_params), + &self.chunk_params, + chunk_vk, + AccumulatorStrategy::new(&self.inner_params), &[instances.as_slice()], &mut transcript, )?, )) } - pub fn verify_inner_proof(&mut self, snark: &Snark) -> anyhow::Result<()> { - let verifier_params = self.zkevm_params.verifier_params(); - let vk = self.target_circuit_vks.entry(C::name()).or_insert_with(|| { + pub fn verify_inner_proof(&mut self, snark: &Snark) -> Result<()> { + let verifier_params = self.inner_params.verifier_params(); + let vk = self.inner_vks.entry(C::name()).or_insert_with(|| { let circuit = C::dummy_inner_circuit(); - keygen_vk(&self.zkevm_params, &circuit) - .unwrap_or_else(|_| panic!("failed to generate {} vk", C::name())) + keygen_vk(&self.inner_params, &circuit) + .unwrap_or_else(|_| panic!("Failed to generate {} vk", C::name())) }); if verify_snark_shplonk::(verifier_params, snark.clone(), vk) { Ok(()) } else { - Err(anyhow!("snark verification failed".to_string())) + bail!("Snark verification failed".to_string()) } } } diff --git a/prover/tests/aggregation_tests.rs b/prover/tests/chunk_tests.rs similarity index 72% rename from prover/tests/aggregation_tests.rs rename to prover/tests/chunk_tests.rs index b5ed199be..952e0f6c4 100644 --- a/prover/tests/aggregation_tests.rs +++ b/prover/tests/chunk_tests.rs @@ -1,9 +1,9 @@ use prover::{ io::{load_snark, write_file, write_snark}, test_util::{load_block_traces_for_test, PARAMS_DIR}, - utils::{init_env_and_log, load_or_download_params}, + utils::init_env_and_log, zkevm::{ - circuit::{SuperCircuit, TargetCircuit, AGG_DEGREE}, + circuit::{SuperCircuit, TargetCircuit}, Prover, }, EvmVerifier, @@ -16,21 +16,17 @@ use std::{ str::FromStr, }; -// An end to end integration test. -// The inner snark proofs are generated from a mock circuit -// instead of the trace files. #[cfg(feature = "prove_verify")] #[test] -fn test_aggregation_api() { +fn test_chunk_prove_verify() { std::env::set_var("VERIFY_CONFIG", "./configs/verify_circuit.config"); - let output_dir = init_env_and_log("agg_tests"); - + let output_dir = init_env_and_log("chunk_tests"); let mut output_path = PathBuf::from_str(&output_dir).unwrap(); - log::info!("created output dir {}", output_dir); + log::info!("Inited ENV and created output-dir {output_dir}"); let block_traces = load_block_traces_for_test().1; - log::info!("loaded block trace"); + log::info!("Loaded block-traces"); // ==================================================== // A whole aggregation procedure takes the following steps @@ -45,24 +41,23 @@ fn test_aggregation_api() { // 1. instantiation the parameters and the prover // - let params = load_or_download_params(PARAMS_DIR, *AGG_DEGREE).unwrap(); - let mut prover = Prover::from_params(params); + let mut prover = Prover::from_params_dir(PARAMS_DIR); log::info!("build prover"); // // 2. read inner circuit proofs (a.k.a. SNARKs) from previous dumped file or // convert block traces into // - let inner_proof_file_path = format!("{}/{}_snark.json", output_dir, SuperCircuit::name()); - let inner_proof = load_snark(&inner_proof_file_path) + let inner_snark_file_path = format!("{}/{}_snark.json", output_dir, SuperCircuit::name()); + let inner_snark = load_snark(&inner_snark_file_path) .unwrap() .unwrap_or_else(|| { let snark = prover - .gen_inner_proof::(block_traces.as_slice()) + .gen_inner_snark::(block_traces.as_slice()) .unwrap(); // Dump inner circuit proof. - write_snark(&inner_proof_file_path, &snark); + write_snark(&inner_snark_file_path, &snark); snark }); @@ -72,12 +67,12 @@ fn test_aggregation_api() { // 3. build an aggregation circuit proof let agg_circuit = AggregationCircuit::new( - &prover.agg_params, - vec![inner_proof.clone()], + &prover.chunk_params, + vec![inner_snark.clone()], XorShiftRng::from_seed([0u8; 16]), ); - let chunk_proof = prover.gen_agg_evm_proof(vec![inner_proof]).unwrap(); + let chunk_proof = prover.gen_agg_evm_proof(vec![inner_snark]).unwrap(); // Dump aggregation proof, vk and instance. chunk_proof.dump(&mut output_path, &"chunk").unwrap(); @@ -85,7 +80,7 @@ fn test_aggregation_api() { log::info!("finished aggregation generation"); // 4. generate bytecode for evm to verify aggregation circuit proof - let agg_vk = prover.agg_pk.as_ref().unwrap().get_vk(); + let agg_vk = prover.chunk_pk.as_ref().unwrap().get_vk(); // Create bytecode and dump yul-code. let yul_file_path = format!("{}/verifier.yul", output_dir); @@ -98,6 +93,6 @@ fn test_aggregation_api() { log::info!("finished byte code generation"); // 5. validate the proof with evm bytecode - EvmVerifier::new(deployment_code).verify(agg_circuit.instances(), chunk_proof.proof); + EvmVerifier::new(deployment_code).verify(agg_circuit.instances(), chunk_proof.proof().to_vec()); log::info!("end to end test completed"); } diff --git a/prover/tests/compression_tests.rs b/prover/tests/compression_tests.rs new file mode 100644 index 000000000..6258e616a --- /dev/null +++ b/prover/tests/compression_tests.rs @@ -0,0 +1,66 @@ +use aggregator::CompressionCircuit; +use prover::{ + aggregator::{Prover, Verifier}, + config::{AGG_LAYER1_DEGREE, AGG_LAYER2_DEGREE, INNER_DEGREE}, + test_util::{ + aggregator::{gen_comp_evm_proof, load_or_gen_chunk_snark, load_or_gen_comp_snark}, + load_block_traces_for_test, PARAMS_DIR, + }, + utils::{chunk_trace_to_witness_block, init_env_and_log}, +}; +use std::path::Path; + +#[cfg(feature = "prove_verify")] +#[test] +fn test_comp_prove_verify() { + // Init, load block traces and construct prover. + + let output_dir = init_env_and_log("comp_tests"); + log::info!("Initialized ENV and created output-dir {output_dir}"); + + let chunk_trace = load_block_traces_for_test().1; + log::info!("Loaded chunk-trace"); + + let witness_block = chunk_trace_to_witness_block(chunk_trace).unwrap(); + log::info!("Got witness-block"); + + let mut prover = Prover::from_params_dir( + PARAMS_DIR, + &[*INNER_DEGREE, *AGG_LAYER1_DEGREE, *AGG_LAYER2_DEGREE], + ); + log::info!("Constructed prover"); + + // Load or generate chunk snark. + let chunk_snark = load_or_gen_chunk_snark(&output_dir, "comp", &mut prover, witness_block); + log::info!("Got chunk-snark"); + + // Load or generate compression wide snark (layer-1). + let layer1_snark = load_or_gen_comp_snark( + &output_dir, + "agg_layer1", + true, + *AGG_LAYER1_DEGREE, + &mut prover, + chunk_snark, + ); + log::info!("Got compression wide snark (layer-1)"); + + // Load or generate compression EVM proof (layer-2). + let proof = gen_comp_evm_proof( + &output_dir, + "agg_layer2", + false, + *AGG_LAYER2_DEGREE, + &mut prover, + layer1_snark, + ); + log::info!("Got compression EVM proof (layer-2)"); + + // Construct verifier and EVM verify. + let params = prover.params(*AGG_LAYER2_DEGREE).clone(); + let vk = prover.pk("agg_layer2").unwrap().get_vk().clone(); + let verifier = Verifier::new(params, Some(vk)); + let yul_file_path = format!("{output_dir}/comp_verifier.yul"); + verifier.evm_verify::(&proof, Some(Path::new(&yul_file_path))); + log::info!("Finish EVM verify"); +} diff --git a/prover/tests/integration.rs b/prover/tests/integration.rs index 4e3752bb8..060293bba 100644 --- a/prover/tests/integration.rs +++ b/prover/tests/integration.rs @@ -1,11 +1,12 @@ use chrono::Utc; use halo2_proofs::{plonk::keygen_vk, SerdeFormat}; use prover::{ + config::INNER_DEGREE, io::serialize_vk, test_util::{load_block_traces_for_test, PARAMS_DIR}, - utils::{get_block_trace_from_file, init_env_and_log, load_or_download_params, load_params}, + utils::{get_block_trace_from_file, init_env_and_log, load_params}, zkevm::{ - circuit::{SuperCircuit, TargetCircuit, DEGREE}, + circuit::{SuperCircuit, TargetCircuit}, CircuitCapacityChecker, Prover, Verifier, }, }; @@ -20,23 +21,24 @@ fn test_load_params() { load_params( "/home/ubuntu/scroll-zkevm/prover/test_params", 26, - SerdeFormat::RawBytesUnchecked, + Some(SerdeFormat::RawBytesUnchecked), ) .unwrap(); load_params( "/home/ubuntu/scroll-zkevm/prover/test_params", 26, - SerdeFormat::RawBytes, + Some(SerdeFormat::RawBytes), ) .unwrap(); load_params( "/home/ubuntu/scroll-zkevm/prover/test_params.old", 26, - SerdeFormat::Processed, + Some(SerdeFormat::Processed), ) .unwrap(); } +#[ignore] #[test] fn test_capacity_checker() { init_env_and_log("integration"); @@ -97,7 +99,7 @@ fn test_mock_prove() { #[cfg(feature = "prove_verify")] #[test] -fn test_prove_verify() { +fn test_inner_prove_verify() { test_target_circuit_prove_verify::(); } @@ -110,10 +112,10 @@ fn test_deterministic() { let block_trace = load_block_traces_for_test().1; let circuit1 = C::from_block_traces(&block_trace).unwrap().0; - let prover1 = MockProver::<_>::run(*DEGREE as u32, &circuit1, circuit1.instance()).unwrap(); + let prover1 = MockProver::<_>::run(*INNER_DEGREE, &circuit1, circuit1.instance()).unwrap(); let circuit2 = C::from_block_traces(&block_trace).unwrap().0; - let prover2 = MockProver::<_>::run(*DEGREE as u32, &circuit2, circuit2.instance()).unwrap(); + let prover2 = MockProver::<_>::run(*INNER_DEGREE, &circuit2, circuit2.instance()).unwrap(); let advice1 = prover1.advices(); let advice2 = prover2.advices(); @@ -141,7 +143,7 @@ fn test_vk_same() { init_env_and_log("integration"); type C = SuperCircuit; let block_trace = load_block_traces_for_test().1; - let params = load_or_download_params(PARAMS_DIR, *DEGREE).unwrap(); + let params = load_params(PARAMS_DIR, *INNER_DEGREE, None).unwrap(); let dummy_circuit = C::dummy_inner_circuit(); let real_circuit = C::from_block_traces(&block_trace).unwrap().0; @@ -151,9 +153,9 @@ fn test_vk_same() { let vk_real_bytes: Vec<_> = serialize_vk(&vk_real); let prover1 = - MockProver::<_>::run(*DEGREE as u32, &dummy_circuit, dummy_circuit.instance()).unwrap(); + MockProver::<_>::run(*INNER_DEGREE, &dummy_circuit, dummy_circuit.instance()).unwrap(); let prover2 = - MockProver::<_>::run(*DEGREE as u32, &real_circuit, real_circuit.instance()).unwrap(); + MockProver::<_>::run(*INNER_DEGREE, &real_circuit, real_circuit.instance()).unwrap(); let fixed1 = prover1.fixed(); let fixed2 = prover2.fixed(); @@ -210,13 +212,14 @@ fn test_target_circuit_prove_verify() { let (_, block_traces) = load_block_traces_for_test(); - log::info!("start generating {} proof", C::name()); + log::info!("start generating {} snark", C::name()); let now = Instant::now(); - let mut prover = Prover::from_param_dir(PARAMS_DIR); - let proof = prover - .gen_inner_proof::(block_traces.as_slice()) + let mut prover = Prover::from_params_dir(PARAMS_DIR); + log::info!("build prover"); + let snark = prover + .gen_inner_snark::(block_traces.as_slice()) .unwrap(); - log::info!("finish generating proof, elapsed: {:?}", now.elapsed()); + log::info!("finish generating snark, elapsed: {:?}", now.elapsed()); let output_file = format!( "/tmp/{}_{}.json", @@ -224,12 +227,12 @@ fn test_target_circuit_prove_verify() { Utc::now().format("%Y%m%d_%H%M%S") ); let mut fd = std::fs::File::create(&output_file).unwrap(); - serde_json::to_writer_pretty(&mut fd, &proof).unwrap(); - log::info!("write proof to {}", output_file); + serde_json::to_writer_pretty(&mut fd, &snark).unwrap(); + log::info!("write snark to {}", output_file); - log::info!("start verifying proof"); + log::info!("start verifying snark"); let now = Instant::now(); - let mut verifier = Verifier::from_fpath(PARAMS_DIR, None); - assert!(verifier.verify_inner_proof::(&proof).is_ok()); - log::info!("finish verifying proof, elapsed: {:?}", now.elapsed()); + let mut verifier = Verifier::from_params_dir(PARAMS_DIR, None); + assert!(verifier.verify_inner_proof::(&snark).is_ok()); + log::info!("finish verifying snark, elapsed: {:?}", now.elapsed()); } diff --git a/prover/tests/snark_verifier_api.rs b/prover/tests/snark_verifier_api.rs index 1dffb758c..fb0ce66d5 100644 --- a/prover/tests/snark_verifier_api.rs +++ b/prover/tests/snark_verifier_api.rs @@ -1,10 +1,8 @@ use halo2_proofs::poly::commitment::Params; -use mock_plonk::{MockPlonkCircuit, StandardPlonk}; +use mock_plonk::StandardPlonk; use prover::{ test_util, - utils::init_env_and_log, - zkevm::{Prover, Verifier}, - EvmVerifier, + utils::{init_env_and_log, load_params}, }; use rand::SeedableRng; use rand_xorshift::XorShiftRng; @@ -18,8 +16,6 @@ use test_util::mock_plonk; #[cfg(feature = "prove_verify")] #[test] fn test_snark_verifier_sdk_api() { - use prover::utils::load_or_download_params; - use crate::test_util::PARAMS_DIR; std::env::set_var("VERIFY_CONFIG", "./configs/verify_circuit.config"); @@ -31,7 +27,7 @@ fn test_snark_verifier_sdk_api() { let mut rng = XorShiftRng::from_seed([0u8; 16]); let circuit = StandardPlonk::rand(&mut rng); - let params_outer = load_or_download_params(PARAMS_DIR, k_agg).unwrap(); + let params_outer = load_params(PARAMS_DIR, k_agg, None).unwrap(); let params_inner = { let mut params = params_outer.clone(); params.downsize(k); diff --git a/types/src/eth.rs b/types/src/eth.rs index 4e745bde1..9b6cb0167 100644 --- a/types/src/eth.rs +++ b/types/src/eth.rs @@ -3,21 +3,13 @@ use eth_types::{ Block, GethExecStep, GethExecTrace, Hash, Transaction, Word, H256, }; use ethers_core::types::{Address, Bytes, U256, U64}; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -fn u64_to_word<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let i: u64 = Deserialize::deserialize(deserializer)?; - Ok((i).into()) -} - #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct BlockTrace { - #[serde(rename = "chainID", default, deserialize_with = "u64_to_word")] - pub chain_id: U256, + #[serde(rename = "chainID", default)] + pub chain_id: u64, pub coinbase: AccountProofWrapper, pub header: EthBlock, pub transactions: Vec,