Skip to content

Commit

Permalink
Do not store debug artifact in a separate file on nargo cli compile
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino committed Jan 10, 2024
1 parent 0fb3262 commit 672bded
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 58 deletions.
7 changes: 5 additions & 2 deletions noir/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 noir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ num-traits = "0.2"
similar-asserts = "1.5.0"
tempfile = "3.6.0"
jsonrpc = { version = "0.16.0", features = ["minreq_http"] }
flate2 = "1.0.24"

tracing = "0.1.40"
tracing-web = "0.1.3"
Expand Down
2 changes: 1 addition & 1 deletion noir/acvm-repo/acir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ acir_field.workspace = true
brillig.workspace = true
serde.workspace = true
thiserror.workspace = true
flate2 = "1.0.24"
flate2.workspace = true
bincode.workspace = true
base64.workspace = true

Expand Down
5 changes: 4 additions & 1 deletion noir/compiler/noirc_errors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ fm.workspace = true
chumsky.workspace = true
serde.workspace = true
serde_with = "3.2.0"
tracing.workspace = true
tracing.workspace = true
flate2.workspace = true
serde_json.workspace = true
base64.workspace = true
41 changes: 40 additions & 1 deletion noir/compiler/noirc_errors/src/debug_info.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
use acvm::acir::circuit::OpcodeLocation;
use acvm::compiler::AcirTransformationMap;

use base64::Engine;
use flate2::Compression;
use flate2::read::DeflateDecoder;
use flate2::write::DeflateEncoder;
use serde::Deserializer;
use serde::Serializer;
use serde_with::serde_as;
use serde_with::DisplayFromStr;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::io::Read;
use std::io::Write;
use std::mem;

use crate::Location;
use serde::{Deserialize, Serialize};
use serde::{de::Error as DeserializationError, ser::Error as SerializationError, Deserialize, Serialize};

#[serde_as]
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -86,4 +94,35 @@ impl DebugInfo {

counted_opcodes
}

pub fn serialize_compressed_base64_json<S>(debug_info: &DebugInfo, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let json_str = serde_json::to_string(debug_info).map_err(S::Error::custom)?;

let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
encoder.write_all(json_str.as_bytes()).map_err(S::Error::custom)?;
let compressed_data = encoder.finish().map_err(S::Error::custom)?;

let encoded_b64 = base64::prelude::BASE64_STANDARD.encode(&compressed_data);
s.serialize_str(&encoded_b64)
}

pub fn deserialize_compressed_base64_json<'de, D>(deserializer: D) -> Result<DebugInfo, D::Error>
where
D: Deserializer<'de>,
{
let encoded_b64: String = Deserialize::deserialize(deserializer)?;

let compressed_data = base64::prelude::BASE64_STANDARD.decode(&encoded_b64)
.map_err(D::Error::custom)?;

let mut decoder = DeflateDecoder::new(&compressed_data[..]);
let mut decompressed_data = Vec::new();
decoder.read_to_end(&mut decompressed_data).map_err(D::Error::custom)?;

let json_str = String::from_utf8(decompressed_data).map_err(D::Error::custom)?;
serde_json::from_str(&json_str).map_err(D::Error::custom)
}
}
19 changes: 19 additions & 0 deletions noir/tooling/nargo/src/artifacts/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ use acvm::acir::circuit::Circuit;
use noirc_abi::{Abi, ContractEvent};
use noirc_driver::{ContractFunction, ContractFunctionType};
use serde::{Deserialize, Serialize};
use noirc_evaluator::errors::SsaReport;

use noirc_driver::DebugFile;
use noirc_errors::debug_info::DebugInfo;
use std::collections::BTreeMap;

use fm::FileId;


#[derive(Serialize, Deserialize)]
pub struct ContractArtifact {
Expand All @@ -13,6 +21,10 @@ pub struct ContractArtifact {
pub functions: Vec<ContractFunctionArtifact>,
/// All the events defined inside the contract scope.
pub events: Vec<ContractEvent>,
/// Map of file Id to the source code so locations in debug info can be mapped to source code they point to.
pub file_map: BTreeMap<FileId, DebugFile>,
/// Compilation warnings.
pub warnings: Vec<SsaReport>,
}

/// Each function in the contract will be compiled as a separate noir program.
Expand All @@ -34,6 +46,12 @@ pub struct ContractFunctionArtifact {
deserialize_with = "Circuit::deserialize_circuit_base64"
)]
pub bytecode: Circuit,

