Skip to content

Commit

Permalink
chore(levm): ef_tests parser for eip7702 (#1749)
Browse files Browse the repository at this point in the history
**Motivation**

The EIP7702 introduces a new tx field, `authorization_list` 

**Description**

Parse the `authorization_list` field present in the new transactions

Linked to #1672

---------

Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com>
  • Loading branch information
fborello-lambda and ilitteri authored Jan 20, 2025
1 parent 6aaf5e3 commit bbf6734
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 22 deletions.
18 changes: 17 additions & 1 deletion cmd/ef_tests/levm/deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::types::{EFTest, EFTestAccessListItem, EFTests, TransactionExpectedException};
use crate::types::{
EFTest, EFTestAccessListItem, EFTestAuthorizationListTuple, EFTests,
TransactionExpectedException,
};
use bytes::Bytes;
use ethrex_core::{H256, U256};
use serde::{Deserialize, Deserializer};
Expand Down Expand Up @@ -194,6 +197,18 @@ where
Ok(Some(final_access_lists))
}

pub fn deserialize_authorization_lists<'de, D>(
deserializer: D,
) -> Result<Option<Vec<EFTestAuthorizationListTuple>>, D::Error>
where
D: serde::Deserializer<'de>,
{
let authorization_list: Option<Vec<EFTestAuthorizationListTuple>> =
Option::<Vec<EFTestAuthorizationListTuple>>::deserialize(deserializer)?;

Ok(authorization_list)
}

pub fn deserialize_u256_optional_safe<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
where
D: serde::Deserializer<'de>,
Expand Down Expand Up @@ -322,6 +337,7 @@ impl<'de> Deserialize<'de> for EFTests {
.get(data_id)
.cloned()
.unwrap_or_default(),
authorization_list: raw_tx.authorization_list.clone(),
};
transactions.insert((data_id, gas_limit_id, value_id), tx);
}
Expand Down
19 changes: 18 additions & 1 deletion cmd/ef_tests/levm/runner/levm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use ethrex_core::{
use ethrex_levm::{
db::CacheDB,
errors::{TransactionReport, TxValidationError, VMError},
vm::VM,
vm::{AuthorizationTuple, VM},
Environment,
};
use ethrex_storage::AccountUpdate;
Expand Down Expand Up @@ -88,6 +88,22 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result<VM, EFTes
.map(|arg| (arg.address, arg.storage_keys.clone()))
.collect();

// Check if the tx has the authorization_lists field implemented by eip7702.
let authorization_list = tx.authorization_list.clone().map(|list| {
list.iter()
.map(|auth_tuple| AuthorizationTuple {
chain_id: auth_tuple.chain_id,
address: auth_tuple.address,
nonce: auth_tuple.nonce,
v: auth_tuple.v,
r_signature: auth_tuple.r,
s_signature: auth_tuple.s,
// If the signer is not present, set it to Address::zero()
signer: auth_tuple.signer.unwrap_or_default(),
})
.collect::<Vec<AuthorizationTuple>>()
});

VM::new(
tx.to.clone(),
Environment {
Expand Down Expand Up @@ -116,6 +132,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result<VM, EFTes
db,
CacheDB::default(),
access_lists,
authorization_list,
)
.map_err(|err| EFTestRunnerError::VMInitializationFailed(err.to_string()))
}
Expand Down
29 changes: 28 additions & 1 deletion cmd/ef_tests/levm/runner/revm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,33 @@ pub fn prepare_revm_for_tx<'state>(
})
.collect();

let authorization_list = None;
// The latest version of revm(19.3.0) is needed.
// Update it in every Cargo.toml.
// revm-inspectors and revm-primitives have to be bumped too.
/*
let revm_authorization_list: Vec<SignedAuthorization> = tx
.authorization_list
.clone()
.unwrap_or_default()
.iter()
.map(|auth_t| {
SignedAuthorization::new_unchecked(
Authorization {
chain_id: RevmU256::from_le_bytes(auth_t.chain_id.to_little_endian()),
address: RevmAddress(auth_t.address.0.into()),
nonce: auth_t.nonce,
},
auth_t.v.as_u32() as u8,
RevmU256::from_le_bytes(auth_t.r.to_little_endian()),
RevmU256::from_le_bytes(auth_t.s.to_little_endian()),
)
})
.collect();
let authorization_list = Some(revm_authorization_list.into());
*/

