1use util::slice_data;
4use {Word, Token, ErrorKind, Error, ResultExt, ParamType};
5
6struct DecodeResult {
7 token: Token,
8 new_offset: usize,
9}
10
11struct BytesTaken {
12 bytes: Vec<u8>,
13 new_offset: usize,
14}
15
16fn as_u32(slice: &Word) -> Result<u32, Error> {
17 if !slice[..28].iter().all(|x| *x == 0) {
18 return Err(ErrorKind::InvalidData.into());
19 }
20
21 let result = ((slice[28] as u32) << 24) +
22 ((slice[29] as u32) << 16) +
23 ((slice[30] as u32) << 8) +
24 (slice[31] as u32);
25
26 Ok(result)
27}
28
29fn as_bool(slice: &Word) -> Result<bool, Error> {
30 if !slice[..31].iter().all(|x| *x == 0) {
31 return Err(ErrorKind::InvalidData.into());
32 }
33
34 Ok(slice[31] == 1)
35}
36
37pub fn decode(types: &[ParamType], data: &[u8]) -> Result<Vec<Token>, Error> {
39 let is_empty_bytes_valid_encoding = types.iter().all(|t| t.is_empty_bytes_valid_encoding());
40 if !is_empty_bytes_valid_encoding && data.is_empty() {
41 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");
42 }
43 let slices = slice_data(data)?;
44 let mut tokens = Vec::with_capacity(types.len());
45 let mut offset = 0;
46 for param in types {
47 let res = decode_param(param, &slices, offset).chain_err(|| format!("Cannot decode {}", param))?;
48 offset = res.new_offset;
49 tokens.push(res.token);
50 }
51 Ok(tokens)
52}
53
54fn peek(slices: &[Word], position: usize) -> Result<&Word, Error> {
55 slices.get(position).ok_or_else(|| ErrorKind::InvalidData.into())
56}
57
58fn take_bytes(slices: &[Word], position: usize, len: usize) -> Result<BytesTaken, Error> {
59 let slices_len = (len + 31) / 32;
60
61 let mut bytes_slices = Vec::with_capacity(slices_len);
62 for i in 0..slices_len {
63 let slice = peek(slices, position + i)?;
64 bytes_slices.push(slice);
65 }
66
67 let bytes = bytes_slices.into_iter()
68 .flat_map(|slice| slice.to_vec())
69 .take(len)
70 .collect();
71
72 let taken = BytesTaken {
73 bytes,
74 new_offset: position + slices_len,
75 };
76
77 Ok(taken)
78}
79
80fn decode_param(param: &ParamType, slices: &[Word], offset: usize) -> Result<DecodeResult, Error> {
81 match *param {
82 ParamType::Address => {
83 let slice = peek(slices, offset)?;
84 let mut address = [0u8; 20];
85 address.copy_from_slice(&slice[12..]);
86
87 let result = DecodeResult {
88 token: Token::Address(address.into()),
89 new_offset: offset + 1,
90 };
91
92 Ok(result)
93 },
94 ParamType::Int(_) => {
95 let slice = peek(slices, offset)?;
96
97 let result = DecodeResult {
98 token: Token::Int(slice.clone().into()),
99 new_offset: offset + 1,
100 };
101
102 Ok(result)
103 },
104 ParamType::Uint(_) => {
105 let slice = peek(slices, offset)?;
106
107 let result = DecodeResult {
108 token: Token::Uint(slice.clone().into()),
109 new_offset: offset + 1,
110 };
111
112 Ok(result)
113 },
114 ParamType::Bool => {
115 let slice = peek(slices, offset)?;
116
117 let b = as_bool(slice)?;
118
119 let result = DecodeResult {
120 token: Token::Bool(b),
121 new_offset: offset + 1,
122 };
123
124 Ok(result)
125 },
126 ParamType::FixedBytes(len) => {
127 let taken = take_bytes(slices, offset, len)?;
128
129 let result = DecodeResult {
130 token: Token::FixedBytes(taken.bytes),
131 new_offset: taken.new_offset,
132 };
133
134 Ok(result)
135 },
136 ParamType::Bytes => {
137 let offset_slice = peek(slices, offset)?;
138 let len_offset = (as_u32(offset_slice)? / 32) as usize;
139
140 let len_slice = peek(slices, len_offset)?;
141 let len = as_u32(len_slice)? as usize;
142
143 let taken = take_bytes(slices, len_offset + 1, len)?;
144
145 let result = DecodeResult {
146 token: Token::Bytes(taken.bytes),
147 new_offset: offset + 1,
148 };
149
150 Ok(result)
151 },
152 ParamType::String => {
153 let offset_slice = peek(slices, offset)?;
154 let len_offset = (as_u32(offset_slice)? / 32) as usize;
155
156 let len_slice = peek(slices, len_offset)?;
157 let len = as_u32(len_slice)? as usize;
158
159 let taken = take_bytes(slices, len_offset + 1, len)?;
160
161 let result = DecodeResult {
162 token: Token::String(String::from_utf8(taken.bytes)?),
163 new_offset: offset + 1,
164 };
165
166 Ok(result)
167 },
168 ParamType::Array(ref t) => {
169 let offset_slice = peek(slices, offset)?;
170 let len_offset = (as_u32(offset_slice)? / 32) as usize;
171
172 let len_slice = peek(slices, len_offset)?;
173 let len = as_u32(len_slice)? as usize;
174
175 let sub_slices = &slices[len_offset + 1..];
176 let mut tokens = Vec::with_capacity(len);
177 let mut new_offset = 0;
178 for _ in 0..len {
179 let res = decode_param(t, &sub_slices, new_offset)?;
180 new_offset = res.new_offset;
181 tokens.push(res.token);
182 }
183
184 let result = DecodeResult {
185 token: Token::Array(tokens),
186 new_offset: offset + 1,
187 };
188
189 Ok(result)
190 },
191 ParamType::FixedArray(ref t, len) => {
192 let mut tokens = Vec::with_capacity(len);
193 let new_offset = if param.is_dynamic() {
194 let offset_slice = peek(slices, offset)?;
195 let tail_offset = (as_u32(offset_slice)? / 32) as usize;
196 let slices = &slices[tail_offset..];
197 let mut new_offset = 0;
198
199 for _ in 0..len {
200 let res = decode_param(t, &slices, new_offset)?;
201 new_offset = res.new_offset;
202 tokens.push(res.token);
203 }
204 offset + 1
205 } else {
206 let mut new_offset = offset;
207
208 for _ in 0..len {
209 let res = decode_param(t, &slices, new_offset)?;
210 new_offset = res.new_offset;
211 tokens.push(res.token);
212 }
213 new_offset
214 };
215
216 let result = DecodeResult {
217 token: Token::FixedArray(tokens),
218 new_offset,
219 };
220
221 Ok(result)
222 }
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use {decode, ParamType};
229
230 #[test]
231 fn decode_from_empty_byte_slice() {
232 assert!(decode(&[ParamType::Address], &[]).is_err());
234 assert!(decode(&[ParamType::Bytes], &[]).is_err());
235 assert!(decode(&[ParamType::Int(0)], &[]).is_err());
236 assert!(decode(&[ParamType::Int(1)], &[]).is_err());
237 assert!(decode(&[ParamType::Int(0)], &[]).is_err());
238 assert!(decode(&[ParamType::Int(1)], &[]).is_err());
239 assert!(decode(&[ParamType::Bool], &[]).is_err());
240 assert!(decode(&[ParamType::String], &[]).is_err());
241 assert!(decode(&[ParamType::Array(Box::new(ParamType::Bool))], &[]).is_err());
242 assert!(decode(&[ParamType::FixedBytes(1)], &[]).is_err());
243 assert!(decode(&[ParamType::FixedArray(Box::new(ParamType::Bool), 1)], &[]).is_err());
244
245 assert!(decode(&[ParamType::FixedBytes(0)], &[]).is_ok());
247 assert!(decode(&[ParamType::FixedArray(Box::new(ParamType::Bool), 0)], &[]).is_ok());
248 }
249}
250