difftreelog
feat Add AbiWrite support for vec with dynamic type
in: master
6 files changed
crates/evm-coder/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -22,6 +22,7 @@
# We want to assert some large binary blobs equality in tests
hex = "0.4.3"
hex-literal = "0.3.4"
+similar-asserts = "1.4.2"
[features]
default = ["std"]
crates/evm-coder/src/abi.rsdiffbeforeafterboth1// 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;3132const ABI_ALIGNMENT: usize = 32;3334trait TypeHelper {35 /// Is type dynamic sized.36 fn is_dynamic() -> bool;3738 /// Size for type aligned to [`ABI_ALIGNMENT`].39 fn size() -> usize;40}4142/// View into RLP data, which provides method to read typed items from it43#[derive(Clone)]44pub struct AbiReader<'i> {45 buf: &'i [u8],46 subresult_offset: usize,47 offset: usize,48}49impl<'i> AbiReader<'i> {50 /// Start reading RLP buffer, assuming there is no padding bytes51 pub fn new(buf: &'i [u8]) -> Self {52 Self {53 buf,54 subresult_offset: 0,55 offset: 0,56 }57 }58 /// Start reading RLP buffer, parsing first 4 bytes as selector59 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {60 if buf.len() < 4 {61 return Err(Error::Error(ExitError::OutOfOffset));62 }63 let mut method_id = [0; 4];64 method_id.copy_from_slice(&buf[0..4]);6566 Ok((67 method_id,68 Self {69 buf,70 subresult_offset: 4,71 offset: 4,72 },73 ))74 }7576 fn read_pad<const S: usize>(77 buf: &[u8],78 offset: usize,79 pad_start: usize,80 pad_size: usize,81 block_start: usize,82 block_size: usize,83 ) -> Result<[u8; S]> {84 if buf.len() - offset < ABI_ALIGNMENT {85 return Err(Error::Error(ExitError::OutOfOffset));86 }87 let mut block = [0; S];88 let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);89 if !is_pad_zeroed {90 return Err(Error::Error(ExitError::InvalidRange));91 }92 block.copy_from_slice(&buf[block_start..block_size]);93 Ok(block)94 }9596 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {97 let offset = self.offset;98 self.offset += ABI_ALIGNMENT;99 Self::read_pad(100 self.buf,101 offset,102 offset,103 offset + ABI_ALIGNMENT - S,104 offset + ABI_ALIGNMENT - S,105 offset + ABI_ALIGNMENT,106 )107 }108109 fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {110 let offset = self.offset;111 self.offset += ABI_ALIGNMENT;112 Self::read_pad(113 self.buf,114 offset,115 offset + S,116 offset + ABI_ALIGNMENT,117 offset,118 offset + S,119 )120 }121122 /// Read [`H160`] at current position, then advance123 pub fn address(&mut self) -> Result<H160> {124 Ok(H160(self.read_padleft()?))125 }126127 /// Read [`bool`] at current position, then advance128 pub fn bool(&mut self) -> Result<bool> {129 let data: [u8; 1] = self.read_padleft()?;130 match data[0] {131 0 => Ok(false),132 1 => Ok(true),133 _ => Err(Error::Error(ExitError::InvalidRange)),134 }135 }136137 /// Read [`[u8; 4]`] at current position, then advance138 pub fn bytes4(&mut self) -> Result<[u8; 4]> {139 self.read_padright()140 }141142 /// Read [`Vec<u8>`] at current position, then advance143 pub fn bytes(&mut self) -> Result<Vec<u8>> {144 let mut subresult = self.subresult(None)?;145 let length = subresult.uint32()? as usize;146 if subresult.buf.len() < subresult.offset + length {147 return Err(Error::Error(ExitError::OutOfOffset));148 }149 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())150 }151152 /// Read [`string`] at current position, then advance153 pub fn string(&mut self) -> Result<string> {154 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))155 }156157 /// Read [`u8`] at current position, then advance158 pub fn uint8(&mut self) -> Result<u8> {159 Ok(self.read_padleft::<1>()?[0])160 }161162 /// Read [`u32`] at current position, then advance163 pub fn uint32(&mut self) -> Result<u32> {164 Ok(u32::from_be_bytes(self.read_padleft()?))165 }166167 /// Read [`u128`] at current position, then advance168 pub fn uint128(&mut self) -> Result<u128> {169 Ok(u128::from_be_bytes(self.read_padleft()?))170 }171172 /// Read [`U256`] at current position, then advance173 pub fn uint256(&mut self) -> Result<U256> {174 let buf: [u8; 32] = self.read_padleft()?;175 Ok(U256::from_big_endian(&buf))176 }177178 /// Read [`u64`] at current position, then advance179 pub fn uint64(&mut self) -> Result<u64> {180 Ok(u64::from_be_bytes(self.read_padleft()?))181 }182183 /// Read [`usize`] at current position, then advance184 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]185 pub fn read_usize(&mut self) -> Result<usize> {186 Ok(usize::from_be_bytes(self.read_padleft()?))187 }188189 /// Slice recursive buffer, advance one word for buffer offset190 /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].191 fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {192 let subresult_offset = self.subresult_offset;193 let offset = if let Some(size) = size {194 self.offset += size;195 self.subresult_offset += size;196 0197 } else {198 self.uint32()? as usize199 };200201 if offset + self.subresult_offset > self.buf.len() {202 return Err(Error::Error(ExitError::InvalidRange));203 }204205 let new_offset = offset + subresult_offset;206 Ok(AbiReader {207 buf: self.buf,208 subresult_offset: new_offset,209 offset: new_offset,210 })211 }212213 /// Is this parser reached end of buffer?214 pub fn is_finished(&self) -> bool {215 self.buf.len() == self.offset216 }217}218219/// Writer for RLP encoded data220#[derive(Default)]221pub struct AbiWriter {222 static_part: Vec<u8>,223 dynamic_part: Vec<(usize, AbiWriter)>,224 had_call: bool,225 is_dynamic: bool,226}227impl AbiWriter {228 /// Initialize internal buffers for output data, assuming no padding required229 pub fn new() -> Self {230 Self::default()231 }232233 /// Initialize internal buffers with data size234 pub fn new_dynamic(is_dynamic: bool) -> Self {235 Self {236 is_dynamic,237 ..Default::default()238 }239 }240 /// Initialize internal buffers, inserting method selector at beginning241 pub fn new_call(method_id: u32) -> Self {242 let mut val = Self::new();243 val.static_part.extend(&method_id.to_be_bytes());244 val.had_call = true;245 val246 }247248 fn write_padleft(&mut self, block: &[u8]) {249 assert!(block.len() <= ABI_ALIGNMENT);250 self.static_part251 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);252 self.static_part.extend(block);253 }254255 fn write_padright(&mut self, bytes: &[u8]) {256 assert!(bytes.len() <= ABI_ALIGNMENT);257 self.static_part.extend(bytes);258 self.static_part259 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);260 }261262 /// Write [`H160`] to end of buffer263 pub fn address(&mut self, address: &H160) {264 self.write_padleft(&address.0)265 }266267 /// Write [`bool`] to end of buffer268 pub fn bool(&mut self, value: &bool) {269 self.write_padleft(&[if *value { 1 } else { 0 }])270 }271272 /// Write [`u8`] to end of buffer273 pub fn uint8(&mut self, value: &u8) {274 self.write_padleft(&[*value])275 }276277 /// Write [`u32`] to end of buffer278 pub fn uint32(&mut self, value: &u32) {279 self.write_padleft(&u32::to_be_bytes(*value))280 }281282 /// Write [`u128`] to end of buffer283 pub fn uint128(&mut self, value: &u128) {284 self.write_padleft(&u128::to_be_bytes(*value))285 }286287 /// Write [`U256`] to end of buffer288 pub fn uint256(&mut self, value: &U256) {289 let mut out = [0; 32];290 value.to_big_endian(&mut out);291 self.write_padleft(&out)292 }293294 /// Write [`usize`] to end of buffer295 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]296 pub fn write_usize(&mut self, value: &usize) {297 self.write_padleft(&usize::to_be_bytes(*value))298 }299300 /// Append recursive data, writing pending offset at end of buffer301 pub fn write_subresult(&mut self, result: Self) {302 self.dynamic_part.push((self.static_part.len(), result));303 // Empty block, to be filled later304 self.write_padleft(&[]);305 }306307 fn memory(&mut self, value: &[u8]) {308 let mut sub = Self::new();309 sub.uint32(&(value.len() as u32));310 for chunk in value.chunks(ABI_ALIGNMENT) {311 sub.write_padright(chunk);312 }313 self.write_subresult(sub);314 }315316 /// Append recursive [`str`] at end of buffer317 pub fn string(&mut self, value: &str) {318 self.memory(value.as_bytes())319 }320321 /// Append recursive [`[u8]`] at end of buffer322 pub fn bytes(&mut self, value: &[u8]) {323 self.memory(value)324 }325326 /// Finish writer, concatenating all internal buffers327 pub fn finish(mut self) -> Vec<u8> {328 for (static_offset, part) in self.dynamic_part {329 let part_offset = self.static_part.len()330 - if self.had_call { 4 } else { 0 }331 - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };332333 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);334 let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();335 let stop = static_offset + ABI_ALIGNMENT;336 self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);337 self.static_part.extend(part.finish())338 }339 self.static_part340 }341}342343/// [`AbiReader`] implements reading of many types, but it should344/// be limited to types defined in spec345///346/// As this trait can't be made sealed,347/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`348pub trait AbiRead<T> {349 /// Read item from current position, advanding decoder350 fn abi_read(&mut self) -> Result<T>;351}352353macro_rules! impl_abi_readable {354 ($ty:ty, $method:ident, $dynamic:literal) => {355 impl TypeHelper for $ty {356 fn is_dynamic() -> bool {357 $dynamic358 }359360 fn size() -> usize {361 ABI_ALIGNMENT362 }363 }364 impl AbiRead<$ty> for AbiReader<'_> {365 fn abi_read(&mut self) -> Result<$ty> {366 self.$method()367 }368 }369 };370}371372impl_abi_readable!(u8, uint8, false);373impl_abi_readable!(u32, uint32, false);374impl_abi_readable!(u64, uint64, false);375impl_abi_readable!(u128, uint128, false);376impl_abi_readable!(U256, uint256, false);377impl_abi_readable!([u8; 4], bytes4, false);378impl_abi_readable!(H160, address, false);379impl_abi_readable!(Vec<u8>, bytes, true);380impl_abi_readable!(bool, bool, true);381impl_abi_readable!(string, string, true);382383mod sealed {384 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead385 pub trait CanBePlacedInVec {}386}387388impl sealed::CanBePlacedInVec for U256 {}389impl sealed::CanBePlacedInVec for string {}390impl sealed::CanBePlacedInVec for H160 {}391392impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>393where394 Self: AbiRead<R>,395{396 fn abi_read(&mut self) -> Result<Vec<R>> {397 let mut sub = self.subresult(None)?;398 let size = sub.uint32()? as usize;399 sub.subresult_offset = sub.offset;400 let mut out = Vec::with_capacity(size);401 for _ in 0..size {402 out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);403 }404 Ok(out)405 }406}407408macro_rules! impl_tuples {409 ($($ident:ident)+) => {410 impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)411 where412 $(413 $ident: TypeHelper,414 )+415 {416 fn is_dynamic() -> bool {417 false418 $(419 || <$ident>::is_dynamic()420 )*421 }422423 fn size() -> usize {424 0 $(+ <$ident>::size())+425 }426 }427 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}428 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>429 where430 $(431 Self: AbiRead<$ident>,432 )+433 ($($ident,)+): TypeHelper,434 {435 fn abi_read(&mut self) -> Result<($($ident,)+)> {436 let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };437 let mut subresult = self.subresult(size)?;438 Ok((439 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+440 ))441 }442 }443 #[allow(non_snake_case)]444 impl<$($ident),+> AbiWrite for ($($ident,)+)445 where446 $($ident: AbiWrite,)+447 {448 fn abi_write(&self, writer: &mut AbiWriter) {449 let ($($ident,)+) = self;450 if writer.is_dynamic {451 let mut sub = AbiWriter::new();452 $($ident.abi_write(&mut sub);)+453 writer.write_subresult(sub);454 } else {455 $($ident.abi_write(writer);)+456 }457 }458 }459 };460}461462impl_tuples! {A}463impl_tuples! {A B}464impl_tuples! {A B C}465impl_tuples! {A B C D}466impl_tuples! {A B C D E}467impl_tuples! {A B C D E F}468impl_tuples! {A B C D E F G}469impl_tuples! {A B C D E F G H}470impl_tuples! {A B C D E F G H I}471impl_tuples! {A B C D E F G H I J}472473/// For questions about inability to provide custom implementations,474/// see [`AbiRead`]475pub trait AbiWrite {476 /// Write value to end of specified encoder477 fn abi_write(&self, writer: &mut AbiWriter);478 /// Specialization for [`crate::solidity_interface`] implementation,479 /// see comment in `impl AbiWrite for ResultWithPostInfo`480 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {481 let mut writer = AbiWriter::new();482 self.abi_write(&mut writer);483 Ok(writer.into())484 }485}486487/// This particular AbiWrite implementation should be split to another trait,488/// which only implements `to_result`, but due to lack of specialization feature489/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,490/// so here we abusing default trait methods for it491impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {492 fn abi_write(&self, _writer: &mut AbiWriter) {493 debug_assert!(false, "shouldn't be called, see comment")494 }495 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {496 match self {497 Ok(v) => Ok(WithPostDispatchInfo {498 post_info: v.post_info.clone(),499 data: {500 let mut out = AbiWriter::new();501 v.data.abi_write(&mut out);502 out503 },504 }),505 Err(e) => Err(e.clone()),506 }507 }508}509510macro_rules! impl_abi_writeable {511 ($ty:ty, $method:ident) => {512 impl AbiWrite for $ty {513 fn abi_write(&self, writer: &mut AbiWriter) {514 writer.$method(&self)515 }516 }517 };518}519520impl_abi_writeable!(u8, uint8);521impl_abi_writeable!(u32, uint32);522impl_abi_writeable!(u128, uint128);523impl_abi_writeable!(U256, uint256);524impl_abi_writeable!(H160, address);525impl_abi_writeable!(bool, bool);526impl_abi_writeable!(&str, string);527impl AbiWrite for string {528 fn abi_write(&self, writer: &mut AbiWriter) {529 writer.string(self)530 }531}532// impl AbiWrite for Vec<u8> {533// fn abi_write(&self, writer: &mut AbiWriter) {534// writer.bytes(self)535// }536// }537538impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {539 fn abi_write(&self, writer: &mut AbiWriter) {540 let is_dynamic = T::is_dynamic();541 let mut sub = if is_dynamic {542 AbiWriter::new_dynamic(is_dynamic)543 } else {544 AbiWriter::new()545 };546547 // Write items count548 (self.len() as u32).abi_write(&mut sub);549550 for item in self {551 item.abi_write(&mut sub);552 }553 writer.write_subresult(sub);554 }555}556557impl AbiWrite for () {558 fn abi_write(&self, _writer: &mut AbiWriter) {}559}560561/// Helper macros to parse reader into variables562#[deprecated]563#[macro_export]564macro_rules! abi_decode {565 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {566 $(567 let $name = $reader.$typ()?;568 )+569 }570}571572/// Helper macros to construct RLP-encoded buffer573#[deprecated]574#[macro_export]575macro_rules! abi_encode {576 ($($typ:ident($value:expr)),* $(,)?) => {{577 #[allow(unused_mut)]578 let mut writer = ::evm_coder::abi::AbiWriter::new();579 $(580 writer.$typ($value);581 )*582 writer583 }};584 (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{585 #[allow(unused_mut)]586 let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);587 $(588 writer.$typ($value);589 )*590 writer591 }}592}593594#[cfg(test)]595pub mod test {596 use crate::{597 abi::{AbiRead, AbiWrite},598 types::{string, uint256, address},599 };600601 use super::{AbiReader, AbiWriter};602 use hex_literal::hex;603 use primitive_types::{H160, U256};604605 #[test]606 fn dynamic_after_static() {607 let mut encoder = AbiWriter::new();608 encoder.bool(&true);609 encoder.string("test");610 let encoded = encoder.finish();611612 let mut encoder = AbiWriter::new();613 encoder.bool(&true);614 // Offset to subresult615 encoder.uint32(&(32 * 2));616 // Len of "test"617 encoder.uint32(&4);618 encoder.write_padright(&[b't', b'e', b's', b't']);619 let alternative_encoded = encoder.finish();620621 assert_eq!(encoded, alternative_encoded);622623 let mut decoder = AbiReader::new(&encoded);624 assert!(decoder.bool().unwrap());625 assert_eq!(decoder.string().unwrap(), "test");626 }627628 #[test]629 fn mint_sample() {630 let (call, mut decoder) = AbiReader::new_call(&hex!(631 "632 50bb4e7f633 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374634 0000000000000000000000000000000000000000000000000000000000000001635 0000000000000000000000000000000000000000000000000000000000000060636 0000000000000000000000000000000000000000000000000000000000000008637 5465737420555249000000000000000000000000000000000000000000000000638 "639 ))640 .unwrap();641 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));642 assert_eq!(643 format!("{:?}", decoder.address().unwrap()),644 "0xad2c0954693c2b5404b7e50967d3481bea432374"645 );646 assert_eq!(decoder.uint32().unwrap(), 1);647 assert_eq!(decoder.string().unwrap(), "Test URI");648 }649650 #[test]651 fn parse_vec_with_dynamic_type() {652 let decoded_data = (653 0x36543006,654 vec![655 (1.into(), "Test URI 0".to_string()),656 (11.into(), "Test URI 1".to_string()),657 (12.into(), "Test URI 2".to_string()),658 ],659 );660661 let encoded_data = &hex!(662 "663 36543006664 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address665 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]666 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]667668 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem669 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem670 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem671672 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60673 0000000000000000000000000000000000000000000000000000000000000040 // offset of string674 000000000000000000000000000000000000000000000000000000000000000a // size of string675 5465737420555249203000000000000000000000000000000000000000000000 // string676677 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0678 0000000000000000000000000000000000000000000000000000000000000040 // offset of string679 000000000000000000000000000000000000000000000000000000000000000a // size of string680 5465737420555249203100000000000000000000000000000000000000000000 // string681682 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160683 0000000000000000000000000000000000000000000000000000000000000040 // offset of string684 000000000000000000000000000000000000000000000000000000000000000a // size of string685 5465737420555249203200000000000000000000000000000000000000000000 // string686 "687 );688689 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();690 assert_eq!(call, u32::to_be_bytes(decoded_data.0));691 let address = decoder.address().unwrap();692 let data =693 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();694 assert_eq!(data, decoded_data.1);695696 let mut writer = AbiWriter::new_call(decoded_data.0);697 address.abi_write(&mut writer);698 decoded_data.1.abi_write(&mut writer);699 let ed = writer.finish();700 similar_asserts::assert_eq!(encoded_data, ed.as_slice());701 }702703 #[test]704 fn parse_vec_with_simple_type() {705 let decoded_data = (706 0x1ACF2D55,707 vec![708 (709 H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),710 U256([10, 0, 0, 0]),711 ),712 (713 H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),714 U256([20, 0, 0, 0]),715 ),716 (717 H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),718 U256([30, 0, 0, 0]),719 ),720 ],721 );722723 let encoded_data = &hex!(724 "725 1ACF2D55726 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]727 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]728729 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address730 000000000000000000000000000000000000000000000000000000000000000A // uint256731732 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address733 0000000000000000000000000000000000000000000000000000000000000014 // uint256734735 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address736 000000000000000000000000000000000000000000000000000000000000001E // uint256737 "738 );739740 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();741 assert_eq!(call, u32::to_be_bytes(decoded_data.0));742 let data =743 <AbiReader<'_> as AbiRead<Vec<(address, uint256)>>>::abi_read(&mut decoder).unwrap();744 assert_eq!(data.len(), 3);745 assert_eq!(data, decoded_data.1);746747 let mut writer = AbiWriter::new_call(decoded_data.0);748 decoded_data.1.abi_write(&mut writer);749 let ed = writer.finish();750 assert_eq!(encoded_data, ed.as_slice());751 }752}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::*,29};30use crate::execution::Result;3132const ABI_ALIGNMENT: usize = 32;3334trait TypeHelper {35 /// Is type dynamic sized.36 fn is_dynamic() -> bool;3738 /// Size for type aligned to [`ABI_ALIGNMENT`].39 fn size() -> usize;40}4142/// View into RLP data, which provides method to read typed items from it43#[derive(Clone)]44pub struct AbiReader<'i> {45 buf: &'i [u8],46 subresult_offset: usize,47 offset: usize,48}49impl<'i> AbiReader<'i> {50 /// Start reading RLP buffer, assuming there is no padding bytes51 pub fn new(buf: &'i [u8]) -> Self {52 Self {53 buf,54 subresult_offset: 0,55 offset: 0,56 }57 }58 /// Start reading RLP buffer, parsing first 4 bytes as selector59 pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {60 if buf.len() < 4 {61 return Err(Error::Error(ExitError::OutOfOffset));62 }63 let mut method_id = [0; 4];64 method_id.copy_from_slice(&buf[0..4]);6566 Ok((67 method_id,68 Self {69 buf,70 subresult_offset: 4,71 offset: 4,72 },73 ))74 }7576 fn read_pad<const S: usize>(77 buf: &[u8],78 offset: usize,79 pad_start: usize,80 pad_size: usize,81 block_start: usize,82 block_size: usize,83 ) -> Result<[u8; S]> {84 if buf.len() - offset < ABI_ALIGNMENT {85 return Err(Error::Error(ExitError::OutOfOffset));86 }87 let mut block = [0; S];88 let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);89 if !is_pad_zeroed {90 return Err(Error::Error(ExitError::InvalidRange));91 }92 block.copy_from_slice(&buf[block_start..block_size]);93 Ok(block)94 }9596 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {97 let offset = self.offset;98 self.offset += ABI_ALIGNMENT;99 Self::read_pad(100 self.buf,101 offset,102 offset,103 offset + ABI_ALIGNMENT - S,104 offset + ABI_ALIGNMENT - S,105 offset + ABI_ALIGNMENT,106 )107 }108109 fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {110 let offset = self.offset;111 self.offset += ABI_ALIGNMENT;112 Self::read_pad(113 self.buf,114 offset,115 offset + S,116 offset + ABI_ALIGNMENT,117 offset,118 offset + S,119 )120 }121122 /// Read [`H160`] at current position, then advance123 pub fn address(&mut self) -> Result<H160> {124 Ok(H160(self.read_padleft()?))125 }126127 /// Read [`bool`] at current position, then advance128 pub fn bool(&mut self) -> Result<bool> {129 let data: [u8; 1] = self.read_padleft()?;130 match data[0] {131 0 => Ok(false),132 1 => Ok(true),133 _ => Err(Error::Error(ExitError::InvalidRange)),134 }135 }136137 /// Read [`[u8; 4]`] at current position, then advance138 pub fn bytes4(&mut self) -> Result<[u8; 4]> {139 self.read_padright()140 }141142 /// Read [`Vec<u8>`] at current position, then advance143 pub fn bytes(&mut self) -> Result<Vec<u8>> {144 let mut subresult = self.subresult(None)?;145 let length = subresult.uint32()? as usize;146 if subresult.buf.len() < subresult.offset + length {147 return Err(Error::Error(ExitError::OutOfOffset));148 }149 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())150 }151152 /// Read [`string`] at current position, then advance153 pub fn string(&mut self) -> Result<string> {154 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))155 }156157 /// Read [`u8`] at current position, then advance158 pub fn uint8(&mut self) -> Result<u8> {159 Ok(self.read_padleft::<1>()?[0])160 }161162 /// Read [`u32`] at current position, then advance163 pub fn uint32(&mut self) -> Result<u32> {164 Ok(u32::from_be_bytes(self.read_padleft()?))165 }166167 /// Read [`u128`] at current position, then advance168 pub fn uint128(&mut self) -> Result<u128> {169 Ok(u128::from_be_bytes(self.read_padleft()?))170 }171172 /// Read [`U256`] at current position, then advance173 pub fn uint256(&mut self) -> Result<U256> {174 let buf: [u8; 32] = self.read_padleft()?;175 Ok(U256::from_big_endian(&buf))176 }177178 /// Read [`u64`] at current position, then advance179 pub fn uint64(&mut self) -> Result<u64> {180 Ok(u64::from_be_bytes(self.read_padleft()?))181 }182183 /// Read [`usize`] at current position, then advance184 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]185 pub fn read_usize(&mut self) -> Result<usize> {186 Ok(usize::from_be_bytes(self.read_padleft()?))187 }188189 /// Slice recursive buffer, advance one word for buffer offset190 /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].191 fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {192 let subresult_offset = self.subresult_offset;193 let offset = if let Some(size) = size {194 self.offset += size;195 self.subresult_offset += size;196 0197 } else {198 self.uint32()? as usize199 };200201 if offset + self.subresult_offset > self.buf.len() {202 return Err(Error::Error(ExitError::InvalidRange));203 }204205 let new_offset = offset + subresult_offset;206 Ok(AbiReader {207 buf: self.buf,208 subresult_offset: new_offset,209 offset: new_offset,210 })211 }212213 /// Is this parser reached end of buffer?214 pub fn is_finished(&self) -> bool {215 self.buf.len() == self.offset216 }217}218219/// Writer for RLP encoded data220#[derive(Default)]221pub struct AbiWriter {222 static_part: Vec<u8>,223 dynamic_part: Vec<(usize, AbiWriter)>,224 had_call: bool,225 is_dynamic: bool,226}227impl AbiWriter {228 /// Initialize internal buffers for output data, assuming no padding required229 pub fn new() -> Self {230 Self::default()231 }232233 /// Initialize internal buffers with data size234 pub fn new_dynamic(is_dynamic: bool) -> Self {235 Self {236 is_dynamic,237 ..Default::default()238 }239 }240 /// Initialize internal buffers, inserting method selector at beginning241 pub fn new_call(method_id: u32) -> Self {242 let mut val = Self::new();243 val.static_part.extend(&method_id.to_be_bytes());244 val.had_call = true;245 val246 }247248 fn write_padleft(&mut self, block: &[u8]) {249 assert!(block.len() <= ABI_ALIGNMENT);250 self.static_part251 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);252 self.static_part.extend(block);253 }254255 fn write_padright(&mut self, block: &[u8]) {256 assert!(block.len() <= ABI_ALIGNMENT);257 self.static_part.extend(block);258 self.static_part259 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);260 }261262 /// Write [`H160`] to end of buffer263 pub fn address(&mut self, address: &H160) {264 self.write_padleft(&address.0)265 }266267 /// Write [`bool`] to end of buffer268 pub fn bool(&mut self, value: &bool) {269 self.write_padleft(&[if *value { 1 } else { 0 }])270 }271272 /// Write [`u8`] to end of buffer273 pub fn uint8(&mut self, value: &u8) {274 self.write_padleft(&[*value])275 }276277 /// Write [`u32`] to end of buffer278 pub fn uint32(&mut self, value: &u32) {279 self.write_padleft(&u32::to_be_bytes(*value))280 }281282 /// Write [`u128`] to end of buffer283 pub fn uint128(&mut self, value: &u128) {284 self.write_padleft(&u128::to_be_bytes(*value))285 }286287 /// Write [`U256`] to end of buffer288 pub fn uint256(&mut self, value: &U256) {289 let mut out = [0; 32];290 value.to_big_endian(&mut out);291 self.write_padleft(&out)292 }293294 /// Write [`usize`] to end of buffer295 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]296 pub fn write_usize(&mut self, value: &usize) {297 self.write_padleft(&usize::to_be_bytes(*value))298 }299300 /// Append recursive data, writing pending offset at end of buffer301 pub fn write_subresult(&mut self, result: Self) {302 self.dynamic_part.push((self.static_part.len(), result));303 // Empty block, to be filled later304 self.write_padleft(&[]);305 }306307 fn memory(&mut self, value: &[u8]) {308 let mut sub = Self::new();309 sub.uint32(&(value.len() as u32));310 for chunk in value.chunks(ABI_ALIGNMENT) {311 sub.write_padright(chunk);312 }313 self.write_subresult(sub);314 }315316 /// Append recursive [`str`] at end of buffer317 pub fn string(&mut self, value: &str) {318 self.memory(value.as_bytes())319 }320321 /// Append recursive [`[u8]`] at end of buffer322 pub fn bytes(&mut self, value: &[u8]) {323 self.memory(value)324 }325326 /// Finish writer, concatenating all internal buffers327 pub fn finish(mut self) -> Vec<u8> {328 for (static_offset, part) in self.dynamic_part {329 let part_offset = self.static_part.len()330 - if self.had_call { 4 } else { 0 }331 - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };332333 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);334 let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();335 let stop = static_offset + ABI_ALIGNMENT;336 self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);337 self.static_part.extend(part.finish())338 }339 self.static_part340 }341}342343/// [`AbiReader`] implements reading of many types, but it should344/// be limited to types defined in spec345///346/// As this trait can't be made sealed,347/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`348pub trait AbiRead<T> {349 /// Read item from current position, advanding decoder350 fn abi_read(&mut self) -> Result<T>;351}352353macro_rules! impl_abi_readable {354 ($ty:ty, $method:ident, $dynamic:literal) => {355 impl TypeHelper for $ty {356 fn is_dynamic() -> bool {357 $dynamic358 }359360 fn size() -> usize {361 ABI_ALIGNMENT362 }363 }364 impl AbiRead<$ty> for AbiReader<'_> {365 fn abi_read(&mut self) -> Result<$ty> {366 self.$method()367 }368 }369 };370}371372impl_abi_readable!(bool, bool, false);373impl_abi_readable!(uint8, uint8, false);374impl_abi_readable!(uint32, uint32, false);375impl_abi_readable!(uint64, uint64, false);376impl_abi_readable!(uint128, uint128, false);377impl_abi_readable!(uint256, uint256, false);378impl_abi_readable!(bytes4, bytes4, false);379impl_abi_readable!(address, address, false);380impl_abi_readable!(string, string, true);381// impl_abi_readable!(bytes, bytes, true);382383impl TypeHelper for bytes {384 fn is_dynamic() -> bool {385 true386 }387 fn size() -> usize {388 ABI_ALIGNMENT389 }390}391impl AbiRead<bytes> for AbiReader<'_> {392 fn abi_read(&mut self) -> Result<bytes> {393 Ok(bytes(self.bytes()?))394 }395}396397mod sealed {398 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead399 pub trait CanBePlacedInVec {}400}401402impl sealed::CanBePlacedInVec for U256 {}403impl sealed::CanBePlacedInVec for string {}404impl sealed::CanBePlacedInVec for H160 {}405406impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>407where408 Self: AbiRead<R>,409{410 fn abi_read(&mut self) -> Result<Vec<R>> {411 let mut sub = self.subresult(None)?;412 let size = sub.uint32()? as usize;413 sub.subresult_offset = sub.offset;414 let mut out = Vec::with_capacity(size);415 for _ in 0..size {416 out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);417 }418 Ok(out)419 }420}421422macro_rules! impl_tuples {423 ($($ident:ident)+) => {424 impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)425 where426 $(427 $ident: TypeHelper,428 )+429 {430 fn is_dynamic() -> bool {431 false432 $(433 || <$ident>::is_dynamic()434 )*435 }436437 fn size() -> usize {438 0 $(+ <$ident>::size())+439 }440 }441 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}442 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>443 where444 $(445 Self: AbiRead<$ident>,446 )+447 ($($ident,)+): TypeHelper,448 {449 fn abi_read(&mut self) -> Result<($($ident,)+)> {450 let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };451 let mut subresult = self.subresult(size)?;452 Ok((453 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+454 ))455 }456 }457 #[allow(non_snake_case)]458 impl<$($ident),+> AbiWrite for ($($ident,)+)459 where460 $($ident: AbiWrite,)+461 {462 fn abi_write(&self, writer: &mut AbiWriter) {463 let ($($ident,)+) = self;464 if writer.is_dynamic {465 let mut sub = AbiWriter::new();466 $($ident.abi_write(&mut sub);)+467 writer.write_subresult(sub);468 } else {469 $($ident.abi_write(writer);)+470 }471 }472 }473 };474}475476impl_tuples! {A}477impl_tuples! {A B}478impl_tuples! {A B C}479impl_tuples! {A B C D}480impl_tuples! {A B C D E}481impl_tuples! {A B C D E F}482impl_tuples! {A B C D E F G}483impl_tuples! {A B C D E F G H}484impl_tuples! {A B C D E F G H I}485impl_tuples! {A B C D E F G H I J}486487/// For questions about inability to provide custom implementations,488/// see [`AbiRead`]489pub trait AbiWrite {490 /// Write value to end of specified encoder491 fn abi_write(&self, writer: &mut AbiWriter);492 /// Specialization for [`crate::solidity_interface`] implementation,493 /// see comment in `impl AbiWrite for ResultWithPostInfo`494 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {495 let mut writer = AbiWriter::new();496 self.abi_write(&mut writer);497 Ok(writer.into())498 }499}500501/// This particular AbiWrite implementation should be split to another trait,502/// which only implements `to_result`, but due to lack of specialization feature503/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,504/// so here we abusing default trait methods for it505impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {506 fn abi_write(&self, _writer: &mut AbiWriter) {507 debug_assert!(false, "shouldn't be called, see comment")508 }509 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {510 match self {511 Ok(v) => Ok(WithPostDispatchInfo {512 post_info: v.post_info.clone(),513 data: {514 let mut out = AbiWriter::new();515 v.data.abi_write(&mut out);516 out517 },518 }),519 Err(e) => Err(e.clone()),520 }521 }522}523524macro_rules! impl_abi_writeable {525 ($ty:ty, $method:ident) => {526 impl AbiWrite for $ty {527 fn abi_write(&self, writer: &mut AbiWriter) {528 writer.$method(&self)529 }530 }531 };532}533534impl_abi_writeable!(u8, uint8);535impl_abi_writeable!(u32, uint32);536impl_abi_writeable!(u128, uint128);537impl_abi_writeable!(U256, uint256);538impl_abi_writeable!(H160, address);539impl_abi_writeable!(bool, bool);540impl_abi_writeable!(&str, string);541542impl AbiWrite for string {543 fn abi_write(&self, writer: &mut AbiWriter) {544 writer.string(self)545 }546}547548impl AbiWrite for bytes {549 fn abi_write(&self, writer: &mut AbiWriter) {550 writer.bytes(self.0.as_slice())551 }552}553554impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {555 fn abi_write(&self, writer: &mut AbiWriter) {556 let is_dynamic = T::is_dynamic();557 let mut sub = if is_dynamic {558 AbiWriter::new_dynamic(is_dynamic)559 } else {560 AbiWriter::new()561 };562563 // Write items count564 (self.len() as u32).abi_write(&mut sub);565566 for item in self {567 item.abi_write(&mut sub);568 }569 writer.write_subresult(sub);570 }571}572573impl AbiWrite for () {574 fn abi_write(&self, _writer: &mut AbiWriter) {}575}576577/// Helper macros to parse reader into variables578#[deprecated]579#[macro_export]580macro_rules! abi_decode {581 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {582 $(583 let $name = $reader.$typ()?;584 )+585 }586}587588/// Helper macros to construct RLP-encoded buffer589#[deprecated]590#[macro_export]591macro_rules! abi_encode {592 ($($typ:ident($value:expr)),* $(,)?) => {{593 #[allow(unused_mut)]594 let mut writer = ::evm_coder::abi::AbiWriter::new();595 $(596 writer.$typ($value);597 )*598 writer599 }};600 (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{601 #[allow(unused_mut)]602 let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);603 $(604 writer.$typ($value);605 )*606 writer607 }}608}609610#[cfg(test)]611pub mod test {612 use crate::{613 abi::{AbiRead, AbiWrite},614 types::{string, uint256, address},615 };616617 use super::{AbiReader, AbiWriter};618 use hex_literal::hex;619 use primitive_types::{H160, U256};620621 #[test]622 fn dynamic_after_static() {623 let mut encoder = AbiWriter::new();624 encoder.bool(&true);625 encoder.string("test");626 let encoded = encoder.finish();627628 let mut encoder = AbiWriter::new();629 encoder.bool(&true);630 // Offset to subresult631 encoder.uint32(&(32 * 2));632 // Len of "test"633 encoder.uint32(&4);634 encoder.write_padright(&[b't', b'e', b's', b't']);635 let alternative_encoded = encoder.finish();636637 assert_eq!(encoded, alternative_encoded);638639 let mut decoder = AbiReader::new(&encoded);640 assert!(decoder.bool().unwrap());641 assert_eq!(decoder.string().unwrap(), "test");642 }643644 #[test]645 fn mint_sample() {646 let (call, mut decoder) = AbiReader::new_call(&hex!(647 "648 50bb4e7f649 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374650 0000000000000000000000000000000000000000000000000000000000000001651 0000000000000000000000000000000000000000000000000000000000000060652 0000000000000000000000000000000000000000000000000000000000000008653 5465737420555249000000000000000000000000000000000000000000000000654 "655 ))656 .unwrap();657 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));658 assert_eq!(659 format!("{:?}", decoder.address().unwrap()),660 "0xad2c0954693c2b5404b7e50967d3481bea432374"661 );662 assert_eq!(decoder.uint32().unwrap(), 1);663 assert_eq!(decoder.string().unwrap(), "Test URI");664 }665666 #[test]667 fn parse_vec_with_dynamic_type() {668 let decoded_data = (669 0x36543006,670 vec![671 (1.into(), "Test URI 0".to_string()),672 (11.into(), "Test URI 1".to_string()),673 (12.into(), "Test URI 2".to_string()),674 ],675 );676677 let encoded_data = &hex!(678 "679 36543006680 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address681 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]682 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]683684 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem685 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem686 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem687688 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60689 0000000000000000000000000000000000000000000000000000000000000040 // offset of string690 000000000000000000000000000000000000000000000000000000000000000a // size of string691 5465737420555249203000000000000000000000000000000000000000000000 // string692693 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0694 0000000000000000000000000000000000000000000000000000000000000040 // offset of string695 000000000000000000000000000000000000000000000000000000000000000a // size of string696 5465737420555249203100000000000000000000000000000000000000000000 // string697698 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160699 0000000000000000000000000000000000000000000000000000000000000040 // offset of string700 000000000000000000000000000000000000000000000000000000000000000a // size of string701 5465737420555249203200000000000000000000000000000000000000000000 // string702 "703 );704705 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();706 assert_eq!(call, u32::to_be_bytes(decoded_data.0));707 let address = decoder.address().unwrap();708 let data =709 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();710 assert_eq!(data, decoded_data.1);711712 let mut writer = AbiWriter::new_call(decoded_data.0);713 address.abi_write(&mut writer);714 decoded_data.1.abi_write(&mut writer);715 let ed = writer.finish();716 similar_asserts::assert_eq!(encoded_data, ed.as_slice());717 }718719 #[test]720 fn parse_vec_with_simple_type() {721 let decoded_data = (722 0x1ACF2D55,723 vec![724 (725 H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),726 U256([10, 0, 0, 0]),727 ),728 (729 H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),730 U256([20, 0, 0, 0]),731 ),732 (733 H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),734 U256([30, 0, 0, 0]),735 ),736 ],737 );738739 let encoded_data = &hex!(740 "741 1ACF2D55742 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]743 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]744745 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address746 000000000000000000000000000000000000000000000000000000000000000A // uint256747748 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address749 0000000000000000000000000000000000000000000000000000000000000014 // uint256750751 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address752 000000000000000000000000000000000000000000000000000000000000001E // uint256753 "754 );755756 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();757 assert_eq!(call, u32::to_be_bytes(decoded_data.0));758 let data =759 <AbiReader<'_> as AbiRead<Vec<(address, uint256)>>>::abi_read(&mut decoder).unwrap();760 assert_eq!(data.len(), 3);761 assert_eq!(data, decoded_data.1);762763 let mut writer = AbiWriter::new_call(decoded_data.0);764 decoded_data.1.abi_write(&mut writer);765 let ed = writer.finish();766 assert_eq!(encoded_data, ed.as_slice());767 }768}crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -133,8 +133,10 @@
pub type string = ::alloc::string::String;
#[cfg(feature = "std")]
pub type string = ::std::string::String;
- pub type bytes = Vec<u8>;
+ #[derive(Default, Debug)]
+ pub struct bytes(pub Vec<u8>);
+
/// Solidity doesn't have `void` type, however we have special implementation
/// for empty tuple return type
pub type void = ();
@@ -157,6 +159,30 @@
/// and there is no `receiver()` function defined.
pub value: U256,
}
+
+ impl From<Vec<u8>> for bytes {
+ fn from(src: Vec<u8>) -> Self {
+ Self(src)
+ }
+ }
+
+ impl Into<Vec<u8>> for bytes {
+ fn into(self) -> Vec<u8> {
+ self.0
+ }
+ }
+
+ impl bytes {
+ #[must_use]
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ #[must_use]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+ }
}
/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -85,7 +85,7 @@
let key = <Vec<u8>>::from(key)
.try_into()
.map_err(|_| "key too large")?;
- let value = value.try_into().map_err(|_| "value too large")?;
+ let value = value.0.try_into().map_err(|_| "value too large")?;
<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })
.map_err(dispatch_to_evm::<T>)
@@ -120,7 +120,7 @@
let props = <CollectionProperties<T>>::get(self.id);
let prop = props.get(&key).ok_or("key not found")?;
- Ok(prop.to_vec())
+ Ok(bytes(prop.to_vec()))
}
/// Set the sponsor of the collection.
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -97,7 +97,7 @@
let key = <Vec<u8>>::from(key)
.try_into()
.map_err(|_| "key too long")?;
- let value = value.try_into().map_err(|_| "value too long")?;
+ let value = value.0.try_into().map_err(|_| "value too long")?;
let nesting_budget = self
.recorder
@@ -146,7 +146,7 @@
let props = <TokenProperties<T>>::get((self.id, token_id));
let prop = props.get(&key).ok_or("key not found")?;
- Ok(prop.to_vec())
+ Ok(prop.to_vec().into())
}
}
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -100,7 +100,7 @@
let key = <Vec<u8>>::from(key)
.try_into()
.map_err(|_| "key too long")?;
- let value = value.try_into().map_err(|_| "value too long")?;
+ let value = value.0.try_into().map_err(|_| "value too long")?;
let nesting_budget = self
.recorder
@@ -149,7 +149,7 @@
let props = <TokenProperties<T>>::get((self.id, token_id));
let prop = props.get(&key).ok_or("key not found")?;
- Ok(prop.to_vec())
+ Ok(prop.to_vec().into())
}
}