api3_common/abi/
decode.rs

1//! ABI decoder.
2
3use crate::abi::{ParamType, Token, Word};
4use crate::Error;
5
6#[derive(Debug)]
7struct DecodeResult {
8    token: Token,
9    new_offset: usize,
10}
11
12fn as_usize(slice: &Word) -> Result<usize, Error> {
13    if !slice[..28].iter().all(|x| *x == 0) {
14        return Err(Error::InvalidData);
15    }
16
17    let result = ((slice[28] as usize) << 24)
18        + ((slice[29] as usize) << 16)
19        + ((slice[30] as usize) << 8)
20        + (slice[31] as usize);
21
22    Ok(result)
23}
24
25/// Decodes ABI compliant vector of bytes into vector of tokens described by types param.
26pub fn decode(types: &[ParamType], data: &[u8]) -> Result<Vec<Token>, Error> {
27    let is_empty_bytes_valid_encoding = types.iter().all(|t| t.is_empty_bytes_valid_encoding());
28    if !is_empty_bytes_valid_encoding && data.is_empty() {
29        return Err(Error::InvalidName(
30            "please ensure the contract and method you're calling exist! \
31			 failed to decode empty bytes. if you're using jsonrpc this is \
32			 likely due to jsonrpc returning `0x` in case contract or method \
33			 don't exist"
34                .into(),
35        ));
36    }
37
38    let mut tokens = vec![];
39    let mut offset = 0;
40
41    for param in types {
42        let res = decode_param(param, data, offset)?;
43        offset = res.new_offset;
44        tokens.push(res.token);
45    }
46
47    Ok(tokens)
48}
49
50fn peek(data: &[u8], offset: usize, len: usize) -> Result<&[u8], Error> {
51    if offset + len > data.len() {
52        Err(Error::InvalidData)
53    } else {
54        Ok(&data[offset..(offset + len)])
55    }
56}
57
58fn peek_32_bytes(data: &[u8], offset: usize) -> Result<Word, Error> {
59    peek(data, offset, 32).map(|x| {
60        let mut out: Word = [0u8; 32];
61        out.copy_from_slice(&x[0..32]);
62        out
63    })
64}
65
66fn take_bytes(data: &[u8], offset: usize, len: usize) -> Result<Vec<u8>, Error> {
67    if offset + len > data.len() {
68        Err(Error::InvalidData)
69    } else {
70        Ok((data[offset..(offset + len)]).to_vec())
71    }
72}
73
74fn decode_param(param: &ParamType, data: &[u8], offset: usize) -> Result<DecodeResult, Error> {
75    match *param {
76        ParamType::Address => {
77            let slice = peek_32_bytes(data, offset)?;
78            let mut address = [0u8; 20];
79            address.copy_from_slice(&slice[12..]);
80            let result = DecodeResult {
81                token: Token::Address(address),
82                new_offset: offset + 32,
83            };
84            Ok(result)
85        }
86        ParamType::Uint(_) => {
87            let slice = peek_32_bytes(data, offset)?;
88            let result = DecodeResult {
89                token: Token::Uint(slice.into()),
90                new_offset: offset + 32,
91            };
92            Ok(result)
93        }
94        ParamType::Int(_) => {
95            let slice = peek_32_bytes(data, offset)?;
96            let result = DecodeResult {
97                token: Token::Int(slice.into()),
98                new_offset: offset + 32,
99            };
100            Ok(result)
101        }
102        ParamType::FixedBytes(len) => {
103            // FixedBytes is anything from bytes1 to bytes32. These values
104            // are padded with trailing zeros to fill 32 bytes.
105            let bytes = take_bytes(data, offset, len)?;
106            let result = DecodeResult {
107                token: Token::FixedBytes(bytes),
108                new_offset: offset + 32,
109            };
110            Ok(result)
111        }
112        ParamType::Bytes => {
113            let dynamic_offset = as_usize(&peek_32_bytes(data, offset)?)?;
114            let len = as_usize(&peek_32_bytes(data, dynamic_offset)?)?;
115            let bytes = take_bytes(data, dynamic_offset + 32, len)?;
116            let result = DecodeResult {
117                token: Token::Bytes(bytes),
118                new_offset: offset + 32,
119            };
120            Ok(result)
121        }
122        ParamType::String => {
123            let dynamic_offset = as_usize(&peek_32_bytes(data, offset)?)?;
124            let len = as_usize(&peek_32_bytes(data, dynamic_offset)?)?;
125            let bytes = take_bytes(data, dynamic_offset + 32, len)?;
126            let result = DecodeResult {
127                // NOTE: We're decoding strings using lossy UTF-8 decoding to
128                // prevent invalid strings written into contracts by either users or
129                // Solidity bugs from causing graph-node to fail decoding event
130                // data.
131                token: Token::String(String::from_utf8_lossy(&*bytes).into()),
132                new_offset: offset + 32,
133            };
134            Ok(result)
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use crate::abi::decode::decode;
142    use crate::abi::types::ParamType;
143    use crate::abi::{Token, Uint};
144    use hex_literal::hex;
145
146    #[test]
147    fn decode_from_empty_byte_slice() {
148        // these can NOT be decoded from empty byte slice
149        assert!(decode(&[ParamType::Address], &[]).is_err());
150        assert!(decode(&[ParamType::Bytes], &[]).is_err());
151        assert!(decode(&[ParamType::String], &[]).is_err());
152        assert!(decode(&[ParamType::FixedBytes(1)], &[]).is_err());
153        // these are the only ones that can be decoded from empty byte slice
154        assert!(decode(&[ParamType::FixedBytes(0)], &[]).is_ok());
155    }
156
157    #[test]
158    fn decode_data_with_size_that_is_not_a_multiple_of_32() {
159        let encoded = hex!(
160            "
161            0000000000000000000000000000000000000000000000000000000000000000
162            00000000000000000000000000000000000000000000000000000000000000a0
163            0000000000000000000000000000000000000000000000000000000000000152
164            0000000000000000000000000000000000000000000000000000000000000001
165            000000000000000000000000000000000000000000000000000000000054840d
166            0000000000000000000000000000000000000000000000000000000000000092
167            3132323033393637623533326130633134633938306235616566666231373034
168            3862646661656632633239336139353039663038656233633662306635663866
169            3039343265376239636337366361353163636132366365353436393230343438
170            6533303866646136383730623565326165313261323430396439343264653432
171            3831313350373230703330667073313678390000000000000000000000000000
172            0000000000000000000000000000000000103933633731376537633061363531
173            3761
174        "
175        );
176
177        assert_eq!(
178            decode(
179                &[
180                    ParamType::Uint(256),
181                    ParamType::String,
182                    ParamType::String,
183                    ParamType::Uint(256),
184                    ParamType::Uint(256),
185                ],
186                &encoded,
187            ).unwrap(),
188            &[
189                Token::Uint(Uint::from(0u128)),
190                Token::String(String::from("12203967b532a0c14c980b5aeffb17048bdfaef2c293a9509f08eb3c6b0f5f8f0942e7b9cc76ca51cca26ce546920448e308fda6870b5e2ae12a2409d942de428113P720p30fps16x9")),
191                Token::String(String::from("93c717e7c0a6517a")),
192                Token::Uint(Uint::from(1u128)),
193                Token::Uint(Uint::from(5538829u128))
194            ]
195        );
196    }
197
198    #[test]
199    fn decode_after_fixed_bytes_with_less_than_32_bytes() {
200        let encoded = hex!(
201            "
202			0000000000000000000000008497afefdc5ac170a664a231f6efb25526ef813f
203			0000000000000000000000000000000000000000000000000000000000000000
204			0000000000000000000000000000000000000000000000000000000000000000
205			0000000000000000000000000000000000000000000000000000000000000080
206			000000000000000000000000000000000000000000000000000000000000000a
207			3078303030303030314600000000000000000000000000000000000000000000
208		"
209        );
210
211        assert_eq!(
212            decode(
213                &[
214                    ParamType::Address,
215                    ParamType::FixedBytes(32),
216                    ParamType::FixedBytes(4),
217                    ParamType::String,
218                ],
219                &encoded,
220            )
221            .unwrap(),
222            &[
223                Token::Address(hex!("8497afefdc5ac170a664a231f6efb25526ef813f").into()),
224                Token::FixedBytes([0u8; 32].to_vec()),
225                Token::FixedBytes([0u8; 4].to_vec()),
226                Token::String("0x0000001F".into()),
227            ]
228        )
229    }
230
231    #[test]
232    fn decode_broken_utf8() {
233        let encoded = hex!(
234            "
235			0000000000000000000000000000000000000000000000000000000000000020
236			0000000000000000000000000000000000000000000000000000000000000004
237			e4b88de500000000000000000000000000000000000000000000000000000000
238        "
239        );
240
241        assert_eq!(
242            decode(&[ParamType::String,], &encoded).unwrap(),
243            &[Token::String("不�".into())]
244        );
245    }
246}