difftreelog
fix AbiRead implementations
in: master
5 files changed
crates/evm-coder/procedural/src/abi_derive.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/abi_derive.rs
+++ b/crates/evm-coder/procedural/src/abi_derive.rs
@@ -1,7 +1,6 @@
use quote::quote;
pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
- // dbg!(ast);
let name = &ast.ident;
let (is_named_fields, field_names, field_types, params_count) = match &ast.data {
syn::Data::Struct(ds) => match ds.fields {
@@ -31,7 +30,7 @@
let abi_type = impl_abi_type(name, field_types.clone());
let abi_read = impl_abi_read(name, is_named_fields, field_names.clone(), field_types);
let abi_write = impl_abi_write(name, is_named_fields, params_count, field_names);
- println!("{}", abi_write);
+
Ok(quote! {
#can_be_plcaed_in_vec
#abi_type
@@ -112,14 +111,19 @@
quote!(
impl ::evm_coder::abi::AbiRead for #name {
fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {
- let size = if !<Self as ::evm_coder::abi::AbiType>::is_dynamic() {
+ let is_dynamic = <Self as ::evm_coder::abi::AbiType>::is_dynamic();
+ let size = if !is_dynamic {
Some(<Self as ::evm_coder::abi::AbiType>::size())
} else {
None
};
let mut subresult = reader.subresult(size)?;
#(
- let #field_names = <#field_types as ::evm_coder::abi::AbiRead>::abi_read(&mut subresult)?;
+ let #field_names = {
+ let value = <#field_types as ::evm_coder::abi::AbiRead>::abi_read(&mut subresult)?;
+ if !is_dynamic {subresult.seek(<#field_types as ::evm_coder::abi::AbiType>::size())};
+ value
+ };
)*
#struct_constructor
crates/evm-coder/src/abi/impls.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/impls.rs
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -92,7 +92,7 @@
}
}
-impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {
+impl<R: AbiType + AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {
fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {
let mut sub = reader.subresult(None)?;
let size = sub.uint32()? as usize;
@@ -100,6 +100,9 @@
let mut out = Vec::with_capacity(size);
for _ in 0..size {
out.push(<R>::abi_read(&mut sub)?);
+ if !<R>::is_dynamic() {
+ sub.subresult_offset += <R>::size()
+ };
}
Ok(out)
}
@@ -295,14 +298,19 @@
impl<$($ident),+> AbiRead for ($($ident,)+)
where
- $($ident: AbiRead,)+
+ $($ident: AbiRead + AbiType,)+
($($ident,)+): AbiType,
{
fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {
- let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };
+ let is_dynamic = <($($ident,)+)>::is_dynamic();
+ let size = if !is_dynamic { Some(<($($ident,)+)>::size()) } else { None };
let mut subresult = reader.subresult(size)?;
Ok((
- $(<$ident>::abi_read(&mut subresult)?,)+
+ $({
+ let value = <$ident>::abi_read(&mut subresult)?;
+ if !is_dynamic {subresult.seek(<$ident as AbiType>::size())};
+ value
+ },)+
))
}
}
crates/evm-coder/src/abi/mod.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)]2021mod traits;22pub use traits::*;23mod impls;2425#[cfg(test)]26mod test;2728#[cfg(not(feature = "std"))]29use alloc::vec::Vec;30use evm_core::ExitError;31use primitive_types::{H160, U256};3233use crate::{34 execution::{Result, Error},35 types::*,36};3738const ABI_ALIGNMENT: usize = 32;3940/// View into RLP data, which provides method to read typed items from it41#[derive(Clone)]42pub struct AbiReader<'i> {43 buf: &'i [u8],44 subresult_offset: usize,45 offset: usize,46}47impl<'i> AbiReader<'i> {48 /// Start reading RLP buffer, assuming there is no padding bytes49 pub fn new(buf: &'i [u8]) -> Self {50 Self {51 buf,52 subresult_offset: 0,53 offset: 0,54 }55 }56 /// Start reading RLP buffer, parsing first 4 bytes as selector57 pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {58 if buf.len() < 4 {59 return Err(Error::Error(ExitError::OutOfOffset));60 }61 let mut method_id = [0; 4];62 method_id.copy_from_slice(&buf[0..4]);6364 Ok((65 method_id,66 Self {67 buf,68 subresult_offset: 4,69 offset: 4,70 },71 ))72 }7374 fn read_pad<const S: usize>(75 buf: &[u8],76 offset: usize,77 pad_start: usize,78 pad_size: usize,79 block_start: usize,80 block_size: usize,81 ) -> Result<[u8; S]> {82 if buf.len() - offset < ABI_ALIGNMENT {83 return Err(Error::Error(ExitError::OutOfOffset));84 }85 let mut block = [0; S];86 let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);87 if !is_pad_zeroed {88 return Err(Error::Error(ExitError::InvalidRange));89 }90 block.copy_from_slice(&buf[block_start..block_size]);91 Ok(block)92 }9394 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {95 let offset = self.offset;96 self.offset += ABI_ALIGNMENT;97 Self::read_pad(98 self.buf,99 offset,100 offset,101 offset + ABI_ALIGNMENT - S,102 offset + ABI_ALIGNMENT - S,103 offset + ABI_ALIGNMENT,104 )105 }106107 fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {108 let offset = self.offset;109 self.offset += ABI_ALIGNMENT;110 Self::read_pad(111 self.buf,112 offset,113 offset + S,114 offset + ABI_ALIGNMENT,115 offset,116 offset + S,117 )118 }119120 /// Read [`H160`] at current position, then advance121 pub fn address(&mut self) -> Result<H160> {122 Ok(H160(self.read_padleft()?))123 }124125 /// Read [`bool`] at current position, then advance126 pub fn bool(&mut self) -> Result<bool> {127 let data: [u8; 1] = self.read_padleft()?;128 match data[0] {129 0 => Ok(false),130 1 => Ok(true),131 _ => Err(Error::Error(ExitError::InvalidRange)),132 }133 }134135 /// Read [`[u8; 4]`] at current position, then advance136 pub fn bytes4(&mut self) -> Result<[u8; 4]> {137 self.read_padright()138 }139140 /// Read [`Vec<u8>`] at current position, then advance141 pub fn bytes(&mut self) -> Result<Vec<u8>> {142 let mut subresult = self.subresult(None)?;143 let length = subresult.uint32()? as usize;144 if subresult.buf.len() < subresult.offset + length {145 return Err(Error::Error(ExitError::OutOfOffset));146 }147 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())148 }149150 /// Read [`string`] at current position, then advance151 pub fn string(&mut self) -> Result<string> {152 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))153 }154155 /// Read [`u8`] at current position, then advance156 pub fn uint8(&mut self) -> Result<u8> {157 Ok(self.read_padleft::<1>()?[0])158 }159160 /// Read [`u32`] at current position, then advance161 pub fn uint32(&mut self) -> Result<u32> {162 Ok(u32::from_be_bytes(self.read_padleft()?))163 }164165 /// Read [`u128`] at current position, then advance166 pub fn uint128(&mut self) -> Result<u128> {167 Ok(u128::from_be_bytes(self.read_padleft()?))168 }169170 /// Read [`U256`] at current position, then advance171 pub fn uint256(&mut self) -> Result<U256> {172 let buf: [u8; 32] = self.read_padleft()?;173 Ok(U256::from_big_endian(&buf))174 }175176 /// Read [`u64`] at current position, then advance177 pub fn uint64(&mut self) -> Result<u64> {178 Ok(u64::from_be_bytes(self.read_padleft()?))179 }180181 /// Read [`usize`] at current position, then advance182 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]183 pub fn read_usize(&mut self) -> Result<usize> {184 Ok(usize::from_be_bytes(self.read_padleft()?))185 }186187 /// Slice recursive buffer, advance one word for buffer offset188 /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].189 pub fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {190 let subresult_offset = self.subresult_offset;191 let offset = if let Some(size) = size {192 self.offset += size;193 self.subresult_offset += size;194 0195 } else {196 self.uint32()? as usize197 };198199 if offset + self.subresult_offset > self.buf.len() {200 return Err(Error::Error(ExitError::InvalidRange));201 }202203 let new_offset = offset + subresult_offset;204 Ok(AbiReader {205 buf: self.buf,206 subresult_offset: new_offset,207 offset: new_offset,208 })209 }210211 /// Is this parser reached end of buffer?212 pub fn is_finished(&self) -> bool {213 self.buf.len() == self.offset214 }215}216217/// Writer for RLP encoded data218#[derive(Default)]219pub struct AbiWriter {220 static_part: Vec<u8>,221 dynamic_part: Vec<(usize, AbiWriter)>,222 had_call: bool,223 is_dynamic: bool,224}225impl AbiWriter {226 /// Initialize internal buffers for output data, assuming no padding required227 pub fn new() -> Self {228 Self::default()229 }230231 /// Initialize internal buffers with data size232 pub fn new_dynamic(is_dynamic: bool) -> Self {233 Self {234 is_dynamic,235 ..Default::default()236 }237 }238 /// Initialize internal buffers, inserting method selector at beginning239 pub fn new_call(method_id: u32) -> Self {240 let mut val = Self::new();241 val.static_part.extend(&method_id.to_be_bytes());242 val.had_call = true;243 val244 }245246 fn write_padleft(&mut self, block: &[u8]) {247 assert!(block.len() <= ABI_ALIGNMENT);248 self.static_part249 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);250 self.static_part.extend(block);251 }252253 fn write_padright(&mut self, block: &[u8]) {254 assert!(block.len() <= ABI_ALIGNMENT);255 self.static_part.extend(block);256 self.static_part257 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);258 }259260 /// Write [`H160`] to end of buffer261 pub fn address(&mut self, address: &H160) {262 self.write_padleft(&address.0)263 }264265 /// Write [`bool`] to end of buffer266 pub fn bool(&mut self, value: &bool) {267 self.write_padleft(&[if *value { 1 } else { 0 }])268 }269270 /// Write [`u8`] to end of buffer271 pub fn uint8(&mut self, value: &u8) {272 self.write_padleft(&[*value])273 }274275 /// Write [`u32`] to end of buffer276 pub fn uint32(&mut self, value: &u32) {277 self.write_padleft(&u32::to_be_bytes(*value))278 }279280 /// Write [`u128`] to end of buffer281 pub fn uint128(&mut self, value: &u128) {282 self.write_padleft(&u128::to_be_bytes(*value))283 }284285 /// Write [`U256`] to end of buffer286 pub fn uint256(&mut self, value: &U256) {287 let mut out = [0; 32];288 value.to_big_endian(&mut out);289 self.write_padleft(&out)290 }291292 /// Write [`usize`] to end of buffer293 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]294 pub fn write_usize(&mut self, value: &usize) {295 self.write_padleft(&usize::to_be_bytes(*value))296 }297298 /// Append recursive data, writing pending offset at end of buffer299 pub fn write_subresult(&mut self, result: Self) {300 self.dynamic_part.push((self.static_part.len(), result));301 // Empty block, to be filled later302 self.write_padleft(&[]);303 }304305 fn memory(&mut self, value: &[u8]) {306 let mut sub = Self::new();307 sub.uint32(&(value.len() as u32));308 for chunk in value.chunks(ABI_ALIGNMENT) {309 sub.write_padright(chunk);310 }311 self.write_subresult(sub);312 }313314 /// Append recursive [`str`] at end of buffer315 pub fn string(&mut self, value: &str) {316 self.memory(value.as_bytes())317 }318319 /// Append recursive [`[u8]`] at end of buffer320 pub fn bytes(&mut self, value: &[u8]) {321 self.memory(value)322 }323324 /// Finish writer, concatenating all internal buffers325 pub fn finish(mut self) -> Vec<u8> {326 for (static_offset, part) in self.dynamic_part {327 let part_offset = self.static_part.len()328 - if self.had_call { 4 } else { 0 }329 - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };330331 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);332 let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();333 let stop = static_offset + ABI_ALIGNMENT;334 self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);335 self.static_part.extend(part.finish())336 }337 self.static_part338 }339}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)]2021mod traits;22pub use traits::*;23mod impls;2425#[cfg(test)]26mod test;2728#[cfg(not(feature = "std"))]29use alloc::vec::Vec;30use evm_core::ExitError;31use primitive_types::{H160, U256};3233use crate::{34 execution::{Result, Error},35 types::*,36};3738const ABI_ALIGNMENT: usize = 32;3940/// View into RLP data, which provides method to read typed items from it41#[derive(Clone)]42pub struct AbiReader<'i> {43 buf: &'i [u8],44 subresult_offset: usize,45 offset: usize,46}47impl<'i> AbiReader<'i> {48 /// Start reading RLP buffer, assuming there is no padding bytes49 pub fn new(buf: &'i [u8]) -> Self {50 Self {51 buf,52 subresult_offset: 0,53 offset: 0,54 }55 }56 /// Start reading RLP buffer, parsing first 4 bytes as selector57 pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {58 if buf.len() < 4 {59 return Err(Error::Error(ExitError::OutOfOffset));60 }61 let mut method_id = [0; 4];62 method_id.copy_from_slice(&buf[0..4]);6364 Ok((65 method_id,66 Self {67 buf,68 subresult_offset: 4,69 offset: 4,70 },71 ))72 }7374 fn read_pad<const S: usize>(75 buf: &[u8],76 offset: usize,77 pad_start: usize,78 pad_end: usize,79 block_start: usize,80 block_end: usize,81 ) -> Result<[u8; S]> {82 if buf.len() - offset < ABI_ALIGNMENT {83 return Err(Error::Error(ExitError::OutOfOffset));84 }85 let mut block = [0; S];86 let is_pad_zeroed = buf[pad_start..pad_end].iter().all(|&v| v == 0);87 if !is_pad_zeroed {88 return Err(Error::Error(ExitError::InvalidRange));89 }90 block.copy_from_slice(&buf[block_start..block_end]);91 Ok(block)92 }9394 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {95 let offset = self.offset;96 self.offset += ABI_ALIGNMENT;97 Self::read_pad(98 self.buf,99 offset,100 offset,101 offset + ABI_ALIGNMENT - S,102 offset + ABI_ALIGNMENT - S,103 offset + ABI_ALIGNMENT,104 )105 }106107 fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {108 let offset = self.offset;109 self.offset += ABI_ALIGNMENT;110 Self::read_pad(111 self.buf,112 offset,113 offset + S,114 offset + ABI_ALIGNMENT,115 offset,116 offset + S,117 )118 }119120 /// Read [`H160`] at current position, then advance121 pub fn address(&mut self) -> Result<H160> {122 Ok(H160(self.read_padleft()?))123 }124125 /// Read [`bool`] at current position, then advance126 pub fn bool(&mut self) -> Result<bool> {127 let data: [u8; 1] = self.read_padleft()?;128 match data[0] {129 0 => Ok(false),130 1 => Ok(true),131 _ => Err(Error::Error(ExitError::InvalidRange)),132 }133 }134135 /// Read [`[u8; 4]`] at current position, then advance136 pub fn bytes4(&mut self) -> Result<[u8; 4]> {137 self.read_padright()138 }139140 /// Read [`Vec<u8>`] at current position, then advance141 pub fn bytes(&mut self) -> Result<Vec<u8>> {142 let mut subresult = self.subresult(None)?;143 let length = subresult.uint32()? as usize;144 if subresult.buf.len() < subresult.offset + length {145 return Err(Error::Error(ExitError::OutOfOffset));146 }147 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())148 }149150 /// Read [`string`] at current position, then advance151 pub fn string(&mut self) -> Result<string> {152 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))153 }154155 /// Read [`u8`] at current position, then advance156 pub fn uint8(&mut self) -> Result<u8> {157 Ok(self.read_padleft::<1>()?[0])158 }159160 /// Read [`u32`] at current position, then advance161 pub fn uint32(&mut self) -> Result<u32> {162 Ok(u32::from_be_bytes(self.read_padleft()?))163 }164165 /// Read [`u128`] at current position, then advance166 pub fn uint128(&mut self) -> Result<u128> {167 Ok(u128::from_be_bytes(self.read_padleft()?))168 }169170 /// Read [`U256`] at current position, then advance171 pub fn uint256(&mut self) -> Result<U256> {172 let buf: [u8; 32] = self.read_padleft()?;173 Ok(U256::from_big_endian(&buf))174 }175176 /// Read [`u64`] at current position, then advance177 pub fn uint64(&mut self) -> Result<u64> {178 Ok(u64::from_be_bytes(self.read_padleft()?))179 }180181 /// Read [`usize`] at current position, then advance182 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]183 pub fn read_usize(&mut self) -> Result<usize> {184 Ok(usize::from_be_bytes(self.read_padleft()?))185 }186187 /// Slice recursive buffer, advance one word for buffer offset188 /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].189 pub fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {190 let subresult_offset = self.subresult_offset;191 let offset = if let Some(size) = size {192 self.offset += size;193 0194 } else {195 self.uint32()? as usize196 };197198 if offset + self.subresult_offset > self.buf.len() {199 return Err(Error::Error(ExitError::InvalidRange));200 }201202 let new_offset = offset + subresult_offset;203 Ok(AbiReader {204 buf: self.buf,205 subresult_offset: new_offset,206 offset: new_offset,207 })208 }209210 /// Notify about readed data portion.211 pub fn seek(&mut self, size: usize) {212 self.subresult_offset += size;213 }214215 /// Is this parser reached end of buffer?216 pub fn is_finished(&self) -> bool {217 self.buf.len() == self.offset218 }219}220221/// Writer for RLP encoded data222#[derive(Default)]223pub struct AbiWriter {224 static_part: Vec<u8>,225 dynamic_part: Vec<(usize, AbiWriter)>,226 had_call: bool,227 is_dynamic: bool,228}229impl AbiWriter {230 /// Initialize internal buffers for output data, assuming no padding required231 pub fn new() -> Self {232 Self::default()233 }234235 /// Initialize internal buffers with data size236 pub fn new_dynamic(is_dynamic: bool) -> Self {237 Self {238 is_dynamic,239 ..Default::default()240 }241 }242 /// Initialize internal buffers, inserting method selector at beginning243 pub fn new_call(method_id: u32) -> Self {244 let mut val = Self::new();245 val.static_part.extend(&method_id.to_be_bytes());246 val.had_call = true;247 val248 }249250 fn write_padleft(&mut self, block: &[u8]) {251 assert!(block.len() <= ABI_ALIGNMENT);252 self.static_part253 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);254 self.static_part.extend(block);255 }256257 fn write_padright(&mut self, block: &[u8]) {258 assert!(block.len() <= ABI_ALIGNMENT);259 self.static_part.extend(block);260 self.static_part261 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);262 }263264 /// Write [`H160`] to end of buffer265 pub fn address(&mut self, address: &H160) {266 self.write_padleft(&address.0)267 }268269 /// Write [`bool`] to end of buffer270 pub fn bool(&mut self, value: &bool) {271 self.write_padleft(&[if *value { 1 } else { 0 }])272 }273274 /// Write [`u8`] to end of buffer275 pub fn uint8(&mut self, value: &u8) {276 self.write_padleft(&[*value])277 }278279 /// Write [`u32`] to end of buffer280 pub fn uint32(&mut self, value: &u32) {281 self.write_padleft(&u32::to_be_bytes(*value))282 }283284 /// Write [`u128`] to end of buffer285 pub fn uint128(&mut self, value: &u128) {286 self.write_padleft(&u128::to_be_bytes(*value))287 }288289 /// Write [`U256`] to end of buffer290 pub fn uint256(&mut self, value: &U256) {291 let mut out = [0; 32];292 value.to_big_endian(&mut out);293 self.write_padleft(&out)294 }295296 /// Write [`usize`] to end of buffer297 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]298 pub fn write_usize(&mut self, value: &usize) {299 self.write_padleft(&usize::to_be_bytes(*value))300 }301302 /// Append recursive data, writing pending offset at end of buffer303 pub fn write_subresult(&mut self, result: Self) {304 self.dynamic_part.push((self.static_part.len(), result));305 // Empty block, to be filled later306 self.write_padleft(&[]);307 }308309 fn memory(&mut self, value: &[u8]) {310 let mut sub = Self::new();311 sub.uint32(&(value.len() as u32));312 for chunk in value.chunks(ABI_ALIGNMENT) {313 sub.write_padright(chunk);314 }315 self.write_subresult(sub);316 }317318 /// Append recursive [`str`] at end of buffer319 pub fn string(&mut self, value: &str) {320 self.memory(value.as_bytes())321 }322323 /// Append recursive [`[u8]`] at end of buffer324 pub fn bytes(&mut self, value: &[u8]) {325 self.memory(value)326 }327328 /// Finish writer, concatenating all internal buffers329 pub fn finish(mut self) -> Vec<u8> {330 for (static_offset, part) in self.dynamic_part {331 let part_offset = self.static_part.len()332 - if self.had_call { 4 } else { 0 }333 - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };334335 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);336 let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();337 let stop = static_offset + ABI_ALIGNMENT;338 self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);339 self.static_part.extend(part.finish())340 }341 self.static_part342 }343}crates/evm-coder/src/abi/test.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/test.rs
+++ b/crates/evm-coder/src/abi/test.rs
@@ -137,6 +137,27 @@
}
#[test]
+fn encode_decode_vec_tuple_uint8_uint8() {
+ test_impl::<Vec<(u8, u8)>>(
+ 0xdeadbeef,
+ vec![(0x0A, 0x0B), (0x0C, 0x0D), (0x0E, 0x0F)],
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 000000000000000000000000000000000000000000000000000000000000000c
+ 000000000000000000000000000000000000000000000000000000000000000d
+ 000000000000000000000000000000000000000000000000000000000000000e
+ 000000000000000000000000000000000000000000000000000000000000000f
+ "
+ ),
+ );
+}
+
+#[test]
fn encode_decode_vec_tuple_uint256_string() {
test_impl::<Vec<(uint256, string)>>(
0xdeadbeef,
@@ -332,3 +353,175 @@
),
);
}
+
+#[test]
+// #[ignore = "reason"]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {
+ let int = 0xff;
+ let by = bytes(vec![0x11, 0x22, 0x33]);
+ let string = "some string".to_string();
+
+ test_impl::<((u8,), (String, bytes), (u8, bytes))>(
+ 0xdeadbeef,
+ ((int,), (string.clone(), by.clone()), (int, by)),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000060
+ 0000000000000000000000000000000000000000000000000000000000000120
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 1122330000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 1122330000000000000000000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8_uint8_tuple1_uint8_uint8() {
+ test_impl::<((u8,), (u8, u8), (u8, u8))>(
+ 0xdeadbeef,
+ ((43,), (44, 45), (46, 47)),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ 000000000000000000000000000000000000000000000000000000000000002d
+ 000000000000000000000000000000000000000000000000000000000000002e
+ 000000000000000000000000000000000000000000000000000000000000002f
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8() {
+ test_impl::<((u8,), (u8,))>(
+ 0xdeadbeef,
+ ((43,), (44,)),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_uint8() {
+ test_impl::<((u8, u8),)>(
+ 0xdeadbeef,
+ ((43, 44),),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple_uint8_uint8() {
+ test_impl::<(u8, u8)>(
+ 0xdeadbeef,
+ (43, 44),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_string() {
+ test_impl::<((String,),)>(
+ 0xdeadbeef,
+ (("some string".to_string(),),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_string() {
+ test_impl::<((u8, String),)>(
+ 0xdeadbeef,
+ ((0xff, "some string".to_string()),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_string_bytes() {
+ test_impl::<((String, bytes),)>(
+ 0xdeadbeef,
+ (("some string".to_string(), bytes(vec![1, 2, 3])),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 0102030000000000000000000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_string() {
+ test_impl::<((u8,), (String,))>(
+ 0xdeadbeef,
+ ((0xff,), ("some string".to_string(),)),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
crates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/abi_derive_generation.rs
+++ b/crates/evm-coder/tests/abi_derive_generation.rs
@@ -1,7 +1,7 @@
use evm_coder_procedural::AbiCoder;
use evm_coder::{
types::*,
- abi::{AbiType, AbiRead, AbiWrite},
+ abi::{AbiType, AbiRead, AbiWrite, AbiReader, AbiWriter},
};
// TODO: move to build_failed tests
@@ -406,66 +406,199 @@
);
}
-fn test_impl<TypeStruct, TupleStruct, Tuple>(
- type_struct_data: TypeStruct,
- tuple_struct_data: TupleStruct,
+const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
+
+fn test_impl<Tuple, TupleStruct, TypeStruct>(
tuple_data: Tuple,
+ tuple_struct_data: TupleStruct,
+ type_struct_data: TypeStruct,
) where
TypeStruct: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
+ TupleStruct: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
Tuple: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
{
- use evm_coder::abi::{AbiReader, AbiWriter};
- const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
+ let encoded_type_struct = test_abi_write_impl(&type_struct_data);
+ let encoded_tuple_struct = test_abi_write_impl(&tuple_struct_data);
+ let encoded_tuple = test_abi_write_impl(&tuple_data);
- let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER);
- tuple_data.abi_write(&mut writer);
- let encoded_tuple = writer.finish();
+ similar_asserts::assert_eq!(encoded_tuple, encoded_type_struct);
+ similar_asserts::assert_eq!(encoded_tuple, encoded_tuple_struct);
- let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER);
- type_struct_data.abi_write(&mut writer);
- let encoded_struct = writer.finish();
+ // dbg!(&encoded_tuple);
+ // dbg!(&encoded_tuple_struct);
+ // dbg!(&encoded_type_struct);
- similar_asserts::assert_eq!(encoded_tuple, encoded_struct);
+ {
+ let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap();
+ let restored_struct_data = <TypeStruct>::abi_read(&mut decoder).unwrap();
+ assert_eq!(restored_struct_data, type_struct_data);
+ }
+ {
+ let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap();
+ let restored_struct_data = <TupleStruct>::abi_read(&mut decoder).unwrap();
+ assert_eq!(restored_struct_data, tuple_struct_data);
+ }
- // let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap();
- // let restored_struct_data = <TypeStruct>::abi_read(&mut decoder).unwrap();
- // assert_eq!(restored_struct_data, type_struct_data);
+ {
+ let (_, mut decoder) = AbiReader::new_call(&encoded_type_struct).unwrap();
+ let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
+ assert_eq!(restored_tuple_data, tuple_data);
+ }
+ {
+ let (_, mut decoder) = AbiReader::new_call(&encoded_tuple_struct).unwrap();
+ let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
+ assert_eq!(restored_tuple_data, tuple_data);
+ }
+}
- // let (_, mut decoder) = AbiReader::new_call(&encoded_struct).unwrap();
- // let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
- // assert_eq!(restored_tuple_data, tuple_data);
+fn test_abi_write_impl<A>(data: &A) -> Vec<u8>
+where
+ A: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
+{
+ let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER);
+ data.abi_write(&mut writer);
+ let encoded_tuple = writer.finish();
+ encoded_tuple
}
#[test]
fn codec_struct_1_simple() {
let _a = 0xff;
- test_impl::<TypeStruct1SimpleParam, TupleStruct1SimpleParam, (uint8,)>(
- TypeStruct1SimpleParam { _a },
+ test_impl::<(uint8,), TupleStruct1SimpleParam, TypeStruct1SimpleParam>(
+ (_a,),
TupleStruct1SimpleParam(_a),
- (_a,),
+ TypeStruct1SimpleParam { _a },
);
}
#[test]
fn codec_struct_1_dynamic() {
let _a: String = "some string".into();
- test_impl::<TypeStruct1DynamicParam, TupleStruct1DynamicParam, (String,)>(
- TypeStruct1DynamicParam { _a: _a.clone() },
+ test_impl::<(String,), TupleStruct1DynamicParam, TypeStruct1DynamicParam>(
+ (_a.clone(),),
TupleStruct1DynamicParam(_a.clone()),
- (_a,),
+ TypeStruct1DynamicParam { _a },
+ );
+}
+
+#[test]
+fn codec_struct_1_derived_simple() {
+ let _a: u8 = 0xff;
+ test_impl::<((u8,),), TupleStruct1DerivedSimpleParam, TypeStruct1DerivedSimpleParam>(
+ ((_a,),),
+ TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam(_a)),
+ TypeStruct1DerivedSimpleParam {
+ _a: TypeStruct1SimpleParam { _a },
+ },
);
}
#[test]
+fn codec_struct_1_derived_dynamic() {
+ let _a: String = "some string".into();
+ test_impl::<((String,),), TupleStruct1DerivedDynamicParam, TypeStruct1DerivedDynamicParam>(
+ ((_a.clone(),),),
+ TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam(_a.clone())),
+ TypeStruct1DerivedDynamicParam {
+ _a: TypeStruct1DynamicParam { _a },
+ },
+ );
+}
+
+#[test]
+fn codec_struct_2_simple() {
+ let _a = 0xff;
+ let _b = 0xbeefbaba;
+ test_impl::<(u8, u32), TupleStruct2SimpleParam, TypeStruct2SimpleParam>(
+ (_a, _b),
+ TupleStruct2SimpleParam(_a, _b),
+ TypeStruct2SimpleParam { _a, _b },
+ );
+}
+
+#[test]
fn codec_struct_2_dynamic() {
let _a: String = "some string".into();
let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
- test_impl::<TypeStruct2DynamicParam, TupleStruct2DynamicParam, (String, bytes)>(
- TypeStruct2DynamicParam {
- _a: _a.clone(),
- _b: _b.clone(),
- },
+ test_impl::<(String, bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(
+ (_a.clone(), _b.clone()),
TupleStruct2DynamicParam(_a.clone(), _b.clone()),
- (_a, _b),
+ TypeStruct2DynamicParam { _a, _b },
+ );
+}
+
+#[test]
+fn codec_struct_2_mixed() {
+ let _a: u8 = 0xff;
+ let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
+ test_impl::<(u8, bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(
+ (_a.clone(), _b.clone()),
+ TupleStruct2MixedParam(_a.clone(), _b.clone()),
+ TypeStruct2MixedParam { _a, _b },
+ );
+}
+
+#[test]
+fn codec_struct_2_derived_simple() {
+ let _a = 0xff;
+ let _b = 0xbeefbaba;
+ test_impl::<((u8,), (u8, u32)), TupleStruct2DerivedSimpleParam, TypeStruct2DerivedSimpleParam>(
+ ((_a,), (_a, _b)),
+ TupleStruct2DerivedSimpleParam(
+ TupleStruct1SimpleParam(_a),
+ TupleStruct2SimpleParam(_a, _b),
+ ),
+ TypeStruct2DerivedSimpleParam {
+ _a: TypeStruct1SimpleParam { _a },
+ _b: TypeStruct2SimpleParam { _a, _b },
+ },
+ );
+}
+
+#[test]
+fn codec_struct_2_derived_dynamic() {
+ let _a = "some string".to_string();
+ let _b = bytes(vec![0x11, 0x22, 0x33]);
+ test_impl::<
+ ((String,), (String, bytes)),
+ TupleStruct2DerivedDynamicParam,
+ TypeStruct2DerivedDynamicParam,
+ >(
+ ((_a.clone(),), (_a.clone(), _b.clone())),
+ TupleStruct2DerivedDynamicParam(
+ TupleStruct1DynamicParam(_a.clone()),
+ TupleStruct2DynamicParam(_a.clone(), _b.clone()),
+ ),
+ TypeStruct2DerivedDynamicParam {
+ _a: TypeStruct1DynamicParam { _a: _a.clone() },
+ _b: TypeStruct2DynamicParam { _a, _b },
+ },
+ );
+}
+
+#[test]
+fn codec_struct_3_derived_mixed() {
+ let int = 0xff;
+ let by = bytes(vec![0x11, 0x22, 0x33]);
+ let string = "some string".to_string();
+ test_impl::<
+ ((u8,), (String, bytes), (u8, bytes)),
+ TupleStruct3DerivedMixedParam,
+ TypeStruct3DerivedMixedParam,
+ >(
+ ((int,), (string.clone(), by.clone()), (int, by.clone())),
+ TupleStruct3DerivedMixedParam(
+ TupleStruct1SimpleParam(int),
+ TupleStruct2DynamicParam(string.clone(), by.clone()),
+ TupleStruct2MixedParam(int, by.clone()),
+ ),
+ TypeStruct3DerivedMixedParam {
+ _a: TypeStruct1SimpleParam { _a: int },
+ _b: TypeStruct2DynamicParam {
+ _a: string.clone(),
+ _b: by.clone(),
+ },
+ _c: TypeStruct2MixedParam { _a: int, _b: by },
+ },
);
}