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

[wip] feat: compilation restrictions #8668

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
53 changes: 24 additions & 29 deletions Cargo.lock

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

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ foundry-linking = { path = "crates/linking" }

# solc & compilation utilities
foundry-block-explorers = { version = "0.7.3", default-features = false }
foundry-compilers = { version = "0.11.1", default-features = false }
foundry-compilers = { version = "0.11", default-features = false }
foundry-fork-db = "0.3"
solang-parser = "=0.3.3"

Expand Down Expand Up @@ -276,7 +276,7 @@ soldeer = "=0.3.4"
proptest = "1"
comfy-table = "7"

# [patch.crates-io]
[patch.crates-io]
# alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" }
# alloy-contract = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" }
# alloy-eips = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" }
Expand All @@ -300,3 +300,4 @@ comfy-table = "7"
# alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" }
# alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" }
# alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" }
foundry-compilers = { git = "https://github.com/foundry-rs/compilers", rev = "5b42d05" }
4 changes: 2 additions & 2 deletions crates/cast/bin/cmd/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use foundry_compilers::{
artifacts::{ConfigurableContractArtifact, StorageLayout},
compilers::{
solc::{Solc, SolcCompiler},
Compiler, CompilerSettings,
Compiler,
},
Artifact, Project,
};
Expand Down Expand Up @@ -288,7 +288,7 @@ fn print_storage(layout: StorageLayout, values: Vec<StorageValue>, pretty: bool)

