rlp/
rlpin.rs

1// Copyright 2020 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
9#[cfg(not(feature = "std"))]
10use alloc::{string::String, vec::Vec};
11use core::{cell::Cell, fmt};
12
13use rustc_hex::ToHex;
14
15use crate::{error::DecoderError, impls::decode_usize, traits::Decodable};
16
17/// rlp offset
18#[derive(Copy, Clone, Debug)]
19struct OffsetCache {
20	index: usize,
21	offset: usize,
22}
23
24impl OffsetCache {
25	const fn new(index: usize, offset: usize) -> OffsetCache {
26		OffsetCache { index, offset }
27	}
28}
29
30#[derive(Debug)]
31/// RLP prototype
32pub enum Prototype {
33	/// Empty
34	Null,
35	/// Value
36	Data(usize),
37	/// List
38	List(usize),
39}
40
41/// Stores basic information about item
42#[derive(Debug)]
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 {
58		return Err(DecoderError::RlpIsTooShort)
59	}
60	let value_len = decode_usize(&header_bytes[1..header_len])?;
61	if value_len <= 55 {
62		return Err(DecoderError::RlpInvalidIndirection)
63	}
64	Ok(PayloadInfo::new(header_len, value_len))
65}
66
67impl PayloadInfo {
68	const fn new(header_len: usize, value_len: usize) -> PayloadInfo {
69		PayloadInfo { header_len, value_len }
70	}
71
72	/// Total size of the RLP.
73	pub fn total(&self) -> usize {
74		self.header_len + self.value_len
75	}
76
77	/// Create a new object from the given bytes RLP. The bytes
78	pub fn from(header_bytes: &[u8]) -> Result<PayloadInfo, DecoderError> {
79		let l = *header_bytes.first().ok_or_else(|| DecoderError::RlpIsTooShort)?;
80		if l <= 0x7f {
81			Ok(PayloadInfo::new(0, 1))
82		} else if l <= 0xb7 {
83			Ok(PayloadInfo::new(1, l as usize - 0x80))
84		} else if l <= 0xbf {
85			let len_of_len = l as usize - 0xb7;
86			calculate_payload_info(header_bytes, len_of_len)
87		} else if l <= 0xf7 {
88			Ok(PayloadInfo::new(1, l as usize - 0xc0))
89		} else {
90			let len_of_len = l as usize - 0xf7;
91			calculate_payload_info(header_bytes, len_of_len)
92		}
93	}
94}
95
96/// Data-oriented view onto rlp-slice.
97///
98/// This is an immutable structure. No operations change it.
99///
100/// Should be used in places where, error handling is required,
101/// eg. on input
102#[derive(Debug, Clone)]
103pub struct Rlp<'a> {
104	bytes: &'a [u8],
105	offset_cache: Cell<Option<OffsetCache>>,
106	count_cache: Cell<Option<usize>>,
107}
108
109impl<'a> fmt::Display for Rlp<'a> {
110	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
111		match self.prototype() {
112			Ok(Prototype::Null) => write!(f, "null"),
113			Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex::<String>()),
114			Ok(Prototype::List(len)) => {
115				write!(f, "[")?;
116				for i in 0..len - 1 {
117					write!(f, "{}, ", self.at(i).unwrap())?;
118				}
119				write!(f, "{}", self.at(len - 1).unwrap())?;
120				write!(f, "]")
121			},
122			Err(err) => write!(f, "{:?}", err),
123		}
124	}
125}
126
127impl<'a> Rlp<'a> {
128	pub const fn new(bytes: &'a [u8]) -> Rlp<'a> {
129		Rlp { bytes, offset_cache: Cell::new(None), count_cache: Cell::new(None) }
130	}
131
132	pub fn as_raw<'view>(&'view self) -> &'a [u8]
133	where
134		'a: 'view,
135	{
136		self.bytes
137	}
138
139	pub fn prototype(&self) -> Result<Prototype, DecoderError> {
140		// optimize? && return appropriate errors
141		if self.is_data() {
142			Ok(Prototype::Data(self.size()))
143		} else if self.is_list() {
144			self.item_count().map(Prototype::List)
145		} else {
146			Ok(Prototype::Null)
147		}
148	}
149
150	pub fn payload_info(&self) -> Result<PayloadInfo, DecoderError> {
151		BasicDecoder::payload_info(self.bytes)
152	}
153
154	pub fn data<'view>(&'view self) -> Result<&'a [u8], DecoderError>
155	where
156		'a: 'view,
157	{
158		let pi = BasicDecoder::payload_info(self.bytes)?;
159		Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)])
160	}
161
162	pub fn item_count(&self) -> Result<usize, DecoderError> {
163		if self.is_list() {
164			match self.count_cache.get() {
165				Some(c) => Ok(c),
166				None => {
167					let c = self.iter().count();
168					self.count_cache.set(Some(c));
169					Ok(c)
170				},
171			}
172		} else {
173			Err(DecoderError::RlpExpectedToBeList)
174		}
175	}
176
177	pub fn size(&self) -> usize {
178		if self.is_data() {
179			// TODO: No panic on malformed data, but ideally would Err on no PayloadInfo.
180			BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0)
181		} else {
182			0
183		}
184	}
185
186	/// Returns an Rlp item in a list at the given index.
187	///
188	/// Returns an error if this Rlp is not a list or if the index is out of range.
189	pub fn at<'view>(&'view self, index: usize) -> Result<Rlp<'a>, DecoderError>
190	where
191		'a: 'view,
192	{
193		let (rlp, _offset) = self.at_with_offset(index)?;
194		Ok(rlp)
195	}
196
197	/// Returns an Rlp item in a list at the given index along with the byte offset into the
198	/// raw data slice.
199	///
200	/// Returns an error if this Rlp is not a list or if the index is out of range.
201	pub fn at_with_offset<'view>(&'view self, index: usize) -> Result<(Rlp<'a>, usize), DecoderError>
202	where
203		'a: 'view,
204	{
205		if !self.is_list() {
206			return Err(DecoderError::RlpExpectedToBeList)
207		}
208
209		// move to cached position if its index is less or equal to
210		// current search index, otherwise move to beginning of list
211		let cache = self.offset_cache.get();
212		let (bytes, indexes_to_skip, bytes_consumed) = match cache {
213			Some(ref cache) if cache.index <= index =>
214				(Rlp::consume(self.bytes, cache.offset)?, index - cache.index, cache.offset),
215			_ => {
216				let (bytes, consumed) = self.consume_list_payload()?;
217				(bytes, index, consumed)
218			},
219		};
220
221		// skip up to x items
222		let (bytes, consumed) = Rlp::consume_items(bytes, indexes_to_skip)?;
223
224		// update the cache
225		let offset = bytes_consumed + consumed;
226		self.offset_cache.set(Some(OffsetCache::new(index, offset)));
227
228		// construct new rlp
229		let found = BasicDecoder::payload_info(bytes)?;
230		Ok((Rlp::new(&bytes[0..found.header_len + found.value_len]), offset))
231	}
232
233	pub fn is_null(&self) -> bool {
234		self.bytes.is_empty()
235	}
236
237	pub fn is_empty(&self) -> bool {
238		!self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80)
239	}
240
241	pub fn is_list(&self) -> bool {
242		!self.is_null() && self.bytes[0] >= 0xc0
243	}
244
245	pub fn is_data(&self) -> bool {
246		!self.is_null() && self.bytes[0] < 0xc0
247	}
248
249	pub fn is_int(&self) -> bool {
250		if self.is_null() {
251			return false
252		}
253
254		match self.bytes[0] {
255			0..=0x80 => true,
256			0x81..=0xb7 => self.bytes[1] != 0,
257			b @ 0xb8..=0xbf => {
258				let payload_idx = 1 + b as usize - 0xb7;
259				payload_idx < self.bytes.len() && self.bytes[payload_idx] != 0
260			},
261			_ => false,
262		}
263	}
264
265	pub fn iter<'view>(&'view self) -> RlpIterator<'a, 'view>
266	where
267		'a: 'view,
268	{
269		self.into_iter()
270	}
271
272	pub fn as_val<T>(&self) -> Result<T, DecoderError>
273	where
274		T: Decodable,
275	{
276		T::decode(self)
277	}
278
279	pub fn as_list<T>(&self) -> Result<Vec<T>, DecoderError>
280	where
281		T: Decodable,
282	{
283		self.iter().map(|rlp| rlp.as_val()).collect()
284	}
285
286	pub fn val_at<T>(&self, index: usize) -> Result<T, DecoderError>
287	where
288		T: Decodable,
289	{
290		self.at(index)?.as_val()
291	}
292
293	pub fn list_at<T>(&self, index: usize) -> Result<Vec<T>, DecoderError>
294	where
295		T: Decodable,
296	{
297		self.at(index)?.as_list()
298	}
299
300	pub fn decoder(&self) -> BasicDecoder {
301		BasicDecoder::new(self.bytes)
302	}
303
304	/// consumes first found prefix
305	fn consume_list_payload(&self) -> Result<(&'a [u8], usize), DecoderError> {
306		let item = BasicDecoder::payload_info(self.bytes)?;
307		if self.bytes.len() < (item.header_len + item.value_len) {
308			return Err(DecoderError::RlpIsTooShort)
309		}
310		Ok((&self.bytes[item.header_len..item.header_len + item.value_len], item.header_len))
311	}
312
313	/// consumes fixed number of items
314	fn consume_items(bytes: &'a [u8], items: usize) -> Result<(&'a [u8], usize), DecoderError> {
315		let mut result = bytes;
316		let mut consumed = 0;
317		for _ in 0..items {
318			let i = BasicDecoder::payload_info(result)?;
319			let to_consume = i.header_len + i.value_len;
320			result = Rlp::consume(result, to_consume)?;
321			consumed += to_consume;
322		}
323		Ok((result, consumed))
324	}
325
326	/// consumes slice prefix of length `len`
327	fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> {
328		if bytes.len() >= len {
329			Ok(&bytes[len..])
330		} else {
331			Err(DecoderError::RlpIsTooShort)
332		}
333	}
334}
335
336/// Iterator over rlp-slice list elements.
337pub struct RlpIterator<'a, 'view>
338where
339	'a: 'view,
340{
341	rlp: &'view Rlp<'a>,
342	index: usize,
343}
344
345impl<'a, 'view> IntoIterator for &'view Rlp<'a>
346where
347	'a: 'view,
348{
349	type Item = Rlp<'a>;
350	type IntoIter = RlpIterator<'a, 'view>;
351
352	fn into_iter(self) -> Self::IntoIter {
353		RlpIterator { rlp: self, index: 0 }
354	}
355}
356
357impl<'a, 'view> Iterator for RlpIterator<'a, 'view> {
358	type Item = Rlp<'a>;
359
360	fn next(&mut self) -> Option<Rlp<'a>> {
361		let index = self.index;
362		let result = self.rlp.at(index).ok();
363		self.index += 1;
364		result
365	}
366}
367
368impl<'a, 'view> ExactSizeIterator for RlpIterator<'a, 'view> {
369	fn len(&self) -> usize {
370		self.rlp.item_count().unwrap_or(0).saturating_sub(self.index)
371	}
372}
373
374pub struct BasicDecoder<'a> {
375	rlp: &'a [u8],
376}
377
378impl<'a> BasicDecoder<'a> {
379	pub const fn new(rlp: &'a [u8]) -> BasicDecoder<'a> {
380		BasicDecoder { rlp }
381	}
382
383	/// Return first item info.
384	fn payload_info(bytes: &[u8]) -> Result<PayloadInfo, DecoderError> {
385		let item = PayloadInfo::from(bytes)?;
386		match item.header_len.checked_add(item.value_len) {
387			Some(x) if x <= bytes.len() => Ok(item),
388			_ => Err(DecoderError::RlpIsTooShort),
389		}
390	}
391
392	pub fn decode_value<T, F>(&self, f: F) -> Result<T, DecoderError>
393	where
394		F: Fn(&[u8]) -> Result<T, DecoderError>,
395	{
396		let bytes = self.rlp;
397
398		let l = *bytes.first().ok_or_else(|| DecoderError::RlpIsTooShort)?;
399
400		if l <= 0x7f {
401			Ok(f(&[l])?)
402		} else if l <= 0xb7 {
403			let last_index_of = 1 + l as usize - 0x80;
404			if bytes.len() < last_index_of {
405				return Err(DecoderError::RlpInconsistentLengthAndData)
406			}
407			let d = &bytes[1..last_index_of];
408			if l == 0x81 && d[0] < 0x80 {
409				return Err(DecoderError::RlpInvalidIndirection)
410			}
411			Ok(f(d)?)
412		} else if l <= 0xbf {
413			let len_of_len = l as usize - 0xb7;
414			let begin_of_value = 1 as usize + len_of_len;
415			if bytes.len() < begin_of_value {
416				return Err(DecoderError::RlpInconsistentLengthAndData)
417			}
418			let len = decode_usize(&bytes[1..begin_of_value])?;
419
420			let last_index_of_value = begin_of_value.checked_add(len).ok_or(DecoderError::RlpInvalidLength)?;
421			if bytes.len() < last_index_of_value {
422				return Err(DecoderError::RlpInconsistentLengthAndData)
423			}
424			Ok(f(&bytes[begin_of_value..last_index_of_value])?)
425		} else {
426			Err(DecoderError::RlpExpectedToBeData)
427		}
428	}
429}