#[serde(
serialize_with = "DebugInfo::serialize_compressed_base64_json",
deserialize_with = "DebugInfo::deserialize_compressed_base64_json"
)]
pub debug_symbols: DebugInfo,
}

impl From<ContractFunction> for ContractFunctionArtifact {
Expand All @@ -44,6 +62,7 @@ impl From<ContractFunction> for ContractFunctionArtifact {
is_internal: func.is_internal,
abi: func.abi,
bytecode: func.bytecode,
debug_symbols: func.debug_symbols,
}
}
}
21 changes: 21 additions & 0 deletions noir/tooling/nargo/src/artifacts/program.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
use std::collections::BTreeMap;

use acvm::acir::circuit::Circuit;
use fm::FileId;
use noirc_abi::Abi;
use noirc_driver::CompiledProgram;
use noirc_driver::DebugFile;
use noirc_errors::debug_info::DebugInfo;
use noirc_evaluator::errors::SsaReport;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -20,6 +26,18 @@ pub struct ProgramArtifact {
deserialize_with = "Circuit::deserialize_circuit_base64"
)]
pub bytecode: Circuit,

#[serde(
serialize_with = "DebugInfo::serialize_compressed_base64_json",
deserialize_with = "DebugInfo::deserialize_compressed_base64_json"
)]
pub debug_symbols: DebugInfo,

/// Map of file Id to the source code so locations in debug info can be mapped to source code they point to.
pub file_map: BTreeMap<FileId, DebugFile>,

/// Compilation warnings.
pub warnings: Vec<SsaReport>,
}

impl From<CompiledProgram> for ProgramArtifact {
Expand All @@ -29,6 +47,9 @@ impl From<CompiledProgram> for ProgramArtifact {
abi: program.abi,
noir_version: program.noir_version,
bytecode: program.circuit,
debug_symbols: program.debug_info,
file_map: program.file_map,
warnings: program.warnings,
}
}
}
47 changes: 15 additions & 32 deletions noir/tooling/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@


use std::path::Path;

use acvm::ExpressionWidth;

use fm::FileManager;
use iter_extended::vecmap;
use nargo::artifacts::contract::{ContractArtifact, ContractFunctionArtifact};
use nargo::artifacts::debug::DebugArtifact;
use nargo::artifacts::program::ProgramArtifact;
use nargo::errors::CompileError;
use nargo::insert_all_files_for_workspace_into_file_manager;
Expand All @@ -15,17 +17,20 @@ use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelec
use noirc_driver::file_manager_with_stdlib;
use noirc_driver::NOIR_ARTIFACT_VERSION_STRING;
use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram};

use noirc_frontend::graph::CrateName;



use clap::Args;

use crate::backends::Backend;
use crate::errors::CliError;

