diff --git a/CHANGELOG.md b/CHANGELOG.md index 33adaf3..534884d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This is a development pre-release. - Support for the `coinbase` opcode. ### Changed +- Removed support for legacy EVM assembly (EVMLA) translation. ### Fixed - Solidity: Add the solc `--libraries` files to sources. diff --git a/Cargo.lock b/Cargo.lock index 31c756d..135a80d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4732,12 +4732,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - [[package]] name = "memchr" version = "2.7.4" @@ -8350,7 +8344,6 @@ dependencies = [ "hex", "inkwell", "itertools 0.14.0", - "md5", "num", "polkavm-common 0.19.0", "polkavm-disassembler", @@ -8398,7 +8391,6 @@ dependencies = [ "hex", "inkwell", "libc", - "md5", "mimalloc", "num", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index c701143..1f8e1e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,6 @@ once_cell = "1.19" num = "0.4.3" sha1 = "0.10" sha3 = "0.10" -md5 = "0.7.0" thiserror = "2.0" which = "7.0" path-slash = "0.2" diff --git a/README.md b/README.md index 4a4afae..5a97160 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # 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! diff --git a/crates/common/src/extension.rs b/crates/common/src/extension.rs index d37fe4c..562acbb 100644 --- a/crates/common/src/extension.rs +++ b/crates/common/src/extension.rs @@ -12,12 +12,6 @@ pub static EXTENSION_ABI: &str = "abi"; /// The Yul IR file extension. 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. pub static EXTENSION_EVM: &str = "evm"; diff --git a/crates/integration/src/tests.rs b/crates/integration/src/tests.rs index d95e9ee..e5da10a 100644 --- a/crates/integration/src/tests.rs +++ b/crates/integration/src/tests.rs @@ -62,7 +62,6 @@ fn instantiate(path: &str, contract: &str) -> Vec { path: Some(path.into()), contract: contract.to_string(), solc_optimizer: None, - pipeline: None, }, data: vec![], salt: OptionalHex::default(), @@ -355,7 +354,6 @@ fn ext_code_size() { path: Some("contracts/Baseline.sol".into()), contract: "Baseline".to_string(), solc_optimizer: None, - pipeline: None, }, data: vec![], salt: OptionalHex::from([0; 32]), diff --git a/crates/llvm-context/Cargo.toml b/crates/llvm-context/Cargo.toml index 5bfd4e4..85dda1b 100644 --- a/crates/llvm-context/Cargo.toml +++ b/crates/llvm-context/Cargo.toml @@ -21,7 +21,6 @@ serde = { workspace = true, features = ["derive"] } num = { workspace = true } hex = { workspace = true } sha3 = { workspace = true } -md5 = { workspace = true } inkwell = { workspace = true } polkavm-disassembler = { workspace = true } polkavm-common = { workspace = true } diff --git a/crates/llvm-context/src/debug_config/ir_type.rs b/crates/llvm-context/src/debug_config/ir_type.rs index 43a4448..86c60f9 100644 --- a/crates/llvm-context/src/debug_config/ir_type.rs +++ b/crates/llvm-context/src/debug_config/ir_type.rs @@ -7,10 +7,6 @@ pub enum IRType { /// Whether to dump the Yul code. 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. LLVM, /// Whether to dump the assembly code. @@ -27,8 +23,6 @@ impl IRType { pub fn file_extension(&self) -> &'static str { match self { 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::Assembly => revive_common::EXTENSION_POLKAVM_ASSEMBLY, #[cfg(debug_assertions)] diff --git a/crates/llvm-context/src/debug_config/mod.rs b/crates/llvm-context/src/debug_config/mod.rs index f60ae6e..e85c14d 100644 --- a/crates/llvm-context/src/debug_config/mod.rs +++ b/crates/llvm-context/src/debug_config/mod.rs @@ -39,30 +39,6 @@ impl DebugConfig { 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. pub fn dump_llvm_ir_unoptimized( &self, diff --git a/crates/llvm-context/src/lib.rs b/crates/llvm-context/src/lib.rs index 5d1c82b..e37ed68 100644 --- a/crates/llvm-context/src/lib.rs +++ b/crates/llvm-context/src/lib.rs @@ -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::code_type::CodeType as PolkaVMCodeType; 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::evmla_data::EVMLAData as PolkaVMFunctionEVMLAData; 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::r#return::Return as PolkaVMFunctionReturn; diff --git a/crates/llvm-context/src/polkavm/context/evmla_data.rs b/crates/llvm-context/src/polkavm/context/evmla_data.rs deleted file mode 100644 index f9e27a0..0000000 --- a/crates/llvm-context/src/polkavm/context/evmla_data.rs +++ /dev/null @@ -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>, -} - -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), - } - } -} diff --git a/crates/llvm-context/src/polkavm/context/function/block/evmla_data/key.rs b/crates/llvm-context/src/polkavm/context/function/block/evmla_data/key.rs deleted file mode 100644 index d890753..0000000 --- a/crates/llvm-context/src/polkavm/context/function/block/evmla_data/key.rs +++ /dev/null @@ -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 - ) - } -} diff --git a/crates/llvm-context/src/polkavm/context/function/block/evmla_data/mod.rs b/crates/llvm-context/src/polkavm/context/function/block/evmla_data/mod.rs deleted file mode 100644 index dbf18c7..0000000 --- a/crates/llvm-context/src/polkavm/context/function/block/evmla_data/mod.rs +++ /dev/null @@ -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, -} - -impl EVMLAData { - /// A shortcut constructor. - pub fn new(stack_hashes: Vec) -> Self { - Self { stack_hashes } - } -} diff --git a/crates/llvm-context/src/polkavm/context/function/block/mod.rs b/crates/llvm-context/src/polkavm/context/function/block/mod.rs deleted file mode 100644 index d8f6ca8..0000000 --- a/crates/llvm-context/src/polkavm/context/function/block/mod.rs +++ /dev/null @@ -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, -} - -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") - } -} diff --git a/crates/llvm-context/src/polkavm/context/function/evmla_data.rs b/crates/llvm-context/src/polkavm/context/function/evmla_data.rs deleted file mode 100644 index eeb1f32..0000000 --- a/crates/llvm-context/src/polkavm/context/function/evmla_data.rs +++ /dev/null @@ -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>>, - /// 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> { - 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)) - } -} diff --git a/crates/llvm-context/src/polkavm/context/function/mod.rs b/crates/llvm-context/src/polkavm/context/function/mod.rs index 9527e41..4280077 100644 --- a/crates/llvm-context/src/polkavm/context/function/mod.rs +++ b/crates/llvm-context/src/polkavm/context/function/mod.rs @@ -1,8 +1,6 @@ //! The LLVM IR generator function. -pub mod block; pub mod declaration; -pub mod evmla_data; pub mod intrinsics; pub mod llvm_runtime; pub mod r#return; @@ -19,7 +17,6 @@ use crate::polkavm::context::attribute::Attribute; use crate::polkavm::context::pointer::Pointer; use self::declaration::Declaration; -use self::evmla_data::EVMLAData; use self::r#return::Return; use self::yul_data::YulData; @@ -45,8 +42,6 @@ pub struct Function<'ctx> { /// The Yul compiler data. yul_data: Option, - /// The EVM legacy assembly compiler data. - evmla_data: Option>, } impl<'ctx> Function<'ctx> { @@ -72,7 +67,6 @@ impl<'ctx> Function<'ctx> { return_block, yul_data: None, - evmla_data: None, } } @@ -300,29 +294,6 @@ impl<'ctx> Function<'ctx> { 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. pub fn set_yul_data(&mut self, data: YulData) { self.yul_data = Some(data); diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index ee21130..502371e 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -6,7 +6,6 @@ pub mod attribute; pub mod build; pub mod code_type; pub mod debug_info; -pub mod evmla_data; pub mod function; pub mod global; pub mod r#loop; @@ -38,7 +37,6 @@ use self::attribute::Attribute; use self::build::Build; use self::code_type::CodeType; use self::debug_info::DebugInfo; -use self::evmla_data::EVMLAData; use self::function::declaration::Declaration as FunctionDeclaration; use self::function::intrinsics::Intrinsics; use self::function::llvm_runtime::LLVMRuntime; @@ -95,8 +93,6 @@ where solidity_data: Option, /// The Yul data. yul_data: Option, - /// The EVM legacy assembly data. - evmla_data: Option>, } impl<'ctx, D> Context<'ctx, D> @@ -257,7 +253,6 @@ where solidity_data: None, yul_data: None, - evmla_data: None, } } @@ -1574,29 +1569,6 @@ where .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. /// If the size is set manually, then it is returned. Otherwise, the number of elements in /// the identifier-to-offset mapping tree is returned. diff --git a/crates/runner/src/lib.rs b/crates/runner/src/lib.rs index 0b6425b..dd58a3d 100644 --- a/crates/runner/src/lib.rs +++ b/crates/runner/src/lib.rs @@ -239,7 +239,6 @@ pub enum Code { Solidity { path: Option, solc_optimizer: Option, - pipeline: Option, contract: String, }, /// Read the contract blob from disk @@ -264,7 +263,6 @@ impl From for pallet_revive::Code { path, contract, solc_optimizer, - pipeline, } => { let Some(path) = path else { panic!("Solidity source of contract '{contract}' missing path"); @@ -276,7 +274,6 @@ impl From for pallet_revive::Code { &contract, &source_code, solc_optimizer.unwrap_or(true), - pipeline.unwrap_or(revive_solidity::SolcPipeline::Yul), )) } Code::Path(path) => pallet_revive::Code::Upload(std::fs::read(path).unwrap()), diff --git a/crates/runner/src/specs.rs b/crates/runner/src/specs.rs index c61a423..403ead0 100644 --- a/crates/runner/src/specs.rs +++ b/crates/runner/src/specs.rs @@ -282,17 +282,11 @@ impl Specs { let Code::Solidity { path: Some(path), solc_optimizer, - pipeline, contract, } = code else { 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!( salt.0.is_none(), "salt is not supported in differential mode" diff --git a/crates/solidity/Cargo.toml b/crates/solidity/Cargo.toml index 410eac1..e2bc150 100644 --- a/crates/solidity/Cargo.toml +++ b/crates/solidity/Cargo.toml @@ -33,7 +33,6 @@ regex = { workspace = true } hex = { workspace = true } num = { workspace = true } sha3 = { workspace = true } -md5 = { workspace = true } inkwell = { workspace = true } revive-common = { workspace = true } diff --git a/crates/solidity/src/evmla/assembly/data.rs b/crates/solidity/src/evmla/assembly/data.rs deleted file mode 100644 index f9ad0df..0000000 --- a/crates/solidity/src/evmla/assembly/data.rs +++ /dev/null @@ -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 { - 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}`"), - } - } -} diff --git a/crates/solidity/src/evmla/assembly/instruction/codecopy.rs b/crates/solidity/src/evmla/assembly/instruction/codecopy.rs deleted file mode 100644 index 33d7aeb..0000000 --- a/crates/solidity/src/evmla/assembly/instruction/codecopy.rs +++ /dev/null @@ -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( - context: &mut revive_llvm_context::PolkaVMContext, - 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::>() - .chunks(revive_common::BYTE_LENGTH_WORD * 2) - .enumerate() - { - let mut value_string = chunk.iter().collect::(); - 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(()) -} diff --git a/crates/solidity/src/evmla/assembly/instruction/jump.rs b/crates/solidity/src/evmla/assembly/instruction/jump.rs deleted file mode 100644 index 5ca34f6..0000000 --- a/crates/solidity/src/evmla/assembly/instruction/jump.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Translates the jump operations. - -/// Translates the unconditional jump. -pub fn unconditional( - context: &mut revive_llvm_context::PolkaVMContext, - 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( - context: &mut revive_llvm_context::PolkaVMContext, - 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(()) -} diff --git a/crates/solidity/src/evmla/assembly/instruction/mod.rs b/crates/solidity/src/evmla/assembly/instruction/mod.rs deleted file mode 100644 index 7cd54b2..0000000 --- a/crates/solidity/src/evmla/assembly/instruction/mod.rs +++ /dev/null @@ -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, - - /// The source code identifier. - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, - /// 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, - ) -> 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(()) - } -} diff --git a/crates/solidity/src/evmla/assembly/instruction/name.rs b/crates/solidity/src/evmla/assembly/instruction/name.rs deleted file mode 100644 index 3f0b953..0000000 --- a/crates/solidity/src/evmla/assembly/instruction/name.rs +++ /dev/null @@ -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('\"') - ), - } - } -} diff --git a/crates/solidity/src/evmla/assembly/instruction/stack.rs b/crates/solidity/src/evmla/assembly/instruction/stack.rs deleted file mode 100644 index 1d70f3c..0000000 --- a/crates/solidity/src/evmla/assembly/instruction/stack.rs +++ /dev/null @@ -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> -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> -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, -) -> anyhow::Result> -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( - context: &mut revive_llvm_context::PolkaVMContext, - 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(_context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - Ok(()) -} diff --git a/crates/solidity/src/evmla/assembly/mod.rs b/crates/solidity/src/evmla/assembly/mod.rs deleted file mode 100644 index bf3502e..0000000 --- a/crates/solidity/src/evmla/assembly/mod.rs +++ /dev/null @@ -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, - /// The deploy code instructions. - #[serde(rename = ".code")] - pub code: Option>, - /// The runtime code. - #[serde(rename = ".data")] - pub data: Option>, - - /// The full contract path. - #[serde(skip_serializing_if = "Option::is_none")] - pub full_path: Option, - /// The factory dependency paths. - #[serde(default = "HashSet::new")] - pub factory_dependencies: HashSet, - /// The EVMLA extra metadata. - #[serde(skip_serializing_if = "Option::is_none")] - pub extra_metadata: Option, -} - -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 `` 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 { - 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, - ) -> anyhow::Result> { - 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, - ) -> anyhow::Result> { - 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 revive_llvm_context::PolkaVMWriteLLVM for Assembly -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn declare( - &mut self, - context: &mut revive_llvm_context::PolkaVMContext, - ) -> 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, - ) -> 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(()) - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/entry_link.rs b/crates/solidity/src/evmla/ethereal_ir/entry_link.rs deleted file mode 100644 index 075148d..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/entry_link.rs +++ /dev/null @@ -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 revive_llvm_context::PolkaVMWriteLLVM for EntryLink -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> 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(()) - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs b/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs deleted file mode 100644 index bde58a2..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs +++ /dev/null @@ -1,1362 +0,0 @@ -//! The Ethereal IR block element. - -pub mod stack; - -use inkwell::values::BasicValue; - -use crate::evmla::assembly::instruction::codecopy; -use crate::evmla::assembly::instruction::name::Name as InstructionName; -use crate::evmla::assembly::instruction::Instruction; - -use self::stack::element::Element as StackElement; -use self::stack::Stack; - -/// The Ethereal IR block element. -#[derive(Debug, Clone)] -pub struct Element { - /// The Solidity compiler version. - pub solc_version: semver::Version, - /// The instruction. - pub instruction: Instruction, - /// The stack data. - pub stack: Stack, - /// The stack input. - pub stack_input: Stack, - /// The stack output. - pub stack_output: Stack, -} - -impl Element { - /// A shortcut constructor. - pub fn new(solc_version: semver::Version, instruction: Instruction) -> Self { - let input_size = instruction.input_size(&solc_version); - let output_size = instruction.output_size(); - - Self { - solc_version, - instruction, - stack: Stack::new(), - stack_input: Stack::with_capacity(input_size), - stack_output: Stack::with_capacity(output_size), - } - } - - /// Pops the specified number of arguments, converted into their LLVM values. - fn pop_arguments_llvm<'ctx, D>( - &mut self, - context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, - ) -> anyhow::Result>> - where - D: revive_llvm_context::PolkaVMDependency + Clone, - { - let input_size = self.instruction.input_size(&context.evmla().version); - let output_size = self.instruction.output_size(); - let mut arguments = Vec::with_capacity(input_size); - for index in 0..input_size { - let pointer = context.evmla().stack - [self.stack.elements.len() + input_size - output_size - 1 - index] - .to_llvm() - .into_pointer_value(); - let value = context.build_load( - revive_llvm_context::PolkaVMPointer::new_stack_field(context, pointer), - format!("argument_{index}").as_str(), - )?; - arguments.push(value); - } - Ok(arguments) - } -} - -impl revive_llvm_context::PolkaVMWriteLLVM for Element -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn into_llvm( - mut self, - context: &mut revive_llvm_context::PolkaVMContext<'_, D>, - ) -> anyhow::Result<()> { - let mut original = self.instruction.value.clone(); - - let result = match self.instruction.name.clone() { - InstructionName::PUSH - | InstructionName::PUSH1 - | InstructionName::PUSH2 - | InstructionName::PUSH3 - | InstructionName::PUSH4 - | InstructionName::PUSH5 - | InstructionName::PUSH6 - | InstructionName::PUSH7 - | InstructionName::PUSH8 - | InstructionName::PUSH9 - | InstructionName::PUSH10 - | InstructionName::PUSH11 - | InstructionName::PUSH12 - | InstructionName::PUSH13 - | InstructionName::PUSH14 - | InstructionName::PUSH15 - | InstructionName::PUSH16 - | InstructionName::PUSH17 - | InstructionName::PUSH18 - | InstructionName::PUSH19 - | InstructionName::PUSH20 - | InstructionName::PUSH21 - | InstructionName::PUSH22 - | InstructionName::PUSH23 - | InstructionName::PUSH24 - | InstructionName::PUSH25 - | InstructionName::PUSH26 - | InstructionName::PUSH27 - | InstructionName::PUSH28 - | InstructionName::PUSH29 - | InstructionName::PUSH30 - | InstructionName::PUSH31 - | InstructionName::PUSH32 => crate::evmla::assembly::instruction::stack::push( - context, - self.instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?, - ) - .map(Some), - InstructionName::PUSH_Tag => crate::evmla::assembly::instruction::stack::push_tag( - context, - self.instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?, - ) - .map(Some), - InstructionName::PUSH_ContractHash => { - revive_llvm_context::polkavm_evm_create::contract_hash( - context, - self.instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?, - ) - .map(|argument| Some(argument.value)) - } - InstructionName::PUSH_ContractHashSize => { - revive_llvm_context::polkavm_evm_create::header_size( - context, - self.instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?, - ) - .map(|argument| Some(argument.value)) - } - InstructionName::PUSHLIB => { - let path = self - .instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?; - - Ok(Some( - context - .resolve_library(path.as_str())? - .as_basic_value_enum(), - )) - } - InstructionName::PUSH_Data => { - let value = self - .instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?; - - if value.len() > revive_common::BYTE_LENGTH_WORD * 2 { - Ok(Some(context.word_const(0).as_basic_value_enum())) - } else { - crate::evmla::assembly::instruction::stack::push(context, value).map(Some) - } - } - InstructionName::PUSHDEPLOYADDRESS => { - revive_llvm_context::polkavm_evm_contract_context::address(context).map(Some) - } - - InstructionName::DUP1 => crate::evmla::assembly::instruction::stack::dup( - context, - 1, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP2 => crate::evmla::assembly::instruction::stack::dup( - context, - 2, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP3 => crate::evmla::assembly::instruction::stack::dup( - context, - 3, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP4 => crate::evmla::assembly::instruction::stack::dup( - context, - 4, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP5 => crate::evmla::assembly::instruction::stack::dup( - context, - 5, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP6 => crate::evmla::assembly::instruction::stack::dup( - context, - 6, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP7 => crate::evmla::assembly::instruction::stack::dup( - context, - 7, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP8 => crate::evmla::assembly::instruction::stack::dup( - context, - 8, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP9 => crate::evmla::assembly::instruction::stack::dup( - context, - 9, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP10 => crate::evmla::assembly::instruction::stack::dup( - context, - 10, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP11 => crate::evmla::assembly::instruction::stack::dup( - context, - 11, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP12 => crate::evmla::assembly::instruction::stack::dup( - context, - 12, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP13 => crate::evmla::assembly::instruction::stack::dup( - context, - 13, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP14 => crate::evmla::assembly::instruction::stack::dup( - context, - 14, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP15 => crate::evmla::assembly::instruction::stack::dup( - context, - 15, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - InstructionName::DUP16 => crate::evmla::assembly::instruction::stack::dup( - context, - 16, - self.stack.elements.len(), - &mut original, - ) - .map(Some), - - InstructionName::SWAP1 => crate::evmla::assembly::instruction::stack::swap( - context, - 1, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP2 => crate::evmla::assembly::instruction::stack::swap( - context, - 2, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP3 => crate::evmla::assembly::instruction::stack::swap( - context, - 3, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP4 => crate::evmla::assembly::instruction::stack::swap( - context, - 4, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP5 => crate::evmla::assembly::instruction::stack::swap( - context, - 5, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP6 => crate::evmla::assembly::instruction::stack::swap( - context, - 6, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP7 => crate::evmla::assembly::instruction::stack::swap( - context, - 7, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP8 => crate::evmla::assembly::instruction::stack::swap( - context, - 8, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP9 => crate::evmla::assembly::instruction::stack::swap( - context, - 9, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP10 => crate::evmla::assembly::instruction::stack::swap( - context, - 10, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP11 => crate::evmla::assembly::instruction::stack::swap( - context, - 11, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP12 => crate::evmla::assembly::instruction::stack::swap( - context, - 12, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP13 => crate::evmla::assembly::instruction::stack::swap( - context, - 13, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP14 => crate::evmla::assembly::instruction::stack::swap( - context, - 14, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP15 => crate::evmla::assembly::instruction::stack::swap( - context, - 15, - self.stack.elements.len(), - ) - .map(|_| None), - InstructionName::SWAP16 => crate::evmla::assembly::instruction::stack::swap( - context, - 16, - self.stack.elements.len(), - ) - .map(|_| None), - - InstructionName::POP => { - crate::evmla::assembly::instruction::stack::pop(context).map(|_| None) - } - - InstructionName::Tag => { - let destination: num::BigUint = self - .instruction - .value - .expect("Always exists") - .parse() - .expect("Always valid"); - - crate::evmla::assembly::instruction::jump::unconditional( - context, - destination, - self.stack.hash(), - ) - .map(|_| None) - } - InstructionName::JUMP => { - let destination = self.stack_input.pop_tag()?; - - crate::evmla::assembly::instruction::jump::unconditional( - context, - destination, - self.stack.hash(), - ) - .map(|_| None) - } - InstructionName::JUMPI => { - let destination = self.stack_input.pop_tag()?; - let _condition = self.stack_input.pop(); - - crate::evmla::assembly::instruction::jump::conditional( - context, - destination, - self.stack.hash(), - self.stack.elements.len(), - ) - .map(|_| None) - } - InstructionName::JUMPDEST => Ok(None), - - InstructionName::ADD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::addition( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SUB => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::subtraction( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::MUL => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::multiplication( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::DIV => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::division( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::MOD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::remainder( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SDIV => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::division_signed( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SMOD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_arithmetic::remainder_signed( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - - InstructionName::LT => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_comparison::compare( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - inkwell::IntPredicate::ULT, - ) - .map(Some) - } - InstructionName::GT => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_comparison::compare( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - inkwell::IntPredicate::UGT, - ) - .map(Some) - } - InstructionName::EQ => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_comparison::compare( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - inkwell::IntPredicate::EQ, - ) - .map(Some) - } - InstructionName::ISZERO => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_comparison::compare( - context, - arguments[0].into_int_value(), - context.word_const(0), - inkwell::IntPredicate::EQ, - ) - .map(Some) - } - InstructionName::SLT => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_comparison::compare( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - inkwell::IntPredicate::SLT, - ) - .map(Some) - } - InstructionName::SGT => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_comparison::compare( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - inkwell::IntPredicate::SGT, - ) - .map(Some) - } - - InstructionName::OR => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::or( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::XOR => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::xor( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::NOT => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::xor( - context, - arguments[0].into_int_value(), - context.word_type().const_all_ones(), - ) - .map(Some) - } - InstructionName::AND => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::and( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SHL => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::shift_left( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SHR => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::shift_right( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SAR => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::shift_right_arithmetic( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::BYTE => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_bitwise::byte( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - - InstructionName::ADDMOD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_math::add_mod( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - arguments[2].into_int_value(), - ) - .map(Some) - } - InstructionName::MULMOD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_math::mul_mod( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - arguments[2].into_int_value(), - ) - .map(Some) - } - InstructionName::EXP => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_math::exponent( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - InstructionName::SIGNEXTEND => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_math::sign_extend( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - - InstructionName::SHA3 | InstructionName::KECCAK256 => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_crypto::sha3( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(Some) - } - - InstructionName::MLOAD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_memory::load( - context, - arguments[0].into_int_value(), - ) - .map(Some) - } - InstructionName::MSTORE => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_memory::store( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(|_| None) - } - InstructionName::MSTORE8 => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_memory::store_byte( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(|_| None) - } - InstructionName::MCOPY => { - let arguments = self.pop_arguments_llvm(context)?; - let destination = revive_llvm_context::PolkaVMPointer::new_with_offset( - context, - revive_llvm_context::PolkaVMAddressSpace::Heap, - context.byte_type(), - arguments[0].into_int_value(), - "mcopy_destination", - ); - let source = revive_llvm_context::PolkaVMPointer::new_with_offset( - context, - revive_llvm_context::PolkaVMAddressSpace::Heap, - context.byte_type(), - arguments[1].into_int_value(), - "mcopy_source", - ); - - context.build_memcpy( - destination, - source, - arguments[2].into_int_value(), - "mcopy_size", - )?; - Ok(None) - } - - InstructionName::SLOAD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_storage::load( - context, - arguments[0].into_int_value(), - ) - .map(Some) - } - InstructionName::SSTORE => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_storage::store( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(|_| None) - } - InstructionName::TLOAD => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_storage::transient_load( - context, - arguments[0].into_int_value(), - ) - .map(Some) - } - InstructionName::TSTORE => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_storage::transient_store( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(|_| None) - } - InstructionName::PUSHIMMUTABLE => { - let key = self - .instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?; - - let offset = context - .solidity_mut() - .get_or_allocate_immutable(key.as_str()) - / revive_common::BYTE_LENGTH_WORD; - - let index = context.xlen_type().const_int(offset as u64, false); - revive_llvm_context::polkavm_evm_immutable::load(context, index).map(Some) - } - InstructionName::ASSIGNIMMUTABLE => { - let mut arguments = self.pop_arguments_llvm(context)?; - - let key = self - .instruction - .value - .ok_or_else(|| anyhow::anyhow!("Instruction value missing"))?; - - let offset = context.solidity_mut().allocate_immutable(key.as_str()) - / revive_common::BYTE_LENGTH_WORD; - - let index = context.xlen_type().const_int(offset as u64, false); - let value = arguments.pop().expect("Always exists").into_int_value(); - revive_llvm_context::polkavm_evm_immutable::store(context, index, value) - .map(|_| None) - } - InstructionName::CALLDATALOAD => { - match context - .code_type() - .ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))? - { - revive_llvm_context::PolkaVMCodeType::Deploy => { - Ok(Some(context.word_const(0).as_basic_value_enum())) - } - revive_llvm_context::PolkaVMCodeType::Runtime => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_calldata::load( - context, - arguments[0].into_int_value(), - ) - .map(Some) - } - } - } - InstructionName::CALLDATASIZE => { - match context - .code_type() - .ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))? - { - revive_llvm_context::PolkaVMCodeType::Deploy => { - Ok(Some(context.word_const(0).as_basic_value_enum())) - } - revive_llvm_context::PolkaVMCodeType::Runtime => { - revive_llvm_context::polkavm_evm_calldata::size(context).map(Some) - } - } - } - InstructionName::CALLDATACOPY => { - let arguments = self.pop_arguments_llvm(context)?; - - match context - .code_type() - .ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))? - { - revive_llvm_context::PolkaVMCodeType::Deploy => { - let calldata_size = - revive_llvm_context::polkavm_evm_calldata::size(context)?; - - revive_llvm_context::polkavm_evm_calldata::copy( - context, - arguments[0].into_int_value(), - calldata_size.into_int_value(), - arguments[2].into_int_value(), - ) - .map(|_| None) - } - revive_llvm_context::PolkaVMCodeType::Runtime => { - revive_llvm_context::polkavm_evm_calldata::copy( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - arguments[2].into_int_value(), - ) - .map(|_| None) - } - } - } - InstructionName::CODESIZE => { - match context - .code_type() - .ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))? - { - revive_llvm_context::PolkaVMCodeType::Deploy => { - revive_llvm_context::polkavm_evm_calldata::size(context).map(Some) - } - revive_llvm_context::PolkaVMCodeType::Runtime => { - revive_llvm_context::polkavm_evm_ext_code::size(context, None).map(Some) - } - } - } - InstructionName::CODECOPY => { - let arguments = self.pop_arguments_llvm(context)?; - - let parent = context.module().get_name().to_str().expect("Always valid"); - let source = &self.stack_input.elements[1]; - let destination = &self.stack_input.elements[2]; - - let library_marker: u64 = 0x0b; - let library_flag: u64 = 0x73; - - match (source, destination) { - (_, StackElement::Constant(destination)) - if destination == &num::BigUint::from(library_marker) => - { - codecopy::library_marker(context, library_marker, library_flag) - } - (StackElement::Data(data), _) => { - codecopy::static_data(context, arguments[0].into_int_value(), data.as_str()) - } - (StackElement::Path(source), _) if source != parent => codecopy::contract_hash( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ), - _ => { - match context.code_type().ok_or_else(|| { - anyhow::anyhow!("The contract code part type is undefined") - })? { - revive_llvm_context::PolkaVMCodeType::Deploy => { - revive_llvm_context::polkavm_evm_calldata::copy( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - arguments[2].into_int_value(), - ) - } - revive_llvm_context::PolkaVMCodeType::Runtime => { - let calldata_size = - revive_llvm_context::polkavm_evm_calldata::size(context)?; - revive_llvm_context::polkavm_evm_calldata::copy( - context, - arguments[0].into_int_value(), - calldata_size.into_int_value(), - arguments[2].into_int_value(), - ) - } - } - } - } - .map(|_| None) - } - InstructionName::PUSHSIZE => Ok(Some(context.word_const(0).as_basic_value_enum())), - InstructionName::RETURNDATASIZE => { - revive_llvm_context::polkavm_evm_return_data::size(context).map(Some) - } - InstructionName::RETURNDATACOPY => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_return_data::copy( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - arguments[2].into_int_value(), - ) - .map(|_| None) - } - InstructionName::EXTCODESIZE => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_ext_code::size( - context, - Some(arguments[0].into_int_value()), - ) - .map(Some) - } - InstructionName::EXTCODEHASH => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_ext_code::hash( - context, - arguments[0].into_int_value(), - ) - .map(Some) - } - - InstructionName::RETURN => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_return::r#return( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(|_| None) - } - InstructionName::REVERT => { - let arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_return::revert( - context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), - ) - .map(|_| None) - } - InstructionName::STOP => { - revive_llvm_context::polkavm_evm_return::stop(context).map(|_| None) - } - InstructionName::INVALID => { - revive_llvm_context::polkavm_evm_return::invalid(context).map(|_| None) - } - - InstructionName::LOG0 => { - let mut arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_event::log( - context, - arguments.remove(0).into_int_value(), - arguments.remove(0).into_int_value(), - arguments - .into_iter() - .map(|argument| argument.into_int_value()) - .collect(), - ) - .map(|_| None) - } - InstructionName::LOG1 => { - let mut arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_event::log( - context, - arguments.remove(0).into_int_value(), - arguments.remove(0).into_int_value(), - arguments - .into_iter() - .map(|argument| argument.into_int_value()) - .collect(), - ) - .map(|_| None) - } - InstructionName::LOG2 => { - let mut arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_event::log( - context, - arguments.remove(0).into_int_value(), - arguments.remove(0).into_int_value(), - arguments - .into_iter() - .map(|argument| argument.into_int_value()) - .collect(), - ) - .map(|_| None) - } - InstructionName::LOG3 => { - let mut arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_event::log( - context, - arguments.remove(0).into_int_value(), - arguments.remove(0).into_int_value(), - arguments - .into_iter() - .map(|argument| argument.into_int_value()) - .collect(), - ) - .map(|_| None) - } - InstructionName::LOG4 => { - let mut arguments = self.pop_arguments_llvm(context)?; - revive_llvm_context::polkavm_evm_event::log( - context, - arguments.remove(0).into_int_value(), - arguments.remove(0).into_int_value(), - arguments - .into_iter() - .map(|argument| argument.into_int_value()) - .collect(), - ) - .map(|_| None) - } - - InstructionName::CALL => { - let mut arguments = self.pop_arguments_llvm(context)?; - - let gas = arguments.remove(0).into_int_value(); - let address = arguments.remove(0).into_int_value(); - let value = arguments.remove(0).into_int_value(); - let input_offset = arguments.remove(0).into_int_value(); - let input_size = arguments.remove(0).into_int_value(); - let output_offset = arguments.remove(0).into_int_value(); - let output_size = arguments.remove(0).into_int_value(); - - revive_llvm_context::polkavm_evm_call::call( - context, - gas, - address, - Some(value), - input_offset, - input_size, - output_offset, - output_size, - vec![], - false, - ) - .map(Some) - } - InstructionName::STATICCALL => { - let mut arguments = self.pop_arguments_llvm(context)?; - - let gas = arguments.remove(0).into_int_value(); - let address = arguments.remove(0).into_int_value(); - let input_offset = arguments.remove(0).into_int_value(); - let input_size = arguments.remove(0).into_int_value(); - let output_offset = arguments.remove(0).into_int_value(); - let output_size = arguments.remove(0).into_int_value(); - - revive_llvm_context::polkavm_evm_call::call( - context, - gas, - address, - None, - input_offset, - input_size, - output_offset, - output_size, - vec![], - true, - ) - .map(Some) - } - InstructionName::DELEGATECALL => { - let mut arguments = self.pop_arguments_llvm(context)?; - - let gas = arguments.remove(0).into_int_value(); - let address = arguments.remove(0).into_int_value(); - let input_offset = arguments.remove(0).into_int_value(); - let input_size = arguments.remove(0).into_int_value(); - let output_offset = arguments.remove(0).into_int_value(); - let output_size = arguments.remove(0).into_int_value(); - - revive_llvm_context::polkavm_evm_call::delegate_call( - context, - gas, - address, - input_offset, - input_size, - output_offset, - output_size, - vec![], - ) - .map(Some) - } - - InstructionName::CREATE | InstructionName::ZK_CREATE => { - let arguments = self.pop_arguments_llvm(context)?; - - let value = arguments[0].into_int_value(); - let input_offset = arguments[1].into_int_value(); - let input_length = arguments[2].into_int_value(); - - revive_llvm_context::polkavm_evm_create::create( - context, - value, - input_offset, - input_length, - None, - ) - .map(Some) - } - InstructionName::CREATE2 | InstructionName::ZK_CREATE2 => { - let arguments = self.pop_arguments_llvm(context)?; - - let value = arguments[0].into_int_value(); - let input_offset = arguments[1].into_int_value(); - let input_length = arguments[2].into_int_value(); - let salt = arguments[3].into_int_value(); - - revive_llvm_context::polkavm_evm_create::create( - context, - value, - input_offset, - input_length, - Some(salt), - ) - .map(Some) - } - - InstructionName::ADDRESS => { - revive_llvm_context::polkavm_evm_contract_context::address(context).map(Some) - } - InstructionName::CALLER => { - revive_llvm_context::polkavm_evm_contract_context::caller(context).map(Some) - } - - InstructionName::CALLVALUE => { - revive_llvm_context::polkavm_evm_ether_gas::value(context).map(Some) - } - InstructionName::GAS => { - revive_llvm_context::polkavm_evm_ether_gas::gas(context).map(Some) - } - InstructionName::BALANCE => { - let arguments = self.pop_arguments_llvm(context)?; - - let address = arguments[0].into_int_value(); - revive_llvm_context::polkavm_evm_ether_gas::balance(context, address).map(Some) - } - InstructionName::SELFBALANCE => { - revive_llvm_context::polkavm_evm_ether_gas::self_balance(context).map(Some) - } - - InstructionName::GASLIMIT => { - revive_llvm_context::polkavm_evm_contract_context::gas_limit(context).map(Some) - } - InstructionName::GASPRICE => { - revive_llvm_context::polkavm_evm_contract_context::gas_price(context).map(Some) - } - InstructionName::ORIGIN => { - revive_llvm_context::polkavm_evm_contract_context::origin(context).map(Some) - } - InstructionName::CHAINID => { - revive_llvm_context::polkavm_evm_contract_context::chain_id(context).map(Some) - } - InstructionName::TIMESTAMP => { - revive_llvm_context::polkavm_evm_contract_context::block_timestamp(context) - .map(Some) - } - InstructionName::NUMBER => { - revive_llvm_context::polkavm_evm_contract_context::block_number(context).map(Some) - } - InstructionName::BLOCKHASH => { - let arguments = self.pop_arguments_llvm(context)?; - let index = arguments[0].into_int_value(); - - revive_llvm_context::polkavm_evm_contract_context::block_hash(context, index) - .map(Some) - } - InstructionName::BLOBHASH => { - let _arguments = self.pop_arguments_llvm(context); - anyhow::bail!("The `BLOBHASH` instruction is not supported until zkVM v1.5.0"); - } - InstructionName::DIFFICULTY | InstructionName::PREVRANDAO => { - revive_llvm_context::polkavm_evm_contract_context::difficulty(context).map(Some) - } - InstructionName::COINBASE => { - revive_llvm_context::polkavm_evm_contract_context::coinbase(context).map(Some) - } - InstructionName::BASEFEE => { - revive_llvm_context::polkavm_evm_contract_context::basefee(context).map(Some) - } - InstructionName::BLOBBASEFEE => { - anyhow::bail!("The `BLOBBASEFEE` instruction is not supported until zkVM v1.5.0"); - } - InstructionName::MSIZE => { - revive_llvm_context::polkavm_evm_memory::msize(context).map(Some) - } - - InstructionName::CALLCODE => { - let mut _arguments = self.pop_arguments_llvm(context); - anyhow::bail!("The `CALLCODE` instruction is not supported"); - } - InstructionName::PC => { - anyhow::bail!("The `PC` instruction is not supported"); - } - InstructionName::EXTCODECOPY => { - let _arguments = self.pop_arguments_llvm(context); - anyhow::bail!("The `EXTCODECOPY` instruction is not supported"); - } - InstructionName::SELFDESTRUCT => { - let _arguments = self.pop_arguments_llvm(context)?; - anyhow::bail!("The `SELFDESTRUCT` instruction is not supported"); - } - - InstructionName::RecursiveCall { - name, - entry_key, - stack_hash, - output_size, - return_address, - .. - } => { - let mut arguments = self.pop_arguments_llvm(context)?; - arguments.pop(); - arguments.reverse(); - arguments.pop(); - - let function = context - .get_function(format!("{name}_{entry_key}").as_str()) - .expect("Always exists") - .borrow() - .declaration(); - let result = context.build_call( - function, - arguments.as_slice(), - format!("call_{}", name).as_str(), - ); - match result { - Some(value) if value.is_int_value() => { - let pointer = context.evmla().stack - [self.stack.elements.len() - output_size] - .to_llvm() - .into_pointer_value(); - context.build_store( - revive_llvm_context::PolkaVMPointer::new_stack_field(context, pointer), - value, - )?; - } - Some(value) if value.is_struct_value() => { - let return_value = value.into_struct_value(); - for index in 0..output_size { - let value = context - .builder() - .build_extract_value( - return_value, - index as u32, - format!("return_value_element_{}", index).as_str(), - ) - .expect("Always exists"); - let pointer = revive_llvm_context::PolkaVMPointer::new( - context.word_type(), - revive_llvm_context::PolkaVMAddressSpace::Stack, - context.evmla().stack - [self.stack.elements.len() - output_size + index] - .to_llvm() - .into_pointer_value(), - ); - context.build_store(pointer, value)?; - } - } - Some(_) => { - panic!("Only integers and structures can be returned from Ethir functions") - } - None => {} - } - - let return_block = context - .current_function() - .borrow() - .evmla() - .find_block(&return_address, &stack_hash)?; - context.build_unconditional_branch(return_block.inner()); - return Ok(()); - } - InstructionName::RecursiveReturn { .. } => { - let mut arguments = self.pop_arguments_llvm(context)?; - arguments.reverse(); - arguments.pop(); - - match context.current_function().borrow().r#return() { - revive_llvm_context::PolkaVMFunctionReturn::None => {} - revive_llvm_context::PolkaVMFunctionReturn::Primitive { pointer } => { - assert_eq!(arguments.len(), 1); - context.build_store(pointer, arguments.remove(0))?; - } - revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, .. } => { - for (index, argument) in arguments.into_iter().enumerate() { - let element_pointer = context.build_gep( - pointer, - &[ - context.word_const(0), - context - .integer_const(revive_common::BIT_LENGTH_X32, index as u64), - ], - context.word_type(), - format!("return_value_pointer_element_{}", index).as_str(), - ); - context.build_store(element_pointer, argument)?; - } - } - } - - let return_block = context.current_function().borrow().return_block(); - context.build_unconditional_branch(return_block); - Ok(None) - } - }?; - - if let Some(result) = result { - let pointer = context.evmla().stack[self.stack.elements.len() - 1] - .to_llvm() - .into_pointer_value(); - context.build_store( - revive_llvm_context::PolkaVMPointer::new_stack_field(context, pointer), - result, - )?; - context.evmla_mut().stack[self.stack.elements.len() - 1].original = original; - } - - Ok(()) - } -} - -impl std::fmt::Display for Element { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut stack = self.stack.to_owned(); - for _ in 0..self.stack_output.len() { - let _ = stack.pop(); - } - - write!(f, "{:80}{}", self.instruction.to_string(), stack)?; - if !self.stack_input.is_empty() { - write!(f, " - {}", self.stack_input)?; - } - if !self.stack_output.is_empty() { - write!(f, " + {}", self.stack_output)?; - } - Ok(()) - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/block/element/stack/element.rs b/crates/solidity/src/evmla/ethereal_ir/function/block/element/stack/element.rs deleted file mode 100644 index 10c1f53..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/block/element/stack/element.rs +++ /dev/null @@ -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"), - } - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/block/element/stack/mod.rs b/crates/solidity/src/evmla/ethereal_ir/function/block/element/stack/mod.rs deleted file mode 100644 index f62a0f2..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/block/element/stack/mod.rs +++ /dev/null @@ -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, -} - -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) -> 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 { - self.elements - .pop() - .ok_or_else(|| anyhow::anyhow!("Stack underflow")) - } - - /// Pops the tag from the top. - pub fn pop_tag(&mut self) -> anyhow::Result { - 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 { - 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::>() - .join(" | ") - ) - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/block/mod.rs b/crates/solidity/src/evmla/ethereal_ir/function/block/mod.rs deleted file mode 100644 index 9732286..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/block/mod.rs +++ /dev/null @@ -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, - /// The block elements relevant to the stack consistency. - pub elements: Vec, - /// 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, -} - -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 revive_llvm_context::PolkaVMWriteLLVM for Block -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> 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::>() - .join(", ") - ) - }, - )?; - for element in self.elements.iter() { - writeln!(f, " {element}")?; - } - Ok(()) - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/mod.rs b/crates/solidity/src/evmla/ethereal_ir/function/mod.rs deleted file mode 100644 index 4ad7ed3..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/mod.rs +++ /dev/null @@ -1,1329 +0,0 @@ -//! The Ethereal IR function. - -pub mod block; -pub mod queue_element; -pub mod r#type; -pub mod visited_element; - -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::HashMap; - -use inkwell::types::BasicType; -use inkwell::values::BasicValue; -use num::CheckedAdd; -use num::CheckedDiv; -use num::CheckedMul; -use num::CheckedSub; -use num::Num; -use num::One; -use num::ToPrimitive; -use num::Zero; - -use crate::evmla::assembly::instruction::name::Name as InstructionName; -use crate::evmla::assembly::instruction::Instruction; -use crate::evmla::ethereal_ir::function::block::element::stack::element::Element; -use crate::evmla::ethereal_ir::function::block::element::stack::Stack; -use crate::evmla::ethereal_ir::EtherealIR; -use crate::solc::standard_json::output::contract::evm::extra_metadata::recursive_function::RecursiveFunction; -use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata; - -use self::block::element::stack::element::Element as StackElement; -use self::block::element::Element as BlockElement; -use self::block::Block; -use self::queue_element::QueueElement; -use self::r#type::Type; -use self::visited_element::VisitedElement; - -/// The Ethereal IR function. -#[derive(Debug, Clone)] -pub struct Function { - /// The Solidity compiler version. - pub solc_version: semver::Version, - /// The function name. - pub name: String, - /// The separately labelled blocks. - pub blocks: BTreeMap>, - /// The function type. - pub r#type: Type, - /// The function stack size. - pub stack_size: usize, -} - -impl Function { - /// A shortcut constructor. - pub fn new(solc_version: semver::Version, r#type: Type) -> Self { - let name = match r#type { - Type::Initial => EtherealIR::DEFAULT_ENTRY_FUNCTION_NAME.to_string(), - Type::Recursive { - ref name, - ref block_key, - .. - } => format!("{name}_{block_key}"), - }; - - Self { - solc_version, - name, - blocks: BTreeMap::new(), - r#type, - stack_size: 0, - } - } - - /// Runs the function block traversal. - pub fn traverse( - &mut self, - blocks: &HashMap, - functions: &mut BTreeMap, - extra_metadata: &ExtraMetadata, - visited_functions: &mut BTreeSet, - ) -> anyhow::Result<()> { - let mut visited_blocks = BTreeSet::new(); - - match self.r#type { - Type::Initial => { - for code_type in [ - revive_llvm_context::PolkaVMCodeType::Deploy, - revive_llvm_context::PolkaVMCodeType::Runtime, - ] { - self.consume_block( - blocks, - functions, - extra_metadata, - visited_functions, - &mut visited_blocks, - QueueElement::new( - revive_llvm_context::PolkaVMFunctionBlockKey::new( - code_type, - num::BigUint::zero(), - ), - None, - Stack::new(), - ), - )?; - } - } - Type::Recursive { - ref block_key, - input_size, - output_size, - .. - } => { - let mut stack = Stack::with_capacity(1 + input_size); - stack.push(Element::ReturnAddress(output_size)); - stack.append(&mut Stack::new_with_elements(vec![ - Element::value( - "ARGUMENT".to_owned() - ); - input_size - ])); - - self.consume_block( - blocks, - functions, - extra_metadata, - visited_functions, - &mut visited_blocks, - QueueElement::new(block_key.to_owned(), None, stack), - )?; - } - } - - self.finalize(); - - Ok(()) - } - - /// Consumes the entry or a conditional block attached to another one. - fn consume_block( - &mut self, - blocks: &HashMap, - functions: &mut BTreeMap, - extra_metadata: &ExtraMetadata, - visited_functions: &mut BTreeSet, - visited_blocks: &mut BTreeSet, - mut queue_element: QueueElement, - ) -> anyhow::Result<()> { - let version = self.solc_version.to_owned(); - - let mut queue = vec![]; - - let mut block = blocks - .get(&queue_element.block_key) - .cloned() - .ok_or_else(|| { - anyhow::anyhow!("Undeclared destination block {}", queue_element.block_key) - })?; - block.initial_stack = queue_element.stack.clone(); - let block = self.insert_block(block); - block.stack = block.initial_stack.clone(); - if let Some(predecessor) = queue_element.predecessor.take() { - block.insert_predecessor(predecessor.0, predecessor.1); - } - - let visited_element = - VisitedElement::new(queue_element.block_key.clone(), queue_element.stack.hash()); - if visited_blocks.contains(&visited_element) { - return Ok(()); - } - visited_blocks.insert(visited_element); - - let mut block_size = 0; - for block_element in block.elements.iter_mut() { - block_size += 1; - - if Self::handle_instruction( - blocks, - functions, - extra_metadata, - visited_functions, - block.key.code_type, - block.instance.unwrap_or_default(), - &mut block.stack, - block_element, - &version, - &mut queue, - &mut queue_element, - ) - .is_err() - { - block_element.instruction = Instruction::invalid(&block_element.instruction); - block_element.stack = block.stack.clone(); - break; - } - } - block.elements.truncate(block_size); - - for element in queue.into_iter() { - self.consume_block( - blocks, - functions, - extra_metadata, - visited_functions, - visited_blocks, - element, - )?; - } - - Ok(()) - } - - /// Processes an instruction, returning an error, if there is an invalid stack state. - /// The blocks with an invalid stack state are considered being partially unreachable, and - /// the invalid part is truncated after terminating with an `INVALID` instruction. - #[allow(clippy::too_many_arguments)] - fn handle_instruction( - blocks: &HashMap, - functions: &mut BTreeMap, - extra_metadata: &ExtraMetadata, - visited_functions: &mut BTreeSet, - code_type: revive_llvm_context::PolkaVMCodeType, - instance: usize, - block_stack: &mut Stack, - block_element: &mut BlockElement, - version: &semver::Version, - queue: &mut Vec, - queue_element: &mut QueueElement, - ) -> anyhow::Result<()> { - let (stack_output, queue_element) = match block_element.instruction { - Instruction { - name: InstructionName::PUSH_Tag, - value: Some(ref tag), - .. - } => { - let tag: num::BigUint = tag.parse().expect("Always valid"); - (vec![Element::Tag(tag & num::BigUint::from(u64::MAX))], None) - } - ref instruction @ Instruction { - name: InstructionName::JUMP, - .. - } => { - queue_element.predecessor = Some((queue_element.block_key.clone(), instance)); - - let block_key = match block_stack - .elements - .last() - .ok_or_else(|| anyhow::anyhow!("Destination tag is missing"))? - { - Element::Tag(destination) if destination > &num::BigUint::from(u32::MAX) => { - revive_llvm_context::PolkaVMFunctionBlockKey::new( - revive_llvm_context::PolkaVMCodeType::Runtime, - destination.to_owned() - num::BigUint::from(1u64 << 32), - ) - } - Element::Tag(destination) => revive_llvm_context::PolkaVMFunctionBlockKey::new( - code_type, - destination.to_owned(), - ), - Element::ReturnAddress(output_size) => { - block_element.instruction = - Instruction::recursive_return(1 + output_size, instruction); - Self::update_io_data(block_stack, block_element, 1 + output_size, vec![])?; - return Ok(()); - } - element => { - return Err(anyhow::anyhow!( - "The {} instruction expected a tag or return address, found {}", - instruction.name, - element - )); - } - }; - - let (next_block_key, stack_output) = - if let Some(recursive_function) = extra_metadata.get(&block_key) { - Self::handle_recursive_function_call( - recursive_function, - blocks, - functions, - extra_metadata, - visited_functions, - block_key, - block_stack, - block_element, - version, - )? - } else { - (block_key, vec![]) - }; - - ( - stack_output, - Some(QueueElement::new( - next_block_key, - queue_element.predecessor.clone(), - Stack::new(), - )), - ) - } - ref instruction @ Instruction { - name: InstructionName::JUMPI, - .. - } => { - queue_element.predecessor = Some((queue_element.block_key.clone(), instance)); - - let block_key = match block_stack - .elements - .last() - .ok_or_else(|| anyhow::anyhow!("Destination tag is missing"))? - { - Element::Tag(destination) if destination > &num::BigUint::from(u32::MAX) => { - revive_llvm_context::PolkaVMFunctionBlockKey::new( - revive_llvm_context::PolkaVMCodeType::Runtime, - destination.to_owned() - num::BigUint::from(1u64 << 32), - ) - } - Element::Tag(destination) => revive_llvm_context::PolkaVMFunctionBlockKey::new( - code_type, - destination.to_owned(), - ), - element => { - return Err(anyhow::anyhow!( - "The {} instruction expected a tag or return address, found {}", - instruction.name, - element - )); - } - }; - - ( - vec![], - Some(QueueElement::new( - block_key, - queue_element.predecessor.clone(), - Stack::new(), - )), - ) - } - Instruction { - name: InstructionName::Tag, - value: Some(ref tag), - .. - } => { - let tag: num::BigUint = tag.parse().expect("Always valid"); - let block_key = revive_llvm_context::PolkaVMFunctionBlockKey::new(code_type, tag); - - queue_element.predecessor = Some((queue_element.block_key.clone(), instance)); - queue_element.block_key = block_key.clone(); - - ( - vec![], - Some(QueueElement::new( - block_key, - queue_element.predecessor.clone(), - Stack::new(), - )), - ) - } - - Instruction { - name: InstructionName::SWAP1, - .. - } => { - block_stack.swap(1)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP2, - .. - } => { - block_stack.swap(2)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP3, - .. - } => { - block_stack.swap(3)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP4, - .. - } => { - block_stack.swap(4)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP5, - .. - } => { - block_stack.swap(5)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP6, - .. - } => { - block_stack.swap(6)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP7, - .. - } => { - block_stack.swap(7)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP8, - .. - } => { - block_stack.swap(8)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP9, - .. - } => { - block_stack.swap(9)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP10, - .. - } => { - block_stack.swap(10)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP11, - .. - } => { - block_stack.swap(11)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP12, - .. - } => { - block_stack.swap(12)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP13, - .. - } => { - block_stack.swap(13)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP14, - .. - } => { - block_stack.swap(14)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP15, - .. - } => { - block_stack.swap(15)?; - (vec![], None) - } - Instruction { - name: InstructionName::SWAP16, - .. - } => { - block_stack.swap(16)?; - (vec![], None) - } - - Instruction { - name: InstructionName::DUP1, - .. - } => (vec![block_stack.dup(1)?], None), - Instruction { - name: InstructionName::DUP2, - .. - } => (vec![block_stack.dup(2)?], None), - Instruction { - name: InstructionName::DUP3, - .. - } => (vec![block_stack.dup(3)?], None), - Instruction { - name: InstructionName::DUP4, - .. - } => (vec![block_stack.dup(4)?], None), - Instruction { - name: InstructionName::DUP5, - .. - } => (vec![block_stack.dup(5)?], None), - Instruction { - name: InstructionName::DUP6, - .. - } => (vec![block_stack.dup(6)?], None), - Instruction { - name: InstructionName::DUP7, - .. - } => (vec![block_stack.dup(7)?], None), - Instruction { - name: InstructionName::DUP8, - .. - } => (vec![block_stack.dup(8)?], None), - Instruction { - name: InstructionName::DUP9, - .. - } => (vec![block_stack.dup(9)?], None), - Instruction { - name: InstructionName::DUP10, - .. - } => (vec![block_stack.dup(10)?], None), - Instruction { - name: InstructionName::DUP11, - .. - } => (vec![block_stack.dup(11)?], None), - Instruction { - name: InstructionName::DUP12, - .. - } => (vec![block_stack.dup(12)?], None), - Instruction { - name: InstructionName::DUP13, - .. - } => (vec![block_stack.dup(13)?], None), - Instruction { - name: InstructionName::DUP14, - .. - } => (vec![block_stack.dup(14)?], None), - Instruction { - name: InstructionName::DUP15, - .. - } => (vec![block_stack.dup(15)?], None), - Instruction { - name: InstructionName::DUP16, - .. - } => (vec![block_stack.dup(16)?], None), - - Instruction { - name: - InstructionName::PUSH - | InstructionName::PUSH1 - | InstructionName::PUSH2 - | InstructionName::PUSH3 - | InstructionName::PUSH4 - | InstructionName::PUSH5 - | InstructionName::PUSH6 - | InstructionName::PUSH7 - | InstructionName::PUSH8 - | InstructionName::PUSH9 - | InstructionName::PUSH10 - | InstructionName::PUSH11 - | InstructionName::PUSH12 - | InstructionName::PUSH13 - | InstructionName::PUSH14 - | InstructionName::PUSH15 - | InstructionName::PUSH16 - | InstructionName::PUSH17 - | InstructionName::PUSH18 - | InstructionName::PUSH19 - | InstructionName::PUSH20 - | InstructionName::PUSH21 - | InstructionName::PUSH22 - | InstructionName::PUSH23 - | InstructionName::PUSH24 - | InstructionName::PUSH25 - | InstructionName::PUSH26 - | InstructionName::PUSH27 - | InstructionName::PUSH28 - | InstructionName::PUSH29 - | InstructionName::PUSH30 - | InstructionName::PUSH31 - | InstructionName::PUSH32, - value: Some(ref constant), - .. - } => ( - vec![num::BigUint::from_str_radix( - constant.as_str(), - revive_common::BASE_HEXADECIMAL, - ) - .map(StackElement::Constant)?], - None, - ), - Instruction { - name: - InstructionName::PUSH_ContractHash - | InstructionName::PUSH_ContractHashSize - | InstructionName::PUSHLIB, - value: Some(ref path), - .. - } => (vec![StackElement::Path(path.to_owned())], None), - Instruction { - name: InstructionName::PUSH_Data, - value: Some(ref data), - .. - } => (vec![StackElement::Data(data.to_owned())], None), - ref instruction @ Instruction { - name: InstructionName::PUSHDEPLOYADDRESS, - .. - } => ( - vec![StackElement::value(instruction.name.to_string())], - None, - ), - - ref instruction @ Instruction { - name: InstructionName::ADD, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Tag(operand_2)) => { - match operand_1.checked_add(operand_2) { - Some(result) if Self::is_tag_value_valid(blocks, &result) => { - Element::Tag(result) - } - Some(_result) => Element::value(instruction.name.to_string()), - None => Element::value(instruction.name.to_string()), - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - match operand_1.checked_add(operand_2) { - Some(result) => Element::Constant(result), - None => Element::value(instruction.name.to_string()), - } - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::SUB, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Tag(operand_2)) => { - match operand_1.checked_sub(operand_2) { - Some(result) if Self::is_tag_value_valid(blocks, &result) => { - Element::Tag(result) - } - Some(_result) => Element::value(instruction.name.to_string()), - None => Element::value(instruction.name.to_string()), - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - match operand_1.checked_sub(operand_2) { - Some(result) => Element::Constant(result), - None => Element::value(instruction.name.to_string()), - } - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::MUL, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Tag(operand_2)) => { - match operand_1.checked_mul(operand_2) { - Some(result) if Self::is_tag_value_valid(blocks, &result) => { - Element::Tag(result) - } - Some(_result) => Element::value(instruction.name.to_string()), - None => Element::value(instruction.name.to_string()), - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - match operand_1.checked_mul(operand_2) { - Some(result) => Element::Constant(result), - None => Element::value(instruction.name.to_string()), - } - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::DIV, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Tag(operand_2)) => { - if operand_2.is_zero() { - Element::Tag(num::BigUint::zero()) - } else { - match operand_1.checked_div(operand_2) { - Some(result) if Self::is_tag_value_valid(blocks, &result) => { - Element::Tag(result) - } - Some(_result) => Element::value(instruction.name.to_string()), - None => Element::value(instruction.name.to_string()), - } - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - if operand_2.is_zero() { - Element::Constant(num::BigUint::zero()) - } else { - match operand_1.checked_div(operand_2) { - Some(result) => Element::Constant(result), - None => Element::value(instruction.name.to_string()), - } - } - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::MOD, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Tag(operand_2)) => { - if operand_2.is_zero() { - Element::Tag(num::BigUint::zero()) - } else { - let result = operand_1 % operand_2; - if Self::is_tag_value_valid(blocks, &result) { - Element::Tag(result) - } else { - Element::value(instruction.name.to_string()) - } - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - if operand_2.is_zero() { - Element::Constant(num::BigUint::zero()) - } else { - Element::Constant(operand_1 % operand_2) - } - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::SHL, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[0], &operands[1]) { - (Element::Tag(tag), Element::Constant(offset)) => { - let offset = offset % revive_common::BIT_LENGTH_WORD; - let offset = offset.to_u64().expect("Always valid"); - let result = tag << offset; - if Self::is_tag_value_valid(blocks, &result) { - Element::Tag(result) - } else { - Element::value(instruction.name.to_string()) - } - } - (Element::Constant(constant), Element::Constant(offset)) => { - let offset = offset % revive_common::BIT_LENGTH_WORD; - let offset = offset.to_u64().expect("Always valid"); - Element::Constant(constant << offset) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::SHR, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[0], &operands[1]) { - (Element::Tag(tag), Element::Constant(offset)) => { - let offset = offset % revive_common::BIT_LENGTH_WORD; - let offset = offset.to_u64().expect("Always valid"); - let result = tag >> offset; - if Self::is_tag_value_valid(blocks, &result) { - Element::Tag(result) - } else { - Element::value(instruction.name.to_string()) - } - } - (Element::Constant(constant), Element::Constant(offset)) => { - let offset = offset % revive_common::BIT_LENGTH_WORD; - let offset = offset.to_u64().expect("Always valid"); - Element::Constant(constant >> offset) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::OR, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) => { - let result = operand_1 | operand_2; - if Self::is_tag_value_valid(blocks, &result) { - Element::Tag(result) - } else { - Element::value(instruction.name.to_string()) - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - Element::Constant(operand_1 | operand_2) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::XOR, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) => { - let result = operand_1 ^ operand_2; - if Self::is_tag_value_valid(blocks, &result) { - Element::Tag(result) - } else { - Element::value(instruction.name.to_string()) - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - Element::Constant(operand_1 ^ operand_2) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::AND, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Tag(operand_2)) - | (Element::Tag(operand_1), Element::Constant(operand_2)) - | (Element::Constant(operand_1), Element::Tag(operand_2)) => { - let result = operand_1 & operand_2; - if Self::is_tag_value_valid(blocks, &result) { - Element::Tag(result) - } else { - Element::value(instruction.name.to_string()) - } - } - (Element::Constant(operand_1), Element::Constant(operand_2)) => { - Element::Constant(operand_1 & operand_2) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - - ref instruction @ Instruction { - name: InstructionName::LT, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Tag(operand_2)) => { - Element::Constant(num::BigUint::from(u64::from(operand_1 < operand_2))) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::GT, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Tag(operand_2)) => { - Element::Constant(num::BigUint::from(u64::from(operand_1 > operand_2))) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::EQ, - .. - } => { - let operands = &block_stack.elements[block_stack.elements.len() - 2..]; - - let result = match (&operands[1], &operands[0]) { - (Element::Tag(operand_1), Element::Tag(operand_2)) => { - Element::Constant(num::BigUint::from(u64::from(operand_1 == operand_2))) - } - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - ref instruction @ Instruction { - name: InstructionName::ISZERO, - .. - } => { - let operand = block_stack - .elements - .last() - .ok_or_else(|| anyhow::anyhow!("Operand is missing"))?; - - let result = match operand { - Element::Tag(operand) => Element::Constant(if operand.is_zero() { - num::BigUint::one() - } else { - num::BigUint::zero() - }), - _ => Element::value(instruction.name.to_string()), - }; - - (vec![result], None) - } - - ref instruction => ( - vec![Element::value(instruction.name.to_string()); instruction.output_size()], - None, - ), - }; - - Self::update_io_data( - block_stack, - block_element, - block_element.instruction.input_size(version), - stack_output, - )?; - - if let Some(mut queue_element) = queue_element { - block_element.stack.clone_into(&mut queue_element.stack); - queue.push(queue_element); - } - - Ok(()) - } - - /// Updates the stack data with input and output data. - fn update_io_data( - block_stack: &mut Stack, - block_element: &mut BlockElement, - input_size: usize, - output_data: Vec, - ) -> anyhow::Result<()> { - if block_stack.len() < input_size { - anyhow::bail!("Stack underflow"); - } - block_element.stack_input = Stack::new_with_elements( - block_stack - .elements - .drain(block_stack.len() - input_size..) - .collect(), - ); - block_element.stack_output = Stack::new_with_elements(output_data); - block_stack.append(&mut block_element.stack_output.clone()); - block_element.stack = block_stack.clone(); - Ok(()) - } - - /// Handles the recursive function call. - #[allow(clippy::too_many_arguments)] - fn handle_recursive_function_call( - recursive_function: &RecursiveFunction, - blocks: &HashMap, - functions: &mut BTreeMap, - extra_metadata: &ExtraMetadata, - visited_functions: &mut BTreeSet, - block_key: revive_llvm_context::PolkaVMFunctionBlockKey, - block_stack: &mut Stack, - block_element: &mut BlockElement, - version: &semver::Version, - ) -> anyhow::Result<(revive_llvm_context::PolkaVMFunctionBlockKey, Vec)> { - let return_address_offset = block_stack.elements.len() - 2 - recursive_function.input_size; - let input_arguments_offset = return_address_offset + 1; - let callee_tag_offset = input_arguments_offset + recursive_function.input_size; - - let return_address = match block_stack.elements[return_address_offset] { - Element::Tag(ref return_address) => revive_llvm_context::PolkaVMFunctionBlockKey::new( - block_key.code_type, - return_address.to_owned(), - ), - ref element => anyhow::bail!("Expected the function return address, found {}", element), - }; - let mut stack = Stack::with_capacity(1 + recursive_function.input_size); - stack.push(StackElement::ReturnAddress( - 1 + recursive_function.output_size, - )); - stack.append(&mut Stack::new_with_elements( - block_stack.elements[input_arguments_offset..callee_tag_offset].to_owned(), - )); - let stack_hash = stack.hash(); - - let visited_element = VisitedElement::new(block_key.clone(), stack_hash); - if !visited_functions.contains(&visited_element) { - let mut function = Self::new( - version.to_owned(), - Type::new_recursive( - recursive_function.name.to_owned(), - block_key.clone(), - recursive_function.input_size, - recursive_function.output_size, - ), - ); - visited_functions.insert(visited_element); - function.traverse(blocks, functions, extra_metadata, visited_functions)?; - functions.insert(block_key.clone(), function); - } - - let stack_output = - vec![Element::value("RETURN_VALUE".to_owned()); recursive_function.output_size]; - let mut return_stack = Stack::new_with_elements( - block_stack.elements[..block_stack.len() - recursive_function.input_size - 2] - .to_owned(), - ); - return_stack.append(&mut Stack::new_with_elements(stack_output.clone())); - let return_stack_hash = return_stack.hash(); - - block_element.instruction = Instruction::recursive_call( - recursive_function.name.to_owned(), - block_key, - return_stack_hash, - recursive_function.input_size + 2, - recursive_function.output_size, - return_address.clone(), - &block_element.instruction, - ); - - Ok((return_address, stack_output)) - } - - /// Pushes a block into the function. - fn insert_block(&mut self, mut block: Block) -> &mut Block { - let key = block.key.clone(); - - if let Some(entry) = self.blocks.get_mut(&key) { - if entry.iter().all(|existing_block| { - existing_block.initial_stack.hash() != block.initial_stack.hash() - }) { - block.instance = Some(entry.len()); - entry.push(block); - } - } else { - block.instance = Some(0); - self.blocks.insert(block.key.clone(), vec![block]); - } - - self.blocks - .get_mut(&key) - .expect("Always exists") - .last_mut() - .expect("Always exists") - } - - /// Checks whether the tag value actually references an existing block. - /// Checks both deploy and runtime code. - fn is_tag_value_valid( - blocks: &HashMap, - tag: &num::BigUint, - ) -> bool { - blocks.contains_key(&revive_llvm_context::PolkaVMFunctionBlockKey::new( - revive_llvm_context::PolkaVMCodeType::Deploy, - tag & num::BigUint::from(u32::MAX), - )) || blocks.contains_key(&revive_llvm_context::PolkaVMFunctionBlockKey::new( - revive_llvm_context::PolkaVMCodeType::Runtime, - tag & num::BigUint::from(u32::MAX), - )) - } - - /// Finalizes the function data. - fn finalize(&mut self) { - for (_tag, blocks) in self.blocks.iter() { - for block in blocks.iter() { - for block_element in block.elements.iter() { - let total_length = block_element.stack.elements.len() - + block_element.stack_input.len() - + block_element.stack_output.len(); - if total_length > self.stack_size { - self.stack_size = total_length; - } - } - } - } - } -} - -impl revive_llvm_context::PolkaVMWriteLLVM for Function -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn declare( - &mut self, - context: &mut revive_llvm_context::PolkaVMContext, - ) -> anyhow::Result<()> { - let (function_type, output_size) = match self.r#type { - Type::Initial => { - let output_size = 0; - let r#type = context.function_type( - vec![context - .integer_type(revive_common::BIT_LENGTH_BOOLEAN) - .as_basic_type_enum()], - output_size, - ); - (r#type, output_size) - } - Type::Recursive { - input_size, - output_size, - .. - } => { - let r#type = context.function_type( - vec![ - context - .integer_type(revive_common::BIT_LENGTH_WORD) - .as_basic_type_enum(); - input_size - ], - output_size, - ); - (r#type, output_size) - } - }; - let function = context.add_function( - self.name.as_str(), - function_type, - output_size, - Some(inkwell::module::Linkage::External), - )?; - function - .borrow_mut() - .set_evmla_data(revive_llvm_context::PolkaVMFunctionEVMLAData::new( - self.stack_size, - )); - - Ok(()) - } - - fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { - context.set_current_function(self.name.as_str(), None)?; - - for (key, blocks) in self.blocks.iter() { - for (index, block) in blocks.iter().enumerate() { - let inner = context.append_basic_block(format!("block_{key}/{index}").as_str()); - let mut stack_hashes = vec![block.initial_stack.hash()]; - stack_hashes.extend_from_slice(block.extra_hashes.as_slice()); - let evmla_data = - revive_llvm_context::PolkaVMFunctionBlockEVMLAData::new(stack_hashes); - let mut block = revive_llvm_context::PolkaVMFunctionBlock::new(inner); - block.set_evmla_data(evmla_data); - context - .current_function() - .borrow_mut() - .evmla_mut() - .insert_block(key.to_owned(), block); - } - } - - context.set_basic_block(context.current_function().borrow().entry_block()); - let mut stack_variables = Vec::with_capacity(self.stack_size); - for stack_index in 0..self.stack_size { - let pointer = context.build_alloca( - context.word_type(), - format!("stack_var_{stack_index:03}").as_str(), - ); - let value = match self.r#type { - Type::Recursive { input_size, .. } - if stack_index >= 1 && stack_index <= input_size => - { - context - .current_function() - .borrow() - .declaration() - .value - .get_nth_param((stack_index - 1) as u32) - .expect("Always valid") - } - _ => context.word_const(0).as_basic_value_enum(), - }; - context.build_store(pointer, value)?; - stack_variables.push(revive_llvm_context::PolkaVMArgument::new( - pointer.value.as_basic_value_enum(), - )); - } - context.evmla_mut().stack = stack_variables; - - match self.r#type { - Type::Initial => { - let is_deploy_code_flag = context - .current_function() - .borrow() - .get_nth_param(0) - .into_int_value(); - let deploy_code_block = context.current_function().borrow().evmla().find_block( - &revive_llvm_context::PolkaVMFunctionBlockKey::new( - revive_llvm_context::PolkaVMCodeType::Deploy, - num::BigUint::zero(), - ), - &Stack::default().hash(), - )?; - let runtime_code_block = context.current_function().borrow().evmla().find_block( - &revive_llvm_context::PolkaVMFunctionBlockKey::new( - revive_llvm_context::PolkaVMCodeType::Runtime, - num::BigUint::zero(), - ), - &Stack::default().hash(), - )?; - context.build_conditional_branch( - is_deploy_code_flag, - deploy_code_block.inner(), - runtime_code_block.inner(), - )?; - } - Type::Recursive { ref block_key, .. } => { - let initial_block = context - .current_function() - .borrow() - .evmla() - .blocks - .get(block_key) - .expect("Always exists") - .first() - .expect("Always exists") - .inner(); - context.build_unconditional_branch(initial_block); - } - } - - for (key, blocks) in self.blocks.into_iter() { - for (llvm_block, ir_block) in context - .current_function() - .borrow() - .evmla() - .blocks - .get(&key) - .cloned() - .ok_or_else(|| anyhow::anyhow!("Undeclared function block {}", key))? - .into_iter() - .map(|block| block.inner()) - .zip(blocks) - { - context.set_basic_block(llvm_block); - ir_block.into_llvm(context)?; - } - } - - context.set_basic_block(context.current_function().borrow().return_block()); - match context.current_function().borrow().r#return() { - revive_llvm_context::PolkaVMFunctionReturn::None => { - context.build_return(None); - } - revive_llvm_context::PolkaVMFunctionReturn::Primitive { pointer } => { - let return_value = context.build_load(pointer, "return_value")?; - context.build_return(Some(&return_value)); - } - revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, .. } => { - let return_value = context.build_load(pointer, "return_value")?; - context.build_return(Some(&return_value)); - } - } - - context.pop_debug_scope(); - - Ok(()) - } -} - -impl std::fmt::Display for Function { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.r#type { - Type::Initial => writeln!(f, "function {} {{", self.name), - Type::Recursive { - input_size, - output_size, - .. - } => writeln!( - f, - "function {}({}) -> {} {{", - self.name, input_size, output_size - ), - }?; - writeln!(f, " stack_usage: {}", self.stack_size)?; - for (_key, blocks) in self.blocks.iter() { - for block in blocks.iter() { - write!(f, "{block}")?; - } - } - writeln!(f, "}}")?; - Ok(()) - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/queue_element.rs b/crates/solidity/src/evmla/ethereal_ir/function/queue_element.rs deleted file mode 100644 index 6a28d31..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/queue_element.rs +++ /dev/null @@ -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, - } - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/type.rs b/crates/solidity/src/evmla/ethereal_ir/function/type.rs deleted file mode 100644 index 1dbeffa..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/type.rs +++ /dev/null @@ -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, - } - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/function/visited_element.rs b/crates/solidity/src/evmla/ethereal_ir/function/visited_element.rs deleted file mode 100644 index c8456eb..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/function/visited_element.rs +++ /dev/null @@ -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 { - 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 - } - } - } - } -} diff --git a/crates/solidity/src/evmla/ethereal_ir/mod.rs b/crates/solidity/src/evmla/ethereal_ir/mod.rs deleted file mode 100644 index 4dd229f..0000000 --- a/crates/solidity/src/evmla/ethereal_ir/mod.rs +++ /dev/null @@ -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, -} - -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, - ) -> anyhow::Result { - 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> { - 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 revive_llvm_context::PolkaVMWriteLLVM for EtherealIR -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn declare( - &mut self, - context: &mut revive_llvm_context::PolkaVMContext, - ) -> 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) -> 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(()) - } -} diff --git a/crates/solidity/src/evmla/mod.rs b/crates/solidity/src/evmla/mod.rs deleted file mode 100644 index 93b907d..0000000 --- a/crates/solidity/src/evmla/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! The EVM legacy assembly compiling tools. - -pub mod assembly; -pub mod ethereal_ir; diff --git a/crates/solidity/src/lib.rs b/crates/solidity/src/lib.rs index ea71225..93ae7b7 100644 --- a/crates/solidity/src/lib.rs +++ b/crates/solidity/src/lib.rs @@ -2,7 +2,6 @@ pub(crate) mod build; pub(crate) mod r#const; -pub(crate) mod evmla; pub(crate) mod missing_libraries; pub(crate) mod process; pub(crate) mod project; @@ -26,7 +25,6 @@ pub use self::project::Project; pub use self::r#const::*; pub use self::solc::combined_json::contract::Contract as SolcCombinedJsonContract; pub use self::solc::combined_json::CombinedJson as SolcCombinedJson; -pub use self::solc::pipeline::Pipeline as SolcPipeline; #[cfg(not(target_os = "emscripten"))] pub use self::solc::solc_compiler::SolcCompiler; #[cfg(target_os = "emscripten")] @@ -119,7 +117,6 @@ pub fn standard_output( evm_version: Option, solc_optimizer_enabled: bool, optimizer_settings: revive_llvm_context::OptimizerSettings, - force_evmla: bool, include_metadata_hash: bool, base_path: Option, include_paths: Vec, @@ -129,7 +126,6 @@ pub fn standard_output( debug_config: revive_llvm_context::DebugConfig, ) -> anyhow::Result { let solc_version = solc.version()?; - let solc_pipeline = SolcPipeline::new(&solc_version, force_evmla); let solc_input = SolcStandardJsonInput::try_from_paths( SolcStandardJsonInputLanguage::Solidity, @@ -137,7 +133,7 @@ pub fn standard_output( input_files, libraries, remappings, - SolcStandardJsonInputSettingsSelection::new_required(solc_pipeline), + SolcStandardJsonInputSettingsSelection::new_required(), SolcStandardJsonInputSettingsOptimizer::new( solc_optimizer_enabled, None, @@ -145,7 +141,6 @@ pub fn standard_output( optimizer_settings.is_fallback_to_size_enabled(), ), None, - solc_pipeline == SolcPipeline::Yul, suppressed_warnings, )?; @@ -156,13 +151,7 @@ pub fn standard_output( .collect(); let libraries = solc_input.settings.libraries.clone().unwrap_or_default(); - let mut solc_output = solc.standard_json( - solc_input, - solc_pipeline, - base_path, - include_paths, - allow_paths, - )?; + let mut solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?; if let Some(errors) = solc_output.errors.as_deref() { let mut has_errors = false; @@ -180,13 +169,8 @@ pub fn standard_output( } } - let project = solc_output.try_to_project( - source_code_files, - libraries, - solc_pipeline, - &solc_version, - &debug_config, - )?; + let project = + solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?; let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?; @@ -198,16 +182,14 @@ pub fn standard_output( pub fn standard_json( solc: &mut T, detect_missing_libraries: bool, - force_evmla: bool, base_path: Option, include_paths: Vec, allow_paths: Option, debug_config: revive_llvm_context::DebugConfig, ) -> anyhow::Result<()> { 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 .sources .iter() @@ -225,13 +207,7 @@ pub fn standard_json( }; let libraries = solc_input.settings.libraries.clone().unwrap_or_default(); - let mut solc_output = solc.standard_json( - solc_input, - solc_pipeline, - base_path, - include_paths, - allow_paths, - )?; + let mut solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?; if let Some(errors) = solc_output.errors.as_deref() { for error in errors.iter() { @@ -242,13 +218,8 @@ pub fn standard_json( } } - let project = solc_output.try_to_project( - source_code_files, - libraries, - solc_pipeline, - &solc_version, - &debug_config, - )?; + let project = + solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?; if detect_missing_libraries { let missing_libraries = project.get_missing_libraries(); @@ -271,7 +242,6 @@ pub fn combined_json( evm_version: Option, solc_optimizer_enabled: bool, optimizer_settings: revive_llvm_context::OptimizerSettings, - force_evmla: bool, include_metadata_hash: bool, base_path: Option, include_paths: Vec, @@ -289,7 +259,6 @@ pub fn combined_json( evm_version, solc_optimizer_enabled, optimizer_settings, - force_evmla, include_metadata_hash, base_path, include_paths, diff --git a/crates/solidity/src/project/contract/ir/evmla.rs b/crates/solidity/src/project/contract/ir/evmla.rs deleted file mode 100644 index 9a1367d..0000000 --- a/crates/solidity/src/project/contract/ir/evmla.rs +++ /dev/null @@ -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 { - self.assembly.get_missing_libraries() - } -} - -impl revive_llvm_context::PolkaVMWriteLLVM for EVMLA -where - D: revive_llvm_context::PolkaVMDependency + Clone, -{ - fn declare( - &mut self, - context: &mut revive_llvm_context::PolkaVMContext, - ) -> anyhow::Result<()> { - self.assembly.declare(context) - } - - fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { - self.assembly.into_llvm(context) - } -} diff --git a/crates/solidity/src/project/contract/ir/mod.rs b/crates/solidity/src/project/contract/ir/mod.rs index a1d9f53..a584390 100644 --- a/crates/solidity/src/project/contract/ir/mod.rs +++ b/crates/solidity/src/project/contract/ir/mod.rs @@ -1,6 +1,5 @@ //! The contract source code. -pub mod evmla; pub mod llvm_ir; pub mod yul; @@ -9,11 +8,8 @@ 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; use crate::yul::parser::statement::object::Object; -use self::evmla::EVMLA; use self::llvm_ir::LLVMIR; use self::yul::Yul; @@ -25,8 +21,6 @@ use self::yul::Yul; pub enum IR { /// The Yul source code. Yul(Yul), - /// The EVM legacy assembly source code. - EVMLA(EVMLA), /// The LLVM IR source code. LLVMIR(LLVMIR), } @@ -37,11 +31,6 @@ impl IR { 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. pub fn new_llvm_ir(path: String, source: String) -> Self { Self::LLVMIR(LLVMIR::new(path, source)) @@ -51,7 +40,6 @@ impl IR { pub fn get_missing_libraries(&self) -> HashSet { match self { Self::Yul(inner) => inner.get_missing_libraries(), - Self::EVMLA(inner) => inner.get_missing_libraries(), Self::LLVMIR(_inner) => HashSet::new(), } } @@ -67,7 +55,6 @@ where ) -> anyhow::Result<()> { match self { Self::Yul(inner) => inner.declare(context), - Self::EVMLA(inner) => inner.declare(context), Self::LLVMIR(_inner) => Ok(()), } } @@ -75,7 +62,6 @@ where fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { match self { Self::Yul(inner) => inner.into_llvm(context), - Self::EVMLA(inner) => inner.into_llvm(context), Self::LLVMIR(_inner) => Ok(()), } } diff --git a/crates/solidity/src/project/contract/mod.rs b/crates/solidity/src/project/contract/mod.rs index 24d56fd..8b6e958 100644 --- a/crates/solidity/src/project/contract/mod.rs +++ b/crates/solidity/src/project/contract/mod.rs @@ -54,12 +54,10 @@ impl Contract { /// Returns the contract identifier, which is: /// - the Yul object identifier for Yul - /// - the full contract path for EVM legacy assembly /// - the module name for LLVM IR pub fn identifier(&self) -> &str { match self.ir { 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(), } } @@ -68,7 +66,6 @@ impl Contract { pub fn drain_factory_dependencies(&mut self) -> HashSet { match self.ir { 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(), } } @@ -129,10 +126,6 @@ impl Contract { IR::Yul(_) => { 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(_) => {} } diff --git a/crates/solidity/src/resolc/arguments.rs b/crates/solidity/src/resolc/arguments.rs index 01d997a..b615fa6 100644 --- a/crates/solidity/src/resolc/arguments.rs +++ b/crates/solidity/src/resolc/arguments.rs @@ -113,12 +113,6 @@ pub struct Arguments { #[structopt(long = "llvm-ir")] 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. /// The only supported value is `none` that disables appending the metadata hash. /// 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 { anyhow::bail!("Disabling the solc optimizer is not supported in Yul, LLVM IR and PolkaVM assembly modes."); } diff --git a/crates/solidity/src/resolc/main.rs b/crates/solidity/src/resolc/main.rs index a8884e2..5699510 100644 --- a/crates/solidity/src/resolc/main.rs +++ b/crates/solidity/src/resolc/main.rs @@ -157,7 +157,6 @@ fn main_inner() -> anyhow::Result<()> { revive_solidity::standard_json( &mut solc, arguments.detect_missing_libraries, - arguments.force_evmla, arguments.base_path, arguments.include_paths, arguments.allow_paths, @@ -173,7 +172,6 @@ fn main_inner() -> anyhow::Result<()> { evm_version, !arguments.disable_solc_optimizer, optimizer_settings, - arguments.force_evmla, include_metadata_hash, arguments.base_path, arguments.include_paths, @@ -193,7 +191,6 @@ fn main_inner() -> anyhow::Result<()> { evm_version, !arguments.disable_solc_optimizer, optimizer_settings, - arguments.force_evmla, include_metadata_hash, arguments.base_path, arguments.include_paths, diff --git a/crates/solidity/src/solc/mod.rs b/crates/solidity/src/solc/mod.rs index 55a47af..b0c88d6 100644 --- a/crates/solidity/src/solc/mod.rs +++ b/crates/solidity/src/solc/mod.rs @@ -1,7 +1,6 @@ //! The Solidity compiler. pub mod combined_json; -pub mod pipeline; #[cfg(not(target_os = "emscripten"))] pub mod solc_compiler; #[cfg(target_os = "emscripten")] @@ -9,35 +8,25 @@ pub mod soljson_compiler; pub mod standard_json; pub mod version; -use once_cell::sync::Lazy; -use semver::VersionReq; use std::path::Path; use std::path::PathBuf; use self::combined_json::CombinedJson; -use self::pipeline::Pipeline; use self::standard_json::input::Input as StandardJsonInput; use self::standard_json::output::Output as StandardJsonOutput; use self::version::Version; /// The first version of `solc` with the support of standard JSON interface. -pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 4, 12); - -/// The first version of `solc`, where Yul codegen is considered robust enough. -pub const FIRST_YUL_VERSION: semver::Version = semver::Version::new(0, 8, 0); +pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0); /// The first version of `solc`, where `--via-ir` codegen mode is supported. pub const FIRST_VIA_IR_VERSION: semver::Version = semver::Version::new(0, 8, 13); /// The last supported version of `solc`. pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 28); -/// `--base-path` was introduced in 0.6.9 -pub static FIRST_SUPPORTS_BASE_PATH: Lazy = - Lazy::new(|| VersionReq::parse(">=0.6.9").unwrap()); -/// `--include-path` was introduced in 0.8.8 -pub static FIRST_SUPPORTS_INCLUDE_PATH: Lazy = - Lazy::new(|| VersionReq::parse(">=0.8.8").unwrap()); +/// `--include-path` was introduced in solc `0.8.8` +pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8); /// The Solidity compiler. pub trait Compiler { @@ -45,7 +34,6 @@ pub trait Compiler { fn standard_json( &mut self, input: StandardJsonInput, - pipeline: Pipeline, base_path: Option, include_paths: Vec, allow_paths: Option, diff --git a/crates/solidity/src/solc/pipeline.rs b/crates/solidity/src/solc/pipeline.rs deleted file mode 100644 index 9b398e8..0000000 --- a/crates/solidity/src/solc/pipeline.rs +++ /dev/null @@ -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 - } - } -} diff --git a/crates/solidity/src/solc/solc_compiler.rs b/crates/solidity/src/solc/solc_compiler.rs index 44c740e..2180268 100644 --- a/crates/solidity/src/solc/solc_compiler.rs +++ b/crates/solidity/src/solc/solc_compiler.rs @@ -5,13 +5,12 @@ use std::path::Path; use std::path::PathBuf; use crate::solc::combined_json::CombinedJson; -use crate::solc::pipeline::Pipeline; use crate::solc::standard_json::input::Input as StandardJsonInput; use crate::solc::standard_json::output::Output as StandardJsonOutput; use crate::solc::version::Version; +use crate::solc::FIRST_INCLUDE_PATH_VERSION; use super::Compiler; -use crate::solc::{FIRST_SUPPORTS_BASE_PATH, FIRST_SUPPORTS_INCLUDE_PATH}; /// The Solidity compiler. pub struct SolcCompiler { @@ -47,45 +46,35 @@ impl Compiler for SolcCompiler { fn standard_json( &mut self, mut input: StandardJsonInput, - pipeline: Pipeline, base_path: Option, include_paths: Vec, allow_paths: Option, ) -> anyhow::Result { - let version = self.version()?; + let version = self.version()?.default; + + if !include_paths.is_empty() && version < FIRST_INCLUDE_PATH_VERSION { + anyhow::bail!("--include-path is not supported in solc {version}"); + } let mut command = std::process::Command::new(self.executable.as_str()); command.stdin(std::process::Stdio::piped()); command.stdout(std::process::Stdio::piped()); command.arg("--standard-json"); - if let Some(base_path) = &base_path { - if !FIRST_SUPPORTS_BASE_PATH.matches(&version.default) { - anyhow::bail!( - "--base-path not supported this version {} of solc", - &version.default - ); - } - command.arg("--base-path").arg(base_path); - } - - if !include_paths.is_empty() && !FIRST_SUPPORTS_INCLUDE_PATH.matches(&version.default) { - anyhow::bail!( - "--include-path not supported this version {} of solc", - &version.default - ); - } - for include_path in include_paths.into_iter() { command.arg("--include-path"); command.arg(include_path); } + if let Some(base_path) = base_path { + command.arg("--base-path"); + command.arg(base_path); + } if let Some(allow_paths) = allow_paths { command.arg("--allow-paths"); command.arg(allow_paths); } - input.normalize(&version.default); + input.normalize(&version); let suppressed_warnings = input.suppressed_warnings.take().unwrap_or_default(); @@ -129,7 +118,7 @@ impl Compiler for SolcCompiler { ), ) })?; - output.preprocess_ast(&version, pipeline, suppressed_warnings.as_slice())?; + output.preprocess_ast(suppressed_warnings.as_slice())?; Ok(output) } diff --git a/crates/solidity/src/solc/soljson_compiler.rs b/crates/solidity/src/solc/soljson_compiler.rs index c2472e6..c73bdce 100644 --- a/crates/solidity/src/solc/soljson_compiler.rs +++ b/crates/solidity/src/solc/soljson_compiler.rs @@ -4,7 +4,6 @@ use std::path::Path; use std::path::PathBuf; use crate::solc::combined_json::CombinedJson; -use crate::solc::pipeline::Pipeline; use crate::solc::standard_json::input::Input as StandardJsonInput; use crate::solc::standard_json::output::Output as StandardJsonOutput; use crate::solc::version::Version; @@ -29,7 +28,6 @@ impl Compiler for SoljsonCompiler { fn standard_json( &mut self, mut input: StandardJsonInput, - pipeline: Pipeline, _base_path: Option, _include_paths: Vec, _allow_paths: Option, @@ -50,7 +48,7 @@ impl Compiler for SoljsonCompiler { .unwrap_or_else(|_| String::from_utf8_lossy(out.as_bytes()).to_string()), ) })?; - output.preprocess_ast(&version, pipeline, suppressed_warnings.as_slice())?; + output.preprocess_ast(suppressed_warnings.as_slice())?; Ok(output) } diff --git a/crates/solidity/src/solc/standard_json/input/mod.rs b/crates/solidity/src/solc/standard_json/input/mod.rs index 5462ade..86c6bed 100644 --- a/crates/solidity/src/solc/standard_json/input/mod.rs +++ b/crates/solidity/src/solc/standard_json/input/mod.rs @@ -13,7 +13,6 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::Deserialize; use serde::Serialize; -use crate::solc::pipeline::Pipeline as SolcPipeline; use crate::solc::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata; use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer; use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection; @@ -40,13 +39,13 @@ pub struct Input { impl Input { /// A shortcut constructor from stdin. - pub fn try_from_stdin(solc_pipeline: SolcPipeline) -> anyhow::Result { + pub fn try_from_stdin() -> anyhow::Result { let mut input: Self = serde_json::from_reader(std::io::BufReader::new(std::io::stdin()))?; input .settings .output_selection .get_or_insert_with(SolcStandardJsonInputSettingsSelection::default) - .extend_with_required(solc_pipeline); + .extend_with_required(); Ok(input) } @@ -61,7 +60,6 @@ impl Input { output_selection: SolcStandardJsonInputSettingsSelection, optimizer: SolcStandardJsonInputSettingsOptimizer, metadata: Option, - via_ir: bool, suppressed_warnings: Option>, ) -> anyhow::Result { let mut paths: BTreeSet = paths.iter().cloned().collect(); @@ -92,7 +90,6 @@ impl Input { libraries, remappings, output_selection, - via_ir, optimizer, metadata, ), @@ -111,7 +108,6 @@ impl Input { output_selection: SolcStandardJsonInputSettingsSelection, optimizer: SolcStandardJsonInputSettingsOptimizer, metadata: Option, - via_ir: bool, suppressed_warnings: Option>, ) -> anyhow::Result { #[cfg(feature = "parallel")] @@ -131,7 +127,6 @@ impl Input { libraries, remappings, output_selection, - via_ir, optimizer, metadata, ), diff --git a/crates/solidity/src/solc/standard_json/input/settings/mod.rs b/crates/solidity/src/solc/standard_json/input/settings/mod.rs index a089ac2..dff5a83 100644 --- a/crates/solidity/src/solc/standard_json/input/settings/mod.rs +++ b/crates/solidity/src/solc/standard_json/input/settings/mod.rs @@ -51,7 +51,6 @@ impl Settings { libraries: BTreeMap>, remappings: Option>, output_selection: Selection, - via_ir: bool, optimizer: Optimizer, metadata: Option, ) -> Self { @@ -60,9 +59,9 @@ impl Settings { libraries: Some(libraries), remappings, output_selection: Some(output_selection), - via_ir: if via_ir { Some(true) } else { None }, optimizer, metadata, + via_ir: Some(true), } } diff --git a/crates/solidity/src/solc/standard_json/input/settings/selection/file/flag.rs b/crates/solidity/src/solc/standard_json/input/settings/selection/file/flag.rs index ad6efc6..bfcb698 100644 --- a/crates/solidity/src/solc/standard_json/input/settings/selection/file/flag.rs +++ b/crates/solidity/src/solc/standard_json/input/settings/selection/file/flag.rs @@ -3,8 +3,6 @@ use serde::Deserialize; use serde::Serialize; -use crate::solc::pipeline::Pipeline as SolcPipeline; - /// The `solc --standard-json` expected output selection flag. #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] #[allow(non_camel_case_types)] @@ -46,15 +44,6 @@ pub enum Flag { Assembly, } -impl From for Flag { - fn from(pipeline: SolcPipeline) -> Self { - match pipeline { - SolcPipeline::Yul => Self::Yul, - SolcPipeline::EVMLA => Self::EVMLA, - } - } -} - impl std::fmt::Display for Flag { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/crates/solidity/src/solc/standard_json/input/settings/selection/file/mod.rs b/crates/solidity/src/solc/standard_json/input/settings/selection/file/mod.rs index df232c3..a960ca9 100644 --- a/crates/solidity/src/solc/standard_json/input/settings/selection/file/mod.rs +++ b/crates/solidity/src/solc/standard_json/input/settings/selection/file/mod.rs @@ -7,8 +7,6 @@ use std::collections::HashSet; use serde::Deserialize; use serde::Serialize; -use crate::solc::pipeline::Pipeline as SolcPipeline; - use self::flag::Flag as SelectionFlag; /// The `solc --standard-json` output file selection. @@ -24,7 +22,7 @@ pub struct File { impl File { /// Creates the selection required by our compilation process. - pub fn new_required(pipeline: SolcPipeline) -> Self { + pub fn new_required() -> Self { Self { per_file: Some(HashSet::from_iter([SelectionFlag::AST])), per_contract: Some(HashSet::from_iter([ @@ -32,14 +30,14 @@ impl File { SelectionFlag::EVMDBC, SelectionFlag::MethodIdentifiers, SelectionFlag::Metadata, - SelectionFlag::from(pipeline), + SelectionFlag::Yul, ])), } } /// Extends the user's output selection with flag required by our compilation process. - pub fn extend_with_required(&mut self, pipeline: SolcPipeline) -> &mut Self { - let required = Self::new_required(pipeline); + pub fn extend_with_required(&mut self) -> &mut Self { + let required = Self::new_required(); self.per_file .get_or_insert_with(HashSet::default) diff --git a/crates/solidity/src/solc/standard_json/input/settings/selection/mod.rs b/crates/solidity/src/solc/standard_json/input/settings/selection/mod.rs index 13d316f..d332f15 100644 --- a/crates/solidity/src/solc/standard_json/input/settings/selection/mod.rs +++ b/crates/solidity/src/solc/standard_json/input/settings/selection/mod.rs @@ -5,8 +5,6 @@ pub mod file; use serde::Deserialize; use serde::Serialize; -use crate::solc::pipeline::Pipeline as SolcPipeline; - use self::file::File as FileSelection; /// The `solc --standard-json` output selection. @@ -19,17 +17,17 @@ pub struct Selection { impl Selection { /// Creates the selection required by our compilation process. - pub fn new_required(pipeline: SolcPipeline) -> Self { + pub fn new_required() -> Self { Self { - all: Some(FileSelection::new_required(pipeline)), + all: Some(FileSelection::new_required()), } } /// Extends the user's output selection with flag required by our compilation process. - pub fn extend_with_required(&mut self, pipeline: SolcPipeline) -> &mut Self { + pub fn extend_with_required(&mut self) -> &mut Self { self.all - .get_or_insert_with(|| FileSelection::new_required(pipeline)) - .extend_with_required(pipeline); + .get_or_insert_with(FileSelection::new_required) + .extend_with_required(); self } } diff --git a/crates/solidity/src/solc/standard_json/output/contract/evm/extra_metadata/mod.rs b/crates/solidity/src/solc/standard_json/output/contract/evm/extra_metadata/mod.rs deleted file mode 100644 index f734419..0000000 --- a/crates/solidity/src/solc/standard_json/output/contract/evm/extra_metadata/mod.rs +++ /dev/null @@ -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, -} - -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 - } -} diff --git a/crates/solidity/src/solc/standard_json/output/contract/evm/extra_metadata/recursive_function.rs b/crates/solidity/src/solc/standard_json/output/contract/evm/extra_metadata/recursive_function.rs deleted file mode 100644 index 188060f..0000000 --- a/crates/solidity/src/solc/standard_json/output/contract/evm/extra_metadata/recursive_function.rs +++ /dev/null @@ -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, - /// The runtime code function block tag. - pub runtime_tag: Option, - /// The number of input arguments. - #[serde(rename = "totalParamSize")] - pub input_size: usize, - /// The number of output arguments. - #[serde(rename = "totalRetParamSize")] - pub output_size: usize, -} diff --git a/crates/solidity/src/solc/standard_json/output/contract/evm/mod.rs b/crates/solidity/src/solc/standard_json/output/contract/evm/mod.rs index c5613cf..6e57bdd 100644 --- a/crates/solidity/src/solc/standard_json/output/contract/evm/mod.rs +++ b/crates/solidity/src/solc/standard_json/output/contract/evm/mod.rs @@ -1,27 +1,20 @@ //! The `solc --standard-json` output contract EVM data. pub mod bytecode; -pub mod extra_metadata; use std::collections::BTreeMap; use serde::Deserialize; use serde::Serialize; -use crate::evmla::assembly::Assembly; - use self::bytecode::Bytecode; use self::bytecode::DeployedBytecode; -use self::extra_metadata::ExtraMetadata; /// The `solc --standard-json` output contract EVM data. /// It is replaced by PolkaVM data after compiling. #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct EVM { - /// The contract EVM legacy assembly code. - #[serde(rename = "legacyAssembly", skip_serializing_if = "Option::is_none")] - pub assembly: Option, /// The contract PolkaVM assembly code. #[serde(rename = "assembly", skip_serializing_if = "Option::is_none")] pub assembly_text: Option, @@ -37,9 +30,6 @@ pub struct EVM { /// The contract function signatures. #[serde(default, skip_serializing_if = "Option::is_none")] pub method_identifiers: Option>, - /// The extra EVMLA metadata. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub extra_metadata: Option, } impl EVM { diff --git a/crates/solidity/src/solc/standard_json/output/error/mod.rs b/crates/solidity/src/solc/standard_json/output/error/mod.rs index f9442e2..065e160 100644 --- a/crates/solidity/src/solc/standard_json/output/error/mod.rs +++ b/crates/solidity/src/solc/standard_json/output/error/mod.rs @@ -125,26 +125,6 @@ impl Error { } } - /// Returns the internal function pointer usage error. - pub fn message_internal_function_pointer(src: Option<&str>) -> Self { - let message = r#" -┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Error: Internal function pointers are not supported in EVM legacy assembly pipeline. │ -│ Please use the Yul IR codegen instead. │ -└──────────────────────────────────────────────────────────────────────────────────────────────────┘"# - .to_owned(); - - Self { - component: "general".to_owned(), - error_code: None, - formatted_message: message.clone(), - message, - severity: "error".to_owned(), - source_location: src.map(SourceLocation::from_str).and_then(Result::ok), - r#type: "Error".to_owned(), - } - } - /// Appends the contract path to the message.. pub fn push_contract_path(&mut self, path: &str) { self.formatted_message diff --git a/crates/solidity/src/solc/standard_json/output/mod.rs b/crates/solidity/src/solc/standard_json/output/mod.rs index 751cdcd..5ea4100 100644 --- a/crates/solidity/src/solc/standard_json/output/mod.rs +++ b/crates/solidity/src/solc/standard_json/output/mod.rs @@ -10,12 +10,9 @@ use serde::Deserialize; use serde::Serialize; use sha3::Digest; -use crate::evmla::assembly::instruction::Instruction; -use crate::evmla::assembly::Assembly; use crate::project::contract::ir::IR as ProjectContractIR; use crate::project::contract::Contract as ProjectContract; use crate::project::Project; -use crate::solc::pipeline::Pipeline as SolcPipeline; use crate::solc::version::Version as SolcVersion; use crate::warning::Warning; use crate::yul::lexer::Lexer; @@ -53,14 +50,9 @@ impl Output { &mut self, source_code_files: BTreeMap, libraries: BTreeMap>, - pipeline: SolcPipeline, solc_version: &SolcVersion, debug_config: &revive_llvm_context::DebugConfig, ) -> anyhow::Result { - if let SolcPipeline::EVMLA = pipeline { - self.preprocess_dependencies()?; - } - let files = match self.contracts.as_ref() { Some(files) => files, None => match &self.errors { @@ -76,38 +68,22 @@ impl Output { for (name, contract) in contracts.iter() { let full_path = format!("{path}:{name}"); - let source = match pipeline { - SolcPipeline::Yul => { - let ir_optimized = match contract.ir_optimized.to_owned() { - Some(ir_optimized) => ir_optimized, - None => continue, - }; - if ir_optimized.is_empty() { - continue; - } - - debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?; - - let mut lexer = Lexer::new(ir_optimized.to_owned()); - let object = Object::parse(&mut lexer, None).map_err(|error| { - anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error) - })?; - - ProjectContractIR::new_yul(ir_optimized.to_owned(), object) - } - SolcPipeline::EVMLA => { - let evm = contract.evm.as_ref(); - let assembly = match evm.and_then(|evm| evm.assembly.to_owned()) { - Some(assembly) => assembly.to_owned(), - None => continue, - }; - let extra_metadata = evm - .and_then(|evm| evm.extra_metadata.to_owned()) - .unwrap_or_default(); - - ProjectContractIR::new_evmla(assembly, extra_metadata) - } + let ir_optimized = match contract.ir_optimized.to_owned() { + Some(ir_optimized) => ir_optimized, + None => continue, }; + if ir_optimized.is_empty() { + continue; + } + + debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?; + + let mut lexer = Lexer::new(ir_optimized.to_owned()); + let object = Object::parse(&mut lexer, None).map_err(|error| { + anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error) + })?; + + let source = ProjectContractIR::new_yul(ir_optimized.to_owned(), object); let source_code = source_code_files .get(path.as_str()) @@ -133,12 +109,7 @@ impl Output { } /// Traverses the AST and returns the list of additional errors and warnings. - pub fn preprocess_ast( - &mut self, - version: &SolcVersion, - pipeline: SolcPipeline, - suppressed_warnings: &[Warning], - ) -> anyhow::Result<()> { + pub fn preprocess_ast(&mut self, suppressed_warnings: &[Warning]) -> anyhow::Result<()> { let sources = match self.sources.as_ref() { Some(sources) => sources, None => return Ok(()), @@ -147,8 +118,7 @@ impl Output { let mut messages = Vec::new(); for (path, source) in sources.iter() { if let Some(ast) = source.ast.as_ref() { - let mut polkavm_messages = - Source::get_messages(ast, version, pipeline, suppressed_warnings); + let mut polkavm_messages = Source::get_messages(ast, suppressed_warnings); for message in polkavm_messages.iter_mut() { message.push_contract_path(path.as_str()); } @@ -165,83 +135,4 @@ impl Output { Ok(()) } - - /// The pass, which replaces with dependency indexes with actual data. - fn preprocess_dependencies(&mut self) -> anyhow::Result<()> { - let files = match self.contracts.as_mut() { - Some(files) => files, - None => return Ok(()), - }; - let mut hash_path_mapping = BTreeMap::new(); - - for (path, contracts) in files.iter() { - for (name, contract) in contracts.iter() { - let full_path = format!("{path}:{name}"); - let hash = match contract - .evm - .as_ref() - .and_then(|evm| evm.assembly.as_ref()) - .map(|assembly| assembly.keccak256()) - { - Some(hash) => hash, - None => continue, - }; - - hash_path_mapping.insert(hash, full_path); - } - } - - for (path, contracts) in files.iter_mut() { - for (name, contract) in contracts.iter_mut() { - let assembly = match contract.evm.as_mut().and_then(|evm| evm.assembly.as_mut()) { - Some(assembly) => assembly, - None => continue, - }; - - let full_path = format!("{path}:{name}"); - Self::preprocess_dependency_level( - full_path.as_str(), - assembly, - &hash_path_mapping, - )?; - } - } - - Ok(()) - } - - /// Preprocesses an assembly JSON structure dependency data map. - fn preprocess_dependency_level( - full_path: &str, - assembly: &mut Assembly, - hash_path_mapping: &BTreeMap, - ) -> 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(()) - } } diff --git a/crates/solidity/src/solc/standard_json/output/source.rs b/crates/solidity/src/solc/standard_json/output/source.rs index 1424b5b..97b2e14 100644 --- a/crates/solidity/src/solc/standard_json/output/source.rs +++ b/crates/solidity/src/solc/standard_json/output/source.rs @@ -3,9 +3,7 @@ use serde::Deserialize; use serde::Serialize; -use crate::solc::pipeline::Pipeline as SolcPipeline; use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputError; -use crate::solc::version::Version as SolcVersion; use crate::warning::Warning; /// The `solc --standard-json` output source. @@ -132,37 +130,9 @@ impl Source { )) } - /// Checks the AST node for the internal function pointers value usage. - pub fn check_internal_function_pointer( - ast: &serde_json::Value, - ) -> Option { - let ast = ast.as_object()?; - - if ast.get("nodeType")?.as_str()? != "VariableDeclaration" { - return None; - } - - let type_descriptions = ast.get("typeDescriptions")?.as_object()?; - if !type_descriptions - .get("typeIdentifier")? - .as_str()? - .contains("function_internal") - { - return None; - } - - Some( - SolcStandardJsonOutputError::message_internal_function_pointer( - ast.get("src")?.as_str(), - ), - ) - } - /// Returns the list of messages for some specific parts of the AST. pub fn get_messages( ast: &serde_json::Value, - version: &SolcVersion, - pipeline: SolcPipeline, suppressed_warnings: &[Warning], ) -> Vec { let mut messages = Vec::new(); @@ -189,31 +159,16 @@ impl Source { messages.push(message); } } - if SolcPipeline::EVMLA == pipeline && version.l2_revision.is_none() { - if let Some(message) = Self::check_internal_function_pointer(ast) { - messages.push(message); - } - } match ast { serde_json::Value::Array(array) => { for element in array.iter() { - messages.extend(Self::get_messages( - element, - version, - pipeline, - suppressed_warnings, - )); + messages.extend(Self::get_messages(element, suppressed_warnings)); } } serde_json::Value::Object(object) => { for (_key, value) in object.iter() { - messages.extend(Self::get_messages( - value, - version, - pipeline, - suppressed_warnings, - )); + messages.extend(Self::get_messages(value, suppressed_warnings)); } } _ => {} diff --git a/crates/solidity/src/test_utils.rs b/crates/solidity/src/test_utils.rs index 2ef5c86..ab86348 100644 --- a/crates/solidity/src/test_utils.rs +++ b/crates/solidity/src/test_utils.rs @@ -8,7 +8,6 @@ use std::sync::Mutex; use once_cell::sync::Lazy; use crate::project::Project; -use crate::solc::pipeline::Pipeline as SolcPipeline; use crate::solc::solc_compiler::SolcCompiler; use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer; use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection; @@ -31,7 +30,6 @@ const DEBUG_CONFIG: revive_llvm_context::DebugConfig = struct CachedBlob { contract_name: String, solc_optimizer_enabled: bool, - pipeline: SolcPipeline, } /// Checks if the required executables are present in `${PATH}`. @@ -54,17 +52,9 @@ pub fn build_solidity( sources: BTreeMap, libraries: BTreeMap>, remappings: Option>, - pipeline: SolcPipeline, optimizer_settings: revive_llvm_context::OptimizerSettings, ) -> anyhow::Result { - build_solidity_with_options( - sources, - libraries, - remappings, - pipeline, - optimizer_settings, - true, - ) + build_solidity_with_options(sources, libraries, remappings, optimizer_settings, true) } /// Builds the Solidity project and returns the standard JSON output. @@ -74,7 +64,6 @@ pub fn build_solidity_with_options( sources: BTreeMap, libraries: BTreeMap>, remappings: Option>, - pipeline: SolcPipeline, optimizer_settings: revive_llvm_context::OptimizerSettings, solc_optimizer_enabled: bool, ) -> anyhow::Result { @@ -93,7 +82,7 @@ pub fn build_solidity_with_options( sources.clone(), libraries.clone(), remappings, - SolcStandardJsonInputSettingsSelection::new_required(pipeline), + SolcStandardJsonInputSettingsSelection::new_required(), SolcStandardJsonInputSettingsOptimizer::new( solc_optimizer_enabled, None, @@ -101,14 +90,12 @@ pub fn build_solidity_with_options( false, ), None, - pipeline == SolcPipeline::Yul, None, )?; - let mut output = solc.standard_json(input, pipeline, None, vec![], None)?; + let mut output = solc.standard_json(input, None, vec![], None)?; - let project = - output.try_to_project(sources, libraries, pipeline, &solc_version, &DEBUG_CONFIG)?; + let project = output.try_to_project(sources, libraries, &solc_version, &DEBUG_CONFIG)?; let build: crate::Build = project.compile(optimizer_settings, false, DEBUG_CONFIG)?; build.write_to_standard_json(&mut output, &solc_version)?; @@ -121,7 +108,6 @@ pub fn build_solidity_with_options_evm( sources: BTreeMap, libraries: BTreeMap>, remappings: Option>, - pipeline: SolcPipeline, solc_optimizer_enabled: bool, ) -> anyhow::Result> { check_dependencies(); @@ -139,7 +125,7 @@ pub fn build_solidity_with_options_evm( sources.clone(), libraries.clone(), remappings, - SolcStandardJsonInputSettingsSelection::new_required(pipeline), + SolcStandardJsonInputSettingsSelection::new_required(), SolcStandardJsonInputSettingsOptimizer::new( solc_optimizer_enabled, None, @@ -147,11 +133,10 @@ pub fn build_solidity_with_options_evm( false, ), None, - pipeline == SolcPipeline::Yul, 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(); 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( sources: BTreeMap, libraries: BTreeMap>, - pipeline: SolcPipeline, ) -> anyhow::Result { check_dependencies(); @@ -193,17 +177,15 @@ pub fn build_solidity_and_detect_missing_libraries( sources.clone(), libraries.clone(), None, - SolcStandardJsonInputSettingsSelection::new_required(pipeline), + SolcStandardJsonInputSettingsSelection::new_required(), SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false), None, - pipeline == SolcPipeline::Yul, None, )?; - let mut output = solc.standard_json(input, pipeline, None, vec![], None)?; + let mut output = solc.standard_json(input, None, vec![], None)?; - let project = - output.try_to_project(sources, libraries, pipeline, &solc_version, &DEBUG_CONFIG)?; + let project = output.try_to_project(sources, libraries, &solc_version, &DEBUG_CONFIG)?; let missing_libraries = project.get_missing_libraries(); missing_libraries.write_to_standard_json(&mut output, &solc.version()?)?; @@ -234,7 +216,6 @@ pub fn check_solidity_warning( source_code: &str, warning_substring: &str, libraries: BTreeMap>, - pipeline: SolcPipeline, skip_for_revive_edition: bool, suppressed_warnings: Option>, ) -> anyhow::Result { @@ -253,14 +234,13 @@ pub fn check_solidity_warning( sources.clone(), libraries, None, - SolcStandardJsonInputSettingsSelection::new_required(pipeline), + SolcStandardJsonInputSettingsSelection::new_required(), SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false), None, - pipeline == SolcPipeline::Yul, 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 .errors .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`. /// The `solc` optimizer will be enabled pub fn compile_blob(contract_name: &str, source_code: &str) -> Vec { - 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`. @@ -298,10 +278,8 @@ fn compile_evm( solc_optimizer_enabled: bool, runtime: bool, ) -> Vec { - let pipeline = SolcPipeline::Yul; let id = CachedBlob { contract_name: contract_name.to_owned(), - pipeline, solc_optimizer_enabled, }; @@ -319,7 +297,6 @@ fn compile_evm( [(file_name.into(), source_code.into())].into(), Default::default(), None, - pipeline, solc_optimizer_enabled, ) .expect("source should compile"); @@ -343,12 +320,10 @@ pub fn compile_blob_with_options( contract_name: &str, source_code: &str, solc_optimizer_enabled: bool, - pipeline: SolcPipeline, ) -> Vec { let id = CachedBlob { contract_name: contract_name.to_owned(), solc_optimizer_enabled, - pipeline, }; 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(), Default::default(), None, - pipeline, revive_llvm_context::OptimizerSettings::cycles(), solc_optimizer_enabled, ) diff --git a/crates/solidity/src/tests/cli-tests/junit.xml b/crates/solidity/src/tests/cli-tests/junit.xml new file mode 100644 index 0000000..7c013eb --- /dev/null +++ b/crates/solidity/src/tests/cli-tests/junit.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/crates/solidity/src/tests/combined-json.tests.ts b/crates/solidity/src/tests/combined-json.tests.ts new file mode 100644 index 0000000..6dc1b25 --- /dev/null +++ b/crates/solidity/src/tests/combined-json.tests.ts @@ -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); + }); + }); + } +}); diff --git a/crates/solidity/src/tests/factory_dependency.rs b/crates/solidity/src/tests/factory_dependency.rs index 2cae2c0..3788672 100644 --- a/crates/solidity/src/tests/factory_dependency.rs +++ b/crates/solidity/src/tests/factory_dependency.rs @@ -4,8 +4,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; - pub const MAIN_CODE: &str = r#" // SPDX-License-Identifier: MIT @@ -51,7 +49,6 @@ fn default() { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .expect("Build failure"); diff --git a/crates/solidity/src/tests/ir_artifacts.rs b/crates/solidity/src/tests/ir_artifacts.rs index 7e01cd5..d5be735 100644 --- a/crates/solidity/src/tests/ir_artifacts.rs +++ b/crates/solidity/src/tests/ir_artifacts.rs @@ -5,8 +5,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; - #[test] fn yul() { let source_code = r#" @@ -27,7 +25,6 @@ contract Test { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .expect("Test failure"); @@ -45,75 +42,4 @@ contract Test { .is_some(), "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", - ); } diff --git a/crates/solidity/src/tests/libraries.rs b/crates/solidity/src/tests/libraries.rs index 75b573f..0178602 100644 --- a/crates/solidity/src/tests/libraries.rs +++ b/crates/solidity/src/tests/libraries.rs @@ -4,8 +4,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; - pub const LIBRARY_TEST_SOURCE: &str = r#" // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -38,29 +36,24 @@ fn not_specified() { let mut sources = BTreeMap::new(); sources.insert("test.sol".to_owned(), LIBRARY_TEST_SOURCE.to_owned()); - for pipeline in [SolcPipeline::EVMLA, SolcPipeline::Yul] { - let output = super::build_solidity_and_detect_missing_libraries( - sources.clone(), - BTreeMap::new(), - pipeline, - ) - .expect("Test failure"); - assert!( - output - .contracts - .as_ref() - .expect("Always exists") - .get("test.sol") - .expect("Always exists") - .get("SimpleContract") - .expect("Always exists") - .missing_libraries - .as_ref() - .expect("Always exists") - .contains("test.sol:SimpleLibrary"), - "Missing library not detected" - ); - } + let output = + super::build_solidity_and_detect_missing_libraries(sources.clone(), BTreeMap::new()) + .expect("Test failure"); + assert!( + output + .contracts + .as_ref() + .expect("Always exists") + .get("test.sol") + .expect("Always exists") + .get("SimpleContract") + .expect("Always exists") + .missing_libraries + .as_ref() + .expect("Always exists") + .contains("test.sol:SimpleLibrary"), + "Missing library not detected" + ); } #[test] @@ -75,28 +68,23 @@ fn specified() { .entry("SimpleLibrary".to_string()) .or_insert("0x00000000000000000000000000000000DEADBEEF".to_string()); - for pipeline in [SolcPipeline::EVMLA, SolcPipeline::Yul] { - let output = super::build_solidity_and_detect_missing_libraries( - sources.clone(), - libraries.clone(), - pipeline, - ) - .expect("Test failure"); - assert!( - output - .contracts - .as_ref() - .expect("Always exists") - .get("test.sol") - .expect("Always exists") - .get("SimpleContract") - .expect("Always exists") - .missing_libraries - .as_ref() - .cloned() - .unwrap_or_default() - .is_empty(), - "The list of missing libraries must be empty" - ); - } + let output = + super::build_solidity_and_detect_missing_libraries(sources.clone(), libraries.clone()) + .expect("Test failure"); + assert!( + output + .contracts + .as_ref() + .expect("Always exists") + .get("test.sol") + .expect("Always exists") + .get("SimpleContract") + .expect("Always exists") + .missing_libraries + .as_ref() + .cloned() + .unwrap_or_default() + .is_empty(), + "The list of missing libraries must be empty" + ); } diff --git a/crates/solidity/src/tests/messages.rs b/crates/solidity/src/tests/messages.rs index bcadcf1..1ddd1b1 100644 --- a/crates/solidity/src/tests/messages.rs +++ b/crates/solidity/src/tests/messages.rs @@ -4,7 +4,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; use crate::warning::Warning; pub const ECRECOVER_TEST_SOURCE: &str = r#" @@ -30,7 +29,6 @@ fn ecrecover() { ECRECOVER_TEST_SOURCE, "Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.", BTreeMap::new(), - SolcPipeline::Yul, false, None, ).expect("Test failure") @@ -44,7 +42,6 @@ fn ecrecover_suppressed() { ECRECOVER_TEST_SOURCE, "Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.", BTreeMap::new(), - SolcPipeline::Yul, false, Some(vec![Warning::EcRecover]), ).expect("Test failure") @@ -76,7 +73,6 @@ fn send() { SEND_TEST_SOURCE, "Warning: It looks like you are using '
.send/transfer()' without providing", BTreeMap::new(), - SolcPipeline::Yul, false, None, ).expect("Test failure") @@ -90,7 +86,6 @@ fn send_suppressed() { SEND_TEST_SOURCE, "Warning: It looks like you are using '
.send/transfer()' without providing", BTreeMap::new(), - SolcPipeline::Yul, false, Some(vec![Warning::SendTransfer]), ).expect("Test failure") @@ -121,7 +116,6 @@ fn transfer() { TRANSFER_TEST_SOURCE, "Warning: It looks like you are using '
.send/transfer()' without providing", BTreeMap::new(), - SolcPipeline::Yul, false, None, ).expect("Test failure") @@ -135,7 +129,6 @@ fn transfer_suppressed() { TRANSFER_TEST_SOURCE, "Warning: It looks like you are using '
.send/transfer()' without providing", BTreeMap::new(), - SolcPipeline::Yul, false, Some(vec![Warning::SendTransfer]), ).expect("Test failure") @@ -163,7 +156,6 @@ fn extcodesize() { EXTCODESIZE_TEST_SOURCE, "Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,", BTreeMap::new(), - SolcPipeline::Yul, false, None, ) @@ -176,7 +168,6 @@ fn extcodesize_suppressed() { EXTCODESIZE_TEST_SOURCE, "Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,", BTreeMap::new(), - SolcPipeline::Yul, false, Some(vec![Warning::ExtCodeSize]), ) @@ -200,7 +191,6 @@ fn tx_origin() { TX_ORIGIN_TEST_SOURCE, "Warning: You are checking for 'tx.origin' in your code, which might lead to", BTreeMap::new(), - SolcPipeline::Yul, false, None, ) @@ -213,7 +203,6 @@ fn tx_origin_suppressed() { TX_ORIGIN_TEST_SOURCE, "Warning: You are checking for 'tx.origin' in your code, which might lead to", BTreeMap::new(), - SolcPipeline::Yul, false, Some(vec![Warning::TxOrigin]), ) @@ -244,7 +233,6 @@ fn tx_origin_assembly() { TX_ORIGIN_ASSEMBLY_TEST_SOURCE, "Warning: You are checking for 'tx.origin' in your code, which might lead to", BTreeMap::new(), - SolcPipeline::Yul, false, None, ) @@ -257,136 +245,8 @@ fn tx_origin_assembly_suppressed() { TX_ORIGIN_ASSEMBLY_TEST_SOURCE, "Warning: You are checking for 'tx.origin' in your code, which might lead to", BTreeMap::new(), - SolcPipeline::Yul, false, Some(vec![Warning::TxOrigin]), ) .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")); -} diff --git a/crates/solidity/src/tests/optimizer.rs b/crates/solidity/src/tests/optimizer.rs index 78abb4b..aa58936 100644 --- a/crates/solidity/src/tests/optimizer.rs +++ b/crates/solidity/src/tests/optimizer.rs @@ -4,8 +4,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; - pub const SOURCE_CODE: &str = r#" // SPDX-License-Identifier: MIT @@ -54,7 +52,6 @@ fn optimizer() { sources.clone(), BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::none(), ) .expect("Build failure"); @@ -62,7 +59,6 @@ fn optimizer() { sources.clone(), BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .expect("Build failure"); @@ -70,7 +66,6 @@ fn optimizer() { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::size(), ) .expect("Build failure"); diff --git a/crates/solidity/src/tests/remappings.rs b/crates/solidity/src/tests/remappings.rs index b34d76c..15dc31e 100644 --- a/crates/solidity/src/tests/remappings.rs +++ b/crates/solidity/src/tests/remappings.rs @@ -5,8 +5,6 @@ use std::collections::BTreeMap; use std::collections::BTreeSet; -use crate::solc::pipeline::Pipeline as SolcPipeline; - pub const CALLEE_TEST_SOURCE: &str = r#" // SPDX-License-Identifier: MIT @@ -46,7 +44,6 @@ fn default() { sources, BTreeMap::new(), Some(remappings), - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .expect("Test failure"); diff --git a/crates/solidity/src/tests/runtime_code.rs b/crates/solidity/src/tests/runtime_code.rs index 65dfe0e..6080311 100644 --- a/crates/solidity/src/tests/runtime_code.rs +++ b/crates/solidity/src/tests/runtime_code.rs @@ -4,8 +4,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; - #[test] #[should_panic(expected = "runtimeCode is not supported")] fn default() { @@ -29,7 +27,6 @@ contract Test { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .expect("Test failure"); diff --git a/crates/solidity/src/tests/unsupported_opcodes.rs b/crates/solidity/src/tests/unsupported_opcodes.rs index ec72436..b6479a0 100644 --- a/crates/solidity/src/tests/unsupported_opcodes.rs +++ b/crates/solidity/src/tests/unsupported_opcodes.rs @@ -4,8 +4,6 @@ use std::collections::BTreeMap; -use crate::solc::pipeline::Pipeline as SolcPipeline; - #[test] #[should_panic(expected = "The `CODECOPY` instruction is not supported")] fn codecopy_yul_runtime() { @@ -34,7 +32,6 @@ contract FixedCodeCopy { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .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] #[should_panic(expected = "The `CALLCODE` instruction is not supported")] fn callcode_yul() { @@ -89,7 +70,6 @@ fn callcode_yul() { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .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] #[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")] fn extcodecopy_yul() { @@ -163,7 +127,6 @@ fn extcodecopy_yul() { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .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] #[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")] fn selfdestruct_yul() { @@ -213,7 +160,6 @@ fn selfdestruct_yul() { sources, BTreeMap::new(), None, - SolcPipeline::Yul, revive_llvm_context::OptimizerSettings::cycles(), ) .expect("Test failure");