From 9966a9741b11a3484911d7268477d0ea847e6c8f Mon Sep 17 00:00:00 2001 From: Oba Date: Thu, 25 Jul 2024 15:48:28 +0200 Subject: [PATCH] feat: execute from outside (#723) * feat: use execute_from_outside entrypoint for tx * feat: remove ACCOUNT_CAIRO1_HELPERS_CLASS * feat: nonce is increased after validation only * fix: wrong arguments * Update crates/ef-testing/src/evm_sequencer/utils.rs Co-authored-by: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> * fix: use relayer nonce for starknet tx * style: ignore trunk warning due to flags * test: increase execute_before OutsideExecution * style: fix warnings * fix: implement Default EVMoutput success was always false due to its default value * refactor: remove unecessary into * fix: use feature flags and improve readiblity * fix: v1 compilation * refactor: make RELAYER_ADDRESS identifiable * refactor: remove unecessary comment * style: remove new line --------- Co-authored-by: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> --- .../ef-testing/src/evm_sequencer/constants.rs | 21 ++- .../src/evm_sequencer/evm_state/v0.rs | 28 ++-- .../src/evm_sequencer/evm_state/v1.rs | 12 +- .../src/evm_sequencer/sequencer/v0.rs | 18 ++- crates/ef-testing/src/evm_sequencer/utils.rs | 136 +++++++++++++----- crates/ef-testing/src/models/case.rs | 29 ++-- crates/ef-testing/src/models/result.rs | 12 +- 7 files changed, 180 insertions(+), 76 deletions(-) diff --git a/crates/ef-testing/src/evm_sequencer/constants.rs b/crates/ef-testing/src/evm_sequencer/constants.rs index fff2f3c4..ca080506 100644 --- a/crates/ef-testing/src/evm_sequencer/constants.rs +++ b/crates/ef-testing/src/evm_sequencer/constants.rs @@ -3,14 +3,16 @@ use std::collections::HashMap; use lazy_static::lazy_static; use reth_primitives::alloy_primitives::{address, Address}; use serde::de::DeserializeOwned; -use starknet::core::types::contract::legacy::LegacyContractClass; use starknet::core::types::contract::CompiledClass; use starknet_api::felt; +use starknet::signers::VerifyingKey; +use starknet::{core::types::contract::legacy::LegacyContractClass, signers::SigningKey}; use starknet_api::{ contract_address, core::{ClassHash, ContractAddress, PatriciaKey}, patricia_key, }; +use starknet_crypto::Felt; fn load_contract_class(path: &str) -> Result where @@ -50,6 +52,7 @@ lazy_static! { pub static ref STRK_FEE_TOKEN_ADDRESS: ContractAddress = contract_address!("0xCa14007Eff0dB1f8135f4C25B34De49AB0d42766"); pub static ref KAKAROT_ADDRESS: ContractAddress = ContractAddress(1_u128.into()); pub static ref KAKAROT_OWNER_ADDRESS: ContractAddress = ContractAddress(2_u128.into()); + pub static ref RELAYER_ADDRESS: ContractAddress = ContractAddress(3_u128.into()); pub static ref FEE_TOKEN_CLASS: LegacyContractClass = load_contract_class("../../build/common/ERC20.json").expect("Failed to load FeeToken contract class"); pub static ref FEE_TOKEN_CLASS_HASH: ClassHash = ClassHash(FEE_TOKEN_CLASS.class_hash().unwrap()); @@ -57,6 +60,10 @@ lazy_static! { pub static ref CAIRO1_HELPERS_CLASS: CompiledClass = load_contract_class("../../build/common/cairo1_helpers.json").expect("Failed to load precompiles contract class"); pub static ref CAIRO1_HELPERS_CLASS_HASH: ClassHash = ClassHash(CAIRO1_HELPERS_CLASS.class_hash().unwrap()); + pub static ref RELAYER_SIGNING_KEY: SigningKey = SigningKey::from_random(); + pub static ref RELAYER_VERIFYING_KEY: VerifyingKey = RELAYER_SIGNING_KEY.verifying_key(); + pub static ref RELAYER_BALANCE: Felt = Felt::from(1_000_000_000_000_000_000_000_000u128); + } #[cfg(feature = "v0")] @@ -65,11 +72,13 @@ lazy_static! { pub static ref KAKAROT_CLASS: LegacyContractClass = load_contract_class("../../build/v0/kakarot.json").expect("Failed to load Kakarot contract class"); pub static ref ACCOUNT_CONTRACT_CLASS: LegacyContractClass = load_contract_class("../../build/v0/account_contract.json").expect("Failed to load ContractAccount contract class"); pub static ref UNINITIALIZED_ACCOUNT_CLASS: LegacyContractClass = load_contract_class("../../build/v0/uninitialized_account.json").expect("Failed to load uninitialized account c contract class"); + pub static ref OPENZEPPELIN_ACCOUNT_CLASS: LegacyContractClass = load_contract_class("../../build/v0/OpenzeppelinAccount.json").expect("Failed to load openzeppelin account contract class"); // Main class hashes pub static ref KAKAROT_CLASS_HASH: ClassHash = ClassHash(KAKAROT_CLASS.class_hash().unwrap()); pub static ref ACCOUNT_CONTRACT_CLASS_HASH: ClassHash = ClassHash(ACCOUNT_CONTRACT_CLASS.class_hash().unwrap()); pub static ref UNINITIALIZED_ACCOUNT_CLASS_HASH: ClassHash = ClassHash(UNINITIALIZED_ACCOUNT_CLASS.class_hash().unwrap()); + pub static ref OPENZEPPELIN_ACCOUNT_CLASS_HASH: ClassHash = ClassHash(OPENZEPPELIN_ACCOUNT_CLASS.class_hash().unwrap()); } #[cfg(feature = "v1")] @@ -107,9 +116,9 @@ pub mod storage_variables { pub const ACCOUNT_NONCE: &str = "Account_nonce"; pub const ACCOUNT_KAKAROT_ADDRESS: &str = "Account_kakarot_address"; pub const ACCOUNT_IMPLEMENTATION: &str = "Account_implementation"; - pub const ACCOUNT_CAIRO1_HELPERS_CLASS: &str = "Account_cairo1_helpers_class_hash"; - pub const ACCOUNT_VALID_JUMPDESTS: &str = "Account_valid_jumpdests"; - pub const ACCOUNT_JUMPDESTS_INITIALIZED: &str = "Account_jumpdests_initialized"; + pub const ACCOUNT_VALID_JUMPDESTS : &str = "Account_valid_jumpdests"; + pub const ACCOUNT_JUMPDESTS_INITIALIZED : &str = "Account_jumpdests_initialized"; + pub const ACCOUNT_PUBLIC_KEY: &str = "Account_public_key"; pub const KAKAROT_COINBASE: &str = "Kakarot_coinbase"; pub const KAKAROT_BASE_FEE: &str = "Kakarot_base_fee"; @@ -123,6 +132,8 @@ pub mod storage_variables { pub const KAKAROT_PREV_RANDAO: &str = "Kakarot_prev_randao"; pub const OWNABLE_OWNER: &str = "Ownable_owner"; + + pub const ERC20_BALANCES: &str = "ERC20_balances"; } #[cfg(test)] @@ -141,4 +152,4 @@ pub mod tests { pub static ref TEST_CONTRACT_ADDRESS: Address = Address::left_padding_from(&0xdeadbeefu64.to_be_bytes()); } -} +} \ No newline at end of file diff --git a/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs b/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs index f338c9fc..3506a0d7 100644 --- a/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs +++ b/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs @@ -13,11 +13,11 @@ use starknet_api::state::StorageKey; use super::Evm; use crate::evm_sequencer::account::KakarotAccount; use crate::evm_sequencer::constants::storage_variables::{ - ACCOUNT_BYTECODE_LEN, ACCOUNT_CAIRO1_HELPERS_CLASS, ACCOUNT_IMPLEMENTATION, ACCOUNT_NONCE, - ACCOUNT_STORAGE, KAKAROT_BASE_FEE, KAKAROT_BLOCK_GAS_LIMIT, KAKAROT_COINBASE, - KAKAROT_EVM_TO_STARKNET_ADDRESS, KAKAROT_PREV_RANDAO, OWNABLE_OWNER, + ACCOUNT_BYTECODE_LEN, ACCOUNT_IMPLEMENTATION, ACCOUNT_NONCE, ACCOUNT_STORAGE, KAKAROT_BASE_FEE, + KAKAROT_BLOCK_GAS_LIMIT, KAKAROT_COINBASE, KAKAROT_EVM_TO_STARKNET_ADDRESS, + KAKAROT_PREV_RANDAO, OWNABLE_OWNER, }; -use crate::evm_sequencer::constants::ETH_FEE_TOKEN_ADDRESS; +use crate::evm_sequencer::constants::{ETH_FEE_TOKEN_ADDRESS, RELAYER_ADDRESS}; use crate::evm_sequencer::sequencer::KakarotSequencer; use crate::evm_sequencer::types::felt::FeltSequencer; use crate::evm_sequencer::utils::{felt_to_bytes, split_u256, to_broadcasted_starknet_transaction}; @@ -93,10 +93,6 @@ impl Evm for KakarotSequencer { ACCOUNT_IMPLEMENTATION, self.environment.account_contract_class_hash.0 ), - starknet_storage!( - ACCOUNT_CAIRO1_HELPERS_CLASS, - self.environment.cairo1_helpers_class_hash.0 - ), // both EOA and CA CH are the same (for now) starknet_storage!(OWNABLE_OWNER, *self.environment.kakarot_address.0.key()), ]); @@ -251,11 +247,17 @@ impl Evm for KakarotSequencer { } })?; let starknet_address = self.compute_starknet_address(&evm_address)?; + let relayer_nonce = self.state_mut().get_nonce_at(*RELAYER_ADDRESS).unwrap(); let starknet_transaction = BroadcastedTransactionWrapper::new(BroadcastedTransaction::Invoke( - to_broadcasted_starknet_transaction(&transaction, *starknet_address.0.key()) - .map_err(|err| TransactionExecutionError::ValidateTransactionError { + to_broadcasted_starknet_transaction( + &transaction, + Felt::from(starknet_address), + relayer_nonce.0.into(), + ) + .map_err(|err| { + TransactionExecutionError::ValidateTransactionError { error: EntryPointExecutionError::InvalidExecutionInput { input_descriptor: String::from("Signed transaction"), info: err.to_string(), @@ -263,7 +265,8 @@ impl Evm for KakarotSequencer { class_hash: Default::default(), storage_address: Default::default(), selector: Default::default(), - })?, + } + })?, )); let chain_id = self.chain_id(); @@ -312,7 +315,7 @@ mod tests { coinbase_address, CHAIN_ID, 0, - 0, + 1, ); let mut transaction = TransactionSigned { @@ -349,7 +352,6 @@ mod tests { sequencer.setup_account(contract).unwrap(); sequencer.setup_account(eoa).unwrap(); let execution_result = sequencer.execute_transaction(transaction); - // Update the output with the execution result of the current transaction let tx_output = extract_output_and_log_execution_result( &execution_result, diff --git a/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs b/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs index 08023378..c41be0ec 100644 --- a/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs +++ b/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs @@ -284,8 +284,13 @@ impl Evm for KakarotSequencer { let starknet_transaction = BroadcastedTransactionWrapper::new(BroadcastedTransaction::Invoke( - to_broadcasted_starknet_transaction(&transaction, *starknet_address.0.key()) - .map_err(|err| TransactionExecutionError::ValidateTransactionError { + to_broadcasted_starknet_transaction( + &transaction, + Felt::from(starknet_address), + None, + ) + .map_err(|err| { + TransactionExecutionError::ValidateTransactionError { error: EntryPointExecutionError::InvalidExecutionInput { input_descriptor: String::from("Failed to convert transaction"), info: err.to_string(), @@ -293,7 +298,8 @@ impl Evm for KakarotSequencer { class_hash: Default::default(), storage_address: Default::default(), selector: Default::default(), - })?, + } + })?, )); let chain_id = self.chain_id(); diff --git a/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs b/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs index dc94b045..4cff2392 100644 --- a/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs +++ b/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs @@ -1,14 +1,16 @@ use crate::evm_sequencer::{ constants::{ storage_variables::{ - KAKAROT_ACCOUNT_CONTRACT_CLASS_HASH, KAKAROT_BLOCK_GAS_LIMIT, - KAKAROT_CAIRO1_HELPERS_CLASS_HASH, KAKAROT_NATIVE_TOKEN_ADDRESS, - KAKAROT_UNINITIALIZED_ACCOUNT_CLASS_HASH, OWNABLE_OWNER, + ACCOUNT_PUBLIC_KEY, ERC20_BALANCES, KAKAROT_ACCOUNT_CONTRACT_CLASS_HASH, + KAKAROT_BLOCK_GAS_LIMIT, KAKAROT_CAIRO1_HELPERS_CLASS_HASH, + KAKAROT_NATIVE_TOKEN_ADDRESS, KAKAROT_UNINITIALIZED_ACCOUNT_CLASS_HASH, OWNABLE_OWNER, }, ACCOUNT_CONTRACT_CLASS, ACCOUNT_CONTRACT_CLASS_HASH, BLOCK_GAS_LIMIT, CAIRO1_HELPERS_CLASS, CAIRO1_HELPERS_CLASS_HASH, ETH_FEE_TOKEN_ADDRESS, FEE_TOKEN_CLASS, FEE_TOKEN_CLASS_HASH, KAKAROT_ADDRESS, KAKAROT_CLASS, KAKAROT_CLASS_HASH, KAKAROT_OWNER_ADDRESS, - UNINITIALIZED_ACCOUNT_CLASS, UNINITIALIZED_ACCOUNT_CLASS_HASH, + OPENZEPPELIN_ACCOUNT_CLASS, OPENZEPPELIN_ACCOUNT_CLASS_HASH, RELAYER_ADDRESS, + RELAYER_BALANCE, RELAYER_VERIFYING_KEY, UNINITIALIZED_ACCOUNT_CLASS, + UNINITIALIZED_ACCOUNT_CLASS_HASH, }, sequencer::{convert_contract_class_v0, convert_contract_class_v1}, }; @@ -59,6 +61,14 @@ lazy_static! { (&mut state).set_class_hash_at(*ETH_FEE_TOKEN_ADDRESS, *FEE_TOKEN_CLASS_HASH).expect("failed to set fee token class hash"); (&mut state).set_contract_class(*CAIRO1_HELPERS_CLASS_HASH, convert_contract_class_v1(&CAIRO1_HELPERS_CLASS).expect("failed to convert CAIRO1_HELPERS Class to contract class")).expect("failed to set cairo1_helpers contract class"); + (&mut state).set_contract_class( + *OPENZEPPELIN_ACCOUNT_CLASS_HASH, + convert_contract_class_v0(&OPENZEPPELIN_ACCOUNT_CLASS).expect("failed to convert OPENZEPPELIN ACCOUNT CLASS to contract class") + ).expect("failed to set openzeppelin account contract class"); + (&mut state).set_class_hash_at(*RELAYER_ADDRESS, *OPENZEPPELIN_ACCOUNT_CLASS_HASH).expect("failed to set relayer class hash"); + (&mut state).set_storage_at(*RELAYER_ADDRESS, get_storage_var_address(ACCOUNT_PUBLIC_KEY, &[]), RELAYER_VERIFYING_KEY.scalar().into()).expect("failed to set relayer public key"); + (&mut state).set_storage_at(*ETH_FEE_TOKEN_ADDRESS, get_storage_var_address(ERC20_BALANCES, &[*RELAYER_ADDRESS.0.key()]), *RELAYER_BALANCE).expect("failed to set relayer balance"); + state }; } diff --git a/crates/ef-testing/src/evm_sequencer/utils.rs b/crates/ef-testing/src/evm_sequencer/utils.rs index c5c283ac..1dcde991 100644 --- a/crates/ef-testing/src/evm_sequencer/utils.rs +++ b/crates/ef-testing/src/evm_sequencer/utils.rs @@ -38,13 +38,16 @@ pub fn felt_to_bytes(felt: &Felt, start: usize) -> Bytes { } /// Converts an signed transaction and a signature to a Starknet-rs transaction. +#[allow(unused_variables)] // necessary for starknet_address which is behind a flag pub fn to_broadcasted_starknet_transaction( transaction: &TransactionSigned, - signer_starknet_address: Felt, + starknet_address: Felt, + relayer_nonce: Option, ) -> Result { let mut bytes = BytesMut::new(); transaction.transaction.encode_without_signature(&mut bytes); + #[allow(unused_mut)] let mut calldata: Vec = { // Pack the calldata in 31-byte chunks. #[cfg(feature = "v0")] @@ -62,27 +65,64 @@ pub fn to_broadcasted_starknet_transaction( } }; - let mut execute_calldata = { + let signature = transaction.signature(); + let [r_low, r_high] = split_u256(signature.r); + let [s_low, s_high] = split_u256(signature.s); + let v = match transaction.transaction.tx_type() { + TxType::Legacy => signature.v(transaction.chain_id()), + _ => signature.odd_y_parity as u64, + }; + + #[allow(unused_mut)] + let mut signature: Vec = vec![ + r_low.into(), + r_high.into(), + s_low.into(), + s_high.into(), + v.into(), + ]; + + let execute_calldata = { #[cfg(feature = "v0")] { + use super::constants::RELAYER_ADDRESS; use crate::evm_sequencer::constants::KAKAROT_ADDRESS; - vec![ - Felt::ONE, // call array length - *KAKAROT_ADDRESS.0.key(), // contract address - selector!("eth_send_transaction"), // selector - Felt::ZERO, // data offset - calldata.len().into(), // data length - calldata.len().into(), // calldata length - ] + + let mut execute_from_outside_calldata = vec![ + *RELAYER_ADDRESS.0.key(), // OutsideExecution caller + Felt::ZERO, // OutsideExecution nonce + Felt::ZERO, // OutsideExecution execute_after + Felt::from(10_000_000_000_000u128), // OutsideExecution execute_before + Felt::ONE, // call_array_len + *KAKAROT_ADDRESS.0.key(), // CallArray to + selector!("eth_send_transaction"), // CallArray selector + Felt::ZERO, // CallArray data_offset + calldata.len().into(), // CallArray data_len + calldata.len().into(), // calldata_len + ]; + execute_from_outside_calldata.append(&mut calldata); + execute_from_outside_calldata.push(signature.len().into()); + execute_from_outside_calldata.append(&mut signature); + + let mut execute_entrypoint_calldata = vec![ + Felt::ONE, // call_array_len + starknet_address, // CallArray to + selector!("execute_from_outside"), // CallArray selector + Felt::ZERO, // CallArray data_offset + (execute_from_outside_calldata.len()).into(), // CallArraydata data_len + (execute_from_outside_calldata.len()).into(), // calldata length + ]; + execute_entrypoint_calldata.append(&mut execute_from_outside_calldata); + execute_entrypoint_calldata } #[cfg(feature = "v1")] { use crate::evm_sequencer::constants::KAKAROT_ADDRESS; vec![ - Felt::ONE, // call array length - *KAKAROT_ADDRESS.0.key(), // contract address - selector!("eth_send_transaction"), // selector - calldata.len().into(), // calldata length + Felt::ONE, // call_array_len + *KAKAROT_ADDRESS.0.key(), // CallArray to + selector!("eth_send_transaction"), // CallArray selector + calldata.len().into(), // CallArray data_len ] } #[cfg(not(any(feature = "v0", feature = "v1")))] @@ -90,31 +130,53 @@ pub fn to_broadcasted_starknet_transaction( vec![] } }; - execute_calldata.append(&mut calldata); - let signature = transaction.signature(); - let [r_low, r_high] = split_u256(signature.r); - let [s_low, s_high] = split_u256(signature.s); - let v = match transaction.transaction.tx_type() { - TxType::Legacy => signature.v(transaction.chain_id()), - _ => signature.odd_y_parity as u64, + let request = { + #[cfg(feature = "v0")] + { + use super::constants::{RELAYER_ADDRESS, RELAYER_SIGNING_KEY}; + use starknet::core::crypto::compute_hash_on_elements; + + let relayer_address = *RELAYER_ADDRESS.0.key(); + let relayer_nonce = relayer_nonce.expect("Relayer nonce not provided"); + let invoke_v1_tx = vec![ + Felt::from_bytes_be_slice(b"invoke"), // "invoke" + Felt::ONE, // version + relayer_address, // sender_address + Felt::ZERO, // 0 + compute_hash_on_elements(&execute_calldata), // h(calldata) + Felt::ZERO, // max_fee + transaction.chain_id().unwrap().into(), // chain_id + relayer_nonce, // nonce + ]; + let transaction_hash = compute_hash_on_elements(&invoke_v1_tx); + let signature_relayer = RELAYER_SIGNING_KEY + .sign(&transaction_hash) + .expect("Signature starknet failed"); + let signature_relayer = vec![signature_relayer.r, signature_relayer.s]; + + BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: Felt::ZERO, + signature: signature_relayer, + nonce: relayer_nonce, + sender_address: relayer_address, + calldata: execute_calldata, + is_query: false, + }) + } + #[cfg(not(feature = "v0"))] + { + let nonce = Felt::from(transaction.nonce()); + BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: Felt::ZERO, + signature, + nonce, + sender_address: starknet_address, + calldata: execute_calldata, + is_query: false, + }) + } }; - let signature = vec![ - r_low.into(), - r_high.into(), - s_low.into(), - s_high.into(), - v.into(), - ]; - - let request = BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { - max_fee: Felt::ZERO, - signature, - nonce: transaction.nonce().into(), - sender_address: signer_starknet_address, - calldata: execute_calldata, - is_query: false, - }); Ok(request) } diff --git a/crates/ef-testing/src/models/case.rs b/crates/ef-testing/src/models/case.rs index 0a018d88..05353338 100644 --- a/crates/ef-testing/src/models/case.rs +++ b/crates/ef-testing/src/models/case.rs @@ -21,7 +21,6 @@ use ef_tests::models::Block; use ef_tests::models::State; use std::collections::BTreeMap; -use ethers_signers::{LocalWallet, Signer}; use reth_primitives::{sign_message, Address, SealedBlock, B256, U256}; #[derive(Debug)] @@ -113,14 +112,7 @@ impl BlockchainTestCase { sequencer: &mut KakarotSequencer, output: EVMOutput, ) -> Result<(), RunnerError> { - let wallet = LocalWallet::from_bytes(&self.secret_key.0) - .map_err(|err| RunnerError::Other(vec![err.to_string()].into()))?; - let sender_address = wallet.address().to_fixed_bytes(); - let maybe_revert_reason = String::from_utf8(output.return_data.as_slice().to_vec()); - let eth_validation_failed = maybe_revert_reason.as_ref().map_or(false, |revert_reason| { - revert_reason == "Kakarot: eth validation failed" - }); // Get gas_used and base_fee from RLP block - as in some cases, the block header is not present in the test data. let sealed_block = SealedBlock::decode(&mut self.block.rlp.as_ref()) @@ -189,13 +181,24 @@ impl BlockchainTestCase { } // Nonce + #[allow(unused_mut)] let mut actual = sequencer.nonce_at(address)?; - // If the transaction failed during ethereum validation, performed in __execute__, the nonce is incremented but should not. - // Substract 1 to the actual nonce. - if eth_validation_failed && address.0 == sender_address { - actual -= U256::from(1); + #[cfg(feature = "v1")] + { + use ethers_signers::{LocalWallet, Signer}; + let wallet = LocalWallet::from_bytes(&self.secret_key.0) + .map_err(|err| RunnerError::Other(vec![err.to_string()].into()))?; + let sender_address = wallet.address().to_fixed_bytes(); + let eth_validation_failed = + maybe_revert_reason.as_ref().map_or(false, |revert_reason| { + revert_reason == "Kakarot: eth validation failed" + }); + // If the transaction failed during ethereum validation, performed in __execute__, the nonce is incremented but should not. + // Substract 1 to the actual nonce. + if eth_validation_failed && address.0 == sender_address { + actual -= U256::from(1); + } } - if actual != expected_state.nonce { let nonce_diff = format!( "nonce mismatch for {:#20x}: expected {:#32x}, got {:#32x}", diff --git a/crates/ef-testing/src/models/result.rs b/crates/ef-testing/src/models/result.rs index 029fbbf2..c4afddbe 100644 --- a/crates/ef-testing/src/models/result.rs +++ b/crates/ef-testing/src/models/result.rs @@ -9,7 +9,7 @@ use tracing::{error, info, warn}; use std::convert::TryFrom; -#[derive(Default, Debug)] +#[derive(Debug)] pub struct EVMOutput { pub return_data: Vec, pub gas_used: u64, @@ -24,6 +24,16 @@ impl EVMOutput { } } +impl Default for EVMOutput { + fn default() -> Self { + Self { + return_data: vec![], + gas_used: 0, + success: true, + } + } +} + impl TryFrom<&EventData> for EVMOutput { type Error = eyre::Report;