Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
],
"EXTERNAL": [
{
"offset": 716,
"offset": 728,
"selector": "0x8e64dfac867f301a439703710296f437e9f91d1bba17cfea5ad7f137a5acd"
},
{
Expand Down Expand Up @@ -157,18 +157,36 @@
"__main__",
"__main__.test_revert_fuzz"
],
"end_pc": 712,
"end_pc": 716,
"flow_tracking_data": {
"ap_tracking": {
"group": 27,
"offset": 73
"offset": 74
},
"reference_ids": {}
},
"name": "error_message",
"start_pc": 712,
"value": "get_block_hash_cairo0"
},
{
"accessible_scopes": [
"__main__",
"__main__",
"__main__.test_revert_fuzz"
],
"end_pc": 724,
"flow_tracking_data": {
"ap_tracking": {
"group": 27,
"offset": 74
},
"reference_ids": {
"__main__.test_revert_fuzz.scenario": 9
}
},
"name": "error_message",
"start_pc": 708,
"start_pc": 720,
"value": "Unknown scenario: {scenario}."
}
],
Expand Down Expand Up @@ -886,20 +904,32 @@
"0x1104800180018000",
"0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe42",
"0x208b7fff7fff7ffe",
"0x4826800180018000",
"0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff0",
"0x20680017fff7fff",
"0xa",
"0x480680017fff8000",
"0x1",
"0x400680017fff7fff",
"0x0",
"0x48127fe97fff8000",
"0x48127fe97fff8000",
"0x48127fe97fff8000",
"0x208b7fff7fff7ffe",
"0x480680017fff8000",
"0x0",
"0x400680017fff7fff",
"0x1",
"0x48127fea7fff8000",
"0x48127fea7fff8000",
"0x48127fea7fff8000",
"0x48127fe97fff8000",
"0x48127fe97fff8000",
"0x48127fe97fff8000",
"0x208b7fff7fff7ffe",
"0x402b7ffd7ffc7ffd",
"0x480280007ffb8000",
"0x480280017ffb8000",
"0x480280027ffb8000",
"0x1104800180018000",
"0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe33",
"0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe27",
"0x40780017fff7fff",
"0x1",
"0x48127ffc7fff8000",
Expand Down Expand Up @@ -1126,7 +1156,7 @@
}
}
],
"722": [
"734": [
{
"accessible_scopes": [
"__main__",
Expand Down Expand Up @@ -1256,6 +1286,10 @@
"type": "const",
"value": 16
},
"__main__.SCENARIO_GET_BLOCK_HASH": {
"type": "const",
"value": 17
},
"__main__.SCENARIO_INCREMENT_COUNTER": {
"type": "const",
"value": 7
Expand Down Expand Up @@ -1906,7 +1940,7 @@
"decorators": [
"external"
],
"pc": 716,
"pc": 728,
"type": "function"
},
"__wrappers__.test_revert_fuzz.Args": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const SCENARIO_CALL_UNDEPLOYED = 13;
const SCENARIO_CALL_NON_EXISTING_ENTRY_POINT = 14;
const SCENARIO_LIBRARY_CALL_NON_EXISTING_ENTRY_POINT = 15;
const SCENARIO_EMIT_EVENT = 16;
const SCENARIO_GET_BLOCK_HASH = 17;

// selector_from_name("pop_front").
const POP_FRONT_SELECTOR = 0x289c2d7d6351cd03d4f928bde75fa14d5f52e32bdbc750d5296e1b48c12f1c3;
Expand Down Expand Up @@ -256,6 +257,13 @@ func test_revert_fuzz{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec
return ();
}

if (scenario == SCENARIO_GET_BLOCK_HASH) {
with_attr error_message("get_block_hash_cairo0") {
assert 0 = 1;
}
return ();
}

with_attr error_message("Unknown scenario: {scenario}.") {
assert 1 = 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ trait IOrchestrator<TContractState> {
fn should_fail_undeployed_panic_message(ref self: TContractState) -> felt252;
fn should_fail_call_no_entrypoint_panic_message(ref self: TContractState) -> felt252;
fn should_fail_libcall_no_entrypoint_panic_message(ref self: TContractState) -> felt252;
fn should_fail_get_block_hash_panic_message(ref self: TContractState) -> felt252;
fn should_succeed_get_block_hash_panic_message(ref self: TContractState) -> felt252;
}

#[starknet::contract]
Expand Down Expand Up @@ -39,6 +41,7 @@ mod FuzzRevertContract {
CallNonExistingEntryPoint,
LibraryCallNonExistingEntryPoint,
EmitEvent,
GetBlockHash,
}

impl FeltTryIntoScenario of TryInto<felt252, Scenario> {
Expand All @@ -64,6 +67,7 @@ mod FuzzRevertContract {
14 => Some(Scenario::CallNonExistingEntryPoint),
15 => Some(Scenario::LibraryCallNonExistingEntryPoint),
16 => Some(Scenario::EmitEvent),
17 => Some(Scenario::GetBlockHash),
_ => None,
}
}
Expand Down Expand Up @@ -112,6 +116,19 @@ mod FuzzRevertContract {
}
}

/// If should_unwrap is true, prepends the orchestrator index to the error and panics.
fn maybe_unwrap_error(ref self: ContractState, error: Array<felt252>, should_unwrap: bool) {
if should_unwrap {
// The inner error does not contain the orchestrator index, so to propagate
// the error the index must be prepended.
let mut new_error: Array<felt252> = array![self.orchestrator().get_index()];
for elem in error {
new_error.append(elem);
}
panic(new_error);
}
}

/// Handle a syscall that immediately fails (e.g. calling a non-existing entry point).
fn handle_syscall_immediate_failure(
ref self: ContractState,
Expand All @@ -121,20 +138,7 @@ mod FuzzRevertContract {
) {
match result {
Result::Ok(_) => panic_with_felt252(panic_message_if_ok),
Result::Err(mut error) => {
// Syscall failed immediately, so no inner calls could have modified the
// orchestrator index. No need to handle index propagation (the !should_unwrap
// case).
if should_unwrap {
// The inner error does not contain the orchestrator index, so to propagate
// the error the index must be prepended.
let mut new_error: Array<felt252> = array![self.orchestrator().get_index()];
for elem in error {
new_error.append(elem);
}
panic(new_error);
}
}
Result::Err(error) => self.maybe_unwrap_error(error, should_unwrap),
}
}
}
Expand Down Expand Up @@ -272,6 +276,22 @@ mod FuzzRevertContract {
);
},
Scenario::EmitEvent => { self.emit(FuzzEvent { data: orchestrator.pop_front() }); },
Scenario::GetBlockHash => {
let block_number: u64 = orchestrator.pop_front().try_into().unwrap();
let expect_panic: bool = orchestrator.pop_front() != 0;
let should_unwrap = true;
match syscalls::get_block_hash_syscall(block_number) {
Result::Ok(_) => assert(
!expect_panic, orchestrator.should_fail_get_block_hash_panic_message()
),
Result::Err(error) => {
assert(
expect_panic, orchestrator.should_succeed_get_block_hash_panic_message()
);
self.maybe_unwrap_error(error, should_unwrap);
}
}
},
}

// Unless explicitly stated otherwise, the next operation should be in the current call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ trait IOrchestrator<TContractState> {
fn should_fail_undeployed_panic_message(ref self: TContractState) -> felt252;
fn should_fail_call_no_entrypoint_panic_message(ref self: TContractState) -> felt252;
fn should_fail_libcall_no_entrypoint_panic_message(ref self: TContractState) -> felt252;
fn should_fail_get_block_hash_panic_message(ref self: TContractState) -> felt252;
fn should_succeed_get_block_hash_panic_message(ref self: TContractState) -> felt252;
}

