Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
feat: add the new stack trace to ValidateTransactionError (#1712)
Browse files Browse the repository at this point in the history
* feat: add the new stack trace to ValidateTransactionError

* test: add test
  • Loading branch information
zuphitf committed Mar 27, 2024
1 parent 59150ce commit 06596a7
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 11 deletions.
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ phf = { version = "0.11", features = ["macros"] }
pretty_assertions = "1.2.1"
pyo3 = "0.19.1"
pyo3-log = "0.8.1"
regex = "1.10.4"
rstest = "0.17.0"
serde = "1.0.184"
serde_json = "1.0.81"
Expand Down
1 change: 1 addition & 0 deletions crates/blockifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ thiserror.workspace = true
[dev-dependencies]
assert_matches.workspace = true
pretty_assertions.workspace = true
regex.workspace = true
rstest.workspace = true
test-case.workspace = true
91 changes: 88 additions & 3 deletions crates/blockifier/src/execution/entry_point_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::collections::HashSet;
use cairo_vm::serde::deserialize_program::BuiltinName;
use num_bigint::BigInt;
use pretty_assertions::assert_eq;
use regex::Regex;
use rstest::rstest;
use starknet_api::core::{EntryPointSelector, PatriciaKey};
use starknet_api::deprecated_contract_class::{EntryPointOffset, EntryPointType};
Expand All @@ -20,9 +21,20 @@ use crate::state::cached_state::CachedState;
use crate::test_utils::contracts::FeatureContract;
use crate::test_utils::dict_state_reader::DictStateReader;
use crate::test_utils::initial_test_state::test_state;
use crate::test_utils::{create_calldata, trivial_external_entry_point_new, CairoVersion, BALANCE};
use crate::transaction::constants::EXECUTE_ENTRY_POINT_NAME;
use crate::transaction::test_utils::{block_context, run_invoke_tx};
use crate::test_utils::{
create_calldata, trivial_external_entry_point_new, CairoVersion, NonceManager, BALANCE,
};
use crate::transaction::account_transaction::AccountTransaction;
use crate::transaction::constants::{
EXECUTE_ENTRY_POINT_NAME, VALIDATE_DECLARE_ENTRY_POINT_NAME, VALIDATE_DEPLOY_ENTRY_POINT_NAME,
VALIDATE_ENTRY_POINT_NAME,
};
use crate::transaction::test_utils::{
block_context, create_account_tx_for_validate_test, run_invoke_tx, FaultyAccountTxCreatorArgs,
INVALID,
};
use crate::transaction::transaction_types::TransactionType;
use crate::transaction::transactions::ExecutableTransaction;
use crate::versioned_constants::VersionedConstants;
use crate::{invoke_tx_args, retdata};

Expand Down Expand Up @@ -995,3 +1007,76 @@ Execution failed. Failure reason: {expected_error}.

assert_eq!(tx_execution_error.to_string(), expected_trace);
}

