#![cfg_attr(not(feature = "std"), no_std)]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
use alloy_primitives::{Address, B256, U256};
use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
use core::{mem, ops::Deref};
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RlpDecodable, RlpEncodable)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct AccessListItem {
pub address: Address,
pub storage_keys: Vec<B256>,
}
impl AccessListItem {
#[inline]
pub fn size(&self) -> usize {
mem::size_of::<Address>() + self.storage_keys.capacity() * mem::size_of::<B256>()
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RlpDecodableWrapper, RlpEncodableWrapper)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AccessList(pub Vec<AccessListItem>);
impl From<Vec<AccessListItem>> for AccessList {
fn from(list: Vec<AccessListItem>) -> Self {
Self(list)
}
}
impl From<AccessList> for Vec<AccessListItem> {
fn from(this: AccessList) -> Self {
this.0
}
}
impl Deref for AccessList {
type Target = Vec<AccessListItem>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AccessList {
pub fn flattened(&self) -> Vec<(Address, Vec<U256>)> {
self.flatten().collect()
}
pub fn into_flattened(self) -> Vec<(Address, Vec<U256>)> {
self.into_flatten().collect()
}
pub fn into_flatten(self) -> impl Iterator<Item = (Address, Vec<U256>)> {
self.0.into_iter().map(|item| {
(
item.address,
item.storage_keys.into_iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
)
})
}
pub fn flatten(&self) -> impl Iterator<Item = (Address, Vec<U256>)> + '_ {
self.0.iter().map(|item| {
(
item.address,
item.storage_keys.iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
)
})
}
fn index_of_address(&self, address: Address) -> Option<usize> {
self.iter().position(|item| item.address == address)
}
pub fn contains_storage(&self, address: Address, slot: B256) -> (bool, bool) {
self.index_of_address(address)
.map_or((false, false), |idx| (true, self.contains_storage_key_at_index(slot, idx)))
}
pub fn contains_address(&self, address: Address) -> bool {
self.iter().any(|item| item.address == address)
}
fn contains_storage_key_at_index(&self, slot: B256, index: usize) -> bool {
self.get(index).map_or(false, |entry| {
entry.storage_keys.iter().any(|storage_key| *storage_key == slot)
})
}
pub fn add_address(&mut self, address: Address) -> bool {
!self.contains_address(address) && {
self.0.push(AccessListItem { address, storage_keys: Vec::new() });
true
}
}
#[inline]
pub fn size(&self) -> usize {
self.0.iter().map(AccessListItem::size).sum::<usize>()
+ self.0.capacity() * mem::size_of::<AccessListItem>()
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct AccessListWithGasUsed {
pub access_list: AccessList,
pub gas_used: U256,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct AccessListResult {
pub access_list: AccessList,
pub gas_used: U256,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
pub error: Option<String>,
}
impl AccessListResult {
pub fn ensure_ok(self) -> Result<AccessListWithGasUsed, String> {
match self.error {
Some(err) => Err(err),
None => {
Ok(AccessListWithGasUsed { access_list: self.access_list, gas_used: self.gas_used })
}
}
}
#[inline]
pub const fn is_err(&self) -> bool {
self.error.is_some()
}
}
#[cfg(all(test, feature = "serde"))]
mod tests {
use super::*;
#[test]
fn access_list_serde() {
let list = AccessList(vec![
AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
]);
let json = serde_json::to_string(&list).unwrap();
let list2 = serde_json::from_str::<AccessList>(&json).unwrap();
assert_eq!(list, list2);
}
#[test]
fn access_list_with_gas_used() {
let list = AccessListResult {
access_list: AccessList(vec![
AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
AccessListItem { address: Address::ZERO, storage_keys: vec![B256::ZERO] },
]),
gas_used: U256::from(100),
error: None,
};
let json = serde_json::to_string(&list).unwrap();
let list2 = serde_json::from_str(&json).unwrap();
assert_eq!(list, list2);
}
}