Skip to main content

alloy_consensus/
size.rs

1//! Trait for calculating a heuristic for the in-memory size of a struct.
2
3use crate::{
4    transaction::TxEip4844Sidecar, EthereumTxEnvelope, Header, Receipt, TxEip1559, TxEip2930,
5    TxEip4844, TxEip4844Variant, TxEip4844WithSidecar, TxEip7702, TxLegacy, TxType,
6};
7use alloc::vec::Vec;
8use alloy_eips::eip4895::Withdrawals;
9use alloy_primitives::{LogData, Signature, TxHash, B256};
10
11/// Trait for calculating a heuristic for the in-memory size of a struct.
12#[auto_impl::auto_impl(&, Arc, Box)]
13pub trait InMemorySize {
14    /// Returns a heuristic for the in-memory size of a struct.
15    fn size(&self) -> usize;
16}
17
18impl<T: InMemorySize> InMemorySize for crate::Signed<T> {
19    fn size(&self) -> usize {
20        T::size(self.tx()) + self.signature().size() + core::mem::size_of::<B256>()
21    }
22}
23
24/// Implement `InMemorySize` for a type with `size_of`
25macro_rules! impl_in_mem_size_size_of {
26    ($($ty:ty),*) => {
27        $(
28            impl InMemorySize for $ty {
29                #[inline]
30                fn size(&self) -> usize {
31                    core::mem::size_of::<Self>()
32                }
33            }
34        )*
35    };
36}
37
38impl_in_mem_size_size_of!(Signature, TxHash, TxType);
39
40/// Implement `InMemorySize` for a type with a native `size` method.
41macro_rules! impl_in_mem_size {
42    ($($ty:ty),*) => {
43        $(
44            impl InMemorySize for $ty {
45                #[inline]
46                fn size(&self) -> usize {
47                   Self::size(self)
48                }
49            }
50        )*
51    };
52}
53
54impl_in_mem_size!(Header, TxLegacy, TxEip2930, TxEip1559, TxEip7702, TxEip4844);
55
56impl<T: TxEip4844Sidecar> InMemorySize for TxEip4844Variant<T> {
57    #[inline]
58    fn size(&self) -> usize {
59        Self::size(self)
60    }
61}
62
63impl<T: TxEip4844Sidecar> InMemorySize for TxEip4844WithSidecar<T> {
64    #[inline]
65    fn size(&self) -> usize {
66        Self::size(self)
67    }
68}
69
70impl InMemorySize for Receipt {
71    fn size(&self) -> usize {
72        let Self { status, cumulative_gas_used, logs } = self;
73        core::mem::size_of_val(status)
74            + core::mem::size_of_val(cumulative_gas_used)
75            + logs.iter().map(|log| log.size()).sum::<usize>()
76    }
77}
78
79impl InMemorySize for LogData {
80    fn size(&self) -> usize {
81        self.data.len() + core::mem::size_of_val(self.topics())
82    }
83}
84
85impl<T: InMemorySize> InMemorySize for alloy_primitives::Log<T> {
86    fn size(&self) -> usize {
87        core::mem::size_of_val(&self.address) + self.data.size()
88    }
89}
90
91impl<T: InMemorySize> InMemorySize for EthereumTxEnvelope<T> {
92    fn size(&self) -> usize {
93        match self {
94            Self::Legacy(tx) => tx.size(),
95            Self::Eip2930(tx) => tx.size(),
96            Self::Eip1559(tx) => tx.size(),
97            Self::Eip4844(tx) => tx.size(),
98            Self::Eip7702(tx) => tx.size(),
99        }
100    }
101}
102
103impl<T: InMemorySize, H: InMemorySize> InMemorySize for crate::BlockBody<T, H> {
104    /// Calculates a heuristic for the in-memory size of the block body
105    #[inline]
106    fn size(&self) -> usize {
107        self.transactions.iter().map(T::size).sum::<usize>()
108            + self.ommers.iter().map(H::size).sum::<usize>()
109            + self
110                .withdrawals
111                .as_ref()
112                .map_or(core::mem::size_of::<Option<Withdrawals>>(), Withdrawals::total_size)
113    }
114}
115
116impl<T: InMemorySize, H: InMemorySize> InMemorySize for crate::Block<T, H> {
117    #[inline]
118    fn size(&self) -> usize {
119        self.header.size() + self.body.size()
120    }
121}
122
123impl<T: InMemorySize> InMemorySize for Vec<T> {
124    fn size(&self) -> usize {
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
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    // ensures we don't have any recursion in the `InMemorySize` impls
140    #[test]
141    fn no_in_memory_no_recursion() {
142        fn assert_no_recursion<T: InMemorySize + Default>() {
143            let _ = T::default().size();
144        }
145        assert_no_recursion::<Header>();
146        assert_no_recursion::<TxLegacy>();
147        assert_no_recursion::<TxEip2930>();
148        assert_no_recursion::<TxEip1559>();
149        assert_no_recursion::<TxEip7702>();
150        assert_no_recursion::<TxEip4844>();
151    }
152}