solidity_abi/
bytes.rs

1// Copyright 2020 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use super::{
6    utils::{padded_big_endian, pull_slice, LinkedBytes},
7    ABIDecodeError, ABIVariable,
8};
9
10pub(super) type Bytes = Vec<u8>;
11
12use cfx_types::U256;
13use std::convert::TryInto;
14
15impl ABIVariable for Bytes {
16    const BASIC_TYPE: bool = false;
17    const STATIC_LENGTH: Option<usize> = None;
18
19    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
20        let pointer = &mut data.iter();
21
22        let expected_length = U256::from_big_endian(pull_slice(
23            pointer,
24            32,
25            "Incomplete length for byte array",
26        )?);
27        let data_without_length = pointer.as_slice();
28        if U256::from(data_without_length.len()) < expected_length {
29            Err(ABIDecodeError("Invalid length in byte array"))
30        } else {
31            let length = expected_length.as_usize();
32            Ok(data_without_length[0..length].to_vec())
33        }
34    }
35
36    fn to_abi(&self) -> LinkedBytes {
37        let mut result = padded_big_endian(self.len());
38        result.extend_from_slice(self);
39        result.extend_from_slice(&vec![0u8; 31 - (self.len() + 31) % 32]);
40        LinkedBytes::from_bytes(result)
41    }
42
43    fn to_packed_abi(&self) -> LinkedBytes {
44        LinkedBytes::from_bytes(self.clone())
45    }
46}
47
48impl<const N: usize> ABIVariable for [u8; N]
49where [u8; N]: SolidityBytes
50{
51    const BASIC_TYPE: bool = true;
52    // We only implement for N<=32. These fixed length bytes are padded with
53    // zeros.
54    const STATIC_LENGTH: Option<usize> = Some(32);
55
56    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
57        let pointer = &mut data.iter();
58
59        let data_without_length = pointer.as_slice();
60        if data_without_length.len() < N {
61            Err(ABIDecodeError("Invalid length in byte array"))
62        } else {
63            Ok(data_without_length[0..N]
64                .try_into()
65                .expect("Length must correct"))
66        }
67    }
68
69    fn to_abi(&self) -> LinkedBytes {
70        let mut result = vec![0u8; 32];
71        result[0..N].copy_from_slice(self);
72        LinkedBytes::from_bytes(result)
73    }
74
75    fn to_packed_abi(&self) -> LinkedBytes {
76        LinkedBytes::from_bytes(self.to_vec())
77    }
78}
79
80pub trait SolidityBytes {}
81
82macro_rules! mark_solidity_bytes {
83    ($($idx:tt),*) => {
84        $(impl SolidityBytes for [u8;$idx] {})*
85    }
86}
87mark_solidity_bytes!(
88    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
89    23, 24, 25, 26, 27, 28, 29, 30, 31, 32
90);