From b606694631974e0ae6a23a9f46f9b595ed09894f Mon Sep 17 00:00:00 2001 From: Atkins Date: Sun, 31 Mar 2019 21:36:35 +0800 Subject: [PATCH 1/6] Fix dynamic array decoding --- ethabi/src/decoder.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ethabi/src/decoder.rs b/ethabi/src/decoder.rs index 4143f01e7..e432fcc2e 100644 --- a/ethabi/src/decoder.rs +++ b/ethabi/src/decoder.rs @@ -172,11 +172,12 @@ fn decode_param(param: &ParamType, slices: &[[u8; 32]], offset: usize) -> Result let len_slice = try!(peek(slices, len_offset)); let len = try!(as_u32(len_slice)) as usize; + let sub_slices = &slices[len_offset + 1..]; let mut tokens = vec![]; - let mut new_offset = len_offset + 1; + let mut new_offset = 0; for _ in 0..len { - let res = try!(decode_param(t, &slices, new_offset)); + let res = try!(decode_param(t, &sub_slices, new_offset)); new_offset = res.new_offset; tokens.push(res.token); } @@ -311,8 +312,8 @@ mod tests { let encoded = hex!(" 0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000000000000000000000000000000000000000000040 0000000000000000000000000000000000000000000000000000000000000080 - 00000000000000000000000000000000000000000000000000000000000000c0 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000001111111111111111111111111111111111111111 0000000000000000000000000000000000000000000000000000000000000001 @@ -338,8 +339,8 @@ mod tests { let encoded = hex!(" 0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000000000000000000000000000000000000000000080 - 00000000000000000000000000000000000000000000000000000000000000e0 + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 0000000000000000000000000000000000000000000000000000000000000002 0000000000000000000000001111111111111111111111111111111111111111 0000000000000000000000002222222222222222222222222222222222222222 From f76a0c13a32dbb582e71f0f8c785840837421099 Mon Sep 17 00:00:00 2001 From: Atkins Date: Sun, 31 Mar 2019 21:54:45 +0800 Subject: [PATCH 2/6] Using type definition `Word` to represent a abi word (32 bytes) --- ethabi/src/decoder.rs | 12 ++++++------ ethabi/src/encoder.rs | 14 +++++++------- ethabi/src/lib.rs | 3 +++ ethabi/src/util.rs | 8 ++++---- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ethabi/src/decoder.rs b/ethabi/src/decoder.rs index e432fcc2e..5d1802f71 100644 --- a/ethabi/src/decoder.rs +++ b/ethabi/src/decoder.rs @@ -1,7 +1,7 @@ //! ABI decoder. use util::slice_data; -use {Token, ErrorKind, Error, ResultExt, ParamType}; +use {Word, Token, ErrorKind, Error, ResultExt, ParamType}; struct DecodeResult { token: Token, @@ -13,7 +13,7 @@ struct BytesTaken { new_offset: usize, } -fn as_u32(slice: &[u8; 32]) -> Result { +fn as_u32(slice: &Word) -> Result { if !slice[..28].iter().all(|x| *x == 0) { return Err(ErrorKind::InvalidData.into()); } @@ -26,7 +26,7 @@ fn as_u32(slice: &[u8; 32]) -> Result { Ok(result) } -fn as_bool(slice: &[u8; 32]) -> Result { +fn as_bool(slice: &Word) -> Result { if !slice[..31].iter().all(|x| *x == 0) { return Err(ErrorKind::InvalidData.into()); } @@ -51,11 +51,11 @@ pub fn decode(types: &[ParamType], data: &[u8]) -> Result, Error> { Ok(tokens) } -fn peek(slices: &[[u8; 32]], position: usize) -> Result<&[u8; 32], Error> { +fn peek(slices: &[Word], position: usize) -> Result<&Word, Error> { slices.get(position).ok_or_else(|| ErrorKind::InvalidData.into()) } -fn take_bytes(slices: &[[u8; 32]], position: usize, len: usize) -> Result { +fn take_bytes(slices: &[Word], position: usize, len: usize) -> Result { let slices_len = (len + 31) / 32; let mut bytes_slices = vec![]; @@ -77,7 +77,7 @@ fn take_bytes(slices: &[[u8; 32]], position: usize, len: usize) -> Result Result { +fn decode_param(param: &ParamType, slices: &[Word], offset: usize) -> Result { match *param { ParamType::Address => { let slice = try!(peek(slices, offset)); diff --git a/ethabi/src/encoder.rs b/ethabi/src/encoder.rs index 2b9bb74a0..cee4ef8d2 100644 --- a/ethabi/src/encoder.rs +++ b/ethabi/src/encoder.rs @@ -1,15 +1,15 @@ //! ABI encoder. use util::pad_u32; -use {Token, Bytes}; +use {Word, Token, Bytes}; -fn pad_bytes(bytes: &[u8]) -> Vec<[u8; 32]> { +fn pad_bytes(bytes: &[u8]) -> Vec { let mut result = vec![pad_u32(bytes.len() as u32)]; result.extend(pad_fixed_bytes(bytes)); result } -fn pad_fixed_bytes(bytes: &[u8]) -> Vec<[u8; 32]> { +fn pad_fixed_bytes(bytes: &[u8]) -> Vec { let mut result = vec![]; let len = (bytes.len() + 31) / 32; for i in 0..len { @@ -33,8 +33,8 @@ fn pad_fixed_bytes(bytes: &[u8]) -> Vec<[u8; 32]> { #[derive(Debug)] enum Mediate { - Raw(Vec<[u8; 32]>), - Prefixed(Vec<[u8; 32]>), + Raw(Vec), + Prefixed(Vec), FixedArray(Vec), Array(Vec), } @@ -65,7 +65,7 @@ impl Mediate { mediates[0..position].iter().fold(init_len, |acc, m| acc + m.closing_len()) } - fn init(&self, suffix_offset: u32) -> Vec<[u8; 32]> { + fn init(&self, suffix_offset: u32) -> Vec { match *self { Mediate::Raw(ref raw) => raw.clone(), Mediate::FixedArray(ref nes) => { @@ -80,7 +80,7 @@ impl Mediate { } } - fn closing(&self, offset: u32) -> Vec<[u8; 32]> { + fn closing(&self, offset: u32) -> Vec { match *self { Mediate::Raw(_) => vec![], Mediate::Prefixed(ref pre) => pre.clone(), diff --git a/ethabi/src/lib.rs b/ethabi/src/lib.rs index f9918dcd2..4992fabbc 100644 --- a/ethabi/src/lib.rs +++ b/ethabi/src/lib.rs @@ -50,6 +50,9 @@ pub use log::{Log, RawLog, LogParam, ParseLog, LogFilter}; pub use event::Event; pub use event_param::EventParam; +/// ABI word. +pub type Word = [u8; 32]; + /// ABI address. pub type Address = ethereum_types::Address; diff --git a/ethabi/src/util.rs b/ethabi/src/util.rs index 600c59117..ee719403f 100644 --- a/ethabi/src/util.rs +++ b/ethabi/src/util.rs @@ -1,9 +1,9 @@ //! Utils used by different modules. -use {Error, ErrorKind}; +use {Word, Error, ErrorKind}; /// Convers vector of bytes with len equal n * 32, to a vector of slices. -pub fn slice_data(data: &[u8]) -> Result, Error> { +pub fn slice_data(data: &[u8]) -> Result, Error> { if data.len() % 32 != 0 { return Err(ErrorKind::InvalidData.into()); } @@ -20,7 +20,7 @@ pub fn slice_data(data: &[u8]) -> Result, Error> { } /// Converts u32 to right aligned array of 32 bytes. -pub fn pad_u32(value: u32) -> [u8; 32] { +pub fn pad_u32(value: u32) -> Word { let mut padded = [0u8; 32]; padded[28] = (value >> 24) as u8; padded[29] = (value >> 16) as u8; @@ -30,7 +30,7 @@ pub fn pad_u32(value: u32) -> [u8; 32] { } /// Converts i32 to right aligned array of 32 bytes. -pub fn pad_i32(value: i32) -> [u8; 32] { +pub fn pad_i32(value: i32) -> Word { if value >= 0 { return pad_u32(value as u32); } From 2b2c4a64c8d504d9263bb62bf9d22ef264d1bb98 Mon Sep 17 00:00:00 2001 From: Atkins Date: Mon, 1 Apr 2019 01:54:47 +0800 Subject: [PATCH 3/6] Fix fixed-length array encoding/decoding --- ethabi/src/decoder.rs | 31 ++++++-- ethabi/src/encoder.rs | 114 ++++++++++++++-------------- ethabi/src/param_type/param_type.rs | 25 ++++++ ethabi/src/token/token.rs | 24 ++++++ 4 files changed, 128 insertions(+), 66 deletions(-) diff --git a/ethabi/src/decoder.rs b/ethabi/src/decoder.rs index 5d1802f71..1e32a21fd 100644 --- a/ethabi/src/decoder.rs +++ b/ethabi/src/decoder.rs @@ -190,13 +190,29 @@ fn decode_param(param: &ParamType, slices: &[Word], offset: usize) -> Result { - let mut tokens = vec![]; - let mut new_offset = offset; - for _ in 0..len { - let res = try!(decode_param(t, &slices, new_offset)); - new_offset = res.new_offset; - tokens.push(res.token); - } + let mut tokens = Vec::with_capacity(len); + let new_offset = if param.is_dynamic() { + let offset_slice = peek(slices, offset)?; + let tail_offset = (as_u32(offset_slice)? / 32) as usize; + let slices = &slices[tail_offset..]; + let mut new_offset = 0; + + for _ in 0..len { + let res = decode_param(t, &slices, new_offset)?; + new_offset = res.new_offset; + tokens.push(res.token); + } + offset + 1 + } else { + let mut new_offset = offset; + + for _ in 0..len { + let res = decode_param(t, &slices, new_offset)?; + new_offset = res.new_offset; + tokens.push(res.token); + } + new_offset + }; let result = DecodeResult { token: Token::FixedArray(tokens), @@ -395,6 +411,7 @@ mod tests { #[test] fn decode_fixed_array_of_dynamic_array_of_addresses() { let encoded = hex!(" + 0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000040 00000000000000000000000000000000000000000000000000000000000000a0 0000000000000000000000000000000000000000000000000000000000000002 diff --git a/ethabi/src/encoder.rs b/ethabi/src/encoder.rs index cee4ef8d2..b7a638546 100644 --- a/ethabi/src/encoder.rs +++ b/ethabi/src/encoder.rs @@ -35,100 +35,91 @@ fn pad_fixed_bytes(bytes: &[u8]) -> Vec { enum Mediate { Raw(Vec), Prefixed(Vec), - FixedArray(Vec), - Array(Vec), + PrefixedArray(Vec), + PrefixedArrayWithLength(Vec), } impl Mediate { - fn init_len(&self) -> u32 { + fn head_len(&self) -> u32 { match *self { Mediate::Raw(ref raw) => 32 * raw.len() as u32, - Mediate::Prefixed(_) => 32, - Mediate::FixedArray(ref nes) => nes.iter().fold(0, |acc, m| acc + m.init_len()), - Mediate::Array(_) => 32, + Mediate::Prefixed(_) | Mediate::PrefixedArray(_) | Mediate::PrefixedArrayWithLength(_) => 32, } } - fn closing_len(&self) -> u32 { + fn tail_len(&self) -> u32 { match *self { Mediate::Raw(_) => 0, Mediate::Prefixed(ref pre) => pre.len() as u32 * 32, - Mediate::FixedArray(ref nes) => nes.iter().fold(0, |acc, m| acc + m.closing_len()), - Mediate::Array(ref nes) => nes.iter().fold(32, |acc, m| acc + m.init_len() + m.closing_len()), + Mediate::PrefixedArray(ref mediates) => mediates.iter().fold(0, |acc, m| acc + m.head_len() + m.tail_len()), + Mediate::PrefixedArrayWithLength(ref mediates) => mediates.iter().fold(32, |acc, m| acc + m.head_len() + m.tail_len()), } } - fn offset_for(mediates: &[Mediate], position: usize) -> u32 { - assert!(position < mediates.len()); - - let init_len = mediates.iter().fold(0, |acc, m| acc + m.init_len()); - mediates[0..position].iter().fold(init_len, |acc, m| acc + m.closing_len()) - } - - fn init(&self, suffix_offset: u32) -> Vec { + fn head(&self, suffix_offset: u32) -> Vec { match *self { Mediate::Raw(ref raw) => raw.clone(), - Mediate::FixedArray(ref nes) => { - nes.iter() - .enumerate() - .flat_map(|(i, m)| m.init(Mediate::offset_for(nes, i))) - .collect() - }, - Mediate::Prefixed(_) | Mediate::Array(_) => { + Mediate::Prefixed(_) | Mediate::PrefixedArray(_) | Mediate::PrefixedArrayWithLength(_) => { vec![pad_u32(suffix_offset)] } } } - fn closing(&self, offset: u32) -> Vec { + fn tail(&self) -> Vec { match *self { Mediate::Raw(_) => vec![], - Mediate::Prefixed(ref pre) => pre.clone(), - Mediate::FixedArray(ref nes) => { - // offset is not taken into account, cause it would be counted twice - // fixed array is just raw representations of similar consecutive items - nes.iter() - .enumerate() - .flat_map(|(i, m)| m.closing(Mediate::offset_for(nes, i))) - .collect() - }, - Mediate::Array(ref nes) => { - // + 32 added to offset represents len of the array prepanded to closing - let prefix = vec![pad_u32(nes.len() as u32)].into_iter(); - - let inits = nes.iter() - .enumerate() - .flat_map(|(i, m)| m.init(Mediate::offset_for(nes, i))); + Mediate::Prefixed(ref raw) => raw.clone(), + Mediate::PrefixedArray(ref mediates) => encode_head_tail(mediates), + Mediate::PrefixedArrayWithLength(ref mediates) => { + // + 32 added to offset represents len of the array prepanded to tail + let mut result = vec![pad_u32(mediates.len() as u32)]; - let closings = nes.iter() - .enumerate() - .flat_map(|(i, m)| m.closing(offset + Mediate::offset_for(nes, i))); + let head_tail = encode_head_tail(mediates); - prefix.chain(inits).chain(closings).collect() + result.extend(head_tail); + result }, } } } -/// Encodes vector of tokens into ABI compliant vector of bytes. +fn encode_head_tail(mediates: &Vec) -> Vec { + let heads_len = mediates.iter() + .fold(0, |acc, m| acc + m.head_len()); + + let (mut result, len) = mediates.iter() + .fold( + (Vec::with_capacity(heads_len as usize), heads_len), + |(mut acc, offset), m| { + acc.extend(m.head(offset)); + (acc, offset + m.tail_len()) + } + ); + + let tails = mediates.iter() + .fold( + Vec::with_capacity((len - heads_len) as usize), + |mut acc, m| { + acc.extend(m.tail()); + acc + } + ); + + result.extend(tails); + result +} + pub fn encode(tokens: &[Token]) -> Bytes { - let mediates: Vec = tokens.iter() + let mediates = &tokens.iter() .map(encode_token) .collect(); - let inits = mediates.iter() - .enumerate() - .flat_map(|(i, m)| m.init(Mediate::offset_for(&mediates, i))); - - let closings = mediates.iter() - .enumerate() - .flat_map(|(i, m)| m.closing(Mediate::offset_for(&mediates, i))); - - inits.chain(closings) - .flat_map(|item| item.to_vec()) + encode_head_tail(mediates).iter() + .flat_map(|word| word.to_vec()) .collect() } +/// Encodes vector of tokens into ABI compliant vector of bytes. fn encode_token(token: &Token) -> Mediate { match *token { Token::Address(ref address) => { @@ -153,14 +144,18 @@ fn encode_token(token: &Token) -> Mediate { .map(encode_token) .collect(); - Mediate::Array(mediates) + Mediate::PrefixedArrayWithLength(mediates) }, Token::FixedArray(ref tokens) => { let mediates = tokens.iter() .map(encode_token) .collect(); - Mediate::FixedArray(mediates) + if token.is_dynamic() { + Mediate::PrefixedArray(mediates) + } else { + Mediate::Raw(encode_head_tail(&mediates)) + } }, } } @@ -229,6 +224,7 @@ mod tests { let fixed = Token::FixedArray(vec![array0, array1]); let encoded = encode(&vec![fixed]); let expected = hex!(" + 0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000040 00000000000000000000000000000000000000000000000000000000000000a0 0000000000000000000000000000000000000000000000000000000000000002 diff --git a/ethabi/src/param_type/param_type.rs b/ethabi/src/param_type/param_type.rs index aaa140087..7c2073169 100644 --- a/ethabi/src/param_type/param_type.rs +++ b/ethabi/src/param_type/param_type.rs @@ -42,6 +42,15 @@ impl ParamType { _ => false, } } + + /// returns whether this param type is dynamic + pub fn is_dynamic(&self) -> bool { + match self { + ParamType::Bytes | ParamType::String | ParamType::Array(_) => true, + ParamType::FixedArray(elem_type, _) => elem_type.is_dynamic(), + _ => false + } + } } #[cfg(test)] @@ -58,7 +67,23 @@ mod tests { assert_eq!(format!("{}", ParamType::Bool), "bool".to_owned()); assert_eq!(format!("{}", ParamType::String), "string".to_owned()); assert_eq!(format!("{}", ParamType::Array(Box::new(ParamType::Bool))), "bool[]".to_owned()); + assert_eq!(format!("{}", ParamType::FixedArray(Box::new(ParamType::Uint(256)), 2)), "uint256[2]".to_owned()); assert_eq!(format!("{}", ParamType::FixedArray(Box::new(ParamType::String), 2)), "string[2]".to_owned()); assert_eq!(format!("{}", ParamType::FixedArray(Box::new(ParamType::Array(Box::new(ParamType::Bool))), 2)), "bool[][2]".to_owned()); } + + #[test] + fn test_is_dynamic() { + assert_eq!(ParamType::Address.is_dynamic(), false); + assert_eq!(ParamType::Bytes.is_dynamic(), true); + assert_eq!(ParamType::FixedBytes(32).is_dynamic(), false); + assert_eq!(ParamType::Uint(256).is_dynamic(), false); + assert_eq!(ParamType::Int(64).is_dynamic(), false); + assert_eq!(ParamType::Bool.is_dynamic(), false); + assert_eq!(ParamType::String.is_dynamic(), true); + assert_eq!(ParamType::Array(Box::new(ParamType::Bool)).is_dynamic(), true); + assert_eq!(ParamType::FixedArray(Box::new(ParamType::Uint(256)), 2).is_dynamic(), false); + assert_eq!(ParamType::FixedArray(Box::new(ParamType::String), 2).is_dynamic(), true); + assert_eq!(ParamType::FixedArray(Box::new(ParamType::Array(Box::new(ParamType::Bool))), 2).is_dynamic(), true); + } } diff --git a/ethabi/src/token/token.rs b/ethabi/src/token/token.rs index edf04e61b..cd734b43c 100644 --- a/ethabi/src/token/token.rs +++ b/ethabi/src/token/token.rs @@ -73,6 +73,15 @@ impl fmt::Display for Token { } impl Token { + /// Returns whether this token is dynamic + pub fn is_dynamic(&self) -> bool { + match self { + Token::Bytes(_) | Token::String(_) | Token::Array(_) => true, + Token::FixedArray(ref tokens) => tokens.iter().any(|ref token| token.is_dynamic()), + _ => false + } + } + /// Check whether the type of the token matches the given parameter type. /// /// Numeric types (`Int` and `Uint`) type check if the size of the token @@ -233,4 +242,19 @@ mod tests { assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Uint(0.into())])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)]); assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Address), 2)]); } + + #[test] + fn test_is_dynamic() { + assert_eq!(Token::Address("0000000000000000000000000000000000000000".parse().unwrap()).is_dynamic(), false); + assert_eq!(Token::Bytes(vec![0, 0, 0, 0]).is_dynamic(), true); + assert_eq!(Token::FixedBytes(vec![0, 0, 0, 0]).is_dynamic(), false); + assert_eq!(Token::Uint(0.into()).is_dynamic(), false); + assert_eq!(Token::Int(0.into()).is_dynamic(), false); + assert_eq!(Token::Bool(false).is_dynamic(), false); + assert_eq!(Token::String("".into()).is_dynamic(), true); + assert_eq!(Token::Array(vec![Token::Bool(false)]).is_dynamic(), true); + assert_eq!(Token::FixedArray(vec![Token::Uint(0.into())]).is_dynamic(), false); + assert_eq!(Token::FixedArray(vec![Token::String("".into())]).is_dynamic(), true); + assert_eq!(Token::FixedArray(vec![Token::Array(vec![Token::Bool(false)])]).is_dynamic(), true); + } } From f5b3f39d1dd2d6605fdf55b95d3ae7617175428e Mon Sep 17 00:00:00 2001 From: Atkins Date: Mon, 1 Apr 2019 02:44:53 +0800 Subject: [PATCH 4/6] Combine encoding/decoding testing --- Cargo.lock | 42 +++- ethabi/Cargo.toml | 1 + ethabi/src/decoder.rs | 283 +---------------------- ethabi/src/encoder.rs | 405 +-------------------------------- ethabi/src/lib.rs | 6 + ethabi/src/tests.rs | 513 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 560 insertions(+), 690 deletions(-) create mode 100644 ethabi/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 98ff9d04b..b246bd370 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,7 @@ dependencies = [ "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -140,7 +141,7 @@ dependencies = [ "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -305,6 +306,26 @@ dependencies = [ "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "paste" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "paste-impl" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "primitive-types" version = "0.3.0" @@ -325,6 +346,16 @@ dependencies = [ "proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro-hack-impl" version = "0.4.0" @@ -422,7 +453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -448,7 +479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.4" +version = "0.15.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -561,8 +592,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" "checksum parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb43c05fb71c03b4ea7327bf15694da1e0f23f19d5b1e95bab6c6d74097e336" +"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79" +"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6" "checksum primitive-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2288eb2a39386c4bc817974cc413afe173010dc80e470fcb1e9a35580869f024" "checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" +"checksum proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "982a35d1194084ba319d65c4a68d24ca28f5fdb5b8bc20899e4eef8641ea5178" "checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" "checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" @@ -579,7 +613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9056ebe7f2d6a38bc63171816fd1d3430da5a43896de21676dc5c0a4b8274a11" +"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" diff --git a/ethabi/Cargo.toml b/ethabi/Cargo.toml index 4a737bccb..f36b3f7d9 100644 --- a/ethabi/Cargo.toml +++ b/ethabi/Cargo.toml @@ -18,6 +18,7 @@ ethereum-types = "0.6.0" [dev-dependencies] hex-literal = "0.1.1" +paste = "0.1.5" [features] backtrace = ["error-chain/backtrace"] diff --git a/ethabi/src/decoder.rs b/ethabi/src/decoder.rs index 1e32a21fd..f8bda469a 100644 --- a/ethabi/src/decoder.rs +++ b/ethabi/src/decoder.rs @@ -226,288 +226,7 @@ fn decode_param(param: &ParamType, slices: &[Word], offset: usize) -> Result) -> Vec { result } +/// Encodes vector of tokens into ABI compliant vector of bytes. pub fn encode(tokens: &[Token]) -> Bytes { let mediates = &tokens.iter() .map(encode_token) @@ -119,7 +120,6 @@ pub fn encode(tokens: &[Token]) -> Bytes { .collect() } -/// Encodes vector of tokens into ABI compliant vector of bytes. fn encode_token(token: &Token) -> Mediate { match *token { Token::Address(ref address) => { @@ -163,334 +163,6 @@ fn encode_token(token: &Token) -> Mediate { #[cfg(test)] mod tests { use util::pad_u32; - use {Token, encode}; - - #[test] - fn encode_address() { - let address = Token::Address([0x11u8; 20].into()); - let encoded = encode(&vec![address]); - let expected = hex!("0000000000000000000000001111111111111111111111111111111111111111"); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_dynamic_array_of_addresses() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let addresses = Token::Array(vec![address1, address2]); - let encoded = encode(&vec![addresses]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_fixed_array_of_addresses() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let addresses = Token::FixedArray(vec![address1, address2]); - let encoded = encode(&vec![addresses]); - let expected = hex!(" - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_two_addresses() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let encoded = encode(&vec![address1, address2]); - let expected = hex!(" - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_fixed_array_of_dynamic_array_of_addresses() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let address3 = Token::Address([0x33u8; 20].into()); - let address4 = Token::Address([0x44u8; 20].into()); - let array0 = Token::Array(vec![address1, address2]); - let array1 = Token::Array(vec![address3, address4]); - let fixed = Token::FixedArray(vec![array0, array1]); - let encoded = encode(&vec![fixed]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000040 - 00000000000000000000000000000000000000000000000000000000000000a0 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000003333333333333333333333333333333333333333 - 0000000000000000000000004444444444444444444444444444444444444444 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_dynamic_array_of_fixed_array_of_addresses() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let address3 = Token::Address([0x33u8; 20].into()); - let address4 = Token::Address([0x44u8; 20].into()); - let array0 = Token::FixedArray(vec![address1, address2]); - let array1 = Token::FixedArray(vec![address3, address4]); - let dynamic = Token::Array(vec![array0, array1]); - let encoded = encode(&vec![dynamic]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - 0000000000000000000000003333333333333333333333333333333333333333 - 0000000000000000000000004444444444444444444444444444444444444444 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_dynamic_array_of_dynamic_arrays() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let array0 = Token::Array(vec![address1]); - let array1 = Token::Array(vec![address2]); - let dynamic = Token::Array(vec![array0, array1]); - let encoded = encode(&vec![dynamic]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000000000000000000000000000000000000000000040 - 0000000000000000000000000000000000000000000000000000000000000080 - 0000000000000000000000000000000000000000000000000000000000000001 - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000000000000000000000000000000000000000000001 - 0000000000000000000000002222222222222222222222222222222222222222 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_dynamic_array_of_dynamic_arrays2() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let address3 = Token::Address([0x33u8; 20].into()); - let address4 = Token::Address([0x44u8; 20].into()); - let array0 = Token::Array(vec![address1, address2]); - let array1 = Token::Array(vec![address3, address4]); - let dynamic = Token::Array(vec![array0, array1]); - let encoded = encode(&vec![dynamic]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000000000000000000000000000000000000000000040 - 00000000000000000000000000000000000000000000000000000000000000a0 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000003333333333333333333333333333333333333333 - 0000000000000000000000004444444444444444444444444444444444444444 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_fixed_array_of_fixed_arrays() { - let address1 = Token::Address([0x11u8; 20].into()); - let address2 = Token::Address([0x22u8; 20].into()); - let address3 = Token::Address([0x33u8; 20].into()); - let address4 = Token::Address([0x44u8; 20].into()); - let array0 = Token::FixedArray(vec![address1, address2]); - let array1 = Token::FixedArray(vec![address3, address4]); - let fixed = Token::FixedArray(vec![array0, array1]); - let encoded = encode(&vec![fixed]); - let expected = hex!(" - 0000000000000000000000001111111111111111111111111111111111111111 - 0000000000000000000000002222222222222222222222222222222222222222 - 0000000000000000000000003333333333333333333333333333333333333333 - 0000000000000000000000004444444444444444444444444444444444444444 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_empty_array() { - // Empty arrays - let encoded = encode(&vec![ - Token::Array(vec![]), - Token::Array(vec![])] - ); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000040 - 0000000000000000000000000000000000000000000000000000000000000060 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - - // Nested empty arrays - let encoded = encode(&vec![ - Token::Array(vec![Token::Array(vec![])]), - Token::Array(vec![Token::Array(vec![])]), - ]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000040 - 00000000000000000000000000000000000000000000000000000000000000a0 - 0000000000000000000000000000000000000000000000000000000000000001 - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000001 - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_bytes() { - let bytes = Token::Bytes(vec![0x12, 0x34]); - let encoded = encode(&vec![bytes]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000002 - 1234000000000000000000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_fixed_bytes() { - let bytes = Token::FixedBytes(vec![0x12, 0x34]); - let encoded = encode(&vec![bytes]); - let expected = hex!("1234000000000000000000000000000000000000000000000000000000000000"); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_string() { - let s = Token::String("gavofyork".to_owned()); - let encoded = encode(&vec![s]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000009 - 6761766f66796f726b0000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_bytes2() { - let bytes = Token::Bytes(hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec()); - let encoded = encode(&vec![bytes]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 000000000000000000000000000000000000000000000000000000000000001f - 1000000000000000000000000000000000000000000000000000000000000200 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_bytes3() { - let bytes = Token::Bytes(hex!(" - 1000000000000000000000000000000000000000000000000000000000000000 - 1000000000000000000000000000000000000000000000000000000000000000 - ").to_vec()); - let encoded = encode(&vec![bytes]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000040 - 1000000000000000000000000000000000000000000000000000000000000000 - 1000000000000000000000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_two_bytes() { - let bytes1 = Token::Bytes(hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec()); - let bytes2 = Token::Bytes(hex!("0010000000000000000000000000000000000000000000000000000000000002").to_vec()); - let encoded = encode(&vec![bytes1, bytes2]); - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000040 - 0000000000000000000000000000000000000000000000000000000000000080 - 000000000000000000000000000000000000000000000000000000000000001f - 1000000000000000000000000000000000000000000000000000000000000200 - 0000000000000000000000000000000000000000000000000000000000000020 - 0010000000000000000000000000000000000000000000000000000000000002 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_uint() { - let mut uint = [0u8; 32]; - uint[31] = 4; - let encoded = encode(&vec![Token::Uint(uint.into())]); - let expected = hex!("0000000000000000000000000000000000000000000000000000000000000004"); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_int() { - let mut int = [0u8; 32]; - int[31] = 4; - let encoded = encode(&vec![Token::Int(int.into())]); - let expected = hex!("0000000000000000000000000000000000000000000000000000000000000004"); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_bool() { - let encoded = encode(&vec![Token::Bool(true)]); - let expected = hex!("0000000000000000000000000000000000000000000000000000000000000001"); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_bool2() { - let encoded = encode(&vec![Token::Bool(false)]); - let expected = hex!("0000000000000000000000000000000000000000000000000000000000000000"); - assert_eq!(encoded, expected); - } - - #[test] - fn comprehensive_test() { - let bytes = hex!(" - 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b - 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b - ").to_vec(); - let encoded = encode(&vec![ - Token::Int(5.into()), - Token::Bytes(bytes.clone()), - Token::Int(3.into()), - Token::Bytes(bytes) - ]); - - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000005 - 0000000000000000000000000000000000000000000000000000000000000080 - 0000000000000000000000000000000000000000000000000000000000000003 - 00000000000000000000000000000000000000000000000000000000000000e0 - 0000000000000000000000000000000000000000000000000000000000000040 - 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b - 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b - 0000000000000000000000000000000000000000000000000000000000000040 - 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b - 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b - ").to_vec(); - assert_eq!(encoded, expected); - } #[test] fn test_pad_u32() { @@ -498,80 +170,5 @@ mod tests { assert_eq!(pad_u32(0x1)[31], 1); assert_eq!(pad_u32(0x100)[30], 1); } - - #[test] - fn comprehensive_test2() { - let encoded = encode(&vec![ - Token::Int(1.into()), - Token::String("gavofyork".to_owned()), - Token::Int(2.into()), - Token::Int(3.into()), - Token::Int(4.into()), - Token::Array(vec![ - Token::Int(5.into()), - Token::Int(6.into()), - Token::Int(7.into()), - ]) - ]); - - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000001 - 00000000000000000000000000000000000000000000000000000000000000c0 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000000000000000000000000000000000000000000003 - 0000000000000000000000000000000000000000000000000000000000000004 - 0000000000000000000000000000000000000000000000000000000000000100 - 0000000000000000000000000000000000000000000000000000000000000009 - 6761766f66796f726b0000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000003 - 0000000000000000000000000000000000000000000000000000000000000005 - 0000000000000000000000000000000000000000000000000000000000000006 - 0000000000000000000000000000000000000000000000000000000000000007 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_dynamic_array_of_bytes() { - let bytes = - hex!("019c80031b20d5e69c8093a571162299032018d913930d93ab320ae5ea44a4218a274f00d607"); - let encoded = encode(&vec![Token::Array(vec![Token::Bytes(bytes.to_vec())])]); - - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000001 - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000026 - 019c80031b20d5e69c8093a571162299032018d913930d93ab320ae5ea44a421 - 8a274f00d6070000000000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - } - - #[test] - fn encode_dynamic_array_of_bytes2() { - let bytes = - hex!("4444444444444444444444444444444444444444444444444444444444444444444444444444"); - let bytes2 = - hex!("6666666666666666666666666666666666666666666666666666666666666666666666666666"); - let encoded = encode(&vec![Token::Array(vec![ - Token::Bytes(bytes.to_vec()), - Token::Bytes(bytes2.to_vec()), - ])]); - - let expected = hex!(" - 0000000000000000000000000000000000000000000000000000000000000020 - 0000000000000000000000000000000000000000000000000000000000000002 - 0000000000000000000000000000000000000000000000000000000000000040 - 00000000000000000000000000000000000000000000000000000000000000a0 - 0000000000000000000000000000000000000000000000000000000000000026 - 4444444444444444444444444444444444444444444444444444444444444444 - 4444444444440000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000026 - 6666666666666666666666666666666666666666666666666666666666666666 - 6666666666660000000000000000000000000000000000000000000000000000 - ").to_vec(); - assert_eq!(encoded, expected); - } } diff --git a/ethabi/src/lib.rs b/ethabi/src/lib.rs index 4992fabbc..9f0ce92c3 100644 --- a/ethabi/src/lib.rs +++ b/ethabi/src/lib.rs @@ -17,6 +17,9 @@ extern crate error_chain; #[macro_use] extern crate hex_literal; +#[cfg(test)] +extern crate paste; + extern crate ethereum_types; pub mod param_type; @@ -36,6 +39,9 @@ mod param; mod signature; mod util; +#[cfg(test)] +mod tests; + pub use param_type::ParamType; pub use constructor::Constructor; pub use contract::{Contract, Functions, Events}; diff --git a/ethabi/src/tests.rs b/ethabi/src/tests.rs new file mode 100644 index 000000000..90efc6e71 --- /dev/null +++ b/ethabi/src/tests.rs @@ -0,0 +1,513 @@ +use {encode, decode, Token, ParamType}; + +macro_rules! test_encode_decode { + (name: $name:tt, types: $types:expr, tokens: $tokens:expr, data: $data:tt) => { + $crate::paste::item! { + #[test] + fn []() { + let encoded = encode(&$tokens); + let expected = $crate::hex_literal::hex!($data).to_vec(); + assert_eq!(encoded, expected); + } + + #[test] + fn []() { + let encoded = hex!($data); + let expected = $tokens; + let decoded = decode(&$types, &encoded).unwrap(); + assert_eq!(decoded, expected); + } + } + } +} + +// test address +test_encode_decode! { + name: address, + types: [ParamType::Address], + tokens: [Token::Address([0x11u8; 20].into())], + data: "0000000000000000000000001111111111111111111111111111111111111111" +} +test_encode_decode! { + name: addresses, + types: [ + ParamType::Address, + ParamType::Address + ], + tokens: [ + Token::Address([0x11u8; 20].into()), + Token::Address([0x22u8; 20].into()) + ], + data: " + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222" +} + +// test bytes +test_encode_decode! { + name: bytes, + types: [ParamType::Bytes], + tokens: [Token::Bytes(vec![0x12, 0x34])], + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 1234000000000000000000000000000000000000000000000000000000000000" +} +test_encode_decode! { + name: bytes2, + types: [ParamType::Bytes], + tokens: [Token::Bytes(hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec())], + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000001f + 1000000000000000000000000000000000000000000000000000000000000200" +} +test_encode_decode! { + name: bytes3, + types: [ParamType::Bytes], + tokens: [ + Token::Bytes(hex!(" + 1000000000000000000000000000000000000000000000000000000000000000 + 1000000000000000000000000000000000000000000000000000000000000000 + ").to_vec()) + ], + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000040 + 1000000000000000000000000000000000000000000000000000000000000000 + 1000000000000000000000000000000000000000000000000000000000000000" +} +test_encode_decode! { + name: two_bytes, + types: [ParamType::Bytes, ParamType::Bytes], + tokens: [ + Token::Bytes(hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec()), + Token::Bytes(hex!("0010000000000000000000000000000000000000000000000000000000000002").to_vec()) + ], + data: " + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 000000000000000000000000000000000000000000000000000000000000001f + 1000000000000000000000000000000000000000000000000000000000000200 + 0000000000000000000000000000000000000000000000000000000000000020 + 0010000000000000000000000000000000000000000000000000000000000002" +} + +// test int +test_encode_decode! { + name: int, + types: [ParamType::Int(32)], + tokens: [Token::Int([0x11u8; 32].into())], + data: "1111111111111111111111111111111111111111111111111111111111111111" +} +test_encode_decode! { + name: int2, + types: [ParamType::Int(32)], + tokens: { + let mut int = [0u8; 32]; + int[31] = 4; + [Token::Int(int.into())] + }, + data: "0000000000000000000000000000000000000000000000000000000000000004" +} + +// test uint +test_encode_decode! { + name: uint, + types: [ParamType::Uint(32)], + tokens: [Token::Uint([0x11u8; 32].into())], + data: "1111111111111111111111111111111111111111111111111111111111111111" +} +test_encode_decode! { + name: uint2, + types: [ParamType::Uint(32)], + tokens: { + let mut uint = [0u8; 32]; + uint[31] = 4; + [Token::Uint(uint.into())] + }, + data: "0000000000000000000000000000000000000000000000000000000000000004" +} + +// test bool +test_encode_decode! { + name: bool, + types: [ParamType::Bool], + tokens: [Token::Bool(true)], + data: "0000000000000000000000000000000000000000000000000000000000000001" +} +test_encode_decode! { + name: bool2, + types: [ParamType::Bool], + tokens: [Token::Bool(false)], + data: "0000000000000000000000000000000000000000000000000000000000000000" +} + +// test string +test_encode_decode! { + name: string, + types: [ParamType::String], + tokens: [Token::String("gavofyork".to_owned())], + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000009 + 6761766f66796f726b0000000000000000000000000000000000000000000000" +} + +// test array +test_encode_decode! { + name: dynamic_array_of_addresses, + types: [ParamType::Array(Box::new(ParamType::Address))], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + [Token::Array(vec![address1, address2])] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222" +} +test_encode_decode! { + name: dynamic_array_of_fixed_arrays_of_addresses, + types: [ + ParamType::Array(Box::new( + ParamType::FixedArray(Box::new(ParamType::Address), 2) + )) + ], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + let address3 = Token::Address([0x33u8; 20].into()); + let address4 = Token::Address([0x44u8; 20].into()); + let array0 = Token::FixedArray(vec![address1, address2]); + let array1 = Token::FixedArray(vec![address3, address4]); + [Token::Array(vec![array0, array1])] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222 + 0000000000000000000000003333333333333333333333333333333333333333 + 0000000000000000000000004444444444444444444444444444444444444444" +} +test_encode_decode! { + name: dynamic_array_of_fixed_arrays_of_dynamic_array, + types: [ + ParamType::Array(Box::new( + ParamType::FixedArray(Box::new(ParamType::Array(Box::new(ParamType::Address))), 2) + )) + ], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + let address3 = Token::Address([0x33u8; 20].into()); + let address4 = Token::Address([0x44u8; 20].into()); + let address5 = Token::Address([0x55u8; 20].into()); + let address6 = Token::Address([0x66u8; 20].into()); + let address7 = Token::Address([0x77u8; 20].into()); + let address8 = Token::Address([0x88u8; 20].into()); + let array0 = Token::FixedArray(vec![ + Token::Array(vec![address1, address2]), + Token::Array(vec![address3, address4]), + ]); + let array1 = Token::FixedArray(vec![ + Token::Array(vec![address5, address6]), + Token::Array(vec![address7, address8]), + ]); + [Token::Array(vec![array0, array1])] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000140 + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000003333333333333333333333333333333333333333 + 0000000000000000000000004444444444444444444444444444444444444444 + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000005555555555555555555555555555555555555555 + 0000000000000000000000006666666666666666666666666666666666666666 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000007777777777777777777777777777777777777777 + 0000000000000000000000008888888888888888888888888888888888888888" +} +test_encode_decode! { + name: dynamic_array_of_dynamic_arrays, + types: [ + ParamType::Array(Box::new( + ParamType::Array(Box::new(ParamType::Address)) + )) + ], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + let array0 = Token::Array(vec![address1]); + let array1 = Token::Array(vec![address2]); + let dynamic = Token::Array(vec![array0, array1]); + [dynamic] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000002222222222222222222222222222222222222222" +} +test_encode_decode! { + name: dynamic_array_of_dynamic_arrays2, + types: [ + ParamType::Array(Box::new( + ParamType::Array(Box::new(ParamType::Address)) + )) + ], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + let address3 = Token::Address([0x33u8; 20].into()); + let address4 = Token::Address([0x44u8; 20].into()); + let array0 = Token::Array(vec![address1, address2]); + let array1 = Token::Array(vec![address3, address4]); + let dynamic = Token::Array(vec![array0, array1]); + [dynamic] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000003333333333333333333333333333333333333333 + 0000000000000000000000004444444444444444444444444444444444444444" +} +test_encode_decode! { + name: dynamic_array_of_bytes, + types: [ParamType::Array(Box::new(ParamType::Bytes))], + tokens: { + let bytes = hex!("019c80031b20d5e69c8093a571162299032018d913930d93ab320ae5ea44a4218a274f00d607").to_vec(); + [Token::Array(vec![Token::Bytes(bytes)])] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000026 + 019c80031b20d5e69c8093a571162299032018d913930d93ab320ae5ea44a421 + 8a274f00d6070000000000000000000000000000000000000000000000000000" +} +test_encode_decode! { + name: dynamic_array_of_bytes2, + types: [ParamType::Array(Box::new(ParamType::Bytes))], + tokens: [ + Token::Array(vec![ + Token::Bytes(hex!("4444444444444444444444444444444444444444444444444444444444444444444444444444").to_vec()), + Token::Bytes(hex!("6666666666666666666666666666666666666666666666666666666666666666666666666666").to_vec()), + ]) + ], + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 + 0000000000000000000000000000000000000000000000000000000000000026 + 4444444444444444444444444444444444444444444444444444444444444444 + 4444444444440000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000026 + 6666666666666666666666666666666666666666666666666666666666666666 + 6666666666660000000000000000000000000000000000000000000000000000" +} +test_encode_decode! { + name: empty_dynamic_array, + types: [ + ParamType::Array(Box::new(ParamType::Bool)), + ParamType::Array(Box::new(ParamType::Bool)), + ], + tokens: [ + Token::Array(vec![]), + Token::Array(vec![]) + ], + data: " + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000060 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000" +} +test_encode_decode! { + name: dynamic_array_of_empty_dynamic_array, + types: [ + ParamType::Array(Box::new(ParamType::Array(Box::new(ParamType::Bool)))), + ParamType::Array(Box::new(ParamType::Array(Box::new(ParamType::Bool)))), + ], + tokens: [ + Token::Array(vec![Token::Array(vec![])]), + Token::Array(vec![Token::Array(vec![])]), + ], + data: " + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000000" +} + +// test fixed array +test_encode_decode! { + name: fixed_array_of_addresses, + types: [ParamType::FixedArray(Box::new(ParamType::Address), 2)], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + [Token::FixedArray(vec![address1, address2])] + }, + data: " + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222" +} +test_encode_decode! { + name: fixed_array_of_fixed_arrays, + types: [ + ParamType::FixedArray( + Box::new(ParamType::FixedArray(Box::new(ParamType::Address), 2)), + 2 + ) + ], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + let address3 = Token::Address([0x33u8; 20].into()); + let address4 = Token::Address([0x44u8; 20].into()); + let array0 = Token::FixedArray(vec![address1, address2]); + let array1 = Token::FixedArray(vec![address3, address4]); + let fixed = Token::FixedArray(vec![array0, array1]); + [fixed] + }, + data: " + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222 + 0000000000000000000000003333333333333333333333333333333333333333 + 0000000000000000000000004444444444444444444444444444444444444444" +} +test_encode_decode! { + name: fixed_array_of_dynamic_array_of_addresses, + types: [ + ParamType::FixedArray( + Box::new(ParamType::Array(Box::new(ParamType::Address))), + 2 + ) + ], + tokens: { + let address1 = Token::Address([0x11u8; 20].into()); + let address2 = Token::Address([0x22u8; 20].into()); + let address3 = Token::Address([0x33u8; 20].into()); + let address4 = Token::Address([0x44u8; 20].into()); + let array0 = Token::Array(vec![address1, address2]); + let array1 = Token::Array(vec![address3, address4]); + [Token::FixedArray(vec![array0, array1])] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000040 + 00000000000000000000000000000000000000000000000000000000000000a0 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000001111111111111111111111111111111111111111 + 0000000000000000000000002222222222222222222222222222222222222222 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000003333333333333333333333333333333333333333 + 0000000000000000000000004444444444444444444444444444444444444444" +} + +// test fixed bytes +test_encode_decode! { + name: fixed_bytes, + types: [ParamType::FixedBytes(2)], + tokens: [Token::FixedBytes(vec![0x12, 0x34])], + data: "1234000000000000000000000000000000000000000000000000000000000000" +} + +// comprehensive test +test_encode_decode! { + name: comprehensive_test, + types: [ + ParamType::Int(32), + ParamType::Bytes, + ParamType::Int(32), + ParamType::Bytes, + ], + tokens: { + let bytes = hex!(" + 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b + 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b + ").to_vec(); + [ + Token::Int(5.into()), + Token::Bytes(bytes.clone()), + Token::Int(3.into()), + Token::Bytes(bytes), + ] + }, + data: " + 0000000000000000000000000000000000000000000000000000000000000005 + 0000000000000000000000000000000000000000000000000000000000000080 + 0000000000000000000000000000000000000000000000000000000000000003 + 00000000000000000000000000000000000000000000000000000000000000e0 + 0000000000000000000000000000000000000000000000000000000000000040 + 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b + 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b + 0000000000000000000000000000000000000000000000000000000000000040 + 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b + 131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b" +} +test_encode_decode! { + name: comprehensive_test2, + types: [ + ParamType::Int(32), + ParamType::String, + ParamType::Int(32), + ParamType::Int(32), + ParamType::Int(32), + ParamType::Array(Box::new(ParamType::Int(32))), + ], + tokens: [ + Token::Int(1.into()), + Token::String("gavofyork".to_owned()), + Token::Int(2.into()), + Token::Int(3.into()), + Token::Int(4.into()), + Token::Array(vec![ + Token::Int(5.into()), + Token::Int(6.into()), + Token::Int(7.into()), + ]) + ], + data: " + 0000000000000000000000000000000000000000000000000000000000000001 + 00000000000000000000000000000000000000000000000000000000000000c0 + 0000000000000000000000000000000000000000000000000000000000000002 + 0000000000000000000000000000000000000000000000000000000000000003 + 0000000000000000000000000000000000000000000000000000000000000004 + 0000000000000000000000000000000000000000000000000000000000000100 + 0000000000000000000000000000000000000000000000000000000000000009 + 6761766f66796f726b0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000003 + 0000000000000000000000000000000000000000000000000000000000000005 + 0000000000000000000000000000000000000000000000000000000000000006 + 0000000000000000000000000000000000000000000000000000000000000007" +} From dd045adc4fe337b11f940e0fee038af064aa0b10 Mon Sep 17 00:00:00 2001 From: Atkins Date: Mon, 1 Apr 2019 02:54:46 +0800 Subject: [PATCH 5/6] Use `Vec::with_capacity` instead of `vec![]` if possible --- ethabi/src/decoder.rs | 7 +++---- ethabi/src/encoder.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ethabi/src/decoder.rs b/ethabi/src/decoder.rs index f8bda469a..41d499960 100644 --- a/ethabi/src/decoder.rs +++ b/ethabi/src/decoder.rs @@ -41,7 +41,7 @@ pub fn decode(types: &[ParamType], data: &[u8]) -> Result, Error> { bail!("please ensure the contract and method you're calling exist! failed to decode empty bytes. if you're using jsonrpc this is likely due to jsonrpc returning `0x` in case contract or method don't exist"); } let slices = slice_data(data)?; - let mut tokens = vec![]; + let mut tokens = Vec::with_capacity(types.len()); let mut offset = 0; for param in types { let res = decode_param(param, &slices, offset).chain_err(|| format!("Cannot decode {}", param))?; @@ -58,7 +58,7 @@ fn peek(slices: &[Word], position: usize) -> Result<&Word, Error> { fn take_bytes(slices: &[Word], position: usize, len: usize) -> Result { let slices_len = (len + 31) / 32; - let mut bytes_slices = vec![]; + let mut bytes_slices = Vec::with_capacity(slices_len); for i in 0..slices_len { let slice = try!(peek(slices, position + i)); bytes_slices.push(slice); @@ -173,9 +173,8 @@ fn decode_param(param: &ParamType, slices: &[Word], offset: usize) -> Result Vec { } fn pad_fixed_bytes(bytes: &[u8]) -> Vec { - let mut result = vec![]; let len = (bytes.len() + 31) / 32; + let mut result = Vec::with_capacity(len); for i in 0..len { let mut padded = [0u8; 32]; From dff6c121449c426e19bad04e7ca2e0a53399737b Mon Sep 17 00:00:00 2001 From: Atkins Date: Mon, 1 Apr 2019 23:21:15 +0800 Subject: [PATCH 6/6] Move test for util to same mod --- ethabi/src/encoder.rs | 12 ------------ ethabi/src/util.rs | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/ethabi/src/encoder.rs b/ethabi/src/encoder.rs index 0a3e2b8a2..9b93133bf 100644 --- a/ethabi/src/encoder.rs +++ b/ethabi/src/encoder.rs @@ -160,15 +160,3 @@ fn encode_token(token: &Token) -> Mediate { } } -#[cfg(test)] -mod tests { - use util::pad_u32; - - #[test] - fn test_pad_u32() { - // this will fail if endianess is not supported - assert_eq!(pad_u32(0x1)[31], 1); - assert_eq!(pad_u32(0x100)[30], 1); - } -} - diff --git a/ethabi/src/util.rs b/ethabi/src/util.rs index ee719403f..97c50f375 100644 --- a/ethabi/src/util.rs +++ b/ethabi/src/util.rs @@ -45,13 +45,22 @@ pub fn pad_i32(value: i32) -> Word { #[cfg(test)] mod tests { - use super::pad_i32; + use super::{pad_u32, pad_i32}; + + #[test] + fn test_pad_u32() { + // this will fail if endianess is not supported + assert_eq!(pad_u32(0).to_vec(), hex!("0000000000000000000000000000000000000000000000000000000000000000").to_vec()); + assert_eq!(pad_u32(1).to_vec(), hex!("0000000000000000000000000000000000000000000000000000000000000001").to_vec()); + assert_eq!(pad_u32(0x100).to_vec(), hex!("0000000000000000000000000000000000000000000000000000000000000100").to_vec()); + assert_eq!(pad_u32(0xffffffff).to_vec(), hex!("00000000000000000000000000000000000000000000000000000000ffffffff").to_vec()); + } #[test] fn test_i32() { - assert_eq!(hex!("0000000000000000000000000000000000000000000000000000000000000000").to_vec(), pad_i32(0).to_vec()); - assert_eq!(hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").to_vec(), pad_i32(-1).to_vec()); - assert_eq!(hex!("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").to_vec(), pad_i32(-2).to_vec()); - assert_eq!(hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00").to_vec(), pad_i32(-256).to_vec()); + assert_eq!(pad_i32(0).to_vec(), hex!("0000000000000000000000000000000000000000000000000000000000000000").to_vec()); + assert_eq!(pad_i32(-1).to_vec(), hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").to_vec()); + assert_eq!(pad_i32(-2).to_vec(), hex!("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").to_vec()); + assert_eq!(pad_i32(-256).to_vec(), hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00").to_vec()); } }