From cf6a1362c9356edc8fe8050608bec052304e9eb5 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Sun, 21 Jan 2024 00:26:38 +0100 Subject: [PATCH 1/3] feat(access-list): refactor and add some utils to AccessList --- .../primitives/src/transaction/access_list.rs | 87 ++++++++++++++----- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/crates/primitives/src/transaction/access_list.rs b/crates/primitives/src/transaction/access_list.rs index 7032c1634b42..32d17b3cf413 100644 --- a/crates/primitives/src/transaction/access_list.rs +++ b/crates/primitives/src/transaction/access_list.rs @@ -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( @@ -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( @@ -81,32 +89,69 @@ impl AccessList { self.0.iter().map(AccessListItem::size).sum::() + self.0.capacity() * mem::size_of::() } + + /// Returns the position of the given address in the access list, if present. + pub fn index_of_address(&self, address: Address) -> Option { + 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 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 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(), + ) } } From 31c250226b7ff5908c4b483bc1138952ed929b09 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Mon, 22 Jan 2024 11:57:23 +0100 Subject: [PATCH 2/3] fix contains_storage_key_at_index and impl Deref for AccessList --- .../primitives/src/transaction/access_list.rs | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/crates/primitives/src/transaction/access_list.rs b/crates/primitives/src/transaction/access_list.rs index 32d17b3cf413..85235048c9f3 100644 --- a/crates/primitives/src/transaction/access_list.rs +++ b/crates/primitives/src/transaction/access_list.rs @@ -2,7 +2,10 @@ 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}, +}; /// Represents a list of addresses and storage keys that a transaction plans to access. /// @@ -51,6 +54,20 @@ pub struct AccessList( pub Vec, ); +impl Deref for AccessList { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for AccessList { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl AccessList { /// Converts the list into a vec, expected by revm pub fn flattened(&self) -> Vec<(Address, Vec)> { @@ -74,7 +91,7 @@ impl AccessList { /// Returns an iterator over the list's addresses and storage keys. pub fn flatten(&self) -> impl Iterator)> + '_ { - self.0.iter().map(|item| { + self.iter().map(|item| { ( item.address, item.storage_keys.iter().map(|slot| U256::from_be_bytes(slot.0)).collect(), @@ -86,13 +103,13 @@ impl AccessList { #[inline] pub fn size(&self) -> usize { // take into account capacity - self.0.iter().map(AccessListItem::size).sum::() + - self.0.capacity() * mem::size_of::() + self.iter().map(AccessListItem::size).sum::() + + self.capacity() * mem::size_of::() } /// Returns the position of the given address in the access list, if present. pub fn index_of_address(&self, address: Address) -> Option { - self.0.iter().position(|item| item.address == address) + self.iter().position(|item| item.address == address) } /// Checks if a specific storage slot within an account is present in the access list. @@ -105,20 +122,22 @@ impl AccessList { /// 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) + 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.0[index].storage_keys.iter().any(|storage_key| *storage_key == slot) + 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.0.push(AccessListItem { address, storage_keys: Vec::new() }); + self.push(AccessListItem { address, storage_keys: Vec::new() }); true } } From 0dabfefc544dad5f11bbc60e0e78d730e5871bf9 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Mon, 22 Jan 2024 13:12:32 +0100 Subject: [PATCH 3/3] fix deref position --- .../primitives/src/transaction/access_list.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/primitives/src/transaction/access_list.rs b/crates/primitives/src/transaction/access_list.rs index 85235048c9f3..ba74aaf1435d 100644 --- a/crates/primitives/src/transaction/access_list.rs +++ b/crates/primitives/src/transaction/access_list.rs @@ -54,20 +54,6 @@ pub struct AccessList( pub Vec, ); -impl Deref for AccessList { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for AccessList { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - impl AccessList { /// Converts the list into a vec, expected by revm pub fn flattened(&self) -> Vec<(Address, Vec)> { @@ -143,6 +129,20 @@ impl AccessList { } } +impl Deref for AccessList { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for AccessList { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl From for AccessList { #[inline] fn from(value: reth_rpc_types::AccessList) -> Self {