use super::utils::left_pad_to_32_bytes;
use super::Parameter;
use std::ops::Range;
pub fn encode_into(hash: &mut Vec<u8>, parameters: Vec<Parameter>) {
let dynamic_offset = hash.len();
let mut dynamic_type_map = Vec::<(usize, Range<usize>)>::with_capacity(parameters.len());
for (i, param) in parameters.iter().enumerate() {
if param.is_dynamic() {
dynamic_type_map.push((i, hash.len()..hash.len() + 32));
hash.extend_from_slice(&[0u8; 32]);
} else {
hash.extend_from_slice(¶m.static_encode());
}
}
for (index, range) in dynamic_type_map.into_iter() {
let offset = (hash.len() - dynamic_offset).to_be_bytes();
hash[range].copy_from_slice(&left_pad_to_32_bytes(&offset));
match ¶meters[index] {
Parameter::Array(data) | Parameter::Tuple(data) => {
hash.extend_from_slice(&left_pad_to_32_bytes(&data.len().to_be_bytes()));
encode_into(hash, data.to_vec());
}
_ => hash.extend_from_slice(¶meters[index].static_encode()),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use ethane_types::U256;
use hex_literal::hex;
#[test]
#[rustfmt::skip]
fn first_contract_abi() {
let mut hash = vec![0xaa, 0xbb, 0xcc, 0xdd];
encode_into(
&mut hash,
vec![Parameter::from(69u32), Parameter::from(true)],
);
assert_eq!(
hash,
vec![
0xaa, 0xbb, 0xcc, 0xdd, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x45, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x01, ]
);
}
#[test]
#[rustfmt::skip]
fn second_contract_abi() {
let mut hash = vec![0x10, 0x11, 0x12, 0x13];
encode_into(
&mut hash,
vec![Parameter::FixedArray(vec![
Parameter::new_fixed_bytes(&"abc".as_bytes()),
Parameter::new_fixed_bytes(&"def".as_bytes()),
])],
);
assert_eq!(
hash,
vec![
0x10, 0x11, 0x12, 0x13, 0x61, 0x62, 0x63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0x64, 0x65, 0x66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
]
);
}
#[test]
#[rustfmt::skip]
fn third_contract_abi() {
let mut hash = vec![0xff, 0xee, 0x00, 0x07];
encode_into(&mut hash, vec![
Parameter::new_bytes(b"dave"),
Parameter::from(true),
Parameter::Array(vec![
Parameter::from(U256::from_int_unchecked(1_u8)),
Parameter::from(U256::from_int_unchecked(2_u8)),
Parameter::from(U256::from_int_unchecked(3_u8)),
])
]);
assert_eq!(hash, vec![
0xff, 0xee, 0x00, 0x07, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x60, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0xa0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x04, 0x64, 0x61, 0x76, 0x65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x03, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x03, ]);
}
#[test]
#[rustfmt::skip]
fn fourth_contract_abi() {
let mut hash = vec![0x8b, 0xe6, 0x52, 0x46];
encode_into(&mut hash, vec![
Parameter::from(U256::from_int_unchecked(0x123_u16)),
Parameter::Array(vec![
Parameter::from(U256::from_int_unchecked(0x456_u16)), Parameter::from(U256::from_int_unchecked(0x789_u16)), ]),
Parameter::new_fixed_bytes(b"1234567890"),
Parameter::new_bytes(b"Hello, world!"),
]);
let expected = hex!(
"8be65246
0000000000000000000000000000000000000000000000000000000000000123
0000000000000000000000000000000000000000000000000000000000000080
3132333435363738393000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000e0
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000456
0000000000000000000000000000000000000000000000000000000000000789
000000000000000000000000000000000000000000000000000000000000000d
48656c6c6f2c20776f726c642100000000000000000000000000000000000000"
);
for i in 0..9 {
let start: usize = 4 + i * 32;
let end: usize = start + 32;
assert_eq!(hash[start..end], expected[start..end]);
}
}
#[test]
#[rustfmt::skip]
fn fifth_contract_abi() {
let mut hash = vec![1, 2, 3, 4];
encode_into(&mut hash, vec![
Parameter::Array(vec![
Parameter::Array(vec![
Parameter::from(U256::from_int_unchecked(1_u8)),
Parameter::from(U256::from_int_unchecked(2_u8)),
]),
Parameter::Array(vec![
Parameter::from(U256::from_int_unchecked(3_u8)),
]),
]),
Parameter::Array(vec![
Parameter::from("one"),
Parameter::from("two"),
Parameter::from("three"),
]),
]);
let expected = hex!(
"01020304
0000000000000000000000000000000000000000000000000000000000000040
0000000000000000000000000000000000000000000000000000000000000140
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000040
00000000000000000000000000000000000000000000000000000000000000a0
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000060
00000000000000000000000000000000000000000000000000000000000000a0
00000000000000000000000000000000000000000000000000000000000000e0
0000000000000000000000000000000000000000000000000000000000000003
6f6e650000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000003
74776f0000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000005
7468726565000000000000000000000000000000000000000000000000000000"
);
for i in 0..20 {
let start: usize = 4 + i * 32;
let end: usize = start + 32;
assert_eq!(hash[start..end], expected[start..end]);
}
}
}