Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: pull in new commits #38

Merged
merged 6 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @hedgar2017
* @nbaztec @elfedy @Karrq @Jrigada @dutterbutter @hedgar2017
12 changes: 6 additions & 6 deletions crates/artifacts/zksolc/src/output_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ use std::collections::HashSet;
#[derive(Debug, Default, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct OutputSelection {
/// Only the 'all' wildcard is available for robustness reasons.
#[serde(rename = "*", skip_serializing_if = "Option::is_none")]
pub all: Option<FileOutputSelection>,
#[serde(rename = "*")]
pub all: FileOutputSelection,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct FileOutputSelection {
/// The per-file output selections.
#[serde(rename = "", skip_serializing_if = "Option::is_none")]
pub per_file: Option<HashSet<OutputSelectionFlag>>,
#[serde(rename = "")]
pub per_file: HashSet<OutputSelectionFlag>,
/// The per-contract output selections.
#[serde(rename = "*", skip_serializing_if = "Option::is_none")]
pub per_contract: Option<HashSet<OutputSelectionFlag>>,
#[serde(rename = "*")]
pub per_contract: HashSet<OutputSelectionFlag>,
}

///
Expand Down
24 changes: 22 additions & 2 deletions crates/compilers/src/compilers/zksolc/input.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::{settings::ZkSolcSettings, ZkSettings};
use super::{
settings::{ZkSolcError, ZkSolcSettings, ZkSolcWarning},
ZkSettings,
};
use crate::{
compilers::{solc::SolcLanguage, CompilerInput},
solc,
Expand All @@ -8,6 +11,7 @@ use semver::Version;
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
collections::HashSet,
path::{Path, PathBuf},
};

Expand All @@ -33,7 +37,7 @@ impl CompilerInput for ZkSolcVersionedInput {
version: Version,
) -> Self {
let ZkSolcSettings { settings, cli_settings } = settings;
let input = ZkSolcInput { language, sources, settings }.sanitized(&version);
let input = ZkSolcInput::new(language, sources, settings).sanitized(&version);

Self { solc_version: version, input, cli_settings }
}
Expand Down Expand Up @@ -65,10 +69,18 @@ impl CompilerInput for ZkSolcVersionedInput {

/// Input type `zksolc` expects.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ZkSolcInput {
pub language: SolcLanguage,
pub sources: Sources,
pub settings: ZkSettings,
// For `zksolc` versions <1.5.7, suppressed warnings / errors were specified on the same level
// as `settings`. For `zksolc` 1.5.7+, they are specified inside `settings`. Since we want to
// support both options at the time, we duplicate fields from `settings` here.
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
pub suppressed_warnings: HashSet<ZkSolcWarning>,
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
pub suppressed_errors: HashSet<ZkSolcError>,
}

/// Default `language` field is set to `"Solidity"`.
Expand All @@ -78,11 +90,19 @@ impl Default for ZkSolcInput {
language: SolcLanguage::Solidity,
sources: Sources::default(),
settings: ZkSettings::default(),
suppressed_warnings: HashSet::default(),
suppressed_errors: HashSet::default(),
}
}
}