fn add_storage_layout_output<C: Compiler>(project: &mut Project<C>) {
project.artifacts.additional_values.storage_layout = true;
project.settings.update_output_selection(|selection| {
project.update_output_selection(|selection| {
selection.0.values_mut().for_each(|contract_selection| {
contract_selection
.values_mut()
Expand Down
76 changes: 76 additions & 0 deletions crates/config/src/compilation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::{filter::GlobMatcher, serde_helpers};
use foundry_compilers::{
artifacts::EvmVersion,
multi::{MultiCompilerRestrictions, MultiCompilerSettings},
settings::VyperRestrictions,
solc::{EvmVersionRestriction, SolcRestrictions},
RestrictionsWithVersion,
};
use semver::VersionReq;
use serde::{Deserialize, Serialize};

/// Keeps possible overrides for default settings which users may configure to construct additional
/// settings profile.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SettingsOverrides {
pub name: String,
via_ir: Option<bool>,
#[serde(default, with = "serde_helpers::display_from_str_opt")]
evm_version: Option<EvmVersion>,
optimizer: Option<bool>,
optimizer_runs: Option<usize>,
}

impl SettingsOverrides {
/// Applies the overrides to the given settings.
pub fn apply(&self, settings: &mut MultiCompilerSettings) {
if let Some(via_ir) = self.via_ir {
settings.solc.via_ir = Some(via_ir);
}

if let Some(evm_version) = self.evm_version {
settings.solc.evm_version = Some(evm_version);
settings.vyper.evm_version = Some(evm_version);
}

if let Some(enabled) = self.optimizer {
settings.solc.optimizer.enabled = Some(enabled);
}

if let Some(optimizer_runs) = self.optimizer_runs {
settings.solc.optimizer.runs = Some(optimizer_runs);
}
}
}

/// Restrictions for compilation of given paths.
///
/// Only purpose of this type is to accept user input to later construct
/// `RestrictionsWithVersion<MultiCompilerRestrictions>`.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct CompilationRestrictions {
pub paths: GlobMatcher,
version: Option<VersionReq>,
via_ir: Option<bool>,
min_optimizer_runs: Option<usize>,
max_optimizer_runs: Option<usize>,
#[serde(flatten)]
evm_version: EvmVersionRestriction,
}

impl From<CompilationRestrictions> for RestrictionsWithVersion<MultiCompilerRestrictions> {
fn from(value: CompilationRestrictions) -> Self {
Self {
restrictions: MultiCompilerRestrictions {
solc: SolcRestrictions {
evm_version: value.evm_version,
via_ir: value.via_ir,
min_optimizer_runs: value.min_optimizer_runs,
max_optimizer_runs: value.max_optimizer_runs,
},
vyper: VyperRestrictions { evm_version: value.evm_version },
},
version: value.version,
}
}
}
76 changes: 72 additions & 4 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ use foundry_compilers::{
Compiler,
},
error::SolcError,
multi::{MultiCompilerParsedSource, MultiCompilerRestrictions},
solc::{CliSettings, SolcSettings},
ConfigurableArtifacts, Project, ProjectPathsConfig, VyperLanguage,
ConfigurableArtifacts, Graph, Project, ProjectPathsConfig, RestrictionsWithVersion,
VyperLanguage,
};
use inflector::Inflector;
use regex::Regex;
Expand All @@ -43,7 +45,7 @@ use semver::Version;
use serde::{Deserialize, Serialize, Serializer};
use std::{
borrow::Cow,
collections::HashMap,
collections::{BTreeMap, HashMap},
fs,
path::{Path, PathBuf},
str::FromStr,
Expand Down Expand Up @@ -115,6 +117,9 @@ use vyper::VyperConfig;
mod bind_json;
use bind_json::BindJsonConfig;

mod compilation;
use compilation::{CompilationRestrictions, SettingsOverrides};

/// Foundry configuration
///
/// # Defaults
Expand Down Expand Up @@ -469,6 +474,14 @@ pub struct Config {
#[serde(rename = "__warnings", default, skip_serializing)]
pub warnings: Vec<Warning>,

/// Additional settings profiles to use when compiling.
#[serde(default)]
pub additional_compiler_profiles: Vec<SettingsOverrides>,

/// Restrictions on compilation of certain files.
#[serde(default)]
pub compilation_restrictions: Vec<CompilationRestrictions>,

/// PRIVATE: This structure may grow, As such, constructing this structure should
/// _always_ be done using a public constructor or update syntax:
///
Expand Down Expand Up @@ -835,12 +848,65 @@ impl Config {
self.create_project(false, true)
}

/// Builds mapping with additional settings profiles.
fn additional_settings(
&self,
base: &MultiCompilerSettings,
) -> BTreeMap<String, MultiCompilerSettings> {
let mut map = BTreeMap::new();

for profile in &self.additional_compiler_profiles {
let mut settings = base.clone();
profile.apply(&mut settings);
map.insert(profile.name.clone(), settings);
}

map
}

/// Resolves globs and builds a mapping from individual source files to their restrictions
fn restrictions(
&self,
paths: &ProjectPathsConfig,
) -> Result<BTreeMap<PathBuf, RestrictionsWithVersion<MultiCompilerRestrictions>>, SolcError>
{
let mut map = BTreeMap::new();

let graph = Graph::<MultiCompilerParsedSource>::resolve(paths)?;
let (sources, _) = graph.into_sources();

for res in &self.compilation_restrictions {
for source in sources.keys().filter(|path| {
if res.paths.is_match(path) {
true
} else if let Ok(path) = path.strip_prefix(&paths.root) {
res.paths.is_match(path)
} else {
false
}
}) {
let res: RestrictionsWithVersion<_> = res.clone().into();
if !map.contains_key(source) {
map.insert(source.clone(), res);
} else {
map.get_mut(source.as_path()).unwrap().merge(res);
}
}
}

Ok(map)
}

/// Creates a [Project] with the given `cached` and `no_artifacts` flags
pub fn create_project(&self, cached: bool, no_artifacts: bool) -> Result<Project, SolcError> {
let settings = self.compiler_settings()?;
let paths = self.project_paths();
let mut builder = Project::builder()
.artifacts(self.configured_artifacts_handler())
.paths(self.project_paths())
.settings(self.compiler_settings()?)
.additional_settings(self.additional_settings(&settings))
.restrictions(self.restrictions(&paths)?)
.settings(settings)
.paths(paths)
.ignore_error_codes(self.ignored_error_codes.iter().copied().map(Into::into))
.ignore_paths(self.ignored_file_paths.clone())
.set_compiler_severity_filter(if self.deny_warnings {
Expand Down Expand Up @@ -2182,6 +2248,8 @@ impl Default for Config {
eof_version: None,
alphanet: false,
transaction_timeout: 120,
additional_compiler_profiles: Default::default(),
compilation_restrictions: vec![],
_non_exhaustive: (),
}
}
Expand Down
Loading
Loading