Add basic solc model checker options (#1258)
* Add basic solc model checker options * Changelog entry * review 1 * chore: fmt Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
parent
b21d7b2b42
commit
eb94e53d1f
|
@ -121,6 +121,8 @@
|
||||||
`enum BytecodeObject` [#656](https://github.com/gakonst/ethers-rs/pull/656).
|
`enum BytecodeObject` [#656](https://github.com/gakonst/ethers-rs/pull/656).
|
||||||
- Nit: remove accidentally doubled double-quotes in an error message
|
- Nit: remove accidentally doubled double-quotes in an error message
|
||||||
- Fix when compiler-out metadata is empty and there's no internalType [#1182](https://github.com/gakonst/ethers-rs/pull/1182)
|
- Fix when compiler-out metadata is empty and there's no internalType [#1182](https://github.com/gakonst/ethers-rs/pull/1182)
|
||||||
|
- Add basic `solc` model checker options.
|
||||||
|
[#1258](https://github.com/gakonst/ethers-rs/pull/1258)
|
||||||
|
|
||||||
### 0.6.0
|
### 0.6.0
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,9 @@ impl CompilerInput {
|
||||||
// <https://github.com/ethereum/solidity/releases/tag/v0.8.10>
|
// <https://github.com/ethereum/solidity/releases/tag/v0.8.10>
|
||||||
debug.debug_info.clear();
|
debug.debug_info.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0.8.10 is the earliest version that has all model checker options.
|
||||||
|
self.settings.model_checker = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -241,6 +244,9 @@ pub struct Settings {
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub remappings: Vec<Remapping>,
|
pub remappings: Vec<Remapping>,
|
||||||
pub optimizer: Optimizer,
|
pub optimizer: Optimizer,
|
||||||
|
/// Model Checker options.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub model_checker: Option<ModelCheckerSettings>,
|
||||||
/// Metadata settings
|
/// Metadata settings
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub metadata: Option<SettingsMetadata>,
|
pub metadata: Option<SettingsMetadata>,
|
||||||
|
@ -386,6 +392,7 @@ impl Default for Settings {
|
||||||
debug: None,
|
debug: None,
|
||||||
libraries: Default::default(),
|
libraries: Default::default(),
|
||||||
remappings: Default::default(),
|
remappings: Default::default(),
|
||||||
|
model_checker: None,
|
||||||
}
|
}
|
||||||
.with_ast()
|
.with_ast()
|
||||||
}
|
}
|
||||||
|
@ -837,6 +844,112 @@ pub struct MetadataSource {
|
||||||
pub license: Option<String>,
|
pub license: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Model checker settings for solc
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct ModelCheckerSettings {
|
||||||
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
|
pub contracts: BTreeMap<String, Vec<String>>,
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "serde_helpers::display_from_str_opt",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
pub engine: Option<ModelCheckerEngine>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub timeout: Option<u32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub targets: Option<Vec<ModelCheckerTarget>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Which model checker engine to run.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum ModelCheckerEngine {
|
||||||
|
Default,
|
||||||
|
All,
|
||||||
|
BMC,
|
||||||
|
CHC,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ModelCheckerEngine {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let string = match self {
|
||||||
|
ModelCheckerEngine::Default => "none",
|
||||||
|
ModelCheckerEngine::All => "all",
|
||||||
|
ModelCheckerEngine::BMC => "bmc",
|
||||||
|
ModelCheckerEngine::CHC => "chc",
|
||||||
|
};
|
||||||
|
write!(f, "{}", string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ModelCheckerEngine {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"none" => Ok(ModelCheckerEngine::Default),
|
||||||
|
"all" => Ok(ModelCheckerEngine::All),
|
||||||
|
"bmc" => Ok(ModelCheckerEngine::BMC),
|
||||||
|
"chc" => Ok(ModelCheckerEngine::CHC),
|
||||||
|
s => Err(format!("Unknown model checker engine: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ModelCheckerEngine {
|
||||||
|
fn default() -> Self {
|
||||||
|
ModelCheckerEngine::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Which model checker targets to check.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub enum ModelCheckerTarget {
|
||||||
|
Assert,
|
||||||
|
Underflow,
|
||||||
|
Overflow,
|
||||||
|
DivByZero,
|
||||||
|
ConstantCondition,
|
||||||
|
PopEmptyArray,
|
||||||
|
OutOfBounds,
|
||||||
|
Balance,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ModelCheckerTarget {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let string = match self {
|
||||||
|
ModelCheckerTarget::Assert => "assert",
|
||||||
|
ModelCheckerTarget::Underflow => "underflow",
|
||||||
|
ModelCheckerTarget::Overflow => "overflow",
|
||||||
|
ModelCheckerTarget::DivByZero => "divByZero",
|
||||||
|
ModelCheckerTarget::ConstantCondition => "constantCondition",
|
||||||
|
ModelCheckerTarget::PopEmptyArray => "popEmptyArray",
|
||||||
|
ModelCheckerTarget::OutOfBounds => "outOfBounds",
|
||||||
|
ModelCheckerTarget::Balance => "balance",
|
||||||
|
};
|
||||||
|
write!(f, "{}", string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ModelCheckerTarget {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"assert" => Ok(ModelCheckerTarget::Assert),
|
||||||
|
"underflow" => Ok(ModelCheckerTarget::Underflow),
|
||||||
|
"overflow" => Ok(ModelCheckerTarget::Overflow),
|
||||||
|
"divByZero" => Ok(ModelCheckerTarget::DivByZero),
|
||||||
|
"constantCondition" => Ok(ModelCheckerTarget::ConstantCondition),
|
||||||
|
"popEmptyArray" => Ok(ModelCheckerTarget::PopEmptyArray),
|
||||||
|
"outOfBounds" => Ok(ModelCheckerTarget::OutOfBounds),
|
||||||
|
"balance" => Ok(ModelCheckerTarget::Balance),
|
||||||
|
s => Err(format!("Unknown model checker target: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
pub version: String,
|
pub version: String,
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
contract Assert {
|
||||||
|
function f(uint x) public pure {
|
||||||
|
assert(x > 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
|
|
||||||
use ethers_core::types::Address;
|
use ethers_core::types::Address;
|
||||||
use ethers_solc::{
|
use ethers_solc::{
|
||||||
artifacts::{BytecodeHash, Libraries},
|
artifacts::{BytecodeHash, Libraries, ModelCheckerEngine::CHC, ModelCheckerSettings},
|
||||||
cache::{SolFilesCache, SOLIDITY_FILES_CACHE_FILENAME},
|
cache::{SolFilesCache, SOLIDITY_FILES_CACHE_FILENAME},
|
||||||
project_util::*,
|
project_util::*,
|
||||||
remappings::Remapping,
|
remappings::Remapping,
|
||||||
|
@ -1310,3 +1310,22 @@ fn can_compile_std_json_input() {
|
||||||
assert!(out.sources.contains_key("lib/ds-test/src/test.sol"));
|
assert!(out.sources.contains_key("lib/ds-test/src/test.sol"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_compile_model_checker_sample() {
|
||||||
|
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/model-checker-sample");
|
||||||
|
let paths = ProjectPathsConfig::builder().sources(root);
|
||||||
|
|
||||||
|
let mut project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap();
|
||||||
|
project.project_mut().solc_config.settings.model_checker = Some(ModelCheckerSettings {
|
||||||
|
contracts: BTreeMap::new(),
|
||||||
|
engine: Some(CHC),
|
||||||
|
targets: None,
|
||||||
|
timeout: Some(10000),
|
||||||
|
});
|
||||||
|
let compiled = project.compile().unwrap();
|
||||||
|
|
||||||
|
assert!(compiled.find("Assert").is_some());
|
||||||
|
assert!(!compiled.has_compiler_errors());
|
||||||
|
assert!(compiled.has_compiler_warnings());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue