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