#[starknet::contract]
Expand Down Expand Up @@ -41,6 +43,7 @@ mod FuzzRevertContract {
CallNonExistingEntryPoint,
LibraryCallNonExistingEntryPoint,
EmitEvent,
GetBlockHash,
}

impl FeltTryIntoScenario of TryInto<felt252, Scenario> {
Expand All @@ -66,6 +69,7 @@ mod FuzzRevertContract {
14 => Some(Scenario::CallNonExistingEntryPoint),
15 => Some(Scenario::LibraryCallNonExistingEntryPoint),
16 => Some(Scenario::EmitEvent),
17 => Some(Scenario::GetBlockHash),
_ => None,
}
}
Expand Down Expand Up @@ -114,6 +118,19 @@ mod FuzzRevertContract {
}
}

/// If should_unwrap is true, prepends the orchestrator index to the error and panics.
fn maybe_unwrap_error(ref self: ContractState, error: Array<felt252>, should_unwrap: bool) {
if should_unwrap {
// The inner error does not contain the orchestrator index, so to propagate
// the error the index must be prepended.
let mut new_error: Array<felt252> = array![self.orchestrator().get_index()];
for elem in error {
new_error.append(elem);
}
panic(new_error);
}
}

/// Handle a syscall that immediately fails (e.g. calling a non-existing entry point).
fn handle_syscall_immediate_failure(
ref self: ContractState,
Expand All @@ -123,20 +140,7 @@ mod FuzzRevertContract {
) {
match result {
Result::Ok(_) => panic_with_felt252(panic_message_if_ok),
Result::Err(mut error) => {
// Syscall failed immediately, so no inner calls could have modified the
// orchestrator index. No need to handle index propagation (the !should_unwrap
// case).
if should_unwrap {
// The inner error does not contain the orchestrator index, so to propagate
// the error the index must be prepended.
let mut new_error: Array<felt252> = array![self.orchestrator().get_index()];
for elem in error {
new_error.append(elem);
}
panic(new_error);
}
}
Result::Err(error) => self.maybe_unwrap_error(error, should_unwrap),
}
}
}
Expand Down Expand Up @@ -274,6 +278,22 @@ mod FuzzRevertContract {
);
},
Scenario::EmitEvent => { self.emit(FuzzEvent { data: orchestrator.pop_front() }); },
Scenario::GetBlockHash => {
let block_number: u64 = orchestrator.pop_front().try_into().unwrap();
let expect_panic: bool = orchestrator.pop_front() != 0;
let should_unwrap = true;
match syscalls::get_block_hash_syscall(block_number) {
Result::Ok(_) => assert(
!expect_panic, orchestrator.should_fail_get_block_hash_panic_message()
),
Result::Err(error) => {
assert(
expect_panic, orchestrator.should_succeed_get_block_hash_panic_message()
);
self.maybe_unwrap_error(error, should_unwrap);
}
}
},
}

