Skip to content

Commit

Permalink
chore: testing flatten - currently fails
Browse files Browse the repository at this point in the history
  • Loading branch information
dutterbutter committed Oct 7, 2024
1 parent 1380ada commit 56dd4d1
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 21 deletions.
6 changes: 0 additions & 6 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ comfy-table = "7"
# [patch."https://github.com/matter-labs/era-test-node"]
# era_test_node = { path = "../era-test-node" }

# [patch."https://github.com/Moonsong-Labs/compilers"]
# foundry-compilers = { path = "../compilers/crates/compilers/" }
[patch."https://github.com/Moonsong-Labs/compilers"]
foundry-compilers = { path = "/Users/dustinbrickwood/Documents/dev/zk/temp/compilers/crates/compilers" }

# [patch."https://github.com/matter-labs/era-boojum"]
# cs_derive = { git = "https://github.com/nbaztec/era-boojum", branch = "foundry-fix" }
Expand Down
184 changes: 184 additions & 0 deletions crates/verify/src/zksync/flatten.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
use super::{ZksyncSourceProvider, VerifyArgs, ZkSourceOutput};
use crate::{
provider::VerificationContext,
zk_provider::{ZkVerificationContext, ZkVersion},
};
use eyre::{Context, Result};
use foundry_block_explorers::verify::CodeFormat;
use foundry_compilers::{
artifacts::{BytecodeHash, Source, Sources},
buildinfo::RawBuildInfo,
compilers::{
solc::{SolcCompiler, SolcLanguage, SolcVersionedInput},
Compiler, CompilerInput,
},
solc::{CliSettings, Solc},
zksolc::{
input::{ZkSolcInput, ZkSolcVersionedInput},
ZkSolc, ZkSolcCompiler,
},
zksync::{
compile::output::AggregatedCompilerOutput as ZkAggregatedCompilerOutput, raw_build_info_new,
},
AggregatedCompilerOutput,
};
use semver::{BuildMetadata, Version};
use std::path::Path;

#[derive(Debug)]
pub struct ZksyncFlattenedSource;
impl ZksyncSourceProvider for ZksyncFlattenedSource {
fn zk_source(
&self,
args: &VerifyArgs,
context: &ZkVerificationContext,
) -> Result<(ZkSourceOutput, String, CodeFormat)> {
let metadata = context.project.settings.settings.metadata.as_ref();
//let bch = metadata.and_then(|m| m.bytecode_hash).unwrap_or_default();

// eyre::ensure!(
// bch == foundry_compilers::zksolc::settings::BytecodeHash::Keccak256,
// "When using flattened source with zksync, bytecodeHash must be set to keccak256 because Etherscan uses Keccak256 in its Compiler Settings when re-compiling your code. BytecodeHash is currently: {}. Hint: Set the bytecodeHash key in your foundry.toml :)",
// bch,
// );
println!("before source");
let source = context
.project
.paths
.clone()
.with_language::<SolcLanguage>()
.flatten(&context.target_path)
.wrap_err("Failed to flatten contract")?;


println!("fails gere?:");


if !args.force {
// solc dry run of flattened code
self.zk_check_flattened(
source.clone(),
&context.compiler_version,
&context.target_path,
)
.map_err(|err| {
eyre::eyre!(
"Failed to compile the flattened code locally: `{}`\
To skip this solc dry, have a look at the `--force` flag of this command.",
err
)
})?;
}

let relative_path = context
.target_path
.strip_prefix(context.project.root())
.unwrap_or(context.target_path.as_path())
.display()
.to_string();
let normalized_path = relative_path.replace('\\', "/");

// Format the name as <path>/<file>:<contract_name>
let name = format!("{}:{}", normalized_path, context.target_name);

Ok((ZkSourceOutput::FlattenedSource(source), name, CodeFormat::SingleFile))
}
}

