git.delta.rocks / unique-network / refs/commits / 6bc9f6eef346

difftreelog

source

crates/evm-coder/src/abi.rs14.4 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! TODO: I misunterstood therminology, abi IS rlp encoded, so18//! this module should be replaced with rlp crate1920#![allow(dead_code)]2122#[cfg(not(feature = "std"))]23use alloc::vec::Vec;24use evm_core::ExitError;25use primitive_types::{H160, U256};2627use crate::{28	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},29	types::{string, self},30};31use crate::execution::Result;3233const ABI_ALIGNMENT: usize = 32;3435#[derive(Clone)]36pub struct AbiReader<'i> {37	buf: &'i [u8],38	subresult_offset: usize,39	offset: usize,40}41impl<'i> AbiReader<'i> {42	pub fn new(buf: &'i [u8]) -> Self {43		Self {44			buf,45			subresult_offset: 0,46			offset: 0,47		}48	}49	pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {50		if buf.len() < 4 {51			return Err(Error::Error(ExitError::OutOfOffset));52		}53		let mut method_id = [0; 4];54		method_id.copy_from_slice(&buf[0..4]);5556		Ok((57			method_id,58			Self {59				buf,60				subresult_offset: 4,61				offset: 4,62			},63		))64	}6566	fn read_pad<const S: usize>(67		buf: &[u8],68		offset: usize,69		pad_start: usize,70		pad_size: usize,71		block_start: usize,72		block_size: usize,73	) -> Result<[u8; S]> {74		if buf.len() - offset < ABI_ALIGNMENT {75			return Err(Error::Error(ExitError::OutOfOffset));76		}77		let mut block = [0; S];78		// Verify padding is empty79		if !buf[pad_start..pad_size].iter().all(|&v| v == 0) {80			return Err(Error::Error(ExitError::InvalidRange));81		}82		block.copy_from_slice(&buf[block_start..block_size]);83		Ok(block)84	}8586	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {87		let offset = self.offset;88		self.offset += ABI_ALIGNMENT;89		Self::read_pad(90			self.buf,91			offset,92			offset,93			offset + ABI_ALIGNMENT - S,94			offset + ABI_ALIGNMENT - S,95			offset + ABI_ALIGNMENT,96		)97	}9899	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {100		let offset = self.offset;101		self.offset += ABI_ALIGNMENT;102		Self::read_pad(103			self.buf,104			offset,105			offset + S,106			offset + ABI_ALIGNMENT,107			offset,108			offset + S,109		)110	}111112	pub fn address(&mut self) -> Result<H160> {113		Ok(H160(self.read_padleft()?))114	}115116	pub fn bool(&mut self) -> Result<bool> {117		let data: [u8; 1] = self.read_padleft()?;118		match data[0] {119			0 => Ok(false),120			1 => Ok(true),121			_ => Err(Error::Error(ExitError::InvalidRange)),122		}123	}124125	pub fn bytes4(&mut self) -> Result<[u8; 4]> {126		self.read_padright()127	}128129	pub fn bytes(&mut self) -> Result<Vec<u8>> {130		let mut subresult = self.subresult()?;131		let length = subresult.read_usize()?;132		if subresult.buf.len() < subresult.offset + length {133			return Err(Error::Error(ExitError::OutOfOffset));134		}135		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())136	}137	pub fn string(&mut self) -> Result<string> {138		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))139	}140141	pub fn uint8(&mut self) -> Result<u8> {142		Ok(self.read_padleft::<1>()?[0])143	}144145	pub fn uint32(&mut self) -> Result<u32> {146		Ok(u32::from_be_bytes(self.read_padleft()?))147	}148149	pub fn uint128(&mut self) -> Result<u128> {150		Ok(u128::from_be_bytes(self.read_padleft()?))151	}152153	pub fn uint256(&mut self) -> Result<U256> {154		let buf: [u8; 32] = self.read_padleft()?;155		Ok(U256::from_big_endian(&buf))156	}157158	pub fn uint64(&mut self) -> Result<u64> {159		Ok(u64::from_be_bytes(self.read_padleft()?))160	}161162	pub fn read_usize(&mut self) -> Result<usize> {163		Ok(usize::from_be_bytes(self.read_padleft()?))164	}165166	fn subresult(&mut self) -> Result<AbiReader<'i>> {167		let offset = self.read_usize()?;168		if offset + self.subresult_offset > self.buf.len() {169			return Err(Error::Error(ExitError::InvalidRange));170		}171		Ok(AbiReader {172			buf: self.buf,173			subresult_offset: offset + self.subresult_offset,174			offset: offset + self.subresult_offset,175		})176	}177178	pub fn is_finished(&self) -> bool {179		self.buf.len() == self.offset180	}181}182183#[derive(Default)]184pub struct AbiWriter {185	static_part: Vec<u8>,186	dynamic_part: Vec<(usize, AbiWriter)>,187	had_call: bool,188}189impl AbiWriter {190	pub fn new() -> Self {191		Self::default()192	}193	pub fn new_call(method_id: u32) -> Self {194		let mut val = Self::new();195		val.static_part.extend(&method_id.to_be_bytes());196		val.had_call = true;197		val198	}199200	fn write_padleft(&mut self, block: &[u8]) {201		assert!(block.len() <= ABI_ALIGNMENT);202		self.static_part203			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);204		self.static_part.extend(block);205	}206207	fn write_padright(&mut self, bytes: &[u8]) {208		assert!(bytes.len() <= ABI_ALIGNMENT);209		self.static_part.extend(bytes);210		self.static_part211			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);212	}213214	pub fn address(&mut self, address: &H160) {215		self.write_padleft(&address.0)216	}217218	pub fn bool(&mut self, value: &bool) {219		self.write_padleft(&[if *value { 1 } else { 0 }])220	}221222	pub fn uint8(&mut self, value: &u8) {223		self.write_padleft(&[*value])224	}225226	pub fn uint32(&mut self, value: &u32) {227		self.write_padleft(&u32::to_be_bytes(*value))228	}229230	pub fn uint128(&mut self, value: &u128) {231		self.write_padleft(&u128::to_be_bytes(*value))232	}233234	pub fn uint256(&mut self, value: &U256) {235		let mut out = [0; 32];236		value.to_big_endian(&mut out);237		self.write_padleft(&out)238	}239240	pub fn write_usize(&mut self, value: &usize) {241		self.write_padleft(&usize::to_be_bytes(*value))242	}243244	pub fn write_subresult(&mut self, result: Self) {245		self.dynamic_part.push((self.static_part.len(), result));246		// Empty block, to be filled later247		self.write_padleft(&[]);248	}249250	pub fn memory(&mut self, value: &[u8]) {251		let mut sub = Self::new();252		sub.write_usize(&value.len());253		for chunk in value.chunks(ABI_ALIGNMENT) {254			sub.write_padright(chunk);255		}256		self.write_subresult(sub);257	}258259	pub fn string(&mut self, value: &str) {260		self.memory(value.as_bytes())261	}262263	pub fn bytes(&mut self, value: &[u8]) {264		self.memory(value)265	}266267	pub fn finish(mut self) -> Vec<u8> {268		for (static_offset, part) in self.dynamic_part {269			let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);270271			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);272			self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()273				..static_offset + ABI_ALIGNMENT]274				.copy_from_slice(&encoded_dynamic_offset);275			self.static_part.extend(part.finish())276		}277		self.static_part278	}279}280281pub trait AbiRead<T> {282	fn abi_read(&mut self) -> Result<T>;283}284285macro_rules! impl_abi_readable {286	($ty:ty, $method:ident) => {287		impl AbiRead<$ty> for AbiReader<'_> {288			fn abi_read(&mut self) -> Result<$ty> {289				self.$method()290			}291		}292	};293}294295impl_abi_readable!(u8, uint8);296impl_abi_readable!(u32, uint32);297impl_abi_readable!(u64, uint64);298impl_abi_readable!(u128, uint128);299impl_abi_readable!(U256, uint256);300impl_abi_readable!([u8; 4], bytes4);301impl_abi_readable!(H160, address);302impl_abi_readable!(Vec<u8>, bytes);303impl_abi_readable!(bool, bool);304impl_abi_readable!(string, string);305306mod sealed {307	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead308	pub trait CanBePlacedInVec {}309}310311impl sealed::CanBePlacedInVec for U256 {}312impl sealed::CanBePlacedInVec for string {}313impl sealed::CanBePlacedInVec for H160 {}314315impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>316where317	Self: AbiRead<R>,318{319	fn abi_read(&mut self) -> Result<Vec<R>> {320		let mut sub = self.subresult()?;321		let size = sub.read_usize()?;322		sub.subresult_offset = sub.offset;323		let mut out = Vec::with_capacity(size);324		for _ in 0..size {325			out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);326		}327		Ok(out)328	}329}330331macro_rules! impl_tuples {332	($($ident:ident)+) => {333		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}334		impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>335		where336			$(Self: AbiRead<$ident>),+337		{338			fn abi_read(&mut self) -> Result<($($ident,)+)> {339				let mut subresult = self.subresult()?;340				Ok((341					$(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+342				))343			}344		}345	};346}347348impl_tuples! {A}349impl_tuples! {A B}350impl_tuples! {A B C}351impl_tuples! {A B C D}352impl_tuples! {A B C D E}353impl_tuples! {A B C D E F}354impl_tuples! {A B C D E F G}355impl_tuples! {A B C D E F G H}356impl_tuples! {A B C D E F G H I}357impl_tuples! {A B C D E F G H I J}358359pub trait AbiWrite {360	fn abi_write(&self, writer: &mut AbiWriter);361	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {362		let mut writer = AbiWriter::new();363		self.abi_write(&mut writer);364		Ok(writer.into())365	}366}367368impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {369	// this particular AbiWrite implementation should be split to another trait,370	// which only implements [`to_result`]371	//372	// But due to lack of specialization feature in stable Rust, we can't have373	// blanket impl of this trait `for T where T: AbiWrite`, so here we abusing374	// default trait methods for it375	fn abi_write(&self, _writer: &mut AbiWriter) {376		debug_assert!(false, "shouldn't be called, see comment")377	}378	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {379		match self {380			Ok(v) => Ok(WithPostDispatchInfo {381				post_info: v.post_info.clone(),382				data: {383					let mut out = AbiWriter::new();384					v.data.abi_write(&mut out);385					out386				},387			}),388			Err(e) => Err(e.clone()),389		}390	}391}392393macro_rules! impl_abi_writeable {394	($ty:ty, $method:ident) => {395		impl AbiWrite for $ty {396			fn abi_write(&self, writer: &mut AbiWriter) {397				writer.$method(&self)398			}399		}400	};401}402403impl_abi_writeable!(u8, uint8);404impl_abi_writeable!(u32, uint32);405impl_abi_writeable!(u128, uint128);406impl_abi_writeable!(U256, uint256);407impl_abi_writeable!(H160, address);408impl_abi_writeable!(bool, bool);409impl_abi_writeable!(&str, string);410impl AbiWrite for &string {411	fn abi_write(&self, writer: &mut AbiWriter) {412		writer.string(self)413	}414}415impl AbiWrite for &Vec<u8> {416	fn abi_write(&self, writer: &mut AbiWriter) {417		writer.bytes(self)418	}419}420421impl AbiWrite for () {422	fn abi_write(&self, _writer: &mut AbiWriter) {}423}424425#[macro_export]426macro_rules! abi_decode {427	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {428		$(429			let $name = $reader.$typ()?;430		)+431	}432}433#[macro_export]434macro_rules! abi_encode {435	($($typ:ident($value:expr)),* $(,)?) => {{436		#[allow(unused_mut)]437		let mut writer = ::evm_coder::abi::AbiWriter::new();438		$(439			writer.$typ($value);440		)*441		writer442	}};443	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{444		#[allow(unused_mut)]445		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);446		$(447			writer.$typ($value);448		)*449		writer450	}}451}452453#[cfg(test)]454pub mod test {455	use crate::{456		abi::AbiRead,457		types::{string, uint256},458	};459460	use super::{AbiReader, AbiWriter};461	use hex_literal::hex;462463	#[test]464	fn dynamic_after_static() {465		let mut encoder = AbiWriter::new();466		encoder.bool(&true);467		encoder.string("test");468		let encoded = encoder.finish();469470		let mut encoder = AbiWriter::new();471		encoder.bool(&true);472		// Offset to subresult473		encoder.uint32(&(32 * 2));474		// Len of "test"475		encoder.uint32(&4);476		encoder.write_padright(&[b't', b'e', b's', b't']);477		let alternative_encoded = encoder.finish();478479		assert_eq!(encoded, alternative_encoded);480481		let mut decoder = AbiReader::new(&encoded);482		assert_eq!(decoder.bool().unwrap(), true);483		assert_eq!(decoder.string().unwrap(), "test");484	}485486	#[test]487	fn mint_sample() {488		let (call, mut decoder) = AbiReader::new_call(&hex!(489			"490				50bb4e7f491				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374492				0000000000000000000000000000000000000000000000000000000000000001493				0000000000000000000000000000000000000000000000000000000000000060494				0000000000000000000000000000000000000000000000000000000000000008495				5465737420555249000000000000000000000000000000000000000000000000496			"497		))498		.unwrap();499		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));500		assert_eq!(501			format!("{:?}", decoder.address().unwrap()),502			"0xad2c0954693c2b5404b7e50967d3481bea432374"503		);504		assert_eq!(decoder.uint32().unwrap(), 1);505		assert_eq!(decoder.string().unwrap(), "Test URI");506	}507508	#[test]509	fn mint_bulk() {510		let (call, mut decoder) = AbiReader::new_call(&hex!(511			"512				36543006513				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address514				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]515				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]516517				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem518				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem519				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem520521				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60522				0000000000000000000000000000000000000000000000000000000000000040 // offset of string523				000000000000000000000000000000000000000000000000000000000000000a // size of string524				5465737420555249203000000000000000000000000000000000000000000000 // string525526				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0527				0000000000000000000000000000000000000000000000000000000000000040 // offset of string528				000000000000000000000000000000000000000000000000000000000000000a // size of string529				5465737420555249203100000000000000000000000000000000000000000000 // string530531				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160532				0000000000000000000000000000000000000000000000000000000000000040 // offset of string533				000000000000000000000000000000000000000000000000000000000000000a // size of string534				5465737420555249203200000000000000000000000000000000000000000000 // string535			"536		))537		.unwrap();538		assert_eq!(call, u32::to_be_bytes(0x36543006));539		let _ = decoder.address().unwrap();540		let data =541			<AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();542		assert_eq!(543			data,544			vec![545				(1.into(), "Test URI 0".to_string()),546				(11.into(), "Test URI 1".to_string()),547				(12.into(), "Test URI 2".to_string())548			]549		);550	}551}