reth_primitives_traits/
size.rs

1use alloc::vec::Vec;
2use alloy_consensus::{
3    EthereumTxEnvelope, Header, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant,
4    TxEip4844WithSidecar, TxEip7702, TxLegacy, TxType,
5};
6use alloy_eips::eip4895::Withdrawals;
7use alloy_primitives::{Signature, TxHash, B256};
8use revm_primitives::Log;
9
10/// Trait for calculating a heuristic for the in-memory size of a struct.
11#[auto_impl::auto_impl(&, Arc, Box)]
12pub trait InMemorySize {
13    /// Returns a heuristic for the in-memory size of a struct.
14    fn size(&self) -> usize;
15}
16
17impl<T: InMemorySize> InMemorySize for alloy_consensus::Signed<T> {
18    fn size(&self) -> usize {
19        T::size(self.tx()) + self.signature().size() + core::mem::size_of::<B256>()
20    }
21}
22
23/// Implement `InMemorySize` for a type with `size_of`
24macro_rules! impl_in_mem_size_size_of {
25    ($($ty:ty),*) => {
26        $(
27            impl InMemorySize for $ty {
28                #[inline]
29                fn size(&self) -> usize {
30                    core::mem::size_of::<Self>()
31                }
32            }
33        )*
34    };
35}
36
37impl_in_mem_size_size_of!(Signature, TxHash, TxType);
38
39/// Implement `InMemorySize` for a type with a native `size` method.
40macro_rules! impl_in_mem_size {
41    ($($ty:ty),*) => {
42        $(
43            impl InMemorySize for $ty {
44                #[inline]
45                fn size(&self) -> usize {
46                   Self::size(self)
47                }
48            }
49        )*
50    };
51}
52
53impl_in_mem_size!(
54    Header,
55    TxLegacy,
56    TxEip2930,
57    TxEip1559,
58    TxEip7702,
59    TxEip4844,
60    TxEip4844Variant,
61    TxEip4844WithSidecar
62);
63
64#[cfg(feature = "op")]
65impl_in_mem_size_size_of!(op_alloy_consensus::OpTxType);
66
67impl InMemorySize for alloy_consensus::Receipt {
68    fn size(&self) -> usize {
69        let Self { status, cumulative_gas_used, logs } = self;
70        core::mem::size_of_val(status) +
71            core::mem::size_of_val(cumulative_gas_used) +
72            logs.capacity() * core::mem::size_of::<Log>()
73    }
74}
75
76impl<T: InMemorySize> InMemorySize for EthereumTxEnvelope<T> {
77    fn size(&self) -> usize {
78        match self {
79            Self::Legacy(tx) => tx.size(),
80            Self::Eip2930(tx) => tx.size(),
81            Self::Eip1559(tx) => tx.size(),
82            Self::Eip4844(tx) => tx.size(),
83            Self::Eip7702(tx) => tx.size(),
84        }
85    }
86}
87
88impl<T: InMemorySize, H: InMemorySize> InMemorySize for alloy_consensus::BlockBody<T, H> {
89    /// Calculates a heuristic for the in-memory size of the block body
90    #[inline]
91    fn size(&self) -> usize {
92        self.transactions.iter().map(T::size).sum::<usize>() +
93            self.transactions.capacity() * core::mem::size_of::<T>() +
94            self.ommers.iter().map(H::size).sum::<usize>() +
95            self.ommers.capacity() * core::mem::size_of::<Header>() +
96            self.withdrawals
97                .as_ref()
98                .map_or(core::mem::size_of::<Option<Withdrawals>>(), Withdrawals::total_size)
99    }
100}
101
102impl<T: InMemorySize, H: InMemorySize> InMemorySize for alloy_consensus::Block<T, H> {
103    #[inline]
104    fn size(&self) -> usize {
105        self.header.size() + self.body.size()
106    }
107}
108
109impl<T: InMemorySize> InMemorySize for Vec<T> {
110    fn size(&self) -> usize {
111        // Note: This does not track additional capacity
112        self.iter().map(T::size).sum::<usize>()
113    }
114}
115
116impl InMemorySize for u64 {
117    fn size(&self) -> usize {
118        core::mem::size_of::<Self>()
119    }
120}
121
122/// Implementation for optimism types
123#[cfg(feature = "op")]
124mod op {
125    use super::*;
126
127    impl InMemorySize for op_alloy_consensus::OpDepositReceipt {
128        fn size(&self) -> usize {
129            let Self { inner, deposit_nonce, deposit_receipt_version } = self;
130            inner.size() +
131                core::mem::size_of_val(deposit_nonce) +
132                core::mem::size_of_val(deposit_receipt_version)
133        }
134    }
135
136    impl InMemorySize for op_alloy_consensus::OpTypedTransaction {
137        fn size(&self) -> usize {
138            match self {
139                Self::Legacy(tx) => tx.size(),
140                Self::Eip2930(tx) => tx.size(),
141                Self::Eip1559(tx) => tx.size(),
142                Self::Eip7702(tx) => tx.size(),
143                Self::Deposit(tx) => tx.size(),
144            }
145        }
146    }
147
148    impl InMemorySize for op_alloy_consensus::OpPooledTransaction {
149        fn size(&self) -> usize {
150            match self {
151                Self::Legacy(tx) => tx.size(),
152                Self::Eip2930(tx) => tx.size(),
153                Self::Eip1559(tx) => tx.size(),
154                Self::Eip7702(tx) => tx.size(),
155            }
156        }
157    }
158
159    impl InMemorySize for op_alloy_consensus::OpTxEnvelope {
160        fn size(&self) -> usize {
161            match self {
162                Self::Legacy(tx) => tx.size(),
163                Self::Eip2930(tx) => tx.size(),
164                Self::Eip1559(tx) => tx.size(),
165                Self::Eip7702(tx) => tx.size(),
166                Self::Deposit(tx) => tx.size(),
167            }
168        }
169    }
170}
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    // ensures we don't have any recursion in the `InMemorySize` impls
176    #[test]
177    fn no_in_memory_no_recursion() {
178        fn assert_no_recursion<T: InMemorySize + Default>() {
179            let _ = T::default().size();
180        }
181        assert_no_recursion::<Header>();
182        assert_no_recursion::<TxLegacy>();
183        assert_no_recursion::<TxEip2930>();
184        assert_no_recursion::<TxEip1559>();
185        assert_no_recursion::<TxEip7702>();
186        assert_no_recursion::<TxEip4844>();
187    }
188}