linera_alloy_eips/
eip2930.rs1#[cfg(not(feature = "std"))]
6use alloc::vec::Vec;
7
8use linera_alloy_primitives::{Address, B256, U256};
9use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
10use core::{mem, ops::Deref};
11
12#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RlpDecodable, RlpEncodable)]
15#[cfg_attr(
16 any(test, feature = "arbitrary"),
17 derive(proptest_derive::Arbitrary, arbitrary::Arbitrary)
18)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
21pub struct AccessListItem {
22 pub address: Address,
24 #[cfg_attr(
26 any(test, feature = "arbitrary"),
27 proptest(
28 strategy = "proptest::collection::vec(proptest::arbitrary::any::<B256>(), 0..=20)"
29 )
30 )]
31 pub storage_keys: Vec<B256>,
32}
33
34impl AccessListItem {
35 #[inline]
37 pub fn size(&self) -> usize {
38 mem::size_of::<Address>() + self.storage_keys.capacity() * mem::size_of::<B256>()
39 }
40}
41
42#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RlpDecodableWrapper, RlpEncodableWrapper)]
44#[cfg_attr(
45 any(test, feature = "arbitrary"),
46 derive(proptest_derive::Arbitrary, arbitrary::Arbitrary)
47)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49pub struct AccessList(
50 #[cfg_attr(
51 any(test, feature = "arbitrary"),
52 proptest(
53 strategy = "proptest::collection::vec(proptest::arbitrary::any::<AccessListItem>(), 0..=20)"
54 )
55 )]
56 pub Vec<AccessListItem>,
57);
58
59impl From<Vec<AccessListItem>> for AccessList {
60 fn from(list: Vec<AccessListItem>) -> Self {
61 Self(list)
62 }
63}
64
65impl From<AccessList> for Vec<AccessListItem> {
66 fn from(this: AccessList) -> Self {
67 this.0
68 }
69}
70
71impl Deref for AccessList {
72 type Target = Vec<AccessListItem>;
73
74 fn deref(&self) -> &Self::Target {
75 &self.0
76 }
77}
78
79impl AccessList {
80 pub fn flattened(&self) -> Vec<(Address, Vec<U256>)> {
82 self.flatten().collect()
83 }
84
85 pub fn into_flattened(self) -> Vec<(Address, Vec<U256>)> {
87 self.into_flatten().collect()
88 }
89
90 pub fn into_flatten(self) -> impl Iterator<Item = (Address, Vec<U256>)> {
92 self.0.into_iter().map(|item| {
93 (
94 item.address,
95 item.storage_keys.into_iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
96 )
97 })
98 }
99
100 pub fn flatten(&self) -> impl Iterator<Item = (Address, Vec<U256>)> + '_ {
102 self.0.iter().map(|item| {
103 (
104 item.address,
105 item.storage_keys.iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
106 )
107 })
108 }
109
110 fn index_of_address(&self, address: Address) -> Option<usize> {
112 self.iter().position(|item| item.address == address)
113 }
114
115 pub fn contains_storage(&self, address: Address, slot: B256) -> (bool, bool) {
119 self.index_of_address(address)
120 .map_or((false, false), |idx| (true, self.contains_storage_key_at_index(slot, idx)))
121 }
122
123 pub fn contains_address(&self, address: Address) -> bool {
125 self.iter().any(|item| item.address == address)
126 }
127
128 fn contains_storage_key_at_index(&self, slot: B256, index: usize) -> bool {
131 self.get(index).map_or(false, |entry| {
132 entry.storage_keys.iter().any(|storage_key| *storage_key == slot)
133 })
134 }
135
136 pub fn add_address(&mut self, address: Address) -> bool {
139 !self.contains_address(address) && {
140 self.0.push(AccessListItem { address, storage_keys: Vec::new() });
141 true
142 }
143 }
144
145 #[inline]
147 pub fn size(&self) -> usize {
148 self.0.iter().map(AccessListItem::size).sum::<usize>()
150 + self.0.capacity() * mem::size_of::<AccessListItem>()
151 }
152}
153
154#[derive(Clone, Debug, Default, PartialEq, Eq)]
156#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
157#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
158pub struct AccessListWithGasUsed {
159 pub access_list: AccessList,
161 pub gas_used: U256,
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn access_list_serde() {
171 let list = AccessList(vec![
172 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
173 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
174 ]);
175 let json = serde_json::to_string(&list).unwrap();
176 let list2 = serde_json::from_str::<AccessList>(&json).unwrap();
177 assert_eq!(list, list2);
178 }
179
180 #[test]
181 fn access_list_with_gas_used() {
182 let list = AccessListWithGasUsed {
183 access_list: AccessList(vec![
184 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
185 AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
186 ]),
187 gas_used: U256::from(100),
188 };
189 let json = serde_json::to_string(&list).unwrap();
190 let list2 = serde_json::from_str::<AccessListWithGasUsed>(&json).unwrap();
191 assert_eq!(list, list2);
192 }
193}