impl ZksyncFlattenedSource {
/// Attempts to compile the flattened content locally with the zksolc and solc compiler
/// versions.
///
/// This expects the completely flattened `content´ and will try to compile it using the
/// provided compiler. If the compiler is missing it will be installed.
///
/// # Errors
///
/// If it failed to install a missing solc compiler
///
/// # Exits
///
/// If the zksolc compiler output contains errors, this could either be due to a bug in the
/// flattening code or could to conflict in the flattened code, for example if there are
/// multiple interfaces with the same name.
fn zk_check_flattened(
&self,
content: impl Into<String>,
compiler_version: &ZkVersion,
contract_path: &Path,
) -> Result<()> {
let solc_version = strip_build_meta(compiler_version.solc.clone());
let zksolc_version = strip_build_meta(compiler_version.zksolc.clone());
println!("zksolc version??? {}", zksolc_version);
println!("solc version??? {}", solc_version);

let zksolc = ZkSolc::find_installed_version(&zksolc_version)?
.unwrap_or(ZkSolc::blocking_install(&zksolc_version)?);
println!("do we get here?");
let input = ZkSolcVersionedInput {
input: ZkSolcInput {
language: SolcLanguage::Solidity,
sources: Sources::from([("contract.sol".into(), Source::new(content))]),
..Default::default()
},
solc_version: solc_version.clone(),
cli_settings: CliSettings::default(),
};
//let solc_version2 = format!("", &solc_version);
let zksync_solc = ZkSolc::solc_blocking_install("0.8.17".into())?;
let ss = Solc::new(zksync_solc)?;
let solc_compiler = SolcCompiler::Specific(ss);
println!("how about here?");
// let mut solc_compiler = if compiler_version.is_zksync_solc {
// // AutoDetect given a specific solc version on the input, will
// // find or install the solc version
// println!("auto detecht");
// let solc = Solc::find_or_install(&solc_version)?;
// SolcCompiler::Specific(solc)
// } else {
// println!("specific");
// println!("solc version??? {}", solc_version);
// let solc = Solc::find_or_install(&solc_version)?;
// SolcCompiler::Specific(solc)
// };

let zksolc_compiler = ZkSolcCompiler { zksolc: zksolc.zksolc, solc: solc_compiler };
println!("zksolc compiler??? {:?}", zksolc_compiler);
let out = zksolc_compiler.zksync_compile(&input)?;
if out.has_error() {
if !out.errors.is_empty() {
for error in &out.errors {
// Assuming `error` has a `message` or similar field for error details
error!("Compilation error: {:?}", error);
}
}
let mut o = ZkAggregatedCompilerOutput::default();
o.extend(solc_version, raw_build_info_new(&input, &out, false)?, out);
let diags = o.diagnostics(&[], &[], Default::default());

eyre::bail!(
"\
Failed to compile the flattened code locally.
This could be a bug, please inspect the output of `forge flatten {}` and report an issue.
To skip this zksolc dry, pass `--force`.
Diagnostics: {diags}",
contract_path.display()
);
}

Ok(())
}
}

/// Strips [BuildMetadata] from the [Version]
///
/// **Note:** this is only for local compilation as a dry run, therefore this will return a
/// sanitized variant of the specific version so that it can be installed. This is merely
/// intended to ensure the flattened code can be compiled without errors.
fn strip_build_meta(version: Version) -> Version {
if version.build != BuildMetadata::EMPTY {
Version::new(version.major, version.minor, version.patch)
} else {
version
}
}
66 changes: 56 additions & 10 deletions crates/verify/src/zksync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@ use alloy_primitives::hex;
use eyre::{eyre, Result};
use foundry_common::{abi::encode_function_args, retry::Retry};
use foundry_compilers::zksolc::input::StandardJsonCompilerInput;
use foundry_block_explorers::verify::CodeFormat;
use futures::FutureExt;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, Serializer};
use std::{fmt::Debug, thread::sleep, time::Duration};

