Skip to main content

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