Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
feat: provide IR for debugging upon failure (#48)
Browse files Browse the repository at this point in the history
* feat: provide IR for debugging upon failure

* fix: fix clippy issues

* fix: fix pr comments

* fix: make evm_arithmetization non optional for ops

* fix: fix pr comments

* fix: fix clippy issues

* fix: fix clippy issue

* fix: fix pr comment

* fix: fix clippy issue

* fix: fix cargo lock

* fix: fix pr comments

* fix: fix format issues

* fix: fix save input on error for test-only

* fix: fix pr comments

* fix: fix

* fix: fix clippy issue

* fix: fmt fix

---------

Co-authored-by: Vladimir Trifonov <trifonov.vp@gmail.com>
  • Loading branch information
vladimir-trifonov and lastminutedev authored Apr 24, 2024
1 parent 57d67b8 commit 4d91738
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ A composition of [`paladin`](https://github.com/0xPolygonZero/paladin) and [`plo
- [RPC Usage](#rpc-usage)
- [Docker](#docker)
- [Development Branches](#development-branches)
- [Testing Blocks](#testing-blocks)
- [Proving Blocks](#proving-blocks)
- [Generating Witnesses Only](#generating-witnesses-only)
- [License](#license)
- [Contribution](#contribution)

Expand Down Expand Up @@ -217,6 +220,8 @@ Options:
If provided, write the generated proof to this file instead of stdout
-h, --help
Print help
-s, --save-inputs-on-error
If provided, save the public inputs to disk on error
```

Prove a block.
Expand Down
2 changes: 2 additions & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ evm_arithmetization = { workspace = true }
clap = { workspace = true }
anyhow = { workspace = true }
trace_decoder = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
seahash = "4.1.0"
102 changes: 102 additions & 0 deletions common/src/debug_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use serde::Serialize;
use serde_json::Error as SerdeError;
use thiserror::Error;

const DEBUG_FOLDER: &str = "./debug";

/// Ensures that the specified directory exists on the filesystem.
///
/// This function checks if the directory at `folder_path` exists. If not, it
/// attempts to create the directory. It returns an error if the path is not a
/// directory or if there are issues accessing or creating the directory.
///
/// # Parameters
/// * `folder_path` - A reference to a `Path` that specifies the directory to
/// check or create.
///
/// # Returns
/// * `Ok(())` - The directory exists or was successfully created.
/// * `Err(io::Error)` - The path is not a directory, or there was a problem
/// accessing or creating the directory.
fn ensure_directory_exists(folder_path: &Path) -> io::Result<()> {
match fs::metadata(folder_path) {
Ok(metadata) => {
if metadata.is_dir() {
Ok(()) // The directory already exists
} else {
Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"The path exists but is not a directory",
))
}
}
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
// Directory does not exist, try to create it
fs::create_dir(folder_path)
} else {
// Re-throw the error if it's not a 'NotFound' error
Err(e)
}
}
}
}

/// An error type for save debug input information.
#[derive(Error, Debug)]
pub enum SaveInputError {
#[error("failed to create directory '{0}'")]
CreateDirectoryError(PathBuf, #[source] io::Error),

#[error("failed to create file '{0}'")]
CreateFileError(PathBuf, #[source] io::Error),

#[error("failed to serialize inputs")]
SerializationError(#[source] SerdeError),

#[error("failed to write to file '{0}'")]
WriteToFileError(PathBuf, #[source] io::Error),
}

/// Serializes a collection of inputs to a pretty-printed JSON format and saves
/// them to a file.
///
/// # Arguments
///
/// * `file_name` - The name of the file (including the extension) where the
/// serialized data will be saved.
/// * `inputs` - A collection of items to be serialized. Each item in the
/// collection must implement the `Serialize` trait.
///
/// # Returns
///
/// This function returns a `Result<(), std::io::Error>` indicating the
/// operation's success or failure.
pub fn save_inputs_to_disk<T: Serialize>(
file_name: String,
inputs: T,
) -> Result<(), SaveInputError> {
let debug_folder = Path::new(DEBUG_FOLDER);
let input_file_path = debug_folder.join(file_name);

// Ensure the DEBUG_FOLDER exists
ensure_directory_exists(debug_folder)
.map_err(|e| SaveInputError::CreateDirectoryError(debug_folder.to_path_buf(), e))?;

let mut file = File::create(&input_file_path)
.map_err(|e| SaveInputError::CreateFileError(input_file_path.clone(), e))?;

// Serialize the entire collection to a pretty JSON string
let all_inputs_str =
serde_json::to_string_pretty(&inputs).map_err(SaveInputError::SerializationError)?;

// Write the serialized data to the file
file.write_all(all_inputs_str.as_bytes())
.map_err(|e| SaveInputError::WriteToFileError(input_file_path, e))?;

Ok(())
}
1 change: 1 addition & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod debug_utils;
pub mod parsing;
pub mod prover_state;
9 changes: 9 additions & 0 deletions leader/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub(crate) enum Command {
/// The previous proof output.
#[arg(long, short = 'f', value_hint = ValueHint::FilePath)]
previous_proof: Option<PathBuf>,
/// If true, save the public inputs to disk on error.
#[arg(short, long, default_value_t = false)]
save_inputs_on_error: bool,
},
/// Reads input from a Jerigon node and writes output to stdout.
Jerigon {
Expand All @@ -44,6 +47,9 @@ pub(crate) enum Command {
/// stdout.
#[arg(long, short = 'o', value_hint = ValueHint::FilePath)]
proof_output_path: Option<PathBuf>,
/// If true, save the public inputs to disk on error.
#[arg(short, long, default_value_t = false)]
save_inputs_on_error: bool,
},
/// Reads input from HTTP and writes output to a directory.
Http {
Expand All @@ -53,5 +59,8 @@ pub(crate) enum Command {
/// The directory to which output should be written.
#[arg(short, long, value_hint = ValueHint::DirPath)]
output_dir: PathBuf,
/// If true, save the public inputs to disk on error.
#[arg(short, long, default_value_t = false)]
save_inputs_on_error: bool,
},
}
16 changes: 13 additions & 3 deletions leader/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ use serde_json::to_writer;
use tracing::{debug, error, info};

/// The main function for the HTTP mode.
pub(crate) async fn http_main(runtime: Runtime, port: u16, output_dir: PathBuf) -> Result<()> {
pub(crate) async fn http_main(
runtime: Runtime,
port: u16,
output_dir: PathBuf,
save_inputs_on_error: bool,
) -> Result<()> {
let addr = SocketAddr::from(([0, 0, 0, 0], port));
debug!("listening on {}", addr);

Expand All @@ -20,7 +25,7 @@ pub(crate) async fn http_main(runtime: Runtime, port: u16, output_dir: PathBuf)
"/prove",
post({
let runtime = runtime.clone();
move |body| prove(body, runtime, output_dir.clone())
move |body| prove(body, runtime, output_dir.clone(), save_inputs_on_error)
}),
);
let listener = tokio::net::TcpListener::bind(&addr).await?;
Expand Down Expand Up @@ -60,12 +65,17 @@ async fn prove(
Json(payload): Json<HttpProverInput>,
runtime: Arc<Runtime>,
output_dir: PathBuf,
save_inputs_on_error: bool,
) -> StatusCode {
debug!("Received payload: {:#?}", payload);

let block_number = payload.prover_input.get_block_number();

match payload.prover_input.prove(&runtime, payload.previous).await {
match payload
.prover_input
.prove(&runtime, payload.previous, save_inputs_on_error)
.await
{
Ok(b_proof) => match write_to_file(output_dir, block_number, &b_proof) {
Ok(file) => {
info!("Successfully wrote proof to {}", file.display());
Expand Down
5 changes: 4 additions & 1 deletion leader/src/jerigon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub(crate) async fn jerigon_main(
checkpoint_block_number: u64,
previous: Option<PlonkyProofIntern>,
proof_output_path_opt: Option<PathBuf>,
save_inputs_on_error: bool,
) -> Result<()> {
let prover_input = rpc::fetch_prover_input(rpc::FetchProverInputRequest {
rpc_url,
Expand All @@ -24,7 +25,9 @@ pub(crate) async fn jerigon_main(
})
.await?;

let proof = prover_input.prove(&runtime, previous).await;
let proof = prover_input
.prove(&runtime, previous, save_inputs_on_error)
.await;
runtime.close().await?;

let proof = serde_json::to_vec(&proof?.intern)?;
Expand Down
17 changes: 13 additions & 4 deletions leader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,18 @@ async fn main() -> Result<()> {
let runtime = Runtime::from_config(&args.paladin, register()).await?;

match args.command {
Command::Stdio { previous_proof } => {
Command::Stdio {
previous_proof,
save_inputs_on_error,
} => {
let previous_proof = get_previous_proof(previous_proof)?;
stdio::stdio_main(runtime, previous_proof).await?;
stdio::stdio_main(runtime, previous_proof, save_inputs_on_error).await?;
}
Command::Http { port, output_dir } => {
Command::Http {
port,
output_dir,
save_inputs_on_error,
} => {
// check if output_dir exists, is a directory, and is writable
let output_dir_metadata = std::fs::metadata(&output_dir);
if output_dir_metadata.is_err() {
Expand All @@ -61,14 +68,15 @@ async fn main() -> Result<()> {
panic!("output-dir is not a writable directory");
}

http::http_main(runtime, port, output_dir).await?;
http::http_main(runtime, port, output_dir, save_inputs_on_error).await?;
}
Command::Jerigon {
rpc_url,
block_number,
checkpoint_block_number,
previous_proof,
proof_output_path,
save_inputs_on_error,
} => {
let previous_proof = get_previous_proof(previous_proof)?;

Expand All @@ -79,6 +87,7 @@ async fn main() -> Result<()> {
checkpoint_block_number,
previous_proof,
proof_output_path,
save_inputs_on_error,
)
.await?;
}
Expand Down
3 changes: 2 additions & 1 deletion leader/src/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ use prover::ProverInput;
pub(crate) async fn stdio_main(
runtime: Runtime,
previous: Option<PlonkyProofIntern>,
save_inputs_on_error: bool,
) -> Result<()> {
let mut buffer = String::new();
std::io::stdin().read_to_string(&mut buffer)?;

let des = &mut serde_json::Deserializer::from_str(&buffer);
let input: ProverInput = serde_path_to_error::deserialize(des)?;
let proof = input.prove(&runtime, previous).await;
let proof = input.prove(&runtime, previous, save_inputs_on_error).await;
runtime.close().await?;
let proof = proof?;

Expand Down
Loading

0 comments on commit 4d91738

Please sign in to comment.