From ac5976ff51251d59d726517278e7555c57a7c7d6 Mon Sep 17 00:00:00 2001 From: Krishang Shah <93703995+kamuik16@users.noreply.github.com> Date: Fri, 15 Nov 2024 21:35:19 +0530 Subject: [PATCH] feat: implement Compact for OpTxType (#12537) --- Cargo.lock | 3 + crates/optimism/primitives/Cargo.toml | 12 ++- crates/optimism/primitives/src/tx_type.rs | 93 ++++++++++++++++++++ crates/primitives/src/transaction/mod.rs | 2 +- crates/primitives/src/transaction/tx_type.rs | 8 +- 5 files changed, 112 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ccf3cdab..ace45858d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8381,7 +8381,10 @@ dependencies = [ "bytes", "derive_more 1.0.0", "op-alloy-consensus", + "reth-codecs", + "reth-primitives", "reth-primitives-traits", + "rstest", ] [[package]] diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index 48f587718..216e559a2 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -19,4 +19,14 @@ alloy-eips.workspace = true alloy-rlp.workspace = true derive_more.workspace = true bytes.workspace = true -reth-primitives-traits.workspace = true \ No newline at end of file +reth-primitives-traits.workspace = true +reth-codecs = { workspace = true, optional = true } +reth-primitives = { workspace = true, features = ["reth-codec"], optional = true } + +[features] +default = ["reth-codec"] +reth-codec = ["dep:reth-codecs", "dep:reth-primitives"] + +[dev-dependencies] +reth-codecs = { workspace = true, features = ["test-utils"] } +rstest.workspace = true \ No newline at end of file diff --git a/crates/optimism/primitives/src/tx_type.rs b/crates/optimism/primitives/src/tx_type.rs index 8536d3525..1b5059201 100644 --- a/crates/optimism/primitives/src/tx_type.rs +++ b/crates/optimism/primitives/src/tx_type.rs @@ -15,6 +15,16 @@ use derive_more::{ use op_alloy_consensus::OpTxType as AlloyOpTxType; use reth_primitives_traits::TxType; +#[cfg(feature = "reth-codec")] +use alloy_consensus::constants::EIP7702_TX_TYPE_ID; +#[cfg(feature = "reth-codec")] +use op_alloy_consensus::DEPOSIT_TX_TYPE_ID; +#[cfg(feature = "reth-codec")] +use reth_primitives::transaction::{ + COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, + COMPACT_IDENTIFIER_LEGACY, +}; + /// Wrapper type for `AlloyOpTxType` to implement `TxType` trait. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Display, Ord, Hash, From, Into)] #[into(u8)] @@ -123,10 +133,55 @@ impl Decodable for OpTxType { } } +#[cfg(any(test, feature = "reth-codec"))] +impl reth_codecs::Compact for OpTxType { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + match self.0 { + AlloyOpTxType::Legacy => COMPACT_IDENTIFIER_LEGACY, + AlloyOpTxType::Eip2930 => COMPACT_IDENTIFIER_EIP2930, + AlloyOpTxType::Eip1559 => COMPACT_IDENTIFIER_EIP1559, + AlloyOpTxType::Eip7702 => { + buf.put_u8(EIP7702_TX_TYPE_ID); + COMPACT_EXTENDED_IDENTIFIER_FLAG + } + AlloyOpTxType::Deposit => { + buf.put_u8(DEPOSIT_TX_TYPE_ID); + COMPACT_EXTENDED_IDENTIFIER_FLAG + } + } + } + + fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) { + use bytes::Buf; + ( + match identifier { + COMPACT_IDENTIFIER_LEGACY => Self(AlloyOpTxType::Legacy), + COMPACT_IDENTIFIER_EIP2930 => Self(AlloyOpTxType::Eip2930), + COMPACT_IDENTIFIER_EIP1559 => Self(AlloyOpTxType::Eip1559), + COMPACT_EXTENDED_IDENTIFIER_FLAG => { + let extended_identifier = buf.get_u8(); + match extended_identifier { + EIP7702_TX_TYPE_ID => Self(AlloyOpTxType::Eip7702), + DEPOSIT_TX_TYPE_ID => Self(AlloyOpTxType::Deposit), + _ => panic!("Unsupported OpTxType identifier: {extended_identifier}"), + } + } + _ => panic!("Unknown identifier for OpTxType: {identifier}"), + }, + buf, + ) + } +} + #[cfg(test)] mod tests { use super::*; use bytes::BytesMut; + use reth_codecs::Compact; + use rstest::rstest; #[test] fn test_from_alloy_op_tx_type() { @@ -215,4 +270,42 @@ mod tests { let result = OpTxType::decode(&mut buf); assert!(result.is_err()); } + + #[rstest] + #[case(OpTxType(AlloyOpTxType::Legacy), COMPACT_IDENTIFIER_LEGACY, vec![])] + #[case(OpTxType(AlloyOpTxType::Eip2930), COMPACT_IDENTIFIER_EIP2930, vec![])] + #[case(OpTxType(AlloyOpTxType::Eip1559), COMPACT_IDENTIFIER_EIP1559, vec![])] + #[case(OpTxType(AlloyOpTxType::Eip7702), COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])] + #[case(OpTxType(AlloyOpTxType::Deposit), COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![DEPOSIT_TX_TYPE_ID])] + fn test_txtype_to_compact( + #[case] tx_type: OpTxType, + #[case] expected_identifier: usize, + #[case] expected_buf: Vec, + ) { + let mut buf = vec![]; + let identifier = tx_type.to_compact(&mut buf); + + assert_eq!( + identifier, expected_identifier, + "Unexpected identifier for OpTxType {tx_type:?}", + ); + assert_eq!(buf, expected_buf, "Unexpected buffer for OpTxType {tx_type:?}",); + } + + #[rstest] + #[case(OpTxType(AlloyOpTxType::Legacy), COMPACT_IDENTIFIER_LEGACY, vec![])] + #[case(OpTxType(AlloyOpTxType::Eip2930), COMPACT_IDENTIFIER_EIP2930, vec![])] + #[case(OpTxType(AlloyOpTxType::Eip1559), COMPACT_IDENTIFIER_EIP1559, vec![])] + #[case(OpTxType(AlloyOpTxType::Eip7702), COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])] + #[case(OpTxType(AlloyOpTxType::Deposit), COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![DEPOSIT_TX_TYPE_ID])] + fn test_txtype_from_compact( + #[case] expected_type: OpTxType, + #[case] identifier: usize, + #[case] buf: Vec, + ) { + let (actual_type, remaining_buf) = OpTxType::from_compact(&buf, identifier); + + assert_eq!(actual_type, expected_type, "Unexpected TxType for identifier {identifier}"); + assert!(remaining_buf.is_empty(), "Buffer not fully consumed for identifier {identifier}"); + } } diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index e5e4517d9..f325b7277 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -62,7 +62,7 @@ use op_alloy_consensus::TxDeposit; #[cfg(feature = "optimism")] pub use tx_type::DEPOSIT_TX_TYPE_ID; #[cfg(any(test, feature = "reth-codec"))] -use tx_type::{ +pub use tx_type::{ COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, COMPACT_IDENTIFIER_LEGACY, }; diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index 66fb7df5d..3445cb184 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -9,21 +9,21 @@ use serde::{Deserialize, Serialize}; /// Identifier parameter for legacy transaction #[cfg(any(test, feature = "reth-codec"))] -pub(crate) const COMPACT_IDENTIFIER_LEGACY: usize = 0; +pub const COMPACT_IDENTIFIER_LEGACY: usize = 0; /// Identifier parameter for EIP-2930 transaction #[cfg(any(test, feature = "reth-codec"))] -pub(crate) const COMPACT_IDENTIFIER_EIP2930: usize = 1; +pub const COMPACT_IDENTIFIER_EIP2930: usize = 1; /// Identifier parameter for EIP-1559 transaction #[cfg(any(test, feature = "reth-codec"))] -pub(crate) const COMPACT_IDENTIFIER_EIP1559: usize = 2; +pub const COMPACT_IDENTIFIER_EIP1559: usize = 2; /// For backwards compatibility purposes only 2 bits of the type are encoded in the identifier /// parameter. In the case of a [`COMPACT_EXTENDED_IDENTIFIER_FLAG`], the full transaction type is /// read from the buffer as a single byte. #[cfg(any(test, feature = "reth-codec"))] -pub(crate) const COMPACT_EXTENDED_IDENTIFIER_FLAG: usize = 3; +pub const COMPACT_EXTENDED_IDENTIFIER_FLAG: usize = 3; /// Identifier for [`TxDeposit`](op_alloy_consensus::TxDeposit) transaction. #[cfg(feature = "optimism")]