1#![cfg_attr(not(feature = "std"), no_std)]
5
6extern crate alloc;
7
8use alloc::{string::String, vec::Vec};
9use alloy_primitives::{Address, B256, U256};
10use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
11use core::{mem, ops::Deref};
12
13#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RlpDecodable, RlpEncodable)]
16#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
19#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
20pub struct AccessListItem {
21 pub address: Address,
23 pub storage_keys: Vec<B256>,
25}
26
27impl AccessListItem {
28 #[inline]
30 pub const fn size(&self) -> usize {
31 mem::size_of::<Address>() + self.storage_keys.capacity() * mem::size_of::<B256>()
32 }
33}
34
35#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RlpDecodableWrapper, RlpEncodableWrapper)]
37#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
40pub struct AccessList(pub Vec<AccessListItem>);
41
42impl From<Vec<AccessListItem>> for AccessList {
43 fn from(list: Vec<AccessListItem>) -> Self {
44 Self(list)
45 }
46}
47
48impl From<AccessList> for Vec<AccessListItem> {
49 fn from(this: AccessList) -> Self {
50 this.0
51 }
52}
53
54impl Deref for AccessList {
55 type Target = Vec<AccessListItem>;
56
57 fn deref(&self) -> &Self::Target {
58 &self.0
59 }
60}
61
62impl AccessList {
63 pub fn flattened(&self) -> Vec<(Address, Vec<U256>)> {
65 self.flatten().collect()
66 }
67
68 pub fn into_flattened(self) -> Vec<(Address, Vec<U256>)> {
70 self.into_flatten().collect()
71 }
72
73 pub fn into_flatten(self) -> impl Iterator<Item = (Address, Vec<U256>)> {
75 self.0.into_iter().map(|item| {
76 (
77 item.address,
78 item.storage_keys.into_iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
79 )
80 })
81 }
82
83 pub fn flatten(&self) -> impl Iterator<Item = (Address, Vec<U256>)> + '_ {
85 self.0.iter().map(|item| {
86 (
87 item.address,
88 item.storage_keys.iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
89 )
90 })
91 }
92
93 fn index_of_address(&self, address: Address) -> Option<usize> {
95 self.iter().position(|item| item.address == address)
96 }
97
98 pub fn storage_keys_count(&self) -> usize {
100 self.iter().map(|i| i.storage_keys.len()).sum::<usize>()
101 }
102
103 pub fn contains_storage(&self, address: Address, slot: B256) -> (bool, bool) {
107 self.index_of_address(address)
108 .map_or((false, false), |idx| (true, self.contains_storage_key_at_index(slot, idx)))
109 }
110
111 pub fn contains_address(&self, address: Address) -> bool {
113 self.iter().any(|item| item.address == address)
114 }
115
116 fn contains_storage_key_at_index(&self, slot: B256, index: usize) -> bool {
119 self.get(index).is_some_and(|entry| entry.storage_keys.contains(&slot))
120 }
121
122 pub fn add_address(&mut self, address: Address) -> bool {
125 !self.contains_address(address) && {
126 self.0.push(AccessListItem { address, storage_keys: Vec::new() });
127 true
128 }
129 }
130
131 #[inline]
133 pub fn size(&self) -> usize {
134 self.0.iter().map(AccessListItem::size).sum::<usize>()
136 + self.0.capacity() * mem::size_of::<AccessListItem>()
137 }
138}
139
140#[derive(Clone, Debug, Default, PartialEq, Eq)]
142#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
143#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
144#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
145pub struct AccessListWithGasUsed {
146 pub access_list: AccessList,
148 pub gas_used: U256,
150}
151
152#[derive(Clone, Debug, Default, PartialEq, Eq)]
154#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
155#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
156#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
157pub struct AccessListResult {
158 pub access_list: AccessList,
160 pub gas_used: U256,
162 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
164 pub error: Option<String>,
165}
166
167impl AccessListResult {
168 pub fn ensure_ok(self) -> Result<AccessListWithGasUsed, String> {
171 match self.error {
172 Some(err) => Err(err),
173 None => {
174 Ok(AccessListWithGasUsed { access_list: self.access_list, gas_used: self.gas_used })
175 }
176 }
177 }
178
179 #[inline]
181 pub const fn is_err(&self) -> bool {
182 self.error.is_some()
183 }
184}
185
186#[cfg(all(test, feature = "serde"))]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn access_list_serde() {
192 let list = AccessList(vec![
193 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
194 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
195 ]);
196 let json = serde_json::to_string(&list).unwrap();
197 let list2 = serde_json::from_str::<AccessList>(&json).unwrap();
198 assert_eq!(list, list2);
199 }
200
201 #[test]
202 fn access_list_with_gas_used() {
203 let list = AccessListResult {
204 access_list: AccessList(vec![
205 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
206 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
207 ]),
208 gas_used: U256::from(100),
209 error: None,
210 };
211 let json = serde_json::to_string(&list).unwrap();
212 let list2 = serde_json::from_str(&json).unwrap();
213 assert_eq!(list, list2);
214 }
215}