git.delta.rocks / unique-network / refs/commits / 420882b802b8

difftreelog

source

crates/evm-coder/src/abi.rs17.9 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//! Implementation of EVM RLP reader/writer1819#![allow(dead_code)]2021#[cfg(not(feature = "std"))]22use alloc::vec::Vec;23use evm_core::ExitError;24use primitive_types::{H160, U256};2526use crate::{27	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28	types::{string, self},29};30use crate::execution::Result;31use crate::solidity::SolidityTypeName;3233const ABI_ALIGNMENT: usize = 32;3435/// View into RLP data, which provides method to read typed items from it36#[derive(Clone)]37pub struct AbiReader<'i> {38	buf: &'i [u8],39	subresult_offset: usize,40	offset: usize,41}42impl<'i> AbiReader<'i> {43	/// Start reading RLP buffer, assuming there is no padding bytes44	pub fn new(buf: &'i [u8]) -> Self {45		Self {46			buf,47			subresult_offset: 0,48			offset: 0,49		}50	}51	/// Start reading RLP buffer, parsing first 4 bytes as selector52	pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {53		if buf.len() < 4 {54			return Err(Error::Error(ExitError::OutOfOffset));55		}56		let mut method_id = [0; 4];57		method_id.copy_from_slice(&buf[0..4]);5859		Ok((60			method_id,61			Self {62				buf,63				subresult_offset: 4,64				offset: 4,65			},66		))67	}6869	fn read_pad<const S: usize>(70		buf: &[u8],71		offset: usize,72		pad_start: usize,73		pad_size: usize,74		block_start: usize,75		block_size: usize,76	) -> Result<[u8; S]> {77		if buf.len() - offset < ABI_ALIGNMENT {78			return Err(Error::Error(ExitError::OutOfOffset));79		}80		let mut block = [0; S];81		let is_pad_zeroed = !buf[pad_start..pad_size].iter().all(|&v| v == 0);82		if is_pad_zeroed {83			return Err(Error::Error(ExitError::InvalidRange));84		}85		block.copy_from_slice(&buf[block_start..block_size]);86		Ok(block)87	}8889	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {90		let offset = self.offset;91		self.offset += ABI_ALIGNMENT;92		Self::read_pad(93			self.buf,94			offset,95			offset,96			offset + ABI_ALIGNMENT - S,97			offset + ABI_ALIGNMENT - S,98			offset + ABI_ALIGNMENT,99		)100	}101102	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {103		let offset = self.offset;104		self.offset += ABI_ALIGNMENT;105		Self::read_pad(106			self.buf,107			offset,108			offset + S,109			offset + ABI_ALIGNMENT,110			offset,111			offset + S,112		)113	}114115	/// Read [`H160`] at current position, then advance116	pub fn address(&mut self) -> Result<H160> {117		Ok(H160(self.read_padleft()?))118	}119120	/// Read [`bool`] at current position, then advance121	pub fn bool(&mut self) -> Result<bool> {122		let data: [u8; 1] = self.read_padleft()?;123		match data[0] {124			0 => Ok(false),125			1 => Ok(true),126			_ => Err(Error::Error(ExitError::InvalidRange)),127		}128	}129130	/// Read [`[u8; 4]`] at current position, then advance131	pub fn bytes4(&mut self) -> Result<[u8; 4]> {132		self.read_padright()133	}134135	/// Read [`Vec<u8>`] at current position, then advance136	pub fn bytes(&mut self) -> Result<Vec<u8>> {137		let mut subresult = self.subresult(None)?;138		let length = subresult.uint32()? as usize;139		if subresult.buf.len() < subresult.offset + length {140			return Err(Error::Error(ExitError::OutOfOffset));141		}142		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())143	}144145	/// Read [`string`] at current position, then advance146	pub fn string(&mut self) -> Result<string> {147		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))148	}149150	/// Read [`u8`] at current position, then advance151	pub fn uint8(&mut self) -> Result<u8> {152		Ok(self.read_padleft::<1>()?[0])153	}154155	/// Read [`u32`] at current position, then advance156	pub fn uint32(&mut self) -> Result<u32> {157		Ok(u32::from_be_bytes(self.read_padleft()?))158	}159160	/// Read [`u128`] at current position, then advance161	pub fn uint128(&mut self) -> Result<u128> {162		Ok(u128::from_be_bytes(self.read_padleft()?))163	}164165	/// Read [`U256`] at current position, then advance166	pub fn uint256(&mut self) -> Result<U256> {167		let buf: [u8; 32] = self.read_padleft()?;168		Ok(U256::from_big_endian(&buf))169	}170171	/// Read [`u64`] at current position, then advance172	pub fn uint64(&mut self) -> Result<u64> {173		Ok(u64::from_be_bytes(self.read_padleft()?))174	}175176	/// Read [`usize`] at current position, then advance177	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]178	pub fn read_usize(&mut self) -> Result<usize> {179		Ok(usize::from_be_bytes(self.read_padleft()?))180	}181182	/// Slice recursive buffer, advance one word for buffer offset183	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].184	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {185		let subresult_offset = self.subresult_offset;186		let offset = if let Some(size) = size {187			self.offset += size;188			self.subresult_offset += size;189			0190		} else {191			self.uint32()? as usize192		};193194		if offset + self.subresult_offset > self.buf.len() {195			return Err(Error::Error(ExitError::InvalidRange));196		}197198		let new_offset = offset + subresult_offset;199		Ok(AbiReader {200			buf: self.buf,201			subresult_offset: new_offset,202			offset: new_offset,203		})204	}205206	/// Is this parser reached end of buffer?207	pub fn is_finished(&self) -> bool {208		self.buf.len() == self.offset209	}210}211212/// Writer for RLP encoded data213#[derive(Default)]214pub struct AbiWriter {215	static_part: Vec<u8>,216	dynamic_part: Vec<(usize, AbiWriter)>,217	had_call: bool,218}219impl AbiWriter {220	/// Initialize internal buffers for output data, assuming no padding required221	pub fn new() -> Self {222		Self::default()223	}224	/// Initialize internal buffers, inserting method selector at beginning225	pub fn new_call(method_id: u32) -> Self {226		let mut val = Self::new();227		val.static_part.extend(&method_id.to_be_bytes());228		val.had_call = true;229		val230	}231232	fn write_padleft(&mut self, block: &[u8]) {233		assert!(block.len() <= ABI_ALIGNMENT);234		self.static_part235			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);236		self.static_part.extend(block);237	}238239	fn write_padright(&mut self, bytes: &[u8]) {240		assert!(bytes.len() <= ABI_ALIGNMENT);241		self.static_part.extend(bytes);242		self.static_part243			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);244	}245246	/// Write [`H160`] to end of buffer247	pub fn address(&mut self, address: &H160) {248		self.write_padleft(&address.0)249	}250251	/// Write [`bool`] to end of buffer252	pub fn bool(&mut self, value: &bool) {253		self.write_padleft(&[if *value { 1 } else { 0 }])254	}255256	/// Write [`u8`] to end of buffer257	pub fn uint8(&mut self, value: &u8) {258		self.write_padleft(&[*value])259	}260261	/// Write [`u32`] to end of buffer262	pub fn uint32(&mut self, value: &u32) {263		self.write_padleft(&u32::to_be_bytes(*value))264	}265266	/// Write [`u128`] to end of buffer267	pub fn uint128(&mut self, value: &u128) {268		self.write_padleft(&u128::to_be_bytes(*value))269	}270271	/// Write [`U256`] to end of buffer272	pub fn uint256(&mut self, value: &U256) {273		let mut out = [0; 32];274		value.to_big_endian(&mut out);275		self.write_padleft(&out)276	}277278	/// Write [`usize`] to end of buffer279	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]280	pub fn write_usize(&mut self, value: &usize) {281		self.write_padleft(&usize::to_be_bytes(*value))282	}283284	/// Append recursive data, writing pending offset at end of buffer285	pub fn write_subresult(&mut self, result: Self) {286		self.dynamic_part.push((self.static_part.len(), result));287		// Empty block, to be filled later288		self.write_padleft(&[]);289	}290291	fn memory(&mut self, value: &[u8]) {292		let mut sub = Self::new();293		sub.uint32(&(value.len() as u32));294		for chunk in value.chunks(ABI_ALIGNMENT) {295			sub.write_padright(chunk);296		}297		self.write_subresult(sub);298	}299300	/// Append recursive [`str`] at end of buffer301	pub fn string(&mut self, value: &str) {302		self.memory(value.as_bytes())303	}304305	/// Append recursive [`[u8]`] at end of buffer306	pub fn bytes(&mut self, value: &[u8]) {307		self.memory(value)308	}309310	/// Finish writer, concatenating all internal buffers311	pub fn finish(mut self) -> Vec<u8> {312		for (static_offset, part) in self.dynamic_part {313			let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);314315			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);316			self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()317				..static_offset + ABI_ALIGNMENT]318				.copy_from_slice(&encoded_dynamic_offset);319			self.static_part.extend(part.finish())320		}321		self.static_part322	}323}324325/// [`AbiReader`] implements reading of many types, but it should326/// be limited to types defined in spec327///328/// As this trait can't be made sealed,329/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`330pub trait AbiRead<T> {331	/// Read item from current position, advanding decoder332	fn abi_read(&mut self) -> Result<T>;333}334335macro_rules! impl_abi_readable {336	($ty:ty, $method:ident) => {337		impl AbiRead<$ty> for AbiReader<'_> {338			fn abi_read(&mut self) -> Result<$ty> {339				self.$method()340			}341		}342	};343}344345impl_abi_readable!(u8, uint8);346impl_abi_readable!(u32, uint32);347impl_abi_readable!(u64, uint64);348impl_abi_readable!(u128, uint128);349impl_abi_readable!(U256, uint256);350impl_abi_readable!([u8; 4], bytes4);351impl_abi_readable!(H160, address);352impl_abi_readable!(Vec<u8>, bytes);353impl_abi_readable!(bool, bool);354impl_abi_readable!(string, string);355356mod sealed {357	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead358	pub trait CanBePlacedInVec {}359}360361impl sealed::CanBePlacedInVec for U256 {}362impl sealed::CanBePlacedInVec for string {}363impl sealed::CanBePlacedInVec for H160 {}364365impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>366where367	Self: AbiRead<R>,368{369	fn abi_read(&mut self) -> Result<Vec<R>> {370		let mut sub = self.subresult(None)?;371		let size = sub.uint32()? as usize;372		sub.subresult_offset = sub.offset;373		let mut out = Vec::with_capacity(size);374		for _ in 0..size {375			out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);376		}377		Ok(out)378	}379}380381fn aligned_size(size: usize) -> usize {382	let need_align = (size % ABI_ALIGNMENT) != 0;383	let aligned_parts = size / ABI_ALIGNMENT;384	(aligned_parts * ABI_ALIGNMENT) + if need_align { ABI_ALIGNMENT } else { 0 }385}386387#[test]388fn test_aligned_size() {389	assert_eq!(aligned_size(20), ABI_ALIGNMENT);390	assert_eq!(aligned_size(32), ABI_ALIGNMENT);391	assert_eq!(aligned_size(52), 2 * ABI_ALIGNMENT);392	assert_eq!(aligned_size(64), 2 * ABI_ALIGNMENT);393}394395macro_rules! impl_tuples {396	($($ident:ident)+) => {397		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}398		impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>399		where400			$(401				Self: AbiRead<$ident>,402			)+403			($($ident,)+): SolidityTypeName,404		{405			fn abi_read(&mut self) -> Result<($($ident,)+)> {406				let size = if <($($ident,)+)>::is_simple() { Some(0 $(+aligned_size(sp_std::mem::size_of::<$ident>()))+) } else { None };407				let mut subresult = self.subresult(size)?;408				Ok((409					$(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+410				))411			}412		}413		#[allow(non_snake_case)]414		impl<$($ident),+> AbiWrite for &($($ident,)+)415		where416			$($ident: AbiWrite,)+417		{418			fn abi_write(&self, writer: &mut AbiWriter) {419				let ($($ident,)+) = self;420				$($ident.abi_write(writer);)+421			}422		}423	};424}425426impl_tuples! {A}427impl_tuples! {A B}428impl_tuples! {A B C}429impl_tuples! {A B C D}430impl_tuples! {A B C D E}431impl_tuples! {A B C D E F}432impl_tuples! {A B C D E F G}433impl_tuples! {A B C D E F G H}434impl_tuples! {A B C D E F G H I}435impl_tuples! {A B C D E F G H I J}436437/// For questions about inability to provide custom implementations,438/// see [`AbiRead`]439pub trait AbiWrite {440	/// Write value to end of specified encoder441	fn abi_write(&self, writer: &mut AbiWriter);442	/// Specialization for [`crate::solidity_interface`] implementation,443	/// see comment in `impl AbiWrite for ResultWithPostInfo`444	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {445		let mut writer = AbiWriter::new();446		self.abi_write(&mut writer);447		Ok(writer.into())448	}449}450451/// This particular AbiWrite implementation should be split to another trait,452/// which only implements `to_result`, but due to lack of specialization feature453/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,454/// so here we abusing default trait methods for it455impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {456	fn abi_write(&self, _writer: &mut AbiWriter) {457		debug_assert!(false, "shouldn't be called, see comment")458	}459	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {460		match self {461			Ok(v) => Ok(WithPostDispatchInfo {462				post_info: v.post_info.clone(),463				data: {464					let mut out = AbiWriter::new();465					v.data.abi_write(&mut out);466					out467				},468			}),469			Err(e) => Err(e.clone()),470		}471	}472}473474macro_rules! impl_abi_writeable {475	($ty:ty, $method:ident) => {476		impl AbiWrite for $ty {477			fn abi_write(&self, writer: &mut AbiWriter) {478				writer.$method(&self)479			}480		}481	};482}483484impl_abi_writeable!(u8, uint8);485impl_abi_writeable!(u32, uint32);486impl_abi_writeable!(u128, uint128);487impl_abi_writeable!(U256, uint256);488impl_abi_writeable!(H160, address);489impl_abi_writeable!(bool, bool);490impl_abi_writeable!(&str, string);491impl AbiWrite for &string {492	fn abi_write(&self, writer: &mut AbiWriter) {493		writer.string(self)494	}495}496impl AbiWrite for &Vec<u8> {497	fn abi_write(&self, writer: &mut AbiWriter) {498		writer.bytes(self)499	}500}501502impl AbiWrite for () {503	fn abi_write(&self, _writer: &mut AbiWriter) {}504}505506/// Helper macros to parse reader into variables507#[deprecated]508#[macro_export]509macro_rules! abi_decode {510	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {511		$(512			let $name = $reader.$typ()?;513		)+514	}515}516517/// Helper macros to construct RLP-encoded buffer518#[deprecated]519#[macro_export]520macro_rules! abi_encode {521	($($typ:ident($value:expr)),* $(,)?) => {{522		#[allow(unused_mut)]523		let mut writer = ::evm_coder::abi::AbiWriter::new();524		$(525			writer.$typ($value);526		)*527		writer528	}};529	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{530		#[allow(unused_mut)]531		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);532		$(533			writer.$typ($value);534		)*535		writer536	}}537}538539#[cfg(test)]540pub mod test {541	use crate::{542		abi::AbiRead,543		types::{string, uint256},544	};545546	use super::{AbiReader, AbiWriter};547	use hex_literal::hex;548549	#[test]550	fn dynamic_after_static() {551		let mut encoder = AbiWriter::new();552		encoder.bool(&true);553		encoder.string("test");554		let encoded = encoder.finish();555556		let mut encoder = AbiWriter::new();557		encoder.bool(&true);558		// Offset to subresult559		encoder.uint32(&(32 * 2));560		// Len of "test"561		encoder.uint32(&4);562		encoder.write_padright(&[b't', b'e', b's', b't']);563		let alternative_encoded = encoder.finish();564565		assert_eq!(encoded, alternative_encoded);566567		let mut decoder = AbiReader::new(&encoded);568		assert!(decoder.bool().unwrap());569		assert_eq!(decoder.string().unwrap(), "test");570	}571572	#[test]573	fn mint_sample() {574		let (call, mut decoder) = AbiReader::new_call(&hex!(575			"576				50bb4e7f577				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374578				0000000000000000000000000000000000000000000000000000000000000001579				0000000000000000000000000000000000000000000000000000000000000060580				0000000000000000000000000000000000000000000000000000000000000008581				5465737420555249000000000000000000000000000000000000000000000000582			"583		))584		.unwrap();585		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));586		assert_eq!(587			format!("{:?}", decoder.address().unwrap()),588			"0xad2c0954693c2b5404b7e50967d3481bea432374"589		);590		assert_eq!(decoder.uint32().unwrap(), 1);591		assert_eq!(decoder.string().unwrap(), "Test URI");592	}593594	#[test]595	fn mint_bulk() {596		let (call, mut decoder) = AbiReader::new_call(&hex!(597			"598				36543006599				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address600				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]601				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]602603				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem604				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem605				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem606607				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60608				0000000000000000000000000000000000000000000000000000000000000040 // offset of string609				000000000000000000000000000000000000000000000000000000000000000a // size of string610				5465737420555249203000000000000000000000000000000000000000000000 // string611612				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0613				0000000000000000000000000000000000000000000000000000000000000040 // offset of string614				000000000000000000000000000000000000000000000000000000000000000a // size of string615				5465737420555249203100000000000000000000000000000000000000000000 // string616617				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160618				0000000000000000000000000000000000000000000000000000000000000040 // offset of string619				000000000000000000000000000000000000000000000000000000000000000a // size of string620				5465737420555249203200000000000000000000000000000000000000000000 // string621			"622		))623		.unwrap();624		assert_eq!(call, u32::to_be_bytes(0x36543006));625		let _ = decoder.address().unwrap();626		let data =627			<AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();628		assert_eq!(629			data,630			vec![631				(1.into(), "Test URI 0".to_string()),632				(11.into(), "Test URI 1".to_string()),633				(12.into(), "Test URI 2".to_string())634			]635		);636	}637}