solidity_abi/
basic.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::{utils::abi_require, ABIDecodeError, ABIVariable, LinkedBytes};
6use cfx_types::{Address, H256, U256};
7
8impl ABIVariable for Address {
9    const BASIC_TYPE: bool = true;
10    const STATIC_LENGTH: Option<usize> = Some(32);
11
12    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
13        abi_require(data.len() == 32, "Invalid call data length")?;
14        Ok(Address::from_slice(&data[12..32]))
15    }
16
17    fn to_abi(&self) -> LinkedBytes {
18        let mut answer = vec![0u8; 12];
19        answer.extend_from_slice(self.as_bytes());
20        LinkedBytes::from_bytes(answer)
21    }
22
23    fn to_packed_abi(&self) -> LinkedBytes {
24        LinkedBytes::from_bytes(self.to_fixed_bytes().into())
25    }
26}
27
28impl ABIVariable for U256 {
29    const BASIC_TYPE: bool = true;
30    const STATIC_LENGTH: Option<usize> = Some(32);
31
32    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
33        abi_require(data.len() == 32, "Invalid call data length")?;
34        Ok(U256::from_big_endian(&data))
35    }
36
37    fn to_abi(&self) -> LinkedBytes {
38        let mut answer = vec![0u8; 32];
39        self.to_big_endian(&mut answer);
40        LinkedBytes::from_bytes(answer)
41    }
42
43    fn to_packed_abi(&self) -> LinkedBytes { self.to_abi() }
44}
45
46impl ABIVariable for H256 {
47    const BASIC_TYPE: bool = <[u8; 32]>::BASIC_TYPE;
48    const STATIC_LENGTH: Option<usize> = <[u8; 32]>::STATIC_LENGTH;
49
50    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
51        Ok(H256::from(<[u8; 32]>::from_abi(data)?))
52    }
53
54    fn to_abi(&self) -> LinkedBytes { self.0.to_abi() }
55
56    fn to_packed_abi(&self) -> LinkedBytes { self.0.to_packed_abi() }
57}
58
59impl ABIVariable for bool {
60    const BASIC_TYPE: bool = true;
61    const STATIC_LENGTH: Option<usize> = Some(32);
62
63    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
64        abi_require(data.len() == 32, "Invalid call data length")?;
65        Ok(data[31] != 0)
66    }
67
68    fn to_abi(&self) -> LinkedBytes {
69        let mut answer = vec![0u8; 32];
70        answer[31] = *self as u8;
71        LinkedBytes::from_bytes(answer)
72    }
73
74    fn to_packed_abi(&self) -> LinkedBytes {
75        LinkedBytes::from_bytes(vec![*self as u8])
76    }
77}
78
79macro_rules! impl_abi_variable_for_primitive {
80    () => {};
81    ($ty: ident) => {impl_abi_variable_for_primitive!($ty,);};
82    ($ty: ident, $($rest: ident),*) => {
83        impl ABIVariable for $ty {
84            const BASIC_TYPE: bool = true;
85            const STATIC_LENGTH: Option<usize> = Some(32);
86
87            fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
88                const BYTES: usize = ($ty::BITS/8) as usize;
89                abi_require(data.len() == 32, "Invalid call data length")?;
90                let mut bytes = [0u8; BYTES];
91                bytes.copy_from_slice(&data[32 - BYTES..]);
92                Ok($ty::from_be_bytes(bytes))
93            }
94
95            fn to_abi(&self) -> LinkedBytes {
96                const BYTES: usize = ($ty::BITS/8) as usize;
97                let mut answer = vec![0u8; 32];
98                answer[32 - BYTES..].copy_from_slice(&self.to_be_bytes());
99                LinkedBytes::from_bytes(answer)
100            }
101
102            fn to_packed_abi(&self) -> LinkedBytes {
103                LinkedBytes::from_bytes(self.to_be_bytes().to_vec())
104            }
105        }
106
107        impl_abi_variable_for_primitive!($($rest),*);
108    }
109}
110
111impl_abi_variable_for_primitive!(U8, u16, u32, u64, u128);
112
113#[allow(dead_code)]
114#[derive(Copy, Clone, Eq, PartialEq)]
115pub struct U8(u8);
116
117impl U8 {
118    #[allow(dead_code)]
119    const BITS: usize = 8;
120
121    #[allow(dead_code)]
122    fn to_be_bytes(self) -> [u8; 1] { [self.0] }
123
124    #[allow(dead_code)]
125    fn from_be_bytes(input: [u8; 1]) -> Self { U8(input[0]) }
126}
127
128#[cfg(test)]
129mod tests_basic {
130    use super::{U8, *};
131    use crate::ABIVariable;
132
133    #[test]
134    fn test_packed_encoding() {
135        let num = 0xDEADBEEFu32;
136        let packed = num.to_packed_abi().to_vec();
137        let expected = num.to_be_bytes().to_vec();
138        assert_eq!(packed, expected);
139    }
140
141    #[test]
142    fn test_u256_abi_basic() {
143        assert!(U256::BASIC_TYPE);
144        assert_eq!(U256::STATIC_LENGTH, Some(32));
145    }
146
147    #[test]
148    fn test_u256_packed_abi_consistency() {
149        let num = U256::max_value();
150        let abi = num.to_abi();
151        let packed_abi = num.to_packed_abi();
152        assert_eq!(abi.to_vec(), packed_abi.to_vec());
153    }
154
155    #[test]
156    fn test_u256_zero_value() {
157        let zero = U256::zero();
158        let encoded = zero.to_abi().to_vec();
159        assert_eq!(encoded, vec![0u8; 32]);
160    }
161
162    #[test]
163    fn test_h256_type_constants() {
164        assert_eq!(H256::BASIC_TYPE, <[u8; 32]>::BASIC_TYPE);
165        assert_eq!(H256::STATIC_LENGTH, <[u8; 32]>::STATIC_LENGTH);
166    }
167
168    #[test]
169    fn test_h256_from_abi_valid() {
170        let input = [42u8; 32];
171        let h256 = H256::from_abi(&input).unwrap();
172        assert_eq!(h256.0, input);
173    }
174
175    #[test]
176    fn test_h256_to_packed_abi() {
177        let h256 = H256([0xBB; 32]);
178        let packed_bytes = h256.to_packed_abi();
179        assert_eq!(packed_bytes.to_vec(), &[0xBB; 32]);
180    }
181
182    #[test]
183    fn test_u8_bits() {
184        assert_eq!(U8::BITS, 8);
185    }
186
187    #[test]
188    fn test_u8_to_be_bytes() {
189        let val = U8::from_be_bytes([123]);
190        assert_eq!(val.to_be_bytes(), [123]);
191    }
192
193    #[test]
194    fn test_u8_from_be_bytes() {
195        let u = U8::from_be_bytes([255]);
196        assert_eq!(u.to_be_bytes(), [255]);
197    }
198
199    #[test]
200    fn test_u8_eq() {
201        let a = U8::from_be_bytes([100]);
202        let b = U8::from_be_bytes([100]);
203        let c = U8::from_be_bytes([200]);
204        assert!(a == b);
205        assert!(a != c);
206    }
207
208    #[test]
209    fn test_u8_boundaries() {
210        let min = U8::from_be_bytes([0]);
211        let max = U8::from_be_bytes([255]);
212        assert_eq!(min.to_be_bytes(), [0]);
213        assert_eq!(max.to_be_bytes(), [255]);
214    }
215
216    #[test]
217    fn test_u8_byte_order_consistency() {
218        let input = [128];
219        let u = U8::from_be_bytes(input);
220        assert_eq!(u.to_be_bytes(), input);
221    }
222}