Skip to content

Commit

Permalink
feat(prover): File-info tool to help prover debugging (#1216)
Browse files Browse the repository at this point in the history
## What ❔

* a helper tool to see the contents of the prover files - it
auto-guesses the file type and displays information.

## Why ❔

* to make prover debugging easier


```shell
cargo run --release  file-info 1_0_1_Scheduler_0.bin
```


![image](https://github.com/matter-labs/zksync-era/assets/128217157/d87d84cc-a16b-43f7-aebe-5da6a6d722dd)
  • Loading branch information
mm-zk committed Mar 18, 2024
1 parent 5a37b42 commit 9759907
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 0 deletions.
24 changes: 24 additions & 0 deletions prover/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions prover/Cargo.toml
Expand Up @@ -12,6 +12,7 @@ members = [
"witness_vector_generator",
"prover_fri_gateway",
"proof_fri_compressor",
"tools",
]

resolver = "2"
Expand Down
17 changes: 17 additions & 0 deletions prover/tools/Cargo.toml
@@ -0,0 +1,17 @@
[package]
name = "tools"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

clap = { version = "4.4.6", features = ["derive"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
zksync_prover_fri_types = {path = "../prover_fri_types"}
bincode = "1.0"
colored = "2.0"
zksync_prover_interface = { path = "../../core/lib/prover_interface" }
hex = "0.4"
37 changes: 37 additions & 0 deletions prover/tools/README.md
@@ -0,0 +1,37 @@
# Tool to better understand and debug provers

For now, it has only one command 'file-info'

```
cargo run --release file-info /zksync-era/prover/artifacts/proofs_fri/l1_batch_proof_1.bin
```

Example outputs:

```
L1 proof
AUX info:
L1 msg linear hash: [163, 243, 172, 16, 189, 59, 100, 227, 249, 46, 226, 220, 82, 135, 213, 208, 221, 228, 49, 46, 121, 136, 78, 163, 15, 155, 199, 82, 64, 24, 172, 198]
Rollup_state_diff_for_compression: [157, 150, 29, 193, 105, 162, 176, 61, 83, 241, 72, 206, 68, 20, 143, 69, 119, 162, 138, 101, 80, 139, 193, 211, 188, 250, 156, 86, 254, 148, 117, 60]
bootloader_heap_initial_content: [112, 2, 120, 255, 156, 227, 172, 92, 134, 48, 247, 243, 148, 241, 11, 122, 6, 189, 46, 164, 89, 78, 209, 118, 115, 239, 195, 15, 225, 143, 97, 204]
events_queue_state: [202, 78, 244, 233, 150, 17, 247, 25, 183, 51, 245, 110, 135, 31, 115, 109, 84, 193, 17, 1, 153, 32, 39, 199, 102, 25, 63, 216, 220, 68, 212, 233]
Inputs: [Fr(0x00000000775db828700e0ebbe0384f8a017598a271dfb6c96ebb2baf22a7a572)]
```

```
== Circuit ==
Type: basic. Id: 1 (Scheduler)
Geometry: CSGeometry { num_columns_under_copy_permutation: 130, num_witness_columns: 0, num_constant_columns: 4, max_allowed_constraint_degree: 8 }
Circuit size: trace length: Some(1048576) something??: Some(100663296)
Scheduler witness info
Previous block data:
Enumeration counter: 25
State root: [107, 233, 138, 154, 21, 134, 189, 220, 183, 250, 117, 243, 103, 124, 71, 221, 160, 136, 249, 25, 197, 109, 8, 75, 26, 12, 81, 109, 36, 56, 30, 17]
Block meta parameters
bootloader code hash: 452367551810219221093730953379759186922674186246309239546886848509599206765
aa code hash: 452349823575802367618424269668644286404749728714566974110193150711820505769
Previous block meta hash: [63, 236, 0, 236, 23, 236, 175, 242, 75, 187, 203, 193, 88, 80, 202, 53, 40, 206, 28, 40, 125, 58, 53, 254, 233, 122, 108, 101, 101, 88, 102, 193]
Previous block aux hash: [200, 12, 70, 33, 103, 13, 251, 174, 96, 165, 135, 138, 34, 75, 249, 81, 93, 86, 110, 52, 30, 172, 198, 51, 155, 82, 86, 137, 156, 215, 11, 119]
EIP 4844 - witnesses: None
EIP 4844 - proofs: 0
```
250 changes: 250 additions & 0 deletions prover/tools/src/main.rs
@@ -0,0 +1,250 @@
use std::fs;

use clap::{Parser, Subcommand};
use colored::Colorize;
use tracing::level_filters::LevelFilter;
use zksync_prover_fri_types::{
circuit_definitions::{
boojum::{
field::goldilocks::{GoldilocksExt2, GoldilocksField},
gadgets::recursion::recursive_tree_hasher::CircuitGoldilocksPoseidon2Sponge,
},
circuit_definitions::{
base_layer::ZkSyncBaseLayerCircuit, recursion_layer::ZkSyncRecursiveLayerCircuit,
},
zkevm_circuits::scheduler::input::SchedulerCircuitInstanceWitness,
},
CircuitWrapper, FriProofWrapper,
};
use zksync_prover_interface::outputs::L1BatchProofForL1;

#[derive(Debug, Parser)]
#[command(
author = "Matter Labs",
version,
about = "Debugging tools for prover related things",
long_about = None
)]

struct Cli {
#[command(subcommand)]
command: Command,
}

#[derive(Debug, Subcommand)]
enum Command {
#[command(name = "file-info")]
FileInfo { file_path: String },
}

fn pretty_print_size_hint(size_hint: (Option<usize>, Option<usize>)) {
println!(
"Circuit size: trace length: {:?} something??: {:?}",
size_hint.0, size_hint.1
);
}

fn pretty_print_scheduler_witness(
witness: &SchedulerCircuitInstanceWitness<
GoldilocksField,
CircuitGoldilocksPoseidon2Sponge,
GoldilocksExt2,
>,
) {
println!("Scheduler witness info");
println!(" Previous block data: ");
println!(
" Enumeration counter: {:?}",
witness.prev_block_data.per_shard_states[0].enumeration_counter[0]
);
println!(
" State root: 0x{}",
hex::encode(witness.prev_block_data.per_shard_states[0].state_root)
);

println!(" Block meta parameters");
println!(
" bootloader code hash: {:?}",
witness.block_meta_parameters.bootloader_code_hash
);
println!(
" aa code hash: {:?}",
witness.block_meta_parameters.default_aa_code_hash
);

println!(
" Previous block meta hash: 0x{}",
hex::encode(witness.previous_block_meta_hash)
);
println!(
" Previous block aux hash: 0x{}",
hex::encode(witness.previous_block_aux_hash)
);

println!(" EIP 4844 - witnesses: {:?}", witness.eip4844_witnesses);
println!(" EIP 4844 - proofs: {:?}", witness.eip4844_proofs.len());
}

fn pretty_print_circuit_wrapper(circuit: &CircuitWrapper) {
println!(" == Circuit ==");
match circuit {
CircuitWrapper::Base(circuit) => {
println!(
"Type: basic. Id: {:?} ({})",
circuit.numeric_circuit_type(),
circuit.short_description().bold()
);
println!("Geometry: {:?}", circuit.geometry());
pretty_print_size_hint(circuit.size_hint());

match circuit {
ZkSyncBaseLayerCircuit::MainVM(_) => todo!(),
ZkSyncBaseLayerCircuit::CodeDecommittmentsSorter(_) => todo!(),
ZkSyncBaseLayerCircuit::CodeDecommitter(_) => todo!(),
ZkSyncBaseLayerCircuit::LogDemuxer(_) => todo!(),
ZkSyncBaseLayerCircuit::KeccakRoundFunction(_) => todo!(),
ZkSyncBaseLayerCircuit::Sha256RoundFunction(_) => todo!(),
ZkSyncBaseLayerCircuit::ECRecover(circuit) => {
println!("Expected public input: {:?}", circuit.expected_public_input);
println!("Max ECRecovers per circuit: {:?}", circuit.config);
}
ZkSyncBaseLayerCircuit::RAMPermutation(_) => todo!(),
ZkSyncBaseLayerCircuit::StorageSorter(_) => todo!(),
ZkSyncBaseLayerCircuit::StorageApplication(circuit) => circuit.debug_witness(),
ZkSyncBaseLayerCircuit::EventsSorter(_) => todo!(),
ZkSyncBaseLayerCircuit::L1MessagesSorter(_) => todo!(),
ZkSyncBaseLayerCircuit::L1MessagesHasher(_) => todo!(),
}
}
CircuitWrapper::Recursive(circuit) => {
println!(
"Type: basic. Id: {:?} ({})",
circuit.numeric_circuit_type(),
circuit.short_description().bold()
);
println!("Geometry: {:?}", circuit.geometry());
pretty_print_size_hint(circuit.size_hint());
match circuit {
ZkSyncRecursiveLayerCircuit::SchedulerCircuit(circuit) => {
//println!("Expected public input: {:?}", circuit.witness);
pretty_print_scheduler_witness(&circuit.witness);
}
ZkSyncRecursiveLayerCircuit::NodeLayerCircuit(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForMainVM(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForCodeDecommittmentsSorter(_) => {
todo!()
}
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForCodeDecommitter(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForLogDemuxer(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForKeccakRoundFunction(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForSha256RoundFunction(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForECRecover(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForRAMPermutation(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForStorageSorter(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForStorageApplication(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForEventsSorter(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForL1MessagesSorter(_) => todo!(),
ZkSyncRecursiveLayerCircuit::LeafLayerCircuitForL1MessagesHasher(_) => todo!(),
}
}
CircuitWrapper::Eip4844(_) => {
println!("Type: eip4844")
}
}
}

fn pretty_print_proof(result: &FriProofWrapper) {
println!("{}", "== FRI proof ==".to_string().bold());
match result {
FriProofWrapper::Base(proof) => {
println!(
"Basic proof {} {}",
proof.numeric_circuit_type(),
proof.short_description()
);
}
FriProofWrapper::Recursive(proof) => {
println!(
"Recursive proof {} {}",
proof.numeric_circuit_type(),
proof.short_description()
);

let proof = proof.clone().into_inner();
println!("Proof config: {:?}", proof.proof_config);
println!("Proof public inputs: {:?}", proof.public_inputs);
}
FriProofWrapper::Eip4844(_) => {
println!("4844 blob proof",);
}
}
}

fn pretty_print_l1_proof(result: &L1BatchProofForL1) {
println!("{}", "== Snark wrapped L1 proof ==".to_string().bold());
println!("AUX info:");
println!(
" L1 msg linear hash: 0x{}",
hex::encode(result.aggregation_result_coords[0])
);
println!(
" Rollup_state_diff_for_compression: 0x{}",
hex::encode(result.aggregation_result_coords[1])
);
println!(
" bootloader_heap_initial_content: 0x{}",
hex::encode(result.aggregation_result_coords[2])
);
println!(
" events_queue_state: 0x{}",
hex::encode(result.aggregation_result_coords[3])
);

println!("Inputs: {:?}", result.scheduler_proof.inputs);
println!(" This proof will pass on L1, if L1 executor computes the block commitment that is matching exactly the Inputs value above");
}

fn file_info(path: String) {
println!("Reading file {} and guessing the type.", path.bold());

let bytes = fs::read(path).unwrap();

// Parsing stuff from `prover_jobs_fri` directory.
let maybe_circuit: Option<CircuitWrapper> = bincode::deserialize(&bytes).ok();
if let Some(circuit) = maybe_circuit {
println!(" Parsing file as CircuitWrapper.");
pretty_print_circuit_wrapper(&circuit);
return;
}
println!(" NOT a CircuitWrapper.");
let maybe_fri_proof: Option<FriProofWrapper> = bincode::deserialize(&bytes).ok();
if let Some(fri_proof) = maybe_fri_proof {
println!(" Parsing file as FriProofWrapper.");
pretty_print_proof(&fri_proof);
return;
}
println!(" NOT a FriProofWrapper.");

let maybe_snark_proof: Option<L1BatchProofForL1> = bincode::deserialize(&bytes).ok();
if let Some(snark_proof) = maybe_snark_proof {
println!(" Parsing file as L1BatchProofForL1.");
pretty_print_l1_proof(&snark_proof)
} else {
println!(" NOT a L1BatchProof.");
}
}

fn main() {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.init();

let opt = Cli::parse();
match opt.command {
Command::FileInfo { file_path } => file_info(file_path),
}
}

0 comments on commit 9759907

Please sign in to comment.