diff --git a/Cargo.lock b/Cargo.lock index 60ec4502b271..65e1e32b2c85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -254,9 +254,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76a2336889f3d0624b18213239d27f4f34eb476eb35bef22f6a8cc24e0c0078" +checksum = "396c07726030fa0f9dab5da8c71ccd69d5eb74a7fe1072b7ae453a67e4fe553e" dependencies = [ "alloy-primitives 0.8.0", "alloy-serde", @@ -756,9 +756,9 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd491aade72a82d51db430379f48a44a1d388ff03711a2023f1faa302c5b675d" +checksum = "398a977d774db13446b8cead8cfa9517aebf9e03fc8a1512892dc1e03e70bb04" dependencies = [ "alloy-primitives 0.8.0", "alloy-rlp", @@ -1086,9 +1086,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", @@ -1632,9 +1632,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b" dependencies = [ "jobserver", "libc", @@ -3634,9 +3634,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http", @@ -3644,7 +3644,7 @@ dependencies = [ "hyper-util", "log", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", "tokio-rustls", @@ -5048,15 +5048,16 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f024d4e0aebc67d887600f90b38ef5c410bce74561995abd79bcb2a8139a52eb" +checksum = "3b7fbb0f5c3754c22c6ea30e100dca6aea73b747e693e27763e23ca92fb02f2f" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives 0.8.0", "alloy-rlp", "alloy-serde", + "arbitrary", "derive_more 1.0.0", "serde", "spin", @@ -5064,9 +5065,9 @@ dependencies = [ [[package]] name = "op-alloy-network" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90477039fba02e655363be5f034da3bbaea03404d6b3fc92cddaee278e3d64b" +checksum = "ff4d24313531c4a988f590da377491accd4a108711b44243ccd6615a3afb9c3f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5079,9 +5080,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a8514b4b8571ef7202c6ad9de623e820952c6356285d928f64d4debbacdc09" +checksum = "b1fbb93dcb71aba9cd555784375011efce1fdaaea67e01972a0a9bc9eb90c626" dependencies = [ "alloy-network", "alloy-primitives 0.8.0", @@ -5094,9 +5095,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.2.2" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620e645c36cc66220909bf97e6632e7a154a2309356221cbf33ae78bf5294478" +checksum = "14716d1b1e82ca710de448f16efb62e29b2ed999f0ea0060801fd037666fabc7" dependencies = [ "alloy-primitives 0.8.0", "alloy-rpc-types-engine", @@ -5701,9 +5702,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", @@ -5719,9 +5720,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand 0.8.5", @@ -5736,15 +5737,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5983,9 +5984,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "regress" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16fe0a24af5daaae947294213d2fd2646fbf5e1fbacc1d4ba3e84b2393854842" +checksum = "1541daf4e4ed43a0922b7969bdc2170178bcacc5dabf7e39bc508a9fa3953a7a" dependencies = [ "hashbrown 0.14.5", "memchr", @@ -6016,7 +6017,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.7.3", "rustls-pemfile", "rustls-pki-types", "serde", @@ -6450,6 +6451,7 @@ dependencies = [ "arbitrary", "bytes", "modular-bitfield", + "op-alloy-consensus", "proptest", "proptest-arbitrary-interop", "reth-codecs-derive", @@ -7947,6 +7949,7 @@ dependencies = [ "k256", "modular-bitfield", "once_cell", + "op-alloy-consensus", "op-alloy-rpc-types", "pprof", "proptest", @@ -8907,9 +8910,9 @@ dependencies = [ [[package]] name = "rlimit" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8" +checksum = "7043b63bd0cd1aaa628e476b80e6d4023a3b50eb32789f2728908107bd0c793a" dependencies = [ "libc", ] @@ -9063,6 +9066,19 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "2.1.3" @@ -9091,7 +9107,7 @@ dependencies = [ "log", "once_cell", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki", "security-framework", @@ -9759,9 +9775,9 @@ dependencies = [ [[package]] name = "symbolic-common" -version = "12.10.1" +version = "12.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1944ea8afd197111bca0c0edea1e1f56abb3edd030e240c1035cc0e3ff51fec" +checksum = "9c1db5ac243c7d7f8439eb3b8f0357888b37cf3732957e91383b0ad61756374e" dependencies = [ "debugid", "memmap2", @@ -9771,9 +9787,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.10.1" +version = "12.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddaccaf1bf8e73c4f64f78dbb30aadd6965c71faa4ff3fba33f8d7296cf94a87" +checksum = "ea26e430c27d4a8a5dea4c4b81440606c7c1a415bd611451ef6af8c81416afc3" dependencies = [ "cpp_demangle", "rustc-demangle", diff --git a/Cargo.toml b/Cargo.toml index 050f71a23c53..ba670c661118 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -449,9 +449,10 @@ alloy-transport-ipc = { version = "0.3.1", default-features = false } alloy-transport-ws = { version = "0.3.1", default-features = false } # op -op-alloy-rpc-types = "0.2.5" -op-alloy-rpc-types-engine = "0.2" -op-alloy-network = "0.2" +op-alloy-rpc-types = "0.2.8" +op-alloy-rpc-types-engine = "0.2.8" +op-alloy-network = "0.2.8" +op-alloy-consensus = "0.2.8" # misc aquamarine = "0.5" diff --git a/crates/optimism/node/src/txpool.rs b/crates/optimism/node/src/txpool.rs index bbe9ccef32aa..f4849d2d4890 100644 --- a/crates/optimism/node/src/txpool.rs +++ b/crates/optimism/node/src/txpool.rs @@ -252,7 +252,7 @@ mod tests { to: TxKind::Create, mint: None, value: U256::ZERO, - gas_limit: 0u64, + gas_limit: 0, is_system_transaction: false, input: Default::default(), }); diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 74b2a0447a92..af7e0a626e53 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -33,6 +33,7 @@ alloy-eips = { workspace = true, features = ["serde"] } # optimism op-alloy-rpc-types = { workspace = true, optional = true } +op-alloy-consensus = { workspace = true, features = ["arbitrary"], optional = true } # crypto secp256k1 = { workspace = true, features = [ @@ -105,7 +106,9 @@ optimism = [ "reth-chainspec/optimism", "reth-ethereum-forks/optimism", "revm-primitives/optimism", + "reth-codecs?/optimism", "dep:reth-optimism-chainspec", + "dep:op-alloy-consensus", ] alloy-compat = ["reth-primitives-traits/alloy-compat", "dep:alloy-rpc-types", "dep:alloy-serde", "dep:op-alloy-rpc-types"] test-utils = ["reth-primitives-traits/test-utils"] diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index ac3d0c551097..f8a05a0f6fd4 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -204,10 +204,7 @@ impl TryFrom> for Transaction { to: TxKind::from(tx.to), mint: fields.mint.filter(|n| *n != 0), value: tx.value, - gas_limit: tx - .gas - .try_into() - .map_err(|_| ConversionError::Eip2718Error(RlpError::Overflow.into()))?, + gas_limit: tx.gas, is_system_transaction: fields.is_system_tx.unwrap_or(false), input: tx.input, })) diff --git a/crates/primitives/src/transaction/compat.rs b/crates/primitives/src/transaction/compat.rs index 60c32b0da751..410d6f7c8fe0 100644 --- a/crates/primitives/src/transaction/compat.rs +++ b/crates/primitives/src/transaction/compat.rs @@ -95,7 +95,7 @@ impl FillTxEnv for TransactionSigned { #[cfg(feature = "optimism")] Transaction::Deposit(tx) => { tx_env.access_list.clear(); - tx_env.gas_limit = tx.gas_limit; + tx_env.gas_limit = tx.gas_limit as u64; tx_env.gas_price = U256::ZERO; tx_env.gas_priority_fee = None; tx_env.transact_to = tx.to; diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index a176f14bddf2..7b8e12f00ff2 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -171,7 +171,11 @@ impl<'a> arbitrary::Arbitrary<'a> for Transaction { Self::Eip7702(tx) } #[cfg(feature = "optimism")] - TxType::Deposit => Self::Deposit(TxDeposit::arbitrary(u)?), + TxType::Deposit => { + let mut tx = TxDeposit::arbitrary(u)?; + tx.gas_limit = (tx.gas_limit as u64).into(); + Self::Deposit(tx) + } }) } } @@ -250,7 +254,7 @@ impl Transaction { Self::Eip4844(_) => TxType::Eip4844, Self::Eip7702(_) => TxType::Eip7702, #[cfg(feature = "optimism")] - Self::Deposit(deposit_tx) => deposit_tx.tx_type(), + Self::Deposit(_) => TxType::Deposit, } } @@ -315,7 +319,7 @@ impl Transaction { Self::Eip7702(TxEip7702 { gas_limit, .. }) => *gas_limit as u64, Self::Eip2930(TxEip2930 { gas_limit, .. }) => *gas_limit as u64, #[cfg(feature = "optimism")] - Self::Deposit(TxDeposit { gas_limit, .. }) => *gas_limit, + Self::Deposit(TxDeposit { gas_limit, .. }) => *gas_limit as u64, } } @@ -556,7 +560,7 @@ impl Transaction { with_header, ), #[cfg(feature = "optimism")] - Self::Deposit(deposit_tx) => deposit_tx.encode(out, with_header), + Self::Deposit(deposit_tx) => deposit_tx.encode_inner(out, with_header), } } @@ -569,7 +573,7 @@ impl Transaction { Self::Eip4844(tx) => tx.gas_limit = gas_limit.into(), Self::Eip7702(tx) => tx.gas_limit = gas_limit.into(), #[cfg(feature = "optimism")] - Self::Deposit(tx) => tx.gas_limit = gas_limit, + Self::Deposit(tx) => tx.gas_limit = gas_limit.into(), } } @@ -839,7 +843,7 @@ impl Encodable for Transaction { } #[cfg(feature = "optimism")] Self::Deposit(deposit_tx) => { - deposit_tx.encode(out, true); + deposit_tx.encode_inner(out, true); } } } @@ -852,7 +856,7 @@ impl Encodable for Transaction { Self::Eip4844(blob_tx) => blob_tx.payload_len_for_signature(), Self::Eip7702(set_code_tx) => set_code_tx.payload_len_for_signature(), #[cfg(feature = "optimism")] - Self::Deposit(deposit_tx) => deposit_tx.payload_len(), + Self::Deposit(deposit_tx) => deposit_tx.encoded_len(true), } } } @@ -1243,7 +1247,7 @@ impl TransactionSigned { true, ), #[cfg(feature = "optimism")] - Transaction::Deposit(deposit_tx) => deposit_tx.payload_len(), + Transaction::Deposit(deposit_tx) => deposit_tx.encoded_len(true), } } @@ -1370,7 +1374,7 @@ impl TransactionSigned { TxType::Eip4844 => Transaction::Eip4844(TxEip4844::decode_fields(data)?), TxType::Eip7702 => Transaction::Eip7702(TxEip7702::decode_fields(data)?), #[cfg(feature = "optimism")] - TxType::Deposit => Transaction::Deposit(TxDeposit::decode_inner(data)?), + TxType::Deposit => Transaction::Deposit(TxDeposit::decode_fields(data)?), TxType::Legacy => return Err(RlpError::Custom("unexpected legacy tx type")), }; @@ -1455,7 +1459,7 @@ impl TransactionSigned { false, ), #[cfg(feature = "optimism")] - Transaction::Deposit(deposit_tx) => deposit_tx.payload_len_without_header(), + Transaction::Deposit(deposit_tx) => deposit_tx.encoded_len(false), } } } diff --git a/crates/primitives/src/transaction/optimism.rs b/crates/primitives/src/transaction/optimism.rs index d7fc652f0751..e2b187a8564b 100644 --- a/crates/primitives/src/transaction/optimism.rs +++ b/crates/primitives/src/transaction/optimism.rs @@ -1,231 +1 @@ -use crate::{Address, Bytes, TxKind, TxType, B256, U256}; -use alloy_rlp::{ - length_of_length, Decodable, Encodable, Error as DecodeError, Header, EMPTY_STRING_CODE, -}; -use bytes::Buf; -use core::mem; -#[cfg(any(test, feature = "reth-codec"))] -use reth_codecs::Compact; -use serde::{Deserialize, Serialize}; - -/// Deposit transactions, also known as deposits are initiated on L1, and executed on L2. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] -#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] -#[cfg_attr(any(test, feature = "reth-codec"), derive(Compact))] -#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))] -pub struct TxDeposit { - /// Hash that uniquely identifies the source of the deposit. - pub source_hash: B256, - /// The address of the sender account. - pub from: Address, - /// The address of the recipient account, or the null (zero-length) address if the deposited - /// transaction is a contract creation. - pub to: TxKind, - /// The ETH value to mint on L2. - pub mint: Option, - /// The ETH value to send to the recipient account. - pub value: U256, - /// The gas limit for the L2 transaction. - pub gas_limit: u64, - /// Field indicating if this transaction is exempt from the L2 gas limit. - pub is_system_transaction: bool, - /// Input has two uses depending if transaction is Create or Call (if `to` field is None or - /// Some). - pub input: Bytes, -} - -impl TxDeposit { - /// Calculates a heuristic for the in-memory size of the [`TxDeposit`] transaction. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() + // source_hash - mem::size_of::
() + // from - self.to.size() + // to - mem::size_of::>() + // mint - mem::size_of::() + // value - mem::size_of::() + // gas_limit - mem::size_of::() + // is_system_transaction - self.input.len() // input - } - - /// Decodes the inner [`TxDeposit`] fields from RLP bytes. - /// - /// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following - /// RLP fields in the following order: - /// - /// - `source_hash` - /// - `from` - /// - `to` - /// - `mint` - /// - `value` - /// - `gas_limit` - /// - `is_system_transaction` - /// - `input` - pub fn decode_inner(buf: &mut &[u8]) -> Result { - Ok(Self { - source_hash: Decodable::decode(buf)?, - from: Decodable::decode(buf)?, - to: Decodable::decode(buf)?, - mint: if *buf.first().ok_or(DecodeError::InputTooShort)? == EMPTY_STRING_CODE { - buf.advance(1); - None - } else { - Some(Decodable::decode(buf)?) - }, - value: Decodable::decode(buf)?, - gas_limit: Decodable::decode(buf)?, - is_system_transaction: Decodable::decode(buf)?, - input: Decodable::decode(buf)?, - }) - } - - /// Outputs the length of the transaction's fields, without a RLP header or length of the - /// eip155 fields. - pub(crate) fn fields_len(&self) -> usize { - self.source_hash.length() + - self.from.length() + - self.to.length() + - self.mint.map_or(1, |mint| mint.length()) + - self.value.length() + - self.gas_limit.length() + - self.is_system_transaction.length() + - self.input.0.length() - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - /// - pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) { - self.source_hash.encode(out); - self.from.encode(out); - self.to.encode(out); - if let Some(mint) = self.mint { - mint.encode(out); - } else { - out.put_u8(EMPTY_STRING_CODE); - } - self.value.encode(out); - self.gas_limit.encode(out); - self.is_system_transaction.encode(out); - self.input.encode(out); - } - - /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating - /// hash that for eip2718 does not require rlp header - pub(crate) fn encode(&self, out: &mut dyn bytes::BufMut, with_header: bool) { - let payload_length = self.fields_len(); - if with_header { - Header { - list: false, - payload_length: 1 + length_of_length(payload_length) + payload_length, - } - .encode(out); - } - out.put_u8(self.tx_type() as u8); - let header = Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - } - - /// Output the length of the RLP signed transaction encoding. This encodes with a RLP header. - pub(crate) fn payload_len(&self) -> usize { - let payload_length = self.fields_len(); - // 'tx type' + 'header length' + 'payload length' - let len = 1 + length_of_length(payload_length) + payload_length; - length_of_length(len) + len - } - - pub(crate) fn payload_len_without_header(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - /// Get the transaction type - pub(crate) const fn tx_type(&self) -> TxType { - TxType::Deposit - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{revm_primitives::hex_literal::hex, TransactionSigned}; - use bytes::BytesMut; - - #[test] - fn test_rlp_roundtrip() { - let bytes = Bytes::from_static(&hex!("7ef9015aa044bae9d41b8380d781187b426c6fe43df5fb2fb57bd4466ef6a701e1f01e015694deaddeaddeaddeaddeaddeaddeaddeaddead000194420000000000000000000000000000000000001580808408f0d18001b90104015d8eb900000000000000000000000000000000000000000000000000000000008057650000000000000000000000000000000000000000000000000000000063d96d10000000000000000000000000000000000000000000000000000000000009f35273d89754a1e0387b89520d989d3be9c37c1f32495a88faf1ea05c61121ab0d1900000000000000000000000000000000000000000000000000000000000000010000000000000000000000002d679b567db6187c0c8323fa982cfb88b74dbcc7000000000000000000000000000000000000000000000000000000000000083400000000000000000000000000000000000000000000000000000000000f4240")); - - let tx_a = TransactionSigned::decode_enveloped(&mut bytes.as_ref()).unwrap(); - let tx_b = TransactionSigned::decode(&mut &bytes[..]).unwrap(); - - let mut buf_a = BytesMut::default(); - tx_a.encode_enveloped(&mut buf_a); - assert_eq!(&buf_a[..], &bytes[..]); - - let mut buf_b = BytesMut::default(); - tx_b.encode_enveloped(&mut buf_b); - assert_eq!(&buf_b[..], &bytes[..]); - } - - #[test] - fn test_encode_decode_fields() { - let original = TxDeposit { - source_hash: B256::default(), - from: Address::default(), - to: TxKind::default(), - mint: Some(100), - value: U256::default(), - gas_limit: 50000, - is_system_transaction: true, - input: Bytes::default(), - }; - - let mut buffer = BytesMut::new(); - original.encode_fields(&mut buffer); - let decoded = TxDeposit::decode_inner(&mut &buffer[..]).expect("Failed to decode"); - - assert_eq!(original, decoded); - } - - #[test] - fn test_encode_with_and_without_header() { - let tx_deposit = TxDeposit { - source_hash: B256::default(), - from: Address::default(), - to: TxKind::default(), - mint: Some(100), - value: U256::default(), - gas_limit: 50000, - is_system_transaction: true, - input: Bytes::default(), - }; - - let mut buffer_with_header = BytesMut::new(); - tx_deposit.encode(&mut buffer_with_header, true); - - let mut buffer_without_header = BytesMut::new(); - tx_deposit.encode(&mut buffer_without_header, false); - - assert!(buffer_with_header.len() > buffer_without_header.len()); - } - - #[test] - fn test_payload_length() { - let tx_deposit = TxDeposit { - source_hash: B256::default(), - from: Address::default(), - to: TxKind::default(), - mint: Some(100), - value: U256::default(), - gas_limit: 50000, - is_system_transaction: true, - input: Bytes::default(), - }; - - let total_len = tx_deposit.payload_len(); - let len_without_header = tx_deposit.payload_len_without_header(); - - assert!(total_len > len_without_header); - } -} +pub use op_alloy_consensus::TxDeposit; diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index d1e0580000fd..1c47b442902c 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -21,6 +21,9 @@ alloy-genesis = { workspace = true, optional = true } alloy-primitives.workspace = true alloy-trie = { workspace = true, optional = true } +# optimism +op-alloy-consensus = { workspace = true, optional = true } + # misc bytes.workspace = true modular-bitfield = { workspace = true, optional = true } @@ -55,3 +58,4 @@ alloy = [ "dep:alloy-trie", "dep:serde" ] +optimism = ["alloy", "dep:op-alloy-consensus"] diff --git a/crates/storage/codecs/src/alloy/transaction/mod.rs b/crates/storage/codecs/src/alloy/transaction/mod.rs index 138ffa6c8fae..717f918fb149 100644 --- a/crates/storage/codecs/src/alloy/transaction/mod.rs +++ b/crates/storage/codecs/src/alloy/transaction/mod.rs @@ -3,6 +3,8 @@ mod eip2930; mod eip4844; mod eip7702; mod legacy; +#[cfg(feature = "optimism")] +mod optimism; #[cfg(test)] mod tests { @@ -13,7 +15,9 @@ mod tests { // this check is to ensure we do not inadvertently add too many fields to a struct which would // expand the flags field and break backwards compatibility - use super::{ + #[cfg(feature = "optimism")] + use crate::alloy::transaction::optimism::TxDeposit; + use crate::alloy::transaction::{ eip1559::TxEip1559, eip2930::TxEip2930, eip4844::TxEip4844, eip7702::TxEip7702, legacy::TxLegacy, }; @@ -26,4 +30,10 @@ mod tests { assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); assert_eq!(TxEip7702::bitflag_encoded_bytes(), 4); } + + #[cfg(feature = "optimism")] + #[test] + fn test_ensure_backwards_compatibility_optimism() { + assert_eq!(TxDeposit::bitflag_encoded_bytes(), 2); + } } diff --git a/crates/storage/codecs/src/alloy/transaction/optimism.rs b/crates/storage/codecs/src/alloy/transaction/optimism.rs new file mode 100644 index 000000000000..c84b19559fd5 --- /dev/null +++ b/crates/storage/codecs/src/alloy/transaction/optimism.rs @@ -0,0 +1,61 @@ +use crate::Compact; +use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; +use op_alloy_consensus::TxDeposit as AlloyTxDeposit; +use reth_codecs_derive::add_arbitrary_tests; +use serde::{Deserialize, Serialize}; + +/// Deposit transactions, also known as deposits are initiated on L1, and executed on L2. +/// +/// This is a helper type to use derive on it instead of manually managing `bitfield`. +/// +/// By deriving `Compact` here, any future changes or enhancements to the `Compact` derive +/// will automatically apply to this type. +/// +/// Notice: Make sure this struct is 1:1 with [`op_alloy_consensus::TxDeposit`] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize, Compact)] +#[cfg_attr(test, derive(arbitrary::Arbitrary))] +#[add_arbitrary_tests(compact)] +pub(crate) struct TxDeposit { + source_hash: B256, + from: Address, + to: TxKind, + mint: Option, + value: U256, + gas_limit: u64, + is_system_transaction: bool, + input: Bytes, +} + +impl Compact for AlloyTxDeposit { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + let tx = TxDeposit { + source_hash: self.source_hash, + from: self.from, + to: self.to, + mint: self.mint, + value: self.value, + gas_limit: self.gas_limit as u64, + is_system_transaction: self.is_system_transaction, + input: self.input.clone(), + }; + tx.to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (tx, _) = TxDeposit::from_compact(buf, len); + let alloy_tx = Self { + source_hash: tx.source_hash, + from: tx.from, + to: tx.to, + mint: tx.mint, + value: tx.value, + gas_limit: tx.gas_limit as u128, + is_system_transaction: tx.is_system_transaction, + input: tx.input, + }; + (alloy_tx, buf) + } +}