mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-13 00:31:02 +00:00
remove support for legacy evm assembly (#186)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
//! The Solidity compiler.
|
||||
|
||||
pub mod combined_json;
|
||||
pub mod pipeline;
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
pub mod solc_compiler;
|
||||
#[cfg(target_os = "emscripten")]
|
||||
@@ -9,35 +8,25 @@ pub mod soljson_compiler;
|
||||
pub mod standard_json;
|
||||
pub mod version;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use semver::VersionReq;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use self::combined_json::CombinedJson;
|
||||
use self::pipeline::Pipeline;
|
||||
use self::standard_json::input::Input as StandardJsonInput;
|
||||
use self::standard_json::output::Output as StandardJsonOutput;
|
||||
use self::version::Version;
|
||||
|
||||
/// The first version of `solc` with the support of standard JSON interface.
|
||||
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 4, 12);
|
||||
|
||||
/// The first version of `solc`, where Yul codegen is considered robust enough.
|
||||
pub const FIRST_YUL_VERSION: semver::Version = semver::Version::new(0, 8, 0);
|
||||
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
|
||||
|
||||
/// The first version of `solc`, where `--via-ir` codegen mode is supported.
|
||||
pub const FIRST_VIA_IR_VERSION: semver::Version = semver::Version::new(0, 8, 13);
|
||||
|
||||
/// The last supported version of `solc`.
|
||||
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 28);
|
||||
/// `--base-path` was introduced in 0.6.9 <https://github.com/ethereum/solidity/releases/tag/v0.6.9>
|
||||
pub static FIRST_SUPPORTS_BASE_PATH: Lazy<VersionReq> =
|
||||
Lazy::new(|| VersionReq::parse(">=0.6.9").unwrap());
|
||||
|
||||
/// `--include-path` was introduced in 0.8.8 <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
|
||||
pub static FIRST_SUPPORTS_INCLUDE_PATH: Lazy<VersionReq> =
|
||||
Lazy::new(|| VersionReq::parse(">=0.8.8").unwrap());
|
||||
/// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
|
||||
pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8);
|
||||
|
||||
/// The Solidity compiler.
|
||||
pub trait Compiler {
|
||||
@@ -45,7 +34,6 @@ pub trait Compiler {
|
||||
fn standard_json(
|
||||
&mut self,
|
||||
input: StandardJsonInput,
|
||||
pipeline: Pipeline,
|
||||
base_path: Option<String>,
|
||||
include_paths: Vec<String>,
|
||||
allow_paths: Option<String>,
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
//! The Solidity compiler pipeline type.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::solc::version::Version as SolcVersion;
|
||||
|
||||
/// The Solidity compiler pipeline type.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub enum Pipeline {
|
||||
/// The Yul IR.
|
||||
Yul,
|
||||
/// The EVM legacy assembly IR.
|
||||
EVMLA,
|
||||
}
|
||||
|
||||
impl Pipeline {
|
||||
/// We always use EVMLA for Solidity <=0.7, or if the user does not want to compile via Yul.
|
||||
pub fn new(solc_version: &SolcVersion, force_evmla: bool) -> Self {
|
||||
if solc_version.default < crate::solc::FIRST_YUL_VERSION || force_evmla {
|
||||
Self::EVMLA
|
||||
} else {
|
||||
Self::Yul
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,12 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::solc::combined_json::CombinedJson;
|
||||
use crate::solc::pipeline::Pipeline;
|
||||
use crate::solc::standard_json::input::Input as StandardJsonInput;
|
||||
use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
||||
use crate::solc::version::Version;
|
||||
use crate::solc::FIRST_INCLUDE_PATH_VERSION;
|
||||
|
||||
use super::Compiler;
|
||||
use crate::solc::{FIRST_SUPPORTS_BASE_PATH, FIRST_SUPPORTS_INCLUDE_PATH};
|
||||
|
||||
/// The Solidity compiler.
|
||||
pub struct SolcCompiler {
|
||||
@@ -47,45 +46,35 @@ impl Compiler for SolcCompiler {
|
||||
fn standard_json(
|
||||
&mut self,
|
||||
mut input: StandardJsonInput,
|
||||
pipeline: Pipeline,
|
||||
base_path: Option<String>,
|
||||
include_paths: Vec<String>,
|
||||
allow_paths: Option<String>,
|
||||
) -> anyhow::Result<StandardJsonOutput> {
|
||||
let version = self.version()?;
|
||||
let version = self.version()?.default;
|
||||
|
||||
if !include_paths.is_empty() && version < FIRST_INCLUDE_PATH_VERSION {
|
||||
anyhow::bail!("--include-path is not supported in solc {version}");
|
||||
}
|
||||
|
||||
let mut command = std::process::Command::new(self.executable.as_str());
|
||||
command.stdin(std::process::Stdio::piped());
|
||||
command.stdout(std::process::Stdio::piped());
|
||||
command.arg("--standard-json");
|
||||
|
||||
if let Some(base_path) = &base_path {
|
||||
if !FIRST_SUPPORTS_BASE_PATH.matches(&version.default) {
|
||||
anyhow::bail!(
|
||||
"--base-path not supported this version {} of solc",
|
||||
&version.default
|
||||
);
|
||||
}
|
||||
command.arg("--base-path").arg(base_path);
|
||||
}
|
||||
|
||||
if !include_paths.is_empty() && !FIRST_SUPPORTS_INCLUDE_PATH.matches(&version.default) {
|
||||
anyhow::bail!(
|
||||
"--include-path not supported this version {} of solc",
|
||||
&version.default
|
||||
);
|
||||
}
|
||||
|
||||
for include_path in include_paths.into_iter() {
|
||||
command.arg("--include-path");
|
||||
command.arg(include_path);
|
||||
}
|
||||
if let Some(base_path) = base_path {
|
||||
command.arg("--base-path");
|
||||
command.arg(base_path);
|
||||
}
|
||||
if let Some(allow_paths) = allow_paths {
|
||||
command.arg("--allow-paths");
|
||||
command.arg(allow_paths);
|
||||
}
|
||||
|
||||
input.normalize(&version.default);
|
||||
input.normalize(&version);
|
||||
|
||||
let suppressed_warnings = input.suppressed_warnings.take().unwrap_or_default();
|
||||
|
||||
@@ -129,7 +118,7 @@ impl Compiler for SolcCompiler {
|
||||
),
|
||||
)
|
||||
})?;
|
||||
output.preprocess_ast(&version, pipeline, suppressed_warnings.as_slice())?;
|
||||
output.preprocess_ast(suppressed_warnings.as_slice())?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::solc::combined_json::CombinedJson;
|
||||
use crate::solc::pipeline::Pipeline;
|
||||
use crate::solc::standard_json::input::Input as StandardJsonInput;
|
||||
use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
||||
use crate::solc::version::Version;
|
||||
@@ -29,7 +28,6 @@ impl Compiler for SoljsonCompiler {
|
||||
fn standard_json(
|
||||
&mut self,
|
||||
mut input: StandardJsonInput,
|
||||
pipeline: Pipeline,
|
||||
_base_path: Option<String>,
|
||||
_include_paths: Vec<String>,
|
||||
_allow_paths: Option<String>,
|
||||
@@ -50,7 +48,7 @@ impl Compiler for SoljsonCompiler {
|
||||
.unwrap_or_else(|_| String::from_utf8_lossy(out.as_bytes()).to_string()),
|
||||
)
|
||||
})?;
|
||||
output.preprocess_ast(&version, pipeline, suppressed_warnings.as_slice())?;
|
||||
output.preprocess_ast(suppressed_warnings.as_slice())?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
||||
use crate::solc::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
|
||||
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
|
||||
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
|
||||
@@ -40,13 +39,13 @@ pub struct Input {
|
||||
|
||||
impl Input {
|
||||
/// A shortcut constructor from stdin.
|
||||
pub fn try_from_stdin(solc_pipeline: SolcPipeline) -> anyhow::Result<Self> {
|
||||
pub fn try_from_stdin() -> anyhow::Result<Self> {
|
||||
let mut input: Self = serde_json::from_reader(std::io::BufReader::new(std::io::stdin()))?;
|
||||
input
|
||||
.settings
|
||||
.output_selection
|
||||
.get_or_insert_with(SolcStandardJsonInputSettingsSelection::default)
|
||||
.extend_with_required(solc_pipeline);
|
||||
.extend_with_required();
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
@@ -61,7 +60,6 @@ impl Input {
|
||||
output_selection: SolcStandardJsonInputSettingsSelection,
|
||||
optimizer: SolcStandardJsonInputSettingsOptimizer,
|
||||
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
|
||||
via_ir: bool,
|
||||
suppressed_warnings: Option<Vec<Warning>>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let mut paths: BTreeSet<PathBuf> = paths.iter().cloned().collect();
|
||||
@@ -92,7 +90,6 @@ impl Input {
|
||||
libraries,
|
||||
remappings,
|
||||
output_selection,
|
||||
via_ir,
|
||||
optimizer,
|
||||
metadata,
|
||||
),
|
||||
@@ -111,7 +108,6 @@ impl Input {
|
||||
output_selection: SolcStandardJsonInputSettingsSelection,
|
||||
optimizer: SolcStandardJsonInputSettingsOptimizer,
|
||||
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
|
||||
via_ir: bool,
|
||||
suppressed_warnings: Option<Vec<Warning>>,
|
||||
) -> anyhow::Result<Self> {
|
||||
#[cfg(feature = "parallel")]
|
||||
@@ -131,7 +127,6 @@ impl Input {
|
||||
libraries,
|
||||
remappings,
|
||||
output_selection,
|
||||
via_ir,
|
||||
optimizer,
|
||||
metadata,
|
||||
),
|
||||
|
||||
@@ -51,7 +51,6 @@ impl Settings {
|
||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||
remappings: Option<BTreeSet<String>>,
|
||||
output_selection: Selection,
|
||||
via_ir: bool,
|
||||
optimizer: Optimizer,
|
||||
metadata: Option<Metadata>,
|
||||
) -> Self {
|
||||
@@ -60,9 +59,9 @@ impl Settings {
|
||||
libraries: Some(libraries),
|
||||
remappings,
|
||||
output_selection: Some(output_selection),
|
||||
via_ir: if via_ir { Some(true) } else { None },
|
||||
optimizer,
|
||||
metadata,
|
||||
via_ir: Some(true),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
||||
|
||||
/// The `solc --standard-json` expected output selection flag.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[allow(non_camel_case_types)]
|
||||
@@ -46,15 +44,6 @@ pub enum Flag {
|
||||
Assembly,
|
||||
}
|
||||
|
||||
impl From<SolcPipeline> for Flag {
|
||||
fn from(pipeline: SolcPipeline) -> Self {
|
||||
match pipeline {
|
||||
SolcPipeline::Yul => Self::Yul,
|
||||
SolcPipeline::EVMLA => Self::EVMLA,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Flag {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -7,8 +7,6 @@ use std::collections::HashSet;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
||||
|
||||
use self::flag::Flag as SelectionFlag;
|
||||
|
||||
/// The `solc --standard-json` output file selection.
|
||||
@@ -24,7 +22,7 @@ pub struct File {
|
||||
|
||||
impl File {
|
||||
/// Creates the selection required by our compilation process.
|
||||
pub fn new_required(pipeline: SolcPipeline) -> Self {
|
||||
pub fn new_required() -> Self {
|
||||
Self {
|
||||
per_file: Some(HashSet::from_iter([SelectionFlag::AST])),
|
||||
per_contract: Some(HashSet::from_iter([
|
||||
@@ -32,14 +30,14 @@ impl File {
|
||||
SelectionFlag::EVMDBC,
|
||||
SelectionFlag::MethodIdentifiers,
|
||||
SelectionFlag::Metadata,
|
||||
SelectionFlag::from(pipeline),
|
||||
SelectionFlag::Yul,
|
||||
])),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends the user's output selection with flag required by our compilation process.
|
||||
pub fn extend_with_required(&mut self, pipeline: SolcPipeline) -> &mut Self {
|
||||
let required = Self::new_required(pipeline);
|
||||
pub fn extend_with_required(&mut self) -> &mut Self {
|
||||
let required = Self::new_required();
|
||||
|
||||
self.per_file
|
||||
.get_or_insert_with(HashSet::default)
|
||||
|
||||
@@ -5,8 +5,6 @@ pub mod file;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
||||
|
||||
use self::file::File as FileSelection;
|
||||
|
||||
/// The `solc --standard-json` output selection.
|
||||
@@ -19,17 +17,17 @@ pub struct Selection {
|
||||
|
||||
impl Selection {
|
||||
/// Creates the selection required by our compilation process.
|
||||
pub fn new_required(pipeline: SolcPipeline) -> Self {
|
||||
pub fn new_required() -> Self {
|
||||
Self {
|
||||
all: Some(FileSelection::new_required(pipeline)),
|
||||
all: Some(FileSelection::new_required()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends the user's output selection with flag required by our compilation process.
|
||||
pub fn extend_with_required(&mut self, pipeline: SolcPipeline) -> &mut Self {
|
||||
pub fn extend_with_required(&mut self) -> &mut Self {
|
||||
self.all
|
||||
.get_or_insert_with(|| FileSelection::new_required(pipeline))
|
||||
.extend_with_required(pipeline);
|
||||
.get_or_insert_with(FileSelection::new_required)
|
||||
.extend_with_required();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
//! The `solc --standard-json` output contract EVM extra metadata.
|
||||
|
||||
pub mod recursive_function;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use self::recursive_function::RecursiveFunction;
|
||||
|
||||
/// The `solc --standard-json` output contract EVM extra metadata.
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExtraMetadata {
|
||||
/// The list of recursive functions.
|
||||
#[serde(default = "Vec::new")]
|
||||
pub recursive_functions: Vec<RecursiveFunction>,
|
||||
}
|
||||
|
||||
impl ExtraMetadata {
|
||||
/// Returns the recursive function reference for the specified tag.
|
||||
pub fn get(
|
||||
&self,
|
||||
block_key: &revive_llvm_context::PolkaVMFunctionBlockKey,
|
||||
) -> Option<&RecursiveFunction> {
|
||||
for function in self.recursive_functions.iter() {
|
||||
match block_key.code_type {
|
||||
revive_llvm_context::PolkaVMCodeType::Deploy => {
|
||||
if let Some(creation_tag) = function.creation_tag {
|
||||
if num::BigUint::from(creation_tag) == block_key.tag {
|
||||
return Some(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
revive_llvm_context::PolkaVMCodeType::Runtime => {
|
||||
if let Some(runtime_tag) = function.runtime_tag {
|
||||
if num::BigUint::from(runtime_tag) == block_key.tag {
|
||||
return Some(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
//! The `solc --standard-json` output contract EVM recursive function.
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
/// The `solc --standard-json` output contract EVM recursive function.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RecursiveFunction {
|
||||
/// The function name.
|
||||
pub name: String,
|
||||
/// The creation code function block tag.
|
||||
pub creation_tag: Option<usize>,
|
||||
/// The runtime code function block tag.
|
||||
pub runtime_tag: Option<usize>,
|
||||
/// The number of input arguments.
|
||||
#[serde(rename = "totalParamSize")]
|
||||
pub input_size: usize,
|
||||
/// The number of output arguments.
|
||||
#[serde(rename = "totalRetParamSize")]
|
||||
pub output_size: usize,
|
||||
}
|
||||
@@ -1,27 +1,20 @@
|
||||
//! The `solc --standard-json` output contract EVM data.
|
||||
|
||||
pub mod bytecode;
|
||||
pub mod extra_metadata;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::evmla::assembly::Assembly;
|
||||
|
||||
use self::bytecode::Bytecode;
|
||||
use self::bytecode::DeployedBytecode;
|
||||
use self::extra_metadata::ExtraMetadata;
|
||||
|
||||
/// The `solc --standard-json` output contract EVM data.
|
||||
/// It is replaced by PolkaVM data after compiling.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EVM {
|
||||
/// The contract EVM legacy assembly code.
|
||||
#[serde(rename = "legacyAssembly", skip_serializing_if = "Option::is_none")]
|
||||
pub assembly: Option<Assembly>,
|
||||
/// The contract PolkaVM assembly code.
|
||||
#[serde(rename = "assembly", skip_serializing_if = "Option::is_none")]
|
||||
pub assembly_text: Option<String>,
|
||||
@@ -37,9 +30,6 @@ pub struct EVM {
|
||||
/// The contract function signatures.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub method_identifiers: Option<BTreeMap<String, String>>,
|
||||
/// The extra EVMLA metadata.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub extra_metadata: Option<ExtraMetadata>,
|
||||
}
|
||||
|
||||
impl EVM {
|
||||
|
||||
@@ -125,26 +125,6 @@ impl Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the internal function pointer usage error.
|
||||
pub fn message_internal_function_pointer(src: Option<&str>) -> Self {
|
||||
let message = r#"
|
||||
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Error: Internal function pointers are not supported in EVM legacy assembly pipeline. │
|
||||
│ Please use the Yul IR codegen instead. │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘"#
|
||||
.to_owned();
|
||||
|
||||
Self {
|
||||
component: "general".to_owned(),
|
||||
error_code: None,
|
||||
formatted_message: message.clone(),
|
||||
message,
|
||||
severity: "error".to_owned(),
|
||||
source_location: src.map(SourceLocation::from_str).and_then(Result::ok),
|
||||
r#type: "Error".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends the contract path to the message..
|
||||
pub fn push_contract_path(&mut self, path: &str) {
|
||||
self.formatted_message
|
||||
|
||||
@@ -10,12 +10,9 @@ use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sha3::Digest;
|
||||
|
||||
use crate::evmla::assembly::instruction::Instruction;
|
||||
use crate::evmla::assembly::Assembly;
|
||||
use crate::project::contract::ir::IR as ProjectContractIR;
|
||||
use crate::project::contract::Contract as ProjectContract;
|
||||
use crate::project::Project;
|
||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
||||
use crate::solc::version::Version as SolcVersion;
|
||||
use crate::warning::Warning;
|
||||
use crate::yul::lexer::Lexer;
|
||||
@@ -53,14 +50,9 @@ impl Output {
|
||||
&mut self,
|
||||
source_code_files: BTreeMap<String, String>,
|
||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||
pipeline: SolcPipeline,
|
||||
solc_version: &SolcVersion,
|
||||
debug_config: &revive_llvm_context::DebugConfig,
|
||||
) -> anyhow::Result<Project> {
|
||||
if let SolcPipeline::EVMLA = pipeline {
|
||||
self.preprocess_dependencies()?;
|
||||
}
|
||||
|
||||
let files = match self.contracts.as_ref() {
|
||||
Some(files) => files,
|
||||
None => match &self.errors {
|
||||
@@ -76,38 +68,22 @@ impl Output {
|
||||
for (name, contract) in contracts.iter() {
|
||||
let full_path = format!("{path}:{name}");
|
||||
|
||||
let source = match pipeline {
|
||||
SolcPipeline::Yul => {
|
||||
let ir_optimized = match contract.ir_optimized.to_owned() {
|
||||
Some(ir_optimized) => ir_optimized,
|
||||
None => continue,
|
||||
};
|
||||
if ir_optimized.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?;
|
||||
|
||||
let mut lexer = Lexer::new(ir_optimized.to_owned());
|
||||
let object = Object::parse(&mut lexer, None).map_err(|error| {
|
||||
anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error)
|
||||
})?;
|
||||
|
||||
ProjectContractIR::new_yul(ir_optimized.to_owned(), object)
|
||||
}
|
||||
SolcPipeline::EVMLA => {
|
||||
let evm = contract.evm.as_ref();
|
||||
let assembly = match evm.and_then(|evm| evm.assembly.to_owned()) {
|
||||
Some(assembly) => assembly.to_owned(),
|
||||
None => continue,
|
||||
};
|
||||
let extra_metadata = evm
|
||||
.and_then(|evm| evm.extra_metadata.to_owned())
|
||||
.unwrap_or_default();
|
||||
|
||||
ProjectContractIR::new_evmla(assembly, extra_metadata)
|
||||
}
|
||||
let ir_optimized = match contract.ir_optimized.to_owned() {
|
||||
Some(ir_optimized) => ir_optimized,
|
||||
None => continue,
|
||||
};
|
||||
if ir_optimized.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?;
|
||||
|
||||
let mut lexer = Lexer::new(ir_optimized.to_owned());
|
||||
let object = Object::parse(&mut lexer, None).map_err(|error| {
|
||||
anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error)
|
||||
})?;
|
||||
|
||||
let source = ProjectContractIR::new_yul(ir_optimized.to_owned(), object);
|
||||
|
||||
let source_code = source_code_files
|
||||
.get(path.as_str())
|
||||
@@ -133,12 +109,7 @@ impl Output {
|
||||
}
|
||||
|
||||
/// Traverses the AST and returns the list of additional errors and warnings.
|
||||
pub fn preprocess_ast(
|
||||
&mut self,
|
||||
version: &SolcVersion,
|
||||
pipeline: SolcPipeline,
|
||||
suppressed_warnings: &[Warning],
|
||||
) -> anyhow::Result<()> {
|
||||
pub fn preprocess_ast(&mut self, suppressed_warnings: &[Warning]) -> anyhow::Result<()> {
|
||||
let sources = match self.sources.as_ref() {
|
||||
Some(sources) => sources,
|
||||
None => return Ok(()),
|
||||
@@ -147,8 +118,7 @@ impl Output {
|
||||
let mut messages = Vec::new();
|
||||
for (path, source) in sources.iter() {
|
||||
if let Some(ast) = source.ast.as_ref() {
|
||||
let mut polkavm_messages =
|
||||
Source::get_messages(ast, version, pipeline, suppressed_warnings);
|
||||
let mut polkavm_messages = Source::get_messages(ast, suppressed_warnings);
|
||||
for message in polkavm_messages.iter_mut() {
|
||||
message.push_contract_path(path.as_str());
|
||||
}
|
||||
@@ -165,83 +135,4 @@ impl Output {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The pass, which replaces with dependency indexes with actual data.
|
||||
fn preprocess_dependencies(&mut self) -> anyhow::Result<()> {
|
||||
let files = match self.contracts.as_mut() {
|
||||
Some(files) => files,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let mut hash_path_mapping = BTreeMap::new();
|
||||
|
||||
for (path, contracts) in files.iter() {
|
||||
for (name, contract) in contracts.iter() {
|
||||
let full_path = format!("{path}:{name}");
|
||||
let hash = match contract
|
||||
.evm
|
||||
.as_ref()
|
||||
.and_then(|evm| evm.assembly.as_ref())
|
||||
.map(|assembly| assembly.keccak256())
|
||||
{
|
||||
Some(hash) => hash,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
hash_path_mapping.insert(hash, full_path);
|
||||
}
|
||||
}
|
||||
|
||||
for (path, contracts) in files.iter_mut() {
|
||||
for (name, contract) in contracts.iter_mut() {
|
||||
let assembly = match contract.evm.as_mut().and_then(|evm| evm.assembly.as_mut()) {
|
||||
Some(assembly) => assembly,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let full_path = format!("{path}:{name}");
|
||||
Self::preprocess_dependency_level(
|
||||
full_path.as_str(),
|
||||
assembly,
|
||||
&hash_path_mapping,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Preprocesses an assembly JSON structure dependency data map.
|
||||
fn preprocess_dependency_level(
|
||||
full_path: &str,
|
||||
assembly: &mut Assembly,
|
||||
hash_path_mapping: &BTreeMap<String, String>,
|
||||
) -> anyhow::Result<()> {
|
||||
assembly.set_full_path(full_path.to_owned());
|
||||
|
||||
let deploy_code_index_path_mapping =
|
||||
assembly.deploy_dependencies_pass(full_path, hash_path_mapping)?;
|
||||
if let Some(deploy_code_instructions) = assembly.code.as_deref_mut() {
|
||||
Instruction::replace_data_aliases(
|
||||
deploy_code_instructions,
|
||||
&deploy_code_index_path_mapping,
|
||||
)?;
|
||||
};
|
||||
|
||||
let runtime_code_index_path_mapping =
|
||||
assembly.runtime_dependencies_pass(full_path, hash_path_mapping)?;
|
||||
if let Some(runtime_code_instructions) = assembly
|
||||
.data
|
||||
.as_mut()
|
||||
.and_then(|data_map| data_map.get_mut("0"))
|
||||
.and_then(|data| data.get_assembly_mut())
|
||||
.and_then(|assembly| assembly.code.as_deref_mut())
|
||||
{
|
||||
Instruction::replace_data_aliases(
|
||||
runtime_code_instructions,
|
||||
&runtime_code_index_path_mapping,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
||||
use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputError;
|
||||
use crate::solc::version::Version as SolcVersion;
|
||||
use crate::warning::Warning;
|
||||
|
||||
/// The `solc --standard-json` output source.
|
||||
@@ -132,37 +130,9 @@ impl Source {
|
||||
))
|
||||
}
|
||||
|
||||
/// Checks the AST node for the internal function pointers value usage.
|
||||
pub fn check_internal_function_pointer(
|
||||
ast: &serde_json::Value,
|
||||
) -> Option<SolcStandardJsonOutputError> {
|
||||
let ast = ast.as_object()?;
|
||||
|
||||
if ast.get("nodeType")?.as_str()? != "VariableDeclaration" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let type_descriptions = ast.get("typeDescriptions")?.as_object()?;
|
||||
if !type_descriptions
|
||||
.get("typeIdentifier")?
|
||||
.as_str()?
|
||||
.contains("function_internal")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(
|
||||
SolcStandardJsonOutputError::message_internal_function_pointer(
|
||||
ast.get("src")?.as_str(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the list of messages for some specific parts of the AST.
|
||||
pub fn get_messages(
|
||||
ast: &serde_json::Value,
|
||||
version: &SolcVersion,
|
||||
pipeline: SolcPipeline,
|
||||
suppressed_warnings: &[Warning],
|
||||
) -> Vec<SolcStandardJsonOutputError> {
|
||||
let mut messages = Vec::new();
|
||||
@@ -189,31 +159,16 @@ impl Source {
|
||||
messages.push(message);
|
||||
}
|
||||
}
|
||||
if SolcPipeline::EVMLA == pipeline && version.l2_revision.is_none() {
|
||||
if let Some(message) = Self::check_internal_function_pointer(ast) {
|
||||
messages.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
match ast {
|
||||
serde_json::Value::Array(array) => {
|
||||
for element in array.iter() {
|
||||
messages.extend(Self::get_messages(
|
||||
element,
|
||||
version,
|
||||
pipeline,
|
||||
suppressed_warnings,
|
||||
));
|
||||
messages.extend(Self::get_messages(element, suppressed_warnings));
|
||||
}
|
||||
}
|
||||
serde_json::Value::Object(object) => {
|
||||
for (_key, value) in object.iter() {
|
||||
messages.extend(Self::get_messages(
|
||||
value,
|
||||
version,
|
||||
pipeline,
|
||||
suppressed_warnings,
|
||||
));
|
||||
messages.extend(Self::get_messages(value, suppressed_warnings));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
Reference in New Issue
Block a user