difftreelog
feat add implementations of AbiRead & AbiWrite with macto AbiCoder
in: master
3 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
@@ -3,12 +3,40 @@
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 {
+ syn::Fields::Named(ref fields) => Ok((
+ true,
+ fields.named.iter().enumerate().map(map_field_to_name),
+ fields.named.iter().map(map_field_to_type),
+ fields.named.len(),
+ )),
+ syn::Fields::Unnamed(ref fields) => Ok((
+ false,
+ fields.unnamed.iter().enumerate().map(map_field_to_name),
+ fields.unnamed.iter().map(map_field_to_type),
+ fields.unnamed.len(),
+ )),
+ syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),
+ },
+ syn::Data::Enum(_) => Err(syn::Error::new(name.span(), "Enums not supported")),
+ syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),
+ }?;
+
+ if params_count == 0 {
+ return Err(syn::Error::new(name.span(), "Empty structs not supported"));
+ };
+
let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
- let abi_type = impl_abi_type(ast)?;
- // println!("{}", abi_type);
+ 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
+ #abi_read
+ #abi_write
})
}
@@ -18,44 +46,37 @@
}
}
+fn map_field_to_name(field: (usize, &syn::Field)) -> syn::Ident {
+ match field.1.ident.as_ref() {
+ Some(name) => name.clone(),
+ None => {
+ let mut name = "field".to_string();
+ name.push_str(field.0.to_string().as_str());
+ syn::Ident::new(name.as_str(), proc_macro2::Span::call_site())
+ }
+ }
+}
+
fn map_field_to_type<'a>(field: &'a syn::Field) -> &'a syn::Type {
&field.ty
}
-fn impl_abi_type(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
- let name = &ast.ident;
- let (fields, params_count) = match &ast.data {
- syn::Data::Struct(ds) => match ds.fields {
- syn::Fields::Named(ref fields) => Ok((
- fields.named.iter().map(map_field_to_type),
- fields.named.len(),
- )),
- syn::Fields::Unnamed(ref fields) => Ok((
- fields.unnamed.iter().map(map_field_to_type),
- fields.unnamed.len(),
- )),
- syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),
- },
- syn::Data::Enum(_) => Err(syn::Error::new(name.span(), "Enums not supported")),
- syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),
- }?;
-
+fn impl_abi_type<'a>(
+ name: &syn::Ident,
+ field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+) -> proc_macro2::TokenStream {
let mut params_signature = {
- let fields = fields.clone();
+ let types = field_types.clone();
quote!(
- #(nameof(<#fields as ::evm_coder::abi::AbiType>::SIGNATURE) fixed(","))*
+ #(nameof(<#types as ::evm_coder::abi::AbiType>::SIGNATURE) fixed(","))*
)
- };
-
- if params_count == 0 {
- return Err(syn::Error::new(name.span(), "Empty structs not supported"));
};
params_signature.extend(quote!(shift_left(1)));
- let fields_for_dynamic = fields.clone();
+ let fields_for_dynamic = field_types.clone();
- Ok(quote! {
+ quote! {
impl ::evm_coder::abi::AbiType for #name {
const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = ::evm_coder::make_signature!(
new fixed("(")
@@ -69,8 +90,71 @@
)*
}
fn size() -> usize {
- 0 #(+ <#fields as ::evm_coder::abi::AbiType>::size())*
+ 0 #(+ <#field_types as ::evm_coder::abi::AbiType>::size())*
+ }
+ }
+ }
+}
+
+fn impl_abi_read<'a>(
+ name: &syn::Ident,
+ is_named_fields: bool,
+ field_names: impl Iterator<Item = proc_macro2::Ident> + Clone,
+ field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+) -> proc_macro2::TokenStream {
+ let field_names1 = field_names.clone();
+
+ let struct_constructor = if is_named_fields {
+ quote!(Ok(Self { #(#field_names1),* }))
+ } else {
+ quote!(Ok(Self ( #(#field_names1),* )))
+ };
+ 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() {
+ 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)?;
+ )*
+
+ #struct_constructor
+ }
+ }
+ )
+}
+
+fn impl_abi_write<'a>(
+ name: &syn::Ident,
+ is_named_fields: bool,
+ params_count: usize,
+ field_names: impl Iterator<Item = proc_macro2::Ident> + Clone,
+) -> proc_macro2::TokenStream {
+ let abi_write = if is_named_fields {
+ quote!(
+ #(
+ self.#field_names.abi_write(writer);
+ )*
+ )
+ } else {
+ let field_names = (0..params_count)
+ .into_iter()
+ .map(proc_macro2::Literal::usize_unsuffixed);
+ quote!(
+ #(
+ self.#field_names.abi_write(writer);
+ )*
+ )
+ };
+ quote!(
+ impl ::evm_coder::abi::AbiWrite for #name {
+ fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {
+ #abi_write
}
}
- })
+ )
}
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 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}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
@@ -405,3 +405,8 @@
<TupleStruct3DerivedMixedParam as AbiType>::size()
);
}
+
+// #[test]
+// fn impl_abi_read() {
+// TypeStruct1SimpleParam::
+// }