From e5e29b38bd759595f163dbeec910d7cbc2ce2c77 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 12:02:58 -0300 Subject: [PATCH 1/4] chore(levm): ef_tests parser for eip7702 --- Cargo.lock | 4 ++-- cmd/ef_tests/levm/deserialize.rs | 18 ++++++++++++++- cmd/ef_tests/levm/runner/levm_runner.rs | 25 ++++++++++++++++++++- cmd/ef_tests/levm/runner/revm_runner.rs | 29 ++++++++++++++++++++++++- cmd/ef_tests/levm/types.rs | 25 +++++++++++++++++++-- crates/vm/levm/src/environment.rs | 16 +------------- crates/vm/levm/src/errors.rs | 8 ++++++- crates/vm/levm/src/utils.rs | 1 + crates/vm/levm/src/vm.rs | 17 +++++++++++++++ crates/vm/levm/tests/tests.rs | 8 +++++++ crates/vm/vm.rs | 4 ++++ 11 files changed, 132 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9e590a376..77952f2378 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,9 +1170,9 @@ dependencies = [ [[package]] name = "bls12_381" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" +source = "git+https://github.com/lambdaclass/bls12_381?branch=expose-fp-struct#219174187bd78154cec35b0809799fc2c991a579" dependencies = [ + "digest 0.10.7", "ff 0.13.0", "group 0.13.0", "pairing 0.23.0", diff --git a/cmd/ef_tests/levm/deserialize.rs b/cmd/ef_tests/levm/deserialize.rs index 505ae696bf..df1d2cdbdf 100644 --- a/cmd/ef_tests/levm/deserialize.rs +++ b/cmd/ef_tests/levm/deserialize.rs @@ -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}; @@ -194,6 +197,18 @@ where Ok(Some(final_access_lists)) } +pub fn deserialize_authorization_lists<'de, D>( + deserializer: D, +) -> Result>, D::Error> +where + D: serde::Deserializer<'de>, +{ + let authorization_list: Option> = + Option::>::deserialize(deserializer)?; + + Ok(authorization_list) +} + pub fn deserialize_u256_optional_safe<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -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); } diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 27447b632d..5a057e3fb6 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -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; @@ -88,6 +88,28 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result + let auth_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::>(); + + Some(auth_list) + } else { + None + }; + VM::new( tx.to.clone(), Environment { @@ -116,6 +138,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result( }) .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 = 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, @@ -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() diff --git a/cmd/ef_tests/levm/types.rs b/cmd/ef_tests/levm/types.rs index 7cb95fb635..5295f7f4da 100644 --- a/cmd/ef_tests/levm/types.rs +++ b/cmd/ef_tests/levm/types.rs @@ -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, @@ -286,6 +287,23 @@ pub struct EFTestAccessListItem { pub storage_keys: Vec, } +#[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
, +} + #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EFTestRawTransaction { @@ -312,6 +330,8 @@ pub struct EFTestRawTransaction { pub blob_versioned_hashes: Option>, #[serde(default, deserialize_with = "deserialize_access_lists")] pub access_lists: Option>>, + #[serde(default, deserialize_with = "deserialize_authorization_lists")] + pub authorization_list: Option>, } #[derive(Debug, Deserialize)] @@ -331,4 +351,5 @@ pub struct EFTestTransaction { pub max_fee_per_blob_gas: Option, pub blob_versioned_hashes: Vec, pub access_list: Vec, + pub authorization_list: Option>, } diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index abfe127e0b..a4130c53ea 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -36,22 +36,8 @@ impl Environment { 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() } } } diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index d6d4d69b69..979198c4e8 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -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")] @@ -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, diff --git a/crates/vm/levm/src/utils.rs b/crates/vm/levm/src/utils.rs index d0c32d8ebd..ffebb9e396 100644 --- a/crates/vm/levm/src/utils.rs +++ b/crates/vm/levm/src/utils.rs @@ -104,5 +104,6 @@ pub fn new_vm_with_ops_addr_bal_db( Arc::new(db), cache, Vec::new(), + None, ) } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 62125929a7..2656b003d3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -62,6 +62,7 @@ pub struct VM { pub cache: CacheDB, pub tx_kind: TxKind, pub access_list: AccessList, + pub authorization_list: Option, } pub fn address_to_word(address: Address) -> U256 { @@ -88,6 +89,19 @@ pub struct AccessListItem { type AccessList = Vec<(Address, Vec)>; +type AuthorizationList = Vec; +// 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, VMError> { let mut valid_jump_destinations = HashSet::new(); let mut pc = 0; @@ -133,6 +147,7 @@ impl VM { db: Arc, mut cache: CacheDB, access_list: AccessList, + authorization_list: Option, ) -> Result { // Maybe this decision should be made in an upper layer @@ -204,6 +219,7 @@ impl VM { cache, tx_kind: to, access_list, + authorization_list, }) } TxKind::Create => { @@ -246,6 +262,7 @@ impl VM { cache, tx_kind: TxKind::Create, access_list, + authorization_list, }) } } diff --git a/crates/vm/levm/tests/tests.rs b/crates/vm/levm/tests/tests.rs index c178261a71..e68d5f6821 100644 --- a/crates/vm/levm/tests/tests.rs +++ b/crates/vm/levm/tests/tests.rs @@ -3891,6 +3891,7 @@ fn caller_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -3934,6 +3935,7 @@ fn origin_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -4004,6 +4006,7 @@ fn address_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -4051,6 +4054,7 @@ fn selfbalance_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -4095,6 +4099,7 @@ fn callvalue_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -4138,6 +4143,7 @@ fn codesize_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -4180,6 +4186,7 @@ fn gasprice_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); @@ -4238,6 +4245,7 @@ fn codecopy_op() { Arc::new(db), cache, Vec::new(), + None ) .unwrap(); diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index ac7d9b786e..196fc77693 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -141,6 +141,7 @@ cfg_if::cfg_if! { store_wrapper, CacheDB::new(), vec![], + None ) .map_err(EvmError::from)?; @@ -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() From 5900bda03c640469128cbfdf48f5aaeb5b10d858 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 12:10:49 -0300 Subject: [PATCH 2/4] chore: fmt --- crates/vm/levm/tests/tests.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/vm/levm/tests/tests.rs b/crates/vm/levm/tests/tests.rs index e68d5f6821..bae5a8dd98 100644 --- a/crates/vm/levm/tests/tests.rs +++ b/crates/vm/levm/tests/tests.rs @@ -3891,7 +3891,7 @@ fn caller_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -3935,7 +3935,7 @@ fn origin_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -4006,7 +4006,7 @@ fn address_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -4054,7 +4054,7 @@ fn selfbalance_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -4099,7 +4099,7 @@ fn callvalue_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -4143,7 +4143,7 @@ fn codesize_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -4186,7 +4186,7 @@ fn gasprice_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); @@ -4245,7 +4245,7 @@ fn codecopy_op() { Arc::new(db), cache, Vec::new(), - None + None, ) .unwrap(); From 3c6c05695eb6d1597907265d0de4e94f3cec9d56 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Mon, 20 Jan 2025 13:07:51 -0300 Subject: [PATCH 3/4] Update cmd/ef_tests/levm/runner/levm_runner.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- cmd/ef_tests/levm/runner/levm_runner.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 5a057e3fb6..44ee12e12b 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -89,10 +89,8 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result - let auth_list = list - .iter() + 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, @@ -103,12 +101,8 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result>(); - - Some(auth_list) - } else { - None - }; + .collect::>() + }); VM::new( tx.to.clone(), From a58512cd5288e4efa438f3154de21e0983e78366 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 13:08:37 -0300 Subject: [PATCH 4/4] pr_comments: implement suggestions --- crates/vm/levm/src/environment.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index a4130c53ea..b1e1ae8956 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -34,7 +34,6 @@ impl Environment { pub fn default_from_address(origin: Address) -> Self { Self { origin, - refunded_gas: 0, gas_limit: u64::MAX, chain_id: U256::one(), ..Default::default()