Skip to content

Commit

Permalink
testing
Browse files Browse the repository at this point in the history
  • Loading branch information
g-r-a-n-t committed Jul 9, 2021
1 parent e447871 commit d08da22
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 596 deletions.
2 changes: 1 addition & 1 deletion crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl AbiType {
AbiType::Bool => false,
AbiType::Address => false,
AbiType::String { .. } => true,
AbiType::Bytes { .. } => true
AbiType::Bytes { .. } => true,
}
}
}
Expand Down
22 changes: 22 additions & 0 deletions crates/test-files/fixtures/features/abi_decode_checks.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
contract Foo:
pub def decode_u256(a: u256):
pass

pub def decode_u128_bool(a: u128, b: bool):
pass

pub def decode_u256_bytes_tuple_array(
a: u256,
b: u8[100],
c: (address, u8),
d: i16[26]
):
pass

pub def decode_string_address_bytes_bool(
a: String<80>,
b: address,
c: u8[1000],
d: bool
):
pass
32 changes: 27 additions & 5 deletions crates/test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,28 @@ impl ContractHarness {
name: &str,
input: &[ethabi::Token],
) -> evm::Capture<(evm::ExitReason, Vec<u8>), std::convert::Infallible> {
let input = self.build_calldata(name, input);
self.capture_call_raw_bytes(executor, input)
}

pub fn build_calldata(&self, name: &str, input: &[ethabi::Token]) -> Vec<u8> {
let function = &self.abi.functions[name][0];
function
.encode_input(input)
.unwrap_or_else(|_| panic!("Unable to encode input for {}", name))
}

pub fn capture_call_raw_bytes(
&self,
executor: &mut Executor,
input: Vec<u8>,
) -> evm::Capture<(evm::ExitReason, Vec<u8>), std::convert::Infallible> {
let context = evm::Context {
address: self.address,
caller: self.caller,
apparent_value: self.value,
};

let input = function
.encode_input(input)
.unwrap_or_else(|_| panic!("Unable to encode input for {}", name));

executor.call(self.address, None, input, None, false, context)
}

Expand Down Expand Up @@ -116,6 +126,13 @@ impl ContractHarness {
}
}

pub fn test_call_reverts(&self, executor: &mut Executor, input: Vec<u8>) {
match self.capture_call_raw_bytes(executor, input) {
evm::Capture::Exit((ExitReason::Revert(_), _)) => {}
_ => panic!("function did not revert"),
}
}

// Executor must be passed by value to get emitted events.
pub fn events_emitted(&self, executor: Executor, events: &[(&str, &[ethabi::Token])]) {
let raw_logs = executor
Expand Down Expand Up @@ -606,10 +623,15 @@ pub fn bytes_token(s: &str) -> ethabi::Token {
}

#[allow(dead_code)]
pub fn u256_array_token(v: &[u64]) -> ethabi::Token {
pub fn uint_array_token(v: &[u64]) -> ethabi::Token {
ethabi::Token::FixedArray(v.iter().map(|n| uint_token(*n)).collect())
}

#[allow(dead_code)]
pub fn int_array_token(v: &[i64]) -> ethabi::Token {
ethabi::Token::FixedArray(v.iter().map(|n| int_token(*n)).collect())
}

#[allow(dead_code)]
pub fn address_array_token(v: &[&str]) -> ethabi::Token {
ethabi::Token::FixedArray(v.iter().map(|s| address_token(s)).collect())
Expand Down
96 changes: 92 additions & 4 deletions crates/tests/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ fn return_array() {
&mut executor,
"bar",
&[uint_token(42)],
Some(&u256_array_token(&[0, 0, 0, 42, 0])),
Some(&uint_array_token(&[0, 0, 0, 42, 0])),
)
})
}
Expand All @@ -289,7 +289,7 @@ fn multi_param() {
&mut executor,
"bar",
&[uint_token(4), uint_token(42), uint_token(420)],
Some(&u256_array_token(&[4, 42, 420])),
Some(&uint_array_token(&[4, 42, 420])),
)
})
}
Expand Down Expand Up @@ -672,7 +672,7 @@ fn sized_vals_in_sto() {
let harness = deploy_contract(&mut executor, "sized_vals_in_sto.fe", "Foo", &[]);

let num = uint_token(68);
let nums = u256_array_token(&(0..42).into_iter().collect::<Vec<_>>());
let nums = uint_array_token(&(0..42).into_iter().collect::<Vec<_>>());
let string = string_token("there are 26 protons in fe");

harness.test_function(&mut executor, "write_num", &[num.clone()], None);
Expand Down Expand Up @@ -1130,7 +1130,7 @@ fn external_contract() {
&mut executor,
"call_build_array",
&[foo_address, uint_token(a), uint_token(b)],
Some(&u256_array_token(&[a, c, b])),
Some(&uint_array_token(&[a, c, b])),
);

foo_harness.events_emitted(executor, &[("MyEvent", &[my_num, my_addrs, my_string])]);
Expand Down Expand Up @@ -1278,3 +1278,91 @@ fn tuple_destructuring() {
);
});
}

