use crate::{revert, EvmResult};
use core::{any::type_name, ops::Range};
use impl_trait_for_tuples::impl_for_tuples;
use sp_core::{H160, H256, U256};
use sp_std::{borrow::ToOwned, convert::TryInto, vec, vec::Vec};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Address(pub H160);
impl From<H160> for Address {
fn from(a: H160) -> Address {
Address(a)
}
}
impl From<Address> for H160 {
fn from(a: Address) -> H160 {
a.0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Bytes(pub Vec<u8>);
impl Bytes {
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn as_str(&self) -> Result<&str, sp_std::str::Utf8Error> {
sp_std::str::from_utf8(&self.0)
}
}
impl From<&[u8]> for Bytes {
fn from(a: &[u8]) -> Self {
Self(a.to_owned())
}
}
impl From<&str> for Bytes {
fn from(a: &str) -> Self {
a.as_bytes().into()
}
}
impl Into<Vec<u8>> for Bytes {
fn into(self) -> Vec<u8> {
self.0
}
}
#[derive(Clone, Copy, Debug)]
pub struct EvmDataReader<'a> {
input: &'a [u8],
cursor: usize,
}
impl<'a> EvmDataReader<'a> {
pub fn new(input: &'a [u8]) -> Self {
Self { input, cursor: 0 }
}
pub fn read_selector<T>(input: &'a [u8]) -> EvmResult<T>
where
T: num_enum::TryFromPrimitive<Primitive = u32>,
{
if input.len() < 4 {
return Err(revert("tried to parse selector out of bounds"))
}
let mut buffer = [0u8; 4];
buffer.copy_from_slice(&input[0..4]);
let selector = T::try_from_primitive(u32::from_be_bytes(buffer)).map_err(|_| {
log::trace!(
target: "precompile-utils",
"Failed to match function selector for {}",
type_name::<T>()
);
revert("unknown selector")
})?;
Ok(selector)
}
pub fn new_skip_selector(input: &'a [u8]) -> EvmResult<Self> {
if input.len() < 4 {
return Err(revert("input is too short"))
}
Ok(Self::new(&input[4..]))
}
pub fn expect_arguments(&self, args: usize) -> EvmResult {
if self.input.len() >= self.cursor + args * 32 {
Ok(())
} else {
Err(revert("input doesn't match expected length"))
}
}
pub fn read<T: EvmData>(&mut self) -> EvmResult<T> {
T::read(self)
}
pub fn read_raw_bytes(&mut self, len: usize) -> EvmResult<&[u8]> {
let range = self.move_cursor(len)?;
let data = self
.input
.get(range)
.ok_or_else(|| revert("tried to parse raw bytes out of bounds"))?;
Ok(data)
}
pub fn read_pointer(&mut self) -> EvmResult<Self> {
let offset: usize = self
.read::<U256>()
.map_err(|_| revert("tried to parse array offset out of bounds"))?
.try_into()
.map_err(|_| revert("array offset is too large"))?;
if offset >= self.input.len() {
return Err(revert("pointer points out of bounds"))
}
Ok(Self {
input: &self.input[offset..],
cursor: 0,
})
}
pub fn read_till_end(&mut self) -> EvmResult<&[u8]> {
let range = self.move_cursor(self.input.len() - self.cursor)?;
let data = self
.input
.get(range)
.ok_or_else(|| revert("tried to parse raw bytes out of bounds"))?;
Ok(data)
}
fn move_cursor(&mut self, len: usize) -> EvmResult<Range<usize>> {
let start = self.cursor;
let end = self
.cursor
.checked_add(len)
.ok_or_else(|| revert("data reading cursor overflow"))?;
self.cursor = end;
Ok(start..end)
}
}
#[derive(Clone, Debug)]
pub struct EvmDataWriter {
pub(crate) data: Vec<u8>,
offset_data: Vec<OffsetDatum>,
selector: Option<u32>,
}
#[derive(Clone, Debug)]
struct OffsetDatum {
offset_position: usize,
data: Vec<u8>,
offset_shift: usize,
}
impl EvmDataWriter {
pub fn new() -> Self {
Self {
data: vec![],
offset_data: vec![],
selector: None,
}
}
pub fn new_with_selector(selector: impl Into<u32>) -> Self {
Self {
data: vec![],
offset_data: vec![],
selector: Some(selector.into()),
}
}
pub fn build(mut self) -> Vec<u8> {
Self::bake_offsets(&mut self.data, self.offset_data);
if let Some(selector) = self.selector {
let mut output = selector.to_be_bytes().to_vec();
output.append(&mut self.data);
output
} else {
self.data
}
}
fn bake_offsets(output: &mut Vec<u8>, offsets: Vec<OffsetDatum>) {
for mut offset_datum in offsets {
let offset_position = offset_datum.offset_position;
let offset_position_end = offset_position + 32;
let free_space_offset = output.len() - offset_datum.offset_shift;
U256::from(free_space_offset)
.to_big_endian(&mut output[offset_position..offset_position_end]);
output.append(&mut offset_datum.data);
}
}
fn write_raw_bytes(mut self, value: &[u8]) -> Self {
self.data.extend_from_slice(value);
self
}
pub fn write<T: EvmData>(mut self, value: T) -> Self {
T::write(&mut self, value);
self
}
pub fn write_pointer(&mut self, data: Vec<u8>) {
let offset_position = self.data.len();
H256::write(self, H256::repeat_byte(0xff));
self.offset_data.push(OffsetDatum {
offset_position,
data,
offset_shift: 0,
});
}
}
impl Default for EvmDataWriter {
fn default() -> Self {
Self::new()
}
}
pub trait EvmData: Sized {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self>;
fn write(writer: &mut EvmDataWriter, value: Self);
fn has_static_size() -> bool;
}
#[impl_for_tuples(1, 18)]
impl EvmData for Tuple {
fn has_static_size() -> bool {
for_tuples!(#( Tuple::has_static_size() )&*)
}
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
if !Self::has_static_size() {
let reader = &mut reader.read_pointer()?;
Ok(for_tuples!( ( #( reader.read::<Tuple>()? ),* ) ))
} else {
Ok(for_tuples!( ( #( reader.read::<Tuple>()? ),* ) ))
}
}
fn write(writer: &mut EvmDataWriter, value: Self) {
if !Self::has_static_size() {
let mut inner_writer = EvmDataWriter::new();
for_tuples!( #( Tuple::write(&mut inner_writer, value.Tuple); )* );
writer.write_pointer(inner_writer.build());
} else {
for_tuples!( #( Tuple::write(writer, value.Tuple); )* );
}
}
}
impl EvmData for H256 {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let range = reader.move_cursor(32)?;
let data = reader
.input
.get(range)
.ok_or_else(|| revert("tried to parse H256 out of bounds"))?;
Ok(H256::from_slice(data))
}
fn write(writer: &mut EvmDataWriter, value: Self) {
writer.data.extend_from_slice(value.as_bytes());
}
fn has_static_size() -> bool {
true
}
}
impl EvmData for Address {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let range = reader.move_cursor(32)?;
let data = reader
.input
.get(range)
.ok_or_else(|| revert("tried to parse H160 out of bounds"))?;
Ok(H160::from_slice(&data[12..32]).into())
}
fn write(writer: &mut EvmDataWriter, value: Self) {
H256::write(writer, value.0.into());
}
fn has_static_size() -> bool {
true
}
}
impl EvmData for U256 {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let range = reader.move_cursor(32)?;
let data = reader
.input
.get(range)
.ok_or_else(|| revert("tried to parse U256 out of bounds"))?;
Ok(U256::from_big_endian(data))
}
fn write(writer: &mut EvmDataWriter, value: Self) {
let mut buffer = [0u8; 32];
value.to_big_endian(&mut buffer);
writer.data.extend_from_slice(&buffer);
}
fn has_static_size() -> bool {
true
}
}
macro_rules! impl_evmdata_for_uints {
($($uint:ty, )*) => {
$(
impl EvmData for $uint {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let value256: U256 = reader.read()?;
let error_msg = "Value Too Big For Type";
value256
.try_into()
.map_err(|_| revert(error_msg.as_bytes()))
}
fn write(writer: &mut EvmDataWriter, value: Self) {
U256::write(writer, value.into());
}
fn has_static_size() -> bool {
true
}
}
)*
};
}
impl_evmdata_for_uints!(u8, u16, u32, u64, u128,);
impl EvmData for bool {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let h256 = H256::read(reader).map_err(|_| revert("tried to parse bool out of bounds"))?;
Ok(!h256.is_zero())
}
fn write(writer: &mut EvmDataWriter, value: Self) {
let mut buffer = [0u8; 32];
if value {
buffer[31] = 1;
}
writer.data.extend_from_slice(&buffer);
}
fn has_static_size() -> bool {
true
}
}
impl<T: EvmData> EvmData for Vec<T> {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let mut inner_reader = reader.read_pointer()?;
let array_size: usize = inner_reader
.read::<U256>()
.map_err(|_| revert("tried to parse array length out of bounds"))?
.try_into()
.map_err(|_| revert("array length is too large"))?;
let mut array = vec![];
let mut item_reader = EvmDataReader {
input: inner_reader
.input
.get(32..)
.ok_or_else(|| revert("try to read array items out of bound"))?,
cursor: 0,
};
for _ in 0..array_size {
array.push(item_reader.read()?);
}
Ok(array)
}
fn write(writer: &mut EvmDataWriter, value: Self) {
let mut inner_writer = EvmDataWriter::new().write(U256::from(value.len()));
for inner in value {
let shift = inner_writer.data.len();
let item_writer = EvmDataWriter::new().write(inner);
inner_writer = inner_writer.write_raw_bytes(&item_writer.data);
for mut offset_datum in item_writer.offset_data {
offset_datum.offset_shift += 32;
offset_datum.offset_position += shift;
inner_writer.offset_data.push(offset_datum);
}
}
writer.write_pointer(inner_writer.build());
}
fn has_static_size() -> bool {
false
}
}
impl EvmData for Bytes {
fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
let mut inner_reader = reader.read_pointer()?;
let array_size: usize = inner_reader
.read::<U256>()
.map_err(|_| revert("tried to parse bytes/string length out of bounds"))?
.try_into()
.map_err(|_| revert("bytes/string length is too large"))?;
let range = inner_reader.move_cursor(array_size)?;
let data = inner_reader
.input
.get(range)
.ok_or_else(|| revert("tried to parse bytes/string out of bounds"))?;
let bytes = Self(data.to_owned());
Ok(bytes)
}
fn write(writer: &mut EvmDataWriter, value: Self) {
let length = value.0.len();
let chunks = length / 32;
let padded_size = match length % 32 {
0 => chunks * 32,
_ => (chunks + 1) * 32,
};
let mut value = value.0.to_vec();
value.resize(padded_size, 0);
writer.write_pointer(
EvmDataWriter::new()
.write(U256::from(length))
.write_raw_bytes(&value)
.build(),
);
}
fn has_static_size() -> bool {
false
}
}