#[rstest]
#[case::validate(TransactionType::InvokeFunction, VALIDATE_ENTRY_POINT_NAME)]
#[case::validate_declare(TransactionType::Declare, VALIDATE_DECLARE_ENTRY_POINT_NAME)]
#[case::validate_deploy(TransactionType::DeployAccount, VALIDATE_DEPLOY_ENTRY_POINT_NAME)]
fn test_validate_trace(
#[case] tx_type: TransactionType,
#[case] entry_point_name: &str,
#[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion,
) {
let create_for_account_testing = &BlockContext::create_for_account_testing();
let block_context = create_for_account_testing;
let faulty_account = FeatureContract::FaultyAccount(cairo_version);
let mut sender_address = faulty_account.get_instance_address(0);
let class_hash = faulty_account.get_class_hash();
let state = &mut test_state(&block_context.chain_info, 0, &[(faulty_account, 1)]);
let selector = selector_from_name(entry_point_name).0;

// Logic failure.
let account_tx = create_account_tx_for_validate_test(
&mut NonceManager::default(),
FaultyAccountTxCreatorArgs {
scenario: INVALID,
tx_type,
sender_address,
class_hash,
..Default::default()
},
);

if let TransactionType::DeployAccount = tx_type {
// Deploy account uses the actual address as the sender address.
match &account_tx {
AccountTransaction::DeployAccount(tx) => {
sender_address = tx.contract_address;
}
_ => panic!("Expected DeployAccountTransaction type"),
}
}

let contract_address = *sender_address.0.key();

let expected_error = match cairo_version {
CairoVersion::Cairo0 => format!(
"Transaction validation has failed:
0: Error in the called contract (contract address: {contract_address}, class hash: {class_hash}, \
selector: {selector}):
Error at pc=0:0:
Cairo traceback (most recent call last):
Unknown location (pc=0:0)
Unknown location (pc=0:0)
An ASSERT_EQ instruction failed: 1 != 0.
"
),
CairoVersion::Cairo1 => format!(
"Transaction validation has failed:
0: Error in the called contract (contract address: {contract_address}, class hash: {class_hash}, \
selector: {selector}):
Execution failed. Failure reason: 0x496e76616c6964207363656e6172696f ('Invalid scenario').
"
),
};

// Clean pc locations from the trace.
let re = Regex::new(r"pc=0:[0-9]+").unwrap();
let cleaned_expected_error = &re.replace_all(&expected_error, "pc=0:*");
let actual_error = account_tx.execute(state, block_context, true, true).unwrap_err();
let actual_error_str = actual_error.to_string();
let cleaned_actual_error = &re.replace_all(&actual_error_str, "pc=0:*");
// Compare actual trace to the expected trace (sans pc locations).
assert_eq!(cleaned_actual_error.to_string(), cleaned_expected_error.to_string());
}
9 changes: 7 additions & 2 deletions crates/blockifier/src/execution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,14 @@ pub fn gen_transaction_execution_error_trace(error: &TransactionExecutionError)
class_hash,
storage_address,
selector,
}
| TransactionExecutionError::ValidateTransactionError {
error,
class_hash,
storage_address,
selector,
} => {
// TODO(zuphit): activate the match on these types once all selectors are available.
// | TransactionExecutionError::ValidateTransactionError { error, storage_address, .. }
// TODO(zuphit): activate the match on this type once all selectors are available.
// | TransactionExecutionError::ContractConstructorExecutionFailed {
// error,
// storage_address,
Expand Down
3 changes: 2 additions & 1 deletion crates/blockifier/src/transaction/account_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ impl ValidatableTransaction for AccountTransaction {
}

let storage_address = tx_info.sender_address();
let class_hash = state.get_class_hash_at(storage_address)?;
let validate_selector = self.validate_entry_point_selector();
let validate_call = CallEntryPoint {
entry_point_type: EntryPointType::External,
Expand All @@ -686,13 +687,13 @@ impl ValidatableTransaction for AccountTransaction {
validate_call.execute(state, resources, &mut context).map_err(|error| {
TransactionExecutionError::ValidateTransactionError {
error,
class_hash,
storage_address,
selector: validate_selector,
}
})?;

// Validate return data.
let class_hash = state.get_class_hash_at(storage_address)?;
let contract_class = state.get_compiled_contract_class(class_hash)?;
if let ContractClass::V1(_) = contract_class {
// The account contract class is a Cairo 1.0 contract; the `validate` entry point should
Expand Down
3 changes: 2 additions & 1 deletion crates/blockifier/src/transaction/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ pub enum TransactionExecutionError {
TransactionPreValidationError(#[from] TransactionPreValidationError),
#[error(transparent)]
TryFromIntError(#[from] std::num::TryFromIntError),
#[error("Transaction validation has failed: {error}")]
#[error("Transaction validation has failed:\n{}", gen_transaction_execution_error_trace(self))]
ValidateTransactionError {
error: EntryPointExecutionError,
class_hash: ClassHash,
storage_address: ContractAddress,
selector: EntryPointSelector,
},
Expand Down

0 comments on commit 06596a7

Please sign in to comment.