Skip to content

Commit

Permalink
feat: support catching EntryPointNotFound
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyalesokhin-starkware committed Oct 8, 2024
1 parent abb5f83 commit 5aa6bfe
Show file tree
Hide file tree
Showing 9 changed files with 833 additions and 693 deletions.
1,453 changes: 784 additions & 669 deletions crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ mod TestContract {
*error_span.pop_back().unwrap() == 'ENTRYPOINT_FAILED',
'Unexpected error',
);
let inner_error = *error_span.pop_back().unwrap();
if entry_point_selector == selector!("bad_selector") {
assert(inner_error == 'ENTRYPOINT_NOT_FOUND', 'Unexpected error');
} else {
assert(inner_error == 'test_revert_helper', 'Unexpected error');
}
},
};
// TODO(Yoni, 1/12/2024): test replace class once get_class_hash_at syscall is supported.
Expand All @@ -103,7 +109,7 @@ mod TestContract {
syscalls::replace_class_syscall(class_hash).unwrap_syscall();
syscalls::send_message_to_l1_syscall(17.try_into().unwrap(), dummy_span).unwrap_syscall();
self.my_storage_var.write(17);
panic!("test_revert_helper");
panic(array!['test_revert_helper']);
}

#[external(v0)]
Expand Down
24 changes: 23 additions & 1 deletion crates/blockifier/src/execution/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use starknet_api::state::StorageKey;
use starknet_api::transaction::{Calldata, TransactionVersion};
use starknet_types_core::felt::Felt;

use super::call_info::{CallExecution, Retdata};
use super::syscalls::hint_processor::ENTRYPOINT_NOT_FOUND_ERROR;
use crate::abi::abi_utils::selector_from_name;
use crate::abi::constants;
use crate::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME;
Expand Down Expand Up @@ -150,7 +152,27 @@ impl CallEntryPoint {
context.n_sent_messages_to_l1,
));

execute_entry_point_call_wrapper(self, contract_class, state, resources, context)
let orig_call = self.clone();
match execute_entry_point_call_wrapper(self, contract_class, state, resources, context) {
Err(EntryPointExecutionError::PreExecutionError(
PreExecutionError::EntryPointNotFound(_),
)) if context.versioned_constants().enable_reverts => Ok(CallInfo {
call: orig_call,
execution: CallExecution {
retdata: Retdata(vec![Felt::from_hex(ENTRYPOINT_NOT_FOUND_ERROR).unwrap()]),
events: Default::default(),
l2_to_l1_messages: Default::default(),
failed: true,
gas_consumed: 0,
},
resources: Default::default(),
inner_calls: vec![],
tracked_resource: TrackedResource::SierraGas,
storage_read_values: vec![],
accessed_storage_keys: Default::default(),
}),
res => res,
}
}

/// Similar to `execute`, but returns an error if the outer call is reverted.
Expand Down
1 change: 1 addition & 0 deletions crates/blockifier/src/execution/entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub fn execute_entry_point_call(
program_extra_data_length,
tracked_resource,
)?;

if call_info.execution.failed && !context.versioned_constants().enable_reverts {
return Err(EntryPointExecutionError::ExecutionFailed {
error_data: call_info.execution.retdata.0,
Expand Down
14 changes: 2 additions & 12 deletions crates/blockifier/src/execution/entry_point_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,8 @@ fn test_entry_point_not_found_in_contract() {
let entry_point_selector = EntryPointSelector(felt!(2_u8));
let entry_point_call =
CallEntryPoint { entry_point_selector, ..trivial_external_entry_point_new(test_contract) };
let error = entry_point_call.execute_directly(&mut state).unwrap_err();
assert_eq!(
format!("Entry point {entry_point_selector:?} not found in contract."),
format!("{error}")
);
let call_info = entry_point_call.execute_directly(&mut state).unwrap();
assert!(call_info.execution.failed);
}

#[test]
Expand Down Expand Up @@ -396,13 +393,6 @@ fn test_syscall_execution_security_failures() {
"test_bad_syscall_request_arg_type",
calldata![],
);
run_security_test(
state,
security_contract,
"Entry point EntryPointSelector(0x19) not found in contract",
"test_bad_call_selector",
calldata![],
);
run_security_test(
state,
security_contract,
Expand Down
3 changes: 3 additions & 0 deletions crates/blockifier/src/execution/syscalls/hint_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ pub const OUT_OF_GAS_ERROR: &str =
// "Block number out of range";
pub const BLOCK_NUMBER_OUT_OF_RANGE_ERROR: &str =
"0x00000000000000426c6f636b206e756d626572206f7574206f662072616e6765";
// "ENTRYPOINT_NOT_FOUND";
pub const ENTRYPOINT_NOT_FOUND_ERROR: &str =
"0x000000000000000000000000454e545259504f494e545f4e4f545f464f554e44";
// "ENTRYPOINT_FAILED";
pub const ENTRYPOINT_FAILED_ERROR: &str =
"0x000000000000000000000000000000454e545259504f494e545f4641494c4544";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ fn test_call_contract_that_panics() {
};
// The inner call should have failed.
assert!(inner_call.execution.failed);
assert_eq!(format_panic_data(&inner_call.execution.retdata.0), "\"test_revert_helper\"");
assert_eq!(
format_panic_data(&inner_call.execution.retdata.0),
"0x746573745f7265766572745f68656c706572 ('test_revert_helper')"
);
assert!(inner_call.execution.events.is_empty());
assert!(inner_call.execution.l2_to_l1_messages.is_empty());
assert_eq!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1504,12 +1504,11 @@ fn test_revert_in_execute(
}

#[rstest]
#[case(true)]
#[case(false)]
fn test_call_contract_that_panics(
mut block_context: BlockContext,
max_l1_resource_bounds: ValidResourceBounds,
#[case] enable_reverts: bool,
#[values(true, false)] enable_reverts: bool,
#[values("test_revert_helper", "bad_selector")] inner_selector: &str,
) {
// Override enable reverts.
block_context.versioned_constants.enable_reverts = enable_reverts;
Expand All @@ -1525,7 +1524,7 @@ fn test_call_contract_that_panics(

let calldata = [
*FeatureContract::TestContract(CairoVersion::Cairo1).get_instance_address(0).0.key(),
selector_from_name("test_revert_helper").0,
selector_from_name(inner_selector).0,
felt!(1_u8),
new_class_hash.0,
];
Expand Down
11 changes: 6 additions & 5 deletions crates/papyrus_rpc/src/v0_8/execution_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ async fn execution_call() {

assert_matches!(err, Error::Call(err) if err == BLOCK_NOT_FOUND.into());

// Calling a non-existent function (contract error).
let err = module
// Calling a non-existent entry point.
let call = module
.call::<_, Vec<Felt>>(
"starknet_V0_8_call",
(
Expand All @@ -286,10 +286,11 @@ async fn execution_call() {
),
)
.await
.unwrap_err();
.unwrap();

const CONTRACT_ERROR_CODE: i32 = 40;
assert_matches!(err, Error::Call(err) if err.code() == CONTRACT_ERROR_CODE);
let entry_point_not_found_error =
felt!("0x000000000000000000000000454e545259504f494e545f4e4f545f464f554e44");
assert_eq!(call, [entry_point_not_found_error]);

// Test that the block context is passed correctly to blockifier.
let mut calldata = get_calldata_for_test_execution_info(
Expand Down

0 comments on commit 5aa6bfe

Please sign in to comment.