Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
23 changes: 4 additions & 19 deletions crates/llvm-context/src/optimizer/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,7 @@ impl Settings {
/// Creates settings from a CLI optimization parameter.
pub fn try_from_cli(value: char) -> anyhow::Result<Self> {
Ok(match value {
'0' => Self::new(
// The middle-end optimization level.
inkwell::OptimizationLevel::None,
// The middle-end size optimization level.
SizeLevel::Zero,
// The back-end optimization level.
inkwell::OptimizationLevel::None,
),
'0' => Self::none(),
'1' => Self::new(
inkwell::OptimizationLevel::Less,
SizeLevel::Zero,
Expand All @@ -84,23 +77,14 @@ impl Settings {
// The back-end does not currently distinguish between O1, O2, and O3.
inkwell::OptimizationLevel::Default,
),
'3' => Self::new(
inkwell::OptimizationLevel::Aggressive,
SizeLevel::Zero,
inkwell::OptimizationLevel::Aggressive,
),
'3' => Self::cycles(),
's' => Self::new(
// The middle-end optimization level is ignored when SizeLevel is set.
inkwell::OptimizationLevel::Default,
SizeLevel::S,
inkwell::OptimizationLevel::Aggressive,
),
'z' => Self::new(
// The middle-end optimization level is ignored when SizeLevel is set.
inkwell::OptimizationLevel::Default,
SizeLevel::Z,
inkwell::OptimizationLevel::Aggressive,
),
'z' => Self::size(),
char => anyhow::bail!("Unexpected optimization option '{}'", char),
})
}
Expand All @@ -126,6 +110,7 @@ impl Settings {
/// Returns the settings for the optimal size.
pub fn size() -> Self {
Self::new(
// The middle-end optimization level is ignored when SizeLevel is set.
inkwell::OptimizationLevel::Default,
SizeLevel::Z,
inkwell::OptimizationLevel::Aggressive,
Expand Down
18 changes: 18 additions & 0 deletions crates/resolc/src/cli_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::{
process::{Command, Stdio},
};

use revive_solc_json_interface::SolcStandardJsonOutput;

use crate::SolcCompiler;

/// The simple Solidity contract test fixture path.
Expand Down Expand Up @@ -158,6 +160,22 @@ pub fn assert_command_failure(result: &CommandResult, error_message_prefix: &str
);
}

/// Asserts that the standard JSON output has at least one error with the given `error_message`.
pub fn assert_standard_json_errors_contain(output: &SolcStandardJsonOutput, error_message: &str) {
assert!(
output
.errors
.iter()
.any(|error| error.is_error() && error.message.contains(error_message)),
"the standard JSON output should contain the error message `{error_message}`"
);
}

/// Converts valid JSON text to `SolcStandardJsonOutput`.
pub fn to_solc_standard_json_output(json_text: &str) -> SolcStandardJsonOutput {
serde_json::from_str(json_text).unwrap()
}

/// Gets the absolute path of a file. The `relative_path` must
/// be relative to the `resolc` crate.
/// Panics if the path does not exist or is not an accessible file.
Expand Down
70 changes: 45 additions & 25 deletions crates/resolc/src/resolc/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
use std::path::Path;
use std::path::PathBuf;

use clap::Parser;
use clap::{command, parser::ValueSource, ArgMatches, CommandFactory, Parser};

Check failure on line 7 in crates/resolc/src/resolc/arguments.rs

View workflow job for this annotation

GitHub Actions / test

unused import: `command`

Check warning on line 7 in crates/resolc/src/resolc/arguments.rs

View workflow job for this annotation

GitHub Actions / build

unused import: `command`

Check warning on line 7 in crates/resolc/src/resolc/arguments.rs

View workflow job for this annotation

GitHub Actions / build / build (x86_64-pc-windows-msvc)

unused import: `command`

Check warning on line 7 in crates/resolc/src/resolc/arguments.rs

View workflow job for this annotation

GitHub Actions / build / build-wasm

unused import: `command`
use path_slash::PathExt;
use resolc::SolcCompiler;

Check failure on line 9 in crates/resolc/src/resolc/arguments.rs

View workflow job for this annotation

GitHub Actions / build

unresolved import `resolc::SolcCompiler`

Check failure on line 9 in crates/resolc/src/resolc/arguments.rs

View workflow job for this annotation

GitHub Actions / build / build-wasm

unresolved import `resolc::SolcCompiler`
use revive_common::MetadataHash;
use revive_solc_json_interface::SolcStandardJsonOutputError;
use revive_solc_json_interface::{
PolkaVMDefaultHeapMemorySize, PolkaVMDefaultStackMemorySize, SolcStandardJsonOutputError,
};

/// Compiles the provided Solidity input files (or use the standard input if no files
/// are given or "-" is specified as a file name). Outputs the components based on the
Expand Down Expand Up @@ -57,8 +60,8 @@

/// Set the optimization parameter -O[0 | 1 | 2 | 3 | s | z].
/// Use `3` for best performance and `z` for minimal size.
#[arg(short = 'O', long = "optimization")]
pub optimization: Option<char>,
#[arg(short = 'O', long = "optimization", default_value = "z")]
pub optimization: char,

/// Disable the `solc` optimizer.
/// Use it if your project uses the `MSIZE` instruction, or in other cases.
Expand All @@ -69,8 +72,8 @@
/// Specify the path to the `solc` executable. By default, the one in `${PATH}` is used.
/// Yul mode: `solc` is used for source code validation, as `resolc` itself assumes that the input Yul is valid.
/// LLVM IR mode: `solc` is unused.
#[arg(long = "solc")]
pub solc: Option<String>,
#[arg(long = "solc", default_value = SolcCompiler::DEFAULT_EXECUTABLE_NAME)]
pub solc: String,

/// The EVM target version to generate IR for.
/// See https://github.com/paritytech/revive/blob/main/crates/common/src/evm_version.rs for reference.
Expand Down Expand Up @@ -116,9 +119,8 @@

/// Set the metadata hash type.
/// Available types: `none`, `ipfs`, `keccak256`.
/// The default is `keccak256`.
#[arg(long)]
pub metadata_hash: Option<String>,
#[arg(long, default_value_t = MetadataHash::Keccak256)]
pub metadata_hash: MetadataHash,

/// Output PolkaVM assembly of the contracts.
#[arg(long = "asm")]
Expand Down Expand Up @@ -185,9 +187,9 @@
/// You are incentiviced to keep this value as small as possible:
/// 1.Increasing the heap size will increase startup costs.
/// 2.The heap size contributes to the total memory size a contract can use,
/// which includes the contracts code size
#[arg(long = "heap-size")]
pub heap_size: Option<u32>,
/// which includes the contracts code size.
#[arg(long = "heap-size", default_value_t = PolkaVMDefaultHeapMemorySize)]
pub heap_size: u32,

/// The contracts total stack size in bytes.
///
Expand All @@ -198,16 +200,17 @@
/// eventually revert execution at runtime!
///
/// You are incentiviced to keep this value as small as possible:
/// 1.Increasing the heap size will increase startup costs.
/// 1.Increasing the stack size will increase startup costs.
/// 2.The stack size contributes to the total memory size a contract can use,
/// which includes the contracts code size
#[arg(long = "stack-size")]
pub stack_size: Option<u32>,
/// which includes the contracts code size.
#[arg(long = "stack-size", default_value_t = PolkaVMDefaultStackMemorySize)]
pub stack_size: u32,
}

impl Arguments {
/// Validates the arguments.
pub fn validate(&self) -> Vec<SolcStandardJsonOutputError> {
let argument_matches = Arguments::command().get_matches();
let mut messages = Vec::new();

if self.version && std::env::args().count() > 2 {
Expand All @@ -226,9 +229,13 @@
));
}

if self.metadata_hash == Some(MetadataHash::IPFS.to_string()) {
if self.metadata_hash == MetadataHash::IPFS {
messages.push(SolcStandardJsonOutputError::new_error(
"`IPFS` metadata hash type is not supported. Please use `keccak256` instead.",
format!(
"`{}` metadata hash type is not supported. Please use `{}` instead.",
MetadataHash::IPFS,
MetadataHash::Keccak256,
),
None,
None,
));
Expand Down Expand Up @@ -350,34 +357,34 @@
}
if self.disable_solc_optimizer {
messages.push(SolcStandardJsonOutputError::new_error(
"Disabling the solc optimizer must specified in standard JSON input settings.",
"Disabling the solc optimizer must be specified in standard JSON input settings.",
None,
None,
));
}
if self.optimization.is_some() {
if !Self::came_from_default_value("optimization", &argument_matches) {
messages.push(SolcStandardJsonOutputError::new_error(
"LLVM optimizations must specified in standard JSON input settings.",
"LLVM optimizations must be specified in standard JSON input settings.",
None,
None,
));
}
if self.metadata_hash.is_some() {
if !Self::came_from_default_value("metadata_hash", &argument_matches) {
messages.push(SolcStandardJsonOutputError::new_error(
"Metadata hash mode must specified in standard JSON input settings.",
"Metadata hash mode must be specified in standard JSON input settings.",
None,
None,
));
}

if self.heap_size.is_some() {
if !Self::came_from_default_value("heap_size", &argument_matches) {
messages.push(SolcStandardJsonOutputError::new_error(
"Heap size must be specified in standard JSON input polkavm memory settings.",
None,
None,
));
}
if self.stack_size.is_some() {
if !Self::came_from_default_value("stack_size", &argument_matches) {
messages.push(SolcStandardJsonOutputError::new_error(
"Stack size must be specified in standard JSON input polkavm memory settings.",
None,
Expand All @@ -403,6 +410,19 @@
messages
}

/// Checks whether the value from the argument with the given `argument_id`
/// came from the preconfigured default value.
///
/// This can be used for determining if a user has explicitly set a value for
/// an argument, even if it is the same value as the default one.
///
/// Panics if the `id` is not a valid argument id.
fn came_from_default_value(argument_id: &str, argument_matches: &ArgMatches) -> bool {
argument_matches
.value_source(argument_id)
.is_some_and(|source| source == ValueSource::DefaultValue)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference and examples, see value_source and default_value.


/// Returns remappings from input paths.
pub fn split_input_files_and_remappings(
&self,
Expand Down
29 changes: 9 additions & 20 deletions crates/resolc/src/resolc/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
//! Solidity to PolkaVM compiler binary.

use std::str::FromStr;
use std::{io::Write, path::PathBuf};

use clap::error::ErrorKind;
use resolc::Process;
use revive_common::{
deserialize_from_str, EVMVersion, MetadataHash, EXIT_CODE_FAILURE, EXIT_CODE_SUCCESS,
};
use revive_common::{deserialize_from_str, EVMVersion, EXIT_CODE_FAILURE, EXIT_CODE_SUCCESS};
use revive_llvm_context::{initialize_llvm, DebugConfig, OptimizerSettings, PolkaVMTarget};
use revive_solc_json_interface::{
ResolcWarning, SolcStandardJsonInputSettingsPolkaVMMemory,
Expand All @@ -32,7 +29,7 @@ fn main() -> anyhow::Result<()> {

let is_standard_json = arguments.standard_json.is_some();
let mut messages = arguments.validate();
if messages.iter().all(|error| error.severity != "error") {
if messages.iter().all(|error| !error.is_error()) {
if !is_standard_json {
std::io::stderr()
.write_all(
Expand Down Expand Up @@ -157,11 +154,7 @@ fn main_inner(
}
#[cfg(not(target_os = "emscripten"))]
{
resolc::SolcCompiler::new(
arguments
.solc
.unwrap_or_else(|| resolc::SolcCompiler::DEFAULT_EXECUTABLE_NAME.to_owned()),
)?
resolc::SolcCompiler::new(arguments.solc)?
}
};

Expand All @@ -170,20 +163,16 @@ fn main_inner(
None => None,
};

let mut optimizer_settings = match arguments.optimization {
Some(mode) => OptimizerSettings::try_from_cli(mode)?,
None => OptimizerSettings::size(),
};
let mut optimizer_settings = OptimizerSettings::try_from_cli(arguments.optimization)?;
optimizer_settings.is_verify_each_enabled = arguments.llvm_verify_each;
optimizer_settings.is_debug_logging_enabled = arguments.llvm_debug_logging;

let metadata_hash = match arguments.metadata_hash {
Some(ref hash_type) => MetadataHash::from_str(hash_type.as_str())?,
None => MetadataHash::Keccak256,
};
let metadata_hash = arguments.metadata_hash;

let memory_config =
SolcStandardJsonInputSettingsPolkaVMMemory::new(arguments.heap_size, arguments.stack_size);
let memory_config = SolcStandardJsonInputSettingsPolkaVMMemory::new(
Some(arguments.heap_size),
Some(arguments.stack_size),
);

let build = if arguments.yul {
resolc::yul(
Expand Down
Loading
Loading