let tx_env = RevmTxEnv {
caller: tx.sender.0.into(),
gas_limit: tx.gas_limit,
Expand All @@ -160,7 +187,7 @@ pub fn prepare_revm_for_tx<'state>(
max_fee_per_blob_gas: tx
.max_fee_per_blob_gas
.map(|fee| RevmU256::from_limbs(fee.0)),
authorization_list: None,
authorization_list,
};

let evm_builder = Revm::builder()
Expand Down
25 changes: 23 additions & 2 deletions cmd/ef_tests/levm/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
deserialize::{
deserialize_access_lists, deserialize_ef_post_value_indexes,
deserialize_h256_vec_optional_safe, deserialize_hex_bytes, deserialize_hex_bytes_vec,
deserialize_access_lists, deserialize_authorization_lists,
deserialize_ef_post_value_indexes, deserialize_h256_vec_optional_safe,
deserialize_hex_bytes, deserialize_hex_bytes_vec,
deserialize_transaction_expected_exception, deserialize_u256_optional_safe,
deserialize_u256_safe, deserialize_u256_valued_hashmap_safe, deserialize_u256_vec_safe,
deserialize_u64_safe, deserialize_u64_vec_safe,
Expand Down Expand Up @@ -286,6 +287,23 @@ pub struct EFTestAccessListItem {
pub storage_keys: Vec<H256>,
}

#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct EFTestAuthorizationListTuple {
#[serde(deserialize_with = "deserialize_u256_safe")]
pub chain_id: U256,
pub address: Address,
#[serde(deserialize_with = "deserialize_u64_safe")]
pub nonce: u64,
#[serde(deserialize_with = "deserialize_u256_safe")]
pub v: U256,
#[serde(deserialize_with = "deserialize_u256_safe")]
pub r: U256,
#[serde(deserialize_with = "deserialize_u256_safe")]
pub s: U256,
pub signer: Option<Address>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EFTestRawTransaction {
Expand All @@ -312,6 +330,8 @@ pub struct EFTestRawTransaction {
pub blob_versioned_hashes: Option<Vec<H256>>,
#[serde(default, deserialize_with = "deserialize_access_lists")]
pub access_lists: Option<Vec<Vec<EFTestAccessListItem>>>,
#[serde(default, deserialize_with = "deserialize_authorization_lists")]
pub authorization_list: Option<Vec<EFTestAuthorizationListTuple>>,
}

#[derive(Debug, Deserialize)]
Expand All @@ -331,4 +351,5 @@ pub struct EFTestTransaction {
pub max_fee_per_blob_gas: Option<U256>,
pub blob_versioned_hashes: Vec<H256>,
pub access_list: Vec<EFTestAccessListItem>,
pub authorization_list: Option<Vec<EFTestAuthorizationListTuple>>,
}
17 changes: 1 addition & 16 deletions crates/vm/levm/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,9 @@ impl Environment {
pub fn default_from_address(origin: Address) -> Self {
Self {
origin,
refunded_gas: 0,
gas_limit: u64::MAX,
spec_id: Default::default(),
block_number: Default::default(),
coinbase: Default::default(),
timestamp: Default::default(),
prev_randao: Default::default(),
chain_id: U256::one(),
base_fee_per_gas: Default::default(),
gas_price: Default::default(),
block_excess_blob_gas: Default::default(),
block_blob_gas_used: Default::default(),
tx_blob_hashes: Default::default(),
tx_max_priority_fee_per_gas: Default::default(),
tx_max_fee_per_gas: Default::default(),
tx_max_fee_per_blob_gas: Default::default(),
block_gas_limit: Default::default(),
transient_storage: Default::default(),
..Default::default()
}
}
}
8 changes: 7 additions & 1 deletion crates/vm/levm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ pub enum TxValidationError {
Type3TxBlobCountExceeded,
#[error("Type3TxContractCreation")]
Type3TxContractCreation,
#[error("Type 4 transactions are not supported before the Prague fork")]
Type4TxPreFork,
#[error("Type4TxAuthorizationListIsEmpty")]
Type4TxAuthorizationListIsEmpty,
#[error("Type4TxContractCreation")]
Type4TxContractCreation,
#[error("Gas limit price product overflow")]
GasLimitPriceProductOverflow,
#[error("Gas limit is too low")]
Expand Down Expand Up @@ -148,7 +154,7 @@ pub enum InternalError {
ArithmeticOperationUnderflow,
#[error("Arithmetic operation divided by zero")]
ArithmeticOperationDividedByZero,
#[error("Accound should have been cached")]
#[error("Account should have been cached")]
AccountShouldHaveBeenCached,
#[error("Tried to convert one type to another")]
ConversionError,
Expand Down
1 change: 1 addition & 0 deletions crates/vm/levm/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,6 @@ pub fn new_vm_with_ops_addr_bal_db(
Arc::new(db),
cache,
Vec::new(),
None,
)
}
17 changes: 17 additions & 0 deletions crates/vm/levm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub struct VM {
pub cache: CacheDB,
pub tx_kind: TxKind,
pub access_list: AccessList,
pub authorization_list: Option<AuthorizationList>,
}

pub fn address_to_word(address: Address) -> U256 {
Expand All @@ -88,6 +89,19 @@ pub struct AccessListItem {

type AccessList = Vec<(Address, Vec<H256>)>;

type AuthorizationList = Vec<AuthorizationTuple>;
// TODO: We have to implement this in ethrex_core
#[derive(Debug, Clone, Default, Copy)]
pub struct AuthorizationTuple {
pub chain_id: U256,
pub address: Address,
pub nonce: u64,
pub v: U256,
pub r_signature: U256,
pub s_signature: U256,
pub signer: Address,
}

pub fn get_valid_jump_destinations(code: &Bytes) -> Result<HashSet<usize>, VMError> {
let mut valid_jump_destinations = HashSet::new();
let mut pc = 0;
Expand Down Expand Up @@ -133,6 +147,7 @@ impl VM {
db: Arc<dyn Database>,
mut cache: CacheDB,
access_list: AccessList,
authorization_list: Option<AuthorizationList>,
) -> Result<Self, VMError> {
// Maybe this decision should be made in an upper layer

Expand Down Expand Up @@ -204,6 +219,7 @@ impl VM {
cache,
tx_kind: to,
access_list,
authorization_list,
})
}
TxKind::Create => {
Expand Down Expand Up @@ -246,6 +262,7 @@ impl VM {
cache,
tx_kind: TxKind::Create,
access_list,
authorization_list,
})
}
}
Expand Down
8 changes: 8 additions & 0 deletions crates/vm/levm/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3891,6 +3891,7 @@ fn caller_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -3934,6 +3935,7 @@ fn origin_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -4004,6 +4006,7 @@ fn address_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -4051,6 +4054,7 @@ fn selfbalance_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -4095,6 +4099,7 @@ fn callvalue_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -4138,6 +4143,7 @@ fn codesize_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -4180,6 +4186,7 @@ fn gasprice_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down Expand Up @@ -4238,6 +4245,7 @@ fn codecopy_op() {
Arc::new(db),
cache,
Vec::new(),
None,
)
.unwrap();

Expand Down
4 changes: 4 additions & 0 deletions crates/vm/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ cfg_if::cfg_if! {
store_wrapper,
CacheDB::new(),
vec![],
None
)
.map_err(EvmError::from)?;

Expand Down Expand Up @@ -325,6 +326,9 @@ cfg_if::cfg_if! {
db,
block_cache,
tx.access_list(),
// TODO: Here we should pass the tx.authorization_list
// We have to implement the EIP7702 tx in ethrex_core
None
)?;

vm.transact()
Expand Down

0 comments on commit bbf6734

Please sign in to comment.