revm_context/journal/
warm_addresses.rs1use bitvec::{bitvec, vec::BitVec};
6use context_interface::journaled_state::JournalLoadError;
7use primitives::{
8 short_address, Address, AddressMap, AddressSet, HashSet, StorageKey, SHORT_ADDRESS_CAP,
9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct WarmAddresses {
23 precompile_set: AddressSet,
25 precompile_short_addresses: BitVec,
28 precompile_all_short_addresses: bool,
30 coinbase: Option<Address>,
32 access_list: AddressMap<HashSet<StorageKey>>,
34}
35
36impl Default for WarmAddresses {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42impl WarmAddresses {
43 #[inline]
45 pub fn new() -> Self {
46 Self {
47 precompile_set: AddressSet::default(),
48 precompile_short_addresses: bitvec![0; SHORT_ADDRESS_CAP],
49 precompile_all_short_addresses: true,
50 coinbase: None,
51 access_list: AddressMap::default(),
52 }
53 }
54
55 #[inline]
57 pub const fn precompiles(&self) -> &AddressSet {
58 &self.precompile_set
59 }
60
61 #[inline]
63 pub const fn coinbase(&self) -> Option<Address> {
64 self.coinbase
65 }
66
67 pub fn set_precompile_addresses(&mut self, addresses: &AddressSet) {
69 self.precompile_short_addresses.fill(false);
70
71 let mut all_short_addresses = true;
72 for address in addresses.iter() {
73 if let Some(short_address) = short_address(address) {
74 self.precompile_short_addresses.set(short_address, true);
75 } else {
76 all_short_addresses = false;
77 }
78 }
79
80 self.precompile_all_short_addresses = all_short_addresses;
81 self.precompile_set.clone_from(addresses);
82 }
83
84 #[inline]
86 pub const fn set_coinbase(&mut self, address: Address) {
87 self.coinbase = Some(address);
88 }
89
90 #[inline]
92 pub fn set_access_list(&mut self, access_list: AddressMap<HashSet<StorageKey>>) {
93 self.access_list = access_list;
94 }
95
96 #[inline]
98 pub const fn access_list(&self) -> &AddressMap<HashSet<StorageKey>> {
99 &self.access_list
100 }
101
102 #[inline]
104 pub const fn clear_coinbase(&mut self) {
105 self.coinbase = None;
106 }
107
108 #[inline]
110 pub fn clear_coinbase_and_access_list(&mut self) {
111 self.coinbase = None;
112 self.access_list.clear();
113 }
114
115 pub fn is_warm(&self, address: &Address) -> bool {
117 if Some(*address) == self.coinbase {
119 return true;
120 }
121
122 if self.access_list.contains_key(address) {
124 return true;
125 }
126
127 if self.precompile_set.is_empty() {
129 return false;
130 }
131
132 if let Some(short_address) = short_address(address) {
134 return self.precompile_short_addresses[short_address];
135 }
136
137 if !self.precompile_all_short_addresses {
138 return self.precompile_set.contains(address);
140 }
141
142 false
143 }
144
145 #[inline]
147 pub fn is_storage_warm(&self, address: &Address, key: &StorageKey) -> bool {
148 if let Some(access_list) = self.access_list.get(address) {
149 return access_list.contains(key);
150 }
151
152 false
153 }
154
155 #[inline]
157 pub fn is_cold(&self, address: &Address) -> bool {
158 !self.is_warm(address)
159 }
160
161 pub fn check_is_cold<E>(
163 &self,
164 address: &Address,
165 skip_cold_load: bool,
166 ) -> Result<bool, JournalLoadError<E>> {
167 let is_cold = self.is_cold(address);
168
169 if is_cold && skip_cold_load {
170 return Err(JournalLoadError::ColdLoadSkipped);
171 }
172
173 Ok(is_cold)
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use primitives::{address, Address};
181
182 #[test]
183 fn test_initialization() {
184 let warm_addresses = WarmAddresses::new();
185 assert!(warm_addresses.precompile_set.is_empty());
186 assert_eq!(
187 warm_addresses.precompile_short_addresses.len(),
188 SHORT_ADDRESS_CAP
189 );
190 assert!(!warm_addresses.precompile_short_addresses.any());
191 assert!(warm_addresses.coinbase.is_none());
192
193 let default_addresses = WarmAddresses::default();
195 assert_eq!(warm_addresses, default_addresses);
196 }
197
198 #[test]
199 fn test_coinbase_management() {
200 let mut warm_addresses = WarmAddresses::new();
201 let coinbase_addr = address!("1234567890123456789012345678901234567890");
202
203 warm_addresses.set_coinbase(coinbase_addr);
205 assert_eq!(warm_addresses.coinbase, Some(coinbase_addr));
206 assert!(warm_addresses.is_warm(&coinbase_addr));
207
208 warm_addresses.clear_coinbase_and_access_list();
210 assert!(warm_addresses.coinbase.is_none());
211 assert!(!warm_addresses.is_warm(&coinbase_addr));
212 }
213
214 #[test]
215 fn test_short_address_precompiles() {
216 let mut warm_addresses = WarmAddresses::new();
217
218 let mut bytes1 = [0u8; 20];
220 bytes1[19] = 1u8;
221 let short_addr1 = Address::from(bytes1);
222
223 let mut bytes2 = [0u8; 20];
224 bytes2[19] = 5u8;
225 let short_addr2 = Address::from(bytes2);
226
227 let mut precompiles = HashSet::default();
228 precompiles.insert(short_addr1);
229 precompiles.insert(short_addr2);
230
231 warm_addresses.set_precompile_addresses(&precompiles);
232
233 assert_eq!(warm_addresses.precompile_set, precompiles);
235 assert_eq!(
236 warm_addresses.precompile_short_addresses.len(),
237 SHORT_ADDRESS_CAP
238 );
239
240 assert!(warm_addresses.precompile_short_addresses[1]);
242 assert!(warm_addresses.precompile_short_addresses[5]);
243 assert!(!warm_addresses.precompile_short_addresses[0]);
244
245 assert!(warm_addresses.is_warm(&short_addr1));
247 assert!(warm_addresses.is_warm(&short_addr2));
248
249 let mut other_bytes = [0u8; 20];
251 other_bytes[19] = 20u8;
252 let other_short_addr = Address::from(other_bytes);
253 assert!(!warm_addresses.is_warm(&other_short_addr));
254 }
255
256 #[test]
257 fn test_regular_address_precompiles() {
258 let mut warm_addresses = WarmAddresses::new();
259
260 let regular_addr = address!("1234567890123456789012345678901234567890");
262 let mut bytes = [0u8; 20];
263 bytes[18] = 1u8;
264 bytes[19] = 44u8; let boundary_addr = Address::from(bytes);
266
267 let mut precompiles = HashSet::default();
268 precompiles.insert(regular_addr);
269 precompiles.insert(boundary_addr);
270
271 warm_addresses.set_precompile_addresses(&precompiles);
272
273 assert_eq!(warm_addresses.precompile_set, precompiles);
275 assert!(!warm_addresses.precompile_short_addresses.any());
276
277 assert!(warm_addresses.is_warm(®ular_addr));
279 assert!(warm_addresses.is_warm(&boundary_addr));
280
281 let other_addr = address!("0987654321098765432109876543210987654321");
283 assert!(!warm_addresses.is_warm(&other_addr));
284 }
285
286 #[test]
287 fn test_mixed_address_types() {
288 let mut warm_addresses = WarmAddresses::new();
289
290 let mut short_bytes = [0u8; 20];
291 short_bytes[19] = 7u8;
292 let short_addr = Address::from(short_bytes);
293 let regular_addr = address!("1234567890123456789012345678901234567890");
294
295 let mut precompiles = HashSet::default();
296 precompiles.insert(short_addr);
297 precompiles.insert(regular_addr);
298
299 warm_addresses.set_precompile_addresses(&precompiles);
300
301 assert!(warm_addresses.is_warm(&short_addr));
303 assert!(warm_addresses.is_warm(®ular_addr));
304
305 assert!(warm_addresses.precompile_short_addresses[7]);
307 assert!(!warm_addresses.precompile_short_addresses[8]);
308 }
309
310 #[test]
311 fn test_short_address_boundary() {
312 let mut warm_addresses = WarmAddresses::new();
313
314 let mut boundary_bytes = [0u8; 20];
316 let boundary_val = (SHORT_ADDRESS_CAP - 1) as u16;
317 boundary_bytes[18] = (boundary_val >> 8) as u8;
318 boundary_bytes[19] = boundary_val as u8;
319 let boundary_addr = Address::from(boundary_bytes);
320
321 let mut precompiles = HashSet::default();
322 precompiles.insert(boundary_addr);
323
324 warm_addresses.set_precompile_addresses(&precompiles);
325
326 assert!(warm_addresses.is_warm(&boundary_addr));
327 assert!(warm_addresses.precompile_short_addresses[SHORT_ADDRESS_CAP - 1]);
328 }
329}