Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/tests/hostapi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,68 @@ mod tests {
.unwrap();
runtime.assert_result("f248a1c000000000000000000000000000000000000000000000000000000000");
}

#[test]
fn test_solidity_revert_short_string() {
let mut runtime = TestRuntime::new(
"test_solidity_revert_short_string",
"target/test_solidity_revert_short_string",
);
runtime.clear_testdata();
let yul_code = runtime.compile_solidity_to_yul(
r#"
pragma solidity ^0.8.0;

contract TestContract {
function test() public {
revert("helloworld");
}
}

"#,
"TestContract",
);
if let Err(err) = &yul_code {
eprintln!("compile to yul error: {err}");
}
assert!(yul_code.is_ok());
let yul_code = yul_code.unwrap();
let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap();
runtime.set_enable_gas_meter(false);
runtime.deploy(&[]).unwrap();
runtime.call(&solidity_selector("test()"), &[]).unwrap();
runtime.assert_revert("08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a68656c6c6f776f726c6400000000000000000000000000000000000000000000");
}

#[test]
fn test_solidity_revert_long_string() {
let mut runtime = TestRuntime::new(
"test_solidity_revert_long_string",
"target/test_solidity_revert_long_string",
);
runtime.clear_testdata();
let yul_code = runtime.compile_solidity_to_yul(
r#"
pragma solidity ^0.8.0;

contract TestContract {
function test() public {
revert("helloworld. This is a long revert string longer than 32bytes");
}
}

"#,
"TestContract",
);
if let Err(err) = &yul_code {
eprintln!("compile to yul error: {err}");
}
assert!(yul_code.is_ok());
let yul_code = yul_code.unwrap();
let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap();
runtime.set_enable_gas_meter(false);
runtime.deploy(&[]).unwrap();
runtime.call(&solidity_selector("test()"), &[]).unwrap();
runtime.assert_revert("08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c68656c6c6f776f726c642e20546869732069732061206c6f6e672072657665727420737472696e67206c6f6e676572207468616e203332627974657300000000");
}
}
51 changes: 51 additions & 0 deletions src/tests/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use rand::distr::Alphanumeric;
use rand::Rng;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use tempfile::tempdir;

Expand Down Expand Up @@ -134,6 +135,56 @@ impl TestRuntime {
}
}

#[allow(unused)]
pub fn compile_solidity_to_yul(
&mut self,
solidity_code: &str,
contract_name: &str,
) -> Result<String, String> {
// avoid using the invalid contract name(not strict check)
// this is because solc will generate yul files with basename of contract name
// but we don't known the name
assert!(solidity_code.contains(&format!("contract {contract_name}")));

// 1. create tmp file to store the solidity code
let tmp_dir = Path::new(&self.output_dir);
let sol_path = tmp_dir.join("input.sol");
let yul_file_basename = &format!("{contract_name}.yul");
let yul_path = tmp_dir.join(yul_file_basename);
println!(
"tmp_dir: {:?}, yul_path: {:?}",
tmp_dir.as_os_str(),
yul_path.as_os_str()
);

if !sol_path.exists() {
let mut sol_file = File::create(&sol_path).map_err(|e| e.to_string())?;
sol_file
.write_all(solidity_code.as_bytes())
.map_err(|e| e.to_string())?;
}
// There are multiple output files, and the output file names are related to the Solidity contract name.
// 2. using `solc` to compile,
// eg. solc --ir --optimize-yul -o . --overwrite input.sol
let output = Command::new("solc")
.current_dir(tmp_dir)
.arg("--ir")
.arg("--optimize-yul")
.arg("--overwrite")
.arg("-o")
.arg(".")
.arg("input.sol")
.output()
.map_err(|e| e.to_string())?;
if !output.status.success() {
return Err(String::from_utf8_lossy(&output.stderr).to_string());
}
// 3. read the generated yul file content
let yul_content = std::fs::read_to_string(&yul_path)
.map_err(|e| format!("Failed to read yul file: {}", e))?;
Ok(yul_content)
}

#[allow(unused)]
pub fn set_sender(&mut self, sender: Option<String>) {
self.sender = sender;
Expand Down
4 changes: 2 additions & 2 deletions src/yul2ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ impl<'ctx> Yul2IRContext<'ctx> {
}

pub fn string_literal(&self, value: &str) -> IntValue<'ctx> {
if value.len() > 31 {
// panic!("String literal length exceeds 31 bytes: {}", value);
if value.len() > 32 {
// panic!("String literal length exceeds 32 bytes: {}", value);
// String literals used in linker symbol, data offset, and data size instructions
// don't need to be processed by string_literal function
// After modifying the logic in instruction.rs, we can restore the panic here
Expand Down