reth_primitives_traits/
size.rs

1use alloc::vec::Vec;
2use alloy_consensus::{
3    transaction::TxEip4844Sidecar, EthereumTxEnvelope, Header, TxEip1559, TxEip2930, TxEip4844,
4    TxEip4844Variant, 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    seismic_alloy_consensus::TxSeismic
61);
62
63impl<T: TxEip4844Sidecar> InMemorySize for TxEip4844Variant<T> {
64    #[inline]
65    fn size(&self) -> usize {
66        Self::size(self)
67    }
68}
69
70impl<T: TxEip4844Sidecar> InMemorySize for TxEip4844WithSidecar<T> {
71    #[inline]
72    fn size(&self) -> usize {
73        Self::size(self)
74    }
75}
76
77#[cfg(feature = "op")]
78impl_in_mem_size_size_of!(op_alloy_consensus::OpTxType, seismic_alloy_consensus::SeismicTxType);
79
80impl InMemorySize for alloy_consensus::Receipt {
81    fn size(&self) -> usize {
82        let Self { status, cumulative_gas_used, logs } = self;
83        core::mem::size_of_val(status) +
84            core::mem::size_of_val(cumulative_gas_used) +
85            logs.capacity() * core::mem::size_of::<Log>()
86    }
87}
88
89impl<T: InMemorySize> InMemorySize for EthereumTxEnvelope<T> {
90    fn size(&self) -> usize {
91        match self {
92            Self::Legacy(tx) => tx.size(),
93            Self::Eip2930(tx) => tx.size(),
94            Self::Eip1559(tx) => tx.size(),
95            Self::Eip4844(tx) => tx.size(),
96            Self::Eip7702(tx) => tx.size(),
97        }
98    }
99}
100
101impl<T: InMemorySize, H: InMemorySize> InMemorySize for alloy_consensus::BlockBody<T, H> {
102    /// Calculates a heuristic for the in-memory size of the block body
103    #[inline]
104    fn size(&self) -> usize {
105        self.transactions.iter().map(T::size).sum::<usize>() +
106            self.transactions.capacity() * core::mem::size_of::<T>() +
107            self.ommers.iter().map(H::size).sum::<usize>() +
108            self.ommers.capacity() * core::mem::size_of::<Header>() +
109            self.withdrawals
110                .as_ref()
111                .map_or(core::mem::size_of::<Option<Withdrawals>>(), Withdrawals::total_size)
112    }
113}
114
115impl<T: InMemorySize, H: InMemorySize> InMemorySize for alloy_consensus::Block<T, H> {
116    #[inline]
117    fn size(&self) -> usize {
118        self.header.size() + self.body.size()
119    }
120}
121
122impl<T: InMemorySize> InMemorySize for Vec<T> {
123    fn size(&self) -> usize {
124        // Note: This does not track additional capacity
125        self.iter().map(T::size).sum::<usize>()
126    }
127}
128
129impl InMemorySize for u64 {
130    fn size(&self) -> usize {
131        core::mem::size_of::<Self>()
132    }
133}
134
135mod seismic {
136    use super::*;
137
138    impl InMemorySize for seismic_alloy_consensus::SeismicTypedTransaction {
139        fn size(&self) -> usize {
140            match self {
141                Self::Legacy(tx) => tx.size(),
142                Self::Eip2930(tx) => tx.size(),
143                Self::Eip1559(tx) => tx.size(),
144                Self::Eip4844(tx) => tx.size(),
145                Self::Eip7702(tx) => tx.size(),
146                Self::Seismic(tx) => tx.size(),
147            }
148        }
149    }
150
151    impl InMemorySize for seismic_alloy_consensus::SeismicTxEnvelope {
152        fn size(&self) -> usize {
153            match self {
154                Self::Legacy(tx) => tx.size(),
155                Self::Eip2930(tx) => tx.size(),
156                Self::Eip1559(tx) => tx.size(),
157                Self::Eip4844(tx) => tx.size(),
158                Self::Eip7702(tx) => tx.size(),
159                Self::Seismic(tx) => tx.size(),
160            }
161        }
162    }
163}
164
165/// Implementation for optimism types
166#[cfg(feature = "op")]
167mod op {
168    use super::*;
169
170    impl InMemorySize for op_alloy_consensus::OpDepositReceipt {
171        fn size(&self) -> usize {
172            let Self { inner, deposit_nonce, deposit_receipt_version } = self;
173            inner.size() +
174                core::mem::size_of_val(deposit_nonce) +
175                core::mem::size_of_val(deposit_receipt_version)
176        }
177    }
178
179    impl InMemorySize for op_alloy_consensus::OpTypedTransaction {
180        fn size(&self) -> usize {
181            match self {
182                Self::Legacy(tx) => tx.size(),
183                Self::Eip2930(tx) => tx.size(),
184                Self::Eip1559(tx) => tx.size(),
185                Self::Eip7702(tx) => tx.size(),
186                Self::Deposit(tx) => tx.size(),
187            }
188        }
189    }
190
191    impl InMemorySize for op_alloy_consensus::OpPooledTransaction {
192        fn size(&self) -> usize {
193            match self {
194                Self::Legacy(tx) => tx.size(),
195                Self::Eip2930(tx) => tx.size(),
196                Self::Eip1559(tx) => tx.size(),
197                Self::Eip7702(tx) => tx.size(),
198            }
199        }
200    }
201
202    impl InMemorySize for op_alloy_consensus::OpTxEnvelope {
203        fn size(&self) -> usize {
204            match self {
205                Self::Legacy(tx) => tx.size(),
206                Self::Eip2930(tx) => tx.size(),
207                Self::Eip1559(tx) => tx.size(),
208                Self::Eip7702(tx) => tx.size(),
209                Self::Deposit(tx) => tx.size(),
210            }
211        }
212    }
213}
214#[cfg(test)]
215mod tests {
216    use super::*;
217
218    // ensures we don't have any recursion in the `InMemorySize` impls
219    #[test]
220    fn no_in_memory_no_recursion() {
221        fn assert_no_recursion<T: InMemorySize + Default>() {
222            let _ = T::default().size();
223        }
224        assert_no_recursion::<Header>();
225        assert_no_recursion::<TxLegacy>();
226        assert_no_recursion::<TxEip2930>();
227        assert_no_recursion::<TxEip1559>();
228        assert_no_recursion::<TxEip7702>();
229        assert_no_recursion::<TxEip4844>();
230    }
231}