impl ZkSolcInput {
fn new(language: SolcLanguage, sources: Sources, settings: ZkSettings) -> Self {
let suppressed_warnings = settings.suppressed_warnings.clone();
let suppressed_errors = settings.suppressed_errors.clone();
Self { language, sources, settings, suppressed_warnings, suppressed_errors }
}

/// Removes the `base` path from all source files
pub fn strip_prefix(&mut self, base: impl AsRef<Path>) {
let base = base.as_ref();
Expand Down
7 changes: 3 additions & 4 deletions crates/compilers/src/compilers/zksolc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ use std::os::unix::fs::PermissionsExt;

pub mod input;
pub mod settings;
pub use settings::ZkSettings;
pub use settings::ZkSolcSettings;
pub use settings::{ZkSettings, ZkSolcSettings};

pub const ZKSOLC: &str = "zksolc";
pub const ZKSYNC_SOLC_RELEASE: Version = Version::new(1, 0, 1);
pub const ZKSOLC_VERSION: Version = Version::new(1, 5, 4);
pub const ZKSOLC_VERSION: Version = Version::new(1, 5, 7);

#[derive(Debug, Clone, Serialize)]
enum ZkSolcOS {
Expand Down Expand Up @@ -336,7 +335,7 @@ impl ZkSolc {
pub fn solc_available_versions() -> Vec<Version> {
let mut ret = vec![];
let min_max_patch_by_minor_versions =
vec![(4, 12, 26), (5, 0, 17), (6, 0, 12), (7, 0, 6), (8, 0, 27)];
vec![(4, 12, 26), (5, 0, 17), (6, 0, 12), (7, 0, 6), (8, 0, 28)];
for (minor, min_patch, max_patch) in min_max_patch_by_minor_versions {
for i in min_patch..=max_patch {
ret.push(Version::new(0, minor, i));
Expand Down
51 changes: 50 additions & 1 deletion crates/compilers/src/compilers/zksolc/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,43 @@ use foundry_compilers_artifacts::{
use semver::Version;
use serde::{Deserialize, Serialize};
use std::{
collections::BTreeSet,
collections::{BTreeSet, HashSet},
fmt,
path::{Path, PathBuf},
str::FromStr,
};

///
/// The Solidity compiler codegen.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Codegen {
/// The Yul IR.
#[default]
Yul,
/// The EVM legacy assembly IR.
EVMLA,
}

/// `zksolc` warnings that can be suppressed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum ZkSolcWarning {
/// `txorigin` warning: Using `tx.origin` in place of `msg.sender`.
TxOrigin,
}

/// `zksolc` errors that can be suppressed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum ZkSolcError {
/// `sendtransfer` error: Using `send()` or `transfer()` methods on `address payable` instead
/// of `call()`.
SendTransfer,
}

/// zksolc standard json input settings. See:
/// https://docs.zksync.io/zk-stack/components/compiler/toolchain/solidity.html#standard-json for differences
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand All @@ -25,6 +56,9 @@ pub struct ZkSettings {
/// false by default.
#[serde(rename = "viaIR", default, skip_serializing_if = "Option::is_none")]
pub via_ir: Option<bool>,
/// The Solidity codegen.
#[serde(default)]
pub codegen: Codegen,
// TODO: era-compiler-solidity uses a BTreeSet of strings. In theory the serialization
// should be the same but maybe we should double check
#[serde(default, skip_serializing_if = "Vec::is_empty")]
Expand Down Expand Up @@ -66,6 +100,12 @@ pub struct ZkSettings {
/// Whether to compile via EVM assembly.
#[serde(default, rename = "forceEVMLA")]
pub force_evmla: bool,
/// Suppressed `zksolc` warnings.
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
pub suppressed_warnings: HashSet<ZkSolcWarning>,
/// Suppressed `zksolc` errors.
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
pub suppressed_errors: HashSet<ZkSolcError>,
}

// Analogous to SolcSettings for Zk compiler
Expand Down Expand Up @@ -143,6 +183,9 @@ impl Default for ZkSettings {
enable_eravm_extensions: false,
llvm_options: Default::default(),
force_evmla: false,
codegen: Default::default(),
suppressed_errors: Default::default(),
suppressed_warnings: Default::default(),
}
}
}
Expand All @@ -168,6 +211,9 @@ impl CompilerSettings for ZkSolcSettings {
enable_eravm_extensions,
llvm_options,
force_evmla,
codegen,
suppressed_warnings,
suppressed_errors,
},
..
} = self;
Expand All @@ -183,6 +229,9 @@ impl CompilerSettings for ZkSolcSettings {
&& *enable_eravm_extensions == other.settings.enable_eravm_extensions
&& *llvm_options == other.settings.llvm_options
&& *force_evmla == other.settings.force_evmla
&& *codegen == other.settings.codegen
&& *suppressed_warnings == other.settings.suppressed_warnings
&& *suppressed_errors == other.settings.suppressed_errors
}

fn with_remappings(mut self, remappings: &[Remapping]) -> Self {
Expand Down
128 changes: 126 additions & 2 deletions crates/compilers/tests/zksync.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
use std::{collections::HashMap, fs, path::PathBuf, str::FromStr};
use std::{
collections::{HashMap, HashSet},
fs,
path::PathBuf,
str::FromStr,
};

use foundry_compilers::{
buildinfo::BuildInfo,
cache::CompilerCache,
project_util::*,
resolver::parse::SolData,
zksolc::{input::ZkSolcInput, ZkSolcCompiler, ZkSolcSettings},
zksolc::{
input::ZkSolcInput,
settings::{ZkSolcError, ZkSolcWarning},
ZkSolc, ZkSolcCompiler, ZkSolcSettings,
},
zksync::{self, artifact_output::zk::ZkArtifactOutput},
Graph, ProjectBuilder, ProjectPathsConfig,
};
Expand Down Expand Up @@ -42,6 +51,121 @@ fn zksync_can_compile_dapp_sample() {
assert_eq!(cache, updated_cache);
}

fn test_zksync_can_compile_contract_with_suppressed_errors(compiler: ZkSolcCompiler) {
let _ = tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.try_init()
.ok();
let mut project = TempProject::<ZkSolcCompiler, ZkArtifactOutput>::dapptools().unwrap();
project.project_mut().compiler = compiler;

project
.add_source(
"Erroneous",
r#"
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.10;
contract Erroneous {
function distribute(address payable recipient) public {
recipient.send(1);
recipient.transfer(1);
}
}
"#,
)
.unwrap();

let compiled = zksync::project_compile(project.project()).unwrap();
assert!(compiled.has_compiler_errors());

project.project_mut().settings.settings.suppressed_errors =
HashSet::from([ZkSolcError::SendTransfer]);

let compiled = zksync::project_compile(project.project()).unwrap();
compiled.assert_success();
assert!(compiled.find_first("Erroneous").is_some());
}

#[test]
fn zksync_can_compile_contract_with_suppressed_errors() {
test_zksync_can_compile_contract_with_suppressed_errors(ZkSolcCompiler::default());
}

#[test]
fn zksync_pre_1_5_7_can_compile_contract_with_suppressed_errors() {
let compiler = ZkSolcCompiler {
zksolc: ZkSolc::get_path_for_version(&semver::Version::new(1, 5, 6)).unwrap(),
solc: Default::default(),
};
test_zksync_can_compile_contract_with_suppressed_errors(compiler);
}

fn test_zksync_can_compile_contract_with_suppressed_warnings(compiler: ZkSolcCompiler) {
let _ = tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.try_init()
.ok();
let mut project = TempProject::<ZkSolcCompiler, ZkArtifactOutput>::dapptools().unwrap();
project.project_mut().compiler = compiler;

project
.add_source(
"Warning",
r#"
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.10;
contract Warning {
function test() public view {
require(tx.origin != address(0), "what");
}
}
"#,
)
.unwrap();

let compiled = zksync::project_compile(project.project()).unwrap();
compiled.assert_success();
assert!(
compiled
.compiler_output
.errors
.iter()
.any(|err| err.is_warning() && err.message.contains("tx.origin")),
"{:#?}",
compiled.compiler_output.errors
);

project.project_mut().settings.settings.suppressed_warnings =
HashSet::from([ZkSolcWarning::TxOrigin]);

let compiled = zksync::project_compile(project.project()).unwrap();
compiled.assert_success();
assert!(compiled.find_first("Warning").is_some());
assert!(
!compiled
.compiler_output
.errors
.iter()
.any(|err| err.is_warning() && err.message.contains("tx.origin")),
"{:#?}",
compiled.compiler_output.errors
);
}

#[test]
fn zksync_can_compile_contract_with_suppressed_warnings() {
test_zksync_can_compile_contract_with_suppressed_warnings(ZkSolcCompiler::default());
}

#[test]
fn zksync_pre_1_5_7_can_compile_contract_with_suppressed_warnings() {
let compiler = ZkSolcCompiler {
zksolc: ZkSolc::get_path_for_version(&semver::Version::new(1, 5, 6)).unwrap(),
solc: Default::default(),
};
test_zksync_can_compile_contract_with_suppressed_warnings(compiler);
}

#[test]
fn zksync_can_compile_dapp_detect_changes_in_libs() {
let _ = tracing_subscriber::fmt()
Expand Down