1use crate::{
2 DecodeAccumulator, DecodeError, DecodeLimits, checked_len_add, require_exact_consumption,
3};
4
5use super::{
6 LONG_LIST_OFFSET, RlpScalar, SHORT_LIST_OFFSET, SHORT_STRING_LIMIT, parse_payload_len, payload,
7};
8
9mod item;
10use item::{ParsedItemKind, parse_item};
11
12pub const MAX_RLP_LIST_TRAVERSAL_DEPTH: usize = 128;
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum RlpListForm {
21 ShortList,
23 LongList,
25}
26
27#[derive(Clone, Copy, Debug)]
32pub struct RlpList<'a> {
33 payload: &'a [u8],
34 encoded_len: usize,
35 header_len: usize,
36 item_count: usize,
37 form: RlpListForm,
38 limits: DecodeLimits,
39 iteration_depth_remaining: usize,
40}
41
42impl<'a> RlpList<'a> {
43 #[must_use]
45 pub const fn payload(self) -> &'a [u8] {
46 self.payload
47 }
48
49 #[must_use]
51 pub const fn encoded_len(self) -> usize {
52 self.encoded_len
53 }
54
55 #[must_use]
57 pub const fn header_len(self) -> usize {
58 self.header_len
59 }
60
61 #[must_use]
63 pub const fn item_count(self) -> usize {
64 self.item_count
65 }
66
67 #[must_use]
69 pub const fn form(self) -> RlpListForm {
70 self.form
71 }
72
73 #[must_use]
75 pub const fn is_empty(self) -> bool {
76 self.item_count == 0
77 }
78
79 #[must_use]
87 pub const fn items(self) -> RlpListItems<'a> {
88 self.items_with_depth_limit(self.iteration_depth_remaining)
89 }
90
91 #[must_use]
99 pub const fn items_with_depth_limit(self, depth: usize) -> RlpListItems<'a> {
100 RlpListItems {
101 input: self.payload,
102 cursor: 0,
103 remaining: self.item_count,
104 limits: self.limits,
105 depth_remaining: depth,
106 }
107 }
108}
109
110impl PartialEq for RlpList<'_> {
111 fn eq(&self, other: &Self) -> bool {
112 self.payload == other.payload
113 && self.encoded_len == other.encoded_len
114 && self.header_len == other.header_len
115 && self.item_count == other.item_count
116 && self.form == other.form
117 }
118}
119
120impl Eq for RlpList<'_> {}
121
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124pub enum RlpItem<'a> {
125 Scalar(RlpScalar<'a>),
127 List(RlpList<'a>),
129}
130
131impl<'a> RlpItem<'a> {
132 #[must_use]
134 pub const fn encoded_len(self) -> usize {
135 match self {
136 Self::Scalar(scalar) => scalar.encoded_len(),
137 Self::List(list) => list.encoded_len(),
138 }
139 }
140
141 #[must_use]
143 pub const fn header_len(self) -> usize {
144 match self {
145 Self::Scalar(scalar) => scalar.header_len(),
146 Self::List(list) => list.header_len(),
147 }
148 }
149
150 #[must_use]
152 pub const fn is_scalar(self) -> bool {
153 matches!(self, Self::Scalar(_))
154 }
155
156 #[must_use]
158 pub const fn is_list(self) -> bool {
159 matches!(self, Self::List(_))
160 }
161
162 #[must_use]
164 pub const fn as_scalar(&self) -> Option<RlpScalar<'a>> {
165 match self {
166 Self::Scalar(scalar) => Some(*scalar),
167 Self::List(_) => None,
168 }
169 }
170
171 #[must_use]
173 pub const fn as_list(&self) -> Option<RlpList<'a>> {
174 match self {
175 Self::Scalar(_) => None,
176 Self::List(list) => Some(*list),
177 }
178 }
179}
180
181#[derive(Clone, Debug)]
183pub struct RlpListItems<'a> {
184 input: &'a [u8],
185 cursor: usize,
186 remaining: usize,
187 limits: DecodeLimits,
188 depth_remaining: usize,
189}
190
191impl<'a> RlpListItems<'a> {
192 #[must_use]
194 pub const fn remaining(&self) -> usize {
195 self.remaining
196 }
197
198 #[cfg(test)]
200 pub(super) const fn for_test(input: &'a [u8], remaining: usize, limits: DecodeLimits) -> Self {
201 Self {
202 input,
203 cursor: 0,
204 remaining,
205 limits,
206 depth_remaining: 0,
207 }
208 }
209}
210
211impl<'a> Iterator for RlpListItems<'a> {
212 type Item = Result<RlpItem<'a>, DecodeError>;
213
214 fn next(&mut self) -> Option<Self::Item> {
215 if self.remaining == 0 {
216 return None;
217 }
218
219 let result = parse_item(self.input, self.cursor, self.input.len())
220 .and_then(|item| {
221 item.into_rlp_item(self.input, self.cursor, self.limits, self.depth_remaining)
222 })
223 .map(|(item, next_cursor)| {
224 self.cursor = next_cursor;
225 item
226 });
227 self.remaining = self.remaining.saturating_sub(1);
228
229 match result {
230 Ok(item) => Some(Ok(item)),
231 Err(error) => {
232 self.remaining = 0;
233 Some(Err(error))
234 }
235 }
236 }
237
238 fn size_hint(&self) -> (usize, Option<usize>) {
239 (0, Some(self.remaining))
240 }
241}
242
243impl core::iter::FusedIterator for RlpListItems<'_> {}
244
245pub fn decode_rlp_list<'a>(
247 input: &'a [u8],
248 limits: DecodeLimits,
249) -> Result<RlpList<'a>, DecodeError> {
250 let mut accumulator = limits.accumulator();
251 let list = decode_rlp_list_partial(input, &mut accumulator)?;
252 require_exact_consumption(list.encoded_len, input.len())?;
253 Ok(list)
254}
255
256pub fn decode_rlp_list_partial<'a>(
265 input: &'a [u8],
266 accumulator: &mut DecodeAccumulator,
267) -> Result<RlpList<'a>, DecodeError> {
268 accumulator.check_input_len(input.len())?;
269 accumulator.account_items(1)?;
270 accumulator.check_nesting_depth(1)?;
271
272 let prefix = *input.first().ok_or(DecodeError::Malformed)?;
273 let list = match prefix {
274 SHORT_LIST_OFFSET..=LONG_LIST_OFFSET => {
275 decode_short_list(input, prefix, accumulator.limits())?
276 }
277 0xf8..=0xff => decode_long_list(input, prefix, accumulator.limits())?,
278 0x00..=0xbf => return Err(DecodeError::UnexpectedScalar),
279 };
280 let item_count = validate_list_payload(list.payload, accumulator)?;
281 accumulator.check_list_count(item_count)?;
282 Ok(RlpList {
283 item_count,
284 iteration_depth_remaining: MAX_RLP_LIST_TRAVERSAL_DEPTH.saturating_sub(1),
285 ..list
286 })
287}
288
289fn decode_short_list(
290 input: &[u8],
291 prefix: u8,
292 limits: DecodeLimits,
293) -> Result<RlpList<'_>, DecodeError> {
294 let payload_len = usize::from(prefix.saturating_sub(SHORT_LIST_OFFSET));
295 let payload = payload(input, 1, payload_len)?;
296 Ok(RlpList {
297 payload,
298 encoded_len: checked_len_add(1, payload_len)?,
299 header_len: 1,
300 item_count: 0,
301 form: RlpListForm::ShortList,
302 limits,
303 iteration_depth_remaining: 0,
304 })
305}
306
307fn decode_long_list(
308 input: &[u8],
309 prefix: u8,
310 limits: DecodeLimits,
311) -> Result<RlpList<'_>, DecodeError> {
312 let len_of_len = usize::from(prefix.saturating_sub(LONG_LIST_OFFSET));
313 let payload_len = parse_payload_len(input, 1, len_of_len)?;
314 if payload_len <= SHORT_STRING_LIMIT {
315 return Err(DecodeError::Malformed);
316 }
317 let header_len = checked_len_add(1, len_of_len)?;
318 let payload = payload(input, header_len, payload_len)?;
319 Ok(RlpList {
320 payload,
321 encoded_len: checked_len_add(header_len, payload_len)?,
322 header_len,
323 item_count: 0,
324 form: RlpListForm::LongList,
325 limits,
326 iteration_depth_remaining: 0,
327 })
328}
329
330#[derive(Clone, Copy)]
331struct ListFrame {
332 end: usize,
333 count: usize,
334}
335
336pub(super) fn validate_list_payload(
337 input: &[u8],
338 accumulator: &mut DecodeAccumulator,
339) -> Result<usize, DecodeError> {
340 let mut stack = [ListFrame { end: 0, count: 0 }; MAX_RLP_LIST_TRAVERSAL_DEPTH];
341 let root = stack.get_mut(0).ok_or(DecodeError::NestingTooDeep)?;
342 *root = ListFrame {
343 end: input.len(),
344 count: 0,
345 };
346 let mut depth = 1usize;
347 let mut cursor = 0usize;
348
349 loop {
350 let frame_index = depth.checked_sub(1).ok_or(DecodeError::LengthOverflow)?;
351 let frame = stack
352 .get_mut(frame_index)
353 .ok_or(DecodeError::NestingTooDeep)?;
354
355 if cursor == frame.end {
356 let finished_count = frame.count;
357 accumulator.check_list_count(finished_count)?;
358 depth = depth.checked_sub(1).ok_or(DecodeError::LengthOverflow)?;
359 if depth == 0 {
360 return Ok(finished_count);
361 }
362 continue;
363 }
364 if cursor > frame.end {
365 return Err(DecodeError::OffsetOutOfBounds);
366 }
367
368 frame.count = checked_len_add(frame.count, 1)?;
369 accumulator.check_list_count(frame.count)?;
370
371 let item = parse_item(input, cursor, frame.end)?;
372 accumulator.account_items(1)?;
373 if matches!(item.kind, ParsedItemKind::List(_)) {
374 let next_depth = checked_len_add(depth, 1)?;
375 accumulator.check_nesting_depth(next_depth)?;
376 if next_depth > MAX_RLP_LIST_TRAVERSAL_DEPTH {
377 return Err(DecodeError::NestingTooDeep);
378 }
379 let child_index = next_depth
380 .checked_sub(1)
381 .ok_or(DecodeError::LengthOverflow)?;
382 let child = stack
383 .get_mut(child_index)
384 .ok_or(DecodeError::NestingTooDeep)?;
385 *child = ListFrame {
386 end: item.payload_end,
387 count: 0,
388 };
389 depth = next_depth;
390 cursor = item.payload_start;
391 } else {
392 cursor = item.item_end;
393 }
394 }
395}
396
397fn count_immediate_items(input: &[u8], limits: DecodeLimits) -> Result<usize, DecodeError> {
398 let mut accumulator = limits.accumulator();
401 accumulator.check_input_len(input.len())?;
402 let mut count = 0usize;
403 let mut cursor = 0usize;
404 while cursor < input.len() {
405 let item = parse_item(input, cursor, input.len())?;
406 count = checked_len_add(count, 1)?;
407 accumulator.account_items(1)?;
408 accumulator.check_list_count(count)?;
409 cursor = item.item_end;
410 }
411 Ok(count)
412}