feat(access-list): refactor and add some utils to AccessList (#6144)

This commit is contained in:
Thomas Coratger
2024-01-22 13:22:51 +01:00
committed by GitHub
parent ade779754a
commit a8574b6990

View File

@ -2,17 +2,28 @@ use crate::{Address, B256};
use alloy_primitives::U256;
use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
use reth_codecs::{main_codec, Compact};
use std::mem;
use std::{
mem,
ops::{Deref, DerefMut},
};
/// A list of addresses and storage keys that the transaction plans to access.
/// Accesses outside the list are possible, but become more expensive.
/// Represents a list of addresses and storage keys that a transaction plans to access.
///
/// Accesses outside this list incur higher costs due to gas charging.
///
/// This structure is part of [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930), introducing an optional access list for Ethereum transactions.
///
/// The access list allows pre-specifying and pre-paying for accounts and storage
/// slots, mitigating risks introduced by [EIP-2929](https://eips.ethereum.org/EIPS/e).
#[main_codec(rlp)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodable, RlpEncodable)]
#[serde(rename_all = "camelCase")]
pub struct AccessListItem {
/// Account addresses that would be loaded at the start of execution
/// Account address that would be loaded at the start of execution
pub address: Address,
/// Keys of storage that would be loaded at the start of execution
/// The storage keys to be loaded at the start of execution.
///
/// Each key is a 32-byte value representing a specific storage slot.
#[cfg_attr(
any(test, feature = "arbitrary"),
proptest(
@ -30,7 +41,7 @@ impl AccessListItem {
}
}
/// AccessList as defined in EIP-2930
/// AccessList as defined in [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)
#[main_codec(rlp)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodableWrapper, RlpEncodableWrapper)]
pub struct AccessList(
@ -66,7 +77,7 @@ impl AccessList {
/// Returns an iterator over the list's addresses and storage keys.
pub fn flatten(&self) -> impl Iterator<Item = (Address, Vec<U256>)> + '_ {
self.0.iter().map(|item| {
self.iter().map(|item| {
(
item.address,
item.storage_keys.iter().map(|slot| U256::from_be_bytes(slot.0)).collect(),
@ -78,35 +89,88 @@ impl AccessList {
#[inline]
pub fn size(&self) -> usize {
// take into account capacity
self.0.iter().map(AccessListItem::size).sum::<usize>() +
self.0.capacity() * mem::size_of::<AccessListItem>()
self.iter().map(AccessListItem::size).sum::<usize>() +
self.capacity() * mem::size_of::<AccessListItem>()
}
/// Returns the position of the given address in the access list, if present.
pub fn index_of_address(&self, address: Address) -> Option<usize> {
self.iter().position(|item| item.address == address)
}
/// Checks if a specific storage slot within an account is present in the access list.
///
/// Returns a tuple with flags for the presence of the account and the slot.
pub fn contains(&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)))
}
/// Checks if the access list contains the specified address.
pub fn contains_address(&self, address: Address) -> bool {
self.iter().any(|item| item.address == address)
}
/// Checks if the storage keys at the given index within an account are present in the access
/// list.
pub 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)
})
}
/// Adds an address to the access list and returns `true` if the operation results in a change,
/// indicating that the address was not previously present.
pub fn add_address(&mut self, address: Address) -> bool {
!self.contains_address(address) && {
self.push(AccessListItem { address, storage_keys: Vec::new() });
true
}
}
}
impl Deref for AccessList {
type Target = Vec<AccessListItem>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for AccessList {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<reth_rpc_types::AccessList> for AccessList {
#[inline]
fn from(value: reth_rpc_types::AccessList) -> Self {
let converted_list = value
.0
.into_iter()
.map(|item| AccessListItem { address: item.address, storage_keys: item.storage_keys })
.collect();
AccessList(converted_list)
AccessList(
value
.0
.into_iter()
.map(|item| AccessListItem {
address: item.address,
storage_keys: item.storage_keys,
})
.collect(),
)
}
}
impl From<AccessList> for reth_rpc_types::AccessList {
#[inline]
fn from(value: AccessList) -> Self {
let list = value
.0
.into_iter()
.map(|item| reth_rpc_types::AccessListItem {
address: item.address,
storage_keys: item.storage_keys,
})
.collect();
reth_rpc_types::AccessList(list)
reth_rpc_types::AccessList(
value
.0
.into_iter()
.map(|item| reth_rpc_types::AccessListItem {
address: item.address,
storage_keys: item.storage_keys,
})
.collect(),
)
}
}