--- 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 { - // 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 { - let size = if !::is_dynamic() { + let is_dynamic = ::is_dynamic(); + let size = if !is_dynamic { Some(::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 --- a/crates/evm-coder/src/abi/impls.rs +++ b/crates/evm-coder/src/abi/impls.rs @@ -92,7 +92,7 @@ } } -impl AbiRead for Vec { +impl AbiRead for Vec { fn abi_read(reader: &mut AbiReader) -> Result> { 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(::abi_read(&mut sub)?); + if !::is_dynamic() { + sub.subresult_offset += ::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 + },)+ )) } } --- a/crates/evm-coder/src/abi/mod.rs +++ b/crates/evm-coder/src/abi/mod.rs @@ -75,19 +75,19 @@ buf: &[u8], offset: usize, pad_start: usize, - pad_size: usize, + pad_end: usize, block_start: usize, - block_size: usize, + block_end: usize, ) -> Result<[u8; S]> { if buf.len() - offset < ABI_ALIGNMENT { return Err(Error::Error(ExitError::OutOfOffset)); } let mut block = [0; S]; - let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0); + let is_pad_zeroed = buf[pad_start..pad_end].iter().all(|&v| v == 0); if !is_pad_zeroed { return Err(Error::Error(ExitError::InvalidRange)); } - block.copy_from_slice(&buf[block_start..block_size]); + block.copy_from_slice(&buf[block_start..block_end]); Ok(block) } @@ -190,7 +190,6 @@ let subresult_offset = self.subresult_offset; let offset = if let Some(size) = size { self.offset += size; - self.subresult_offset += size; 0 } else { self.uint32()? as usize @@ -208,6 +207,11 @@ }) } + /// Notify about readed data portion. + pub fn seek(&mut self, size: usize) { + self.subresult_offset += size; + } + /// Is this parser reached end of buffer? pub fn is_finished(&self) -> bool { self.buf.len() == self.offset --- 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::>( + 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::>( 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 + " + ), + ); +} --- 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( - type_struct_data: TypeStruct, - tuple_struct_data: TupleStruct, +const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef; + +fn test_impl( 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 = ::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 = ::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 = ::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 = ::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 = ::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 = ::abi_read(&mut decoder).unwrap(); - // assert_eq!(restored_tuple_data, tuple_data); +fn test_abi_write_impl(data: &A) -> Vec +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 { _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 { _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 { - _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 }, + }, ); }