vapabi/
decoder.rs

1//! ABI decoder.
2
3use 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
37/// Decodes ABI compliant vector of bytes into vector of tokens described by types param.
38pub 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        // these can NOT be decoded from empty byte slice
233        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        // these are the only ones that can be decoded from empty byte slice
246        assert!(decode(&[ParamType::FixedBytes(0)], &[]).is_ok());
247        assert!(decode(&[ParamType::FixedArray(Box::new(ParamType::Bool), 0)], &[]).is_ok());
248	}
249}
250