use super::fs::program::only_acir;
use super::fs::program::{
read_debug_artifact_from_file, read_program_from_file, save_contract_to_file,
save_debug_artifact_to_file, save_program_to_file,
read_program_from_file, save_contract_to_file,
save_program_to_file,
};
use super::NargoConfig;
use rayon::prelude::*;
Expand Down Expand Up @@ -170,20 +175,15 @@ fn compile_program(
let (mut context, crate_id) = prepare_package(file_manager, package);

let program_artifact_path = workspace.package_build_path(package);
let mut debug_artifact_path = program_artifact_path.clone();
debug_artifact_path.set_file_name(format!("debug_{}.json", package.name));
let cached_program = if let (Ok(program_artifact), Ok(mut debug_artifact)) = (
read_program_from_file(program_artifact_path),
read_debug_artifact_from_file(debug_artifact_path),
) {
let cached_program = if let Ok(program_artifact) = read_program_from_file(program_artifact_path) {
Some(CompiledProgram {
hash: program_artifact.hash,
circuit: program_artifact.bytecode,
abi: program_artifact.abi,
noir_version: program_artifact.noir_version,
debug: debug_artifact.debug_symbols.remove(0),
file_map: debug_artifact.file_map,
warnings: debug_artifact.warnings,
debug: program_artifact.debug_symbols,
file_map: program_artifact.file_map,
warnings: program_artifact.warnings,
})
} else {
None
Expand Down Expand Up @@ -244,53 +244,36 @@ pub(super) fn save_program(
} else {
save_program_to_file(&program_artifact, &package.name, circuit_dir);
}

let debug_artifact = DebugArtifact {
debug_symbols: vec![program.debug],
file_map: program.file_map,
warnings: program.warnings,
};
let circuit_name: String = (&package.name).into();
save_debug_artifact_to_file(&debug_artifact, &circuit_name, circuit_dir);
}

fn save_contract(contract: CompiledContract, package: &Package, circuit_dir: &Path) {
// TODO(#1389): I wonder if it is incorrect for nargo-core to know anything about contracts.
// As can be seen here, It seems like a leaky abstraction where ContractFunctions (essentially CompiledPrograms)
// are compiled via nargo-core and then the ContractArtifact is constructed here.
// This is due to EACH function needing it's own CRS, PKey, and VKey from the backend.
let debug_artifact = DebugArtifact {
debug_symbols: contract.functions.iter().map(|function| function.debug.clone()).collect(),
file_map: contract.file_map,
warnings: contract.warnings,
};

let functions = vecmap(contract.functions, |func| ContractFunctionArtifact {
name: func.name,
function_type: func.function_type,
is_internal: func.is_internal,
abi: func.abi,
bytecode: func.bytecode,
debug_symbols: func.debug,
});

let contract_artifact = ContractArtifact {
noir_version: contract.noir_version,
name: contract.name,
functions,
events: contract.events,
file_map: contract.file_map,
warnings: contract.warnings,
};

save_contract_to_file(
&contract_artifact,
&format!("{}-{}", package.name, contract_artifact.name),
circuit_dir,
);

save_debug_artifact_to_file(
&debug_artifact,
&format!("{}-{}", package.name, contract_artifact.name),
circuit_dir,
);
}

/// Helper function for reporting any errors in a `CompilationResult<T>`
Expand Down
22 changes: 1 addition & 21 deletions noir/tooling/nargo_cli/src/cli/fs/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};

use acvm::acir::circuit::Circuit;
use nargo::artifacts::{
contract::ContractArtifact, debug::DebugArtifact, program::ProgramArtifact,
contract::ContractArtifact, program::ProgramArtifact,
};
use noirc_frontend::graph::CrateName;

Expand Down Expand Up @@ -40,15 +40,6 @@ pub(crate) fn save_contract_to_file<P: AsRef<Path>>(
save_build_artifact_to_file(compiled_contract, circuit_name, circuit_dir)
}

pub(crate) fn save_debug_artifact_to_file<P: AsRef<Path>>(
debug_artifact: &DebugArtifact,
circuit_name: &str,
circuit_dir: P,
) -> PathBuf {
let artifact_name = format!("debug_{circuit_name}");
save_build_artifact_to_file(debug_artifact, &artifact_name, circuit_dir)
}

fn save_build_artifact_to_file<P: AsRef<Path>, T: ?Sized + serde::Serialize>(
build_artifact: &T,
artifact_name: &str,
Expand All @@ -74,14 +65,3 @@ pub(crate) fn read_program_from_file<P: AsRef<Path>>(

Ok(program)
}

pub(crate) fn read_debug_artifact_from_file<P: AsRef<Path>>(
debug_artifact_path: P,
) -> Result<DebugArtifact, FilesystemError> {
let input_string = std::fs::read(&debug_artifact_path)
.map_err(|_| FilesystemError::PathNotValid(debug_artifact_path.as_ref().into()))?;
let program = serde_json::from_slice(&input_string)
.map_err(|err| FilesystemError::ProgramSerializationError(err.to_string()))?;

Ok(program)
}

0 comments on commit 672bded

Please sign in to comment.