reth_codecs/alloy/transaction/
txtype.rs

1//! Compact implementation for [`TxType`]
2
3use crate::txtype::{
4    COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
5    COMPACT_IDENTIFIER_LEGACY,
6};
7use alloy_consensus::{constants::*, TxType};
8
9impl crate::Compact for TxType {
10    fn to_compact<B>(&self, buf: &mut B) -> usize
11    where
12        B: bytes::BufMut + AsMut<[u8]>,
13    {
14        use crate::txtype::*;
15
16        match self {
17            Self::Legacy => COMPACT_IDENTIFIER_LEGACY,
18            Self::Eip2930 => COMPACT_IDENTIFIER_EIP2930,
19            Self::Eip1559 => COMPACT_IDENTIFIER_EIP1559,
20            Self::Eip4844 => {
21                buf.put_u8(EIP4844_TX_TYPE_ID);
22                COMPACT_EXTENDED_IDENTIFIER_FLAG
23            }
24            Self::Eip7702 => {
25                buf.put_u8(EIP7702_TX_TYPE_ID);
26                COMPACT_EXTENDED_IDENTIFIER_FLAG
27            }
28        }
29    }
30
31    // For backwards compatibility purposes only 2 bits of the type are encoded in the identifier
32    // parameter. In the case of a [`COMPACT_EXTENDED_IDENTIFIER_FLAG`], the full transaction type
33    // is read from the buffer as a single byte.
34    fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
35        use bytes::Buf;
36        (
37            match identifier {
38                COMPACT_IDENTIFIER_LEGACY => Self::Legacy,
39                COMPACT_IDENTIFIER_EIP2930 => Self::Eip2930,
40                COMPACT_IDENTIFIER_EIP1559 => Self::Eip1559,
41                COMPACT_EXTENDED_IDENTIFIER_FLAG => {
42                    let extended_identifier = buf.get_u8();
43                    match extended_identifier {
44                        EIP4844_TX_TYPE_ID => Self::Eip4844,
45                        EIP7702_TX_TYPE_ID => Self::Eip7702,
46                        _ => panic!("Unsupported TxType identifier: {extended_identifier}"),
47                    }
48                }
49                _ => panic!("Unknown identifier for TxType: {identifier}"),
50            },
51            buf,
52        )
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use rstest::rstest;
60
61    use crate::Compact;
62    use alloy_consensus::constants::{EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID};
63
64    #[rstest]
65    #[case(TxType::Legacy, COMPACT_IDENTIFIER_LEGACY, vec![])]
66    #[case(TxType::Eip2930, COMPACT_IDENTIFIER_EIP2930, vec![])]
67    #[case(TxType::Eip1559, COMPACT_IDENTIFIER_EIP1559, vec![])]
68    #[case(TxType::Eip4844, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP4844_TX_TYPE_ID])]
69    #[case(TxType::Eip7702, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])]
70    fn test_txtype_to_compact(
71        #[case] tx_type: TxType,
72        #[case] expected_identifier: usize,
73        #[case] expected_buf: Vec<u8>,
74    ) {
75        let mut buf = vec![];
76        let identifier = tx_type.to_compact(&mut buf);
77
78        assert_eq!(identifier, expected_identifier, "Unexpected identifier for TxType {tx_type:?}",);
79        assert_eq!(buf, expected_buf, "Unexpected buffer for TxType {tx_type:?}",);
80    }
81
82    #[rstest]
83    #[case(TxType::Legacy, COMPACT_IDENTIFIER_LEGACY, vec![])]
84    #[case(TxType::Eip2930, COMPACT_IDENTIFIER_EIP2930, vec![])]
85    #[case(TxType::Eip1559, COMPACT_IDENTIFIER_EIP1559, vec![])]
86    #[case(TxType::Eip4844, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP4844_TX_TYPE_ID])]
87    #[case(TxType::Eip7702, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])]
88    fn test_txtype_from_compact(
89        #[case] expected_type: TxType,
90        #[case] identifier: usize,
91        #[case] buf: Vec<u8>,
92    ) {
93        let (actual_type, remaining_buf) = TxType::from_compact(&buf, identifier);
94
95        assert_eq!(actual_type, expected_type, "Unexpected TxType for identifier {identifier}");
96        assert!(remaining_buf.is_empty(), "Buffer not fully consumed for identifier {identifier}");
97    }
98}