mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-10-31 07:59:52 +00:00
Separate compilation and linker phases (#376)
Separate between compilation and linker phases to allow deploy time linking and back-porting era compiler changes to fix #91. Unlinked contract binaries (caused by missing libraries or missing factory dependencies in turn) are emitted as raw ELF object. Few drive by fixes: - #98 - A compiler panic on missing libraries definitions. - Fixes some incosistent type forwarding in JSON output (empty string vs. null object). - Remove the unused fallback for size optimization setting. - Remove the broken `--lvm-ir` mode. - CI workflow fixes. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com> Signed-off-by: xermicus <bigcyrill@hotmail.com> Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
1 parent
13faedf08a
commit
94ec34c4d5
169 files changed
+6288
-5206
No files matched your search
@@ -0,0 +1,70 @@
|
||||
//! The Solidity compiler unit tests for factory dependencies.
|
||||
|
||||
use crate::test_utils::{build_solidity, sources};
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let caller_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
import "./callable.sol";
|
||||
|
||||
contract Main {
|
||||
function main() external returns(uint256) {
|
||||
Callable callable = new Callable();
|
||||
|
||||
callable.set(10);
|
||||
return callable.get();
|
||||
}
|
||||
}"#;
|
||||
|
||||
let callee_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
contract Callable {
|
||||
uint256 value;
|
||||
|
||||
function set(uint256 x) external {
|
||||
value = x;
|
||||
}
|
||||
|
||||
function get() external view returns(uint256) {
|
||||
return value;
|
||||
}
|
||||
}"#;
|
||||
|
||||
let output = build_solidity(sources(&[
|
||||
("main.sol", caller_code),
|
||||
("callable.sol", callee_code),
|
||||
]))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
output
|
||||
.contracts
|
||||
.get("main.sol")
|
||||
.expect("Missing file `main.sol`")
|
||||
.get("Main")
|
||||
.expect("Missing contract `main.sol:Main`")
|
||||
.factory_dependencies
|
||||
.len(),
|
||||
1,
|
||||
"Expected 1 factory dependency in `main.sol:Main`"
|
||||
);
|
||||
assert_eq!(
|
||||
output
|
||||
.contracts
|
||||
.get("callable.sol")
|
||||
.expect("Missing file `callable.sol`")
|
||||
.get("Callable")
|
||||
.expect("Missing contract `callable.sol:Callable`")
|
||||
.factory_dependencies
|
||||
.len(),
|
||||
0,
|
||||
"Expected 0 factory dependencies in `callable.sol:Callable`"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//! The Solidity compiler unit tests for IR artifacts.
|
||||
//! The tests check if the IR artifacts are kept in the final output.
|
||||
|
||||
use crate::test_utils::{build_solidity, sources};
|
||||
|
||||
#[test]
|
||||
fn yul() {
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract Test {
|
||||
function main() public view returns (uint) {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let build = build_solidity(sources(&[("test.sol", code)])).expect("Test failure");
|
||||
|
||||
assert!(
|
||||
!build
|
||||
.contracts
|
||||
.get("test.sol")
|
||||
.expect("Always exists")
|
||||
.get("Test")
|
||||
.expect("Always exists")
|
||||
.ir_optimized
|
||||
.is_empty(),
|
||||
"Yul IR is missing"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//! The Solidity compiler unit tests for libraries.
|
||||
|
||||
use revive_solc_json_interface::SolcStandardJsonInputSettingsLibraries;
|
||||
|
||||
use crate::test_utils::build_solidity_and_detect_missing_libraries;
|
||||
|
||||
pub const CODE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
// A simple library with at least one external method
|
||||
library SimpleLibrary {
|
||||
function add(uint256 a, uint256 b) external pure returns (uint256) {
|
||||
return a + b;
|
||||
}
|
||||
}
|
||||
|
||||
// A contract calling that library
|
||||
contract SimpleContract {
|
||||
using SimpleLibrary for uint256;
|
||||
|
||||
function performAlgorithm(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
uint sum = 0;
|
||||
if (a > b) {
|
||||
while (true) {
|
||||
sum += a.add(b);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn not_specified() {
|
||||
let output =
|
||||
build_solidity_and_detect_missing_libraries(&[("test.sol", CODE)], Default::default())
|
||||
.unwrap();
|
||||
assert!(
|
||||
output
|
||||
.contracts
|
||||
.get("test.sol")
|
||||
.expect("Always exists")
|
||||
.get("SimpleContract")
|
||||
.expect("Always exists")
|
||||
.missing_libraries
|
||||
.contains("test.sol:SimpleLibrary"),
|
||||
"Missing library not detected"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn specified() {
|
||||
let mut libraries = SolcStandardJsonInputSettingsLibraries::default();
|
||||
libraries
|
||||
.as_inner_mut()
|
||||
.entry("test.sol".to_string())
|
||||
.or_default()
|
||||
.entry("SimpleLibrary".to_string())
|
||||
.or_insert("0x00000000000000000000000000000000DEADBEEF".to_string());
|
||||
|
||||
let output =
|
||||
build_solidity_and_detect_missing_libraries(&[("test.sol", CODE)], libraries.clone())
|
||||
.unwrap();
|
||||
assert!(
|
||||
output
|
||||
.contracts
|
||||
.get("test.sol")
|
||||
.expect("Always exists")
|
||||
.get("SimpleContract")
|
||||
.expect("Always exists")
|
||||
.missing_libraries
|
||||
.is_empty(),
|
||||
"The list of missing libraries must be empty"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
//! The Solidity compiler unit tests for messages.
|
||||
|
||||
use revive_llvm_context::OptimizerSettings;
|
||||
use revive_solc_json_interface::{ResolcWarning, SolcStandardJsonOutput};
|
||||
|
||||
use crate::test_utils::{build_solidity, build_solidity_with_options, sources};
|
||||
|
||||
pub const SEND_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract SendExample {
|
||||
address payable public recipient;
|
||||
|
||||
constructor(address payable _recipient) {
|
||||
recipient = _recipient;
|
||||
}
|
||||
|
||||
function forwardEther() external payable {
|
||||
bool success = recipient.send(msg.value);
|
||||
require(success, "Failed to send Ether");
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub const TRANSFER_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TransferExample {
|
||||
address payable public recipient;
|
||||
|
||||
constructor(address payable _recipient) {
|
||||
recipient = _recipient;
|
||||
}
|
||||
|
||||
function forwardEther() external payable {
|
||||
recipient.transfer(msg.value);
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub const TX_ORIGIN_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TxOriginExample {
|
||||
function isOriginSender() public view returns (bool) {
|
||||
return tx.origin == msg.sender;
|
||||
}
|
||||
}"#;
|
||||
|
||||
fn contains_warning(build: SolcStandardJsonOutput, warning: ResolcWarning) -> bool {
|
||||
build
|
||||
.errors
|
||||
.iter()
|
||||
.any(|error| error.is_warning() && error.message.contains(warning.as_message()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
let build = build_solidity(sources(&[("test.sol", SEND_TEST_SOURCE)])).unwrap();
|
||||
assert!(contains_warning(build, ResolcWarning::SendAndTransfer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_suppressed() {
|
||||
let build = build_solidity_with_options(
|
||||
sources(&[("test.sol", SEND_TEST_SOURCE)]),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
OptimizerSettings::cycles(),
|
||||
true,
|
||||
vec![ResolcWarning::SendAndTransfer],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!contains_warning(build, ResolcWarning::SendAndTransfer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer() {
|
||||
let build = build_solidity(sources(&[("test.sol", TRANSFER_TEST_SOURCE)])).unwrap();
|
||||
assert!(contains_warning(build, ResolcWarning::SendAndTransfer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_suppressed() {
|
||||
let build = build_solidity_with_options(
|
||||
sources(&[("test.sol", TRANSFER_TEST_SOURCE)]),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
OptimizerSettings::cycles(),
|
||||
true,
|
||||
vec![ResolcWarning::SendAndTransfer],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!contains_warning(build, ResolcWarning::SendAndTransfer))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_origin() {
|
||||
let build = build_solidity(sources(&[("test.sol", TX_ORIGIN_TEST_SOURCE)])).unwrap();
|
||||
assert!(contains_warning(build, ResolcWarning::TxOrigin));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_origin_suppressed() {
|
||||
let build = build_solidity_with_options(
|
||||
sources(&[("test.sol", TX_ORIGIN_TEST_SOURCE)]),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
OptimizerSettings::cycles(),
|
||||
true,
|
||||
vec![ResolcWarning::TxOrigin],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!contains_warning(build, ResolcWarning::TxOrigin))
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//! The Solidity compiler unit tests.
|
||||
|
||||
mod factory_dependency;
|
||||
mod ir_artifacts;
|
||||
mod libraries;
|
||||
mod messages;
|
||||
mod optimizer;
|
||||
mod remappings;
|
||||
mod runtime_code;
|
||||
mod standard_json;
|
||||
mod unsupported_opcodes;
|
||||
@@ -0,0 +1,119 @@
|
||||
//! The Solidity compiler unit tests for the optimizer.
|
||||
|
||||
use crate::test_utils::{build_solidity, build_solidity_with_options, sources};
|
||||
|
||||
#[test]
|
||||
fn optimizer() {
|
||||
let source = &[(
|
||||
"test.sol",
|
||||
r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.5.0;
|
||||
|
||||
contract Test {
|
||||
uint8 constant ARRAY_SIZE = 40;
|
||||
uint128 constant P = 257;
|
||||
uint128 constant MODULO = 1000000007;
|
||||
|
||||
function complex() public pure returns(uint64) {
|
||||
uint8[ARRAY_SIZE] memory array;
|
||||
// generate array where first half equals second
|
||||
for(uint8 i = 0; i < ARRAY_SIZE; i++) {
|
||||
array[i] = (i % (ARRAY_SIZE / 2)) * (255 / (ARRAY_SIZE / 2 - 1));
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
for(uint8 i = 0; i < ARRAY_SIZE/2; i++) {
|
||||
result = result && hash(array, 0, i + 1) == hash(array, ARRAY_SIZE/2, ARRAY_SIZE/2 + i + 1)
|
||||
&& hash(array, i, ARRAY_SIZE/2) == hash(array, i + ARRAY_SIZE/2, ARRAY_SIZE);
|
||||
}
|
||||
if (result) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function hash(uint8[ARRAY_SIZE] memory array, uint8 begin, uint8 end) private pure returns(uint128) {
|
||||
uint128 h = 0;
|
||||
for(uint8 i = begin; i < end; i++) {
|
||||
h = (h * P + array[i]) % MODULO;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}"#,
|
||||
)];
|
||||
|
||||
let build_unoptimized = build_solidity_with_options(
|
||||
sources(source),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
revive_llvm_context::OptimizerSettings::none(),
|
||||
true,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
let build_optimized_for_cycles = build_solidity(sources(source)).unwrap();
|
||||
let build_optimized_for_size = build_solidity_with_options(
|
||||
sources(source),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
revive_llvm_context::OptimizerSettings::size(),
|
||||
true,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let size_when_unoptimized = build_unoptimized
|
||||
.contracts
|
||||
.get("test.sol")
|
||||
.expect("Missing file `test.sol`")
|
||||
.get("Test")
|
||||
.expect("Missing contract `test.sol:Test`")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("Missing EVM data")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("Missing bytecode")
|
||||
.object
|
||||
.len();
|
||||
let size_when_optimized_for_cycles = build_optimized_for_cycles
|
||||
.contracts
|
||||
.get("test.sol")
|
||||
.expect("Missing file `test.sol`")
|
||||
.get("Test")
|
||||
.expect("Missing contract `test.sol:Test`")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("Missing EVM data")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("Missing bytecode")
|
||||
.object
|
||||
.len();
|
||||
let size_when_optimized_for_size = build_optimized_for_size
|
||||
.contracts
|
||||
.get("test.sol")
|
||||
.expect("Missing file `test.sol`")
|
||||
.get("Test")
|
||||
.expect("Missing contract `test.sol:Test`")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("Missing EVM data")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("Missing bytecode")
|
||||
.object
|
||||
.len();
|
||||
|
||||
assert!(
|
||||
size_when_optimized_for_cycles < size_when_unoptimized,
|
||||
"Expected the cycles-optimized bytecode to be smaller than the unoptimized. Optimized: {size_when_optimized_for_cycles}B, Unoptimized: {size_when_unoptimized}B",
|
||||
);
|
||||
assert!(
|
||||
size_when_optimized_for_size < size_when_unoptimized,
|
||||
"Expected the size-optimized bytecode to be smaller than the unoptimized. Optimized: {size_when_optimized_for_size}B, Unoptimized: {size_when_unoptimized}B",
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//! The Solidity compiler unit tests for remappings.
|
||||
|
||||
use crate::test_utils::{build_solidity_with_options, sources};
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let callee_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
contract Callable {
|
||||
function f(uint a) public pure returns(uint) {
|
||||
return a * 2;
|
||||
}
|
||||
}"#;
|
||||
|
||||
let caller_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
import "libraries/default/callable.sol";
|
||||
|
||||
contract Main {
|
||||
function main(Callable callable) public returns(uint) {
|
||||
return callable.f(5);
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity_with_options(
|
||||
sources(&[("./test.sol", caller_code), ("./callable.sol", callee_code)]),
|
||||
Default::default(),
|
||||
["libraries/default/=./".to_owned()].into(),
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
true,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//! The Solidity compiler unit tests for runtime code.
|
||||
|
||||
use crate::test_utils::{build_solidity, sources};
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract A {}
|
||||
|
||||
contract Test {
|
||||
function main() public pure returns(bytes memory) {
|
||||
return type(A).runtimeCode;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", code)]))
|
||||
.unwrap()
|
||||
.errors
|
||||
.iter()
|
||||
.find(|error| {
|
||||
error
|
||||
.to_string()
|
||||
.contains("Error: Deploy and runtime code are merged in PVM")
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use revive_solc_json_interface::SolcStandardJsonInput;
|
||||
|
||||
use crate::test_utils::build_yul_standard_json;
|
||||
|
||||
#[test]
|
||||
fn standard_json_yul_solc() {
|
||||
let solc_input = SolcStandardJsonInput::try_from(Some(
|
||||
PathBuf::from("src/tests/data/standard_json/yul_solc.json").as_path(),
|
||||
))
|
||||
.unwrap();
|
||||
let solc_output = build_yul_standard_json(solc_input).unwrap();
|
||||
|
||||
assert!(!solc_output
|
||||
.contracts
|
||||
.get("Test")
|
||||
.expect("The `Test` contract is missing")
|
||||
.get("Return")
|
||||
.expect("The `Return` contract is missing")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("The `evm` field is missing")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("The `bytecode` field is missing")
|
||||
.object
|
||||
.is_empty())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standard_json_yul_solc_urls() {
|
||||
let solc_input = SolcStandardJsonInput::try_from(Some(
|
||||
PathBuf::from("src/tests/data/standard_json/yul_solc_urls.json").as_path(),
|
||||
))
|
||||
.unwrap();
|
||||
let solc_output = build_yul_standard_json(solc_input).unwrap();
|
||||
|
||||
assert!(!solc_output
|
||||
.contracts
|
||||
.get("Test")
|
||||
.expect("The `Test` contract is missing")
|
||||
.get("Return")
|
||||
.expect("The `Return` contract is missing")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("The `evm` field is missing")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("The `bytecode` field is missing")
|
||||
.object
|
||||
.is_empty())
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
//! The Solidity compiler unit tests for unsupported opcodes.
|
||||
|
||||
use crate::test_utils::{build_solidity, build_yul, sources};
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `CODECOPY` instruction is not supported")]
|
||||
fn codecopy_yul_runtime() {
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract FixedCodeCopy {
|
||||
function copyCode() public view returns (bytes memory) {
|
||||
uint256 fixedCodeSize = 64;
|
||||
bytes memory code = new bytes(fixedCodeSize);
|
||||
|
||||
assembly {
|
||||
codecopy(add(code, 0x20), 0, fixedCodeSize)
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", code)])).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `CALLCODE` instruction is not supported")]
|
||||
fn callcode_yul() {
|
||||
let solidity = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract CallcodeTest {
|
||||
function testCallcode(address target, bytes4 signature, uint256 inputValue) public returns (bool) {
|
||||
bool success;
|
||||
|
||||
assembly {
|
||||
let input := mload(0x40)
|
||||
mstore(input, signature)
|
||||
mstore(add(input, 0x04), inputValue)
|
||||
|
||||
let callResult := callcode(gas(), target, 0, input, 0x24, 0, 0)
|
||||
|
||||
success := and(callResult, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", solidity)])).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `PC` instruction is not supported")]
|
||||
fn pc_yul() {
|
||||
let code = r#"
|
||||
object "ProgramCounter" {
|
||||
code {
|
||||
datacopy(0, dataoffset("ProgramCounter_deployed"), datasize("ProgramCounter_deployed"))
|
||||
return(0, datasize("ProgramCounter_deployed"))
|
||||
}
|
||||
object "ProgramCounter_deployed" {
|
||||
code {
|
||||
function getPC() -> programCounter {
|
||||
programCounter := pc()
|
||||
}
|
||||
|
||||
let pcValue := getPC()
|
||||
sstore(0, pcValue)
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_yul(&[("test.sol", code)]).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")]
|
||||
fn extcodecopy_yul() {
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ExternalCodeCopy {
|
||||
function copyExternalCode(address target, uint256 codeSize) public view returns (bytes memory) {
|
||||
bytes memory code = new bytes(codeSize);
|
||||
|
||||
assembly {
|
||||
extcodecopy(target, add(code, 0x20), 0, codeSize)
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", code)])).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
||||
fn selfdestruct_yul() {
|
||||
let solidity = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract MinimalDestructible {
|
||||
address payable public owner;
|
||||
|
||||
constructor() {
|
||||
owner = payable(msg.sender);
|
||||
}
|
||||
|
||||
function destroy() public {
|
||||
require(msg.sender == owner, "Only the owner can call this function.");
|
||||
selfdestruct(owner);
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", solidity)])).unwrap();
|
||||
}
|
||||
Reference in new issue
Block a user