Skip to content

Commit

Permalink
revert functions take single type
Browse files Browse the repository at this point in the history
  • Loading branch information
g-r-a-n-t committed Jul 27, 2021
1 parent f990cde commit 8133e19
Show file tree
Hide file tree
Showing 20 changed files with 79 additions and 79 deletions.
4 changes: 2 additions & 2 deletions crates/tests/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ fn test_revert() {

validate_revert(
harness.capture_call(&mut executor, "revert_custom_error", &[]),
&encode_revert("Error((uint256,bool))", &[uint_token(1), bool_token(true)]),
&encode_revert("Error(uint256,bool)", &[uint_token(1), bool_token(true)]),
);

validate_revert(
harness.capture_call(&mut executor, "revert_other_error", &[]),
&encode_revert(
"OtherError((uint256,bool))",
"OtherError(uint256,bool)",
&[uint_token(1), bool_token(true)],
),
);
Expand Down
12 changes: 6 additions & 6 deletions crates/yulgen/src/mappers/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::mappers::{assignments, declarations, expressions};
use crate::names;
use crate::operations::data as data_operations;
use crate::operations::revert as revert_operations;
use crate::types::{AbiType, EvmSized};
use crate::types::{AbiType, EvmSized, to_abi_types};
use crate::Context;
use fe_analyzer::context::ExpressionAttributes;
use fe_analyzer::namespace::types::{FixedSize, Type};
Expand Down Expand Up @@ -129,11 +129,11 @@ fn revert(context: &mut Context, stmt: &Node<fe::FuncStmt>) -> yul::Statement {
.get_expression(error_expr)
.expect("missing expression");

if let Type::Struct(val) = &error_attributes.typ {
context.revert_errors.insert(val.clone());
if let Type::Struct(_struct) = &error_attributes.typ {
context.revert_errors.insert(_struct.clone());

let revert_data = expressions::expr(context, error_expr);
let revert_fn = names::revert_name(&val.name, &[AbiType::from(val)]);
let revert_fn = names::revert_name(&_struct.name, &AbiType::from(_struct));

statement! {
([revert_fn]([revert_data]))
Expand Down Expand Up @@ -180,13 +180,13 @@ fn assert(context: &mut Context, stmt: &Node<fe::FuncStmt>) -> yul::Statement {

if let Type::String(string) = &msg_attributes.typ {
context.assert_strings.insert(string.to_owned());
revert_operations::error_revert(&[AbiType::from(string)], test, msg)
revert_operations::error_revert(&AbiType::from(string), test, msg)
} else {
unreachable!()
}
}
None => {
statement! { if (iszero([test])) { (revert_with_panic([literal_expression! {(PANIC_FAILED_ASSERTION)}])) } }
statement! { if (iszero([test])) { (revert_with_Panic_uint256([literal_expression! {(PANIC_FAILED_ASSERTION)}])) } }
}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion crates/yulgen/src/names/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub fn vals(prefix: &str, n: usize) -> (Vec<yul::Identifier>, Vec<yul::Expressio
.unzip()
}

fn typ(_typ: &AbiType) -> String {
pub fn typ(_typ: &AbiType) -> String {
match _typ {
AbiType::Uint { size } => format!("uint{}", size * 8),
AbiType::Int { size } => format!("int{}", size * 8),
Expand Down
12 changes: 8 additions & 4 deletions crates/yulgen/src/names/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@ pub fn var_name(name: &str) -> yul::Identifier {
}

/// Generate a revert function name for the name `Error` and a given set of types
pub fn error_revert_name(types: &[AbiType]) -> yul::Identifier {
revert_name("Error", types)
pub fn error_revert_name(typ: &AbiType) -> yul::Identifier {
revert_name("Error", typ)
}

pub fn panic_revert_name(typ: &AbiType) -> yul::Identifier {
revert_name("Panic", typ)
}

/// Generates a revert function name for a given name and types
pub fn revert_name(name: &str, types: &[AbiType]) -> yul::Identifier {
let name = format!("revert_with_{}_{}", name, abi_names::types(types));
pub fn revert_name(name: &str, typ: &AbiType) -> yul::Identifier {
let name = format!("revert_with_{}_{}", name, abi_names::typ(typ));

identifier! { (name) }
}
Expand Down
4 changes: 2 additions & 2 deletions crates/yulgen/src/operations/revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::types::AbiType;
use crate::names;
use yultsur::*;

pub fn error_revert(types: &[AbiType], test: yul::Expression, msg: yul::Expression) -> yul::Statement {
let func_name = names::error_revert_name(types);
pub fn error_revert(typ: &AbiType, test: yul::Expression, msg: yul::Expression) -> yul::Statement {
let func_name = names::error_revert_name(typ);

statement! {
if (iszero([test])) {
Expand Down
4 changes: 2 additions & 2 deletions crates/yulgen/src/runtime/functions/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use yultsur::*;

/// Return all abi runtime functions
pub fn all() -> Vec<yul::Statement> {
vec![unpack(), is_left_padded(), is_right_padded()]
vec![unpack(), is_left_padded(), is_right_padded(), encode(vec![AbiType::Uint { size: 32 }])]
}

/// Creates a batch of encoding function for the given type arrays.
Expand Down Expand Up @@ -447,7 +447,7 @@ pub fn is_right_padded() -> yul::Statement {
}

fn revert_with_invalid_abi_data() -> yul::Statement {
statement!(revert_with_panic([
statement!(revert_with_Panic_uint256([
literal_expression! { (PANIC_INVALID_ABI_DATA) }
]))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/yulgen/src/runtime/functions/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ pub fn all() -> Vec<yul::Statement> {
}

fn revert_with_over_or_under_flow() -> yul::Statement {
statement!(revert_with_panic([
statement!(revert_with_Panic_uint256([
literal_expression! {(PANIC_OVER_OR_UNDERFLOW)}
]))
}

fn revert_with_div_or_mod_by_zero() -> yul::Statement {
statement!(revert_with_panic([
statement!(revert_with_Panic_uint256([
literal_expression! {(PANIC_DIV_OR_MOD_BY_ZERO)}
]))
}
Expand Down
7 changes: 5 additions & 2 deletions crates/yulgen/src/runtime/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ pub mod structs;

/// Returns all functions that should be available during runtime.
pub fn std() -> Vec<yul::Statement> {
[
let mut functions = [
contracts::all(),
abi::all(),
data::all(),
math::all(),
revert::all(),
]
.concat()
.concat();
functions.sort();
functions.dedup();
functions
}
52 changes: 22 additions & 30 deletions crates/yulgen/src/runtime/functions/revert.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,49 @@
use crate::names;
use crate::names::abi as abi_names;
use crate::operations::abi as abi_operations;
use crate::types::{to_abi_selector_names, AbiType};
use crate::types::{to_abi_selector_names, AbiType, to_abi_types};
use fe_analyzer::namespace::types::Struct;
use yultsur::*;

/// Generate a YUL function to revert with the `Error` signature and the
/// given set of params.
/// NOTE: This is currently used for `assert False, "message"` statements which are
/// encoded as `Error(msg="message")`. This will be removed in the future.
pub fn generate_revert_fn_for_assert(params: &[AbiType]) -> yul::Statement {
generate_revert_fn("Error", params)
}

/// Generate a YUL function to revert with a specific struct used as error data
pub fn generate_struct_revert(val: &Struct) -> yul::Statement {
let typ = AbiType::from(val);
generate_revert_fn(&val.name, &[typ])
pub fn error_revert(typ: &AbiType) -> yul::Statement {
revert("Error", typ)
}

/// Generate a YUL function to revert with panic codes
pub fn generate_revert_fn_for_panic() -> yul::Statement {
let selector = fe_abi::utils::func_selector("Panic", &["uint256".to_string()]);
let selector = literal_expression! { (selector) };

function_definition! {
function revert_with_panic(error_code) {
(let ptr := alloc_mstoren([selector], 4))
(pop((alloc_mstoren(error_code, 32))))
(revert(ptr, (add(4, 32))))
}
}
pub fn panic_revert() -> yul::Statement {
revert("Panic", &AbiType::Uint { size: 32 })
}

/// Generate a YUL function to revert with data
pub fn generate_revert_fn(name: &str, params: &[AbiType]) -> yul::Statement {
let function_name = names::revert_name(name, params);
let (param_idents, param_exprs) = abi_names::vals("params", params.len());
let selector = fe_abi::utils::func_selector(name, &to_abi_selector_names(params));
let selector = literal_expression! { (selector) };
let encode_params = abi_operations::encode(params, param_exprs.clone());
let encoding_size = abi_operations::encoding_size(params, param_exprs);
pub fn revert(name: &str, typ: &AbiType) -> yul::Statement {
let function_name = names::revert_name(name, typ);
// the selector parens around a tuple are removed for the selector preimage
// e.g. we use `MyError(bool, address)` instead of `MyError(bool, address)`
let selector = {
let selector_params = match typ.clone() {
AbiType::Tuple { components } => components,
typ => vec![typ]
};
let selector = fe_abi::utils::func_selector(name, &to_abi_selector_names(&selector_params));
literal_expression! { (selector) }
};
let encode_val = abi_operations::encode(&[typ.to_owned()], vec![expression! { val }]);
let encoding_size = abi_operations::encoding_size(&[typ.to_owned()], vec![expression! { val }]);

function_definition! {
function [function_name]([param_idents...]) {
function [function_name](val) {
(let ptr := alloc_mstoren([selector], 4))
(pop([encode_params]))
(pop([encode_val]))
(revert(ptr, (add(4, [encoding_size]))))
}
}
}

/// Return all revert runtime functions
pub fn all() -> Vec<yul::Statement> {
vec![generate_revert_fn_for_panic()]
vec![panic_revert()]
}
13 changes: 7 additions & 6 deletions crates/yulgen/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub fn build(context: &Context, contract: &Node<fe::Contract>) -> Vec<yul::State
.map(|val| to_abi_types(&val.get_field_types()))
.collect::<Vec<_>>();

let revert_panic_batch = vec![vec![AbiType::Uint { size: 32 }]];

let structs_batch = attributes
.structs
.iter()
Expand All @@ -61,6 +63,7 @@ pub fn build(context: &Context, contract: &Node<fe::Contract>) -> Vec<yul::State
contracts_batch,
assert_strings_batch,
revert_errors_batch,
revert_panic_batch,
structs_batch,
]
.concat();
Expand Down Expand Up @@ -120,16 +123,14 @@ pub fn build(context: &Context, contract: &Node<fe::Contract>) -> Vec<yul::State

let revert_calls_from_assert = context
.assert_strings
.clone()
.into_iter()
.map(|val| functions::revert::generate_revert_fn_for_assert(&[AbiType::from(&val)]))
.iter()
.map(|string| functions::revert::error_revert(&AbiType::from(string)))
.collect::<Vec<_>>();

let revert_calls = context
.revert_errors
.clone()
.into_iter()
.map(|val| functions::revert::generate_struct_revert(&val))
.iter()
.map(|_struct| functions::revert::revert(&_struct.name, &AbiType::from(_struct)))
.collect::<Vec<_>>();

let mut funcs = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ expression: "abi_functions::decode_component_bool(AbiDecodeLocation::Memory)"
function abi_decode_component_bool_mem(head_start, offset) -> return_val {
let ptr := add(head_start, offset)
return_val := mload(ptr)
if iszero(is_left_padded(255, return_val)) { revert_with_panic(153) }
if iszero(is_left_padded(255, return_val)) { revert_with_Panic_uint256(153) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ expression: "abi_functions::decode_component_bool(AbiDecodeLocation::Calldata)"
function abi_decode_component_bool_calldata(head_start, offset) -> return_val {
let ptr := add(head_start, offset)
return_val := calldataload(ptr)
if iszero(is_left_padded(255, return_val)) { revert_with_panic(153) }
if iszero(is_left_padded(255, return_val)) { revert_with_Panic_uint256(153) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ function abi_decode_component_bytes_26_mem(head_start, head_offset) -> return_va
data_start_offset := mload(head_ptr)
let data_start := add(head_start, data_start_offset)
let bytes_size := mload(data_start)
if iszero(eq(bytes_size, 26)) { revert_with_panic(153) }
if iszero(eq(bytes_size, 26)) { revert_with_Panic_uint256(153) }
let data_size := add(bytes_size, 32)
let padded_data_size := ceil32(data_size)
data_end_offset := add(data_start_offset, padded_data_size)
let end_word := mload(sub(add(head_start, data_end_offset), 32))
let padding_size_bits := mul(sub(padded_data_size, data_size), 8)
if iszero(is_right_padded(padding_size_bits, end_word)) { revert_with_panic(153) }
if iszero(is_right_padded(padding_size_bits, end_word)) { revert_with_Panic_uint256(153) }
return_val := mcopym(add(data_start, 32), sub(data_size, 32))
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ expression: "abi_functions::decode_component_int(2, AbiDecodeLocation::Calldata)
function abi_decode_component_int16_calldata(head_start, offset) -> return_val {
let ptr := add(head_start, offset)
return_val := calldataload(ptr)
if iszero(or(iszero(shr(15, return_val)), iszero(shr(15, not(return_val))))) { revert_with_panic(153) }
if iszero(or(iszero(shr(15, return_val)), iszero(shr(15, not(return_val))))) { revert_with_Panic_uint256(153) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ function abi_decode_component_bytes_26_calldata(head_start, head_offset) -> retu
data_start_offset := calldataload(head_ptr)
let data_start := add(head_start, data_start_offset)
let bytes_size := calldataload(data_start)
if iszero(eq(bytes_size, 26)) { revert_with_panic(153) }
if iszero(eq(bytes_size, 26)) { revert_with_Panic_uint256(153) }
let data_size := add(bytes_size, 32)
let padded_data_size := ceil32(data_size)
data_end_offset := add(data_start_offset, padded_data_size)
let end_word := calldataload(sub(add(head_start, data_end_offset), 32))
let padding_size_bits := mul(sub(padded_data_size, data_size), 8)
if iszero(is_right_padded(padding_size_bits, end_word)) { revert_with_panic(153) }
if iszero(is_right_padded(padding_size_bits, end_word)) { revert_with_Panic_uint256(153) }
return_val := ccopym(add(data_start, 32), sub(data_size, 32))
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ expression: "abi_functions::decode_component_uint(32, AbiDecodeLocation::Memory)
function abi_decode_component_uint256_mem(head_start, offset) -> return_val {
let ptr := add(head_start, offset)
return_val := mload(ptr)
if iszero(is_left_padded(0, return_val)) { revert_with_panic(153) }
if iszero(is_left_padded(0, return_val)) { revert_with_Panic_uint256(153) }
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
source: crates/yulgen/tests/yulgen.rs
expression: "abi_functions::decode_data(&[Base::Bool, Base::Address],\n AbiDecodeLocation::Memory)"
expression: "abi_functions::decode_data(&[AbiType::Bool, AbiType::Address],\n AbiDecodeLocation::Memory)"

---
function abi_decode_data_bool_address_mem(head_start, data_end) -> return_val_0, return_val_1 {
let encoding_size := sub(data_end, head_start)
if iszero(eq(encoding_size, 64)) { revert_with_panic(153) }
if iszero(eq(encoding_size, 64)) { revert_with_Panic_uint256(153) }
let head_offset_0 := 0
let head_offset_1 := 32
let decoded_val_0 := abi_decode_component_bool_mem(head_start, head_offset_0)
let decoded_val_1 := abi_decode_component_address_mem(head_start, head_offset_1)
if iszero(eq(encoding_size, 64)) { revert_with_panic(153) }
if iszero(eq(encoding_size, 64)) { revert_with_Panic_uint256(153) }
return_val_0 := decoded_val_0
return_val_1 := decoded_val_1
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
source: crates/yulgen/tests/yulgen.rs
expression: "abi_functions::decode_data(&[FixedSize::u256(),\n FixedSize::Array(Array{inner:\n Base::Numeric(Integer::U8),\n size: 100,}),\n FixedSize::String(FeString{max_size: 42,}),\n FixedSize::bool(), FixedSize::address(),\n FixedSize::Array(Array{inner:\n Base::Numeric(Integer::U8),\n size: 100,})],\n AbiDecodeLocation::Calldata)"
expression: "abi_functions::decode_data(&[AbiType::Uint{size: 32,},\n AbiType::Bytes{size: 100,},\n AbiType::String{max_size: 42,}, AbiType::Bool,\n AbiType::Address, AbiType::Bytes{size: 100,}],\n AbiDecodeLocation::Calldata)"

---
function abi_decode_data_uint256_bytes_100_string_42_bool_address_bytes_100_calldata(head_start, data_end) -> return_val_0, return_val_1, return_val_2, return_val_3, return_val_4, return_val_5 {
let encoding_size := sub(data_end, head_start)
if or(lt(encoding_size, 544), gt(encoding_size, 608)) { revert_with_panic(153) }
if or(lt(encoding_size, 544), gt(encoding_size, 608)) { revert_with_Panic_uint256(153) }
let head_offset_0 := 0
let head_offset_1 := 32
let head_offset_2 := 64
Expand All @@ -18,10 +18,10 @@ function abi_decode_data_uint256_bytes_100_string_42_bool_address_bytes_100_call
let decoded_val_3 := abi_decode_component_bool_calldata(head_start, head_offset_3)
let decoded_val_4 := abi_decode_component_address_calldata(head_start, head_offset_4)
let decoded_val_5, data_start_offset_5, data_end_offset_5 := abi_decode_component_bytes_100_calldata(head_start, head_offset_5)
if iszero(eq(data_start_offset_1, 192)) { revert_with_panic(153) }
if iszero(eq(data_start_offset_2, data_end_offset_1)) { revert_with_panic(153) }
if iszero(eq(data_start_offset_5, data_end_offset_2)) { revert_with_panic(153) }
if iszero(eq(encoding_size, data_end_offset_5)) { revert_with_panic(153) }
if iszero(eq(data_start_offset_1, 192)) { revert_with_Panic_uint256(153) }
if iszero(eq(data_start_offset_2, data_end_offset_1)) { revert_with_Panic_uint256(153) }
if iszero(eq(data_start_offset_5, data_end_offset_2)) { revert_with_Panic_uint256(153) }
if iszero(eq(encoding_size, data_end_offset_5)) { revert_with_Panic_uint256(153) }
return_val_0 := decoded_val_0
return_val_1 := decoded_val_1
return_val_2 := decoded_val_2
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
source: crates/yulgen/tests/yulgen.rs
expression: "revert_functions::generate_revert_fn_for_assert(&[AbiType::String{max_size:\n 3,}])"
expression: "revert_functions::error_revert(&AbiType::String{max_size: 3,})"

---
function revert_with_Error_string_3(params_val_0) {
function revert_with_Error_string_3(val) {
let ptr := alloc_mstoren(0x08c379a0, 4)
pop(abi_encode_string_3(params_val_0))
revert(ptr, add(4, add(64, ceil32(mload(params_val_0)))))
pop(abi_encode_string_3(val))
revert(ptr, add(4, add(64, ceil32(mload(val)))))
}
2 changes: 1 addition & 1 deletion crates/yulgen/tests/yulgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,5 +220,5 @@ test_yulgen! {
// revert functions
test_yulgen! {
revert_string_error,
revert_functions::generate_revert_fn_for_assert(&[AbiType::String { max_size: 3 }])
revert_functions::error_revert(&AbiType::String { max_size: 3 })
}

0 comments on commit 8133e19

Please sign in to comment.