Skip to content

Commit

Permalink
test(blockifier): test negative flows of cairo1 revert trace
Browse files Browse the repository at this point in the history
  • Loading branch information
dorimedini-starkware committed Oct 23, 2024
1 parent 77832c9 commit 56714fe
Showing 1 changed file with 120 additions and 2 deletions.
122 changes: 120 additions & 2 deletions crates/blockifier/src/execution/stack_trace_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use assert_matches::assert_matches;
use pretty_assertions::assert_eq;
use regex::Regex;
use rstest::rstest;
use starknet_api::core::{calculate_contract_address, Nonce};
use starknet_api::core::{calculate_contract_address, ContractAddress, EntryPointSelector, Nonce};
use starknet_api::transaction::{
ContractAddressSalt,
Fee,
Expand All @@ -10,12 +11,18 @@ use starknet_api::transaction::{
ValidResourceBounds,
};
use starknet_api::{calldata, felt, invoke_tx_args};
use starknet_types_core::felt::Felt;

use crate::abi::abi_utils::selector_from_name;
use crate::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME;
use crate::context::{BlockContext, ChainInfo};
use crate::execution::call_info::{CallExecution, CallInfo, Retdata};
use crate::execution::stack_trace::{extract_trailing_cairo1_revert_trace, TRACE_LENGTH_CAP};
use crate::execution::errors::EntryPointExecutionError;
use crate::execution::stack_trace::{
extract_trailing_cairo1_revert_trace,
Cairo1RevertStack,
TRACE_LENGTH_CAP,
};
use crate::execution::syscalls::hint_processor::ENTRYPOINT_FAILED_ERROR;
use crate::test_utils::contracts::FeatureContract;
use crate::test_utils::initial_test_state::{fund_account, test_state};
Expand Down Expand Up @@ -849,5 +856,116 @@ fn test_cairo1_revert_error_truncation(#[case] n_frames: usize, #[case] n_retdat
assert!(
format!("{}", extract_trailing_cairo1_revert_trace(&next_call_info)).len()
<= TRACE_LENGTH_CAP
)
}

#[test]
fn test_cairo1_stack_extraction_inner_call_successful() {
let failure_reason_str = "0x1";
let error_data = Retdata(vec![felt!(failure_reason_str)]);
let callinfo = CallInfo {
execution: CallExecution { retdata: error_data, failed: true, ..Default::default() },
inner_calls: vec![CallInfo::default()],
..Default::default()
};
let error = EntryPointExecutionError::ExecutionFailed {
error_trace: extract_trailing_cairo1_revert_trace(&callinfo),
};
assert_eq!(
error.to_string(),
format!(
"Execution failed. Failure reason:
Error in contract (contract address: {:#064x}, class hash: _, selector: {:#064x}):
{failure_reason_str}.",
ContractAddress::default().0.key(),
EntryPointSelector::default().0
)
);
}

#[test]
fn test_ambiguous_inner_cairo1_failure() {
let (failure_reason_0, failure_reason_1) = (Felt::ONE, Felt::TWO);
let outer_retdata =
Retdata(vec![failure_reason_0, failure_reason_1, felt!(ENTRYPOINT_FAILED_ERROR)]);
let inner_call_info = CallInfo {
execution: CallExecution {
retdata: Retdata(vec![failure_reason_0, failure_reason_1]),
failed: true,
..Default::default()
},
..Default::default()
};
let call_info = CallInfo {
execution: CallExecution {
retdata: outer_retdata.clone(),
failed: true,
..Default::default()
},
// Both of these inner calls can be the source of error; expect fallback value.
inner_calls: vec![inner_call_info.clone(), inner_call_info],
..Default::default()
};
assert_matches!(
extract_trailing_cairo1_revert_trace(&call_info),
Cairo1RevertStack { stack, last_retdata }
if stack.is_empty() && last_retdata == outer_retdata
);
}

#[rstest]
fn test_inner_cairo1_failure_not_last(#[values(true, false)] last_is_failed: bool) {
let (failure_reason_0, failure_reason_1) = (Felt::ONE, Felt::TWO);
let outer_retdata =
Retdata(vec![failure_reason_0, failure_reason_1, felt!(ENTRYPOINT_FAILED_ERROR)]);
let first_inner_retdata = Retdata(outer_retdata.0[..outer_retdata.0.len() - 1].into());
let first_inner_call_info = CallInfo {
execution: CallExecution {
retdata: first_inner_retdata.clone(),
failed: true,
..Default::default()
},
..Default::default()
};
let last_inner_call_info = CallInfo {
execution: CallExecution {
retdata: Retdata(
// Not a prefix of the outer retdata. Should not be selected as inner failure.
vec![failure_reason_1, felt!(ENTRYPOINT_FAILED_ERROR)],
),
failed: last_is_failed,
..Default::default()
},
..Default::default()
};
let call_info = CallInfo {
execution: CallExecution {
retdata: outer_retdata.clone(),
failed: true,
..Default::default()
},
inner_calls: vec![first_inner_call_info, last_inner_call_info],
..Default::default()
};
assert_matches!(
extract_trailing_cairo1_revert_trace(&call_info),
Cairo1RevertStack { stack, last_retdata }
if stack.len() == 2 && last_retdata == first_inner_retdata
);
}

/// If extraction function is called with a successful callinfo, it should return an empty stack and
/// the original retdata.
#[test]
fn test_cairo1_stack_extraction_not_failure_fallback() {
let expected_retdata = Retdata(vec![Felt::ONE, Felt::THREE]);
let successful_call = CallInfo {
execution: CallExecution { retdata: expected_retdata.clone(), ..Default::default() },
..Default::default()
};
assert_matches!(
extract_trailing_cairo1_revert_trace(&successful_call),
Cairo1RevertStack { stack, last_retdata }
if stack.is_empty() && last_retdata == expected_retdata
);
}

0 comments on commit 56714fe

Please sign in to comment.