From d9d94a23ea97abce54052cc3211e13875a898441 Mon Sep 17 00:00:00 2001 From: enitrat Date: Thu, 12 Sep 2024 19:16:52 +0200 Subject: [PATCH 1/2] fix: access list deserializing" --- .../contracts/src/kakarot_core/kakarot.cairo | 56 +++++------ .../contracts/tests/test_kakarot_core.cairo | 3 +- crates/evm/src/backend/validation.cairo | 16 +++- .../src/instructions/memory_operations.cairo | 1 - .../src/instructions/system_operations.cairo | 2 +- crates/utils/src/errors.cairo | 39 +++----- crates/utils/src/eth_transaction.cairo | 2 +- .../utils/src/eth_transaction/eip1559.cairo | 2 +- .../utils/src/eth_transaction/eip2930.cairo | 2 +- .../src/eth_transaction/transaction.cairo | 2 +- crates/utils/src/rlp.cairo | 95 +++++++++---------- 11 files changed, 104 insertions(+), 116 deletions(-) diff --git a/crates/contracts/src/kakarot_core/kakarot.cairo b/crates/contracts/src/kakarot_core/kakarot.cairo index 1a6056655..1b88c7263 100644 --- a/crates/contracts/src/kakarot_core/kakarot.cairo +++ b/crates/contracts/src/kakarot_core/kakarot.cairo @@ -7,7 +7,7 @@ pub mod KakarotCore { use contracts::components::ownable::{ownable_component}; use contracts::components::upgradeable::{IUpgradeable, upgradeable_component}; use contracts::kakarot_core::interface::IKakarotCore; - use core::num::traits::{Zero, CheckedSub}; + use core::num::traits::Zero; use core::starknet::event::EventEmitter; use core::starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, @@ -19,12 +19,8 @@ pub mod KakarotCore { }; use evm::backend::starknet_backend; use evm::backend::validation::validate_eth_tx; - use evm::errors::{EVMError, ensure, EVMErrorTrait,}; - use evm::gas; use evm::model::account::AccountTrait; - use evm::model::{ - Message, TransactionResult, TransactionResultTrait, ExecutionSummaryTrait, Address - }; + use evm::model::{Message, TransactionResult, ExecutionSummaryTrait, Address}; use evm::precompiles::eth_precompile_addresses; use evm::state::StateTrait; use evm::{EVMTrait}; @@ -156,16 +152,24 @@ pub mod KakarotCore { core::panic_with_felt252('fn must be called, not invoked'); }; - let origin = Address { evm: origin, starknet: self.compute_starknet_address(origin) }; + let (gas_price, intrinsic_gas) = validate_eth_tx(self, tx); + + let starknet_caller_address = get_caller_address(); + let account = IAccountDispatcher { contract_address: starknet_caller_address }; + let origin = Address { + evm: account.get_evm_address(), starknet: starknet_caller_address + }; - let TransactionResult { success, return_data, gas_used, state: _ } = self - .process_transaction(origin, tx, tx.effective_gas_price(Option::None)); + let TransactionResult { success, return_data, gas_used, state: _state } = self + .process_transaction(origin, tx, gas_price, intrinsic_gas); (success, return_data, gas_used) } - fn eth_send_transaction(ref self: ContractState, tx: Transaction) -> (bool, Span, u64) { - let gas_price = validate_eth_tx(@self, tx); + fn eth_send_transaction( + ref self: ContractState, mut tx: Transaction + ) -> (bool, Span, u64) { + let (gas_price, intrinsic_gas) = validate_eth_tx(@self, tx); let starknet_caller_address = get_caller_address(); let account = IAccountDispatcher { contract_address: starknet_caller_address }; @@ -174,7 +178,7 @@ pub mod KakarotCore { }; let TransactionResult { success, return_data, gas_used, mut state } = self - .process_transaction(origin, tx, gas_price); + .process_transaction(origin, tx, gas_price, intrinsic_gas); starknet_backend::commit(ref state).expect('Committing state failed'); (success, return_data, gas_used) } @@ -271,34 +275,20 @@ pub mod KakarotCore { fn process_transaction( - self: @ContractState, origin: Address, tx: Transaction, gas_price: u128 + self: @ContractState, + origin: Address, + tx: Transaction, + gas_price: u128, + intrinsic_gas: u64 ) -> TransactionResult { - let gas_limit = tx.gas_limit(); + // Charge the cost of intrinsic gas - which has been verified to be <= gas_limit. + let gas_left = tx.gas_limit() - intrinsic_gas; let mut env = starknet_backend::get_env(origin.evm, gas_price); - // TX Gas - let gas_fee = gas_limit.into() * gas_price; let mut sender_account = env.state.get_account(origin.evm); - let sender_balance = sender_account.balance(); sender_account.set_nonce(sender_account.nonce() + 1); env.state.set_account(sender_account); - match ensure( - sender_balance >= gas_fee.into() + tx.value(), EVMError::InsufficientBalance - ) { - Result::Ok(_) => {}, - Result::Err(err) => { - return TransactionResultTrait::exceptional_failure(err.to_bytes(), gas_limit); - } - }; - let gas_left = match gas_limit.checked_sub(gas::calculate_intrinsic_gas_cost(@tx)) { - Option::Some(gas_left) => gas_left, - Option::None => { - return TransactionResultTrait::exceptional_failure( - EVMError::OutOfGas.to_bytes(), gas_limit - ); - } - }; // Handle deploy/non-deploy transaction cases let (to, is_deploy_tx, code, code_address, calldata) = match tx.kind() { TxKind::Create => { diff --git a/crates/contracts/tests/test_kakarot_core.cairo b/crates/contracts/tests/test_kakarot_core.cairo index 667a6f659..2e1b82460 100644 --- a/crates/contracts/tests/test_kakarot_core.cairo +++ b/crates/contracts/tests/test_kakarot_core.cairo @@ -330,7 +330,8 @@ fn test_process_transaction() { .process_transaction( origin: Address { evm: eoa_evm_address, starknet: eoa_starknet_address }, tx: Transaction::Legacy(tx), - :gas_price + :gas_price, + intrinsic_gas: 0 ); let return_data = result.return_data; diff --git a/crates/evm/src/backend/validation.cairo b/crates/evm/src/backend/validation.cairo index 8f288b686..574335cc1 100644 --- a/crates/evm/src/backend/validation.cairo +++ b/crates/evm/src/backend/validation.cairo @@ -4,13 +4,19 @@ use contracts::kakarot_core::KakarotCore; use core::ops::SnapshotDeref; use core::starknet::storage::{StoragePointerReadAccess}; use core::starknet::{get_caller_address, get_tx_info}; +use evm::gas; use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; use starknet::storage::StorageTrait; use utils::constants::POW_2_32; use utils::eth_transaction::get_effective_gas_price; use utils::eth_transaction::transaction::{Transaction, TransactionTrait}; -pub fn validate_eth_tx(kakarot_state: @KakarotCore::ContractState, tx: Transaction) -> u128 { +/// Validates the ethereum transaction by checking adherence to Ethereum rules regarding +/// Gas logic, nonce, chainId and required balance. +/// Returns +/// - Effective gas price of the transaction +/// - Intrinsic Gas Cost of the transcation +pub fn validate_eth_tx(kakarot_state: @KakarotCore::ContractState, tx: Transaction) -> (u128, u64) { let kakarot_storage = kakarot_state.snapshot_deref().storage(); // Validate transaction @@ -32,12 +38,16 @@ pub fn validate_eth_tx(kakarot_state: @KakarotCore::ContractState, tx: Transacti assert(account.get_nonce() == tx.nonce(), 'Invalid nonce'); // Validate gas - assert(tx.gas_limit() <= kakarot_state.get_block_gas_limit(), 'Tx gas > Block gas'); + let gas_limit = tx.gas_limit(); + assert(gas_limit <= kakarot_state.get_block_gas_limit(), 'Tx gas > Block gas'); let block_base_fee = kakarot_storage.Kakarot_base_fee.read(); let effective_gas_price = get_effective_gas_price( Option::Some(tx.max_fee_per_gas()), tx.max_priority_fee_per_gas(), block_base_fee.into() ); assert!(effective_gas_price.is_ok(), "{:?}", effective_gas_price.unwrap_err()); + // Intrinsic Gas + let intrinsic_gas = gas::calculate_intrinsic_gas_cost(@tx); + assert(gas_limit > intrinsic_gas, 'Intrinsic gas > gas limit'); // Validate balance let balance = IERC20CamelDispatcher { @@ -47,5 +57,5 @@ pub fn validate_eth_tx(kakarot_state: @KakarotCore::ContractState, tx: Transacti let max_gas_fee = tx.gas_limit().into() * tx.max_fee_per_gas(); let tx_cost = tx.value() + max_gas_fee.into(); assert(tx_cost <= balance, 'Not enough ETH'); - effective_gas_price.unwrap() + (effective_gas_price.unwrap(), intrinsic_gas) } diff --git a/crates/evm/src/instructions/memory_operations.cairo b/crates/evm/src/instructions/memory_operations.cairo index b9ca00069..659297291 100644 --- a/crates/evm/src/instructions/memory_operations.cairo +++ b/crates/evm/src/instructions/memory_operations.cairo @@ -320,7 +320,6 @@ mod tests { native_token }; use snforge_std::{test_address, start_mock_call}; - use utils::constants::EMPTY_KECCAK; use utils::helpers::U8SpanExTrait; use utils::helpers::compute_starknet_address; diff --git a/crates/evm/src/instructions/system_operations.cairo b/crates/evm/src/instructions/system_operations.cairo index 04f48cd79..7bfe4c8f5 100644 --- a/crates/evm/src/instructions/system_operations.cairo +++ b/crates/evm/src/instructions/system_operations.cairo @@ -853,7 +853,7 @@ mod tests { 0xf4, 0x00 ].span(); - let code_hash = bytecode.compute_keccak256_hash(); + let _code_hash = bytecode.compute_keccak256_hash(); let mut vm = VMBuilderTrait::new_with_presets().with_bytecode(bytecode).build(); let eoa_account = Account { address: vm.message().target, diff --git a/crates/utils/src/errors.cairo b/crates/utils/src/errors.cairo index 357817c28..24aa9d7ba 100644 --- a/crates/utils/src/errors.cairo +++ b/crates/utils/src/errors.cairo @@ -7,7 +7,13 @@ pub enum RLPError { EmptyInput, InputTooShort, InvalidInput, - Custom: felt252 + Custom: felt252, + NotAString, + FailedParsingU128, + FailedParsingU256, + FailedParsingAddress, + FailedParsingAccessList, + NotAList } @@ -17,7 +23,13 @@ pub impl RLPErrorIntoU256 of Into { RLPError::EmptyInput => 'input is null'.into(), RLPError::InputTooShort => 'input too short'.into(), RLPError::InvalidInput => 'rlp input not conform'.into(), - RLPError::Custom(msg) => msg.into() + RLPError::Custom(msg) => msg.into(), + RLPError::NotAString => 'rlp input is not a string'.into(), + RLPError::FailedParsingU128 => 'rlp failed parsing u128'.into(), + RLPError::FailedParsingU256 => 'rlp failed parsing u256'.into(), + RLPError::FailedParsingAddress => 'rlp failed parsing address'.into(), + RLPError::FailedParsingAccessList => 'rlp failed parsing access_list'.into(), + RLPError::NotAList => 'rlp input is not a list'.into() } } } @@ -32,35 +44,12 @@ pub impl RLPErrorImpl of RLPErrorTrait { } } - -#[derive(Drop, Copy, PartialEq, Debug)] -pub enum RLPHelpersError { - NotAString, - FailedParsingU128, - FailedParsingU256, - FailedParsingAddress, - FailedParsingAccessList, - NotAList -} - -#[generate_trait] -pub impl RLPHelpersErrorImpl of RLPHelpersErrorTrait { - fn map_err(self: Result) -> Result { - match self { - Result::Ok(val) => Result::Ok(val), - Result::Err(error) => { Result::Err(EthTransactionError::RlpHelpersError(error)) } - } - } -} - - #[derive(Drop, Copy, PartialEq, Debug)] pub enum EthTransactionError { RLPError: RLPError, ExpectedRLPItemToBeList, ExpectedRLPItemToBeString, TransactionTypeError, - RlpHelpersError: RLPHelpersError, // the usize represents the encountered length of payload TopLevelRlpListWrongLength: usize, // the usize represents the encountered length of payload diff --git a/crates/utils/src/eth_transaction.cairo b/crates/utils/src/eth_transaction.cairo index 1cf35294e..a51e83b38 100644 --- a/crates/utils/src/eth_transaction.cairo +++ b/crates/utils/src/eth_transaction.cairo @@ -9,7 +9,7 @@ use core::cmp::min; use core::num::traits::{CheckedAdd, Zero}; use core::option::OptionTrait; use core::starknet::{EthAddress, secp256_trait::Signature,}; -use utils::errors::{EthTransactionError, RLPErrorImpl, RLPHelpersErrorImpl}; +use utils::errors::{EthTransactionError, RLPErrorImpl}; use utils::helpers::ByteArrayExt; diff --git a/crates/utils/src/eth_transaction/eip1559.cairo b/crates/utils/src/eth_transaction/eip1559.cairo index de0fef5e4..21216806f 100644 --- a/crates/utils/src/eth_transaction/eip1559.cairo +++ b/crates/utils/src/eth_transaction/eip1559.cairo @@ -1,5 +1,5 @@ use core::num::traits::SaturatingSub; -use crate::errors::{EthTransactionError, RLPError, RLPHelpersErrorTrait}; +use crate::errors::{EthTransactionError, RLPError, RLPErrorTrait}; use crate::eth_transaction::common::TxKind; use crate::eth_transaction::eip2930::AccessListItem; use crate::rlp::{RLPItem, RLPHelpersTrait}; diff --git a/crates/utils/src/eth_transaction/eip2930.cairo b/crates/utils/src/eth_transaction/eip2930.cairo index d7fa8f985..c49eef230 100644 --- a/crates/utils/src/eth_transaction/eip2930.cairo +++ b/crates/utils/src/eth_transaction/eip2930.cairo @@ -1,5 +1,5 @@ use core::starknet::EthAddress; -use crate::errors::{EthTransactionError, RLPError, RLPHelpersErrorTrait}; +use crate::errors::{EthTransactionError, RLPError, RLPErrorTrait}; use crate::eth_transaction::common::TxKind; use crate::rlp::{RLPItem, RLPHelpersTrait}; use crate::traits::SpanDefault; diff --git a/crates/utils/src/eth_transaction/transaction.cairo b/crates/utils/src/eth_transaction/transaction.cairo index cb9d9571b..b7aa07ee8 100644 --- a/crates/utils/src/eth_transaction/transaction.cairo +++ b/crates/utils/src/eth_transaction/transaction.cairo @@ -1,5 +1,5 @@ use core::starknet::EthAddress; -use crate::errors::{RLPError, EthTransactionError, RLPErrorTrait, RLPHelpersErrorTrait}; +use crate::errors::{RLPError, EthTransactionError, RLPErrorTrait}; use crate::eth_transaction::common::{TxKind, TxKindTrait}; use crate::eth_transaction::eip1559::{TxEip1559, TxEip1559Trait}; use crate::eth_transaction::eip2930::{AccessListItem, TxEip2930, TxEip2930Trait}; diff --git a/crates/utils/src/rlp.cairo b/crates/utils/src/rlp.cairo index caccfb64e..2b93766dd 100644 --- a/crates/utils/src/rlp.cairo +++ b/crates/utils/src/rlp.cairo @@ -3,7 +3,7 @@ use core::array::SpanTrait; use core::option::OptionTrait; use core::panic_with_felt252; use core::starknet::EthAddress; -use crate::errors::{RLPError, RLPHelpersError}; +use crate::errors::{RLPError}; use crate::eth_transaction::eip2930::AccessListItem; use crate::helpers::{EthAddressExTrait, ArrayExtension, ToBytes, FromBytes}; @@ -202,7 +202,7 @@ pub impl RLPImpl of RLPTrait { #[generate_trait] pub impl RLPHelpersImpl of RLPHelpersTrait { - fn parse_u64_from_string(self: RLPItem) -> Result { + fn parse_u64_from_string(self: RLPItem) -> Result { match self { RLPItem::String(bytes) => { // Empty strings means 0 @@ -212,11 +212,11 @@ pub impl RLPHelpersImpl of RLPHelpersTrait { let value = bytes.from_be_bytes_partial().expect('parse_u64_from_string'); Result::Ok(value) }, - RLPItem::List(_) => { Result::Err(RLPHelpersError::NotAString) } + RLPItem::List(_) => { Result::Err(RLPError::NotAString) } } } - fn parse_u128_from_string(self: RLPItem) -> Result { + fn parse_u128_from_string(self: RLPItem) -> Result { match self { RLPItem::String(bytes) => { // Empty strings means 0 @@ -226,11 +226,11 @@ pub impl RLPHelpersImpl of RLPHelpersTrait { let value = bytes.from_be_bytes_partial().expect('parse_u128_from_string'); Result::Ok(value) }, - RLPItem::List(_) => { Result::Err(RLPHelpersError::NotAString) } + RLPItem::List(_) => { Result::Err(RLPError::NotAString) } } } - fn try_parse_address_from_string(self: RLPItem) -> Result, RLPHelpersError> { + fn try_parse_address_from_string(self: RLPItem) -> Result, RLPError> { match self { RLPItem::String(bytes) => { if bytes.len() == 0 { @@ -240,13 +240,13 @@ pub impl RLPHelpersImpl of RLPHelpersTrait { let value = EthAddressExTrait::from_bytes(bytes); return Result::Ok(Option::Some(value)); } - return Result::Err(RLPHelpersError::FailedParsingAddress); + return Result::Err(RLPError::FailedParsingAddress); }, - RLPItem::List(_) => { Result::Err(RLPHelpersError::NotAString) } + RLPItem::List(_) => { Result::Err(RLPError::NotAString) } } } - fn parse_u256_from_string(self: RLPItem) -> Result { + fn parse_u256_from_string(self: RLPItem) -> Result { match self { RLPItem::String(bytes) => { // Empty strings means 0 @@ -256,24 +256,24 @@ pub impl RLPHelpersImpl of RLPHelpersTrait { let value = bytes.from_be_bytes_partial().expect('parse_u256_from_string'); Result::Ok(value) }, - RLPItem::List(_) => { Result::Err(RLPHelpersError::NotAString) } + RLPItem::List(_) => { Result::Err(RLPError::NotAString) } } } - fn parse_bytes_from_string(self: RLPItem) -> Result, RLPHelpersError> { + fn parse_bytes_from_string(self: RLPItem) -> Result, RLPError> { match self { RLPItem::String(bytes) => { Result::Ok(bytes) }, - RLPItem::List(_) => { Result::Err(RLPHelpersError::NotAString) } + RLPItem::List(_) => { Result::Err(RLPError::NotAString) } } } - fn parse_storage_keys_from_rlp_item(self: RLPItem) -> Result, RLPHelpersError> { + fn parse_storage_keys_from_rlp_item(self: RLPItem) -> Result, RLPError> { match self { - RLPItem::String(_) => { return Result::Err(RLPHelpersError::NotAList); }, + RLPItem::String(_) => { return Result::Err(RLPError::NotAList); }, RLPItem::List(mut keys) => { let mut storage_keys: Array = array![]; - let storage_keys: Result, RLPHelpersError> = loop { + let storage_keys: Result, RLPError> = loop { match keys.pop_front() { Option::Some(rlp_item) => { let storage_key = match ((*rlp_item).parse_u256_from_string()) { @@ -292,36 +292,39 @@ pub impl RLPHelpersImpl of RLPHelpersTrait { } } - fn parse_access_list(self: RLPItem) -> Result, RLPHelpersError> { - match self { - RLPItem::String(_) => { Result::Err(RLPHelpersError::NotAList) }, - RLPItem::List(mut list) => { - let res: Result, RLPHelpersError> = loop { - let mut access_list: Array = array![]; - let list = match list.pop_front() { - Option::Some(rlp_item) => { - match rlp_item { - RLPItem::String(_) => { - break Result::Err(RLPHelpersError::NotAList); - }, - RLPItem::List(list) => *list, - } - }, - Option::None => { break Result::Ok(access_list.span()); } - }; + /// The data passed is in form + /// RLPItem::List([RLPItem::List([RLPItem::String(eth_address), RLPItem::List(storage_keys)]), + /// RLPItem::List([RLPItem::String(eth_address), RLPItem::List(storage_keys)])]) + fn parse_access_list(self: RLPItem) -> Result, RLPError> { + let mut list_of_accessed_tuples: Span = match self { + RLPItem::String(_) => { return Result::Err(RLPError::NotAList); }, + RLPItem::List(list) => list + }; - // since access list is a list of tuples of 2 elements - // accessList: Span<(EthAddress, Span)> - if (list.len() != 2) { - break Result::Err(RLPHelpersError::FailedParsingAccessList); - } + let mut parsed_access_list = array![]; + + // Iterate over the List of [Tuples (RLPString, RLPList)] representing all access list + // entries + let result = loop { + // Get the front Tuple (RLPString, RLPList) + let mut inner_tuple = match list_of_accessed_tuples.pop_front() { + Option::None => { break Result::Ok(parsed_access_list.span()); }, + Option::Some(inner_tuple) => match inner_tuple { + RLPItem::String(_) => { break Result::Err(RLPError::NotAList); }, + RLPItem::List(accessed_tuples) => *accessed_tuples + } + }; - let ethereum_address = match ((*list.at(0)).try_parse_address_from_string()) { + match inner_tuple.multi_pop_front::<2>() { + Option::None => { break Result::Err(RLPError::InputTooShort); }, + Option::Some(inner_tuple) => { + let [rlp_address, rlp_keys] = (*inner_tuple).unbox(); + let ethereum_address = match rlp_address.try_parse_address_from_string() { Result::Ok(maybe_eth_address) => { match (maybe_eth_address) { Option::Some(eth_address) => { eth_address }, Option::None => { - break Result::Err(RLPHelpersError::FailedParsingAccessList); + break Result::Err(RLPError::FailedParsingAccessList); } } }, @@ -329,19 +332,15 @@ pub impl RLPHelpersImpl of RLPHelpersTrait { }; let storage_keys: Span = - match (*list.at(1)).parse_storage_keys_from_rlp_item() { + match rlp_keys.parse_storage_keys_from_rlp_item() { Result::Ok(storage_keys) => storage_keys, Result::Err(err) => { break Result::Err(err); } }; - - access_list.append(AccessListItem { ethereum_address, storage_keys }); - - break Result::Ok(access_list.span()); - }; - - res + parsed_access_list.append(AccessListItem { ethereum_address, storage_keys }); + } } - } + }; + result } } From 14dfd53ee1bcd4134b88253347c2a900304a7d3f Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 13 Sep 2024 09:49:12 +0200 Subject: [PATCH 2/2] add test for access list pasing --- .../contracts/src/kakarot_core/kakarot.cairo | 10 +- crates/utils/src/rlp.cairo | 241 +++++++++++++++--- 2 files changed, 206 insertions(+), 45 deletions(-) diff --git a/crates/contracts/src/kakarot_core/kakarot.cairo b/crates/contracts/src/kakarot_core/kakarot.cairo index 1b88c7263..a35d41802 100644 --- a/crates/contracts/src/kakarot_core/kakarot.cairo +++ b/crates/contracts/src/kakarot_core/kakarot.cairo @@ -152,16 +152,10 @@ pub mod KakarotCore { core::panic_with_felt252('fn must be called, not invoked'); }; - let (gas_price, intrinsic_gas) = validate_eth_tx(self, tx); - - let starknet_caller_address = get_caller_address(); - let account = IAccountDispatcher { contract_address: starknet_caller_address }; - let origin = Address { - evm: account.get_evm_address(), starknet: starknet_caller_address - }; + let origin = Address { evm: origin, starknet: self.compute_starknet_address(origin) }; let TransactionResult { success, return_data, gas_used, state: _state } = self - .process_transaction(origin, tx, gas_price, intrinsic_gas); + .process_transaction(origin, tx, tx.effective_gas_price(Option::None), 0); (success, return_data, gas_used) } diff --git a/crates/utils/src/rlp.cairo b/crates/utils/src/rlp.cairo index 2b93766dd..4dd6256df 100644 --- a/crates/utils/src/rlp.cairo +++ b/crates/utils/src/rlp.cairo @@ -2486,58 +2486,225 @@ mod tests { assert!(res.unwrap_err() == RLPError::InputTooShort); } + #[test] + fn test_rlp_item_parse_access_list_empty() { + let rlp_encoded_access_list: Span = [0xc0].span(); + let decoded_data = RLPTrait::decode(rlp_encoded_access_list).unwrap(); + assert_eq!(decoded_data.len(), 1); + + let rlp_item = *decoded_data[0]; + let res = rlp_item.parse_access_list().unwrap(); + assert_eq!(res.len(), 0); + } + #[test] fn test_rlp_item_parse_access_list() { - // [ [ "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", [ "0x01", "0x02", "0x03", "0x04", - // "0x05" ] ]] + // (('0x0000000000000000000000000000000000000001', + // ('0x0100000000000000000000000000000000000000000000000000000000000000',)), + // ('0x0000000000000000000000000000000000000002', + // ('0x0100000000000000000000000000000000000000000000000000000000000000', + // '0x0200000000000000000000000000000000000000000000000000000000000000')), + // ('0x0000000000000000000000000000000000000003', ())) let rlp_encoded_access_list: Span = [ - 220, - 219, + 248, + 170, + 247, 148, - 31, - 152, - 64, - 168, - 93, - 90, - 245, - 191, - 29, - 23, - 98, - 249, - 37, - 189, - 173, - 220, - 66, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 1, - 249, - 132, - 197, + 225, + 160, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 248, + 89, + 148, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 248, + 66, + 160, 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 160, 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 214, + 148, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 3, - 4, - 5 + 192 ].span(); let decoded_data = RLPTrait::decode(rlp_encoded_access_list).unwrap(); assert_eq!(decoded_data.len(), 1); let rlp_item = *decoded_data[0]; - let expected_access_list_item = AccessListItem { - ethereum_address: 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984.try_into().unwrap(), - storage_keys: [ - 0x1, 0x2, 0x3, 0x4, 0x5 - ].span() - }; - - let expected_access_list = [expected_access_list_item].span(); + let expected_access_list = [ + AccessListItem { + ethereum_address: 0x0000000000000000000000000000000000000001.try_into().unwrap(), + storage_keys: [ + 0x0100000000000000000000000000000000000000000000000000000000000000 + ].span() + }, + AccessListItem { + ethereum_address: 0x0000000000000000000000000000000000000002.try_into().unwrap(), + storage_keys: [ + 0x0100000000000000000000000000000000000000000000000000000000000000, + 0x0200000000000000000000000000000000000000000000000000000000000000 + ].span() + }, + AccessListItem { + ethereum_address: 0x0000000000000000000000000000000000000003.try_into().unwrap(), + storage_keys: [].span() + } + ].span(); let res = rlp_item.parse_access_list().unwrap(); - assert_eq!(res.len(), 1); - - assert!(res == expected_access_list, "access list are not equal"); + assert!(res == expected_access_list); } }