// Unless explicitly stated otherwise, the next operation should be in the current call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mod FuzzRevertOrchestratorContract {
const UNEXPECTED_FAIL_UNDEPLOYED: felt252 = 'should_fail_undeployed';
const UNEXPECTED_FAIL_CALL_NO_ENTRYPOINT: felt252 = 'call_no_entrypoint';
const UNEXPECTED_FAIL_LIBCALL_NO_ENTRYPOINT: felt252 = 'libcall_no_entrypoint';
const UNEXPECTED_SUCCESS_GET_BLOCK_HASH: felt252 = 'get_block_hash_success';
const UNEXPECTED_FAIL_GET_BLOCK_HASH: felt252 = 'get_block_hash_fail';

#[storage]
struct Storage {
Expand Down Expand Up @@ -52,11 +54,14 @@ mod FuzzRevertOrchestratorContract {
/// will panic (this can happen if an unexpected error occurs and is propagated).
#[external(v0)]
fn set_index(ref self: ContractState, index: felt252) {
let error = array![OOB_ERROR, index];
let index_u64: u64 = match index.try_into() {
Option::Some(val) => val,
Option::None => panic_with_felt252(OOB_ERROR),
Option::None => panic(error),
};
assert(index_u64 <= self.scenarios.len(), OOB_ERROR);
if index_u64 > self.scenarios.len() {
panic(error);
}
self.front_index.write(index_u64);
}

Expand All @@ -83,26 +88,49 @@ mod FuzzRevertOrchestratorContract {
UNEXPECTED_FAIL_LIBCALL_NO_ENTRYPOINT
}

#[external(v0)]
fn should_fail_get_block_hash_panic_message(ref self: ContractState) -> felt252 {
UNEXPECTED_SUCCESS_GET_BLOCK_HASH
}

#[external(v0)]
fn should_succeed_get_block_hash_panic_message(ref self: ContractState) -> felt252 {
UNEXPECTED_FAIL_GET_BLOCK_HASH
}

/// Start the test. The first address must be an initialized fuzz test contract.
#[external(v0)]
fn start_test(ref self: ContractState, first_address: ContractAddress) {
match syscalls::call_contract_syscall(
first_address, selector!("test_revert_fuzz"), array![].span(),
) {
Result::Ok(_) => (),
Result::Err(mut error) => {
// Assert the error is not any unexpected error.
let error_value = error.pop_front().unwrap();
for unexpected_error in array![
Result::Err(error) => {
// Assert the error does not contain any unexpected error.
let unexpected_errors = array![
UNEXPECTED_FAIL_INVALID_SCENARIO,
OOB_ERROR,
UNEXPECTED_FAIL_UNDEPLOYED,
UNEXPECTED_FAIL_CALL_NO_ENTRYPOINT,
UNEXPECTED_FAIL_LIBCALL_NO_ENTRYPOINT
UNEXPECTED_FAIL_LIBCALL_NO_ENTRYPOINT,
UNEXPECTED_SUCCESS_GET_BLOCK_HASH,
UNEXPECTED_FAIL_GET_BLOCK_HASH
]
.span();
let mut contains_unexpected_error = false;
for error_value in error
.span() {
assert(error_value != *unexpected_error, *unexpected_error);
for unexpected_error in unexpected_errors {
if error_value == unexpected_error {
contains_unexpected_error = true;
break;
}
}
}

if contains_unexpected_error {
panic(error);
}
}
}
}
Expand Down
Loading
Loading