1use alloy_primitives::{Address, B256, U256};
2use arb_storage::{
3 STORAGE_READ_GAS as STORAGE_READ_COST, STORAGE_WRITE_ZERO_GAS as STORAGE_WRITE_ZERO_COST,
4 Storage, StorageBackedAddress, StorageBackedUint64, StorageBackend, SystemStateBackend,
5};
6use revm::Database;
7
8mod error;
9pub use error::AddressSetError;
10
11fn write_cost(value: B256) -> u64 {
12 arb_storage::write_cost(value == B256::ZERO)
13}
14
15pub struct AddressSet<'a, D> {
20 backing_storage: Storage<'a, D>,
21 size: StorageBackedUint64,
22 by_address: Storage<'a, D>,
23}
24
25pub fn initialize_address_set<D: Database>(sto: &Storage<'_, D>) -> Result<(), AddressSetError> {
26 Ok(sto.set_by_uint64(0, B256::ZERO)?)
27}
28
29pub fn open_address_set<D>(sto: Storage<'_, D>) -> AddressSet<'_, D> {
30 let size = StorageBackedUint64::new(sto.base_key(), 0);
31 let by_address = sto.open_sub_storage(&[0u8]);
32 AddressSet {
33 backing_storage: sto,
34 size,
35 by_address,
36 }
37}
38
39impl<D> AddressSet<'_, D> {
40 pub fn size<B: SystemStateBackend>(&self, backend: &mut B) -> Result<u64, AddressSetError> {
41 Ok(self.size.get(backend)?)
42 }
43
44 pub fn is_member<B: SystemStateBackend>(
45 &self,
46 backend: &mut B,
47 addr: Address,
48 ) -> Result<bool, AddressSetError> {
49 let value = self.by_address_get(backend, address_to_hash(addr))?;
50 Ok(value != B256::ZERO)
51 }
52
53 pub fn get_any_member<B: SystemStateBackend>(
54 &self,
55 backend: &mut B,
56 ) -> Result<Option<Address>, AddressSetError> {
57 let size = self.size.get(backend)?;
58 if size == 0 {
59 return Ok(None);
60 }
61 let sba = StorageBackedAddress::new(self.backing_storage.base_key(), 1);
62 Ok(sba.get(backend).map(Some)?)
63 }
64
65 pub fn clear<B: StorageBackend>(&self, backend: &mut B) -> Result<(), AddressSetError> {
66 let size = self.size.get(backend)?;
67 if size == 0 {
68 return Ok(());
69 }
70 for i in 1..=size {
71 let contents = self.backing_get_by_uint64(backend, i)?;
72 self.backing_set_by_uint64(backend, i, B256::ZERO)?;
73 self.by_address_set(backend, contents, B256::ZERO)?;
74 }
75 Ok(self.size.set(backend, 0)?)
76 }
77
78 pub fn all_members<B: SystemStateBackend>(
79 &self,
80 backend: &mut B,
81 max_num: u64,
82 ) -> Result<Vec<Address>, AddressSetError> {
83 let mut size = self.size.get(backend)?;
84 if size > max_num {
85 size = max_num;
86 }
87 let mut ret = Vec::with_capacity(size as usize);
88 for i in 0..size {
89 let sba = StorageBackedAddress::new(self.backing_storage.base_key(), i + 1);
90 ret.push(sba.get(backend)?);
91 }
92 Ok(ret)
93 }
94
95 pub fn clear_list<B: StorageBackend>(&self, backend: &mut B) -> Result<(), AddressSetError> {
96 let size = self.size.get(backend)?;
97 if size == 0 {
98 return Ok(());
99 }
100 for i in 1..=size {
101 self.backing_set_by_uint64(backend, i, B256::ZERO)?;
102 }
103 Ok(self.size.set(backend, 0)?)
104 }
105
106 pub fn rectify_mapping<B: StorageBackend>(
107 &self,
108 backend: &mut B,
109 addr: Address,
110 ) -> Result<(), AddressSetError> {
111 if !self.is_member(backend, addr)? {
112 return Err(AddressSetError::NotMember);
113 }
114
115 let addr_as_hash = address_to_hash(addr);
116 let slot = hash_to_uint64(self.by_address_get(backend, addr_as_hash)?);
117 let at_slot = self.backing_get_by_uint64(backend, slot)?;
118 let size = self.size.get(backend)?;
119
120 if at_slot == addr_as_hash && slot <= size {
121 return Err(AddressSetError::MappingAlreadyConsistent);
122 }
123
124 self.by_address_set(backend, addr_as_hash, B256::ZERO)?;
125 self.add(backend, addr)
126 }
127
128 pub fn add<B: StorageBackend>(
129 &self,
130 backend: &mut B,
131 addr: Address,
132 ) -> Result<(), AddressSetError> {
133 let present = self.is_member(backend, addr)?;
134 if present {
135 return Ok(());
136 }
137
138 let size = self.size.get(backend)?;
139 let slot = uint_to_hash(1 + size);
140 let addr_as_hash = address_to_hash(addr);
141
142 self.by_address_set(backend, addr_as_hash, slot)?;
143
144 let sba = StorageBackedAddress::new(self.backing_storage.base_key(), 1 + size);
145 sba.set(backend, addr)?;
146
147 Ok(self.size.set(backend, size + 1)?)
148 }
149
150 pub fn remove<B: StorageBackend>(
152 &self,
153 backend: &mut B,
154 addr: Address,
155 arbos_version: u64,
156 gas: &mut u64,
157 ) -> Result<(), AddressSetError> {
158 let addr_as_hash = address_to_hash(addr);
159 let slot_hash = self.by_address_get(backend, addr_as_hash)?;
160 *gas += STORAGE_READ_COST;
161 let slot = hash_to_uint64(slot_hash);
162
163 if slot == 0 {
164 return Ok(());
165 }
166
167 self.by_address_set(backend, addr_as_hash, B256::ZERO)?;
168 *gas += STORAGE_WRITE_ZERO_COST;
169
170 let size = self.size.get(backend)?;
171 *gas += STORAGE_READ_COST;
172 if slot < size {
173 let at_size = self.backing_get_by_uint64(backend, size)?;
174 *gas += STORAGE_READ_COST;
175 self.backing_set_by_uint64(backend, slot, at_size)?;
176 *gas += write_cost(at_size);
177
178 if arbos_version >= 11 {
179 self.by_address_set(backend, at_size, uint_to_hash(slot))?;
180 *gas += write_cost(uint_to_hash(slot));
181 }
182 }
183
184 self.backing_set_by_uint64(backend, size, B256::ZERO)?;
185 *gas += STORAGE_WRITE_ZERO_COST;
186
187 let new_size = size - 1;
188 *gas += STORAGE_READ_COST;
189 self.size.set(backend, new_size)?;
190 *gas += write_cost(uint_to_hash(new_size));
191 Ok(())
192 }
193
194 fn by_address_get<B: SystemStateBackend>(
195 &self,
196 backend: &mut B,
197 key: B256,
198 ) -> Result<B256, AddressSetError> {
199 let slot = self.by_address.slot_for_key(key);
200 let value = backend
201 .sload_system(self.by_address.account(), slot)
202 .map_err(Into::into)?;
203 Ok(B256::from(value.to_be_bytes::<32>()))
204 }
205
206 fn by_address_set<B: StorageBackend>(
207 &self,
208 backend: &mut B,
209 key: B256,
210 value: B256,
211 ) -> Result<(), AddressSetError> {
212 let slot = self.by_address.slot_for_key(key);
213 backend
214 .sstore(
215 self.by_address.account(),
216 slot,
217 U256::from_be_bytes(value.0),
218 )
219 .map_err(Into::into)?;
220 Ok(())
221 }
222
223 fn backing_get_by_uint64<B: SystemStateBackend>(
224 &self,
225 backend: &mut B,
226 offset: u64,
227 ) -> Result<B256, AddressSetError> {
228 let slot = self.backing_storage.new_slot(offset);
229 let value = backend
230 .sload_system(self.backing_storage.account(), slot)
231 .map_err(Into::into)?;
232 Ok(B256::from(value.to_be_bytes::<32>()))
233 }
234
235 fn backing_set_by_uint64<B: StorageBackend>(
236 &self,
237 backend: &mut B,
238 offset: u64,
239 value: B256,
240 ) -> Result<(), AddressSetError> {
241 let slot = self.backing_storage.new_slot(offset);
242 backend
243 .sstore(
244 self.backing_storage.account(),
245 slot,
246 U256::from_be_bytes(value.0),
247 )
248 .map_err(Into::into)?;
249 Ok(())
250 }
251}
252
253fn address_to_hash(addr: Address) -> B256 {
254 let mut bytes = [0u8; 32];
255 bytes[12..32].copy_from_slice(addr.as_slice());
256 B256::from(bytes)
257}
258
259fn uint_to_hash(val: u64) -> B256 {
260 B256::from(U256::from(val))
261}
262
263fn hash_to_uint64(hash: B256) -> u64 {
264 U256::from_be_bytes(hash.0).to::<u64>()
265}