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