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 InMemorySize for LogData {
82    fn size(&self) -> usize {
83        self.data.len() + core::mem::size_of_val(self.topics())
84    }
85}
86
87impl<T: InMemorySize> InMemorySize for Log<T> {
88    fn size(&self) -> usize {
89        core::mem::size_of_val(&self.address) + self.data.size()
90    }
91}
92
93impl<T: InMemorySize> InMemorySize for EthereumTxEnvelope<T> {
94    fn size(&self) -> usize {
95        match self {
96            Self::Legacy(tx) => tx.size(),
97            Self::Eip2930(tx) => tx.size(),
98            Self::Eip1559(tx) => tx.size(),
99            Self::Eip4844(tx) => tx.size(),
100            Self::Eip7702(tx) => tx.size(),
101        }
102    }
103}
104
105impl<T: InMemorySize, H: InMemorySize> InMemorySize for alloy_consensus::BlockBody<T, H> {
106    /// Calculates a heuristic for the in-memory size of the block body
107    #[inline]
108    fn size(&self) -> usize {
109        self.transactions.iter().map(T::size).sum::<usize>() +
110            self.ommers.iter().map(H::size).sum::<usize>() +
111            self.withdrawals
112                .as_ref()
113                .map_or(core::mem::size_of::<Option<Withdrawals>>(), Withdrawals::total_size)
114    }
115}
116
117impl<T: InMemorySize, H: InMemorySize> InMemorySize for alloy_consensus::Block<T, H> {
118    #[inline]
119    fn size(&self) -> usize {
120        self.header.size() + self.body.size()
121    }
122}
123
124impl<T: InMemorySize> InMemorySize for Vec<T> {
125    fn size(&self) -> usize {
126        // Note: This does not track additional capacity
127        self.iter().map(T::size).sum::<usize>()
128    }
129}
130
131impl InMemorySize for u64 {
132    fn size(&self) -> usize {
133        core::mem::size_of::<Self>()
134    }
135}
136
137/// Implementation for optimism types
138#[cfg(feature = "op")]
139mod op {
140    use super::*;
141
142    impl InMemorySize for op_alloy_consensus::OpDepositReceipt {
143        fn size(&self) -> usize {
144            let Self { inner, deposit_nonce, deposit_receipt_version } = self;
145            inner.size() +
146                core::mem::size_of_val(deposit_nonce) +
147                core::mem::size_of_val(deposit_receipt_version)
148        }
149    }
150
151    impl InMemorySize for op_alloy_consensus::OpTypedTransaction {
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::Eip7702(tx) => tx.size(),
158                Self::Deposit(tx) => tx.size(),
159            }
160        }
161    }
162
163    impl InMemorySize for op_alloy_consensus::OpPooledTransaction {
164        fn size(&self) -> usize {
165            match self {
166                Self::Legacy(tx) => tx.size(),
167                Self::Eip2930(tx) => tx.size(),
168                Self::Eip1559(tx) => tx.size(),
169                Self::Eip7702(tx) => tx.size(),
170            }
171        }
172    }
173
174    impl InMemorySize for op_alloy_consensus::OpTxEnvelope {
175        fn size(&self) -> usize {
176            match self {
177                Self::Legacy(tx) => tx.size(),
178                Self::Eip2930(tx) => tx.size(),
179                Self::Eip1559(tx) => tx.size(),
180                Self::Eip7702(tx) => tx.size(),
181                Self::Deposit(tx) => tx.size(),
182            }
183        }
184    }
185}
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    // ensures we don't have any recursion in the `InMemorySize` impls
191    #[test]
192    fn no_in_memory_no_recursion() {
193        fn assert_no_recursion<T: InMemorySize + Default>() {
194            let _ = T::default().size();
195        }
196        assert_no_recursion::<Header>();
197        assert_no_recursion::<TxLegacy>();
198        assert_no_recursion::<TxEip2930>();
199        assert_no_recursion::<TxEip1559>();
200        assert_no_recursion::<TxEip7702>();
201        assert_no_recursion::<TxEip4844>();
202    }
203}