pub mod standard_json;
pub mod flatten;

#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct ZkVerificationProvider;

pub enum ZkSourceOutput {
StandardJson(StandardJsonCompilerInput),
FlattenedSource(String),
}

pub trait ZksyncSourceProvider: Send + Sync + Debug {
fn zk_source(
&self,
args: &VerifyArgs,
context: &ZkVerificationContext,
) -> Result<(StandardJsonCompilerInput, String)>;
) -> Result<(ZkSourceOutput, String, CodeFormat)>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -124,17 +132,21 @@ impl VerificationProvider for ZkVerificationProvider {
}

impl ZkVerificationProvider {
fn source_provider(&self) -> Box<dyn ZksyncSourceProvider> {
Box::new(standard_json::ZksyncStandardJsonSource)
fn source_provider(&self, args: &VerifyArgs) -> Box<dyn ZksyncSourceProvider> {
if args.flatten {
Box::new(flatten::ZksyncFlattenedSource)
} else {
Box::new(standard_json::ZksyncStandardJsonSource)
}
}
async fn prepare_request(
&mut self,
args: &VerifyArgs,
context: &CompilerVerificationContext,
) -> Result<VerifyContractRequest> {
let (source, contract_name) = if let CompilerVerificationContext::ZkSolc(context) = context
let (source_output, contract_name, code_format) = if let CompilerVerificationContext::ZkSolc(context) = context
{
self.source_provider().zk_source(context)?
self.source_provider(args).zk_source(args, context)?
} else {
eyre::bail!("Unsupported compiler context: only ZkSolc is supported");
};
Expand All @@ -152,22 +164,38 @@ impl ZkVerificationProvider {
));
}
};
let optimization_used = source.settings.optimizer.enabled.unwrap_or(false);

let (source_code, optimization_used) = match source_output {
ZkSourceOutput::StandardJson(compiler_input) => {
// Assuming the `StandardJsonCompilerInput` has `settings` field or similar
let optimization_used = compiler_input.settings.optimizer.enabled.unwrap_or(false);
(SourceCode::StandardJson(compiler_input), optimization_used)
}
ZkSourceOutput::FlattenedSource(flattened_source) => {
// Flattened source does not contain optimization details
(SourceCode::Flattened(flattened_source), false)
}
};
// TODO: investigate runs better. Currently not included in the verification request.
let _runs = args.num_of_optimizations.map(|n| n as u64);
let constructor_args = self.constructor_args(args, context).await?.unwrap_or_default();

let request = VerifyContractRequest {
contract_address: args.address.to_string(),
source_code: source,
code_format: "solidity-standard-json-input".to_string(),
source_code: source_code,
code_format: match code_format {
CodeFormat::StandardJsonInput => "solidity-standard-json-input".to_string(),
CodeFormat::SingleFile => "solidity-single-file".to_string(),
},
contract_name,
compiler_version: solc_version,
zk_compiler_version,
constructor_arguments: constructor_args,
optimization_used,
};

warn!("request: {:?}", request);

Ok(request)
}

Expand Down Expand Up @@ -336,12 +364,30 @@ impl ContractVerificationStatusResponse {
}
}

#[derive(Debug)]
pub enum SourceCode {
StandardJson(StandardJsonCompilerInput),
Flattened(String),
}

impl Serialize for SourceCode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
SourceCode::StandardJson(input) => input.serialize(serializer),
SourceCode::Flattened(flattened_source) => flattened_source.serialize(serializer),
}
}
}

#[derive(Debug, Serialize)]
pub struct VerifyContractRequest {
#[serde(rename = "contractAddress")]
contract_address: String,
#[serde(rename = "sourceCode")]
source_code: StandardJsonCompilerInput,
source_code: SourceCode,
#[serde(rename = "codeFormat")]
code_format: String,
#[serde(rename = "contractName")]
Expand Down
Loading

0 comments on commit 56dd4d1

Please sign in to comment.