1mod bounded_decoder;
2mod decode_as_debug_str;
3
4use std::io::Read;
5
6use crate::{
7 codec::abi_decoder::{
8 bounded_decoder::BoundedDecoder, decode_as_debug_str::decode_as_debug_str,
9 },
10 types::{Token, errors::Result, param_types::ParamType},
11};
12
13#[derive(Debug, Clone, Copy)]
14pub struct DecoderConfig {
15 pub max_depth: usize,
18 pub max_tokens: usize,
21}
22
23impl Default for DecoderConfig {
25 fn default() -> Self {
26 Self {
27 max_depth: 45,
28 max_tokens: 10_000,
29 }
30 }
31}
32#[derive(Default)]
35pub struct ABIDecoder {
36 pub config: DecoderConfig,
37}
38
39impl ABIDecoder {
40 pub fn new(config: DecoderConfig) -> Self {
41 Self { config }
42 }
43
44 pub fn decode(&self, param_type: &ParamType, mut bytes: impl Read) -> Result<Token> {
64 BoundedDecoder::new(self.config).decode(param_type, &mut bytes)
65 }
66
67 pub fn decode_multiple(
82 &self,
83 param_types: &[ParamType],
84 mut bytes: impl Read,
85 ) -> Result<Vec<Token>> {
86 BoundedDecoder::new(self.config).decode_multiple(param_types, &mut bytes)
87 }
88
89 pub fn decode_as_debug_str(
110 &self,
111 param_type: &ParamType,
112 mut bytes: impl Read,
113 ) -> Result<String> {
114 let token = BoundedDecoder::new(self.config).decode(param_type, &mut bytes)?;
115 decode_as_debug_str(param_type, &token)
116 }
117
118 pub fn decode_multiple_as_debug_str(
119 &self,
120 param_types: &[ParamType],
121 mut bytes: impl Read,
122 ) -> Result<Vec<String>> {
123 let token = BoundedDecoder::new(self.config).decode_multiple(param_types, &mut bytes)?;
124 token
125 .into_iter()
126 .zip(param_types)
127 .map(|(token, param_type)| decode_as_debug_str(param_type, &token))
128 .collect()
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use std::vec;
135
136 use ParamType::*;
137
138 use super::*;
139 use crate::{
140 constants::WORD_SIZE,
141 to_named,
142 traits::Parameterize,
143 types::{StaticStringToken, U256, errors::Error, param_types::EnumVariants},
144 };
145
146 #[test]
147 fn decode_multiple_uint() -> Result<()> {
148 let types = vec![
149 ParamType::U8,
150 ParamType::U16,
151 ParamType::U32,
152 ParamType::U64,
153 ParamType::U128,
154 ParamType::U256,
155 ];
156
157 let data = [
158 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
163 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
165 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ];
167
168 let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
169
170 let expected = vec![
171 Token::U8(u8::MAX),
172 Token::U16(u16::MAX),
173 Token::U32(u32::MAX),
174 Token::U64(u64::MAX),
175 Token::U128(u128::MAX),
176 Token::U256(U256::MAX),
177 ];
178 assert_eq!(decoded, expected);
179
180 Ok(())
181 }
182
183 #[test]
184 fn decode_bool() -> Result<()> {
185 let types = vec![ParamType::Bool, ParamType::Bool];
186 let data = [1, 0];
187
188 let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
189
190 let expected = vec![Token::Bool(true), Token::Bool(false)];
191
192 assert_eq!(decoded, expected);
193
194 Ok(())
195 }
196
197 #[test]
198 fn decode_b256() -> Result<()> {
199 let data = [
200 213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
201 152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11,
202 ];
203
204 let decoded = ABIDecoder::default().decode(&ParamType::B256, data.as_slice())?;
205
206 assert_eq!(decoded, Token::B256(data));
207
208 Ok(())
209 }
210
211 #[test]
212 fn decode_string_array() -> Result<()> {
213 let types = vec![ParamType::StringArray(23), ParamType::StringArray(5)];
214 let data = [
215 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
216 116, 101, 110, 99, 101, 72, 101, 108, 108, 111, ];
219
220 let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
221
222 let expected = vec![
223 Token::StringArray(StaticStringToken::new(
224 "This is a full sentence".into(),
225 Some(23),
226 )),
227 Token::StringArray(StaticStringToken::new("Hello".into(), Some(5))),
228 ];
229
230 assert_eq!(decoded, expected);
231
232 Ok(())
233 }
234
235 #[test]
236 fn decode_string_slice() -> Result<()> {
237 let data = [
238 0, 0, 0, 0, 0, 0, 0, 23, 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
240 116, 101, 110, 99, 101, ];
242
243 let decoded = ABIDecoder::default().decode(&ParamType::StringSlice, data.as_slice())?;
244
245 let expected = Token::StringSlice(StaticStringToken::new(
246 "This is a full sentence".into(),
247 None,
248 ));
249
250 assert_eq!(decoded, expected);
251
252 Ok(())
253 }
254
255 #[test]
256 fn decode_string() -> Result<()> {
257 let data = [
258 0, 0, 0, 0, 0, 0, 0, 23, 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
260 116, 101, 110, 99, 101, ];
262
263 let decoded = ABIDecoder::default().decode(&ParamType::String, data.as_slice())?;
264
265 let expected = Token::String("This is a full sentence".to_string());
266
267 assert_eq!(decoded, expected);
268
269 Ok(())
270 }
271
272 #[test]
273 fn decode_tuple() -> Result<()> {
274 let param_type = ParamType::Tuple(vec![ParamType::U32, ParamType::Bool]);
275 let data = [
276 0, 0, 0, 255, 1, ];
279
280 let result = ABIDecoder::default().decode(¶m_type, data.as_slice())?;
281
282 let expected = Token::Tuple(vec![Token::U32(255), Token::Bool(true)]);
283
284 assert_eq!(result, expected);
285
286 Ok(())
287 }
288
289 #[test]
290 fn decode_array() -> Result<()> {
291 let types = vec![ParamType::Array(Box::new(ParamType::U8), 2)];
292 let data = [255, 42];
293
294 let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
295
296 let expected = vec![Token::Array(vec![Token::U8(255), Token::U8(42)])];
297 assert_eq!(decoded, expected);
298
299 Ok(())
300 }
301
302 #[test]
303 fn decode_struct() -> Result<()> {
304 let data = [1, 1];
310
311 let param_type = ParamType::Struct {
312 name: "".to_string(),
313 fields: to_named(&[ParamType::U8, ParamType::Bool]),
314 generics: vec![],
315 };
316
317 let decoded = ABIDecoder::default().decode(¶m_type, data.as_slice())?;
318
319 let expected = Token::Struct(vec![Token::U8(1), Token::Bool(true)]);
320
321 assert_eq!(decoded, expected);
322
323 Ok(())
324 }
325
326 #[test]
327 fn decode_bytes() -> Result<()> {
328 let data = [0, 0, 0, 0, 0, 0, 0, 7, 255, 0, 1, 2, 3, 4, 5];
329
330 let decoded = ABIDecoder::default().decode(&ParamType::Bytes, data.as_slice())?;
331
332 let expected = Token::Bytes([255, 0, 1, 2, 3, 4, 5].to_vec());
333
334 assert_eq!(decoded, expected);
335
336 Ok(())
337 }
338
339 #[test]
340 fn decode_raw_slice() -> Result<()> {
341 let data = [0, 0, 0, 0, 0, 0, 0, 7, 255, 0, 1, 2, 3, 4, 5];
342
343 let decoded = ABIDecoder::default().decode(&ParamType::RawSlice, data.as_slice())?;
344
345 let expected = Token::RawSlice([255, 0, 1, 2, 3, 4, 5].to_vec());
346
347 assert_eq!(decoded, expected);
348
349 Ok(())
350 }
351
352 #[test]
353 fn decode_enum() -> Result<()> {
354 let types = to_named(&[ParamType::U32, ParamType::Bool]);
360 let inner_enum_types = EnumVariants::new(types)?;
361 let types = vec![ParamType::Enum {
362 name: "".to_string(),
363 enum_variants: inner_enum_types.clone(),
364 generics: vec![],
365 }];
366
367 let data = [
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, ];
371
372 let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
373
374 let expected = vec![Token::Enum(Box::new((0, Token::U32(42), inner_enum_types)))];
375 assert_eq!(decoded, expected);
376
377 Ok(())
378 }
379
380 #[test]
381 fn decode_nested_struct() -> Result<()> {
382 let fields = to_named(&[
393 ParamType::U16,
394 ParamType::Struct {
395 name: "".to_string(),
396 fields: to_named(&[
397 ParamType::Bool,
398 ParamType::Array(Box::new(ParamType::U8), 2),
399 ]),
400 generics: vec![],
401 },
402 ]);
403 let nested_struct = ParamType::Struct {
404 name: "".to_string(),
405 fields,
406 generics: vec![],
407 };
408
409 let data = [0, 10, 1, 1, 2];
410
411 let decoded = ABIDecoder::default().decode(&nested_struct, data.as_slice())?;
412
413 let my_nested_struct = vec![
414 Token::U16(10),
415 Token::Struct(vec![
416 Token::Bool(true),
417 Token::Array(vec![Token::U8(1), Token::U8(2)]),
418 ]),
419 ];
420
421 assert_eq!(decoded, Token::Struct(my_nested_struct));
422
423 Ok(())
424 }
425
426 #[test]
427 fn decode_comprehensive() -> Result<()> {
428 let fields = to_named(&[
442 ParamType::U16,
443 ParamType::Struct {
444 name: "".to_string(),
445 fields: to_named(&[
446 ParamType::Bool,
447 ParamType::Array(Box::new(ParamType::U8), 2),
448 ]),
449 generics: vec![],
450 },
451 ]);
452 let nested_struct = ParamType::Struct {
453 name: "".to_string(),
454 fields,
455 generics: vec![],
456 };
457
458 let u8_arr = ParamType::Array(Box::new(ParamType::U8), 2);
459 let b256 = ParamType::B256;
460
461 let types = [nested_struct, u8_arr, b256];
462
463 let bytes = [
464 0, 10, 1, 1, 2, 1, 2, 213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
469 152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11, ];
471
472 let decoded = ABIDecoder::default().decode_multiple(&types, bytes.as_slice())?;
473
474 let foo = Token::Struct(vec![
476 Token::U16(10),
477 Token::Struct(vec![
478 Token::Bool(true),
479 Token::Array(vec![Token::U8(1), Token::U8(2)]),
480 ]),
481 ]);
482
483 let u8_arr = Token::Array(vec![Token::U8(1), Token::U8(2)]);
484
485 let b256 = Token::B256([
486 213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
487 152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11,
488 ]);
489
490 let expected: Vec<Token> = vec![foo, u8_arr, b256];
491
492 assert_eq!(decoded, expected);
493
494 Ok(())
495 }
496
497 #[test]
498 fn enums_with_all_unit_variants_are_decoded_from_one_word() -> Result<()> {
499 let data = [0, 0, 0, 0, 0, 0, 0, 1];
500 let types = to_named(&[ParamType::Unit, ParamType::Unit]);
501 let enum_variants = EnumVariants::new(types)?;
502 let enum_w_only_units = ParamType::Enum {
503 name: "".to_string(),
504 enum_variants: enum_variants.clone(),
505 generics: vec![],
506 };
507
508 let result = ABIDecoder::default().decode(&enum_w_only_units, data.as_slice())?;
509
510 let expected_enum = Token::Enum(Box::new((1, Token::Unit, enum_variants)));
511 assert_eq!(result, expected_enum);
512
513 Ok(())
514 }
515
516 #[test]
517 fn out_of_bounds_discriminant_is_detected() -> Result<()> {
518 let data = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2];
519 let types = to_named(&[ParamType::U64]);
520 let enum_variants = EnumVariants::new(types)?;
521 let enum_type = ParamType::Enum {
522 name: "".to_string(),
523 enum_variants,
524 generics: vec![],
525 };
526
527 let result = ABIDecoder::default().decode(&enum_type, data.as_slice());
528
529 let error = result.expect_err("should have resulted in an error");
530
531 let expected_msg = "discriminant `1` doesn't point to any variant: ";
532 assert!(matches!(error, Error::Other(str) if str.starts_with(expected_msg)));
533
534 Ok(())
535 }
536
537 #[test]
538 pub fn division_by_zero() {
539 let param_type = Vec::<[u16; 0]>::param_type();
540 let result = ABIDecoder::default().decode(¶m_type, [].as_slice());
541 assert!(matches!(result, Err(Error::IO(_))));
542 }
543
544 #[test]
545 pub fn multiply_overflow_enum() {
546 let result = ABIDecoder::default().decode(
547 &Enum {
548 name: "".to_string(),
549 enum_variants: EnumVariants::new(to_named(&[
550 Array(Box::new(Array(Box::new(RawSlice), 8)), usize::MAX),
551 B256,
552 B256,
553 B256,
554 B256,
555 B256,
556 B256,
557 B256,
558 B256,
559 B256,
560 B256,
561 ]))
562 .unwrap(),
563 generics: vec![U16],
564 },
565 [].as_slice(),
566 );
567
568 assert!(matches!(result, Err(Error::IO(_))));
569 }
570
571 #[test]
572 pub fn multiply_overflow_arith() {
573 let mut param_type: ParamType = U16;
574 for _ in 0..50 {
575 param_type = Array(Box::new(param_type), 8);
576 }
577 let result = ABIDecoder::default().decode(
578 &Enum {
579 name: "".to_string(),
580 enum_variants: EnumVariants::new(to_named(&[param_type])).unwrap(),
581 generics: vec![U16],
582 },
583 [].as_slice(),
584 );
585 assert!(matches!(result, Err(Error::IO(_))));
586 }
587
588 #[test]
589 pub fn capacity_overflow() {
590 let result = ABIDecoder::default().decode(
591 &Array(Box::new(Array(Box::new(Tuple(vec![])), usize::MAX)), 1),
592 [].as_slice(),
593 );
594 assert!(matches!(result, Err(Error::Codec(_))));
595 }
596
597 #[test]
598 pub fn stack_overflow() {
599 let mut param_type: ParamType = U16;
600 for _ in 0..13500 {
601 param_type = Vector(Box::new(param_type));
602 }
603 let result = ABIDecoder::default().decode(¶m_type, [].as_slice());
604 assert!(matches!(result, Err(Error::IO(_))));
605 }
606
607 #[test]
608 pub fn capacity_malloc() {
609 let param_type = Array(Box::new(U8), usize::MAX);
610 let result = ABIDecoder::default().decode(¶m_type, [].as_slice());
611 assert!(matches!(result, Err(Error::IO(_))));
612 }
613
614 #[test]
615 fn max_depth_surpassed() {
616 const MAX_DEPTH: usize = 2;
617 let config = DecoderConfig {
618 max_depth: MAX_DEPTH,
619 ..Default::default()
620 };
621 let msg = format!("depth limit `{MAX_DEPTH}` reached while decoding. Try increasing it");
622 let data = [0; MAX_DEPTH * WORD_SIZE];
624
625 [nested_struct, nested_enum, nested_tuple, nested_array]
626 .iter()
627 .map(|fun| fun(MAX_DEPTH + 1))
628 .for_each(|param_type| {
629 assert_decoding_failed_w_data(config, ¶m_type, &msg, data.as_slice());
630 })
631 }
632
633 #[test]
634 fn depth_is_not_reached() {
635 const MAX_DEPTH: usize = 3;
636 const ACTUAL_DEPTH: usize = MAX_DEPTH - 1;
637
638 let data = [0; 2 * ACTUAL_DEPTH * (WORD_SIZE * 2)];
640 let config = DecoderConfig {
641 max_depth: MAX_DEPTH,
642 ..Default::default()
643 };
644
645 [nested_struct, nested_enum, nested_tuple, nested_array]
646 .into_iter()
647 .map(|fun| fun(ACTUAL_DEPTH))
648 .map(|param_type| {
649 ParamType::Struct {
652 name: "".to_string(),
653 fields: to_named(&[param_type.clone(), param_type]),
654 generics: vec![],
655 }
656 })
657 .for_each(|param_type| {
658 ABIDecoder::new(config)
659 .decode(¶m_type, data.as_slice())
660 .unwrap();
661 })
662 }
663
664 #[test]
665 fn too_many_tokens() {
666 let config = DecoderConfig {
667 max_tokens: 3,
668 ..Default::default()
669 };
670 {
671 let data = [0; 3 * WORD_SIZE];
672 let inner_param_types = vec![ParamType::U64; 3];
673 for param_type in [
674 ParamType::Struct {
675 name: "".to_string(),
676 fields: to_named(&inner_param_types),
677 generics: vec![],
678 },
679 ParamType::Tuple(inner_param_types.clone()),
680 ParamType::Array(Box::new(ParamType::U64), 3),
681 ] {
682 assert_decoding_failed_w_data(
683 config,
684 ¶m_type,
685 "token limit `3` reached while decoding. Try increasing it",
686 &data,
687 );
688 }
689 }
690 {
691 let data = [0, 0, 0, 0, 0, 0, 0, 3, 1, 2, 3];
692
693 assert_decoding_failed_w_data(
694 config,
695 &ParamType::Vector(Box::new(ParamType::U8)),
696 "token limit `3` reached while decoding. Try increasing it",
697 &data,
698 );
699 }
700 }
701
702 #[test]
703 fn token_count_is_being_reset_between_decodings() {
704 let config = DecoderConfig {
706 max_tokens: 3,
707 ..Default::default()
708 };
709
710 let param_type = ParamType::Array(Box::new(ParamType::StringArray(0)), 2);
711
712 let decoder = ABIDecoder::new(config);
713 decoder.decode(¶m_type, [].as_slice()).unwrap();
714
715 let result = decoder.decode(¶m_type, [].as_slice());
717
718 result.expect("element count to be reset");
720 }
721
722 fn assert_decoding_failed_w_data(
723 config: DecoderConfig,
724 param_type: &ParamType,
725 msg: &str,
726 data: &[u8],
727 ) {
728 let decoder = ABIDecoder::new(config);
729
730 let err = decoder.decode(param_type, data);
731
732 let Err(Error::Codec(actual_msg)) = err else {
733 panic!("expected a `Codec` error. Got: `{err:?}`");
734 };
735
736 assert_eq!(actual_msg, msg);
737 }
738
739 fn nested_struct(depth: usize) -> ParamType {
740 let fields = if depth == 1 {
741 vec![]
742 } else {
743 to_named(&[nested_struct(depth - 1)])
744 };
745
746 ParamType::Struct {
747 name: "".to_string(),
748 fields,
749 generics: vec![],
750 }
751 }
752
753 fn nested_enum(depth: usize) -> ParamType {
754 let fields = if depth == 1 {
755 to_named(&[ParamType::U8])
756 } else {
757 to_named(&[nested_enum(depth - 1)])
758 };
759
760 ParamType::Enum {
761 name: "".to_string(),
762 enum_variants: EnumVariants::new(fields).unwrap(),
763 generics: vec![],
764 }
765 }
766
767 fn nested_array(depth: usize) -> ParamType {
768 let field = if depth == 1 {
769 ParamType::U8
770 } else {
771 nested_array(depth - 1)
772 };
773
774 ParamType::Array(Box::new(field), 1)
775 }
776
777 fn nested_tuple(depth: usize) -> ParamType {
778 let fields = if depth == 1 {
779 vec![ParamType::U8]
780 } else {
781 vec![nested_tuple(depth - 1)]
782 };
783
784 ParamType::Tuple(fields)
785 }
786}