git.delta.rocks / unique-network / refs/commits / 12cd6cb586e3

difftreelog

source

crates/evm-coder/src/abi.rs13.1 KiBsourcehistory
1//! TODO: I misunterstood therminology, abi IS rlp encoded, so2//! this module should be replaced with rlp crate34#![allow(dead_code)]56#[cfg(not(feature = "std"))]7use alloc::vec::Vec;8use evm_core::ExitError;9use primitive_types::{H160, U256};1011use crate::{12	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},13	types::string,14};15use crate::execution::Result;1617const ABI_ALIGNMENT: usize = 32;1819#[derive(Clone)]20pub struct AbiReader<'i> {21	buf: &'i [u8],22	subresult_offset: usize,23	offset: usize,24}25impl<'i> AbiReader<'i> {26	pub fn new(buf: &'i [u8]) -> Self {27		Self {28			buf,29			subresult_offset: 0,30			offset: 0,31		}32	}33	pub fn new_call(buf: &'i [u8]) -> Result<(u32, Self)> {34		if buf.len() < 4 {35			return Err(Error::Error(ExitError::OutOfOffset));36		}37		let mut method_id = [0; 4];38		method_id.copy_from_slice(&buf[0..4]);3940		Ok((41			u32::from_be_bytes(method_id),42			Self {43				buf,44				subresult_offset: 4,45				offset: 4,46			},47		))48	}4950	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {51		if self.buf.len() - self.offset < ABI_ALIGNMENT {52			return Err(Error::Error(ExitError::OutOfOffset));53		}54		let mut block = [0; S];55		// Verify padding is empty56		if !self.buf[self.offset..self.offset + ABI_ALIGNMENT - S]57			.iter()58			.all(|&v| v == 0)59		{60			return Err(Error::Error(ExitError::InvalidRange));61		}62		block.copy_from_slice(63			&self.buf[self.offset + ABI_ALIGNMENT - S..self.offset + ABI_ALIGNMENT],64		);65		self.offset += ABI_ALIGNMENT;66		Ok(block)67	}6869	pub fn address(&mut self) -> Result<H160> {70		Ok(H160(self.read_padleft()?))71	}7273	pub fn bool(&mut self) -> Result<bool> {74		let data: [u8; 1] = self.read_padleft()?;75		match data[0] {76			0 => Ok(false),77			1 => Ok(true),78			_ => Err(Error::Error(ExitError::InvalidRange)),79		}80	}8182	pub fn bytes4(&mut self) -> Result<[u8; 4]> {83		self.read_padleft()84	}8586	pub fn bytes(&mut self) -> Result<Vec<u8>> {87		let mut subresult = self.subresult()?;88		let length = subresult.read_usize()?;89		if subresult.buf.len() <= subresult.offset + length {90			return Err(Error::Error(ExitError::OutOfOffset));91		}92		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())93	}94	pub fn string(&mut self) -> Result<string> {95		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))96	}9798	pub fn uint8(&mut self) -> Result<u8> {99		Ok(self.read_padleft::<1>()?[0])100	}101102	pub fn uint32(&mut self) -> Result<u32> {103		Ok(u32::from_be_bytes(self.read_padleft()?))104	}105106	pub fn uint128(&mut self) -> Result<u128> {107		Ok(u128::from_be_bytes(self.read_padleft()?))108	}109110	pub fn uint256(&mut self) -> Result<U256> {111		let buf: [u8; 32] = self.read_padleft()?;112		Ok(U256::from_big_endian(&buf))113	}114115	pub fn uint64(&mut self) -> Result<u64> {116		Ok(u64::from_be_bytes(self.read_padleft()?))117	}118119	pub fn read_usize(&mut self) -> Result<usize> {120		Ok(usize::from_be_bytes(self.read_padleft()?))121	}122123	fn subresult(&mut self) -> Result<AbiReader<'i>> {124		let offset = self.read_usize()?;125		if offset + self.subresult_offset > self.buf.len() {126			return Err(Error::Error(ExitError::InvalidRange));127		}128		Ok(AbiReader {129			buf: self.buf,130			subresult_offset: offset + self.subresult_offset,131			offset: offset + self.subresult_offset,132		})133	}134135	pub fn is_finished(&self) -> bool {136		self.buf.len() == self.offset137	}138}139140#[derive(Default)]141pub struct AbiWriter {142	static_part: Vec<u8>,143	dynamic_part: Vec<(usize, AbiWriter)>,144}145impl AbiWriter {146	pub fn new() -> Self {147		Self::default()148	}149	pub fn new_call(method_id: u32) -> Self {150		let mut val = Self::new();151		val.static_part.extend(&method_id.to_be_bytes());152		val153	}154155	fn write_padleft(&mut self, block: &[u8]) {156		assert!(block.len() <= ABI_ALIGNMENT);157		self.static_part158			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);159		self.static_part.extend(block);160	}161162	fn write_padright(&mut self, bytes: &[u8]) {163		assert!(bytes.len() <= ABI_ALIGNMENT);164		self.static_part.extend(bytes);165		self.static_part166			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);167	}168169	pub fn address(&mut self, address: &H160) {170		self.write_padleft(&address.0)171	}172173	pub fn bool(&mut self, value: &bool) {174		self.write_padleft(&[if *value { 1 } else { 0 }])175	}176177	pub fn uint8(&mut self, value: &u8) {178		self.write_padleft(&[*value])179	}180181	pub fn uint32(&mut self, value: &u32) {182		self.write_padleft(&u32::to_be_bytes(*value))183	}184185	pub fn uint128(&mut self, value: &u128) {186		self.write_padleft(&u128::to_be_bytes(*value))187	}188189	pub fn uint256(&mut self, value: &U256) {190		let mut out = [0; 32];191		value.to_big_endian(&mut out);192		self.write_padleft(&out)193	}194195	pub fn write_usize(&mut self, value: &usize) {196		self.write_padleft(&usize::to_be_bytes(*value))197	}198199	pub fn write_subresult(&mut self, result: Self) {200		self.dynamic_part.push((self.static_part.len(), result));201		// Empty block, to be filled later202		self.write_padleft(&[]);203	}204205	pub fn memory(&mut self, value: &[u8]) {206		let mut sub = Self::new();207		sub.write_usize(&value.len());208		for chunk in value.chunks(ABI_ALIGNMENT) {209			sub.write_padright(chunk);210		}211		self.write_subresult(sub);212	}213214	pub fn string(&mut self, value: &str) {215		self.memory(value.as_bytes())216	}217218	pub fn bytes(&mut self, value: &[u8]) {219		self.memory(value)220	}221222	pub fn finish(mut self) -> Vec<u8> {223		for (static_offset, part) in self.dynamic_part {224			let part_offset = self.static_part.len();225226			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);227			self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()228				..static_offset + ABI_ALIGNMENT]229				.copy_from_slice(&encoded_dynamic_offset);230			self.static_part.extend(part.finish())231		}232		self.static_part233	}234}235236pub trait AbiRead<T> {237	fn abi_read(&mut self) -> Result<T>;238}239240macro_rules! impl_abi_readable {241	($ty:ty, $method:ident) => {242		impl AbiRead<$ty> for AbiReader<'_> {243			fn abi_read(&mut self) -> Result<$ty> {244				self.$method()245			}246		}247	};248}249250impl_abi_readable!(u8, uint8);251impl_abi_readable!(u32, uint32);252impl_abi_readable!(u64, uint64);253impl_abi_readable!(u128, uint128);254impl_abi_readable!(U256, uint256);255impl_abi_readable!(H160, address);256impl_abi_readable!(Vec<u8>, bytes);257impl_abi_readable!(bool, bool);258impl_abi_readable!(string, string);259260mod sealed {261	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead262	pub trait CanBePlacedInVec {}263}264265impl sealed::CanBePlacedInVec for U256 {}266impl sealed::CanBePlacedInVec for string {}267impl sealed::CanBePlacedInVec for H160 {}268269impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>270where271	Self: AbiRead<R>,272{273	fn abi_read(&mut self) -> Result<Vec<R>> {274		let mut sub = self.subresult()?;275		let size = sub.read_usize()?;276		sub.subresult_offset = sub.offset;277		let mut out = Vec::with_capacity(size);278		for _ in 0..size {279			out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);280		}281		Ok(out)282	}283}284285macro_rules! impl_tuples {286	($($ident:ident)+) => {287		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}288		impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>289		where290			$(Self: AbiRead<$ident>),+291		{292			fn abi_read(&mut self) -> Result<($($ident,)+)> {293				let mut subresult = self.subresult()?;294				Ok((295					$(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+296				))297			}298		}299	};300}301302impl_tuples! {A}303impl_tuples! {A B}304impl_tuples! {A B C}305impl_tuples! {A B C D}306impl_tuples! {A B C D E}307impl_tuples! {A B C D E F}308impl_tuples! {A B C D E F G}309impl_tuples! {A B C D E F G H}310impl_tuples! {A B C D E F G H I}311impl_tuples! {A B C D E F G H I J}312313pub trait AbiWrite {314	fn abi_write(&self, writer: &mut AbiWriter);315	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {316		let mut writer = AbiWriter::new();317		self.abi_write(&mut writer);318		Ok(writer.into())319	}320}321322impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {323	// this particular AbiWrite implementation should be split to another trait,324	// which only implements [`to_result`]325	//326	// But due to lack of specialization feature in stable Rust, we can't have327	// blanket impl of this trait `for T where T: AbiWrite`, so here we abusing328	// default trait methods for it329	fn abi_write(&self, _writer: &mut AbiWriter) {330		debug_assert!(false, "shouldn't be called, see comment")331	}332	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {333		match self {334			Ok(v) => Ok(WithPostDispatchInfo {335				post_info: v.post_info.clone(),336				data: {337					let mut out = AbiWriter::new();338					v.data.abi_write(&mut out);339					out340				},341			}),342			Err(e) => Err(e.clone()),343		}344	}345}346347macro_rules! impl_abi_writeable {348	($ty:ty, $method:ident) => {349		impl AbiWrite for $ty {350			fn abi_write(&self, writer: &mut AbiWriter) {351				writer.$method(&self)352			}353		}354	};355}356357impl_abi_writeable!(u8, uint8);358impl_abi_writeable!(u32, uint32);359impl_abi_writeable!(u128, uint128);360impl_abi_writeable!(U256, uint256);361impl_abi_writeable!(H160, address);362impl_abi_writeable!(bool, bool);363impl_abi_writeable!(&str, string);364impl AbiWrite for &string {365	fn abi_write(&self, writer: &mut AbiWriter) {366		writer.string(self)367	}368}369impl AbiWrite for &Vec<u8> {370	fn abi_write(&self, writer: &mut AbiWriter) {371		writer.bytes(self)372	}373}374375impl AbiWrite for () {376	fn abi_write(&self, _writer: &mut AbiWriter) {}377}378379#[macro_export]380macro_rules! abi_decode {381	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {382		$(383			let $name = $reader.$typ()?;384		)+385	}386}387#[macro_export]388macro_rules! abi_encode {389	($($typ:ident($value:expr)),* $(,)?) => {{390		#[allow(unused_mut)]391		let mut writer = ::evm_coder::abi::AbiWriter::new();392		$(393			writer.$typ($value);394		)*395		writer396	}};397	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{398		#[allow(unused_mut)]399		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);400		$(401			writer.$typ($value);402		)*403		writer404	}}405}406407#[cfg(test)]408pub mod test {409	use crate::{410		abi::AbiRead,411		types::{string, uint256},412	};413414	use super::{AbiReader, AbiWriter};415	use hex_literal::hex;416417	#[test]418	fn dynamic_after_static() {419		let mut encoder = AbiWriter::new();420		encoder.bool(&true);421		encoder.string("test");422		let encoded = encoder.finish();423424		let mut encoder = AbiWriter::new();425		encoder.bool(&true);426		// Offset to subresult427		encoder.uint32(&(32 * 2));428		// Len of "test"429		encoder.uint32(&4);430		encoder.write_padright(&[b't', b'e', b's', b't']);431		let alternative_encoded = encoder.finish();432433		assert_eq!(encoded, alternative_encoded);434435		let mut decoder = AbiReader::new(&encoded);436		assert_eq!(decoder.bool().unwrap(), true);437		assert_eq!(decoder.string().unwrap(), "test");438	}439440	#[test]441	fn mint_sample() {442		let (call, mut decoder) = AbiReader::new_call(&hex!(443			"444				50bb4e7f445				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374446				0000000000000000000000000000000000000000000000000000000000000001447				0000000000000000000000000000000000000000000000000000000000000060448				0000000000000000000000000000000000000000000000000000000000000008449				5465737420555249000000000000000000000000000000000000000000000000450			"451		))452		.unwrap();453		assert_eq!(call, 0x50bb4e7f);454		assert_eq!(455			format!("{:?}", decoder.address().unwrap()),456			"0xad2c0954693c2b5404b7e50967d3481bea432374"457		);458		assert_eq!(decoder.uint32().unwrap(), 1);459		assert_eq!(decoder.string().unwrap(), "Test URI");460	}461462	#[test]463	fn mint_bulk() {464		let (call, mut decoder) = AbiReader::new_call(&hex!(465			"466				36543006467				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address468				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]469				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]470471				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem472				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem473				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem474475				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60476				0000000000000000000000000000000000000000000000000000000000000040 // offset of string477				000000000000000000000000000000000000000000000000000000000000000a // size of string478				5465737420555249203000000000000000000000000000000000000000000000 // string479480				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0481				0000000000000000000000000000000000000000000000000000000000000040 // offset of string482				000000000000000000000000000000000000000000000000000000000000000a // size of string483				5465737420555249203100000000000000000000000000000000000000000000 // string484485				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160486				0000000000000000000000000000000000000000000000000000000000000040 // offset of string487				000000000000000000000000000000000000000000000000000000000000000a // size of string488				5465737420555249203200000000000000000000000000000000000000000000 // string489			"490		))491		.unwrap();492		assert_eq!(call, 0x36543006);493		let _ = decoder.address().unwrap();494		let data =495			<AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();496		assert_eq!(497			data,498			vec![499				(1.into(), "Test URI 0".to_string()),500				(11.into(), "Test URI 1".to_string()),501				(12.into(), "Test URI 2".to_string())502			]503		);504	}505}