revm_context/journal/
warm_addresses.rs1use bitvec::{bitvec, vec::BitVec};
6use primitives::{short_address, Address, HashMap, HashSet, StorageKey, SHORT_ADDRESS_CAP};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct WarmAddresses {
20 precompile_set: HashSet<Address>,
22 precompile_short_addresses: BitVec,
25 precompile_all_short_addresses: bool,
27 coinbase: Option<Address>,
29 access_list: HashMap<Address, HashSet<StorageKey>>,
31}
32
33impl Default for WarmAddresses {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl WarmAddresses {
40 #[inline]
42 pub fn new() -> Self {
43 Self {
44 precompile_set: HashSet::default(),
45 precompile_short_addresses: bitvec![0; SHORT_ADDRESS_CAP],
46 precompile_all_short_addresses: true,
47 coinbase: None,
48 access_list: HashMap::default(),
49 }
50 }
51
52 #[inline]
54 pub fn precompiles(&self) -> &HashSet<Address> {
55 &self.precompile_set
56 }
57
58 #[inline]
60 pub fn coinbase(&self) -> Option<Address> {
61 self.coinbase
62 }
63
64 #[inline]
66 pub fn set_precompile_addresses(&mut self, addresses: HashSet<Address>) {
67 self.precompile_short_addresses.fill(false);
68
69 let mut all_short_addresses = true;
70 for address in addresses.iter() {
71 if let Some(short_address) = short_address(address) {
72 self.precompile_short_addresses.set(short_address, true);
73 } else {
74 all_short_addresses = false;
75 }
76 }
77
78 self.precompile_all_short_addresses = all_short_addresses;
79 self.precompile_set = addresses;
80 }
81
82 #[inline]
84 pub fn set_coinbase(&mut self, address: Address) {
85 self.coinbase = Some(address);
86 }
87
88 #[inline]
90 pub fn set_access_list(&mut self, access_list: HashMap<Address, HashSet<StorageKey>>) {
91 self.access_list = access_list;
92 }
93
94 #[inline]
96 pub fn clear_coinbase(&mut self) {
97 self.coinbase = None;
98 }
99
100 #[inline]
102 pub fn clear_coinbase_and_access_list(&mut self) {
103 self.coinbase = None;
104 self.access_list.clear();
105 }
106
107 #[inline]
109 pub fn is_warm(&self, address: &Address) -> bool {
110 if Some(*address) == self.coinbase {
112 return true;
113 }
114
115 if self.access_list.contains_key(address) {
117 return true;
118 }
119
120 if self.precompile_set.is_empty() {
122 return false;
123 }
124
125 if let Some(short_address) = short_address(address) {
127 return self.precompile_short_addresses[short_address];
128 }
129
130 if !self.precompile_all_short_addresses {
131 return self.precompile_set.contains(address);
133 }
134
135 false
136 }
137
138 #[inline]
140 pub fn is_storage_warm(&self, address: &Address, key: &StorageKey) -> bool {
141 if let Some(access_list) = self.access_list.get(address) {
142 return access_list.contains(key);
143 }
144
145 false
146 }
147
148 #[inline]
150 pub fn is_cold(&self, address: &Address) -> bool {
151 !self.is_warm(address)
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use primitives::{address, Address};
159
160 #[test]
161 fn test_initialization() {
162 let warm_addresses = WarmAddresses::new();
163 assert!(warm_addresses.precompile_set.is_empty());
164 assert_eq!(
165 warm_addresses.precompile_short_addresses.len(),
166 SHORT_ADDRESS_CAP
167 );
168 assert!(!warm_addresses.precompile_short_addresses.any());
169 assert!(warm_addresses.coinbase.is_none());
170
171 let default_addresses = WarmAddresses::default();
173 assert_eq!(warm_addresses, default_addresses);
174 }
175
176 #[test]
177 fn test_coinbase_management() {
178 let mut warm_addresses = WarmAddresses::new();
179 let coinbase_addr = address!("1234567890123456789012345678901234567890");
180
181 warm_addresses.set_coinbase(coinbase_addr);
183 assert_eq!(warm_addresses.coinbase, Some(coinbase_addr));
184 assert!(warm_addresses.is_warm(&coinbase_addr));
185
186 warm_addresses.clear_coinbase_and_access_list();
188 assert!(warm_addresses.coinbase.is_none());
189 assert!(!warm_addresses.is_warm(&coinbase_addr));
190 }
191
192 #[test]
193 fn test_short_address_precompiles() {
194 let mut warm_addresses = WarmAddresses::new();
195
196 let mut bytes1 = [0u8; 20];
198 bytes1[19] = 1u8;
199 let short_addr1 = Address::from(bytes1);
200
201 let mut bytes2 = [0u8; 20];
202 bytes2[19] = 5u8;
203 let short_addr2 = Address::from(bytes2);
204
205 let mut precompiles = HashSet::default();
206 precompiles.insert(short_addr1);
207 precompiles.insert(short_addr2);
208
209 warm_addresses.set_precompile_addresses(precompiles.clone());
210
211 assert_eq!(warm_addresses.precompile_set, precompiles);
213 assert_eq!(
214 warm_addresses.precompile_short_addresses.len(),
215 SHORT_ADDRESS_CAP
216 );
217
218 assert!(warm_addresses.precompile_short_addresses[1]);
220 assert!(warm_addresses.precompile_short_addresses[5]);
221 assert!(!warm_addresses.precompile_short_addresses[0]);
222
223 assert!(warm_addresses.is_warm(&short_addr1));
225 assert!(warm_addresses.is_warm(&short_addr2));
226
227 let mut other_bytes = [0u8; 20];
229 other_bytes[19] = 20u8;
230 let other_short_addr = Address::from(other_bytes);
231 assert!(!warm_addresses.is_warm(&other_short_addr));
232 }
233
234 #[test]
235 fn test_regular_address_precompiles() {
236 let mut warm_addresses = WarmAddresses::new();
237
238 let regular_addr = address!("1234567890123456789012345678901234567890");
240 let mut bytes = [0u8; 20];
241 bytes[18] = 1u8;
242 bytes[19] = 44u8; let boundary_addr = Address::from(bytes);
244
245 let mut precompiles = HashSet::default();
246 precompiles.insert(regular_addr);
247 precompiles.insert(boundary_addr);
248
249 warm_addresses.set_precompile_addresses(precompiles.clone());
250
251 assert_eq!(warm_addresses.precompile_set, precompiles);
253 assert!(!warm_addresses.precompile_short_addresses.any());
254
255 assert!(warm_addresses.is_warm(®ular_addr));
257 assert!(warm_addresses.is_warm(&boundary_addr));
258
259 let other_addr = address!("0987654321098765432109876543210987654321");
261 assert!(!warm_addresses.is_warm(&other_addr));
262 }
263
264 #[test]
265 fn test_mixed_address_types() {
266 let mut warm_addresses = WarmAddresses::new();
267
268 let mut short_bytes = [0u8; 20];
269 short_bytes[19] = 7u8;
270 let short_addr = Address::from(short_bytes);
271 let regular_addr = address!("1234567890123456789012345678901234567890");
272
273 let mut precompiles = HashSet::default();
274 precompiles.insert(short_addr);
275 precompiles.insert(regular_addr);
276
277 warm_addresses.set_precompile_addresses(precompiles);
278
279 assert!(warm_addresses.is_warm(&short_addr));
281 assert!(warm_addresses.is_warm(®ular_addr));
282
283 assert!(warm_addresses.precompile_short_addresses[7]);
285 assert!(!warm_addresses.precompile_short_addresses[8]);
286 }
287
288 #[test]
289 fn test_short_address_boundary() {
290 let mut warm_addresses = WarmAddresses::new();
291
292 let mut boundary_bytes = [0u8; 20];
294 let boundary_val = (SHORT_ADDRESS_CAP - 1) as u16;
295 boundary_bytes[18] = (boundary_val >> 8) as u8;
296 boundary_bytes[19] = boundary_val as u8;
297 let boundary_addr = Address::from(boundary_bytes);
298
299 let mut precompiles = HashSet::default();
300 precompiles.insert(boundary_addr);
301
302 warm_addresses.set_precompile_addresses(precompiles);
303
304 assert!(warm_addresses.is_warm(&boundary_addr));
305 assert!(warm_addresses.precompile_short_addresses[SHORT_ADDRESS_CAP - 1]);
306 }
307}