Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: skip nonce increment when eth validation failed in __execute__ #653

Merged
merged 6 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions crates/ef-testing/src/models/case.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Inspired by https://github.com/paradigmxyz/reth/tree/main/testing/ef-tests
use super::error::RunnerError;
use super::result::log_execution_result;
use super::result::{extract_execution_retdata, log_execution_result};
use crate::evm_sequencer::constants::{
CONTRACT_ACCOUNT_CLASS_HASH, EOA_CLASS_HASH, KAKAROT_ADDRESS, PROXY_CLASS_HASH,
};
Expand Down Expand Up @@ -74,7 +74,10 @@ impl BlockchainTestCase {
Ok(())
}

fn handle_transaction(&self, sequencer: &mut KakarotSequencer) -> Result<(), RunnerError> {
fn handle_transaction(
&self,
sequencer: &mut KakarotSequencer,
) -> Result<Option<String>, RunnerError> {
// we extract the transaction from the block
let block = &self.block;
let block =
Expand All @@ -92,16 +95,28 @@ impl BlockchainTestCase {
tx_signed.signature = signature;

let execution_result = sequencer.execute_transaction(tx_signed);
log_execution_result(execution_result, &self.case_name, &self.case_category);
log_execution_result(&execution_result, &self.case_name, &self.case_category);

Ok(())
let retdata = execution_result
.map(extract_execution_retdata)
.unwrap_or_default();

Ok(retdata)
}

fn handle_post_state(&self, sequencer: &mut KakarotSequencer) -> Result<(), RunnerError> {
fn handle_post_state(
&self,
sequencer: &mut KakarotSequencer,
retdata: Option<String>,
) -> 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 eth_validation_failed = retdata
.map(|retdata| retdata == "Kakarot: eth validation failed")
.unwrap_or_default();

let maybe_block_header = self.block.block_header.as_ref();
// Get gas used from block header
let gas_used = maybe_block_header
Expand Down Expand Up @@ -167,7 +182,13 @@ impl BlockchainTestCase {
}

// Nonce
let actual = sequencer.nonce_at(address)?;
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);
}

if actual != expected_state.nonce.0 {
let nonce_diff = format!(
"nonce mismatch for {:#20x}: expected {:#32x}, got {:#32x}",
Expand Down Expand Up @@ -252,9 +273,9 @@ impl Case for BlockchainTestCase {

self.handle_pre_state(&mut sequencer)?;

self.handle_transaction(&mut sequencer)?;
let retdata = self.handle_transaction(&mut sequencer)?;

self.handle_post_state(&mut sequencer)?;
self.handle_post_state(&mut sequencer, retdata)?;
Ok(())
}
}
32 changes: 27 additions & 5 deletions crates/ef-testing/src/models/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ use tracing::{error, info, warn};

#[allow(clippy::cognitive_complexity)]
pub(crate) fn log_execution_result(
result: TransactionExecutionResult<TransactionExecutionInfo>,
result: &TransactionExecutionResult<TransactionExecutionInfo>,
case_name: &str,
case_category: &str,
) {
let case = format!("{}::{}", case_category, case_name);
match result {
TransactionExecutionResult::Ok(info) => {
if let Some(err) = info.revert_error {
/* trunk-ignore(clippy/option_if_let_else) */
if let Some(err) = info.revert_error.as_ref() {
warn!("{} reverted:\n{}", case, err.replace("\\n", "\n"));
} else {
info!("{} passed: {:?}", case, info.actual_resources);
#[cfg(feature = "v0")]
if let Some(call) = info.execute_call_info {
if let Some(call) = info.execute_call_info.as_ref() {
greged93 marked this conversation as resolved.
Show resolved Hide resolved
use starknet::core::types::FieldElement;
use starknet_api::hash::StarkFelt;
let events = kakarot_execution_events(&call);
Expand All @@ -36,7 +37,7 @@ pub(crate) fn log_execution_result(
return;
}
if events[0].data.0.last() == Some(&StarkFelt::ZERO) {
let return_data = call.execution.retdata.0;
let return_data = call.execution.retdata.0.clone();
greged93 marked this conversation as resolved.
Show resolved Hide resolved

let revert_message_len = return_data.first().cloned().unwrap_or_default();
let revert_message_len =
Expand Down Expand Up @@ -72,7 +73,7 @@ pub(crate) fn log_execution_result(
let re = regex::Regex::new(
r#"Error in the called contract \((0x[0-9a-zA-Z]+)\)[\s\S]*?EntryPointSelector\(StarkFelt\("(0x[0-9a-zA-Z]+)"\)\)"#,
).unwrap();
let matches: Vec<_> = re.captures_iter(&trace).map(|c| c.extract::<2>()).collect();
let matches: Vec<_> = re.captures_iter(trace).map(|c| c.extract::<2>()).collect();
let last_match = matches.last().cloned().unwrap_or_default();
warn!(
"Failed to find entrypoint {} for contract {}",
Expand All @@ -83,6 +84,27 @@ pub(crate) fn log_execution_result(
}
}

pub(crate) fn extract_execution_retdata(
execution_info: TransactionExecutionInfo,
) -> Option<String> {
if let Some(call) = execution_info.execute_call_info {
let call_exec = &call.execution;
let retdata = &call_exec.retdata;

// Skip the first byte which is the length of the return data
let retdata_bytes: Vec<u8> = retdata
.0
.iter()
.skip(1)
.filter_map(|felt| felt.bytes().last().cloned())
.collect();

let retdata_str: String = retdata_bytes.iter().map(|&c| c as char).collect();
return Some(retdata_str);
}
None
}

#[allow(dead_code)]
fn kakarot_execution_events(call_info: &CallInfo) -> Vec<EventContent> {
let mut events = Vec::new();
Expand Down
Loading