esvm_rlp/
untrusted_rlp.rs

1// Copyright 2015-2017 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::cell::Cell;
10use std::fmt;
11use rustc_serialize::hex::ToHex;
12use impls::decode_usize;
13use {Decodable, DecoderError};
14
15/// rlp offset
16#[derive(Copy, Clone, Debug)]
17struct OffsetCache {
18	index: usize,
19	offset: usize,
20}
21
22impl OffsetCache {
23	fn new(index: usize, offset: usize) -> OffsetCache {
24		OffsetCache {
25			index: index,
26			offset: offset,
27		}
28	}
29}
30
31#[derive(Debug)]
32/// RLP prototype
33pub enum Prototype {
34	/// Empty
35	Null,
36	/// Value
37	Data(usize),
38	/// List
39	List(usize),
40}
41
42/// Stores basic information about item
43pub struct PayloadInfo {
44	/// Header length in bytes
45	pub header_len: usize,
46	/// Value length in bytes
47	pub value_len: usize,
48}
49
50fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result<PayloadInfo, DecoderError> {
51	let header_len = 1 + len_of_len;
52	match header_bytes.get(1) {
53		Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix),
54		None => return Err(DecoderError::RlpIsTooShort),
55		_ => (),
56	}
57	if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); }
58	let value_len = decode_usize(&header_bytes[1..header_len])?;
59	Ok(PayloadInfo::new(header_len, value_len))
60}
61
62impl PayloadInfo {
63	fn new(header_len: usize, value_len: usize) -> PayloadInfo {
64		PayloadInfo {
65			header_len: header_len,
66			value_len: value_len,
67		}
68	}
69
70	/// Total size of the RLP.
71	pub fn total(&self) -> usize { self.header_len + self.value_len }
72
73	/// Create a new object from the given bytes RLP. The bytes
74	pub fn from(header_bytes: &[u8]) -> Result<PayloadInfo, DecoderError> {
75		match header_bytes.first().cloned() {
76			None => Err(DecoderError::RlpIsTooShort),
77			Some(0...0x7f) => Ok(PayloadInfo::new(0, 1)),
78			Some(l @ 0x80...0xb7) => Ok(PayloadInfo::new(1, l as usize - 0x80)),
79			Some(l @ 0xb8...0xbf) => {
80				let len_of_len = l as usize - 0xb7;
81				calculate_payload_info(header_bytes, len_of_len)
82			}
83			Some(l @ 0xc0...0xf7) => Ok(PayloadInfo::new(1, l as usize - 0xc0)),
84			Some(l @ 0xf8...0xff) => {
85				let len_of_len = l as usize - 0xf7;
86				calculate_payload_info(header_bytes, len_of_len)
87			},
88			// we cant reach this place, but rust requires _ to be implemented
89			_ => { unreachable!(); }
90		}
91	}
92}
93
94/// Data-oriented view onto rlp-slice.
95///
96/// This is immutable structere. No operations change it.
97///
98/// Should be used in places where, error handling is required,
99/// eg. on input
100#[derive(Debug)]
101pub struct UntrustedRlp<'a> {
102	bytes: &'a [u8],
103	offset_cache: Cell<OffsetCache>,
104	count_cache: Cell<Option<usize>>,
105}
106
107impl<'a> Clone for UntrustedRlp<'a> {
108	fn clone(&self) -> UntrustedRlp<'a> {
109		UntrustedRlp {
110			bytes: self.bytes,
111			offset_cache: self.offset_cache.clone(),
112			count_cache: self.count_cache.clone(),
113		}
114	}
115}
116
117impl<'a> fmt::Display for UntrustedRlp<'a> {
118	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
119		match self.prototype() {
120			Ok(Prototype::Null) => write!(f, "null"),
121			Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()),
122			Ok(Prototype::List(len)) => {
123				write!(f, "[")?;
124				for i in 0..len-1 {
125					write!(f, "{}, ", self.at(i).unwrap())?;
126				}
127				write!(f, "{}", self.at(len - 1).unwrap())?;
128				write!(f, "]")
129			},
130			Err(err) => write!(f, "{:?}", err)
131		}
132	}
133}
134
135impl<'a, 'view> UntrustedRlp<'a> where 'a: 'view {
136	pub fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> {
137		UntrustedRlp {
138			bytes: bytes,
139			offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)),
140			count_cache: Cell::new(None)
141		}
142	}
143
144	pub fn as_raw(&'view self) -> &'a [u8] {
145		self.bytes
146	}
147
148	pub fn prototype(&self) -> Result<Prototype, DecoderError> {
149		// optimize? && return appropriate errors
150		if self.is_data() {
151			Ok(Prototype::Data(self.size()))
152		} else if self.is_list() {
153			self.item_count().map(Prototype::List)
154		} else {
155			Ok(Prototype::Null)
156		}
157	}
158
159	pub fn payload_info(&self) -> Result<PayloadInfo, DecoderError> {
160		BasicDecoder::payload_info(self.bytes)
161	}
162
163	pub fn data(&'view self) -> Result<&'a [u8], DecoderError> {
164		let pi = BasicDecoder::payload_info(self.bytes)?;
165		Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)])
166	}
167
168	pub fn item_count(&self) -> Result<usize, DecoderError> {
169		match self.is_list() {
170			true => match self.count_cache.get() {
171				Some(c) => Ok(c),
172				None => {
173					let c = self.iter().count();
174					self.count_cache.set(Some(c));
175					Ok(c)
176				}
177			},
178			false => Err(DecoderError::RlpExpectedToBeList),
179		}
180	}
181
182	pub fn size(&self) -> usize {
183		match self.is_data() {
184			// TODO: No panic on malformed data, but ideally would Err on no PayloadInfo.
185			true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0),
186			false => 0
187		}
188	}
189
190	pub fn at(&'view self, index: usize) -> Result<UntrustedRlp<'a>, DecoderError> {
191		if !self.is_list() {
192			return Err(DecoderError::RlpExpectedToBeList);
193		}
194
195		// move to cached position if its index is less or equal to
196		// current search index, otherwise move to beginning of list
197		let c = self.offset_cache.get();
198		let (mut bytes, to_skip) = match c.index <= index {
199			true => (UntrustedRlp::consume(self.bytes, c.offset)?, index - c.index),
200			false => (self.consume_list_payload()?, index),
201		};
202
203		// skip up to x items
204		bytes = UntrustedRlp::consume_items(bytes, to_skip)?;
205
206		// update the cache
207		self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len()));
208
209		// construct new rlp
210		let found = BasicDecoder::payload_info(bytes)?;
211		Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len]))
212	}
213
214	pub fn is_null(&self) -> bool {
215		self.bytes.len() == 0
216	}
217
218	pub fn is_empty(&self) -> bool {
219		!self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80)
220	}
221
222	pub fn is_list(&self) -> bool {
223		!self.is_null() && self.bytes[0] >= 0xc0
224	}
225
226	pub fn is_data(&self) -> bool {
227		!self.is_null() && self.bytes[0] < 0xc0
228	}
229
230	pub fn is_int(&self) -> bool {
231		if self.is_null() {
232			return false;
233		}
234
235		match self.bytes[0] {
236			0...0x80 => true,
237			0x81...0xb7 => self.bytes[1] != 0,
238			b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0,
239			_ => false
240		}
241	}
242
243	pub fn iter(&'view self) -> UntrustedRlpIterator<'a, 'view> {
244		self.into_iter()
245	}
246
247	pub fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable {
248		T::decode(self)
249	}
250
251	pub fn as_list<T>(&self) -> Result<Vec<T>, DecoderError> where T: Decodable {
252		self.iter().map(|rlp| rlp.as_val()).collect()
253	}
254
255	pub fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable {
256		self.at(index)?.as_val()
257	}
258
259	pub fn list_at<T>(&self, index: usize) -> Result<Vec<T>, DecoderError> where T: Decodable {
260		self.at(index)?.as_list()
261	}
262
263	pub fn decoder(&self) -> BasicDecoder {
264		BasicDecoder::new(self.clone())
265	}
266
267	/// consumes first found prefix
268	fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> {
269		let item = BasicDecoder::payload_info(self.bytes)?;
270		let bytes = UntrustedRlp::consume(self.bytes, item.header_len)?;
271		Ok(bytes)
272	}
273
274	/// consumes fixed number of items
275	fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> {
276		let mut result = bytes;
277		for _ in 0..items {
278			let i = BasicDecoder::payload_info(result)?;
279			result = UntrustedRlp::consume(result, (i.header_len + i.value_len))?;
280		}
281		Ok(result)
282	}
283
284
285	/// consumes slice prefix of length `len`
286	fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> {
287		match bytes.len() >= len {
288			true => Ok(&bytes[len..]),
289			false => Err(DecoderError::RlpIsTooShort),
290		}
291	}
292}
293
294/// Iterator over rlp-slice list elements.
295pub struct UntrustedRlpIterator<'a, 'view> where 'a: 'view {
296	rlp: &'view UntrustedRlp<'a>,
297	index: usize,
298}
299
300impl<'a, 'view> IntoIterator for &'view UntrustedRlp<'a> where 'a: 'view {
301	type Item = UntrustedRlp<'a>;
302	type IntoIter = UntrustedRlpIterator<'a, 'view>;
303
304	fn into_iter(self) -> Self::IntoIter {
305		UntrustedRlpIterator {
306			rlp: self,
307			index: 0,
308		}
309	}
310}
311
312impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> {
313	type Item = UntrustedRlp<'a>;
314
315	fn next(&mut self) -> Option<UntrustedRlp<'a>> {
316		let index = self.index;
317		let result = self.rlp.at(index).ok();
318		self.index += 1;
319		result
320	}
321}
322
323pub struct BasicDecoder<'a> {
324	rlp: UntrustedRlp<'a>
325}
326
327impl<'a> BasicDecoder<'a> {
328	pub fn new(rlp: UntrustedRlp<'a>) -> BasicDecoder<'a> {
329		BasicDecoder {
330			rlp: rlp
331		}
332	}
333
334	/// Return first item info.
335	fn payload_info(bytes: &[u8]) -> Result<PayloadInfo, DecoderError> {
336		let item = PayloadInfo::from(bytes)?;
337		match item.header_len.checked_add(item.value_len) {
338			Some(x) if x <= bytes.len() => Ok(item),
339			_ => Err(DecoderError::RlpIsTooShort),
340		}
341	}
342
343	pub fn decode_value<T, F>(&self, f: F) -> Result<T, DecoderError>
344		where F: Fn(&[u8]) -> Result<T, DecoderError> {
345
346		let bytes = self.rlp.as_raw();
347
348		match bytes.first().cloned() {
349			// RLP is too short.
350			None => Err(DecoderError::RlpIsTooShort),
351			// Single byte value.
352			Some(l @ 0...0x7f) => Ok(f(&[l])?),
353			// 0-55 bytes
354			Some(l @ 0x80...0xb7) => {
355				let last_index_of = 1 + l as usize - 0x80;
356				if bytes.len() < last_index_of {
357					return Err(DecoderError::RlpInconsistentLengthAndData);
358				}
359				let d = &bytes[1..last_index_of];
360				if l == 0x81 && d[0] < 0x80 {
361					return Err(DecoderError::RlpInvalidIndirection);
362				}
363				Ok(f(d)?)
364			},
365			// Longer than 55 bytes.
366			Some(l @ 0xb8...0xbf) => {
367				let len_of_len = l as usize - 0xb7;
368				let begin_of_value = 1 as usize + len_of_len;
369				if bytes.len() < begin_of_value {
370					return Err(DecoderError::RlpInconsistentLengthAndData);
371				}
372				let len = decode_usize(&bytes[1..begin_of_value])?;
373
374				let last_index_of_value = begin_of_value + len;
375				if bytes.len() < last_index_of_value {
376					return Err(DecoderError::RlpInconsistentLengthAndData);
377				}
378				Ok(f(&bytes[begin_of_value..last_index_of_value])?)
379			}
380			// We are reading value, not a list!
381			_ => Err(DecoderError::RlpExpectedToBeData)
382		}
383	}
384}
385
386#[cfg(test)]
387mod tests {
388	use UntrustedRlp;
389
390	#[test]
391	fn test_rlp_display() {
392		use rustc_serialize::hex::FromHex;
393		let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap();
394		let rlp = UntrustedRlp::new(&data);
395		assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]");
396	}
397}