Skip to content

Commit

Permalink
Add support for revert reason strings in assert statement
Browse files Browse the repository at this point in the history
Closes #288
  • Loading branch information
cburgdorf committed Apr 21, 2021
1 parent faccb1c commit 22771e7
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 9 deletions.
11 changes: 8 additions & 3 deletions compiler/src/yul/mappers/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,15 @@ fn emit(context: &Context, stmt: &Node<fe::FuncStmt>) -> yul::Statement {
}

fn assert(context: &Context, stmt: &Node<fe::FuncStmt>) -> yul::Statement {
if let fe::FuncStmt::Assert { test, msg: _ } = &stmt.kind {
if let fe::FuncStmt::Assert { test, msg } = &stmt.kind {
let test = expressions::expr(context, test);

return statement! { if (iszero([test])) { (revert(0, 0)) } };
return match msg {
Some(val) => {
let msg = expressions::expr(context, val);
statement! { if (iszero([test])) { (revert_with_reason_string([msg])) } }
}
None => statement! { if (iszero([test])) { (revert(0, 0)) } },
};
}

unreachable!()
Expand Down
34 changes: 29 additions & 5 deletions compiler/tests/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,41 @@ fn test_assert() {

let exit1 = harness.capture_call(&mut executor, "bar", &[uint_token(4)]);

assert!(matches!(
exit1,
evm::Capture::Exit((evm::ExitReason::Revert(_), _))
));
match exit1 {
evm::Capture::Exit((evm::ExitReason::Revert(_), output)) => assert_eq!(output.len(), 0),
_ => panic!("Did not revert correctly"),
}

let exit2 = harness.capture_call(&mut executor, "bar", &[uint_token(42)]);

assert!(matches!(
exit2,
evm::Capture::Exit((evm::ExitReason::Succeed(_), _))
))
));

let exit3 =
harness.capture_call(&mut executor, "revert_with_static_string", &[uint_token(4)]);

match exit3 {
evm::Capture::Exit((evm::ExitReason::Revert(_), output)) => {
assert_eq!(output, encode_error_reason("Must be greater than five"))
}
_ => panic!("Did not revert correctly"),
}

let reason = "A very looooooooooooooong reason that consumes multiple words";
let exit4 = harness.capture_call(
&mut executor,
"revert_with",
&[uint_token(4), string_token(&reason)],
);

match exit4 {
evm::Capture::Exit((evm::ExitReason::Revert(_), output)) => {
assert_eq!(output, encode_error_reason(reason))
}
_ => panic!("Did not revert correctly"),
}
})
}

Expand Down
8 changes: 7 additions & 1 deletion compiler/tests/fixtures/features/assert.fe
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
contract Foo:
pub def bar(baz: u256):
assert baz > 5
assert baz > 5

pub def revert_with_static_string(baz: u256):
assert baz > 5, "Must be greater than five"

pub def revert_with(baz: u256, reason: string1000):
assert baz > 5, reason
17 changes: 17 additions & 0 deletions newsfragments/288.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Support for revert messages in assert statements

E.g

```
assert a == b, "my revert statement"
```

The provided string is abi-encoded as if it were a call
to a function `Error(string)`. For example, the revert string `"Not enough Ether provided."` returns the following hexadecimal as error return data:

```
0x08c379a0 // Function selector for Error(string)
0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset
0x000000000000000000000000000000000000000000000000000000000000001a // String length
0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data
```

0 comments on commit 22771e7

Please sign in to comment.