--- a/Cargo.lock +++ b/Cargo.lock @@ -2169,7 +2169,7 @@ [[package]] name = "evm-coder" -version = "0.1.1" +version = "0.1.2" dependencies = [ "ethereum", "evm-coder-procedural", @@ -2178,6 +2178,7 @@ "hex-literal", "impl-trait-for-tuples", "primitive-types", + "sp-std", ] [[package]] --- a/crates/evm-coder/CHANGELOG.md +++ b/crates/evm-coder/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [0.1.3] - 2022-08-29 + +### Fixed + + - Parsing simple values. + ## [v0.1.2] 2022-08-19 @@ -21,4 +27,4 @@ - build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b \ No newline at end of file +- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b --- a/crates/evm-coder/Cargo.toml +++ b/crates/evm-coder/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evm-coder" -version = "0.1.1" +version = "0.1.2" license = "GPLv3" edition = "2021" @@ -11,8 +11,9 @@ primitive-types = { version = "0.11.1", default-features = false } # Evm doesn't have reexports for log and others ethereum = { version = "0.12.0", default-features = false } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" } # Error types for execution -evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" } +evm-core = { default-features = false , git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" } # We have tuple-heavy code in solidity.rs impl-trait-for-tuples = "0.2.2" --- a/crates/evm-coder/src/abi.rs +++ b/crates/evm-coder/src/abi.rs @@ -28,6 +28,7 @@ types::{string, self}, }; use crate::execution::Result; +use crate::solidity::SolidityTypeName; const ABI_ALIGNMENT: usize = 32; @@ -77,8 +78,8 @@ return Err(Error::Error(ExitError::OutOfOffset)); } let mut block = [0; S]; - // Verify padding is empty - if !buf[pad_start..pad_size].iter().all(|&v| v == 0) { + let is_pad_zeroed = !buf[pad_start..pad_size].iter().all(|&v| v == 0); + if is_pad_zeroed { return Err(Error::Error(ExitError::InvalidRange)); } block.copy_from_slice(&buf[block_start..block_size]); @@ -133,7 +134,7 @@ /// Read [`Vec`] at current position, then advance pub fn bytes(&mut self) -> Result> { - let mut subresult = self.subresult()?; + let mut subresult = self.subresult(None)?; let length = subresult.uint32()? as usize; if subresult.buf.len() < subresult.offset + length { return Err(Error::Error(ExitError::OutOfOffset)); @@ -179,15 +180,26 @@ } /// Slice recursive buffer, advance one word for buffer offset - fn subresult(&mut self) -> Result> { - let offset = self.uint32()? as usize; + /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`]. + fn subresult(&mut self, size: Option) -> Result> { + let subresult_offset = self.subresult_offset; + let offset = if let Some(size) = size { + self.offset += size; + self.subresult_offset += size; + 0 + } else { + self.uint32()? as usize + }; + if offset + self.subresult_offset > self.buf.len() { return Err(Error::Error(ExitError::InvalidRange)); } + + let new_offset = offset + subresult_offset; Ok(AbiReader { buf: self.buf, - subresult_offset: offset + self.subresult_offset, - offset: offset + self.subresult_offset, + subresult_offset: new_offset, + offset: new_offset, }) } @@ -355,7 +367,7 @@ Self: AbiRead, { fn abi_read(&mut self) -> Result> { - let mut sub = self.subresult()?; + let mut sub = self.subresult(None)?; let size = sub.uint32()? as usize; sub.subresult_offset = sub.offset; let mut out = Vec::with_capacity(size); @@ -366,15 +378,33 @@ } } +fn aligned_size(size: usize) -> usize { + let need_align = (size % ABI_ALIGNMENT) != 0; + let aligned_parts = size / ABI_ALIGNMENT; + (aligned_parts * ABI_ALIGNMENT) + if need_align { ABI_ALIGNMENT } else { 0 } +} + +#[test] +fn test_aligned_size() { + assert_eq!(aligned_size(20), ABI_ALIGNMENT); + assert_eq!(aligned_size(32), ABI_ALIGNMENT); + assert_eq!(aligned_size(52), 2 * ABI_ALIGNMENT); + assert_eq!(aligned_size(64), 2 * ABI_ALIGNMENT); +} + macro_rules! impl_tuples { ($($ident:ident)+) => { impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {} impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_> where - $(Self: AbiRead<$ident>),+ + $( + Self: AbiRead<$ident>, + )+ + ($($ident,)+): SolidityTypeName, { fn abi_read(&mut self) -> Result<($($ident,)+)> { - let mut subresult = self.subresult()?; + let size = if <($($ident,)+)>::is_simple() { Some(0 $(+aligned_size(sp_std::mem::size_of::<$ident>()))+) } else { None }; + let mut subresult = self.subresult(size)?; Ok(( $(>::abi_read(&mut subresult)?,)+ )) @@ -535,7 +565,7 @@ assert_eq!(encoded, alternative_encoded); let mut decoder = AbiReader::new(&encoded); - assert_eq!(decoder.bool().unwrap(), true); + assert!(decoder.bool().unwrap()); assert_eq!(decoder.string().unwrap(), "test"); } --- a/crates/evm-coder/src/solidity.rs +++ b/crates/evm-coder/src/solidity.rs @@ -192,7 +192,10 @@ write!(writer, "{}", tc.collect_tuple::()) } fn is_simple() -> bool { - false + true + $( + && <$ident>::is_simple() + )* } #[allow(unused_assignments)] fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -179,7 +179,12 @@ .weight_calls_budget(>::find_parent()); let amounts = amounts .into_iter() - .map(|(to, amount)| Ok((T::CrossAccountId::from_eth(to), amount.try_into().map_err(|_| "amount overflow")?))) + .map(|(to, amount)| { + Ok(( + T::CrossAccountId::from_eth(to), + amount.try_into().map_err(|_| "amount overflow")?, + )) + }) .collect::>()?; >::create_multiple_items(&self, &caller, amounts, &budget)