ssz/decode/
impls.rs

1use super::*;
2use crate::decode::try_from_iter::{TryCollect, TryFromIter};
3use alloy_primitives::{Address, Bloom, Bytes, FixedBytes, U128, U256};
4use core::num::NonZeroUsize;
5use itertools::process_results;
6use smallvec::SmallVec;
7use std::collections::{BTreeMap, BTreeSet};
8use std::iter::{self, FromIterator};
9use std::sync::Arc;
10
11macro_rules! impl_decodable_for_uint {
12    ($type: ident, $bit_size: expr) => {
13        impl Decode for $type {
14            #[inline(always)]
15            fn is_ssz_fixed_len() -> bool {
16                true
17            }
18
19            #[inline(always)]
20            fn ssz_fixed_len() -> usize {
21                $bit_size / 8
22            }
23
24            #[inline(always)]
25            fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
26                let len = bytes.len();
27                let expected = <Self as Decode>::ssz_fixed_len();
28
29                if len != expected {
30                    Err(DecodeError::InvalidByteLength { len, expected })
31                } else {
32                    let mut array: [u8; $bit_size / 8] = std::default::Default::default();
33                    array.clone_from_slice(bytes);
34
35                    Ok(Self::from_le_bytes(array))
36                }
37            }
38        }
39    };
40}
41
42impl_decodable_for_uint!(u8, 8);
43impl_decodable_for_uint!(u16, 16);
44impl_decodable_for_uint!(u32, 32);
45impl_decodable_for_uint!(u64, 64);
46impl_decodable_for_uint!(u128, 128);
47
48#[cfg(target_pointer_width = "32")]
49impl_decodable_for_uint!(usize, 32);
50
51#[cfg(target_pointer_width = "64")]
52impl_decodable_for_uint!(usize, 64);
53
54macro_rules! impl_decode_for_tuples {
55    ($(
56        $Tuple:ident {
57            $(($idx:tt) -> $T:ident)+
58        }
59    )+) => {
60        $(
61            impl<$($T: Decode),+> Decode for ($($T,)+) {
62                fn is_ssz_fixed_len() -> bool {
63                    $(
64                        <$T as Decode>::is_ssz_fixed_len() &&
65                    )*
66                        true
67                }
68
69                fn ssz_fixed_len() -> usize {
70                    if <Self as Decode>::is_ssz_fixed_len() {
71                        $(
72                            <$T as Decode>::ssz_fixed_len() +
73                        )*
74                            0
75                    } else {
76                        BYTES_PER_LENGTH_OFFSET
77                    }
78                }
79
80                fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
81                    let mut builder = SszDecoderBuilder::new(bytes);
82
83                    $(
84                        builder.register_type::<$T>()?;
85                    )*
86
87                    let mut decoder = builder.build()?;
88
89                    Ok(($(
90                            decoder.decode_next::<$T>()?,
91                        )*
92                    ))
93                }
94            }
95        )+
96    }
97}
98
99impl_decode_for_tuples! {
100    Tuple2 {
101        (0) -> A
102        (1) -> B
103    }
104    Tuple3 {
105        (0) -> A
106        (1) -> B
107        (2) -> C
108    }
109    Tuple4 {
110        (0) -> A
111        (1) -> B
112        (2) -> C
113        (3) -> D
114    }
115    Tuple5 {
116        (0) -> A
117        (1) -> B
118        (2) -> C
119        (3) -> D
120        (4) -> E
121    }
122    Tuple6 {
123        (0) -> A
124        (1) -> B
125        (2) -> C
126        (3) -> D
127        (4) -> E
128        (5) -> F
129    }
130    Tuple7 {
131        (0) -> A
132        (1) -> B
133        (2) -> C
134        (3) -> D
135        (4) -> E
136        (5) -> F
137        (6) -> G
138    }
139    Tuple8 {
140        (0) -> A
141        (1) -> B
142        (2) -> C
143        (3) -> D
144        (4) -> E
145        (5) -> F
146        (6) -> G
147        (7) -> H
148    }
149    Tuple9 {
150        (0) -> A
151        (1) -> B
152        (2) -> C
153        (3) -> D
154        (4) -> E
155        (5) -> F
156        (6) -> G
157        (7) -> H
158        (8) -> I
159    }
160    Tuple10 {
161        (0) -> A
162        (1) -> B
163        (2) -> C
164        (3) -> D
165        (4) -> E
166        (5) -> F
167        (6) -> G
168        (7) -> H
169        (8) -> I
170        (9) -> J
171    }
172    Tuple11 {
173        (0) -> A
174        (1) -> B
175        (2) -> C
176        (3) -> D
177        (4) -> E
178        (5) -> F
179        (6) -> G
180        (7) -> H
181        (8) -> I
182        (9) -> J
183        (10) -> K
184    }
185    Tuple12 {
186        (0) -> A
187        (1) -> B
188        (2) -> C
189        (3) -> D
190        (4) -> E
191        (5) -> F
192        (6) -> G
193        (7) -> H
194        (8) -> I
195        (9) -> J
196        (10) -> K
197        (11) -> L
198    }
199}
200
201impl Decode for bool {
202    fn is_ssz_fixed_len() -> bool {
203        true
204    }
205
206    fn ssz_fixed_len() -> usize {
207        1
208    }
209
210    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
211        let len = bytes.len();
212        let expected = <Self as Decode>::ssz_fixed_len();
213
214        if len != expected {
215            Err(DecodeError::InvalidByteLength { len, expected })
216        } else {
217            match bytes[0] {
218                0b0000_0000 => Ok(false),
219                0b0000_0001 => Ok(true),
220                _ => Err(DecodeError::BytesInvalid(format!(
221                    "Out-of-range for boolean: {}",
222                    bytes[0]
223                ))),
224            }
225        }
226    }
227}
228
229impl Decode for NonZeroUsize {
230    fn is_ssz_fixed_len() -> bool {
231        <usize as Decode>::is_ssz_fixed_len()
232    }
233
234    fn ssz_fixed_len() -> usize {
235        <usize as Decode>::ssz_fixed_len()
236    }
237
238    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
239        let x = usize::from_ssz_bytes(bytes)?;
240
241        if x == 0 {
242            Err(DecodeError::BytesInvalid(
243                "NonZeroUsize cannot be zero.".to_string(),
244            ))
245        } else {
246            // `unwrap` is safe here as `NonZeroUsize::new()` succeeds if `x > 0` and this path
247            // never executes when `x == 0`.
248            Ok(NonZeroUsize::new(x).unwrap())
249        }
250    }
251}
252
253impl<T: Decode> Decode for Option<T> {
254    fn is_ssz_fixed_len() -> bool {
255        false
256    }
257    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
258        let (selector, body) = split_union_bytes(bytes)?;
259        match selector.into() {
260            0u8 => {
261                if body.is_empty() {
262                    Ok(None)
263                } else {
264                    Err(DecodeError::InvalidByteLength {
265                        len: body.len(),
266                        expected: 0,
267                    })
268                }
269            }
270            1u8 => <T as Decode>::from_ssz_bytes(body).map(Option::Some),
271            other => Err(DecodeError::UnionSelectorInvalid(other)),
272        }
273    }
274}
275
276impl<T: Decode> Decode for Arc<T> {
277    fn is_ssz_fixed_len() -> bool {
278        T::is_ssz_fixed_len()
279    }
280
281    fn ssz_fixed_len() -> usize {
282        T::ssz_fixed_len()
283    }
284
285    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
286        T::from_ssz_bytes(bytes).map(Arc::new)
287    }
288}
289
290impl Decode for Address {
291    fn is_ssz_fixed_len() -> bool {
292        true
293    }
294
295    fn ssz_fixed_len() -> usize {
296        20
297    }
298
299    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
300        let len = bytes.len();
301        let expected = <Self as Decode>::ssz_fixed_len();
302
303        if len != expected {
304            Err(DecodeError::InvalidByteLength { len, expected })
305        } else {
306            Ok(Self::from_slice(bytes))
307        }
308    }
309}
310
311impl<const N: usize> Decode for FixedBytes<N> {
312    fn is_ssz_fixed_len() -> bool {
313        true
314    }
315
316    fn ssz_fixed_len() -> usize {
317        N
318    }
319
320    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
321        if bytes.len() != N {
322            return Err(DecodeError::InvalidByteLength {
323                len: bytes.len(),
324                expected: N,
325            });
326        }
327
328        let mut fixed_array = [0u8; N];
329        fixed_array.copy_from_slice(bytes);
330
331        Ok(Self(fixed_array))
332    }
333}
334
335impl Decode for Bloom {
336    fn is_ssz_fixed_len() -> bool {
337        true
338    }
339
340    fn ssz_fixed_len() -> usize {
341        256
342    }
343
344    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
345        let len = bytes.len();
346        let expected = <Self as Decode>::ssz_fixed_len();
347
348        if len != expected {
349            Err(DecodeError::InvalidByteLength { len, expected })
350        } else {
351            Ok(Self::from_slice(bytes))
352        }
353    }
354}
355
356impl Decode for U256 {
357    fn is_ssz_fixed_len() -> bool {
358        true
359    }
360
361    fn ssz_fixed_len() -> usize {
362        32
363    }
364
365    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
366        let len = bytes.len();
367        let expected = <Self as Decode>::ssz_fixed_len();
368
369        if len != expected {
370            Err(DecodeError::InvalidByteLength { len, expected })
371        } else {
372            Ok(U256::from_le_slice(bytes))
373        }
374    }
375}
376
377impl Decode for Bytes {
378    #[inline]
379    fn is_ssz_fixed_len() -> bool {
380        false
381    }
382
383    #[inline]
384    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
385        Ok(bytes.to_vec().into())
386    }
387}
388
389impl Decode for U128 {
390    fn is_ssz_fixed_len() -> bool {
391        true
392    }
393
394    fn ssz_fixed_len() -> usize {
395        16
396    }
397
398    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
399        let len = bytes.len();
400        let expected = <Self as Decode>::ssz_fixed_len();
401
402        if len != expected {
403            Err(DecodeError::InvalidByteLength { len, expected })
404        } else {
405            Ok(U128::from_le_slice(bytes))
406        }
407    }
408}
409
410impl<const N: usize> Decode for [u8; N] {
411    fn is_ssz_fixed_len() -> bool {
412        true
413    }
414
415    fn ssz_fixed_len() -> usize {
416        N
417    }
418
419    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
420        let len = bytes.len();
421        let expected = <Self as Decode>::ssz_fixed_len();
422
423        if len != expected {
424            Err(DecodeError::InvalidByteLength { len, expected })
425        } else {
426            let mut array: [u8; N] = [0; N];
427            array.copy_from_slice(bytes);
428
429            Ok(array)
430        }
431    }
432}
433
434impl<T: Decode> Decode for Vec<T> {
435    fn is_ssz_fixed_len() -> bool {
436        false
437    }
438
439    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
440        if bytes.is_empty() {
441            Ok(vec![])
442        } else if T::is_ssz_fixed_len() {
443            bytes
444                .chunks(T::ssz_fixed_len())
445                .map(T::from_ssz_bytes)
446                .collect()
447        } else {
448            decode_list_of_variable_length_items(bytes, None)
449        }
450    }
451}
452
453impl<T: Decode, const N: usize> Decode for SmallVec<[T; N]> {
454    fn is_ssz_fixed_len() -> bool {
455        false
456    }
457
458    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
459        if bytes.is_empty() {
460            Ok(SmallVec::new())
461        } else if T::is_ssz_fixed_len() {
462            bytes
463                .chunks(T::ssz_fixed_len())
464                .map(T::from_ssz_bytes)
465                .collect()
466        } else {
467            decode_list_of_variable_length_items(bytes, None)
468        }
469    }
470}
471
472impl<K, V> Decode for BTreeMap<K, V>
473where
474    K: Decode + Ord,
475    V: Decode,
476{
477    fn is_ssz_fixed_len() -> bool {
478        false
479    }
480
481    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
482        if bytes.is_empty() {
483            Ok(Self::from_iter(iter::empty()))
484        } else if <(K, V)>::is_ssz_fixed_len() {
485            bytes
486                .chunks(<(K, V)>::ssz_fixed_len())
487                .map(<(K, V)>::from_ssz_bytes)
488                .collect()
489        } else {
490            decode_list_of_variable_length_items(bytes, None)
491        }
492    }
493}
494
495impl<T> Decode for BTreeSet<T>
496where
497    T: Decode + Ord,
498{
499    fn is_ssz_fixed_len() -> bool {
500        false
501    }
502
503    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
504        if bytes.is_empty() {
505            Ok(Self::from_iter(iter::empty()))
506        } else if T::is_ssz_fixed_len() {
507            bytes
508                .chunks(T::ssz_fixed_len())
509                .map(T::from_ssz_bytes)
510                .collect()
511        } else {
512            decode_list_of_variable_length_items(bytes, None)
513        }
514    }
515}
516
517/// Decodes `bytes` as if it were a list of variable-length items.
518///
519/// The `ssz::SszDecoder` can also perform this functionality, however this function is
520/// significantly faster as it is optimized to read same-typed items whilst `ssz::SszDecoder`
521/// supports reading items of differing types.
522pub fn decode_list_of_variable_length_items<T: Decode, Container: TryFromIter<T>>(
523    bytes: &[u8],
524    max_len: Option<usize>,
525) -> Result<Container, DecodeError> {
526    if bytes.is_empty() {
527        return Container::try_from_iter(iter::empty()).map_err(|e| {
528            DecodeError::BytesInvalid(format!("Error trying to collect empty list: {:?}", e))
529        });
530    }
531
532    let first_offset = read_offset(bytes)?;
533    sanitize_offset(first_offset, None, bytes.len(), Some(first_offset))?;
534
535    if first_offset % BYTES_PER_LENGTH_OFFSET != 0 || first_offset < BYTES_PER_LENGTH_OFFSET {
536        return Err(DecodeError::InvalidListFixedBytesLen(first_offset));
537    }
538
539    let num_items = first_offset / BYTES_PER_LENGTH_OFFSET;
540
541    if max_len.is_some_and(|max| num_items > max) {
542        return Err(DecodeError::BytesInvalid(format!(
543            "Variable length list of {} items exceeds maximum of {:?}",
544            num_items, max_len
545        )));
546    }
547
548    let mut offset = first_offset;
549    process_results(
550        (1..=num_items).map(|i| {
551            let slice_option = if i == num_items {
552                bytes.get(offset..)
553            } else {
554                let start = offset;
555
556                let next_offset = read_offset(&bytes[(i * BYTES_PER_LENGTH_OFFSET)..])?;
557                offset =
558                    sanitize_offset(next_offset, Some(offset), bytes.len(), Some(first_offset))?;
559
560                bytes.get(start..offset)
561            };
562
563            let slice = slice_option.ok_or(DecodeError::OutOfBoundsByte { i: offset })?;
564            T::from_ssz_bytes(slice)
565        }),
566        |iter| iter.try_collect(),
567    )?
568    .map_err(|e| DecodeError::BytesInvalid(format!("Error collecting into container: {:?}", e)))
569}
570
571#[cfg(test)]
572mod tests {
573    use super::*;
574    use alloy_primitives::B256;
575
576    // Note: decoding of valid bytes is generally tested "indirectly" in the `/tests` dir, by
577    // encoding then decoding the element.
578
579    #[test]
580    fn invalid_u8_array_4() {
581        assert_eq!(
582            <[u8; 4]>::from_ssz_bytes(&[0; 3]),
583            Err(DecodeError::InvalidByteLength {
584                len: 3,
585                expected: 4
586            })
587        );
588
589        assert_eq!(
590            <[u8; 4]>::from_ssz_bytes(&[0; 5]),
591            Err(DecodeError::InvalidByteLength {
592                len: 5,
593                expected: 4
594            })
595        );
596    }
597
598    #[test]
599    fn invalid_bool() {
600        assert_eq!(
601            bool::from_ssz_bytes(&[0; 2]),
602            Err(DecodeError::InvalidByteLength {
603                len: 2,
604                expected: 1
605            })
606        );
607
608        assert_eq!(
609            bool::from_ssz_bytes(&[]),
610            Err(DecodeError::InvalidByteLength {
611                len: 0,
612                expected: 1
613            })
614        );
615
616        if let Err(DecodeError::BytesInvalid(_)) = bool::from_ssz_bytes(&[2]) {
617            // Success.
618        } else {
619            panic!("Did not return error on invalid bool val")
620        }
621    }
622
623    #[test]
624    fn invalid_b256() {
625        assert_eq!(
626            B256::from_ssz_bytes(&[0; 33]),
627            Err(DecodeError::InvalidByteLength {
628                len: 33,
629                expected: 32
630            })
631        );
632
633        assert_eq!(
634            B256::from_ssz_bytes(&[0; 31]),
635            Err(DecodeError::InvalidByteLength {
636                len: 31,
637                expected: 32
638            })
639        );
640    }
641
642    #[test]
643    fn empty_list() {
644        let vec: Vec<Vec<u16>> = vec![];
645        let bytes = vec.as_ssz_bytes();
646        assert!(bytes.is_empty());
647        assert_eq!(Vec::from_ssz_bytes(&bytes), Ok(vec),);
648    }
649
650    #[test]
651    fn first_length_points_backwards() {
652        assert_eq!(
653            <Vec<Vec<u16>>>::from_ssz_bytes(&[0, 0, 0, 0]),
654            Err(DecodeError::InvalidListFixedBytesLen(0))
655        );
656
657        assert_eq!(
658            <Vec<Vec<u16>>>::from_ssz_bytes(&[1, 0, 0, 0]),
659            Err(DecodeError::InvalidListFixedBytesLen(1))
660        );
661
662        assert_eq!(
663            <Vec<Vec<u16>>>::from_ssz_bytes(&[2, 0, 0, 0]),
664            Err(DecodeError::InvalidListFixedBytesLen(2))
665        );
666
667        assert_eq!(
668            <Vec<Vec<u16>>>::from_ssz_bytes(&[3, 0, 0, 0]),
669            Err(DecodeError::InvalidListFixedBytesLen(3))
670        );
671    }
672
673    #[test]
674    fn lengths_are_decreasing() {
675        assert_eq!(
676            <Vec<Vec<u16>>>::from_ssz_bytes(&[12, 0, 0, 0, 14, 0, 0, 0, 12, 0, 0, 0, 1, 0, 1, 0]),
677            Err(DecodeError::OffsetsAreDecreasing(12))
678        );
679    }
680
681    #[test]
682    fn awkward_fixed_length_portion() {
683        assert_eq!(
684            <Vec<Vec<u16>>>::from_ssz_bytes(&[10, 0, 0, 0, 10, 0, 0, 0, 0, 0]),
685            Err(DecodeError::InvalidListFixedBytesLen(10))
686        );
687    }
688
689    #[test]
690    fn length_out_of_bounds() {
691        assert_eq!(
692            <Vec<Vec<u16>>>::from_ssz_bytes(&[5, 0, 0, 0]),
693            Err(DecodeError::OffsetOutOfBounds(5))
694        );
695        assert_eq!(
696            <Vec<Vec<u16>>>::from_ssz_bytes(&[8, 0, 0, 0, 9, 0, 0, 0]),
697            Err(DecodeError::OffsetOutOfBounds(9))
698        );
699        assert_eq!(
700            <Vec<Vec<u16>>>::from_ssz_bytes(&[8, 0, 0, 0, 16, 0, 0, 0]),
701            Err(DecodeError::OffsetOutOfBounds(16))
702        );
703    }
704
705    #[test]
706    fn vec_of_vec_of_u16() {
707        assert_eq!(
708            <Vec<Vec<u16>>>::from_ssz_bytes(&[4, 0, 0, 0]),
709            Ok(vec![vec![]])
710        );
711
712        assert_eq!(
713            <Vec<u16>>::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]),
714            Ok(vec![0, 1, 2, 3])
715        );
716        assert_eq!(<u16>::from_ssz_bytes(&[16, 0]), Ok(16));
717        assert_eq!(<u16>::from_ssz_bytes(&[0, 1]), Ok(256));
718        assert_eq!(<u16>::from_ssz_bytes(&[255, 255]), Ok(65535));
719
720        assert_eq!(
721            <u16>::from_ssz_bytes(&[255]),
722            Err(DecodeError::InvalidByteLength {
723                len: 1,
724                expected: 2
725            })
726        );
727
728        assert_eq!(
729            <u16>::from_ssz_bytes(&[]),
730            Err(DecodeError::InvalidByteLength {
731                len: 0,
732                expected: 2
733            })
734        );
735
736        assert_eq!(
737            <u16>::from_ssz_bytes(&[0, 1, 2]),
738            Err(DecodeError::InvalidByteLength {
739                len: 3,
740                expected: 2
741            })
742        );
743    }
744
745    #[test]
746    fn vec_of_u16() {
747        assert_eq!(<Vec<u16>>::from_ssz_bytes(&[0, 0, 0, 0]), Ok(vec![0, 0]));
748        assert_eq!(
749            <Vec<u16>>::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]),
750            Ok(vec![0, 1, 2, 3])
751        );
752        assert_eq!(<u16>::from_ssz_bytes(&[16, 0]), Ok(16));
753        assert_eq!(<u16>::from_ssz_bytes(&[0, 1]), Ok(256));
754        assert_eq!(<u16>::from_ssz_bytes(&[255, 255]), Ok(65535));
755
756        assert_eq!(
757            <u16>::from_ssz_bytes(&[255]),
758            Err(DecodeError::InvalidByteLength {
759                len: 1,
760                expected: 2
761            })
762        );
763
764        assert_eq!(
765            <u16>::from_ssz_bytes(&[]),
766            Err(DecodeError::InvalidByteLength {
767                len: 0,
768                expected: 2
769            })
770        );
771
772        assert_eq!(
773            <u16>::from_ssz_bytes(&[0, 1, 2]),
774            Err(DecodeError::InvalidByteLength {
775                len: 3,
776                expected: 2
777            })
778        );
779    }
780
781    #[test]
782    fn u16() {
783        assert_eq!(<u16>::from_ssz_bytes(&[0, 0]), Ok(0));
784        assert_eq!(<u16>::from_ssz_bytes(&[16, 0]), Ok(16));
785        assert_eq!(<u16>::from_ssz_bytes(&[0, 1]), Ok(256));
786        assert_eq!(<u16>::from_ssz_bytes(&[255, 255]), Ok(65535));
787
788        assert_eq!(
789            <u16>::from_ssz_bytes(&[255]),
790            Err(DecodeError::InvalidByteLength {
791                len: 1,
792                expected: 2
793            })
794        );
795
796        assert_eq!(
797            <u16>::from_ssz_bytes(&[]),
798            Err(DecodeError::InvalidByteLength {
799                len: 0,
800                expected: 2
801            })
802        );
803
804        assert_eq!(
805            <u16>::from_ssz_bytes(&[0, 1, 2]),
806            Err(DecodeError::InvalidByteLength {
807                len: 3,
808                expected: 2
809            })
810        );
811    }
812
813    #[test]
814    fn tuple() {
815        assert_eq!(<(u16, u16)>::from_ssz_bytes(&[0, 0, 0, 0]), Ok((0, 0)));
816        assert_eq!(<(u16, u16)>::from_ssz_bytes(&[16, 0, 17, 0]), Ok((16, 17)));
817        assert_eq!(<(u16, u16)>::from_ssz_bytes(&[0, 1, 2, 0]), Ok((256, 2)));
818        assert_eq!(
819            <(u16, u16)>::from_ssz_bytes(&[255, 255, 0, 0]),
820            Ok((65535, 0))
821        );
822    }
823
824    #[test]
825    fn vec_of_u128_roundtrip() {
826        let values = vec![
827            vec![0u128, 55u128, u128::MAX, u128::MAX - 3],
828            vec![],
829            vec![u128::MAX],
830            vec![u32::MAX as u128],
831            vec![0, 0, 0, 0],
832            vec![0, 0, 0, 0, 0, 0],
833        ];
834        for vec in values {
835            assert_eq!(
836                Vec::<u128>::from_ssz_bytes(&vec.as_ssz_bytes()).unwrap(),
837                vec
838            );
839        }
840    }
841
842    #[test]
843    fn option_union_rejects_trailing_bytes() {
844        // Selector 0x00 for None variant, followed by a trailing byte 0xFF
845        // This should be rejected as the None variant must have an empty body.
846        let dirty_bytes: &[u8] = &[0x00, 0xFF];
847
848        assert_eq!(
849            <Option<u8>>::from_ssz_bytes(dirty_bytes),
850            Err(DecodeError::InvalidByteLength {
851                len: 1,
852                expected: 0
853            })
854        );
855
856        // Also test with multiple trailing bytes
857        let dirty_bytes_multi: &[u8] = &[0x00, 0xFF, 0xAB, 0xCD];
858
859        assert_eq!(
860            <Option<u8>>::from_ssz_bytes(dirty_bytes_multi),
861            Err(DecodeError::InvalidByteLength {
862                len: 3,
863                expected: 0
864            })
865        );
866
867        // Valid None encoding (just the selector with no body) should still work
868        let valid_none: &[u8] = &[0x00];
869        assert_eq!(<Option<u8>>::from_ssz_bytes(valid_none), Ok(None));
870
871        // Valid Some encoding should still work
872        let valid_some: &[u8] = &[0x01, 0x42];
873        assert_eq!(<Option<u8>>::from_ssz_bytes(valid_some), Ok(Some(0x42)));
874    }
875
876    #[test]
877    fn option_union_invalid_selector() {
878        assert_eq!(
879            <Option::<u8>>::from_ssz_bytes(&[0x02]),
880            Err(DecodeError::UnionSelectorInvalid(2))
881        );
882        assert_eq!(
883            <Option::<u8>>::from_ssz_bytes(&[0xff, 0x00, 0x00]),
884            Err(DecodeError::UnionSelectorInvalid(255))
885        );
886    }
887}