1use crate::{
2 DecodeAccumulator, DecodeError, DecodeLimits, checked_len_add, require_exact_consumption,
3 require_range_in_bounds,
4};
5
6use super::{
7 LONG_LIST_OFFSET, RlpScalar, RlpScalarForm, SHORT_LIST_OFFSET, SHORT_STRING_LIMIT,
8 decode_long_string, decode_short_string, parse_payload_len, payload,
9};
10
11pub const MAX_RLP_LIST_TRAVERSAL_DEPTH: usize = 128;
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum RlpListForm {
20 ShortList,
22 LongList,
24}
25
26#[derive(Clone, Copy, Debug)]
31pub struct RlpList<'a> {
32 payload: &'a [u8],
33 encoded_len: usize,
34 header_len: usize,
35 item_count: usize,
36 form: RlpListForm,
37 limits: DecodeLimits,
38}
39
40impl<'a> RlpList<'a> {
41 #[must_use]
43 pub const fn payload(self) -> &'a [u8] {
44 self.payload
45 }
46
47 #[must_use]
49 pub const fn encoded_len(self) -> usize {
50 self.encoded_len
51 }
52
53 #[must_use]
55 pub const fn header_len(self) -> usize {
56 self.header_len
57 }
58
59 #[must_use]
61 pub const fn item_count(self) -> usize {
62 self.item_count
63 }
64
65 #[must_use]
67 pub const fn form(self) -> RlpListForm {
68 self.form
69 }
70
71 #[must_use]
73 pub const fn is_empty(self) -> bool {
74 self.item_count == 0
75 }
76
77 #[must_use]
79 pub const fn items(self) -> RlpListItems<'a> {
80 RlpListItems {
81 input: self.payload,
82 cursor: 0,
83 remaining: self.item_count,
84 limits: self.limits,
85 }
86 }
87}
88
89impl PartialEq for RlpList<'_> {
90 fn eq(&self, other: &Self) -> bool {
91 self.payload == other.payload
92 && self.encoded_len == other.encoded_len
93 && self.header_len == other.header_len
94 && self.item_count == other.item_count
95 && self.form == other.form
96 }
97}
98
99impl Eq for RlpList<'_> {}
100
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103pub enum RlpItem<'a> {
104 Scalar(RlpScalar<'a>),
106 List(RlpList<'a>),
108}
109
110impl<'a> RlpItem<'a> {
111 #[must_use]
113 pub const fn encoded_len(self) -> usize {
114 match self {
115 Self::Scalar(scalar) => scalar.encoded_len(),
116 Self::List(list) => list.encoded_len(),
117 }
118 }
119
120 #[must_use]
122 pub const fn header_len(self) -> usize {
123 match self {
124 Self::Scalar(scalar) => scalar.header_len(),
125 Self::List(list) => list.header_len(),
126 }
127 }
128
129 #[must_use]
131 pub const fn is_scalar(self) -> bool {
132 matches!(self, Self::Scalar(_))
133 }
134
135 #[must_use]
137 pub const fn is_list(self) -> bool {
138 matches!(self, Self::List(_))
139 }
140
141 #[must_use]
143 pub const fn as_scalar(&self) -> Option<RlpScalar<'a>> {
144 match self {
145 Self::Scalar(scalar) => Some(*scalar),
146 Self::List(_) => None,
147 }
148 }
149
150 #[must_use]
152 pub const fn as_list(&self) -> Option<RlpList<'a>> {
153 match self {
154 Self::Scalar(_) => None,
155 Self::List(list) => Some(*list),
156 }
157 }
158}
159
160#[derive(Clone, Debug)]
162pub struct RlpListItems<'a> {
163 input: &'a [u8],
164 cursor: usize,
165 remaining: usize,
166 limits: DecodeLimits,
167}
168
169impl<'a> RlpListItems<'a> {
170 #[must_use]
172 pub const fn remaining(&self) -> usize {
173 self.remaining
174 }
175}
176
177impl<'a> Iterator for RlpListItems<'a> {
178 type Item = Result<RlpItem<'a>, DecodeError>;
179
180 fn next(&mut self) -> Option<Self::Item> {
181 if self.remaining == 0 {
182 return None;
183 }
184
185 match parse_item(self.input, self.cursor, self.input.len())
186 .and_then(|item| item.into_rlp_item(self.input, self.cursor, self.limits))
187 {
188 Ok((item, next_cursor)) => {
189 self.cursor = next_cursor;
190 self.remaining = self.remaining.saturating_sub(1);
191 Some(Ok(item))
192 }
193 Err(error) => {
194 self.remaining = 0;
195 Some(Err(error))
196 }
197 }
198 }
199
200 fn size_hint(&self) -> (usize, Option<usize>) {
201 (self.remaining, Some(self.remaining))
202 }
203}
204
205impl ExactSizeIterator for RlpListItems<'_> {}
206
207impl core::iter::FusedIterator for RlpListItems<'_> {}
208
209pub fn decode_rlp_list<'a>(
211 input: &'a [u8],
212 limits: DecodeLimits,
213) -> Result<RlpList<'a>, DecodeError> {
214 let mut accumulator = limits.accumulator();
215 let list = decode_rlp_list_partial(input, &mut accumulator)?;
216 require_exact_consumption(list.encoded_len, input.len())?;
217 Ok(list)
218}
219
220pub fn decode_rlp_list_partial<'a>(
229 input: &'a [u8],
230 accumulator: &mut DecodeAccumulator,
231) -> Result<RlpList<'a>, DecodeError> {
232 accumulator.check_input_len(input.len())?;
233 accumulator.account_items(1)?;
234 accumulator.check_nesting_depth(1)?;
235
236 let prefix = *input.first().ok_or(DecodeError::Malformed)?;
237 let list = match prefix {
238 SHORT_LIST_OFFSET..=LONG_LIST_OFFSET => {
239 decode_short_list(input, prefix, accumulator.limits())?
240 }
241 0xf8..=0xff => decode_long_list(input, prefix, accumulator.limits())?,
242 0x00..=0xbf => return Err(DecodeError::UnexpectedScalar),
243 };
244 let item_count = validate_list_payload(list.payload, accumulator)?;
245 accumulator.check_list_count(item_count)?;
246 Ok(RlpList { item_count, ..list })
247}
248
249fn decode_short_list(
250 input: &[u8],
251 prefix: u8,
252 limits: DecodeLimits,
253) -> Result<RlpList<'_>, DecodeError> {
254 let payload_len = usize::from(prefix.saturating_sub(SHORT_LIST_OFFSET));
255 let payload = payload(input, 1, payload_len)?;
256 Ok(RlpList {
257 payload,
258 encoded_len: checked_len_add(1, payload_len)?,
259 header_len: 1,
260 item_count: 0,
261 form: RlpListForm::ShortList,
262 limits,
263 })
264}
265
266fn decode_long_list(
267 input: &[u8],
268 prefix: u8,
269 limits: DecodeLimits,
270) -> Result<RlpList<'_>, DecodeError> {
271 let len_of_len = usize::from(prefix.saturating_sub(LONG_LIST_OFFSET));
272 let payload_len = parse_payload_len(input, 1, len_of_len)?;
273 if payload_len <= SHORT_STRING_LIMIT {
274 return Err(DecodeError::Malformed);
275 }
276 let header_len = checked_len_add(1, len_of_len)?;
277 let payload = payload(input, header_len, payload_len)?;
278 Ok(RlpList {
279 payload,
280 encoded_len: checked_len_add(header_len, payload_len)?,
281 header_len,
282 item_count: 0,
283 form: RlpListForm::LongList,
284 limits,
285 })
286}
287
288#[derive(Clone, Copy)]
289struct ListFrame {
290 end: usize,
291 count: usize,
292}
293
294pub(super) fn validate_list_payload(
295 input: &[u8],
296 accumulator: &mut DecodeAccumulator,
297) -> Result<usize, DecodeError> {
298 let mut stack = [ListFrame { end: 0, count: 0 }; MAX_RLP_LIST_TRAVERSAL_DEPTH];
299 let root = stack.get_mut(0).ok_or(DecodeError::NestingTooDeep)?;
300 *root = ListFrame {
301 end: input.len(),
302 count: 0,
303 };
304 let mut depth = 1usize;
305 let mut cursor = 0usize;
306
307 loop {
308 let frame_index = depth.checked_sub(1).ok_or(DecodeError::LengthOverflow)?;
309 let frame = stack
310 .get_mut(frame_index)
311 .ok_or(DecodeError::NestingTooDeep)?;
312
313 if cursor == frame.end {
314 let finished_count = frame.count;
315 accumulator.check_list_count(finished_count)?;
316 depth = depth.checked_sub(1).ok_or(DecodeError::LengthOverflow)?;
317 if depth == 0 {
318 return Ok(finished_count);
319 }
320 continue;
321 }
322 if cursor > frame.end {
323 return Err(DecodeError::OffsetOutOfBounds);
324 }
325
326 frame.count = checked_len_add(frame.count, 1)?;
327 accumulator.check_list_count(frame.count)?;
328
329 let item = parse_item(input, cursor, frame.end)?;
330 accumulator.account_items(1)?;
331 if matches!(item.kind, ParsedItemKind::List(_)) {
332 let next_depth = checked_len_add(depth, 1)?;
333 accumulator.check_nesting_depth(next_depth)?;
334 if next_depth > MAX_RLP_LIST_TRAVERSAL_DEPTH {
335 return Err(DecodeError::NestingTooDeep);
336 }
337 let child_index = next_depth
338 .checked_sub(1)
339 .ok_or(DecodeError::LengthOverflow)?;
340 let child = stack
341 .get_mut(child_index)
342 .ok_or(DecodeError::NestingTooDeep)?;
343 *child = ListFrame {
344 end: item.payload_end,
345 count: 0,
346 };
347 depth = next_depth;
348 cursor = item.payload_start;
349 } else {
350 cursor = item.item_end;
351 }
352 }
353}
354
355struct ParsedItem {
356 kind: ParsedItemKind,
357 header_len: usize,
358 payload_start: usize,
359 payload_end: usize,
360 item_end: usize,
361}
362
363impl ParsedItem {
364 fn into_rlp_item<'a>(
365 self,
366 input: &'a [u8],
367 offset: usize,
368 limits: DecodeLimits,
369 ) -> Result<(RlpItem<'a>, usize), DecodeError> {
370 let payload = input
371 .get(self.payload_start..self.payload_end)
372 .ok_or(DecodeError::OffsetOutOfBounds)?;
373 let encoded_len = self
374 .item_end
375 .checked_sub(offset)
376 .ok_or(DecodeError::LengthOverflow)?;
377 let item = match self.kind {
378 ParsedItemKind::Scalar(form) => RlpItem::Scalar(RlpScalar {
379 payload,
380 encoded_len,
381 header_len: self.header_len,
382 form,
383 }),
384 ParsedItemKind::List(form) => RlpItem::List(RlpList {
385 payload,
386 encoded_len,
387 header_len: self.header_len,
388 item_count: count_immediate_items(payload, limits)?,
389 form,
390 limits,
391 }),
392 };
393 Ok((item, self.item_end))
394 }
395}
396
397#[derive(Clone, Copy)]
398enum ParsedItemKind {
399 Scalar(RlpScalarForm),
400 List(RlpListForm),
401}
402
403fn parse_item(
404 input: &[u8],
405 offset: usize,
406 container_end: usize,
407) -> Result<ParsedItem, DecodeError> {
408 let local = input
409 .get(offset..container_end)
410 .ok_or(DecodeError::OffsetOutOfBounds)?;
411 let prefix = *local.first().ok_or(DecodeError::Malformed)?;
412 let (kind, header_len, payload_len) = match prefix {
413 0x00..=0x7f => (ParsedItemKind::Scalar(RlpScalarForm::SingleByte), 0, 1),
414 super::SHORT_STRING_OFFSET..=super::LONG_STRING_OFFSET => {
415 let scalar = decode_short_string(local, prefix)?;
416 (
417 ParsedItemKind::Scalar(scalar.form()),
418 scalar.header_len(),
419 scalar.payload().len(),
420 )
421 }
422 0xb8..=0xbf => {
423 let scalar = decode_long_string(local, prefix)?;
424 (
425 ParsedItemKind::Scalar(scalar.form()),
426 scalar.header_len(),
427 scalar.payload().len(),
428 )
429 }
430 SHORT_LIST_OFFSET..=LONG_LIST_OFFSET => {
431 let payload_len = usize::from(prefix.saturating_sub(SHORT_LIST_OFFSET));
432 payload(local, 1, payload_len)?;
433 (ParsedItemKind::List(RlpListForm::ShortList), 1, payload_len)
434 }
435 0xf8..=0xff => {
436 let len_of_len = usize::from(prefix.saturating_sub(LONG_LIST_OFFSET));
437 let payload_len = parse_payload_len(local, 1, len_of_len)?;
438 if payload_len <= SHORT_STRING_LIMIT {
439 return Err(DecodeError::Malformed);
440 }
441 let header_len = checked_len_add(1, len_of_len)?;
442 payload(local, header_len, payload_len)?;
443 (
444 ParsedItemKind::List(RlpListForm::LongList),
445 header_len,
446 payload_len,
447 )
448 }
449 };
450 let payload_start = checked_len_add(offset, header_len)?;
451 let payload_end = checked_len_add(payload_start, payload_len)?;
452 let item_end = if header_len == 0 {
453 checked_len_add(offset, 1)?
454 } else {
455 payload_end
456 };
457 require_range_in_bounds(offset, item_end.saturating_sub(offset), container_end)?;
458 Ok(ParsedItem {
459 kind,
460 header_len,
461 payload_start,
462 payload_end,
463 item_end,
464 })
465}
466
467fn count_immediate_items(input: &[u8], limits: DecodeLimits) -> Result<usize, DecodeError> {
468 let mut accumulator = limits.accumulator();
471 accumulator.check_input_len(input.len())?;
472 let mut count = 0usize;
473 let mut cursor = 0usize;
474 while cursor < input.len() {
475 let item = parse_item(input, cursor, input.len())?;
476 count = checked_len_add(count, 1)?;
477 accumulator.account_items(1)?;
478 accumulator.check_list_count(count)?;
479 cursor = item.item_end;
480 }
481 if cursor == input.len() {
482 Ok(count)
483 } else {
484 Err(DecodeError::OffsetOutOfBounds)
485 }
486}