Skip to content

Commit

Permalink
Add revert_with_reason_string runtime function
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Apr 21, 2021
1 parent b2f6347 commit 78518a5
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 73 deletions.
56 changes: 41 additions & 15 deletions compiler/src/yul/runtime/functions/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@ use yultsur::*;
/// Return all data runtime functions
pub fn all() -> Vec<yul::Statement> {
vec![
avail(),
alloc(),
alloc_mstoren(),
free(),
alloc(),
avail(),
bytes_mcopys(),
bytes_scopym(),
bytes_scopys(),
bytes_sloadn(),
bytes_sstoren(),
ccopym(),
ceil32(),
cloadn(),
free(),
load_data_string(),
map_value_ptr(),
mcopym(),
mcopys(),
mloadn(),
mstoren(),
revert_with_reason_string(),
scopym(),
mcopym(),
scopys(),
mloadn(),
set_zero(),
sloadn(),
bytes_sloadn(),
cloadn(),
mstoren(),
sstoren(),
bytes_sstoren(),
bytes_mcopys(),
bytes_scopym(),
bytes_scopys(),
map_value_ptr(),
ceil32(),
ternary(),
set_zero(),
]
}

Expand Down Expand Up @@ -380,3 +381,28 @@ pub fn load_data_string() -> yul::Statement {
}
}
}

/// Revert with encoded reason string
pub fn revert_with_reason_string() -> yul::Statement {
function_definition! {
function revert_with_reason_string(reason) {
// Function selector for Error(string)
(let ptr := alloc_mstoren(0x08C379A0, 4))

// Write the (fixed) data offset into the next 32 bytes of memory
(pop((alloc_mstoren(0x0000000000000000000000000000000000000000000000000000000000000020, 32))))

// Read the size of the string
(let reason_size := mloadn(reason, 32))

//Copy the whole reason string (length + data) to the current segment of memory
(pop((mcopym(reason , (add(reason_size, 32))))))

// Right pad the reason bytes to a multiple of 32 bytes
(let padding := sub((ceil32(reason_size)), reason_size))
(pop((alloc(padding))))

(revert(ptr, (add(68, (add(reason_size, padding))))))
}
}
}
93 changes: 55 additions & 38 deletions compiler/tests/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#![cfg(feature = "solc-backend")]
use fe_compiler::yul::runtime::functions;
use rstest::rstest;
use yultsur::*;

mod utils;
Expand All @@ -11,6 +12,7 @@ use fe_analyzer::namespace::types::{
Integer,
Struct,
};
use fe_common::utils::keccak;
use utils::*;

macro_rules! assert_eq {
Expand All @@ -23,13 +25,37 @@ macro_rules! assert_eq {
};
}

#[rstest(
reason,
case("foo"),
case("A very looooooooooooooong reason that consumes multiple words")
)]
fn test_revert_with_reason_string(reason: &str) {
let reason_id = format!(r#""{}""#, keccak::full(reason.as_bytes()));

with_executor(&|mut executor| {
test_runtime_functions_revert(
&mut executor,
Runtime::default()
.with_data(
vec![yul::Data { name: keccak::full(reason.as_bytes()), value: reason.to_owned() }]
)
.with_test_statements(
statements! {
(let reason := load_data_string((dataoffset([literal_expression! { (reason_id) }])), (datasize([literal_expression! { (reason_id) }]))))
(revert_with_reason_string(reason))
}),
&encode_error_reason(reason)
);
})
}

#[test]
fn test_runtime_alloc_and_avail() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := avail())
(let b := alloc(5))
(let c := alloc(10))
Expand All @@ -38,7 +64,7 @@ fn test_runtime_alloc_and_avail() {
[assert_eq!(b, a)]
[assert_eq!(c, (add(b, 5)))]
[assert_eq!(d, (add(c, 10)))]
},
}),
);
})
}
Expand All @@ -48,8 +74,7 @@ fn test_runtime_mcopys() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x0111114211111111011111112342311101111112221151110111111111111111)
(let b := 0x0111111234111111011123411111111101112431111111110111111234411111)
(let c := 0x0111341111111111011111111123411101111123411111110111111234111111)
Expand All @@ -75,7 +100,7 @@ fn test_runtime_mcopys() {
[assert_eq!(b, (sload(47)))]
[assert_eq!(c, (sload(48)))]
[assert_eq!(d, (sload(49)))]
},
}),
);
})
}
Expand All @@ -85,8 +110,7 @@ fn test_runtime_scopym() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x0111114211111111011111112342311101111112221151110111111111111111)
(let b := 0x0111111234111111011123411111111101112431111111110111111234411111)
(let c := 0x0111341111111111011111111123411101111123411111110111111234111111)
Expand Down Expand Up @@ -118,7 +142,7 @@ fn test_runtime_scopym() {
[assert_eq!(b, (mload(ptr6)))]
[assert_eq!(c, (mload(ptr7)))]
[assert_eq!(d, (mload(ptr8)))]
},
}),
);
})
}
Expand All @@ -128,16 +152,15 @@ fn test_runtime_mloadn() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x4200000000000000000000000000000000000000000000000000000000420026)
(mstore(100, a))