#[test]
fn abi_decode_checks() {
with_executor(&|mut executor| {
let harness = deploy_contract(&mut executor, "abi_decode_checks.fe", "Foo", &[]);

// decode_u256
{
let input = [uint_token(99999999)];
let data = harness.build_calldata("decode_u256", &input);

// add a byte
let mut tampered_data = data.clone();
tampered_data.push(42);
harness.test_call_reverts(&mut executor, tampered_data);

// remove last 8 bytes
let mut tampered_data = data.clone();
tampered_data.truncate(data.len() - 8);
harness.test_call_reverts(&mut executor, tampered_data);
}

// decode_u128_bool
{
let input = [uint_token(99999999), bool_token(true)];
let data = harness.build_calldata("decode_u128_bool", &input);

// add a byte
let mut tampered_data = data.clone();
tampered_data.push(42);
harness.test_call_reverts(&mut executor, tampered_data);

// place non-zero byte in padded region of `u128`
let mut tampered_data = data.clone();
// 4 bytes past end of selector (4 + 4)
tampered_data[9] = 26;
harness.test_call_reverts(&mut executor, tampered_data);

// place non-zero byte in padded region of u128
let mut tampered_data = data.clone();
// 8 bytes past end of u128 (4 + 32 + 8)
tampered_data[44] = 1;
harness.test_call_reverts(&mut executor, tampered_data);
}

// decode_u256_bytes_tuple_array
// head_size = 32 + 32 + 64 + (26 * 32) = 960
{
let input = [
uint_token(99999999),
bytes_token(
iter::repeat("ten bytes.")
.take(10)
.collect::<String>()
.as_str(),
),
tuple_token(&[address_token("a"), uint_token(42)]),
int_array_token(&(-10..16).collect::<Vec<_>>()),
];
let data = harness.build_calldata("decode_u256_bytes_tuple_array", &input);

// add a byte
let mut tampered_data = data.clone();
tampered_data.push(42);
harness.test_call_reverts(&mut executor, tampered_data);

// give invalid length to bytes. it expects 100, we give 99
let mut tampered_data = data.clone();
// final byte in data size location for bytes[100] (4 + head_size + 31)
tampered_data[995] = 99;
harness.test_call_reverts(&mut executor, tampered_data);

// place non-zero byte in padded region of bytes
let mut tampered_data = data.clone();
// the first byte directly following the bytes' data (4 + head_size + 32 + 100)
tampered_data[1096] = 128; // set the first bit to `1`
harness.test_call_reverts(&mut executor, tampered_data);

// place non-zero byte in padded region of bytes
let mut tampered_data = data.clone();
// the first byte directly following the bytes' data (4 + head_size + 32 + 127)
tampered_data[1123] = 1; // set the last bit to `1`
// sanity check
assert_eq!(tampered_data.len(), 1124);
harness.test_call_reverts(&mut executor, tampered_data);
}
});
}
8 changes: 4 additions & 4 deletions crates/tests/src/stress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ fn data_copying_stress() {

harness.test_function(&mut executor, "emit_my_event", &[], None);

let my_array = u256_array_token(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let my_mutated_array = u256_array_token(&[1, 2, 3, 5, 5, 6, 7, 8, 9, 10]);
let my_array = uint_array_token(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let my_mutated_array = uint_array_token(&[1, 2, 3, 5, 5, 6, 7, 8, 9, 10]);

let my_addrs = address_array_token(&["0", "1", "2"]);
let my_second_addr = address_token("1");
Expand Down Expand Up @@ -80,7 +80,7 @@ fn data_copying_stress() {
&mut executor,
"assign_my_nums_and_return",
&[],
Some(&u256_array_token(&[42, 26, 0, 1, 255])),
Some(&uint_array_token(&[42, 26, 0, 1, 255])),
);

harness.test_function(&mut executor, "set_my_addrs", &[my_addrs], None);
Expand Down Expand Up @@ -112,7 +112,7 @@ fn abi_encoding_stress() {
let my_addrs = address_array_token(&["a", "b", "c", "d", "e"]);
let my_u128 = uint_token(42);
let my_string = string_token("my string");
let my_u16s = u256_array_token(&(0..255).collect::<Vec<_>>());
let my_u16s = uint_array_token(&(0..255).collect::<Vec<_>>());
let my_bool = bool_token(true);
let my_bytes = bytes_token(
iter::repeat("ten bytes.")
Expand Down
14 changes: 7 additions & 7 deletions crates/yulgen/src/operations/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub enum EncodingSize {
Exact(yul::Expression),
Bounded {
min: yul::Expression,
max: yul::Expression
}
max: yul::Expression,
},
}

/// Returns an expression that encodes the given values and returns a pointer to
Expand Down Expand Up @@ -58,13 +58,13 @@ pub fn encoding_known_size<T: AbiEncoding>(types: &[T]) -> EncodingSize {
AbiType::String { max_size } => {
min += 32;
max += ceil_32(max_size) + 32;
},
}
AbiType::Bytes { size } => {
let size = ceil_32(size) + 32;
min += size;
max += size;
},
_ => {},
}
_ => {}
}

(min, max)
Expand All @@ -75,7 +75,7 @@ pub fn encoding_known_size<T: AbiEncoding>(types: &[T]) -> EncodingSize {
} else {
EncodingSize::Bounded {
min: literal_expression! { (min) },
max: literal_expression! { (max) }
max: literal_expression! { (max) },
}
}
}
Expand Down Expand Up @@ -145,4 +145,4 @@ pub fn check_right_padding(size_bits: yul::Expression, val: yul::Expression) ->
(revert(0, 0))
}
}
}
}
6 changes: 4 additions & 2 deletions crates/yulgen/src/runtime/abi_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ fn dispatch_arm(attributes: FunctionAttributes) -> yul::Case {
&[attributes.return_type.clone()],
expressions! { return_val },
);
let encode_size =
abi_operations::encoding_size(&[attributes.return_type], expressions! { return_val });
let encode_size = abi_operations::encoding_size(
&[attributes.return_type],
expressions! { return_val },
);
statements! {
(let return_val := [call])
(let encode_start := [encode])
Expand Down
Loading

0 comments on commit d08da22

Please sign in to comment.