diff --git a/Cargo.lock b/Cargo.lock index 6c1146640..5550c83d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5411,9 +5411,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d95d0ec6457ad4d3d7fc0ad41db490b219587ed837ada87a26b28e535db15f" +checksum = "e5085cc8be65a2da9c04e9a904eccfe38eb69ecc3bc6c6485ce0f1af879f3abe" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5429,9 +5429,9 @@ dependencies = [ [[package]] name = "op-alloy-genesis" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8692a934265dd0fc68f02e2a1d644a80b76ae07dbc59552aa51d6df06953e9d" +checksum = "64f5aa1201d83af3b0ebffbfc28fdc7e772d7e44f4dea9e41c51162f84412edf" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5444,9 +5444,9 @@ dependencies = [ [[package]] name = "op-alloy-network" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f973f9e396dc53138ef89501875991bb1728ec34bbd9c0e1ab30caa5518abfa3" +checksum = "9d12eafaad5b89792de75f1344d42634dd5271945fd36256e4e5d766cf32107e" dependencies = [ "alloy-consensus", "alloy-network", @@ -5459,9 +5459,9 @@ dependencies = [ [[package]] name = "op-alloy-protocol" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cb147e6f39d34bd8284b1107bcbca2e4c14e95b5bc49e5498ca6c0068a94c2" +checksum = "2cf8c05e1b7ed20c4af6f72a54cc389225d2c6af6fcf932ef6481cfdfcb540ac" dependencies = [ "alloc-no-stdlib", "alloy-consensus", @@ -5483,9 +5483,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-jsonrpsee" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7e394ccd907c63acc8213c24ebfb1be24f184b75af89cbaa92178b11de34a8" +checksum = "3b6edd6fb56f23ab45c704ad0c598641086e07b3a55d74890acaa01226ffc3e2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -5496,9 +5496,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba1b44e2035ec04cc61762cb9b5457d0ecd29d9af631e1a1c107ef571ce2318" +checksum = "b44194f44faef3db1edd17fc8e0b1309d377c6c7a4ba74a02d78c13d5f2ed90d" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5515,9 +5515,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bcf8a51980231bbcd250a686c9ef41501c9e7aaa348ffe5808aa61dfe14151" +checksum = "c005d0a4431fbd9cd16eb0c2f67306de4245f76f311fa1628a68b79e7ea5aa0e" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8583,6 +8583,7 @@ dependencies = [ "arbitrary", "bytes", "derive_more", + "modular-bitfield", "op-alloy-consensus", "proptest", "proptest-arbitrary-interop", @@ -8590,6 +8591,7 @@ dependencies = [ "reth-codecs", "reth-primitives", "reth-primitives-traits", + "reth-zstd-compressors", "revm-primitives", "rstest", "secp256k1", diff --git a/Cargo.toml b/Cargo.toml index 3d652c590..80233cdb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -477,11 +477,11 @@ alloy-transport-ipc = { version = "0.8.0", default-features = false } alloy-transport-ws = { version = "0.8.0", default-features = false } # op -op-alloy-rpc-types = "0.8.0" -op-alloy-rpc-types-engine = "0.8.0" -op-alloy-rpc-jsonrpsee = "0.8.0" -op-alloy-network = "0.8.0" -op-alloy-consensus = "0.8.0" +op-alloy-rpc-types = "0.8.1" +op-alloy-rpc-types-engine = "0.8.1" +op-alloy-rpc-jsonrpsee = "0.8.1" +op-alloy-network = "0.8.1" +op-alloy-consensus = "0.8.1" # misc aquamarine = "0.6" diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index ed8e9686f..c3bd68def 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -16,6 +16,7 @@ workspace = true reth-primitives.workspace = true reth-primitives-traits = { workspace = true, features = ["op"] } reth-codecs = { workspace = true, optional = true, features = ["op"] } +reth-zstd-compressors = { workspace = true, optional = true } # ethereum alloy-primitives.workspace = true @@ -30,6 +31,7 @@ op-alloy-consensus.workspace = true # codec bytes = { workspace = true, optional = true } +modular-bitfield = { workspace = true, optional = true } serde = { workspace = true, optional = true } # misc @@ -59,9 +61,10 @@ std = [ "serde?/std", "bytes?/std", "derive_more/std", - "revm-primitives/std", - "secp256k1?/std", - "alloy-rlp/std", + "revm-primitives/std", + "secp256k1?/std", + "alloy-rlp/std", + "reth-zstd-compressors?/std" ] reth-codec = [ "dep:reth-codecs", @@ -74,6 +77,8 @@ reth-codec = [ "reth-codecs?/op", "reth-primitives/reth-codec", "dep:bytes", + "dep:modular-bitfield", + "dep:reth-zstd-compressors" ] serde = [ "dep:serde", diff --git a/crates/optimism/primitives/src/lib.rs b/crates/optimism/primitives/src/lib.rs index b1f029d20..2eedf2453 100644 --- a/crates/optimism/primitives/src/lib.rs +++ b/crates/optimism/primitives/src/lib.rs @@ -18,6 +18,9 @@ pub mod transaction; pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType, OpTransaction}; +mod receipt; +pub use receipt::OpReceipt; + /// Optimism primitive types. pub type OpPrimitives = reth_primitives::EthPrimitives; diff --git a/crates/optimism/primitives/src/receipt.rs b/crates/optimism/primitives/src/receipt.rs new file mode 100644 index 000000000..1c9ca4424 --- /dev/null +++ b/crates/optimism/primitives/src/receipt.rs @@ -0,0 +1,299 @@ +use alloy_consensus::{ + Eip2718EncodableReceipt, Eip658Value, Receipt, ReceiptWithBloom, RlpDecodableReceipt, + RlpEncodableReceipt, TxReceipt, Typed2718, +}; +use alloy_primitives::{Bloom, Log}; +use alloy_rlp::{BufMut, Decodable, Header}; +use op_alloy_consensus::{OpDepositReceipt, OpTxType}; +use reth_primitives_traits::InMemorySize; + +/// Typed ethereum transaction receipt. +/// Receipt containing result of transaction execution. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum OpReceipt { + /// Legacy receipt + Legacy(Receipt), + /// EIP-2930 receipt + Eip2930(Receipt), + /// EIP-1559 receipt + Eip1559(Receipt), + /// EIP-7702 receipt + Eip7702(Receipt), + /// Deposit receipt + Deposit(OpDepositReceipt), +} + +impl OpReceipt { + /// Returns [`OpTxType`] of the receipt. + pub const fn tx_type(&self) -> OpTxType { + match self { + Self::Legacy(_) => OpTxType::Legacy, + Self::Eip2930(_) => OpTxType::Eip2930, + Self::Eip1559(_) => OpTxType::Eip1559, + Self::Eip7702(_) => OpTxType::Eip7702, + Self::Deposit(_) => OpTxType::Deposit, + } + } + + /// Returns inner [`Receipt`], + pub const fn as_receipt(&self) -> &Receipt { + match self { + Self::Legacy(receipt) | + Self::Eip2930(receipt) | + Self::Eip1559(receipt) | + Self::Eip7702(receipt) => receipt, + Self::Deposit(receipt) => &receipt.inner, + } + } + + /// Returns length of RLP-encoded receipt fields with the given [`Bloom`] without an RLP header. + pub fn rlp_encoded_fields_length(&self, bloom: &Bloom) -> usize { + match self { + Self::Legacy(receipt) | + Self::Eip2930(receipt) | + Self::Eip1559(receipt) | + Self::Eip7702(receipt) => receipt.rlp_encoded_fields_length_with_bloom(bloom), + Self::Deposit(receipt) => receipt.rlp_encoded_fields_length_with_bloom(bloom), + } + } + + /// RLP-encodes receipt fields with the given [`Bloom`] without an RLP header. + pub fn rlp_encode_fields(&self, bloom: &Bloom, out: &mut dyn BufMut) { + match self { + Self::Legacy(receipt) | + Self::Eip2930(receipt) | + Self::Eip1559(receipt) | + Self::Eip7702(receipt) => receipt.rlp_encode_fields_with_bloom(bloom, out), + Self::Deposit(receipt) => receipt.rlp_encode_fields_with_bloom(bloom, out), + } + } + + /// Returns RLP header for inner encoding. + pub fn rlp_header_inner(&self, bloom: &Bloom) -> Header { + Header { list: true, payload_length: self.rlp_encoded_fields_length(bloom) } + } + + /// RLP-decodes the receipt from the provided buffer. This does not expect a type byte or + /// network header. + pub fn rlp_decode_inner( + buf: &mut &[u8], + tx_type: OpTxType, + ) -> alloy_rlp::Result> { + match tx_type { + OpTxType::Legacy => { + let ReceiptWithBloom { receipt, logs_bloom } = + RlpDecodableReceipt::rlp_decode_with_bloom(buf)?; + Ok(ReceiptWithBloom { receipt: Self::Legacy(receipt), logs_bloom }) + } + OpTxType::Eip2930 => { + let ReceiptWithBloom { receipt, logs_bloom } = + RlpDecodableReceipt::rlp_decode_with_bloom(buf)?; + Ok(ReceiptWithBloom { receipt: Self::Eip2930(receipt), logs_bloom }) + } + OpTxType::Eip1559 => { + let ReceiptWithBloom { receipt, logs_bloom } = + RlpDecodableReceipt::rlp_decode_with_bloom(buf)?; + Ok(ReceiptWithBloom { receipt: Self::Eip1559(receipt), logs_bloom }) + } + OpTxType::Eip7702 => { + let ReceiptWithBloom { receipt, logs_bloom } = + RlpDecodableReceipt::rlp_decode_with_bloom(buf)?; + Ok(ReceiptWithBloom { receipt: Self::Eip7702(receipt), logs_bloom }) + } + OpTxType::Deposit => { + let ReceiptWithBloom { receipt, logs_bloom } = + RlpDecodableReceipt::rlp_decode_with_bloom(buf)?; + Ok(ReceiptWithBloom { receipt: Self::Deposit(receipt), logs_bloom }) + } + } + } +} + +impl Eip2718EncodableReceipt for OpReceipt { + fn eip2718_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize { + !self.tx_type().is_legacy() as usize + self.rlp_header_inner(bloom).length_with_payload() + } + + fn eip2718_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) { + if !self.tx_type().is_legacy() { + out.put_u8(self.tx_type() as u8); + } + self.rlp_header_inner(bloom).encode(out); + self.rlp_encode_fields(bloom, out); + } +} + +impl RlpEncodableReceipt for OpReceipt { + fn rlp_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize { + let mut len = self.eip2718_encoded_length_with_bloom(bloom); + if !self.tx_type().is_legacy() { + len += Header { + list: false, + payload_length: self.eip2718_encoded_length_with_bloom(bloom), + } + .length(); + } + + len + } + + fn rlp_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) { + if !self.tx_type().is_legacy() { + Header { list: false, payload_length: self.eip2718_encoded_length_with_bloom(bloom) } + .encode(out); + } + self.eip2718_encode_with_bloom(bloom, out); + } +} + +impl RlpDecodableReceipt for OpReceipt { + fn rlp_decode_with_bloom(buf: &mut &[u8]) -> alloy_rlp::Result> { + let header_buf = &mut &**buf; + let header = Header::decode(header_buf)?; + + // Legacy receipt, reuse initial buffer without advancing + if header.list { + return Self::rlp_decode_inner(buf, OpTxType::Legacy) + } + + // Otherwise, advance the buffer and try decoding type flag followed by receipt + *buf = *header_buf; + + let remaining = buf.len(); + let tx_type = OpTxType::decode(buf)?; + let this = Self::rlp_decode_inner(buf, tx_type)?; + + if buf.len() + header.payload_length != remaining { + return Err(alloy_rlp::Error::UnexpectedLength); + } + + Ok(this) + } +} + +impl TxReceipt for OpReceipt { + type Log = Log; + + fn status_or_post_state(&self) -> Eip658Value { + self.as_receipt().status_or_post_state() + } + + fn status(&self) -> bool { + self.as_receipt().status() + } + + fn bloom(&self) -> Bloom { + self.as_receipt().bloom() + } + + fn cumulative_gas_used(&self) -> u128 { + self.as_receipt().cumulative_gas_used() + } + + fn logs(&self) -> &[Log] { + self.as_receipt().logs() + } +} + +impl Typed2718 for OpReceipt { + fn ty(&self) -> u8 { + self.tx_type().into() + } +} + +impl InMemorySize for OpReceipt { + fn size(&self) -> usize { + self.as_receipt().size() + } +} + +impl reth_primitives_traits::Receipt for OpReceipt {} + +#[cfg(feature = "reth-codec")] +mod compact { + use super::*; + use alloc::borrow::Cow; + use reth_codecs::Compact; + + #[derive(reth_codecs::CompactZstd)] + #[reth_zstd( + compressor = reth_zstd_compressors::RECEIPT_COMPRESSOR, + decompressor = reth_zstd_compressors::RECEIPT_DECOMPRESSOR + )] + struct CompactOpReceipt<'a> { + tx_type: OpTxType, + success: bool, + cumulative_gas_used: u64, + logs: Cow<'a, Vec>, + deposit_nonce: Option, + deposit_receipt_version: Option, + } + + impl<'a> From<&'a OpReceipt> for CompactOpReceipt<'a> { + fn from(receipt: &'a OpReceipt) -> Self { + Self { + tx_type: receipt.tx_type(), + success: receipt.status(), + cumulative_gas_used: receipt.cumulative_gas_used() as u64, + logs: Cow::Borrowed(&receipt.as_receipt().logs), + deposit_nonce: if let OpReceipt::Deposit(receipt) = receipt { + receipt.deposit_nonce + } else { + None + }, + deposit_receipt_version: if let OpReceipt::Deposit(receipt) = receipt { + receipt.deposit_receipt_version + } else { + None + }, + } + } + } + + impl From> for OpReceipt { + fn from(receipt: CompactOpReceipt<'_>) -> Self { + let CompactOpReceipt { + tx_type, + success, + cumulative_gas_used, + logs, + deposit_nonce, + deposit_receipt_version, + } = receipt; + + let inner = Receipt { + status: success.into(), + cumulative_gas_used: cumulative_gas_used as u128, + logs: logs.into_owned(), + }; + + match tx_type { + OpTxType::Legacy => Self::Legacy(inner), + OpTxType::Eip2930 => Self::Eip2930(inner), + OpTxType::Eip1559 => Self::Eip1559(inner), + OpTxType::Eip7702 => Self::Eip7702(inner), + OpTxType::Deposit => Self::Deposit(OpDepositReceipt { + inner, + deposit_nonce, + deposit_receipt_version, + }), + } + } + } + + impl Compact for OpReceipt { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + CompactOpReceipt::from(self).to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (receipt, buf) = CompactOpReceipt::from_compact(buf, len); + (receipt.into(), buf) + } + } +} diff --git a/crates/optimism/primitives/src/transaction/signed.rs b/crates/optimism/primitives/src/transaction/signed.rs index 5acf9b8a8..796a33cf3 100644 --- a/crates/optimism/primitives/src/transaction/signed.rs +++ b/crates/optimism/primitives/src/transaction/signed.rs @@ -40,7 +40,7 @@ use std::sync::OnceLock; #[derive(Debug, Clone, Eq, AsRef, Deref)] pub struct OpTransactionSigned { /// Transaction hash - #[serde(skip)] + #[cfg_attr(feature = "serde", serde(skip))] pub hash: OnceLock, /// The transaction signature values pub signature: Signature, diff --git a/crates/primitives-traits/src/size.rs b/crates/primitives-traits/src/size.rs index a1978ff37..be19ae812 100644 --- a/crates/primitives-traits/src/size.rs +++ b/crates/primitives-traits/src/size.rs @@ -1,5 +1,6 @@ use alloy_consensus::{Header, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy, TxType}; use alloy_primitives::{PrimitiveSignature as Signature, TxHash}; +use revm_primitives::Log; /// Trait for calculating a heuristic for the in-memory size of a struct. #[auto_impl::auto_impl(&, Arc, Box)] @@ -49,6 +50,25 @@ impl_in_mem_size!(Header, TxLegacy, TxEip2930, TxEip1559, TxEip7702, TxEip4844); #[cfg(feature = "op")] impl_in_mem_size_size_of!(op_alloy_consensus::OpTxType); +impl InMemorySize for alloy_consensus::Receipt { + fn size(&self) -> usize { + let Self { status, cumulative_gas_used, logs } = self; + core::mem::size_of_val(status) + + core::mem::size_of_val(cumulative_gas_used) + + logs.capacity() * core::mem::size_of::() + } +} + +#[cfg(feature = "op")] +impl InMemorySize for op_alloy_consensus::OpDepositReceipt { + fn size(&self) -> usize { + let Self { inner, deposit_nonce, deposit_receipt_version } = self; + inner.size() + + core::mem::size_of_val(deposit_nonce) + + core::mem::size_of_val(deposit_receipt_version) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index b6e7949a3..d4c15fe85 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -21,7 +21,6 @@ pub use reth_primitives_traits::receipt::gas_spent_by_transactions; Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable, Serialize, Deserialize, )] #[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::CompactZstd))] -#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests)] #[cfg_attr(any(test, feature = "reth-codec"), reth_zstd( compressor = reth_zstd_compressors::RECEIPT_COMPRESSOR, decompressor = reth_zstd_compressors::RECEIPT_DECOMPRESSOR diff --git a/crates/storage/codecs/derive/src/compact/flags.rs b/crates/storage/codecs/derive/src/compact/flags.rs index 798c9ad53..622eba60b 100644 --- a/crates/storage/codecs/derive/src/compact/flags.rs +++ b/crates/storage/codecs/derive/src/compact/flags.rs @@ -126,7 +126,9 @@ fn build_struct_field_flags( let mut total_bits = 0; // Find out the adequate bit size for the length of each field, if applicable. - for (name, ftype, is_compact, _) in fields { + for field in fields { + let StructFieldDescriptor { name, ftype, is_compact, use_alt_impl: _, is_reference: _ } = + field; // This happens when dealing with a wrapper struct eg. Struct(pub U256). let name = if name.is_empty() { "placeholder" } else { name }; diff --git a/crates/storage/codecs/derive/src/compact/generator.rs b/crates/storage/codecs/derive/src/compact/generator.rs index a84913f59..26a1f1012 100644 --- a/crates/storage/codecs/derive/src/compact/generator.rs +++ b/crates/storage/codecs/derive/src/compact/generator.rs @@ -41,7 +41,15 @@ pub fn generate_from_to( } }; - let fn_from_compact = if has_lifetime { + let has_ref_fields = fields.iter().any(|field| { + if let FieldTypes::StructField(field) = field { + field.is_reference + } else { + false + } + }); + + let fn_from_compact = if has_ref_fields { quote! { unimplemented!("from_compact not supported with ref structs") } } else { quote! { @@ -100,7 +108,7 @@ fn generate_from_compact( ) -> TokenStream2 { let mut lines = vec![]; let mut known_types = - vec!["B256", "Address", "Bloom", "Vec", "TxHash", "BlockHash", "FixedBytes"]; + vec!["B256", "Address", "Bloom", "Vec", "TxHash", "BlockHash", "FixedBytes", "Cow"]; // Only types without `Bytes` should be added here. It's currently manually added, since // it's hard to figure out with derive_macro which types have Bytes fields. @@ -132,8 +140,8 @@ fn generate_from_compact( }); } else { let fields = fields.iter().filter_map(|field| { - if let FieldTypes::StructField((name, _, _, _)) = field { - let ident = format_ident!("{name}"); + if let FieldTypes::StructField(field) = field { + let ident = format_ident!("{}", field.name); return Some(quote! { #ident: #ident, }) diff --git a/crates/storage/codecs/derive/src/compact/mod.rs b/crates/storage/codecs/derive/src/compact/mod.rs index ab9ed78e1..e7906bbdb 100644 --- a/crates/storage/codecs/derive/src/compact/mod.rs +++ b/crates/storage/codecs/derive/src/compact/mod.rs @@ -17,10 +17,6 @@ use structs::*; use crate::ZstdConfig; -// Helper Alias type -type IsCompact = bool; -// Helper Alias type -type FieldName = String; // Helper Alias type type FieldType = String; /// `Compact` has alternative functions that can be used as a workaround for type @@ -30,7 +26,14 @@ type FieldType = String; /// require the len of the element, while the latter one does. type UseAlternative = bool; // Helper Alias type -type StructFieldDescriptor = (FieldName, FieldType, IsCompact, UseAlternative); +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct StructFieldDescriptor { + name: String, + ftype: String, + is_compact: bool, + use_alt_impl: bool, + is_reference: bool, +} // Helper Alias type type FieldList = Vec; @@ -150,12 +153,13 @@ fn load_field_from_segments( attr.path().segments.iter().any(|path| path.ident == "maybe_zero") }); - fields.push(FieldTypes::StructField(( - field.ident.as_ref().map(|i| i.to_string()).unwrap_or_default(), + fields.push(FieldTypes::StructField(StructFieldDescriptor { + name: field.ident.as_ref().map(|i| i.to_string()).unwrap_or_default(), ftype, - should_compact, + is_compact: should_compact, use_alt_impl, - ))); + is_reference: matches!(field.ty, syn::Type::Reference(_)), + })); } } } @@ -196,7 +200,7 @@ fn should_use_alt_impl(ftype: &str, segment: &syn::PathSegment) -> bool { pub fn get_bit_size(ftype: &str) -> u8 { match ftype { "TransactionKind" | "TxKind" | "bool" | "Option" | "Signature" => 1, - "TxType" => 2, + "TxType" | "OpTxType" => 2, "u64" | "BlockNumber" | "TxNumber" | "ChainId" | "NumTransactions" => 4, "u128" => 5, "U256" => 6, diff --git a/crates/storage/codecs/derive/src/compact/structs.rs b/crates/storage/codecs/derive/src/compact/structs.rs index 07d7a3803..f8ebda334 100644 --- a/crates/storage/codecs/derive/src/compact/structs.rs +++ b/crates/storage/codecs/derive/src/compact/structs.rs @@ -44,7 +44,8 @@ impl<'a> StructHandler<'a> { /// Generates `to_compact` code for a struct field. fn to(&mut self, field_descriptor: &StructFieldDescriptor) { - let (name, ftype, is_compact, use_alt_impl) = field_descriptor; + let StructFieldDescriptor { name, ftype, is_compact, use_alt_impl, is_reference: _ } = + field_descriptor; let to_compact_ident = if *use_alt_impl { format_ident!("specialized_to_compact") @@ -97,7 +98,7 @@ impl<'a> StructHandler<'a> { /// Generates `from_compact` code for a struct field. fn from(&mut self, field_descriptor: &StructFieldDescriptor, known_types: &[&str]) { - let (name, ftype, is_compact, use_alt_impl) = field_descriptor; + let StructFieldDescriptor { name, ftype, is_compact, use_alt_impl, .. } = field_descriptor; let (name, len) = if name.is_empty() { self.is_wrapper = true; diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index 8c6ba5e4c..cf18e548b 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -25,7 +25,10 @@ use serde as _; use alloy_primitives::{Address, Bloom, Bytes, FixedBytes, U256}; use bytes::{Buf, BufMut}; -use alloc::vec::Vec; +use alloc::{ + borrow::{Cow, ToOwned}, + vec::Vec, +}; #[cfg(feature = "test-utils")] pub mod alloy; @@ -343,6 +346,32 @@ where } } +impl> Compact for Cow<'_, T> { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + self.as_ref().to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (element, buf) = T::from_compact(buf, len); + (Cow::Owned(element), buf) + } + + fn specialized_to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + self.as_ref().specialized_to_compact(buf) + } + + fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (element, buf) = T::specialized_from_compact(buf, len); + (Cow::Owned(element), buf) + } +} + impl Compact for U256 { #[inline] fn to_compact(&self, buf: &mut B) -> usize