mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-07-18 15:55:43 +00:00
remove support for legacy evm assembly (#186)
This commit is contained in:
@@ -8,6 +8,7 @@ This is a development pre-release.
|
|||||||
- Support for the `coinbase` opcode.
|
- Support for the `coinbase` opcode.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- Removed support for legacy EVM assembly (EVMLA) translation.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Solidity: Add the solc `--libraries` files to sources.
|
- Solidity: Add the solc `--libraries` files to sources.
|
||||||
|
|||||||
Generated
-8
@@ -4732,12 +4732,6 @@ dependencies = [
|
|||||||
"rawpointer",
|
"rawpointer",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "md5"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
@@ -8350,7 +8344,6 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
"md5",
|
|
||||||
"num",
|
"num",
|
||||||
"polkavm-common 0.19.0",
|
"polkavm-common 0.19.0",
|
||||||
"polkavm-disassembler",
|
"polkavm-disassembler",
|
||||||
@@ -8398,7 +8391,6 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
"libc",
|
"libc",
|
||||||
"md5",
|
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"num",
|
"num",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ once_cell = "1.19"
|
|||||||
num = "0.4.3"
|
num = "0.4.3"
|
||||||
sha1 = "0.10"
|
sha1 = "0.10"
|
||||||
sha3 = "0.10"
|
sha3 = "0.10"
|
||||||
md5 = "0.7.0"
|
|
||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
which = "7.0"
|
which = "7.0"
|
||||||
path-slash = "0.2"
|
path-slash = "0.2"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
# revive
|
# revive
|
||||||
|
|
||||||
YUL and EVM assembly recompiler to LLVM, targetting RISC-V on [PolkaVM](https://github.com/koute/polkavm).
|
YUL recompiler to LLVM, targetting RISC-V on [PolkaVM](https://github.com/koute/polkavm).
|
||||||
|
|
||||||
Visit [contracts.polkadot.io](https://contracts.polkadot.io) to learn more about contracts on Polkadot!
|
Visit [contracts.polkadot.io](https://contracts.polkadot.io) to learn more about contracts on Polkadot!
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,6 @@ pub static EXTENSION_ABI: &str = "abi";
|
|||||||
/// The Yul IR file extension.
|
/// The Yul IR file extension.
|
||||||
pub static EXTENSION_YUL: &str = "yul";
|
pub static EXTENSION_YUL: &str = "yul";
|
||||||
|
|
||||||
/// The EVM legacy assembly IR file extension.
|
|
||||||
pub static EXTENSION_EVMLA: &str = "evmla";
|
|
||||||
|
|
||||||
/// The Ethereal IR file extension.
|
|
||||||
pub static EXTENSION_ETHIR: &str = "ethir";
|
|
||||||
|
|
||||||
/// The EVM file extension.
|
/// The EVM file extension.
|
||||||
pub static EXTENSION_EVM: &str = "evm";
|
pub static EXTENSION_EVM: &str = "evm";
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
|||||||
path: Some(path.into()),
|
path: Some(path.into()),
|
||||||
contract: contract.to_string(),
|
contract: contract.to_string(),
|
||||||
solc_optimizer: None,
|
solc_optimizer: None,
|
||||||
pipeline: None,
|
|
||||||
},
|
},
|
||||||
data: vec![],
|
data: vec![],
|
||||||
salt: OptionalHex::default(),
|
salt: OptionalHex::default(),
|
||||||
@@ -355,7 +354,6 @@ fn ext_code_size() {
|
|||||||
path: Some("contracts/Baseline.sol".into()),
|
path: Some("contracts/Baseline.sol".into()),
|
||||||
contract: "Baseline".to_string(),
|
contract: "Baseline".to_string(),
|
||||||
solc_optimizer: None,
|
solc_optimizer: None,
|
||||||
pipeline: None,
|
|
||||||
},
|
},
|
||||||
data: vec![],
|
data: vec![],
|
||||||
salt: OptionalHex::from([0; 32]),
|
salt: OptionalHex::from([0; 32]),
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ serde = { workspace = true, features = ["derive"] }
|
|||||||
num = { workspace = true }
|
num = { workspace = true }
|
||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
sha3 = { workspace = true }
|
sha3 = { workspace = true }
|
||||||
md5 = { workspace = true }
|
|
||||||
inkwell = { workspace = true }
|
inkwell = { workspace = true }
|
||||||
polkavm-disassembler = { workspace = true }
|
polkavm-disassembler = { workspace = true }
|
||||||
polkavm-common = { workspace = true }
|
polkavm-common = { workspace = true }
|
||||||
|
|||||||
@@ -7,10 +7,6 @@
|
|||||||
pub enum IRType {
|
pub enum IRType {
|
||||||
/// Whether to dump the Yul code.
|
/// Whether to dump the Yul code.
|
||||||
Yul,
|
Yul,
|
||||||
/// Whether to dump the EVM legacy assembly code.
|
|
||||||
EVMLA,
|
|
||||||
/// Whether to dump the Ethereal IR code.
|
|
||||||
EthIR,
|
|
||||||
/// Whether to dump the LLVM IR code.
|
/// Whether to dump the LLVM IR code.
|
||||||
LLVM,
|
LLVM,
|
||||||
/// Whether to dump the assembly code.
|
/// Whether to dump the assembly code.
|
||||||
@@ -27,8 +23,6 @@ impl IRType {
|
|||||||
pub fn file_extension(&self) -> &'static str {
|
pub fn file_extension(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Yul => revive_common::EXTENSION_YUL,
|
Self::Yul => revive_common::EXTENSION_YUL,
|
||||||
Self::EthIR => revive_common::EXTENSION_ETHIR,
|
|
||||||
Self::EVMLA => revive_common::EXTENSION_EVMLA,
|
|
||||||
Self::LLVM => revive_common::EXTENSION_LLVM_SOURCE,
|
Self::LLVM => revive_common::EXTENSION_LLVM_SOURCE,
|
||||||
Self::Assembly => revive_common::EXTENSION_POLKAVM_ASSEMBLY,
|
Self::Assembly => revive_common::EXTENSION_POLKAVM_ASSEMBLY,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|||||||
@@ -39,30 +39,6 @@ impl DebugConfig {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dumps the EVM legacy assembly IR.
|
|
||||||
pub fn dump_evmla(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
|
|
||||||
if let Some(output_directory) = self.output_directory.as_ref() {
|
|
||||||
let mut file_path = output_directory.to_owned();
|
|
||||||
let full_file_name = Self::full_file_name(contract_path, None, IRType::EVMLA);
|
|
||||||
file_path.push(full_file_name);
|
|
||||||
std::fs::write(file_path, code)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dumps the Ethereal IR.
|
|
||||||
pub fn dump_ethir(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
|
|
||||||
if let Some(output_directory) = self.output_directory.as_ref() {
|
|
||||||
let mut file_path = output_directory.to_owned();
|
|
||||||
let full_file_name = Self::full_file_name(contract_path, None, IRType::EthIR);
|
|
||||||
file_path.push(full_file_name);
|
|
||||||
std::fs::write(file_path, code)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dumps the unoptimized LLVM IR.
|
/// Dumps the unoptimized LLVM IR.
|
||||||
pub fn dump_llvm_ir_unoptimized(
|
pub fn dump_llvm_ir_unoptimized(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -17,12 +17,7 @@ pub use self::polkavm::context::attribute::Attribute as PolkaVMAttribute;
|
|||||||
pub use self::polkavm::context::build::Build as PolkaVMBuild;
|
pub use self::polkavm::context::build::Build as PolkaVMBuild;
|
||||||
pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType;
|
pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType;
|
||||||
pub use self::polkavm::context::debug_info::DebugInfo;
|
pub use self::polkavm::context::debug_info::DebugInfo;
|
||||||
pub use self::polkavm::context::evmla_data::EVMLAData as PolkaVMContextEVMLAData;
|
|
||||||
pub use self::polkavm::context::function::block::evmla_data::key::Key as PolkaVMFunctionBlockKey;
|
|
||||||
pub use self::polkavm::context::function::block::evmla_data::EVMLAData as PolkaVMFunctionBlockEVMLAData;
|
|
||||||
pub use self::polkavm::context::function::block::Block as PolkaVMFunctionBlock;
|
|
||||||
pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFunctionDeclaration;
|
pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFunctionDeclaration;
|
||||||
pub use self::polkavm::context::function::evmla_data::EVMLAData as PolkaVMFunctionEVMLAData;
|
|
||||||
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
|
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
|
||||||
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
|
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
|
||||||
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
|
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
//! The LLVM IR generator EVM legacy assembly data.
|
|
||||||
|
|
||||||
use crate::polkavm::context::argument::Argument;
|
|
||||||
|
|
||||||
/// The LLVM IR generator EVM legacy assembly data.
|
|
||||||
/// Describes some data that is only relevant to the EVM legacy assembly.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EVMLAData<'ctx> {
|
|
||||||
/// The Solidity compiler version.
|
|
||||||
/// Some instruction behave differenly depending on the version.
|
|
||||||
pub version: semver::Version,
|
|
||||||
/// The static stack allocated for the current function.
|
|
||||||
pub stack: Vec<Argument<'ctx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EVMLAData<'_> {
|
|
||||||
/// The default stack size.
|
|
||||||
pub const DEFAULT_STACK_SIZE: usize = 64;
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(version: semver::Version) -> Self {
|
|
||||||
Self {
|
|
||||||
version,
|
|
||||||
stack: Vec::with_capacity(Self::DEFAULT_STACK_SIZE),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
//! The LLVM IR generator function block key.
|
|
||||||
|
|
||||||
use crate::polkavm::context::code_type::CodeType;
|
|
||||||
|
|
||||||
/// The LLVM IR generator function block key.
|
|
||||||
/// Is only relevant to the EVM legacy assembly.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct Key {
|
|
||||||
/// The block code type.
|
|
||||||
pub code_type: CodeType,
|
|
||||||
/// The block tag.
|
|
||||||
pub tag: num::BigUint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Key {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(code_type: CodeType, tag: num::BigUint) -> Self {
|
|
||||||
Self { code_type, tag }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Key {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}_{}",
|
|
||||||
match self.code_type {
|
|
||||||
CodeType::Deploy => "dt",
|
|
||||||
CodeType::Runtime => "rt",
|
|
||||||
},
|
|
||||||
self.tag
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
//! The LLVM function block EVM legacy assembly data.
|
|
||||||
|
|
||||||
pub mod key;
|
|
||||||
|
|
||||||
/// The LLVM function block EVM legacy assembly data.
|
|
||||||
/// Describes some data that is only relevant to the EVM legacy assembly.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EVMLAData {
|
|
||||||
/// The initial hashes of the allowed stack states.
|
|
||||||
pub stack_hashes: Vec<md5::Digest>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EVMLAData {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(stack_hashes: Vec<md5::Digest>) -> Self {
|
|
||||||
Self { stack_hashes }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
//! The LLVM IR generator function block.
|
|
||||||
|
|
||||||
pub mod evmla_data;
|
|
||||||
|
|
||||||
use self::evmla_data::EVMLAData;
|
|
||||||
|
|
||||||
/// The LLVM IR generator function block.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Block<'ctx> {
|
|
||||||
/// The inner block.
|
|
||||||
inner: inkwell::basic_block::BasicBlock<'ctx>,
|
|
||||||
/// The EVM legacy assembly compiler data.
|
|
||||||
evmla_data: Option<EVMLAData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> Block<'ctx> {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(inner: inkwell::basic_block::BasicBlock<'ctx>) -> Self {
|
|
||||||
Self {
|
|
||||||
inner,
|
|
||||||
evmla_data: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the EVM legacy assembly data.
|
|
||||||
pub fn set_evmla_data(&mut self, data: EVMLAData) {
|
|
||||||
self.evmla_data = Some(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The LLVM object reference.
|
|
||||||
pub fn inner(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
|
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the EVM data reference.
|
|
||||||
/// # Panics
|
|
||||||
/// If the EVM data has not been initialized.
|
|
||||||
pub fn evm(&self) -> &EVMLAData {
|
|
||||||
self.evmla_data
|
|
||||||
.as_ref()
|
|
||||||
.expect("The EVM data must have been initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the EVM data mutable reference.
|
|
||||||
/// # Panics
|
|
||||||
/// If the EVM data has not been initialized.
|
|
||||||
pub fn evm_mut(&mut self) -> &mut EVMLAData {
|
|
||||||
self.evmla_data
|
|
||||||
.as_mut()
|
|
||||||
.expect("The EVM data must have been initialized")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
//! The LLVM function EVM legacy assembly data.
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use crate::polkavm::context::function::block::evmla_data::key::Key as BlockKey;
|
|
||||||
use crate::polkavm::context::function::block::Block;
|
|
||||||
|
|
||||||
/// The LLVM function EVM legacy assembly data.
|
|
||||||
/// Describes some data that is only relevant to the EVM legacy assembly.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EVMLAData<'ctx> {
|
|
||||||
/// The ordinary blocks with numeric tags.
|
|
||||||
/// Is only used by the Solidity EVM compiler.
|
|
||||||
pub blocks: BTreeMap<BlockKey, Vec<Block<'ctx>>>,
|
|
||||||
/// The function stack size.
|
|
||||||
pub stack_size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> EVMLAData<'ctx> {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(stack_size: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
blocks: BTreeMap::new(),
|
|
||||||
stack_size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts a function block.
|
|
||||||
pub fn insert_block(&mut self, key: BlockKey, block: Block<'ctx>) {
|
|
||||||
if let Some(blocks) = self.blocks.get_mut(&key) {
|
|
||||||
blocks.push(block);
|
|
||||||
} else {
|
|
||||||
self.blocks.insert(key, vec![block]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the block with the specified tag and initial stack pattern.
|
|
||||||
/// If there is only one block, it is returned unconditionally.
|
|
||||||
pub fn find_block(
|
|
||||||
&self,
|
|
||||||
key: &BlockKey,
|
|
||||||
stack_hash: &md5::Digest,
|
|
||||||
) -> anyhow::Result<Block<'ctx>> {
|
|
||||||
if self
|
|
||||||
.blocks
|
|
||||||
.get(key)
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Undeclared function block {}", key))?
|
|
||||||
.len()
|
|
||||||
== 1
|
|
||||||
{
|
|
||||||
return self
|
|
||||||
.blocks
|
|
||||||
.get(key)
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Undeclared function block {}", key))?
|
|
||||||
.first()
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Undeclared function block {}", key));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.blocks
|
|
||||||
.get(key)
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Undeclared function block {}", key))?
|
|
||||||
.iter()
|
|
||||||
.find(|block| {
|
|
||||||
block
|
|
||||||
.evm()
|
|
||||||
.stack_hashes
|
|
||||||
.iter()
|
|
||||||
.any(|hash| hash == stack_hash)
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Undeclared function block {}", key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
//! The LLVM IR generator function.
|
//! The LLVM IR generator function.
|
||||||
|
|
||||||
pub mod block;
|
|
||||||
pub mod declaration;
|
pub mod declaration;
|
||||||
pub mod evmla_data;
|
|
||||||
pub mod intrinsics;
|
pub mod intrinsics;
|
||||||
pub mod llvm_runtime;
|
pub mod llvm_runtime;
|
||||||
pub mod r#return;
|
pub mod r#return;
|
||||||
@@ -19,7 +17,6 @@ use crate::polkavm::context::attribute::Attribute;
|
|||||||
use crate::polkavm::context::pointer::Pointer;
|
use crate::polkavm::context::pointer::Pointer;
|
||||||
|
|
||||||
use self::declaration::Declaration;
|
use self::declaration::Declaration;
|
||||||
use self::evmla_data::EVMLAData;
|
|
||||||
use self::r#return::Return;
|
use self::r#return::Return;
|
||||||
use self::yul_data::YulData;
|
use self::yul_data::YulData;
|
||||||
|
|
||||||
@@ -45,8 +42,6 @@ pub struct Function<'ctx> {
|
|||||||
|
|
||||||
/// The Yul compiler data.
|
/// The Yul compiler data.
|
||||||
yul_data: Option<YulData>,
|
yul_data: Option<YulData>,
|
||||||
/// The EVM legacy assembly compiler data.
|
|
||||||
evmla_data: Option<EVMLAData<'ctx>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Function<'ctx> {
|
impl<'ctx> Function<'ctx> {
|
||||||
@@ -72,7 +67,6 @@ impl<'ctx> Function<'ctx> {
|
|||||||
return_block,
|
return_block,
|
||||||
|
|
||||||
yul_data: None,
|
yul_data: None,
|
||||||
evmla_data: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,29 +294,6 @@ impl<'ctx> Function<'ctx> {
|
|||||||
self.return_block
|
self.return_block
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the EVM legacy assembly data.
|
|
||||||
pub fn set_evmla_data(&mut self, data: EVMLAData<'ctx>) {
|
|
||||||
self.evmla_data = Some(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the EVM legacy assembly data reference.
|
|
||||||
/// # Panics
|
|
||||||
/// If the EVM data has not been initialized.
|
|
||||||
pub fn evmla(&self) -> &EVMLAData<'ctx> {
|
|
||||||
self.evmla_data
|
|
||||||
.as_ref()
|
|
||||||
.expect("The EVM data must have been initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the EVM legacy assembly data mutable reference.
|
|
||||||
/// # Panics
|
|
||||||
/// If the EVM data has not been initialized.
|
|
||||||
pub fn evmla_mut(&mut self) -> &mut EVMLAData<'ctx> {
|
|
||||||
self.evmla_data
|
|
||||||
.as_mut()
|
|
||||||
.expect("The EVM data must have been initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the Yul data.
|
/// Sets the Yul data.
|
||||||
pub fn set_yul_data(&mut self, data: YulData) {
|
pub fn set_yul_data(&mut self, data: YulData) {
|
||||||
self.yul_data = Some(data);
|
self.yul_data = Some(data);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ pub mod attribute;
|
|||||||
pub mod build;
|
pub mod build;
|
||||||
pub mod code_type;
|
pub mod code_type;
|
||||||
pub mod debug_info;
|
pub mod debug_info;
|
||||||
pub mod evmla_data;
|
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod global;
|
pub mod global;
|
||||||
pub mod r#loop;
|
pub mod r#loop;
|
||||||
@@ -38,7 +37,6 @@ use self::attribute::Attribute;
|
|||||||
use self::build::Build;
|
use self::build::Build;
|
||||||
use self::code_type::CodeType;
|
use self::code_type::CodeType;
|
||||||
use self::debug_info::DebugInfo;
|
use self::debug_info::DebugInfo;
|
||||||
use self::evmla_data::EVMLAData;
|
|
||||||
use self::function::declaration::Declaration as FunctionDeclaration;
|
use self::function::declaration::Declaration as FunctionDeclaration;
|
||||||
use self::function::intrinsics::Intrinsics;
|
use self::function::intrinsics::Intrinsics;
|
||||||
use self::function::llvm_runtime::LLVMRuntime;
|
use self::function::llvm_runtime::LLVMRuntime;
|
||||||
@@ -95,8 +93,6 @@ where
|
|||||||
solidity_data: Option<SolidityData>,
|
solidity_data: Option<SolidityData>,
|
||||||
/// The Yul data.
|
/// The Yul data.
|
||||||
yul_data: Option<YulData>,
|
yul_data: Option<YulData>,
|
||||||
/// The EVM legacy assembly data.
|
|
||||||
evmla_data: Option<EVMLAData<'ctx>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, D> Context<'ctx, D>
|
impl<'ctx, D> Context<'ctx, D>
|
||||||
@@ -257,7 +253,6 @@ where
|
|||||||
|
|
||||||
solidity_data: None,
|
solidity_data: None,
|
||||||
yul_data: None,
|
yul_data: None,
|
||||||
evmla_data: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1574,29 +1569,6 @@ where
|
|||||||
.expect("The Yul data must have been initialized")
|
.expect("The Yul data must have been initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the EVM legacy assembly data.
|
|
||||||
pub fn set_evmla_data(&mut self, data: EVMLAData<'ctx>) {
|
|
||||||
self.evmla_data = Some(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the EVM legacy assembly data reference.
|
|
||||||
/// # Panics
|
|
||||||
/// If the EVM data has not been initialized.
|
|
||||||
pub fn evmla(&self) -> &EVMLAData<'ctx> {
|
|
||||||
self.evmla_data
|
|
||||||
.as_ref()
|
|
||||||
.expect("The EVMLA data must have been initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the EVM legacy assembly data mutable reference.
|
|
||||||
/// # Panics
|
|
||||||
/// If the EVM data has not been initialized.
|
|
||||||
pub fn evmla_mut(&mut self) -> &mut EVMLAData<'ctx> {
|
|
||||||
self.evmla_data
|
|
||||||
.as_mut()
|
|
||||||
.expect("The EVMLA data must have been initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current number of immutables values in the contract.
|
/// Returns the current number of immutables values in the contract.
|
||||||
/// If the size is set manually, then it is returned. Otherwise, the number of elements in
|
/// If the size is set manually, then it is returned. Otherwise, the number of elements in
|
||||||
/// the identifier-to-offset mapping tree is returned.
|
/// the identifier-to-offset mapping tree is returned.
|
||||||
|
|||||||
@@ -239,7 +239,6 @@ pub enum Code {
|
|||||||
Solidity {
|
Solidity {
|
||||||
path: Option<std::path::PathBuf>,
|
path: Option<std::path::PathBuf>,
|
||||||
solc_optimizer: Option<bool>,
|
solc_optimizer: Option<bool>,
|
||||||
pipeline: Option<revive_solidity::SolcPipeline>,
|
|
||||||
contract: String,
|
contract: String,
|
||||||
},
|
},
|
||||||
/// Read the contract blob from disk
|
/// Read the contract blob from disk
|
||||||
@@ -264,7 +263,6 @@ impl From<Code> for pallet_revive::Code {
|
|||||||
path,
|
path,
|
||||||
contract,
|
contract,
|
||||||
solc_optimizer,
|
solc_optimizer,
|
||||||
pipeline,
|
|
||||||
} => {
|
} => {
|
||||||
let Some(path) = path else {
|
let Some(path) = path else {
|
||||||
panic!("Solidity source of contract '{contract}' missing path");
|
panic!("Solidity source of contract '{contract}' missing path");
|
||||||
@@ -276,7 +274,6 @@ impl From<Code> for pallet_revive::Code {
|
|||||||
&contract,
|
&contract,
|
||||||
&source_code,
|
&source_code,
|
||||||
solc_optimizer.unwrap_or(true),
|
solc_optimizer.unwrap_or(true),
|
||||||
pipeline.unwrap_or(revive_solidity::SolcPipeline::Yul),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Code::Path(path) => pallet_revive::Code::Upload(std::fs::read(path).unwrap()),
|
Code::Path(path) => pallet_revive::Code::Upload(std::fs::read(path).unwrap()),
|
||||||
|
|||||||
@@ -282,17 +282,11 @@ impl Specs {
|
|||||||
let Code::Solidity {
|
let Code::Solidity {
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
solc_optimizer,
|
solc_optimizer,
|
||||||
pipeline,
|
|
||||||
contract,
|
contract,
|
||||||
} = code
|
} = code
|
||||||
else {
|
else {
|
||||||
panic!("the differential runner requires Code::Solidity source");
|
panic!("the differential runner requires Code::Solidity source");
|
||||||
};
|
};
|
||||||
assert_ne!(
|
|
||||||
pipeline,
|
|
||||||
Some(revive_solidity::SolcPipeline::EVMLA),
|
|
||||||
"yul pipeline must be enabled in differential mode"
|
|
||||||
);
|
|
||||||
assert!(
|
assert!(
|
||||||
salt.0.is_none(),
|
salt.0.is_none(),
|
||||||
"salt is not supported in differential mode"
|
"salt is not supported in differential mode"
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ regex = { workspace = true }
|
|||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
num = { workspace = true }
|
num = { workspace = true }
|
||||||
sha3 = { workspace = true }
|
sha3 = { workspace = true }
|
||||||
md5 = { workspace = true }
|
|
||||||
inkwell = { workspace = true }
|
inkwell = { workspace = true }
|
||||||
|
|
||||||
revive-common = { workspace = true }
|
revive-common = { workspace = true }
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
//! The inner JSON legacy assembly code element.
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::evmla::assembly::Assembly;
|
|
||||||
|
|
||||||
/// The inner JSON legacy assembly code element.
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum Data {
|
|
||||||
/// The assembly code wrapper.
|
|
||||||
Assembly(Assembly),
|
|
||||||
/// The hash.
|
|
||||||
Hash(String),
|
|
||||||
/// The full contract path after the factory dependencies replacing pass.
|
|
||||||
Path(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Data {
|
|
||||||
/// Returns the inner assembly reference if it is present.
|
|
||||||
pub fn get_assembly(&self) -> Option<&Assembly> {
|
|
||||||
match self {
|
|
||||||
Self::Assembly(ref assembly) => Some(assembly),
|
|
||||||
Self::Hash(_) => None,
|
|
||||||
Self::Path(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Returns the inner assembly mutable reference if it is present.
|
|
||||||
pub fn get_assembly_mut(&mut self) -> Option<&mut Assembly> {
|
|
||||||
match self {
|
|
||||||
Self::Assembly(ref mut assembly) => Some(assembly),
|
|
||||||
Self::Hash(_) => None,
|
|
||||||
Self::Path(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the list of missing deployable libraries.
|
|
||||||
pub fn get_missing_libraries(&self) -> HashSet<String> {
|
|
||||||
match self {
|
|
||||||
Self::Assembly(assembly) => assembly.get_missing_libraries(),
|
|
||||||
Self::Hash(_) => HashSet::new(),
|
|
||||||
Self::Path(_) => HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the contract `keccak256` hash.
|
|
||||||
pub fn keccak256(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Self::Assembly(assembly) => assembly.keccak256(),
|
|
||||||
Self::Hash(hash) => panic!("Expected assembly, found hash `{hash}`"),
|
|
||||||
Self::Path(path) => panic!("Expected assembly, found path `{path}`"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Data {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Assembly(inner) => writeln!(f, "{inner}"),
|
|
||||||
Self::Hash(inner) => writeln!(f, "Hash `{inner}`"),
|
|
||||||
Self::Path(inner) => writeln!(f, "Path `{inner}`"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
//! Translates the CODECOPY use cases.
|
|
||||||
|
|
||||||
/// Translates the contract hash copying.
|
|
||||||
pub fn contract_hash<'ctx, D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
|
||||||
offset: inkwell::values::IntValue<'ctx>,
|
|
||||||
value: inkwell::values::IntValue<'ctx>,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let offset = context.builder().build_int_add(
|
|
||||||
offset,
|
|
||||||
context
|
|
||||||
.word_const((revive_common::BYTE_LENGTH_X32 + revive_common::BYTE_LENGTH_WORD) as u64),
|
|
||||||
"datacopy_contract_hash_offset",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_memory::store(context, offset, value)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the library marker copying.
|
|
||||||
pub fn library_marker<D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
offset: u64,
|
|
||||||
value: u64,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
revive_llvm_context::polkavm_evm_memory::store_byte(
|
|
||||||
context,
|
|
||||||
context.word_const(offset),
|
|
||||||
context.word_const(value),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the static data copying.
|
|
||||||
pub fn static_data<'ctx, D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
|
||||||
destination: inkwell::values::IntValue<'ctx>,
|
|
||||||
source: &str,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let mut offset = 0;
|
|
||||||
for (index, chunk) in source
|
|
||||||
.chars()
|
|
||||||
.collect::<Vec<char>>()
|
|
||||||
.chunks(revive_common::BYTE_LENGTH_WORD * 2)
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
let mut value_string = chunk.iter().collect::<String>();
|
|
||||||
value_string.push_str(
|
|
||||||
"0".repeat((revive_common::BYTE_LENGTH_WORD * 2) - chunk.len())
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let datacopy_destination = context.builder().build_int_add(
|
|
||||||
destination,
|
|
||||||
context.word_const(offset as u64),
|
|
||||||
format!("datacopy_destination_index_{index}").as_str(),
|
|
||||||
)?;
|
|
||||||
let datacopy_value = context.word_const_str_hex(value_string.as_str());
|
|
||||||
revive_llvm_context::polkavm_evm_memory::store(
|
|
||||||
context,
|
|
||||||
datacopy_destination,
|
|
||||||
datacopy_value,
|
|
||||||
)?;
|
|
||||||
offset += chunk.len() / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//! Translates the jump operations.
|
|
||||||
|
|
||||||
/// Translates the unconditional jump.
|
|
||||||
pub fn unconditional<D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
destination: num::BigUint,
|
|
||||||
stack_hash: md5::Digest,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let code_type = context
|
|
||||||
.code_type()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?;
|
|
||||||
let block_key = revive_llvm_context::PolkaVMFunctionBlockKey::new(code_type, destination);
|
|
||||||
|
|
||||||
let block = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.evmla()
|
|
||||||
.find_block(&block_key, &stack_hash)?;
|
|
||||||
context.build_unconditional_branch(block.inner());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the conditional jump.
|
|
||||||
pub fn conditional<D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
destination: num::BigUint,
|
|
||||||
stack_hash: md5::Digest,
|
|
||||||
stack_height: usize,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let code_type = context
|
|
||||||
.code_type()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?;
|
|
||||||
let block_key = revive_llvm_context::PolkaVMFunctionBlockKey::new(code_type, destination);
|
|
||||||
|
|
||||||
let condition_pointer = context.evmla().stack[stack_height]
|
|
||||||
.to_llvm()
|
|
||||||
.into_pointer_value();
|
|
||||||
let condition = context.build_load(
|
|
||||||
revive_llvm_context::PolkaVMPointer::new_stack_field(context, condition_pointer),
|
|
||||||
format!("conditional_{block_key}_condition").as_str(),
|
|
||||||
)?;
|
|
||||||
let condition = context.builder().build_int_compare(
|
|
||||||
inkwell::IntPredicate::NE,
|
|
||||||
condition.into_int_value(),
|
|
||||||
context.word_const(0),
|
|
||||||
format!("conditional_{block_key}_condition_compared").as_str(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let then_block = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.evmla()
|
|
||||||
.find_block(&block_key, &stack_hash)?;
|
|
||||||
let join_block =
|
|
||||||
context.append_basic_block(format!("conditional_{block_key}_join_block").as_str());
|
|
||||||
|
|
||||||
context.build_conditional_branch(condition, then_block.inner(), join_block)?;
|
|
||||||
|
|
||||||
context.set_basic_block(join_block);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,382 +0,0 @@
|
|||||||
//! The EVM instruction.
|
|
||||||
|
|
||||||
pub mod codecopy;
|
|
||||||
pub mod jump;
|
|
||||||
pub mod name;
|
|
||||||
pub mod stack;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use self::name::Name;
|
|
||||||
|
|
||||||
/// The EVM instruction.
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
|
||||||
pub struct Instruction {
|
|
||||||
/// The opcode or tag identifier.
|
|
||||||
pub name: Name,
|
|
||||||
/// The optional value argument.
|
|
||||||
pub value: Option<String>,
|
|
||||||
|
|
||||||
/// The source code identifier.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub source: Option<isize>,
|
|
||||||
/// The source code location begin.
|
|
||||||
pub begin: isize,
|
|
||||||
/// The source code location end.
|
|
||||||
pub end: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instruction {
|
|
||||||
/// Returns the number of input stack arguments.
|
|
||||||
pub const fn input_size(&self, version: &semver::Version) -> usize {
|
|
||||||
match self.name {
|
|
||||||
Name::POP => 1,
|
|
||||||
|
|
||||||
Name::JUMP => 1,
|
|
||||||
Name::JUMPI => 2,
|
|
||||||
|
|
||||||
Name::ADD => 2,
|
|
||||||
Name::SUB => 2,
|
|
||||||
Name::MUL => 2,
|
|
||||||
Name::DIV => 2,
|
|
||||||
Name::MOD => 2,
|
|
||||||
Name::SDIV => 2,
|
|
||||||
Name::SMOD => 2,
|
|
||||||
|
|
||||||
Name::LT => 2,
|
|
||||||
Name::GT => 2,
|
|
||||||
Name::EQ => 2,
|
|
||||||
Name::ISZERO => 1,
|
|
||||||
Name::SLT => 2,
|
|
||||||
Name::SGT => 2,
|
|
||||||
|
|
||||||
Name::OR => 2,
|
|
||||||
Name::XOR => 2,
|
|
||||||
Name::NOT => 1,
|
|
||||||
Name::AND => 2,
|
|
||||||
Name::SHL => 2,
|
|
||||||
Name::SHR => 2,
|
|
||||||
Name::SAR => 2,
|
|
||||||
Name::BYTE => 2,
|
|
||||||
|
|
||||||
Name::ADDMOD => 3,
|
|
||||||
Name::MULMOD => 3,
|
|
||||||
Name::EXP => 2,
|
|
||||||
Name::SIGNEXTEND => 2,
|
|
||||||
Name::SHA3 => 2,
|
|
||||||
Name::KECCAK256 => 2,
|
|
||||||
|
|
||||||
Name::MLOAD => 1,
|
|
||||||
Name::MSTORE => 2,
|
|
||||||
Name::MSTORE8 => 2,
|
|
||||||
Name::MCOPY => 3,
|
|
||||||
|
|
||||||
Name::SLOAD => 1,
|
|
||||||
Name::SSTORE => 2,
|
|
||||||
Name::TLOAD => 1,
|
|
||||||
Name::TSTORE => 2,
|
|
||||||
Name::PUSHIMMUTABLE => 0,
|
|
||||||
Name::ASSIGNIMMUTABLE => {
|
|
||||||
if version.minor >= 8 {
|
|
||||||
2
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Name::CALLDATALOAD => 1,
|
|
||||||
Name::CALLDATACOPY => 3,
|
|
||||||
Name::CODECOPY => 3,
|
|
||||||
Name::RETURNDATACOPY => 3,
|
|
||||||
Name::EXTCODESIZE => 1,
|
|
||||||
Name::EXTCODEHASH => 1,
|
|
||||||
|
|
||||||
Name::CALL => 7,
|
|
||||||
Name::CALLCODE => 7,
|
|
||||||
Name::STATICCALL => 6,
|
|
||||||
Name::DELEGATECALL => 6,
|
|
||||||
|
|
||||||
Name::RETURN => 2,
|
|
||||||
Name::REVERT => 2,
|
|
||||||
Name::SELFDESTRUCT => 1,
|
|
||||||
|
|
||||||
Name::LOG0 => 2,
|
|
||||||
Name::LOG1 => 3,
|
|
||||||
Name::LOG2 => 4,
|
|
||||||
Name::LOG3 => 5,
|
|
||||||
Name::LOG4 => 6,
|
|
||||||
|
|
||||||
Name::CREATE => 3,
|
|
||||||
Name::CREATE2 => 4,
|
|
||||||
|
|
||||||
Name::ZK_CREATE => 3,
|
|
||||||
Name::ZK_CREATE2 => 4,
|
|
||||||
|
|
||||||
Name::BALANCE => 1,
|
|
||||||
|
|
||||||
Name::BLOCKHASH => 1,
|
|
||||||
Name::BLOBHASH => 1,
|
|
||||||
|
|
||||||
Name::EXTCODECOPY => 4,
|
|
||||||
|
|
||||||
Name::RecursiveCall { input_size, .. } => input_size,
|
|
||||||
Name::RecursiveReturn { input_size } => input_size,
|
|
||||||
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of output stack arguments.
|
|
||||||
pub const fn output_size(&self) -> usize {
|
|
||||||
match self.name {
|
|
||||||
Name::PUSH => 1,
|
|
||||||
Name::PUSH_Data => 1,
|
|
||||||
Name::PUSH_Tag => 1,
|
|
||||||
Name::PUSH_ContractHash => 1,
|
|
||||||
Name::PUSH_ContractHashSize => 1,
|
|
||||||
Name::PUSHLIB => 1,
|
|
||||||
Name::PUSHDEPLOYADDRESS => 1,
|
|
||||||
|
|
||||||
Name::PUSH1 => 1,
|
|
||||||
Name::PUSH2 => 1,
|
|
||||||
Name::PUSH3 => 1,
|
|
||||||
Name::PUSH4 => 1,
|
|
||||||
Name::PUSH5 => 1,
|
|
||||||
Name::PUSH6 => 1,
|
|
||||||
Name::PUSH7 => 1,
|
|
||||||
Name::PUSH8 => 1,
|
|
||||||
Name::PUSH9 => 1,
|
|
||||||
Name::PUSH10 => 1,
|
|
||||||
Name::PUSH11 => 1,
|
|
||||||
Name::PUSH12 => 1,
|
|
||||||
Name::PUSH13 => 1,
|
|
||||||
Name::PUSH14 => 1,
|
|
||||||
Name::PUSH15 => 1,
|
|
||||||
Name::PUSH16 => 1,
|
|
||||||
Name::PUSH17 => 1,
|
|
||||||
Name::PUSH18 => 1,
|
|
||||||
Name::PUSH19 => 1,
|
|
||||||
Name::PUSH20 => 1,
|
|
||||||
Name::PUSH21 => 1,
|
|
||||||
Name::PUSH22 => 1,
|
|
||||||
Name::PUSH23 => 1,
|
|
||||||
Name::PUSH24 => 1,
|
|
||||||
Name::PUSH25 => 1,
|
|
||||||
Name::PUSH26 => 1,
|
|
||||||
Name::PUSH27 => 1,
|
|
||||||
Name::PUSH28 => 1,
|
|
||||||
Name::PUSH29 => 1,
|
|
||||||
Name::PUSH30 => 1,
|
|
||||||
Name::PUSH31 => 1,
|
|
||||||
Name::PUSH32 => 1,
|
|
||||||
|
|
||||||
Name::DUP1 => 1,
|
|
||||||
Name::DUP2 => 1,
|
|
||||||
Name::DUP3 => 1,
|
|
||||||
Name::DUP4 => 1,
|
|
||||||
Name::DUP5 => 1,
|
|
||||||
Name::DUP6 => 1,
|
|
||||||
Name::DUP7 => 1,
|
|
||||||
Name::DUP8 => 1,
|
|
||||||
Name::DUP9 => 1,
|
|
||||||
Name::DUP10 => 1,
|
|
||||||
Name::DUP11 => 1,
|
|
||||||
Name::DUP12 => 1,
|
|
||||||
Name::DUP13 => 1,
|
|
||||||
Name::DUP14 => 1,
|
|
||||||
Name::DUP15 => 1,
|
|
||||||
Name::DUP16 => 1,
|
|
||||||
|
|
||||||
Name::ADD => 1,
|
|
||||||
Name::SUB => 1,
|
|
||||||
Name::MUL => 1,
|
|
||||||
Name::DIV => 1,
|
|
||||||
Name::MOD => 1,
|
|
||||||
Name::SDIV => 1,
|
|
||||||
Name::SMOD => 1,
|
|
||||||
|
|
||||||
Name::LT => 1,
|
|
||||||
Name::GT => 1,
|
|
||||||
Name::EQ => 1,
|
|
||||||
Name::ISZERO => 1,
|
|
||||||
Name::SLT => 1,
|
|
||||||
Name::SGT => 1,
|
|
||||||
|
|
||||||
Name::OR => 1,
|
|
||||||
Name::XOR => 1,
|
|
||||||
Name::NOT => 1,
|
|
||||||
Name::AND => 1,
|
|
||||||
Name::SHL => 1,
|
|
||||||
Name::SHR => 1,
|
|
||||||
Name::SAR => 1,
|
|
||||||
Name::BYTE => 1,
|
|
||||||
|
|
||||||
Name::ADDMOD => 1,
|
|
||||||
Name::MULMOD => 1,
|
|
||||||
Name::EXP => 1,
|
|
||||||
Name::SIGNEXTEND => 1,
|
|
||||||
Name::SHA3 => 1,
|
|
||||||
Name::KECCAK256 => 1,
|
|
||||||
|
|
||||||
Name::MLOAD => 1,
|
|
||||||
|
|
||||||
Name::SLOAD => 1,
|
|
||||||
Name::TLOAD => 1,
|
|
||||||
Name::PUSHIMMUTABLE => 1,
|
|
||||||
|
|
||||||
Name::CALLDATALOAD => 1,
|
|
||||||
Name::CALLDATASIZE => 1,
|
|
||||||
Name::CODESIZE => 1,
|
|
||||||
Name::PUSHSIZE => 1,
|
|
||||||
Name::RETURNDATASIZE => 1,
|
|
||||||
Name::EXTCODESIZE => 1,
|
|
||||||
Name::EXTCODEHASH => 1,
|
|
||||||
|
|
||||||
Name::CALL => 1,
|
|
||||||
Name::CALLCODE => 1,
|
|
||||||
Name::STATICCALL => 1,
|
|
||||||
Name::DELEGATECALL => 1,
|
|
||||||
|
|
||||||
Name::CREATE => 1,
|
|
||||||
Name::CREATE2 => 1,
|
|
||||||
|
|
||||||
Name::ZK_CREATE => 1,
|
|
||||||
Name::ZK_CREATE2 => 1,
|
|
||||||
|
|
||||||
Name::ADDRESS => 1,
|
|
||||||
Name::CALLER => 1,
|
|
||||||
Name::TIMESTAMP => 1,
|
|
||||||
Name::NUMBER => 1,
|
|
||||||
|
|
||||||
Name::CALLVALUE => 1,
|
|
||||||
Name::GAS => 1,
|
|
||||||
Name::BALANCE => 1,
|
|
||||||
Name::SELFBALANCE => 1,
|
|
||||||
|
|
||||||
Name::GASLIMIT => 1,
|
|
||||||
Name::GASPRICE => 1,
|
|
||||||
Name::ORIGIN => 1,
|
|
||||||
Name::CHAINID => 1,
|
|
||||||
Name::BLOCKHASH => 1,
|
|
||||||
Name::BLOBHASH => 1,
|
|
||||||
Name::DIFFICULTY => 1,
|
|
||||||
Name::PREVRANDAO => 1,
|
|
||||||
Name::COINBASE => 1,
|
|
||||||
Name::MSIZE => 1,
|
|
||||||
|
|
||||||
Name::BASEFEE => 1,
|
|
||||||
Name::BLOBBASEFEE => 1,
|
|
||||||
Name::PC => 1,
|
|
||||||
|
|
||||||
Name::RecursiveCall { output_size, .. } => output_size,
|
|
||||||
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replaces the instruction data aliases with the actual data.
|
|
||||||
pub fn replace_data_aliases(
|
|
||||||
instructions: &mut [Self],
|
|
||||||
mapping: &BTreeMap<String, String>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
for instruction in instructions.iter_mut() {
|
|
||||||
match instruction {
|
|
||||||
Instruction {
|
|
||||||
name: Name::PUSH_ContractHash | Name::PUSH_ContractHashSize,
|
|
||||||
value: Some(value),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*value = mapping.get(value.as_str()).cloned().ok_or_else(|| {
|
|
||||||
anyhow::anyhow!("Contract alias `{}` data not found", value)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Instruction {
|
|
||||||
name: Name::PUSH_Data,
|
|
||||||
value: Some(value),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let mut key_extended =
|
|
||||||
"0".repeat(revive_common::BYTE_LENGTH_WORD * 2 - value.len());
|
|
||||||
key_extended.push_str(value.as_str());
|
|
||||||
|
|
||||||
*value = mapping.get(key_extended.as_str()).cloned().ok_or_else(|| {
|
|
||||||
anyhow::anyhow!("Data chunk alias `{}` data not found", key_extended)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes an `INVALID` instruction to terminate an invalid unreachable block part.
|
|
||||||
pub fn invalid(previous: &Self) -> Self {
|
|
||||||
Self {
|
|
||||||
name: Name::INVALID,
|
|
||||||
value: None,
|
|
||||||
|
|
||||||
source: previous.source,
|
|
||||||
begin: previous.begin,
|
|
||||||
end: previous.end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes a recursive function `Call` instruction.
|
|
||||||
pub fn recursive_call(
|
|
||||||
name: String,
|
|
||||||
entry_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
stack_hash: md5::Digest,
|
|
||||||
input_size: usize,
|
|
||||||
output_size: usize,
|
|
||||||
return_address: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
previous: &Self,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name: Name::RecursiveCall {
|
|
||||||
name,
|
|
||||||
entry_key,
|
|
||||||
stack_hash,
|
|
||||||
input_size,
|
|
||||||
output_size,
|
|
||||||
return_address,
|
|
||||||
},
|
|
||||||
value: None,
|
|
||||||
|
|
||||||
source: previous.source,
|
|
||||||
begin: previous.begin,
|
|
||||||
end: previous.end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes a recursive function `Return` instruction.
|
|
||||||
pub fn recursive_return(input_size: usize, previous: &Self) -> Self {
|
|
||||||
Self {
|
|
||||||
name: Name::RecursiveReturn { input_size },
|
|
||||||
value: None,
|
|
||||||
|
|
||||||
source: previous.source,
|
|
||||||
begin: previous.begin,
|
|
||||||
end: previous.end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Instruction {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let name = self.name.to_string();
|
|
||||||
match self.name {
|
|
||||||
Name::Tag => write!(f, "{:4}", name),
|
|
||||||
_ => write!(f, "{:15}", name),
|
|
||||||
}?;
|
|
||||||
match self.value {
|
|
||||||
Some(ref value) if value.len() <= 64 => write!(f, "{}", value)?,
|
|
||||||
Some(ref value) => write!(f, "... {}", &value[value.len() - 60..])?,
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,417 +0,0 @@
|
|||||||
//! The EVM instruction name.
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
/// The EVM instruction name.
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
|
||||||
pub enum Name {
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH,
|
|
||||||
/// Pushes a constant tag index.
|
|
||||||
#[serde(rename = "PUSH [tag]")]
|
|
||||||
PUSH_Tag,
|
|
||||||
/// Pushes an unknown `data` value.
|
|
||||||
#[serde(rename = "PUSH data")]
|
|
||||||
PUSH_Data,
|
|
||||||
/// Pushes a contract hash size.
|
|
||||||
#[serde(rename = "PUSH #[$]")]
|
|
||||||
PUSH_ContractHashSize,
|
|
||||||
/// Pushes a contract hash.
|
|
||||||
#[serde(rename = "PUSH [$]")]
|
|
||||||
PUSH_ContractHash,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH1,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH2,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH3,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH4,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH5,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH6,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH7,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH8,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH9,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH10,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH11,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH12,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH13,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH14,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH15,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH16,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH17,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH18,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH19,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH20,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH21,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH22,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH23,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH24,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH25,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH26,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH27,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH28,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH29,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH30,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH31,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSH32,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP1,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP2,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP3,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP4,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP5,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP6,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP7,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP8,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP9,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP10,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP11,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP12,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP13,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP14,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP15,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DUP16,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP1,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP2,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP3,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP4,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP5,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP6,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP7,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP8,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP9,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP10,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP11,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP12,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP13,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP14,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP15,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SWAP16,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
POP,
|
|
||||||
|
|
||||||
/// Sets the current basic code block.
|
|
||||||
#[serde(rename = "tag")]
|
|
||||||
Tag,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
JUMP,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
JUMPI,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
JUMPDEST,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
ADD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SUB,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MUL,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DIV,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MOD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SDIV,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SMOD,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
LT,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
GT,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
EQ,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
ISZERO,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SLT,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SGT,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
OR,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
XOR,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
NOT,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
AND,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SHL,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SHR,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SAR,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
BYTE,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
ADDMOD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MULMOD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
EXP,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SIGNEXTEND,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SHA3,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
KECCAK256,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MLOAD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MSTORE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MSTORE8,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MCOPY,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SLOAD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SSTORE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
TLOAD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
TSTORE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSHIMMUTABLE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
ASSIGNIMMUTABLE,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALLDATALOAD,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALLDATASIZE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALLDATACOPY,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CODESIZE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CODECOPY,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSHSIZE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
EXTCODESIZE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
EXTCODEHASH,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
RETURNDATASIZE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
RETURNDATACOPY,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
RETURN,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
REVERT,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
STOP,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
INVALID,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
LOG0,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
LOG1,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
LOG2,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
LOG3,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
LOG4,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALL,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
STATICCALL,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DELEGATECALL,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CREATE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CREATE2,
|
|
||||||
|
|
||||||
/// The eponymous PolkaVM instruction.
|
|
||||||
#[serde(rename = "$ZK_CREATE")]
|
|
||||||
ZK_CREATE,
|
|
||||||
/// The eponymous PolkaVM instruction.
|
|
||||||
#[serde(rename = "$ZK_CREATE2")]
|
|
||||||
ZK_CREATE2,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
ADDRESS,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALLER,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALLVALUE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
GAS,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
BALANCE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SELFBALANCE,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSHLIB,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PUSHDEPLOYADDRESS,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
GASLIMIT,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
GASPRICE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
ORIGIN,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CHAINID,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
TIMESTAMP,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
NUMBER,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
BLOCKHASH,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
BLOBHASH,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
DIFFICULTY,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PREVRANDAO,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
COINBASE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
BASEFEE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
BLOBBASEFEE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
MSIZE,
|
|
||||||
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
CALLCODE,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
PC,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
EXTCODECOPY,
|
|
||||||
/// The eponymous EVM instruction.
|
|
||||||
SELFDESTRUCT,
|
|
||||||
|
|
||||||
/// The recursive function call instruction.
|
|
||||||
#[serde(skip)]
|
|
||||||
RecursiveCall {
|
|
||||||
/// The called function name.
|
|
||||||
name: String,
|
|
||||||
/// The called function key.
|
|
||||||
entry_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
/// The stack state hash after return.
|
|
||||||
stack_hash: md5::Digest,
|
|
||||||
/// The input size.
|
|
||||||
input_size: usize,
|
|
||||||
/// The output size.
|
|
||||||
output_size: usize,
|
|
||||||
/// The return address.
|
|
||||||
return_address: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
},
|
|
||||||
/// The recursive function return instruction.
|
|
||||||
#[serde(skip)]
|
|
||||||
RecursiveReturn {
|
|
||||||
/// The output size.
|
|
||||||
input_size: usize,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Tag => write!(f, "Tag"),
|
|
||||||
Self::RecursiveCall {
|
|
||||||
name,
|
|
||||||
entry_key,
|
|
||||||
input_size,
|
|
||||||
output_size,
|
|
||||||
return_address,
|
|
||||||
..
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"RECURSIVE_CALL({}_{}, {}, {}, {})",
|
|
||||||
name, entry_key, input_size, output_size, return_address
|
|
||||||
),
|
|
||||||
Self::RecursiveReturn { input_size } => write!(f, "RECURSIVE_RETURN({})", input_size),
|
|
||||||
_ => write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
serde_json::to_string(self)
|
|
||||||
.expect("Always valid")
|
|
||||||
.trim_matches('\"')
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
//! Translates the stack memory operations.
|
|
||||||
|
|
||||||
use inkwell::values::BasicValue;
|
|
||||||
|
|
||||||
/// Translates the ordinar value push.
|
|
||||||
pub fn push<'ctx, D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
|
||||||
value: String,
|
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let result = context
|
|
||||||
.word_type()
|
|
||||||
.const_int_from_string(
|
|
||||||
value.to_ascii_uppercase().as_str(),
|
|
||||||
inkwell::types::StringRadix::Hexadecimal,
|
|
||||||
)
|
|
||||||
.expect("Always valid")
|
|
||||||
.as_basic_value_enum();
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the block tag label push.
|
|
||||||
pub fn push_tag<'ctx, D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
|
||||||
value: String,
|
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let result = context
|
|
||||||
.word_type()
|
|
||||||
.const_int_from_string(value.as_str(), inkwell::types::StringRadix::Decimal)
|
|
||||||
.expect("Always valid");
|
|
||||||
Ok(result.as_basic_value_enum())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the stack memory duplicate.
|
|
||||||
pub fn dup<'ctx, D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
|
||||||
offset: usize,
|
|
||||||
height: usize,
|
|
||||||
original: &mut Option<String>,
|
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let element = &context.evmla().stack[height - offset - 1];
|
|
||||||
let value = context.build_load(
|
|
||||||
revive_llvm_context::PolkaVMPointer::new_stack_field(
|
|
||||||
context,
|
|
||||||
element.to_llvm().into_pointer_value(),
|
|
||||||
),
|
|
||||||
format!("dup{offset}").as_str(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
element.original.clone_into(original);
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the stack memory swap.
|
|
||||||
pub fn swap<D>(
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
offset: usize,
|
|
||||||
height: usize,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
let top_element = context.evmla().stack[height - 1].to_owned();
|
|
||||||
let top_pointer = revive_llvm_context::PolkaVMPointer::new_stack_field(
|
|
||||||
context,
|
|
||||||
top_element.to_llvm().into_pointer_value(),
|
|
||||||
);
|
|
||||||
let top_value = context.build_load(top_pointer, format!("swap{offset}_top_value").as_str())?;
|
|
||||||
|
|
||||||
let swap_element = context.evmla().stack[height - offset - 1].to_owned();
|
|
||||||
let swap_pointer = revive_llvm_context::PolkaVMPointer::new_stack_field(
|
|
||||||
context,
|
|
||||||
swap_element.to_llvm().into_pointer_value(),
|
|
||||||
);
|
|
||||||
let swap_value =
|
|
||||||
context.build_load(swap_pointer, format!("swap{offset}_swap_value").as_str())?;
|
|
||||||
|
|
||||||
swap_element
|
|
||||||
.original
|
|
||||||
.clone_into(&mut context.evmla_mut().stack[height - 1].original);
|
|
||||||
top_element
|
|
||||||
.original
|
|
||||||
.clone_into(&mut context.evmla_mut().stack[height - offset - 1].original);
|
|
||||||
|
|
||||||
context.build_store(top_pointer, swap_value)?;
|
|
||||||
context.build_store(swap_pointer, top_value)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translates the stack memory pop.
|
|
||||||
pub fn pop<D>(_context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
//! The `solc --asm-json` output.
|
|
||||||
|
|
||||||
pub mod data;
|
|
||||||
pub mod instruction;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
use sha3::Digest;
|
|
||||||
|
|
||||||
use crate::evmla::ethereal_ir::entry_link::EntryLink;
|
|
||||||
use crate::evmla::ethereal_ir::EtherealIR;
|
|
||||||
use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata;
|
|
||||||
|
|
||||||
use self::data::Data;
|
|
||||||
use self::instruction::name::Name as InstructionName;
|
|
||||||
use self::instruction::Instruction;
|
|
||||||
|
|
||||||
/// The JSON assembly.
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct Assembly {
|
|
||||||
/// The metadata string.
|
|
||||||
#[serde(rename = ".auxdata")]
|
|
||||||
pub auxdata: Option<String>,
|
|
||||||
/// The deploy code instructions.
|
|
||||||
#[serde(rename = ".code")]
|
|
||||||
pub code: Option<Vec<Instruction>>,
|
|
||||||
/// The runtime code.
|
|
||||||
#[serde(rename = ".data")]
|
|
||||||
pub data: Option<BTreeMap<String, Data>>,
|
|
||||||
|
|
||||||
/// The full contract path.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub full_path: Option<String>,
|
|
||||||
/// The factory dependency paths.
|
|
||||||
#[serde(default = "HashSet::new")]
|
|
||||||
pub factory_dependencies: HashSet<String>,
|
|
||||||
/// The EVMLA extra metadata.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub extra_metadata: Option<ExtraMetadata>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Assembly {
|
|
||||||
/// Gets the contract `keccak256` hash.
|
|
||||||
pub fn keccak256(&self) -> String {
|
|
||||||
let json = serde_json::to_vec(self).expect("Always valid");
|
|
||||||
hex::encode(sha3::Keccak256::digest(json.as_slice()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the full contract path.
|
|
||||||
pub fn set_full_path(&mut self, full_path: String) {
|
|
||||||
self.full_path = Some(full_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the full contract path if it is set, or `<undefined>` otherwise.
|
|
||||||
/// # Panics
|
|
||||||
/// If the `full_path` has not been set.
|
|
||||||
pub fn full_path(&self) -> &str {
|
|
||||||
self.full_path
|
|
||||||
.as_deref()
|
|
||||||
.unwrap_or_else(|| panic!("The full path of some contracts is unset"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the list of missing deployable libraries.
|
|
||||||
pub fn get_missing_libraries(&self) -> HashSet<String> {
|
|
||||||
let mut missing_libraries = HashSet::new();
|
|
||||||
if let Some(code) = self.code.as_ref() {
|
|
||||||
for instruction in code.iter() {
|
|
||||||
if let InstructionName::PUSHLIB = instruction.name {
|
|
||||||
let library_path = instruction.value.to_owned().expect("Always exists");
|
|
||||||
missing_libraries.insert(library_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(data) = self.data.as_ref() {
|
|
||||||
for (_, data) in data.iter() {
|
|
||||||
missing_libraries.extend(data.get_missing_libraries());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
missing_libraries
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replaces the deploy code dependencies with full contract path and returns the list.
|
|
||||||
pub fn deploy_dependencies_pass(
|
|
||||||
&mut self,
|
|
||||||
full_path: &str,
|
|
||||||
hash_data_mapping: &BTreeMap<String, String>,
|
|
||||||
) -> anyhow::Result<BTreeMap<String, String>> {
|
|
||||||
let mut index_path_mapping = BTreeMap::new();
|
|
||||||
let index = "0".repeat(revive_common::BYTE_LENGTH_WORD * 2);
|
|
||||||
index_path_mapping.insert(index, full_path.to_owned());
|
|
||||||
|
|
||||||
let dependencies = match self.data.as_mut() {
|
|
||||||
Some(dependencies) => dependencies,
|
|
||||||
None => return Ok(index_path_mapping),
|
|
||||||
};
|
|
||||||
for (index, data) in dependencies.iter_mut() {
|
|
||||||
if index == "0" {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut index_extended = "0".repeat(revive_common::BYTE_LENGTH_WORD * 2 - index.len());
|
|
||||||
index_extended.push_str(index.as_str());
|
|
||||||
|
|
||||||
*data = match data {
|
|
||||||
Data::Assembly(assembly) => {
|
|
||||||
let hash = assembly.keccak256();
|
|
||||||
let full_path =
|
|
||||||
hash_data_mapping
|
|
||||||
.get(hash.as_str())
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| {
|
|
||||||
anyhow::anyhow!("Contract path not found for hash `{}`", hash)
|
|
||||||
})?;
|
|
||||||
self.factory_dependencies.insert(full_path.to_owned());
|
|
||||||
|
|
||||||
index_path_mapping.insert(index_extended, full_path.clone());
|
|
||||||
Data::Path(full_path)
|
|
||||||
}
|
|
||||||
Data::Hash(hash) => {
|
|
||||||
index_path_mapping.insert(index_extended, hash.to_owned());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(index_path_mapping)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replaces the runtime code dependencies with full contract path and returns the list.
|
|
||||||
pub fn runtime_dependencies_pass(
|
|
||||||
&mut self,
|
|
||||||
full_path: &str,
|
|
||||||
hash_data_mapping: &BTreeMap<String, String>,
|
|
||||||
) -> anyhow::Result<BTreeMap<String, String>> {
|
|
||||||
let mut index_path_mapping = BTreeMap::new();
|
|
||||||
let index = "0".repeat(revive_common::BYTE_LENGTH_WORD * 2);
|
|
||||||
index_path_mapping.insert(index, full_path.to_owned());
|
|
||||||
|
|
||||||
let dependencies = match self
|
|
||||||
.data
|
|
||||||
.as_mut()
|
|
||||||
.and_then(|data| data.get_mut("0"))
|
|
||||||
.and_then(|data| data.get_assembly_mut())
|
|
||||||
.and_then(|assembly| assembly.data.as_mut())
|
|
||||||
{
|
|
||||||
Some(dependencies) => dependencies,
|
|
||||||
None => return Ok(index_path_mapping),
|
|
||||||
};
|
|
||||||
for (index, data) in dependencies.iter_mut() {
|
|
||||||
let mut index_extended = "0".repeat(revive_common::BYTE_LENGTH_WORD * 2 - index.len());
|
|
||||||
index_extended.push_str(index.as_str());
|
|
||||||
|
|
||||||
*data = match data {
|
|
||||||
Data::Assembly(assembly) => {
|
|
||||||
let hash = assembly.keccak256();
|
|
||||||
let full_path =
|
|
||||||
hash_data_mapping
|
|
||||||
.get(hash.as_str())
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| {
|
|
||||||
anyhow::anyhow!("Contract path not found for hash `{}`", hash)
|
|
||||||
})?;
|
|
||||||
self.factory_dependencies.insert(full_path.to_owned());
|
|
||||||
|
|
||||||
index_path_mapping.insert(index_extended, full_path.clone());
|
|
||||||
Data::Path(full_path)
|
|
||||||
}
|
|
||||||
Data::Hash(hash) => {
|
|
||||||
index_path_mapping.insert(index_extended, hash.to_owned());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(index_path_mapping)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for Assembly
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
fn declare(
|
|
||||||
&mut self,
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let mut entry = revive_llvm_context::PolkaVMEntryFunction::default();
|
|
||||||
entry.declare(context)?;
|
|
||||||
|
|
||||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(
|
|
||||||
revive_llvm_context::PolkaVMDummyLLVMWritable::default(),
|
|
||||||
)
|
|
||||||
.declare(context)?;
|
|
||||||
revive_llvm_context::PolkaVMRuntimeCodeFunction::new(
|
|
||||||
revive_llvm_context::PolkaVMDummyLLVMWritable::default(),
|
|
||||||
)
|
|
||||||
.declare(context)?;
|
|
||||||
revive_llvm_context::PolkaVMImmutableDataLoadFunction.declare(context)?;
|
|
||||||
|
|
||||||
entry.into_llvm(context)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_llvm(
|
|
||||||
mut self,
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let full_path = self.full_path().to_owned();
|
|
||||||
|
|
||||||
context
|
|
||||||
.debug_config()
|
|
||||||
.dump_evmla(full_path.as_str(), self.to_string().as_str())?;
|
|
||||||
|
|
||||||
let deploy_code_blocks = EtherealIR::get_blocks(
|
|
||||||
context.evmla().version.to_owned(),
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy,
|
|
||||||
self.code
|
|
||||||
.as_deref()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Deploy code instructions not found"))?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let data = self
|
|
||||||
.data
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Runtime code data not found"))?
|
|
||||||
.remove("0")
|
|
||||||
.expect("Always exists");
|
|
||||||
|
|
||||||
context
|
|
||||||
.debug_config()
|
|
||||||
.dump_evmla(full_path.as_str(), data.to_string().as_str())?;
|
|
||||||
|
|
||||||
let runtime_code_instructions = match data {
|
|
||||||
Data::Assembly(assembly) => assembly
|
|
||||||
.code
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Runtime code instructions not found"))?,
|
|
||||||
Data::Hash(hash) => {
|
|
||||||
anyhow::bail!("Expected runtime code instructions, found hash `{}`", hash)
|
|
||||||
}
|
|
||||||
Data::Path(path) => {
|
|
||||||
anyhow::bail!("Expected runtime code instructions, found path `{}`", path)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let runtime_code_blocks = EtherealIR::get_blocks(
|
|
||||||
context.evmla().version.to_owned(),
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime,
|
|
||||||
runtime_code_instructions.as_slice(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let extra_metadata = self.extra_metadata.take().unwrap_or_default();
|
|
||||||
let mut blocks = deploy_code_blocks;
|
|
||||||
blocks.extend(runtime_code_blocks);
|
|
||||||
let mut ethereal_ir =
|
|
||||||
EtherealIR::new(context.evmla().version.to_owned(), extra_metadata, blocks)?;
|
|
||||||
|
|
||||||
context
|
|
||||||
.debug_config()
|
|
||||||
.dump_ethir(full_path.as_str(), ethereal_ir.to_string().as_str())?;
|
|
||||||
|
|
||||||
ethereal_ir.declare(context)?;
|
|
||||||
ethereal_ir.into_llvm(context)?;
|
|
||||||
|
|
||||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(EntryLink::new(
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy,
|
|
||||||
))
|
|
||||||
.into_llvm(context)?;
|
|
||||||
revive_llvm_context::PolkaVMRuntimeCodeFunction::new(EntryLink::new(
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime,
|
|
||||||
))
|
|
||||||
.into_llvm(context)?;
|
|
||||||
revive_llvm_context::PolkaVMImmutableDataLoadFunction.into_llvm(context)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Assembly {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
if let Some(instructions) = self.code.as_ref() {
|
|
||||||
for (index, instruction) in instructions.iter().enumerate() {
|
|
||||||
match instruction.name {
|
|
||||||
InstructionName::Tag => writeln!(f, "{index:03} {instruction}")?,
|
|
||||||
_ => writeln!(f, "{index:03} {instruction}")?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
//! The Ethereal IR entry function link.
|
|
||||||
|
|
||||||
use inkwell::values::BasicValue;
|
|
||||||
|
|
||||||
use crate::evmla::ethereal_ir::EtherealIR;
|
|
||||||
|
|
||||||
/// The Ethereal IR entry function link.
|
|
||||||
/// The link represents branching between the deploy and runtime code.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EntryLink {
|
|
||||||
/// The code part type.
|
|
||||||
pub code_type: revive_llvm_context::PolkaVMCodeType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EntryLink {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(code_type: revive_llvm_context::PolkaVMCodeType) -> Self {
|
|
||||||
Self { code_type }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for EntryLink
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
|
||||||
let target = context
|
|
||||||
.get_function(EtherealIR::DEFAULT_ENTRY_FUNCTION_NAME)
|
|
||||||
.expect("Always exists")
|
|
||||||
.borrow()
|
|
||||||
.declaration();
|
|
||||||
let is_deploy_code = match self.code_type {
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy => context
|
|
||||||
.integer_type(revive_common::BIT_LENGTH_BOOLEAN)
|
|
||||||
.const_int(1, false),
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime => context
|
|
||||||
.integer_type(revive_common::BIT_LENGTH_BOOLEAN)
|
|
||||||
.const_int(0, false),
|
|
||||||
};
|
|
||||||
context.build_call(
|
|
||||||
target,
|
|
||||||
&[is_deploy_code.as_basic_value_enum()],
|
|
||||||
format!("call_link_{}", EtherealIR::DEFAULT_ENTRY_FUNCTION_NAME).as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
|||||||
//! The Ethereal IR block element stack element.
|
|
||||||
|
|
||||||
/// The Ethereal IR block element stack element.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Element {
|
|
||||||
/// The runtime value.
|
|
||||||
Value(String),
|
|
||||||
/// The compile-time value.
|
|
||||||
Constant(num::BigUint),
|
|
||||||
/// The compile-time destination tag.
|
|
||||||
Tag(num::BigUint),
|
|
||||||
/// The compile-time path.
|
|
||||||
Path(String),
|
|
||||||
/// The compile-time hexadecimal data chunk.
|
|
||||||
Data(String),
|
|
||||||
/// The recursive function return address.
|
|
||||||
ReturnAddress(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Element {
|
|
||||||
pub fn value(identifier: String) -> Self {
|
|
||||||
Self::Value(identifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Element {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Value(identifier) => write!(f, "V_{identifier}"),
|
|
||||||
Self::Constant(value) => write!(f, "{value:X}"),
|
|
||||||
Self::Tag(tag) => write!(f, "T_{tag}"),
|
|
||||||
Self::Path(path) => write!(f, "{path}"),
|
|
||||||
Self::Data(data) => write!(f, "{data}"),
|
|
||||||
Self::ReturnAddress(_) => write!(f, "RETURN_ADDRESS"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
//! The Ethereal IR block element stack.
|
|
||||||
|
|
||||||
pub mod element;
|
|
||||||
|
|
||||||
use self::element::Element;
|
|
||||||
|
|
||||||
/// The Ethereal IR block element stack.
|
|
||||||
#[derive(Debug, Default, Clone)]
|
|
||||||
pub struct Stack {
|
|
||||||
/// The stack elements.
|
|
||||||
pub elements: Vec<Element>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stack {
|
|
||||||
/// The default stack size.
|
|
||||||
pub const DEFAULT_STACK_SIZE: usize = 16;
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
elements: Vec::with_capacity(Self::DEFAULT_STACK_SIZE),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
elements: Vec::with_capacity(capacity),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new_with_elements(elements: Vec<Element>) -> Self {
|
|
||||||
Self { elements }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The stack state hash, which acts as a block identifier.
|
|
||||||
/// Each block clone has its own initial stack state, which uniquely identifies the block.
|
|
||||||
pub fn hash(&self) -> md5::Digest {
|
|
||||||
let mut hash_context = md5::Context::new();
|
|
||||||
for element in self.elements.iter() {
|
|
||||||
match element {
|
|
||||||
Element::Tag(tag) => hash_context.consume(tag.to_bytes_be()),
|
|
||||||
_ => hash_context.consume([0]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hash_context.compute()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pushes an element onto the stack.
|
|
||||||
pub fn push(&mut self, element: Element) {
|
|
||||||
self.elements.push(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Appends another stack on top of this one.
|
|
||||||
pub fn append(&mut self, other: &mut Self) {
|
|
||||||
self.elements.append(&mut other.elements);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pops a stack element.
|
|
||||||
pub fn pop(&mut self) -> anyhow::Result<Element> {
|
|
||||||
self.elements
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Stack underflow"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pops the tag from the top.
|
|
||||||
pub fn pop_tag(&mut self) -> anyhow::Result<num::BigUint> {
|
|
||||||
match self.elements.pop() {
|
|
||||||
Some(Element::Tag(tag)) => Ok(tag),
|
|
||||||
Some(element) => anyhow::bail!("Expected tag, found {}", element),
|
|
||||||
None => anyhow::bail!("Stack underflow"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Swaps two stack elements.
|
|
||||||
pub fn swap(&mut self, index: usize) -> anyhow::Result<()> {
|
|
||||||
if self.elements.len() < index + 1 {
|
|
||||||
anyhow::bail!("Stack underflow");
|
|
||||||
}
|
|
||||||
|
|
||||||
let length = self.elements.len();
|
|
||||||
self.elements.swap(length - 1, length - 1 - index);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duplicates a stack element.
|
|
||||||
pub fn dup(&mut self, index: usize) -> anyhow::Result<Element> {
|
|
||||||
if self.elements.len() < index {
|
|
||||||
anyhow::bail!("Stack underflow");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self.elements[self.elements.len() - index].to_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the stack length.
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.elements.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an emptiness flag.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.elements.len() == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Stack {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"[ {} ]",
|
|
||||||
self.elements
|
|
||||||
.iter()
|
|
||||||
.map(Element::to_string)
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" | ")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
//! The Ethereal IR block.
|
|
||||||
|
|
||||||
pub mod element;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use num::Zero;
|
|
||||||
|
|
||||||
use crate::evmla::assembly::instruction::name::Name as InstructionName;
|
|
||||||
use crate::evmla::assembly::instruction::Instruction;
|
|
||||||
|
|
||||||
use self::element::stack::Stack as ElementStack;
|
|
||||||
use self::element::Element;
|
|
||||||
|
|
||||||
/// The Ethereal IR block.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Block {
|
|
||||||
/// The Solidity compiler version.
|
|
||||||
pub solc_version: semver::Version,
|
|
||||||
/// The block key.
|
|
||||||
pub key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
/// The block instance.
|
|
||||||
pub instance: Option<usize>,
|
|
||||||
/// The block elements relevant to the stack consistency.
|
|
||||||
pub elements: Vec<Element>,
|
|
||||||
/// The block predecessors.
|
|
||||||
pub predecessors: HashSet<(revive_llvm_context::PolkaVMFunctionBlockKey, usize)>,
|
|
||||||
/// The initial stack state.
|
|
||||||
pub initial_stack: ElementStack,
|
|
||||||
/// The stack.
|
|
||||||
pub stack: ElementStack,
|
|
||||||
/// The extra block hashes for alternative routes.
|
|
||||||
pub extra_hashes: Vec<md5::Digest>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block {
|
|
||||||
/// The elements vector initial capacity.
|
|
||||||
pub const ELEMENTS_VECTOR_DEFAULT_CAPACITY: usize = 64;
|
|
||||||
/// The predecessors hashset initial capacity.
|
|
||||||
pub const PREDECESSORS_HASHSET_DEFAULT_CAPACITY: usize = 4;
|
|
||||||
|
|
||||||
/// Assembles a block from the sequence of instructions.
|
|
||||||
pub fn try_from_instructions(
|
|
||||||
solc_version: semver::Version,
|
|
||||||
code_type: revive_llvm_context::PolkaVMCodeType,
|
|
||||||
slice: &[Instruction],
|
|
||||||
) -> anyhow::Result<(Self, usize)> {
|
|
||||||
let mut cursor = 0;
|
|
||||||
|
|
||||||
let tag: num::BigUint = match slice[cursor].name {
|
|
||||||
InstructionName::Tag => {
|
|
||||||
let tag = slice[cursor]
|
|
||||||
.value
|
|
||||||
.as_deref()
|
|
||||||
.expect("Always exists")
|
|
||||||
.parse()
|
|
||||||
.expect("Always valid");
|
|
||||||
cursor += 1;
|
|
||||||
tag
|
|
||||||
}
|
|
||||||
_ => num::BigUint::zero(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut block = Self {
|
|
||||||
solc_version: solc_version.clone(),
|
|
||||||
key: revive_llvm_context::PolkaVMFunctionBlockKey::new(code_type, tag),
|
|
||||||
instance: None,
|
|
||||||
elements: Vec::with_capacity(Self::ELEMENTS_VECTOR_DEFAULT_CAPACITY),
|
|
||||||
predecessors: HashSet::with_capacity(Self::PREDECESSORS_HASHSET_DEFAULT_CAPACITY),
|
|
||||||
initial_stack: ElementStack::new(),
|
|
||||||
stack: ElementStack::new(),
|
|
||||||
extra_hashes: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut dead_code = false;
|
|
||||||
while cursor < slice.len() {
|
|
||||||
if !dead_code {
|
|
||||||
let element: Element = Element::new(solc_version.clone(), slice[cursor].to_owned());
|
|
||||||
block.elements.push(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
match slice[cursor].name {
|
|
||||||
InstructionName::RETURN
|
|
||||||
| InstructionName::REVERT
|
|
||||||
| InstructionName::STOP
|
|
||||||
| InstructionName::INVALID => {
|
|
||||||
cursor += 1;
|
|
||||||
dead_code = true;
|
|
||||||
}
|
|
||||||
InstructionName::JUMP => {
|
|
||||||
cursor += 1;
|
|
||||||
dead_code = true;
|
|
||||||
}
|
|
||||||
InstructionName::Tag => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
cursor += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((block, cursor))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts a predecessor tag.
|
|
||||||
pub fn insert_predecessor(
|
|
||||||
&mut self,
|
|
||||||
key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
instance: usize,
|
|
||||||
) {
|
|
||||||
self.predecessors.insert((key, instance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for Block
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
|
||||||
context.set_code_type(self.key.code_type);
|
|
||||||
|
|
||||||
for element in self.elements.into_iter() {
|
|
||||||
element.into_llvm(context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Block {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"block_{}/{}: {}",
|
|
||||||
self.key,
|
|
||||||
self.instance.unwrap_or_default(),
|
|
||||||
if self.predecessors.is_empty() {
|
|
||||||
"".to_owned()
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"(predecessors: {})",
|
|
||||||
self.predecessors
|
|
||||||
.iter()
|
|
||||||
.map(|(key, instance)| format!("{}/{}", key, instance))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(", ")
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
for element in self.elements.iter() {
|
|
||||||
writeln!(f, " {element}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +0,0 @@
|
|||||||
//! The Ethereal IR block queue element.
|
|
||||||
|
|
||||||
use crate::evmla::ethereal_ir::function::block::element::stack::Stack;
|
|
||||||
|
|
||||||
/// The Ethereal IR block queue element.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct QueueElement {
|
|
||||||
/// The block key.
|
|
||||||
pub block_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
/// The block predecessor.
|
|
||||||
pub predecessor: Option<(revive_llvm_context::PolkaVMFunctionBlockKey, usize)>,
|
|
||||||
/// The predecessor's last stack state.
|
|
||||||
pub stack: Stack,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QueueElement {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(
|
|
||||||
block_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
predecessor: Option<(revive_llvm_context::PolkaVMFunctionBlockKey, usize)>,
|
|
||||||
stack: Stack,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
block_key,
|
|
||||||
predecessor,
|
|
||||||
stack,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//! The Ethereal IR function type.
|
|
||||||
|
|
||||||
/// The Ethereal IR function type.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Type {
|
|
||||||
/// The initial function, combining deploy and runtime code.
|
|
||||||
Initial,
|
|
||||||
/// The recursive function with a specific block starting its recursive context.
|
|
||||||
Recursive {
|
|
||||||
/// The function name.
|
|
||||||
name: String,
|
|
||||||
/// The function initial block key.
|
|
||||||
block_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
/// The size of stack input (in cells or 256-bit words).
|
|
||||||
input_size: usize,
|
|
||||||
/// The size of stack output (in cells or 256-bit words).
|
|
||||||
output_size: usize,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Type {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new_initial() -> Self {
|
|
||||||
Self::Initial
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new_recursive(
|
|
||||||
name: String,
|
|
||||||
block_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
input_size: usize,
|
|
||||||
output_size: usize,
|
|
||||||
) -> Self {
|
|
||||||
Self::Recursive {
|
|
||||||
name,
|
|
||||||
block_key,
|
|
||||||
input_size,
|
|
||||||
output_size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//! The Ethereal IR block visited element.
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
/// The Ethereal IR block visited element.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct VisitedElement {
|
|
||||||
/// The block key.
|
|
||||||
pub block_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
/// The initial stack state hash.
|
|
||||||
pub stack_hash: md5::Digest,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VisitedElement {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(
|
|
||||||
block_key: revive_llvm_context::PolkaVMFunctionBlockKey,
|
|
||||||
stack_hash: md5::Digest,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
block_key,
|
|
||||||
stack_hash,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for VisitedElement {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for VisitedElement {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
match (self.block_key.code_type, other.block_key.code_type) {
|
|
||||||
(
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy,
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime,
|
|
||||||
) => Ordering::Less,
|
|
||||||
(
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime,
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy,
|
|
||||||
) => Ordering::Greater,
|
|
||||||
(
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy,
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Deploy,
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime,
|
|
||||||
revive_llvm_context::PolkaVMCodeType::Runtime,
|
|
||||||
) => {
|
|
||||||
let tag_comparison = self.block_key.tag.cmp(&other.block_key.tag);
|
|
||||||
if tag_comparison == Ordering::Equal {
|
|
||||||
if self.stack_hash == other.stack_hash {
|
|
||||||
Ordering::Equal
|
|
||||||
} else {
|
|
||||||
Ordering::Less
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tag_comparison
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
//! The Ethereal IR of the EVM bytecode.
|
|
||||||
|
|
||||||
pub mod entry_link;
|
|
||||||
pub mod function;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::evmla::assembly::instruction::Instruction;
|
|
||||||
use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata;
|
|
||||||
|
|
||||||
use self::function::block::Block;
|
|
||||||
use self::function::r#type::Type as FunctionType;
|
|
||||||
use self::function::Function;
|
|
||||||
|
|
||||||
/// The Ethereal IR of the EVM bytecode.
|
|
||||||
/// The Ethereal IR (EthIR) is a special IR between the EVM legacy assembly and LLVM IR. It is
|
|
||||||
/// created to facilitate the translation and provide an additional environment for applying some
|
|
||||||
/// transformations, duplicating parts of the call and control flow graphs, tracking the
|
|
||||||
/// data flow, and a few more algorithms of static analysis.
|
|
||||||
/// The most important feature of EthIR is flattening the block tags and duplicating blocks for
|
|
||||||
/// each of initial states of the stack. The LLVM IR supports only static control flow, so the
|
|
||||||
/// stack state must be known all the way throughout the program.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EtherealIR {
|
|
||||||
/// The Solidity compiler version.
|
|
||||||
pub solc_version: semver::Version,
|
|
||||||
/// The EVMLA extra metadata.
|
|
||||||
pub extra_metadata: ExtraMetadata,
|
|
||||||
/// The all-inlined function.
|
|
||||||
pub entry_function: Function,
|
|
||||||
/// The recursive functions.
|
|
||||||
pub recursive_functions: BTreeMap<revive_llvm_context::PolkaVMFunctionBlockKey, Function>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EtherealIR {
|
|
||||||
/// The default entry function name.
|
|
||||||
pub const DEFAULT_ENTRY_FUNCTION_NAME: &'static str = "main";
|
|
||||||
|
|
||||||
/// The blocks hashmap initial capacity.
|
|
||||||
pub const BLOCKS_HASHMAP_DEFAULT_CAPACITY: usize = 64;
|
|
||||||
|
|
||||||
/// Assembles a sequence of functions from the sequence of instructions.
|
|
||||||
pub fn new(
|
|
||||||
solc_version: semver::Version,
|
|
||||||
extra_metadata: ExtraMetadata,
|
|
||||||
blocks: HashMap<revive_llvm_context::PolkaVMFunctionBlockKey, Block>,
|
|
||||||
) -> anyhow::Result<Self> {
|
|
||||||
let mut entry_function = Function::new(solc_version.clone(), FunctionType::new_initial());
|
|
||||||
let mut recursive_functions = BTreeMap::new();
|
|
||||||
let mut visited_functions = BTreeSet::new();
|
|
||||||
entry_function.traverse(
|
|
||||||
&blocks,
|
|
||||||
&mut recursive_functions,
|
|
||||||
&extra_metadata,
|
|
||||||
&mut visited_functions,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
solc_version,
|
|
||||||
extra_metadata,
|
|
||||||
entry_function,
|
|
||||||
recursive_functions,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets blocks for the specified type of the contract code.
|
|
||||||
pub fn get_blocks(
|
|
||||||
solc_version: semver::Version,
|
|
||||||
code_type: revive_llvm_context::PolkaVMCodeType,
|
|
||||||
instructions: &[Instruction],
|
|
||||||
) -> anyhow::Result<HashMap<revive_llvm_context::PolkaVMFunctionBlockKey, Block>> {
|
|
||||||
let mut blocks = HashMap::with_capacity(Self::BLOCKS_HASHMAP_DEFAULT_CAPACITY);
|
|
||||||
let mut offset = 0;
|
|
||||||
|
|
||||||
while offset < instructions.len() {
|
|
||||||
let (block, size) = Block::try_from_instructions(
|
|
||||||
solc_version.clone(),
|
|
||||||
code_type,
|
|
||||||
&instructions[offset..],
|
|
||||||
)?;
|
|
||||||
blocks.insert(
|
|
||||||
revive_llvm_context::PolkaVMFunctionBlockKey::new(code_type, block.key.tag.clone()),
|
|
||||||
block,
|
|
||||||
);
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(blocks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for EtherealIR
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
fn declare(
|
|
||||||
&mut self,
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
self.entry_function.declare(context)?;
|
|
||||||
|
|
||||||
for (_key, function) in self.recursive_functions.iter_mut() {
|
|
||||||
function.declare(context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
|
||||||
context.evmla_mut().stack = vec![];
|
|
||||||
|
|
||||||
self.entry_function.into_llvm(context)?;
|
|
||||||
|
|
||||||
for (_key, function) in self.recursive_functions.into_iter() {
|
|
||||||
function.into_llvm(context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for EtherealIR {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
writeln!(f, "{}", self.entry_function)?;
|
|
||||||
|
|
||||||
for (_key, function) in self.recursive_functions.iter() {
|
|
||||||
writeln!(f, "{}", function)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
//! The EVM legacy assembly compiling tools.
|
|
||||||
|
|
||||||
pub mod assembly;
|
|
||||||
pub mod ethereal_ir;
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
pub(crate) mod build;
|
pub(crate) mod build;
|
||||||
pub(crate) mod r#const;
|
pub(crate) mod r#const;
|
||||||
pub(crate) mod evmla;
|
|
||||||
pub(crate) mod missing_libraries;
|
pub(crate) mod missing_libraries;
|
||||||
pub(crate) mod process;
|
pub(crate) mod process;
|
||||||
pub(crate) mod project;
|
pub(crate) mod project;
|
||||||
@@ -26,7 +25,6 @@ pub use self::project::Project;
|
|||||||
pub use self::r#const::*;
|
pub use self::r#const::*;
|
||||||
pub use self::solc::combined_json::contract::Contract as SolcCombinedJsonContract;
|
pub use self::solc::combined_json::contract::Contract as SolcCombinedJsonContract;
|
||||||
pub use self::solc::combined_json::CombinedJson as SolcCombinedJson;
|
pub use self::solc::combined_json::CombinedJson as SolcCombinedJson;
|
||||||
pub use self::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
pub use self::solc::solc_compiler::SolcCompiler;
|
pub use self::solc::solc_compiler::SolcCompiler;
|
||||||
#[cfg(target_os = "emscripten")]
|
#[cfg(target_os = "emscripten")]
|
||||||
@@ -119,7 +117,6 @@ pub fn standard_output<T: Compiler>(
|
|||||||
evm_version: Option<revive_common::EVMVersion>,
|
evm_version: Option<revive_common::EVMVersion>,
|
||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
||||||
force_evmla: bool,
|
|
||||||
include_metadata_hash: bool,
|
include_metadata_hash: bool,
|
||||||
base_path: Option<String>,
|
base_path: Option<String>,
|
||||||
include_paths: Vec<String>,
|
include_paths: Vec<String>,
|
||||||
@@ -129,7 +126,6 @@ pub fn standard_output<T: Compiler>(
|
|||||||
debug_config: revive_llvm_context::DebugConfig,
|
debug_config: revive_llvm_context::DebugConfig,
|
||||||
) -> anyhow::Result<Build> {
|
) -> anyhow::Result<Build> {
|
||||||
let solc_version = solc.version()?;
|
let solc_version = solc.version()?;
|
||||||
let solc_pipeline = SolcPipeline::new(&solc_version, force_evmla);
|
|
||||||
|
|
||||||
let solc_input = SolcStandardJsonInput::try_from_paths(
|
let solc_input = SolcStandardJsonInput::try_from_paths(
|
||||||
SolcStandardJsonInputLanguage::Solidity,
|
SolcStandardJsonInputLanguage::Solidity,
|
||||||
@@ -137,7 +133,7 @@ pub fn standard_output<T: Compiler>(
|
|||||||
input_files,
|
input_files,
|
||||||
libraries,
|
libraries,
|
||||||
remappings,
|
remappings,
|
||||||
SolcStandardJsonInputSettingsSelection::new_required(solc_pipeline),
|
SolcStandardJsonInputSettingsSelection::new_required(),
|
||||||
SolcStandardJsonInputSettingsOptimizer::new(
|
SolcStandardJsonInputSettingsOptimizer::new(
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
None,
|
None,
|
||||||
@@ -145,7 +141,6 @@ pub fn standard_output<T: Compiler>(
|
|||||||
optimizer_settings.is_fallback_to_size_enabled(),
|
optimizer_settings.is_fallback_to_size_enabled(),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
solc_pipeline == SolcPipeline::Yul,
|
|
||||||
suppressed_warnings,
|
suppressed_warnings,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -156,13 +151,7 @@ pub fn standard_output<T: Compiler>(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let libraries = solc_input.settings.libraries.clone().unwrap_or_default();
|
let libraries = solc_input.settings.libraries.clone().unwrap_or_default();
|
||||||
let mut solc_output = solc.standard_json(
|
let mut solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?;
|
||||||
solc_input,
|
|
||||||
solc_pipeline,
|
|
||||||
base_path,
|
|
||||||
include_paths,
|
|
||||||
allow_paths,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(errors) = solc_output.errors.as_deref() {
|
if let Some(errors) = solc_output.errors.as_deref() {
|
||||||
let mut has_errors = false;
|
let mut has_errors = false;
|
||||||
@@ -180,13 +169,8 @@ pub fn standard_output<T: Compiler>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let project = solc_output.try_to_project(
|
let project =
|
||||||
source_code_files,
|
solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?;
|
||||||
libraries,
|
|
||||||
solc_pipeline,
|
|
||||||
&solc_version,
|
|
||||||
&debug_config,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
|
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
|
||||||
|
|
||||||
@@ -198,16 +182,14 @@ pub fn standard_output<T: Compiler>(
|
|||||||
pub fn standard_json<T: Compiler>(
|
pub fn standard_json<T: Compiler>(
|
||||||
solc: &mut T,
|
solc: &mut T,
|
||||||
detect_missing_libraries: bool,
|
detect_missing_libraries: bool,
|
||||||
force_evmla: bool,
|
|
||||||
base_path: Option<String>,
|
base_path: Option<String>,
|
||||||
include_paths: Vec<String>,
|
include_paths: Vec<String>,
|
||||||
allow_paths: Option<String>,
|
allow_paths: Option<String>,
|
||||||
debug_config: revive_llvm_context::DebugConfig,
|
debug_config: revive_llvm_context::DebugConfig,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let solc_version = solc.version()?;
|
let solc_version = solc.version()?;
|
||||||
let solc_pipeline = SolcPipeline::new(&solc_version, force_evmla);
|
|
||||||
|
|
||||||
let solc_input = SolcStandardJsonInput::try_from_stdin(solc_pipeline)?;
|
let solc_input = SolcStandardJsonInput::try_from_stdin()?;
|
||||||
let source_code_files = solc_input
|
let source_code_files = solc_input
|
||||||
.sources
|
.sources
|
||||||
.iter()
|
.iter()
|
||||||
@@ -225,13 +207,7 @@ pub fn standard_json<T: Compiler>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let libraries = solc_input.settings.libraries.clone().unwrap_or_default();
|
let libraries = solc_input.settings.libraries.clone().unwrap_or_default();
|
||||||
let mut solc_output = solc.standard_json(
|
let mut solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?;
|
||||||
solc_input,
|
|
||||||
solc_pipeline,
|
|
||||||
base_path,
|
|
||||||
include_paths,
|
|
||||||
allow_paths,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(errors) = solc_output.errors.as_deref() {
|
if let Some(errors) = solc_output.errors.as_deref() {
|
||||||
for error in errors.iter() {
|
for error in errors.iter() {
|
||||||
@@ -242,13 +218,8 @@ pub fn standard_json<T: Compiler>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let project = solc_output.try_to_project(
|
let project =
|
||||||
source_code_files,
|
solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?;
|
||||||
libraries,
|
|
||||||
solc_pipeline,
|
|
||||||
&solc_version,
|
|
||||||
&debug_config,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if detect_missing_libraries {
|
if detect_missing_libraries {
|
||||||
let missing_libraries = project.get_missing_libraries();
|
let missing_libraries = project.get_missing_libraries();
|
||||||
@@ -271,7 +242,6 @@ pub fn combined_json<T: Compiler>(
|
|||||||
evm_version: Option<revive_common::EVMVersion>,
|
evm_version: Option<revive_common::EVMVersion>,
|
||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
||||||
force_evmla: bool,
|
|
||||||
include_metadata_hash: bool,
|
include_metadata_hash: bool,
|
||||||
base_path: Option<String>,
|
base_path: Option<String>,
|
||||||
include_paths: Vec<String>,
|
include_paths: Vec<String>,
|
||||||
@@ -289,7 +259,6 @@ pub fn combined_json<T: Compiler>(
|
|||||||
evm_version,
|
evm_version,
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
optimizer_settings,
|
optimizer_settings,
|
||||||
force_evmla,
|
|
||||||
include_metadata_hash,
|
include_metadata_hash,
|
||||||
base_path,
|
base_path,
|
||||||
include_paths,
|
include_paths,
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
//! The contract EVM legacy assembly source code.
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::evmla::assembly::Assembly;
|
|
||||||
use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata;
|
|
||||||
|
|
||||||
/// The contract EVM legacy assembly source code.
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
|
||||||
pub struct EVMLA {
|
|
||||||
/// The EVM legacy assembly source code.
|
|
||||||
pub assembly: Assembly,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EVMLA {
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(mut assembly: Assembly, extra_metadata: ExtraMetadata) -> Self {
|
|
||||||
assembly.extra_metadata = Some(extra_metadata);
|
|
||||||
Self { assembly }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the list of missing deployable libraries.
|
|
||||||
pub fn get_missing_libraries(&self) -> HashSet<String> {
|
|
||||||
self.assembly.get_missing_libraries()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for EVMLA
|
|
||||||
where
|
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
|
||||||
{
|
|
||||||
fn declare(
|
|
||||||
&mut self,
|
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
self.assembly.declare(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
|
||||||
self.assembly.into_llvm(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
//! The contract source code.
|
//! The contract source code.
|
||||||
|
|
||||||
pub mod evmla;
|
|
||||||
pub mod llvm_ir;
|
pub mod llvm_ir;
|
||||||
pub mod yul;
|
pub mod yul;
|
||||||
|
|
||||||
@@ -9,11 +8,8 @@ use std::collections::HashSet;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::evmla::assembly::Assembly;
|
|
||||||
use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata;
|
|
||||||
use crate::yul::parser::statement::object::Object;
|
use crate::yul::parser::statement::object::Object;
|
||||||
|
|
||||||
use self::evmla::EVMLA;
|
|
||||||
use self::llvm_ir::LLVMIR;
|
use self::llvm_ir::LLVMIR;
|
||||||
use self::yul::Yul;
|
use self::yul::Yul;
|
||||||
|
|
||||||
@@ -25,8 +21,6 @@ use self::yul::Yul;
|
|||||||
pub enum IR {
|
pub enum IR {
|
||||||
/// The Yul source code.
|
/// The Yul source code.
|
||||||
Yul(Yul),
|
Yul(Yul),
|
||||||
/// The EVM legacy assembly source code.
|
|
||||||
EVMLA(EVMLA),
|
|
||||||
/// The LLVM IR source code.
|
/// The LLVM IR source code.
|
||||||
LLVMIR(LLVMIR),
|
LLVMIR(LLVMIR),
|
||||||
}
|
}
|
||||||
@@ -37,11 +31,6 @@ impl IR {
|
|||||||
Self::Yul(Yul::new(source_code, object))
|
Self::Yul(Yul::new(source_code, object))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new_evmla(assembly: Assembly, extra_metadata: ExtraMetadata) -> Self {
|
|
||||||
Self::EVMLA(EVMLA::new(assembly, extra_metadata))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
/// A shortcut constructor.
|
||||||
pub fn new_llvm_ir(path: String, source: String) -> Self {
|
pub fn new_llvm_ir(path: String, source: String) -> Self {
|
||||||
Self::LLVMIR(LLVMIR::new(path, source))
|
Self::LLVMIR(LLVMIR::new(path, source))
|
||||||
@@ -51,7 +40,6 @@ impl IR {
|
|||||||
pub fn get_missing_libraries(&self) -> HashSet<String> {
|
pub fn get_missing_libraries(&self) -> HashSet<String> {
|
||||||
match self {
|
match self {
|
||||||
Self::Yul(inner) => inner.get_missing_libraries(),
|
Self::Yul(inner) => inner.get_missing_libraries(),
|
||||||
Self::EVMLA(inner) => inner.get_missing_libraries(),
|
|
||||||
Self::LLVMIR(_inner) => HashSet::new(),
|
Self::LLVMIR(_inner) => HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +55,6 @@ where
|
|||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::Yul(inner) => inner.declare(context),
|
Self::Yul(inner) => inner.declare(context),
|
||||||
Self::EVMLA(inner) => inner.declare(context),
|
|
||||||
Self::LLVMIR(_inner) => Ok(()),
|
Self::LLVMIR(_inner) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +62,6 @@ where
|
|||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::Yul(inner) => inner.into_llvm(context),
|
Self::Yul(inner) => inner.into_llvm(context),
|
||||||
Self::EVMLA(inner) => inner.into_llvm(context),
|
|
||||||
Self::LLVMIR(_inner) => Ok(()),
|
Self::LLVMIR(_inner) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,12 +54,10 @@ impl Contract {
|
|||||||
|
|
||||||
/// Returns the contract identifier, which is:
|
/// Returns the contract identifier, which is:
|
||||||
/// - the Yul object identifier for Yul
|
/// - the Yul object identifier for Yul
|
||||||
/// - the full contract path for EVM legacy assembly
|
|
||||||
/// - the module name for LLVM IR
|
/// - the module name for LLVM IR
|
||||||
pub fn identifier(&self) -> &str {
|
pub fn identifier(&self) -> &str {
|
||||||
match self.ir {
|
match self.ir {
|
||||||
IR::Yul(ref yul) => yul.object.identifier.as_str(),
|
IR::Yul(ref yul) => yul.object.identifier.as_str(),
|
||||||
IR::EVMLA(ref evm) => evm.assembly.full_path(),
|
|
||||||
IR::LLVMIR(ref llvm_ir) => llvm_ir.path.as_str(),
|
IR::LLVMIR(ref llvm_ir) => llvm_ir.path.as_str(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +66,6 @@ impl Contract {
|
|||||||
pub fn drain_factory_dependencies(&mut self) -> HashSet<String> {
|
pub fn drain_factory_dependencies(&mut self) -> HashSet<String> {
|
||||||
match self.ir {
|
match self.ir {
|
||||||
IR::Yul(ref mut yul) => yul.object.factory_dependencies.drain().collect(),
|
IR::Yul(ref mut yul) => yul.object.factory_dependencies.drain().collect(),
|
||||||
IR::EVMLA(ref mut evm) => evm.assembly.factory_dependencies.drain().collect(),
|
|
||||||
IR::LLVMIR(_) => HashSet::new(),
|
IR::LLVMIR(_) => HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,10 +126,6 @@ impl Contract {
|
|||||||
IR::Yul(_) => {
|
IR::Yul(_) => {
|
||||||
context.set_yul_data(Default::default());
|
context.set_yul_data(Default::default());
|
||||||
}
|
}
|
||||||
IR::EVMLA(_) => {
|
|
||||||
let evmla_data = revive_llvm_context::PolkaVMContextEVMLAData::new(version.default);
|
|
||||||
context.set_evmla_data(evmla_data);
|
|
||||||
}
|
|
||||||
IR::LLVMIR(_) => {}
|
IR::LLVMIR(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,12 +113,6 @@ pub struct Arguments {
|
|||||||
#[structopt(long = "llvm-ir")]
|
#[structopt(long = "llvm-ir")]
|
||||||
pub llvm_ir: bool,
|
pub llvm_ir: bool,
|
||||||
|
|
||||||
/// Forcibly switch to EVM legacy assembly pipeline.
|
|
||||||
/// It is useful for older revisions of `solc` 0.8, where Yul was considered highly experimental
|
|
||||||
/// and contained more bugs than today.
|
|
||||||
#[structopt(long = "force-evmla")]
|
|
||||||
pub force_evmla: bool,
|
|
||||||
|
|
||||||
/// Set metadata hash mode.
|
/// Set metadata hash mode.
|
||||||
/// The only supported value is `none` that disables appending the metadata hash.
|
/// The only supported value is `none` that disables appending the metadata hash.
|
||||||
/// Is enabled by default.
|
/// Is enabled by default.
|
||||||
@@ -248,10 +242,6 @@ impl Arguments {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.force_evmla {
|
|
||||||
anyhow::bail!("EVM legacy assembly mode is not supported in Yul, LLVM IR and PolkaVM assembly modes.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.disable_solc_optimizer {
|
if self.disable_solc_optimizer {
|
||||||
anyhow::bail!("Disabling the solc optimizer is not supported in Yul, LLVM IR and PolkaVM assembly modes.");
|
anyhow::bail!("Disabling the solc optimizer is not supported in Yul, LLVM IR and PolkaVM assembly modes.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ fn main_inner() -> anyhow::Result<()> {
|
|||||||
revive_solidity::standard_json(
|
revive_solidity::standard_json(
|
||||||
&mut solc,
|
&mut solc,
|
||||||
arguments.detect_missing_libraries,
|
arguments.detect_missing_libraries,
|
||||||
arguments.force_evmla,
|
|
||||||
arguments.base_path,
|
arguments.base_path,
|
||||||
arguments.include_paths,
|
arguments.include_paths,
|
||||||
arguments.allow_paths,
|
arguments.allow_paths,
|
||||||
@@ -173,7 +172,6 @@ fn main_inner() -> anyhow::Result<()> {
|
|||||||
evm_version,
|
evm_version,
|
||||||
!arguments.disable_solc_optimizer,
|
!arguments.disable_solc_optimizer,
|
||||||
optimizer_settings,
|
optimizer_settings,
|
||||||
arguments.force_evmla,
|
|
||||||
include_metadata_hash,
|
include_metadata_hash,
|
||||||
arguments.base_path,
|
arguments.base_path,
|
||||||
arguments.include_paths,
|
arguments.include_paths,
|
||||||
@@ -193,7 +191,6 @@ fn main_inner() -> anyhow::Result<()> {
|
|||||||
evm_version,
|
evm_version,
|
||||||
!arguments.disable_solc_optimizer,
|
!arguments.disable_solc_optimizer,
|
||||||
optimizer_settings,
|
optimizer_settings,
|
||||||
arguments.force_evmla,
|
|
||||||
include_metadata_hash,
|
include_metadata_hash,
|
||||||
arguments.base_path,
|
arguments.base_path,
|
||||||
arguments.include_paths,
|
arguments.include_paths,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
//! The Solidity compiler.
|
//! The Solidity compiler.
|
||||||
|
|
||||||
pub mod combined_json;
|
pub mod combined_json;
|
||||||
pub mod pipeline;
|
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
pub mod solc_compiler;
|
pub mod solc_compiler;
|
||||||
#[cfg(target_os = "emscripten")]
|
#[cfg(target_os = "emscripten")]
|
||||||
@@ -9,35 +8,25 @@ pub mod soljson_compiler;
|
|||||||
pub mod standard_json;
|
pub mod standard_json;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use semver::VersionReq;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use self::combined_json::CombinedJson;
|
use self::combined_json::CombinedJson;
|
||||||
use self::pipeline::Pipeline;
|
|
||||||
use self::standard_json::input::Input as StandardJsonInput;
|
use self::standard_json::input::Input as StandardJsonInput;
|
||||||
use self::standard_json::output::Output as StandardJsonOutput;
|
use self::standard_json::output::Output as StandardJsonOutput;
|
||||||
use self::version::Version;
|
use self::version::Version;
|
||||||
|
|
||||||
/// The first version of `solc` with the support of standard JSON interface.
|
/// 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);
|
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
|
||||||
|
|
||||||
/// 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);
|
|
||||||
|
|
||||||
/// The first version of `solc`, where `--via-ir` codegen mode is supported.
|
/// 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);
|
pub const FIRST_VIA_IR_VERSION: semver::Version = semver::Version::new(0, 8, 13);
|
||||||
|
|
||||||
/// The last supported version of `solc`.
|
/// The last supported version of `solc`.
|
||||||
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 28);
|
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>
|
/// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
|
||||||
pub static FIRST_SUPPORTS_INCLUDE_PATH: Lazy<VersionReq> =
|
pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8);
|
||||||
Lazy::new(|| VersionReq::parse(">=0.8.8").unwrap());
|
|
||||||
|
|
||||||
/// The Solidity compiler.
|
/// The Solidity compiler.
|
||||||
pub trait Compiler {
|
pub trait Compiler {
|
||||||
@@ -45,7 +34,6 @@ pub trait Compiler {
|
|||||||
fn standard_json(
|
fn standard_json(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: StandardJsonInput,
|
input: StandardJsonInput,
|
||||||
pipeline: Pipeline,
|
|
||||||
base_path: Option<String>,
|
base_path: Option<String>,
|
||||||
include_paths: Vec<String>,
|
include_paths: Vec<String>,
|
||||||
allow_paths: Option<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 std::path::PathBuf;
|
||||||
|
|
||||||
use crate::solc::combined_json::CombinedJson;
|
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::input::Input as StandardJsonInput;
|
||||||
use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
||||||
use crate::solc::version::Version;
|
use crate::solc::version::Version;
|
||||||
|
use crate::solc::FIRST_INCLUDE_PATH_VERSION;
|
||||||
|
|
||||||
use super::Compiler;
|
use super::Compiler;
|
||||||
use crate::solc::{FIRST_SUPPORTS_BASE_PATH, FIRST_SUPPORTS_INCLUDE_PATH};
|
|
||||||
|
|
||||||
/// The Solidity compiler.
|
/// The Solidity compiler.
|
||||||
pub struct SolcCompiler {
|
pub struct SolcCompiler {
|
||||||
@@ -47,45 +46,35 @@ impl Compiler for SolcCompiler {
|
|||||||
fn standard_json(
|
fn standard_json(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut input: StandardJsonInput,
|
mut input: StandardJsonInput,
|
||||||
pipeline: Pipeline,
|
|
||||||
base_path: Option<String>,
|
base_path: Option<String>,
|
||||||
include_paths: Vec<String>,
|
include_paths: Vec<String>,
|
||||||
allow_paths: Option<String>,
|
allow_paths: Option<String>,
|
||||||
) -> anyhow::Result<StandardJsonOutput> {
|
) -> 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());
|
let mut command = std::process::Command::new(self.executable.as_str());
|
||||||
command.stdin(std::process::Stdio::piped());
|
command.stdin(std::process::Stdio::piped());
|
||||||
command.stdout(std::process::Stdio::piped());
|
command.stdout(std::process::Stdio::piped());
|
||||||
command.arg("--standard-json");
|
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() {
|
for include_path in include_paths.into_iter() {
|
||||||
command.arg("--include-path");
|
command.arg("--include-path");
|
||||||
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 {
|
if let Some(allow_paths) = allow_paths {
|
||||||
command.arg("--allow-paths");
|
command.arg("--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();
|
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)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use std::path::Path;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::solc::combined_json::CombinedJson;
|
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::input::Input as StandardJsonInput;
|
||||||
use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
||||||
use crate::solc::version::Version;
|
use crate::solc::version::Version;
|
||||||
@@ -29,7 +28,6 @@ impl Compiler for SoljsonCompiler {
|
|||||||
fn standard_json(
|
fn standard_json(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut input: StandardJsonInput,
|
mut input: StandardJsonInput,
|
||||||
pipeline: Pipeline,
|
|
||||||
_base_path: Option<String>,
|
_base_path: Option<String>,
|
||||||
_include_paths: Vec<String>,
|
_include_paths: Vec<String>,
|
||||||
_allow_paths: Option<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()),
|
.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)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
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::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
|
||||||
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
|
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
|
||||||
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
|
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
|
||||||
@@ -40,13 +39,13 @@ pub struct Input {
|
|||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
/// A shortcut constructor from stdin.
|
/// 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()))?;
|
let mut input: Self = serde_json::from_reader(std::io::BufReader::new(std::io::stdin()))?;
|
||||||
input
|
input
|
||||||
.settings
|
.settings
|
||||||
.output_selection
|
.output_selection
|
||||||
.get_or_insert_with(SolcStandardJsonInputSettingsSelection::default)
|
.get_or_insert_with(SolcStandardJsonInputSettingsSelection::default)
|
||||||
.extend_with_required(solc_pipeline);
|
.extend_with_required();
|
||||||
Ok(input)
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +60,6 @@ impl Input {
|
|||||||
output_selection: SolcStandardJsonInputSettingsSelection,
|
output_selection: SolcStandardJsonInputSettingsSelection,
|
||||||
optimizer: SolcStandardJsonInputSettingsOptimizer,
|
optimizer: SolcStandardJsonInputSettingsOptimizer,
|
||||||
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
|
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
|
||||||
via_ir: bool,
|
|
||||||
suppressed_warnings: Option<Vec<Warning>>,
|
suppressed_warnings: Option<Vec<Warning>>,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let mut paths: BTreeSet<PathBuf> = paths.iter().cloned().collect();
|
let mut paths: BTreeSet<PathBuf> = paths.iter().cloned().collect();
|
||||||
@@ -92,7 +90,6 @@ impl Input {
|
|||||||
libraries,
|
libraries,
|
||||||
remappings,
|
remappings,
|
||||||
output_selection,
|
output_selection,
|
||||||
via_ir,
|
|
||||||
optimizer,
|
optimizer,
|
||||||
metadata,
|
metadata,
|
||||||
),
|
),
|
||||||
@@ -111,7 +108,6 @@ impl Input {
|
|||||||
output_selection: SolcStandardJsonInputSettingsSelection,
|
output_selection: SolcStandardJsonInputSettingsSelection,
|
||||||
optimizer: SolcStandardJsonInputSettingsOptimizer,
|
optimizer: SolcStandardJsonInputSettingsOptimizer,
|
||||||
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
|
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
|
||||||
via_ir: bool,
|
|
||||||
suppressed_warnings: Option<Vec<Warning>>,
|
suppressed_warnings: Option<Vec<Warning>>,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
@@ -131,7 +127,6 @@ impl Input {
|
|||||||
libraries,
|
libraries,
|
||||||
remappings,
|
remappings,
|
||||||
output_selection,
|
output_selection,
|
||||||
via_ir,
|
|
||||||
optimizer,
|
optimizer,
|
||||||
metadata,
|
metadata,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ impl Settings {
|
|||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
remappings: Option<BTreeSet<String>>,
|
remappings: Option<BTreeSet<String>>,
|
||||||
output_selection: Selection,
|
output_selection: Selection,
|
||||||
via_ir: bool,
|
|
||||||
optimizer: Optimizer,
|
optimizer: Optimizer,
|
||||||
metadata: Option<Metadata>,
|
metadata: Option<Metadata>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -60,9 +59,9 @@ impl Settings {
|
|||||||
libraries: Some(libraries),
|
libraries: Some(libraries),
|
||||||
remappings,
|
remappings,
|
||||||
output_selection: Some(output_selection),
|
output_selection: Some(output_selection),
|
||||||
via_ir: if via_ir { Some(true) } else { None },
|
|
||||||
optimizer,
|
optimizer,
|
||||||
metadata,
|
metadata,
|
||||||
|
via_ir: Some(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
/// The `solc --standard-json` expected output selection flag.
|
/// The `solc --standard-json` expected output selection flag.
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@@ -46,15 +44,6 @@ pub enum Flag {
|
|||||||
Assembly,
|
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 {
|
impl std::fmt::Display for Flag {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ use std::collections::HashSet;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
use self::flag::Flag as SelectionFlag;
|
use self::flag::Flag as SelectionFlag;
|
||||||
|
|
||||||
/// The `solc --standard-json` output file selection.
|
/// The `solc --standard-json` output file selection.
|
||||||
@@ -24,7 +22,7 @@ pub struct File {
|
|||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
/// Creates the selection required by our compilation process.
|
/// Creates the selection required by our compilation process.
|
||||||
pub fn new_required(pipeline: SolcPipeline) -> Self {
|
pub fn new_required() -> Self {
|
||||||
Self {
|
Self {
|
||||||
per_file: Some(HashSet::from_iter([SelectionFlag::AST])),
|
per_file: Some(HashSet::from_iter([SelectionFlag::AST])),
|
||||||
per_contract: Some(HashSet::from_iter([
|
per_contract: Some(HashSet::from_iter([
|
||||||
@@ -32,14 +30,14 @@ impl File {
|
|||||||
SelectionFlag::EVMDBC,
|
SelectionFlag::EVMDBC,
|
||||||
SelectionFlag::MethodIdentifiers,
|
SelectionFlag::MethodIdentifiers,
|
||||||
SelectionFlag::Metadata,
|
SelectionFlag::Metadata,
|
||||||
SelectionFlag::from(pipeline),
|
SelectionFlag::Yul,
|
||||||
])),
|
])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extends the user's output selection with flag required by our compilation process.
|
/// 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 {
|
||||||
let required = Self::new_required(pipeline);
|
let required = Self::new_required();
|
||||||
|
|
||||||
self.per_file
|
self.per_file
|
||||||
.get_or_insert_with(HashSet::default)
|
.get_or_insert_with(HashSet::default)
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ pub mod file;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
use self::file::File as FileSelection;
|
use self::file::File as FileSelection;
|
||||||
|
|
||||||
/// The `solc --standard-json` output selection.
|
/// The `solc --standard-json` output selection.
|
||||||
@@ -19,17 +17,17 @@ pub struct Selection {
|
|||||||
|
|
||||||
impl Selection {
|
impl Selection {
|
||||||
/// Creates the selection required by our compilation process.
|
/// Creates the selection required by our compilation process.
|
||||||
pub fn new_required(pipeline: SolcPipeline) -> Self {
|
pub fn new_required() -> Self {
|
||||||
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.
|
/// 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
|
self.all
|
||||||
.get_or_insert_with(|| FileSelection::new_required(pipeline))
|
.get_or_insert_with(FileSelection::new_required)
|
||||||
.extend_with_required(pipeline);
|
.extend_with_required();
|
||||||
self
|
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.
|
//! The `solc --standard-json` output contract EVM data.
|
||||||
|
|
||||||
pub mod bytecode;
|
pub mod bytecode;
|
||||||
pub mod extra_metadata;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::evmla::assembly::Assembly;
|
|
||||||
|
|
||||||
use self::bytecode::Bytecode;
|
use self::bytecode::Bytecode;
|
||||||
use self::bytecode::DeployedBytecode;
|
use self::bytecode::DeployedBytecode;
|
||||||
use self::extra_metadata::ExtraMetadata;
|
|
||||||
|
|
||||||
/// The `solc --standard-json` output contract EVM data.
|
/// The `solc --standard-json` output contract EVM data.
|
||||||
/// It is replaced by PolkaVM data after compiling.
|
/// It is replaced by PolkaVM data after compiling.
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct EVM {
|
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.
|
/// The contract PolkaVM assembly code.
|
||||||
#[serde(rename = "assembly", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "assembly", skip_serializing_if = "Option::is_none")]
|
||||||
pub assembly_text: Option<String>,
|
pub assembly_text: Option<String>,
|
||||||
@@ -37,9 +30,6 @@ pub struct EVM {
|
|||||||
/// The contract function signatures.
|
/// The contract function signatures.
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub method_identifiers: Option<BTreeMap<String, String>>,
|
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 {
|
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..
|
/// Appends the contract path to the message..
|
||||||
pub fn push_contract_path(&mut self, path: &str) {
|
pub fn push_contract_path(&mut self, path: &str) {
|
||||||
self.formatted_message
|
self.formatted_message
|
||||||
|
|||||||
@@ -10,12 +10,9 @@ use serde::Deserialize;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use sha3::Digest;
|
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::ir::IR as ProjectContractIR;
|
||||||
use crate::project::contract::Contract as ProjectContract;
|
use crate::project::contract::Contract as ProjectContract;
|
||||||
use crate::project::Project;
|
use crate::project::Project;
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
use crate::solc::version::Version as SolcVersion;
|
use crate::solc::version::Version as SolcVersion;
|
||||||
use crate::warning::Warning;
|
use crate::warning::Warning;
|
||||||
use crate::yul::lexer::Lexer;
|
use crate::yul::lexer::Lexer;
|
||||||
@@ -53,14 +50,9 @@ impl Output {
|
|||||||
&mut self,
|
&mut self,
|
||||||
source_code_files: BTreeMap<String, String>,
|
source_code_files: BTreeMap<String, String>,
|
||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
solc_version: &SolcVersion,
|
solc_version: &SolcVersion,
|
||||||
debug_config: &revive_llvm_context::DebugConfig,
|
debug_config: &revive_llvm_context::DebugConfig,
|
||||||
) -> anyhow::Result<Project> {
|
) -> anyhow::Result<Project> {
|
||||||
if let SolcPipeline::EVMLA = pipeline {
|
|
||||||
self.preprocess_dependencies()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let files = match self.contracts.as_ref() {
|
let files = match self.contracts.as_ref() {
|
||||||
Some(files) => files,
|
Some(files) => files,
|
||||||
None => match &self.errors {
|
None => match &self.errors {
|
||||||
@@ -76,38 +68,22 @@ impl Output {
|
|||||||
for (name, contract) in contracts.iter() {
|
for (name, contract) in contracts.iter() {
|
||||||
let full_path = format!("{path}:{name}");
|
let full_path = format!("{path}:{name}");
|
||||||
|
|
||||||
let source = match pipeline {
|
let ir_optimized = match contract.ir_optimized.to_owned() {
|
||||||
SolcPipeline::Yul => {
|
Some(ir_optimized) => ir_optimized,
|
||||||
let ir_optimized = match contract.ir_optimized.to_owned() {
|
None => continue,
|
||||||
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)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
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
|
let source_code = source_code_files
|
||||||
.get(path.as_str())
|
.get(path.as_str())
|
||||||
@@ -133,12 +109,7 @@ impl Output {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Traverses the AST and returns the list of additional errors and warnings.
|
/// Traverses the AST and returns the list of additional errors and warnings.
|
||||||
pub fn preprocess_ast(
|
pub fn preprocess_ast(&mut self, suppressed_warnings: &[Warning]) -> anyhow::Result<()> {
|
||||||
&mut self,
|
|
||||||
version: &SolcVersion,
|
|
||||||
pipeline: SolcPipeline,
|
|
||||||
suppressed_warnings: &[Warning],
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let sources = match self.sources.as_ref() {
|
let sources = match self.sources.as_ref() {
|
||||||
Some(sources) => sources,
|
Some(sources) => sources,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
@@ -147,8 +118,7 @@ impl Output {
|
|||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
for (path, source) in sources.iter() {
|
for (path, source) in sources.iter() {
|
||||||
if let Some(ast) = source.ast.as_ref() {
|
if let Some(ast) = source.ast.as_ref() {
|
||||||
let mut polkavm_messages =
|
let mut polkavm_messages = Source::get_messages(ast, suppressed_warnings);
|
||||||
Source::get_messages(ast, version, pipeline, suppressed_warnings);
|
|
||||||
for message in polkavm_messages.iter_mut() {
|
for message in polkavm_messages.iter_mut() {
|
||||||
message.push_contract_path(path.as_str());
|
message.push_contract_path(path.as_str());
|
||||||
}
|
}
|
||||||
@@ -165,83 +135,4 @@ impl Output {
|
|||||||
|
|
||||||
Ok(())
|
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::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputError;
|
use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputError;
|
||||||
use crate::solc::version::Version as SolcVersion;
|
|
||||||
use crate::warning::Warning;
|
use crate::warning::Warning;
|
||||||
|
|
||||||
/// The `solc --standard-json` output source.
|
/// 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.
|
/// Returns the list of messages for some specific parts of the AST.
|
||||||
pub fn get_messages(
|
pub fn get_messages(
|
||||||
ast: &serde_json::Value,
|
ast: &serde_json::Value,
|
||||||
version: &SolcVersion,
|
|
||||||
pipeline: SolcPipeline,
|
|
||||||
suppressed_warnings: &[Warning],
|
suppressed_warnings: &[Warning],
|
||||||
) -> Vec<SolcStandardJsonOutputError> {
|
) -> Vec<SolcStandardJsonOutputError> {
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
@@ -189,31 +159,16 @@ impl Source {
|
|||||||
messages.push(message);
|
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 {
|
match ast {
|
||||||
serde_json::Value::Array(array) => {
|
serde_json::Value::Array(array) => {
|
||||||
for element in array.iter() {
|
for element in array.iter() {
|
||||||
messages.extend(Self::get_messages(
|
messages.extend(Self::get_messages(element, suppressed_warnings));
|
||||||
element,
|
|
||||||
version,
|
|
||||||
pipeline,
|
|
||||||
suppressed_warnings,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serde_json::Value::Object(object) => {
|
serde_json::Value::Object(object) => {
|
||||||
for (_key, value) in object.iter() {
|
for (_key, value) in object.iter() {
|
||||||
messages.extend(Self::get_messages(
|
messages.extend(Self::get_messages(value, suppressed_warnings));
|
||||||
value,
|
|
||||||
version,
|
|
||||||
pipeline,
|
|
||||||
suppressed_warnings,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use std::sync::Mutex;
|
|||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::project::Project;
|
use crate::project::Project;
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
use crate::solc::solc_compiler::SolcCompiler;
|
use crate::solc::solc_compiler::SolcCompiler;
|
||||||
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
|
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
|
||||||
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
|
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
|
||||||
@@ -31,7 +30,6 @@ const DEBUG_CONFIG: revive_llvm_context::DebugConfig =
|
|||||||
struct CachedBlob {
|
struct CachedBlob {
|
||||||
contract_name: String,
|
contract_name: String,
|
||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the required executables are present in `${PATH}`.
|
/// Checks if the required executables are present in `${PATH}`.
|
||||||
@@ -54,17 +52,9 @@ pub fn build_solidity(
|
|||||||
sources: BTreeMap<String, String>,
|
sources: BTreeMap<String, String>,
|
||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
remappings: Option<BTreeSet<String>>,
|
remappings: Option<BTreeSet<String>>,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
||||||
) -> anyhow::Result<SolcStandardJsonOutput> {
|
) -> anyhow::Result<SolcStandardJsonOutput> {
|
||||||
build_solidity_with_options(
|
build_solidity_with_options(sources, libraries, remappings, optimizer_settings, true)
|
||||||
sources,
|
|
||||||
libraries,
|
|
||||||
remappings,
|
|
||||||
pipeline,
|
|
||||||
optimizer_settings,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the Solidity project and returns the standard JSON output.
|
/// Builds the Solidity project and returns the standard JSON output.
|
||||||
@@ -74,7 +64,6 @@ pub fn build_solidity_with_options(
|
|||||||
sources: BTreeMap<String, String>,
|
sources: BTreeMap<String, String>,
|
||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
remappings: Option<BTreeSet<String>>,
|
remappings: Option<BTreeSet<String>>,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
) -> anyhow::Result<SolcStandardJsonOutput> {
|
) -> anyhow::Result<SolcStandardJsonOutput> {
|
||||||
@@ -93,7 +82,7 @@ pub fn build_solidity_with_options(
|
|||||||
sources.clone(),
|
sources.clone(),
|
||||||
libraries.clone(),
|
libraries.clone(),
|
||||||
remappings,
|
remappings,
|
||||||
SolcStandardJsonInputSettingsSelection::new_required(pipeline),
|
SolcStandardJsonInputSettingsSelection::new_required(),
|
||||||
SolcStandardJsonInputSettingsOptimizer::new(
|
SolcStandardJsonInputSettingsOptimizer::new(
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
None,
|
None,
|
||||||
@@ -101,14 +90,12 @@ pub fn build_solidity_with_options(
|
|||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
pipeline == SolcPipeline::Yul,
|
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut output = solc.standard_json(input, pipeline, None, vec![], None)?;
|
let mut output = solc.standard_json(input, None, vec![], None)?;
|
||||||
|
|
||||||
let project =
|
let project = output.try_to_project(sources, libraries, &solc_version, &DEBUG_CONFIG)?;
|
||||||
output.try_to_project(sources, libraries, pipeline, &solc_version, &DEBUG_CONFIG)?;
|
|
||||||
|
|
||||||
let build: crate::Build = project.compile(optimizer_settings, false, DEBUG_CONFIG)?;
|
let build: crate::Build = project.compile(optimizer_settings, false, DEBUG_CONFIG)?;
|
||||||
build.write_to_standard_json(&mut output, &solc_version)?;
|
build.write_to_standard_json(&mut output, &solc_version)?;
|
||||||
@@ -121,7 +108,6 @@ pub fn build_solidity_with_options_evm(
|
|||||||
sources: BTreeMap<String, String>,
|
sources: BTreeMap<String, String>,
|
||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
remappings: Option<BTreeSet<String>>,
|
remappings: Option<BTreeSet<String>>,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
) -> anyhow::Result<BTreeMap<String, (Bytecode, DeployedBytecode)>> {
|
) -> anyhow::Result<BTreeMap<String, (Bytecode, DeployedBytecode)>> {
|
||||||
check_dependencies();
|
check_dependencies();
|
||||||
@@ -139,7 +125,7 @@ pub fn build_solidity_with_options_evm(
|
|||||||
sources.clone(),
|
sources.clone(),
|
||||||
libraries.clone(),
|
libraries.clone(),
|
||||||
remappings,
|
remappings,
|
||||||
SolcStandardJsonInputSettingsSelection::new_required(pipeline),
|
SolcStandardJsonInputSettingsSelection::new_required(),
|
||||||
SolcStandardJsonInputSettingsOptimizer::new(
|
SolcStandardJsonInputSettingsOptimizer::new(
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
None,
|
None,
|
||||||
@@ -147,11 +133,10 @@ pub fn build_solidity_with_options_evm(
|
|||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
pipeline == SolcPipeline::Yul,
|
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut output = solc.standard_json(input, pipeline, None, vec![], None)?;
|
let mut output = solc.standard_json(input, None, vec![], None)?;
|
||||||
|
|
||||||
let mut contracts = BTreeMap::new();
|
let mut contracts = BTreeMap::new();
|
||||||
if let Some(files) = output.contracts.as_mut() {
|
if let Some(files) = output.contracts.as_mut() {
|
||||||
@@ -176,7 +161,6 @@ pub fn build_solidity_with_options_evm(
|
|||||||
pub fn build_solidity_and_detect_missing_libraries(
|
pub fn build_solidity_and_detect_missing_libraries(
|
||||||
sources: BTreeMap<String, String>,
|
sources: BTreeMap<String, String>,
|
||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
) -> anyhow::Result<SolcStandardJsonOutput> {
|
) -> anyhow::Result<SolcStandardJsonOutput> {
|
||||||
check_dependencies();
|
check_dependencies();
|
||||||
|
|
||||||
@@ -193,17 +177,15 @@ pub fn build_solidity_and_detect_missing_libraries(
|
|||||||
sources.clone(),
|
sources.clone(),
|
||||||
libraries.clone(),
|
libraries.clone(),
|
||||||
None,
|
None,
|
||||||
SolcStandardJsonInputSettingsSelection::new_required(pipeline),
|
SolcStandardJsonInputSettingsSelection::new_required(),
|
||||||
SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false),
|
SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false),
|
||||||
None,
|
None,
|
||||||
pipeline == SolcPipeline::Yul,
|
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut output = solc.standard_json(input, pipeline, None, vec![], None)?;
|
let mut output = solc.standard_json(input, None, vec![], None)?;
|
||||||
|
|
||||||
let project =
|
let project = output.try_to_project(sources, libraries, &solc_version, &DEBUG_CONFIG)?;
|
||||||
output.try_to_project(sources, libraries, pipeline, &solc_version, &DEBUG_CONFIG)?;
|
|
||||||
|
|
||||||
let missing_libraries = project.get_missing_libraries();
|
let missing_libraries = project.get_missing_libraries();
|
||||||
missing_libraries.write_to_standard_json(&mut output, &solc.version()?)?;
|
missing_libraries.write_to_standard_json(&mut output, &solc.version()?)?;
|
||||||
@@ -234,7 +216,6 @@ pub fn check_solidity_warning(
|
|||||||
source_code: &str,
|
source_code: &str,
|
||||||
warning_substring: &str,
|
warning_substring: &str,
|
||||||
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
libraries: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
skip_for_revive_edition: bool,
|
skip_for_revive_edition: bool,
|
||||||
suppressed_warnings: Option<Vec<Warning>>,
|
suppressed_warnings: Option<Vec<Warning>>,
|
||||||
) -> anyhow::Result<bool> {
|
) -> anyhow::Result<bool> {
|
||||||
@@ -253,14 +234,13 @@ pub fn check_solidity_warning(
|
|||||||
sources.clone(),
|
sources.clone(),
|
||||||
libraries,
|
libraries,
|
||||||
None,
|
None,
|
||||||
SolcStandardJsonInputSettingsSelection::new_required(pipeline),
|
SolcStandardJsonInputSettingsSelection::new_required(),
|
||||||
SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false),
|
SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false),
|
||||||
None,
|
None,
|
||||||
pipeline == SolcPipeline::Yul,
|
|
||||||
suppressed_warnings,
|
suppressed_warnings,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let output = solc.standard_json(input, pipeline, None, vec![], None)?;
|
let output = solc.standard_json(input, None, vec![], None)?;
|
||||||
let contains_warning = output
|
let contains_warning = output
|
||||||
.errors
|
.errors
|
||||||
.ok_or_else(|| anyhow::anyhow!("Solidity compiler messages not found"))?
|
.ok_or_else(|| anyhow::anyhow!("Solidity compiler messages not found"))?
|
||||||
@@ -273,7 +253,7 @@ pub fn check_solidity_warning(
|
|||||||
/// Compile the blob of `contract_name` found in given `source_code`.
|
/// Compile the blob of `contract_name` found in given `source_code`.
|
||||||
/// The `solc` optimizer will be enabled
|
/// The `solc` optimizer will be enabled
|
||||||
pub fn compile_blob(contract_name: &str, source_code: &str) -> Vec<u8> {
|
pub fn compile_blob(contract_name: &str, source_code: &str) -> Vec<u8> {
|
||||||
compile_blob_with_options(contract_name, source_code, true, SolcPipeline::Yul)
|
compile_blob_with_options(contract_name, source_code, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile the EVM bin-runtime of `contract_name` found in given `source_code`.
|
/// Compile the EVM bin-runtime of `contract_name` found in given `source_code`.
|
||||||
@@ -298,10 +278,8 @@ fn compile_evm(
|
|||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
runtime: bool,
|
runtime: bool,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let pipeline = SolcPipeline::Yul;
|
|
||||||
let id = CachedBlob {
|
let id = CachedBlob {
|
||||||
contract_name: contract_name.to_owned(),
|
contract_name: contract_name.to_owned(),
|
||||||
pipeline,
|
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -319,7 +297,6 @@ fn compile_evm(
|
|||||||
[(file_name.into(), source_code.into())].into(),
|
[(file_name.into(), source_code.into())].into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
None,
|
None,
|
||||||
pipeline,
|
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
)
|
)
|
||||||
.expect("source should compile");
|
.expect("source should compile");
|
||||||
@@ -343,12 +320,10 @@ pub fn compile_blob_with_options(
|
|||||||
contract_name: &str,
|
contract_name: &str,
|
||||||
source_code: &str,
|
source_code: &str,
|
||||||
solc_optimizer_enabled: bool,
|
solc_optimizer_enabled: bool,
|
||||||
pipeline: SolcPipeline,
|
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let id = CachedBlob {
|
let id = CachedBlob {
|
||||||
contract_name: contract_name.to_owned(),
|
contract_name: contract_name.to_owned(),
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
pipeline,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(blob) = PVM_BLOB_CACHE.lock().unwrap().get(&id) {
|
if let Some(blob) = PVM_BLOB_CACHE.lock().unwrap().get(&id) {
|
||||||
@@ -360,7 +335,6 @@ pub fn compile_blob_with_options(
|
|||||||
[(file_name.into(), source_code.into())].into(),
|
[(file_name.into(), source_code.into())].into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
None,
|
None,
|
||||||
pipeline,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
solc_optimizer_enabled,
|
solc_optimizer_enabled,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<testsuites name="jest tests" tests="27" failures="0" errors="0" time="2.146">
|
||||||
|
<testsuite name="Run with --yul by default" errors="0" failures="0" skipped="1" timestamp="2024-10-24T17:08:50" time="1.508" tests="6">
|
||||||
|
<testcase classname="Run with --yul by default Valid command exit code = 0" name="Run with --yul by default Valid command exit code = 0" time="0.003">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --yul by default --yul output is presented" name="Run with --yul by default --yul output is presented" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --yul by default solc exit code == resolc exit code" name="Run with --yul by default solc exit code == resolc exit code" time="0">
|
||||||
|
<skipped/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --yul by default run invalid: resolc --yul" name="Run with --yul by default run invalid: resolc --yul" time="0.001">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --yul by default Invalid command exit code = 1" name="Run with --yul by default Invalid command exit code = 1" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --yul by default Invalid solc exit code == Invalid resolc exit code" name="Run with --yul by default Invalid solc exit code == Invalid resolc exit code" time="0.041">
|
||||||
|
</testcase>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="Run with --asm by default" errors="0" failures="0" skipped="0" timestamp="2024-10-24T17:08:50" time="1.512" tests="6">
|
||||||
|
<testcase classname="Run with --asm by default Valid command exit code = 0" name="Run with --asm by default Valid command exit code = 0" time="0.002">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --asm by default --asm output is presented" name="Run with --asm by default --asm output is presented" time="0.001">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --asm by default solc exit code == resolc exit code" name="Run with --asm by default solc exit code == resolc exit code" time="0.044">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --asm by default run invalid: resolc --asm" name="Run with --asm by default run invalid: resolc --asm" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --asm by default Invalid command exit code = 1" name="Run with --asm by default Invalid command exit code = 1" time="0.001">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run with --asm by default Invalid solc exit code == Invalid resolc exit code" name="Run with --asm by default Invalid solc exit code == Invalid resolc exit code" time="0.04">
|
||||||
|
</testcase>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="Run resolc without any options" errors="0" failures="0" skipped="2" timestamp="2024-10-24T17:08:50" time="2.016" tests="15">
|
||||||
|
<testcase classname="Run resolc without any options Info with help is presented" name="Run resolc without any options Info with help is presented" time="0.002">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run resolc without any options Exit code = 1" name="Run resolc without any options Exit code = 1" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Run resolc without any options solc exit code == resolc exit code" name="Run resolc without any options solc exit code == resolc exit code" time="0.044">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Compiler run successful" name="Default run a command from the help Compiler run successful" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Exit code = 0" name="Default run a command from the help Exit code = 0" time="0.001">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Output dir is created" name="Default run a command from the help Output dir is created" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Output file is created" name="Default run a command from the help Output file is created" time="0">
|
||||||
|
<skipped/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help the output file is not empty" name="Default run a command from the help the output file is not empty" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help No 'Error'/'Warning'/'Fail' in the output" name="Default run a command from the help No 'Error'/'Warning'/'Fail' in the output" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Compiler run successful" name="Default run a command from the help Compiler run successful" time="0.001">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Exit code = 0" name="Default run a command from the help Exit code = 0" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Output dir is created" name="Default run a command from the help Output dir is created" time="0">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help Output files are created" name="Default run a command from the help Output files are created" time="0">
|
||||||
|
<skipped/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help the output files are not empty" name="Default run a command from the help the output files are not empty" time="0.003">
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="Default run a command from the help No 'Error'/'Warning'/'Fail' in the output" name="Default run a command from the help No 'Error'/'Warning'/'Fail' in the output" time="0">
|
||||||
|
</testcase>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import { executeCommand } from "../src/helper";
|
||||||
|
import { paths } from '../src/entities';
|
||||||
|
|
||||||
|
|
||||||
|
describe("Set of --combined-json tests", () => {
|
||||||
|
const zksolcCommand = 'zksolc';
|
||||||
|
const solcCommand = 'solc';
|
||||||
|
const json_args: string[] = [`abi`, `hashes`, `metadata`, `devdoc`, `userdoc`, `storage-layout`, `ast`, `asm`, `bin`, `bin-runtime`];
|
||||||
|
|
||||||
|
//id1742:I
|
||||||
|
describe(`Run ${zksolcCommand} with just --combined-json`, () => {
|
||||||
|
const args = [`--combined-json`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
it("Valid command exit code = 1", () => {
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(requires a value but none was supplied)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//id1742:II
|
||||||
|
describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => {
|
||||||
|
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
it("Valid command exit code = 1", () => {
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(requires a value but none was supplied)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//id1742:III
|
||||||
|
for (let i = 0; i < json_args.length; i++) {
|
||||||
|
describe(`Run ${zksolcCommand} with Sol, --combined-json and ARG: ${json_args[i]}`, () => {
|
||||||
|
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
it("Valid command exit code = 0", () => {
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(contracts)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//id1829:I
|
||||||
|
for (let i = 0; i < json_args.length; i++) {
|
||||||
|
describe(`Run ${zksolcCommand} with Sol, --combined-json and wrong ARG: --${json_args[i]}`, () => {
|
||||||
|
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `--${json_args[i]}`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
it("Valid command exit code = 1", () => {
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(Invalid option|error)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//id1829:II
|
||||||
|
for (let i = 0; i < json_args.length; i++) {
|
||||||
|
describe(`Run ${zksolcCommand} with Sol, --combined-json and multiple ARG: ${json_args[i]} ${json_args[i]}`, () => {
|
||||||
|
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`, `${json_args[i]}`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
xit("Valid command exit code = 1", () => {
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(No such file or directory|cannot find the file specified)/i); // Hopefully we should have more precise message here!
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//id1829:III
|
||||||
|
for (let i = 0; i < json_args.length; i++) {
|
||||||
|
describe(`Run ${zksolcCommand} with Sol, and multiple (--combined-json ${json_args[i]})`, () => {
|
||||||
|
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`, `--combined-json`, `${json_args[i]}`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
it("Valid command exit code = 1", () => {
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(cannot be used multiple times)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//id1830
|
||||||
|
for (let i = 0; i < json_args.length; i++) {
|
||||||
|
describe(`Run ${zksolcCommand} with Yul, and --combined-json ${json_args[i]}`, () => {
|
||||||
|
const args = [`${paths.pathToBasicYulContract}`, `--combined-json`, `${json_args[i]}`];
|
||||||
|
const result = executeCommand(zksolcCommand, args);
|
||||||
|
|
||||||
|
it("Valid command exit code = 1", () => {
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("--combined-json error is presented", () => {
|
||||||
|
expect(result.output).toMatch(/(ParserError: Expected identifier)/i);
|
||||||
|
});
|
||||||
|
asd
|
||||||
|
|
||||||
|
it("solc exit code == zksolc exit code", () => {
|
||||||
|
const solcResult = executeCommand(solcCommand, args);
|
||||||
|
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
pub const MAIN_CODE: &str = r#"
|
pub const MAIN_CODE: &str = r#"
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
@@ -51,7 +49,6 @@ fn default() {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Build failure");
|
.expect("Build failure");
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn yul() {
|
fn yul() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
@@ -27,7 +25,6 @@ contract Test {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
@@ -45,75 +42,4 @@ contract Test {
|
|||||||
.is_some(),
|
.is_some(),
|
||||||
"Yul IR is missing"
|
"Yul IR is missing"
|
||||||
);
|
);
|
||||||
assert!(
|
|
||||||
build
|
|
||||||
.contracts
|
|
||||||
.as_ref()
|
|
||||||
.expect("Always exists")
|
|
||||||
.get("test.sol")
|
|
||||||
.expect("Always exists")
|
|
||||||
.get("Test")
|
|
||||||
.expect("Always exists")
|
|
||||||
.evm
|
|
||||||
.as_ref()
|
|
||||||
.expect("EVM object is missing")
|
|
||||||
.assembly
|
|
||||||
.is_none(),
|
|
||||||
"EVMLA IR is present although not requested"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn evmla() {
|
|
||||||
let source_code = r#"
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
contract Test {
|
|
||||||
function main() public view returns (uint) {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let mut sources = BTreeMap::new();
|
|
||||||
sources.insert("test.sol".to_owned(), source_code.to_owned());
|
|
||||||
|
|
||||||
let build = super::build_solidity(
|
|
||||||
sources,
|
|
||||||
BTreeMap::new(),
|
|
||||||
None,
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
|
||||||
)
|
|
||||||
.expect("Test failure");
|
|
||||||
assert!(
|
|
||||||
build
|
|
||||||
.contracts
|
|
||||||
.as_ref()
|
|
||||||
.expect("Always exists")
|
|
||||||
.get("test.sol")
|
|
||||||
.expect("Always exists")
|
|
||||||
.get("Test")
|
|
||||||
.expect("Always exists")
|
|
||||||
.evm
|
|
||||||
.as_ref()
|
|
||||||
.expect("EVM object is missing")
|
|
||||||
.assembly
|
|
||||||
.is_some(),
|
|
||||||
"EVMLA IR is missing",
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
build
|
|
||||||
.contracts
|
|
||||||
.as_ref()
|
|
||||||
.expect("Always exists")
|
|
||||||
.get("test.sol")
|
|
||||||
.expect("Always exists")
|
|
||||||
.get("Test")
|
|
||||||
.expect("Always exists")
|
|
||||||
.ir_optimized
|
|
||||||
.is_none(),
|
|
||||||
"Yul IR is present although not requested",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
pub const LIBRARY_TEST_SOURCE: &str = r#"
|
pub const LIBRARY_TEST_SOURCE: &str = r#"
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
@@ -38,29 +36,24 @@ fn not_specified() {
|
|||||||
let mut sources = BTreeMap::new();
|
let mut sources = BTreeMap::new();
|
||||||
sources.insert("test.sol".to_owned(), LIBRARY_TEST_SOURCE.to_owned());
|
sources.insert("test.sol".to_owned(), LIBRARY_TEST_SOURCE.to_owned());
|
||||||
|
|
||||||
for pipeline in [SolcPipeline::EVMLA, SolcPipeline::Yul] {
|
let output =
|
||||||
let output = super::build_solidity_and_detect_missing_libraries(
|
super::build_solidity_and_detect_missing_libraries(sources.clone(), BTreeMap::new())
|
||||||
sources.clone(),
|
.expect("Test failure");
|
||||||
BTreeMap::new(),
|
assert!(
|
||||||
pipeline,
|
output
|
||||||
)
|
.contracts
|
||||||
.expect("Test failure");
|
.as_ref()
|
||||||
assert!(
|
.expect("Always exists")
|
||||||
output
|
.get("test.sol")
|
||||||
.contracts
|
.expect("Always exists")
|
||||||
.as_ref()
|
.get("SimpleContract")
|
||||||
.expect("Always exists")
|
.expect("Always exists")
|
||||||
.get("test.sol")
|
.missing_libraries
|
||||||
.expect("Always exists")
|
.as_ref()
|
||||||
.get("SimpleContract")
|
.expect("Always exists")
|
||||||
.expect("Always exists")
|
.contains("test.sol:SimpleLibrary"),
|
||||||
.missing_libraries
|
"Missing library not detected"
|
||||||
.as_ref()
|
);
|
||||||
.expect("Always exists")
|
|
||||||
.contains("test.sol:SimpleLibrary"),
|
|
||||||
"Missing library not detected"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -75,28 +68,23 @@ fn specified() {
|
|||||||
.entry("SimpleLibrary".to_string())
|
.entry("SimpleLibrary".to_string())
|
||||||
.or_insert("0x00000000000000000000000000000000DEADBEEF".to_string());
|
.or_insert("0x00000000000000000000000000000000DEADBEEF".to_string());
|
||||||
|
|
||||||
for pipeline in [SolcPipeline::EVMLA, SolcPipeline::Yul] {
|
let output =
|
||||||
let output = super::build_solidity_and_detect_missing_libraries(
|
super::build_solidity_and_detect_missing_libraries(sources.clone(), libraries.clone())
|
||||||
sources.clone(),
|
.expect("Test failure");
|
||||||
libraries.clone(),
|
assert!(
|
||||||
pipeline,
|
output
|
||||||
)
|
.contracts
|
||||||
.expect("Test failure");
|
.as_ref()
|
||||||
assert!(
|
.expect("Always exists")
|
||||||
output
|
.get("test.sol")
|
||||||
.contracts
|
.expect("Always exists")
|
||||||
.as_ref()
|
.get("SimpleContract")
|
||||||
.expect("Always exists")
|
.expect("Always exists")
|
||||||
.get("test.sol")
|
.missing_libraries
|
||||||
.expect("Always exists")
|
.as_ref()
|
||||||
.get("SimpleContract")
|
.cloned()
|
||||||
.expect("Always exists")
|
.unwrap_or_default()
|
||||||
.missing_libraries
|
.is_empty(),
|
||||||
.as_ref()
|
"The list of missing libraries must be empty"
|
||||||
.cloned()
|
);
|
||||||
.unwrap_or_default()
|
|
||||||
.is_empty(),
|
|
||||||
"The list of missing libraries must be empty"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
use crate::warning::Warning;
|
use crate::warning::Warning;
|
||||||
|
|
||||||
pub const ECRECOVER_TEST_SOURCE: &str = r#"
|
pub const ECRECOVER_TEST_SOURCE: &str = r#"
|
||||||
@@ -30,7 +29,6 @@ fn ecrecover() {
|
|||||||
ECRECOVER_TEST_SOURCE,
|
ECRECOVER_TEST_SOURCE,
|
||||||
"Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.",
|
"Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).expect("Test failure")
|
).expect("Test failure")
|
||||||
@@ -44,7 +42,6 @@ fn ecrecover_suppressed() {
|
|||||||
ECRECOVER_TEST_SOURCE,
|
ECRECOVER_TEST_SOURCE,
|
||||||
"Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.",
|
"Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
Some(vec![Warning::EcRecover]),
|
Some(vec![Warning::EcRecover]),
|
||||||
).expect("Test failure")
|
).expect("Test failure")
|
||||||
@@ -76,7 +73,6 @@ fn send() {
|
|||||||
SEND_TEST_SOURCE,
|
SEND_TEST_SOURCE,
|
||||||
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).expect("Test failure")
|
).expect("Test failure")
|
||||||
@@ -90,7 +86,6 @@ fn send_suppressed() {
|
|||||||
SEND_TEST_SOURCE,
|
SEND_TEST_SOURCE,
|
||||||
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
Some(vec![Warning::SendTransfer]),
|
Some(vec![Warning::SendTransfer]),
|
||||||
).expect("Test failure")
|
).expect("Test failure")
|
||||||
@@ -121,7 +116,6 @@ fn transfer() {
|
|||||||
TRANSFER_TEST_SOURCE,
|
TRANSFER_TEST_SOURCE,
|
||||||
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).expect("Test failure")
|
).expect("Test failure")
|
||||||
@@ -135,7 +129,6 @@ fn transfer_suppressed() {
|
|||||||
TRANSFER_TEST_SOURCE,
|
TRANSFER_TEST_SOURCE,
|
||||||
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)' without providing",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
Some(vec![Warning::SendTransfer]),
|
Some(vec![Warning::SendTransfer]),
|
||||||
).expect("Test failure")
|
).expect("Test failure")
|
||||||
@@ -163,7 +156,6 @@ fn extcodesize() {
|
|||||||
EXTCODESIZE_TEST_SOURCE,
|
EXTCODESIZE_TEST_SOURCE,
|
||||||
"Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,",
|
"Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@@ -176,7 +168,6 @@ fn extcodesize_suppressed() {
|
|||||||
EXTCODESIZE_TEST_SOURCE,
|
EXTCODESIZE_TEST_SOURCE,
|
||||||
"Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,",
|
"Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
Some(vec![Warning::ExtCodeSize]),
|
Some(vec![Warning::ExtCodeSize]),
|
||||||
)
|
)
|
||||||
@@ -200,7 +191,6 @@ fn tx_origin() {
|
|||||||
TX_ORIGIN_TEST_SOURCE,
|
TX_ORIGIN_TEST_SOURCE,
|
||||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@@ -213,7 +203,6 @@ fn tx_origin_suppressed() {
|
|||||||
TX_ORIGIN_TEST_SOURCE,
|
TX_ORIGIN_TEST_SOURCE,
|
||||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
Some(vec![Warning::TxOrigin]),
|
Some(vec![Warning::TxOrigin]),
|
||||||
)
|
)
|
||||||
@@ -244,7 +233,6 @@ fn tx_origin_assembly() {
|
|||||||
TX_ORIGIN_ASSEMBLY_TEST_SOURCE,
|
TX_ORIGIN_ASSEMBLY_TEST_SOURCE,
|
||||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@@ -257,136 +245,8 @@ fn tx_origin_assembly_suppressed() {
|
|||||||
TX_ORIGIN_ASSEMBLY_TEST_SOURCE,
|
TX_ORIGIN_ASSEMBLY_TEST_SOURCE,
|
||||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
SolcPipeline::Yul,
|
|
||||||
false,
|
false,
|
||||||
Some(vec![Warning::TxOrigin]),
|
Some(vec![Warning::TxOrigin]),
|
||||||
)
|
)
|
||||||
.expect("Test failure"));
|
.expect("Test failure"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn internal_function_pointer_argument() {
|
|
||||||
let source_code = r#"
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
contract InternalFunctionPointerExample {
|
|
||||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
||||||
return a - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeOperation(
|
|
||||||
function (uint256, uint256) internal pure returns (uint256) operation,
|
|
||||||
uint256 a,
|
|
||||||
uint256 b
|
|
||||||
) private pure returns (uint256) {
|
|
||||||
return operation(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testAdd(uint256 a, uint256 b) public pure returns (uint256) {
|
|
||||||
return executeOperation(add, a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testSub(uint256 a, uint256 b) public pure returns (uint256) {
|
|
||||||
return executeOperation(sub, a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
assert!(super::check_solidity_warning(
|
|
||||||
source_code,
|
|
||||||
"Error: Internal function pointers are not supported in EVM legacy assembly pipeline.",
|
|
||||||
BTreeMap::new(),
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.expect("Test failure"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn internal_function_pointer_stack() {
|
|
||||||
let source_code = r#"
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
contract StackFunctionPointerExample {
|
|
||||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
||||||
return a - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function testAdd(uint256 a, uint256 b) public pure returns (uint256) {
|
|
||||||
function (uint256, uint256) internal pure returns (uint256) operation = add;
|
|
||||||
return operation(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testSub(uint256 a, uint256 b) public pure returns (uint256) {
|
|
||||||
function (uint256, uint256) internal pure returns (uint256) operation = sub;
|
|
||||||
return operation(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
assert!(super::check_solidity_warning(
|
|
||||||
source_code,
|
|
||||||
"Error: Internal function pointers are not supported in EVM legacy assembly pipeline.",
|
|
||||||
BTreeMap::new(),
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.expect("Test failure"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn internal_function_pointer_storage() {
|
|
||||||
let source_code = r#"
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
contract StorageFunctionPointerExample {
|
|
||||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
||||||
return a - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function (uint256, uint256) internal pure returns (uint256) operation;
|
|
||||||
bool private isOperationSet = false;
|
|
||||||
|
|
||||||
function setOperation(bool isAdd) public {
|
|
||||||
if (isAdd) {
|
|
||||||
operation = add;
|
|
||||||
} else {
|
|
||||||
operation = sub;
|
|
||||||
}
|
|
||||||
isOperationSet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeOperation(uint256 a, uint256 b) public view returns (uint256) {
|
|
||||||
require(isOperationSet, "Operation not set");
|
|
||||||
return operation(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
assert!(super::check_solidity_warning(
|
|
||||||
source_code,
|
|
||||||
"Error: Internal function pointers are not supported in EVM legacy assembly pipeline.",
|
|
||||||
BTreeMap::new(),
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.expect("Test failure"));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
pub const SOURCE_CODE: &str = r#"
|
pub const SOURCE_CODE: &str = r#"
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
@@ -54,7 +52,6 @@ fn optimizer() {
|
|||||||
sources.clone(),
|
sources.clone(),
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::none(),
|
revive_llvm_context::OptimizerSettings::none(),
|
||||||
)
|
)
|
||||||
.expect("Build failure");
|
.expect("Build failure");
|
||||||
@@ -62,7 +59,6 @@ fn optimizer() {
|
|||||||
sources.clone(),
|
sources.clone(),
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Build failure");
|
.expect("Build failure");
|
||||||
@@ -70,7 +66,6 @@ fn optimizer() {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::size(),
|
revive_llvm_context::OptimizerSettings::size(),
|
||||||
)
|
)
|
||||||
.expect("Build failure");
|
.expect("Build failure");
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
pub const CALLEE_TEST_SOURCE: &str = r#"
|
pub const CALLEE_TEST_SOURCE: &str = r#"
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
@@ -46,7 +44,6 @@ fn default() {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
Some(remappings),
|
Some(remappings),
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "runtimeCode is not supported")]
|
#[should_panic(expected = "runtimeCode is not supported")]
|
||||||
fn default() {
|
fn default() {
|
||||||
@@ -29,7 +27,6 @@ contract Test {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::solc::pipeline::Pipeline as SolcPipeline;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "The `CODECOPY` instruction is not supported")]
|
#[should_panic(expected = "The `CODECOPY` instruction is not supported")]
|
||||||
fn codecopy_yul_runtime() {
|
fn codecopy_yul_runtime() {
|
||||||
@@ -34,7 +32,6 @@ contract FixedCodeCopy {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
@@ -63,22 +60,6 @@ contract CallcodeTest {
|
|||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "The `CALLCODE` instruction is not supported")]
|
|
||||||
fn callcode_evmla() {
|
|
||||||
let mut sources = BTreeMap::new();
|
|
||||||
sources.insert("test.sol".to_owned(), CALLCODE_TEST_SOURCE.to_owned());
|
|
||||||
|
|
||||||
super::build_solidity(
|
|
||||||
sources,
|
|
||||||
BTreeMap::new(),
|
|
||||||
None,
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
|
||||||
)
|
|
||||||
.expect("Test failure");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "The `CALLCODE` instruction is not supported")]
|
#[should_panic(expected = "The `CALLCODE` instruction is not supported")]
|
||||||
fn callcode_yul() {
|
fn callcode_yul() {
|
||||||
@@ -89,7 +70,6 @@ fn callcode_yul() {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
@@ -137,22 +117,6 @@ contract ExternalCodeCopy {
|
|||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")]
|
|
||||||
fn extcodecopy_evmla() {
|
|
||||||
let mut sources = BTreeMap::new();
|
|
||||||
sources.insert("test.sol".to_owned(), EXTCODECOPY_TEST_SOURCE.to_owned());
|
|
||||||
|
|
||||||
super::build_solidity(
|
|
||||||
sources,
|
|
||||||
BTreeMap::new(),
|
|
||||||
None,
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
|
||||||
)
|
|
||||||
.expect("Test failure");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")]
|
#[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")]
|
||||||
fn extcodecopy_yul() {
|
fn extcodecopy_yul() {
|
||||||
@@ -163,7 +127,6 @@ fn extcodecopy_yul() {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
@@ -187,22 +150,6 @@ contract MinimalDestructible {
|
|||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
|
||||||
fn selfdestruct_evmla() {
|
|
||||||
let mut sources = BTreeMap::new();
|
|
||||||
sources.insert("test.sol".to_owned(), SELFDESTRUCT_TEST_SOURCE.to_owned());
|
|
||||||
|
|
||||||
super::build_solidity(
|
|
||||||
sources,
|
|
||||||
BTreeMap::new(),
|
|
||||||
None,
|
|
||||||
SolcPipeline::EVMLA,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
|
||||||
)
|
|
||||||
.expect("Test failure");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
||||||
fn selfdestruct_yul() {
|
fn selfdestruct_yul() {
|
||||||
@@ -213,7 +160,6 @@ fn selfdestruct_yul() {
|
|||||||
sources,
|
sources,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
None,
|
None,
|
||||||
SolcPipeline::Yul,
|
|
||||||
revive_llvm_context::OptimizerSettings::cycles(),
|
revive_llvm_context::OptimizerSettings::cycles(),
|
||||||
)
|
)
|
||||||
.expect("Test failure");
|
.expect("Test failure");
|
||||||
|
|||||||
Reference in New Issue
Block a user