1use crate::{
6 SlotChanges, balance_change::BalanceChange, code_change::CodeChange, nonce_change::NonceChange,
7};
8use alloc::vec::Vec;
9use alloy_primitives::{Address, U256};
10
11#[derive(Debug, Clone, Default, PartialEq, Eq)]
13#[cfg_attr(feature = "rlp", derive(alloy_rlp::RlpEncodable, alloy_rlp::RlpDecodable))]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
16#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
17#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
18pub struct AccountChanges {
19 pub address: Address,
21 pub storage_changes: Vec<SlotChanges>,
23 pub storage_reads: Vec<U256>,
25 pub balance_changes: Vec<BalanceChange>,
27 pub nonce_changes: Vec<NonceChange>,
29 pub code_changes: Vec<CodeChange>,
31}
32
33impl AccountChanges {
34 pub const fn new(address: Address) -> Self {
36 Self {
37 address,
38 storage_changes: Vec::new(),
39 storage_reads: Vec::new(),
40 balance_changes: Vec::new(),
41 nonce_changes: Vec::new(),
42 code_changes: Vec::new(),
43 }
44 }
45
46 pub fn with_capacity(address: Address, capacity: usize) -> Self {
48 Self {
49 address,
50 storage_changes: Vec::with_capacity(capacity),
51 storage_reads: Vec::with_capacity(capacity),
52 balance_changes: Vec::with_capacity(capacity),
53 nonce_changes: Vec::with_capacity(capacity),
54 code_changes: Vec::with_capacity(capacity),
55 }
56 }
57
58 #[inline]
60 pub const fn address(&self) -> Address {
61 self.address
62 }
63
64 #[inline]
66 pub fn storage_changes(&self) -> &[SlotChanges] {
67 &self.storage_changes
68 }
69
70 #[inline]
74 pub fn storage_post_states(&self) -> impl Iterator<Item = (U256, U256)> + '_ {
75 self.storage_changes.iter().filter_map(|changes| {
76 changes.changes.last().map(|change| (changes.slot, change.new_value))
77 })
78 }
79
80 #[inline]
82 pub fn storage_reads(&self) -> &[U256] {
83 &self.storage_reads
84 }
85
86 #[inline]
88 pub fn balance_changes(&self) -> &[BalanceChange] {
89 &self.balance_changes
90 }
91
92 #[inline]
94 pub fn nonce_changes(&self) -> &[NonceChange] {
95 &self.nonce_changes
96 }
97
98 #[inline]
100 pub fn code_changes(&self) -> &[CodeChange] {
101 &self.code_changes
102 }
103
104 pub fn sort(&mut self) {
121 self.storage_changes.sort_unstable_by_key(|changes| changes.slot);
122 for slot_changes in &mut self.storage_changes {
123 slot_changes.sort();
124 }
125
126 self.storage_reads.sort_unstable();
127 self.balance_changes.sort_unstable_by_key(|change| change.block_access_index);
128 self.nonce_changes.sort_unstable_by_key(|change| change.block_access_index);
129 self.code_changes.sort_unstable_by_key(|change| change.block_access_index);
130 }
131
132 pub const fn with_address(mut self, address: Address) -> Self {
134 self.address = address;
135 self
136 }
137
138 pub fn with_storage_read(mut self, key: U256) -> Self {
140 self.storage_reads.push(key);
141 self
142 }
143
144 pub fn with_storage_change(mut self, change: SlotChanges) -> Self {
146 self.storage_changes.push(change);
147 self
148 }
149
150 pub fn with_balance_change(mut self, change: BalanceChange) -> Self {
152 self.balance_changes.push(change);
153 self
154 }
155
156 pub fn with_nonce_change(mut self, change: NonceChange) -> Self {
158 self.nonce_changes.push(change);
159 self
160 }
161
162 pub fn with_code_change(mut self, change: CodeChange) -> Self {
164 self.code_changes.push(change);
165 self
166 }
167
168 pub fn extend_storage_reads<I>(mut self, iter: I) -> Self
170 where
171 I: IntoIterator<Item = U256>,
172 {
173 self.storage_reads.extend(iter);
174 self
175 }
176
177 pub fn extend_storage_changes<I>(mut self, iter: I) -> Self
179 where
180 I: IntoIterator<Item = SlotChanges>,
181 {
182 self.storage_changes.extend(iter);
183 self
184 }
185}
186
187#[cfg(test)]
188mod sort_tests {
189 use crate::{BlockAccessIndex, StorageChange};
190
191 use super::*;
192 use alloy_primitives::Bytes;
193
194 #[test]
195 fn sort_orders_account_local_eip7928_lists() {
196 let mut account = AccountChanges {
197 address: Address::from([0x11; 20]),
198 storage_changes: vec![
199 SlotChanges::new(
200 U256::from(3),
201 vec![
202 StorageChange::new(BlockAccessIndex::new(8), U256::from(0x80)),
203 StorageChange::new(BlockAccessIndex::new(2), U256::from(0x20)),
204 ],
205 ),
206 SlotChanges::new(
207 U256::from(1),
208 vec![
209 StorageChange::new(BlockAccessIndex::new(5), U256::from(0x50)),
210 StorageChange::new(BlockAccessIndex::new(1), U256::from(0x10)),
211 ],
212 ),
213 ],
214 storage_reads: vec![U256::from(4), U256::from(2)],
215 balance_changes: vec![
216 BalanceChange::new(BlockAccessIndex::new(6), U256::from(600)),
217 BalanceChange::new(BlockAccessIndex::new(3), U256::from(300)),
218 ],
219 nonce_changes: vec![
220 NonceChange::new(BlockAccessIndex::new(7), 70),
221 NonceChange::new(BlockAccessIndex::new(4), 40),
222 ],
223 code_changes: vec![
224 CodeChange::new(BlockAccessIndex::new(9), Bytes::from_static(&[0x60, 0x09])),
225 CodeChange::new(BlockAccessIndex::new(5), Bytes::from_static(&[0x60, 0x05])),
226 ],
227 };
228
229 account.sort();
230
231 assert_eq!(
232 account.storage_changes.iter().map(|changes| changes.slot).collect::<Vec<_>>(),
233 vec![U256::from(1), U256::from(3)]
234 );
235 assert_eq!(
236 account.storage_changes[0]
237 .changes
238 .iter()
239 .map(|change| change.block_access_index)
240 .collect::<Vec<_>>(),
241 vec![BlockAccessIndex::new(1), BlockAccessIndex::new(5)]
242 );
243 assert_eq!(
244 account.storage_changes[1]
245 .changes
246 .iter()
247 .map(|change| change.block_access_index)
248 .collect::<Vec<_>>(),
249 vec![BlockAccessIndex::new(2), BlockAccessIndex::new(8)]
250 );
251 assert_eq!(account.storage_reads, vec![U256::from(2), U256::from(4)]);
252 assert_eq!(
253 account
254 .balance_changes
255 .iter()
256 .map(|change| change.block_access_index)
257 .collect::<Vec<_>>(),
258 vec![BlockAccessIndex::new(3), BlockAccessIndex::new(6)]
259 );
260 assert_eq!(
261 account
262 .nonce_changes
263 .iter()
264 .map(|change| change.block_access_index)
265 .collect::<Vec<_>>(),
266 vec![BlockAccessIndex::new(4), BlockAccessIndex::new(7)]
267 );
268 assert_eq!(
269 account.code_changes.iter().map(|change| change.block_access_index).collect::<Vec<_>>(),
270 vec![BlockAccessIndex::new(5), BlockAccessIndex::new(9)]
271 );
272 }
273}
274
275#[cfg(test)]
276mod post_state_tests {
277 use crate::{BlockAccessIndex, StorageChange};
278
279 use super::*;
280
281 #[test]
282 fn storage_post_states_yields_last_change_per_slot() {
283 let account = AccountChanges::new(Address::from([0x11; 20]))
284 .with_storage_change(SlotChanges::new(
285 U256::from(1),
286 vec![
287 StorageChange::new(BlockAccessIndex::new(0), U256::from(0xaa)),
288 StorageChange::new(BlockAccessIndex::new(2), U256::from(0xbb)),
289 ],
290 ))
291 .with_storage_change(SlotChanges::new(
292 U256::from(3),
293 vec![
294 StorageChange::new(BlockAccessIndex::new(1), U256::from(0xcc)),
295 StorageChange::new(BlockAccessIndex::new(3), U256::from(0xdd)),
296 ],
297 ));
298
299 let post_states = account.storage_post_states().collect::<Vec<_>>();
300
301 assert_eq!(
302 post_states,
303 vec![(U256::from(1), U256::from(0xbb)), (U256::from(3), U256::from(0xdd))]
304 );
305 }
306}
307
308#[cfg(all(test, feature = "serde"))]
309mod tests {
310 use crate::{BlockAccessIndex, StorageChange};
311
312 use super::*;
313 use alloy_primitives::Bytes;
314 use serde_json;
315
316 #[test]
317 fn test_account_changes_serde() {
318 let acc = AccountChanges {
319 address: Address::from([0x11; 20]),
320 storage_changes: vec![SlotChanges {
321 slot: U256::from(1),
322 changes: vec![StorageChange {
323 block_access_index: BlockAccessIndex::new(0),
324 new_value: U256::from(100),
325 }],
326 }],
327 storage_reads: vec![U256::from(2)],
328 balance_changes: vec![BalanceChange {
329 block_access_index: BlockAccessIndex::new(1),
330 post_balance: U256::from(1000),
331 }],
332 nonce_changes: vec![NonceChange {
333 block_access_index: BlockAccessIndex::new(2),
334 new_nonce: 42,
335 }],
336 code_changes: vec![CodeChange {
337 block_access_index: BlockAccessIndex::new(3),
338 new_code: Bytes::from(vec![0x60, 0x00]),
339 }],
340 };
341
342 let json = serde_json::to_string(&acc).unwrap();
343 let decoded: AccountChanges = serde_json::from_str(&json).unwrap();
344
345 assert_eq!(acc, decoded);
346 }
347
348 #[test]
349 fn test_vec_account_changes_serde() {
350 let acc1 = AccountChanges::new(Address::from([0x11; 20]))
351 .with_storage_read(U256::from(1))
352 .with_balance_change(BalanceChange {
353 block_access_index: BlockAccessIndex::new(0),
354 post_balance: U256::from(100),
355 });
356
357 let acc2 = AccountChanges::new(Address::from([0x22; 20]))
358 .with_storage_change(SlotChanges {
359 slot: U256::from(2),
360 changes: vec![StorageChange {
361 block_access_index: BlockAccessIndex::new(1),
362 new_value: U256::from(200),
363 }],
364 })
365 .with_nonce_change(NonceChange {
366 block_access_index: BlockAccessIndex::new(2),
367 new_nonce: 42,
368 });
369
370 let acc3 = AccountChanges::new(Address::from([0x33; 20])).with_code_change(CodeChange {
371 block_access_index: BlockAccessIndex::new(3),
372 new_code: Bytes::from(vec![0x60, 0x00]),
373 });
374
375 let vec_acc = vec![acc1, acc2, acc3];
376
377 let json = serde_json::to_string(&vec_acc).unwrap();
378 let decoded: Vec<AccountChanges> = serde_json::from_str(&json).unwrap();
379
380 assert_eq!(vec_acc, decoded);
381 }
382}