[assert_eq!(0x42, (mloadn(100, 1)))]
[assert_eq!(0x420026, (mloadn(129, 3)))]
[assert_eq!(0x26, (mloadn(130, 2)))]
[assert_eq!(0x26, (mloadn(131, 1)))]
},
}),
);
})
}
Expand All @@ -147,16 +170,15 @@ fn test_runtime_storage_sanity() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
vec![],
statements! {
Runtime::new().with_test_statements(statements! {
(let a := 0x4200000000000000000000000000000000000000000000000000000000000026)
(let b := 0x9900000000000000000000000000000000000000000000000000000000000077)
(sstore(0, a))
(sstore(1, b))

[assert_eq!(a, (sload(0)))]
[assert_eq!(b, (sload(1)))]
},
}),
);
})
}
Expand All @@ -166,8 +188,7 @@ fn test_runtime_sloadn() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x4200000000000000000000000000000000000000000000000000000000000026)
(let b := 0x9900530000003900000000000000000000000000000000000000000000000077)
(sstore(1000, a))
Expand All @@ -184,7 +205,7 @@ fn test_runtime_sloadn() {
[assert_eq!(0x77, (sloadn(1001, 31, 1)))]
[assert_eq!(0x990053, (sloadn(1001, 0, 3)))]
[assert_eq!(0x5300000039, (sloadn(1001, 2, 5)))]
},
}),
);
})
}
Expand All @@ -194,8 +215,7 @@ fn test_runtime_sstoren() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x0111111111111111011111111111111101111111111111110111111111111111)
// dashes indicate which bytes are to be replaced in this test
// 0----2 8----10 15----------------23 31--32
Expand All @@ -213,7 +233,7 @@ fn test_runtime_sstoren() {
(sstoren(1000, 0, 32, c))

[assert_eq!(c, (sload(1000)))]
},
}),
);
})
}
Expand All @@ -223,11 +243,10 @@ fn test_runtime_ceil32() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
[assert_eq!(32, (ceil32(29)))]
[assert_eq!(256, (ceil32(225)))]
},
}),
);
})
}
Expand All @@ -237,14 +256,13 @@ fn test_runtime_ternary() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := ternary(0, 42, 26))
(let b := ternary(1, 42, 26))

[assert_eq!(a, 26)]
[assert_eq!(b, 42)]
},
}),
);
})
}
Expand All @@ -254,8 +272,7 @@ fn test_runtime_abi_unpack() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x0042002600530000000000000000000000000000000000000000000000000000)
(let packed := alloc_mstoren(a, 32))
(let unpacked := avail())
Expand All @@ -268,7 +285,7 @@ fn test_runtime_abi_unpack() {
[assert_eq!(elem0, 0x0042)]
[assert_eq!(elem1, 0x0026)]
[assert_eq!(elem2, 0x0053)]
},
}),
);
})
}
Expand All @@ -278,7 +295,7 @@ fn test_keccak256() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
Runtime::default().with_test_statements(
statements! {
(let num := 63806209331542711802848847270949280092855778197726125910674179583545433573378)
(let result :=109966633016701122630199943745061001312678661825260870342362413625737614346915)
Expand All @@ -288,6 +305,7 @@ fn test_keccak256() {
(mstore(0, num))
[assert_eq!(result, (keccak256(0, 32)))]
},
)
);
})
}
Expand All @@ -297,8 +315,7 @@ fn test_runtime_set_zero() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
(let a := 0x1111111111111111111111111111111111111111111111111111111111111111)
(let b := 0x1111110000000000000000000000000000000000000000000000001111111111)
(let c := 0x1111100000000000000000000000000000000000000000000000000000000000)
Expand All @@ -307,7 +324,7 @@ fn test_runtime_set_zero() {
[assert_eq!(0x11, (set_zero(0, 248, a)))]
[assert_eq!(b, (set_zero(24, 216, a)))]
[assert_eq!(c, (set_zero(20, 256, a)))]
},
}),
);
})
}
Expand All @@ -330,7 +347,7 @@ fn test_runtime_house_struct() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
[functions::std(), house_api.clone()].concat(),
Runtime::new().with_functions([functions::std(), house_api.clone()].concat()).with_test_statements(
statements! {
(let price := 42)
(let size := 26)
Expand Down Expand Up @@ -369,6 +386,7 @@ fn test_runtime_house_struct() {
[assert_eq!(rooms, (bytes_sloadn((struct_House_get_rooms_ptr(house_storage)), 1)))]
[assert_eq!(vacant, (bytes_sloadn((struct_House_get_vacant_ptr(house_storage)), 1)))]
},
)
);
})
}
Expand All @@ -378,10 +396,9 @@ fn checked_exp_signed() {
with_executor(&|mut executor| {
test_runtime_functions(
&mut executor,
functions::std(),
statements! {
Runtime::default().with_test_statements(statements! {
[assert_eq!(4, (checked_exp_signed(2, 2, 0, 100)))]
},
}),
);
})
}
Loading

0 comments on commit 78518a5

Please sign in to comment.