revm_context/journal/
warm_addresses.rs1use bitvec::{bitvec, order::Lsb0, vec::BitVec};
6use primitives::{short_address, Address, HashSet, SHORT_ADDRESS_CAP};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct WarmAddresses {
12 precompile_set: HashSet<Address>,
14 precompile_short_addresses: BitVec,
17 all_short_addresses: bool,
19 coinbase: Option<Address>,
21}
22
23impl Default for WarmAddresses {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl WarmAddresses {
30 #[inline]
32 pub fn new() -> Self {
33 Self {
34 precompile_set: HashSet::default(),
35 precompile_short_addresses: BitVec::new(),
36 all_short_addresses: true,
37 coinbase: None,
38 }
39 }
40
41 #[inline]
43 pub fn precompiles(&self) -> &HashSet<Address> {
44 &self.precompile_set
45 }
46
47 #[inline]
49 pub fn coinbase(&self) -> Option<Address> {
50 self.coinbase
51 }
52
53 #[inline]
55 pub fn set_precompile_addresses(&mut self, addresses: HashSet<Address>) {
56 self.precompile_short_addresses = bitvec![usize, Lsb0; 0; SHORT_ADDRESS_CAP];
58
59 let mut all_short_addresses = true;
60 for address in addresses.iter() {
61 if let Some(short_address) = short_address(address) {
62 self.precompile_short_addresses.set(short_address, true);
63 } else {
64 all_short_addresses = false;
65 }
66 }
67
68 self.all_short_addresses = all_short_addresses;
69 self.precompile_set = addresses;
70 }
71
72 #[inline]
74 pub fn set_coinbase(&mut self, address: Address) {
75 self.coinbase = Some(address);
76 }
77
78 #[inline]
80 pub fn clear_coinbase(&mut self) {
81 self.coinbase = None;
82 }
83
84 #[inline]
86 pub fn is_warm(&self, address: &Address) -> bool {
87 if Some(*address) == self.coinbase {
89 return true;
90 }
91
92 if self.precompile_set.is_empty() {
94 return false;
95 }
96
97 if let Some(short_address) = short_address(address) {
99 return self.precompile_short_addresses[short_address];
100 }
101
102 if self.all_short_addresses {
104 return false;
105 }
106
107 self.precompile_set.contains(address)
109 }
110
111 #[inline]
113 pub fn is_cold(&self, address: &Address) -> bool {
114 !self.is_warm(address)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use primitives::{address, Address};
122
123 #[test]
124 fn test_initialization() {
125 let warm_addresses = WarmAddresses::new();
126 assert!(warm_addresses.precompile_set.is_empty());
127 assert!(warm_addresses.precompile_short_addresses.is_empty());
128 assert!(warm_addresses.coinbase.is_none());
129
130 let default_addresses = WarmAddresses::default();
132 assert_eq!(warm_addresses, default_addresses);
133 }
134
135 #[test]
136 fn test_coinbase_management() {
137 let mut warm_addresses = WarmAddresses::new();
138 let coinbase_addr = address!("1234567890123456789012345678901234567890");
139
140 warm_addresses.set_coinbase(coinbase_addr);
142 assert_eq!(warm_addresses.coinbase, Some(coinbase_addr));
143 assert!(warm_addresses.is_warm(&coinbase_addr));
144
145 warm_addresses.clear_coinbase();
147 assert!(warm_addresses.coinbase.is_none());
148 assert!(!warm_addresses.is_warm(&coinbase_addr));
149 }
150
151 #[test]
152 fn test_short_address_precompiles() {
153 let mut warm_addresses = WarmAddresses::new();
154
155 let mut bytes1 = [0u8; 20];
157 bytes1[19] = 1u8;
158 let short_addr1 = Address::from(bytes1);
159
160 let mut bytes2 = [0u8; 20];
161 bytes2[19] = 5u8;
162 let short_addr2 = Address::from(bytes2);
163
164 let mut precompiles = HashSet::default();
165 precompiles.insert(short_addr1);
166 precompiles.insert(short_addr2);
167
168 warm_addresses.set_precompile_addresses(precompiles.clone());
169
170 assert_eq!(warm_addresses.precompile_set, precompiles);
172 assert_eq!(
173 warm_addresses.precompile_short_addresses.len(),
174 SHORT_ADDRESS_CAP
175 );
176
177 assert!(warm_addresses.precompile_short_addresses[1]);
179 assert!(warm_addresses.precompile_short_addresses[5]);
180 assert!(!warm_addresses.precompile_short_addresses[0]);
181
182 assert!(warm_addresses.is_warm(&short_addr1));
184 assert!(warm_addresses.is_warm(&short_addr2));
185
186 let mut other_bytes = [0u8; 20];
188 other_bytes[19] = 20u8;
189 let other_short_addr = Address::from(other_bytes);
190 assert!(!warm_addresses.is_warm(&other_short_addr));
191 }
192
193 #[test]
194 fn test_regular_address_precompiles() {
195 let mut warm_addresses = WarmAddresses::new();
196
197 let regular_addr = address!("1234567890123456789012345678901234567890");
199 let mut bytes = [0u8; 20];
200 bytes[18] = 1u8;
201 bytes[19] = 44u8; let boundary_addr = Address::from(bytes);
203
204 let mut precompiles = HashSet::default();
205 precompiles.insert(regular_addr);
206 precompiles.insert(boundary_addr);
207
208 warm_addresses.set_precompile_addresses(precompiles.clone());
209
210 assert_eq!(warm_addresses.precompile_set, precompiles);
212 assert!(!warm_addresses.precompile_short_addresses.any());
213
214 assert!(warm_addresses.is_warm(®ular_addr));
216 assert!(warm_addresses.is_warm(&boundary_addr));
217
218 let other_addr = address!("0987654321098765432109876543210987654321");
220 assert!(!warm_addresses.is_warm(&other_addr));
221 }
222
223 #[test]
224 fn test_mixed_address_types() {
225 let mut warm_addresses = WarmAddresses::new();
226
227 let mut short_bytes = [0u8; 20];
228 short_bytes[19] = 7u8;
229 let short_addr = Address::from(short_bytes);
230 let regular_addr = address!("1234567890123456789012345678901234567890");
231
232 let mut precompiles = HashSet::default();
233 precompiles.insert(short_addr);
234 precompiles.insert(regular_addr);
235
236 warm_addresses.set_precompile_addresses(precompiles);
237
238 assert!(warm_addresses.is_warm(&short_addr));
240 assert!(warm_addresses.is_warm(®ular_addr));
241
242 assert!(warm_addresses.precompile_short_addresses[7]);
244 assert!(!warm_addresses.precompile_short_addresses[8]);
245 }
246
247 #[test]
248 fn test_short_address_boundary() {
249 let mut warm_addresses = WarmAddresses::new();
250
251 let mut boundary_bytes = [0u8; 20];
253 let boundary_val = (SHORT_ADDRESS_CAP - 1) as u16;
254 boundary_bytes[18] = (boundary_val >> 8) as u8;
255 boundary_bytes[19] = boundary_val as u8;
256 let boundary_addr = Address::from(boundary_bytes);
257
258 let mut precompiles = HashSet::default();
259 precompiles.insert(boundary_addr);
260
261 warm_addresses.set_precompile_addresses(precompiles);
262
263 assert!(warm_addresses.is_warm(&boundary_addr));
264 assert!(warm_addresses.precompile_short_addresses[SHORT_ADDRESS_CAP - 1]);
265 }
266}