Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 66 additions & 21 deletions crates/primitives/src/transaction/access_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@ use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWra
use reth_codecs::{main_codec, Compact};
use std::mem;

/// 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(
Expand All @@ -30,7 +38,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(
Expand Down Expand Up @@ -81,32 +89,69 @@ impl AccessList {
self.0.iter().map(AccessListItem::size).sum::<usize>() +
self.0.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.0.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.0.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.0[index].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.0.push(AccessListItem { address, storage_keys: Vec::new() });
true
}
}
}

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(),
)
}
}
Loading