Skip to content

Commit

Permalink
Fix panic if event don't follow constraints (#1932)
Browse files Browse the repository at this point in the history
<!-- Reference any GitHub issues resolved by this PR -->


## Introduced changes

<!-- A brief description of the changes -->

- Fixes https://t.me/starknet_foundry/777
  • Loading branch information
Draggu authored Mar 22, 2024
1 parent 3687426 commit b08fc03
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,13 @@ impl<Extension: DeprecatedExtensionLogic> DeprecatedExtendedRuntime<Extension> {
{
Ok(())
} else {
let res = self
.extended_runtime
.execute_hint(vm, exec_scopes, hint_data, constants);
self.extended_runtime
.execute_hint(vm, exec_scopes, hint_data, constants)?;

self.extension
.post_syscall_hook(&selector, &mut self.extended_runtime);

res
Ok(())
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/forge-runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub enum TestCrateRunResult {
}

pub async fn run_tests_from_crate(
tests: Arc<CompiledTestCrateRunnable>,
tests: CompiledTestCrateRunnable,
runner_config: Arc<RunnerConfig>,
runner_params: Arc<RunnerParams>,
tests_filter: &impl TestCaseFilter,
Expand All @@ -172,7 +172,7 @@ pub async fn run_tests_from_crate(
let casm_program = Arc::new(compile_sierra_to_casm(sierra_program)?);

let mut tasks = FuturesUnordered::new();
let test_cases = &tests.test_cases;
let test_cases = tests.test_cases;
// Initiate two channels to manage the `--exit-first` flag.
// Owing to `cheatnet` fork's utilization of its own Tokio runtime for RPC requests,
// test execution must occur within a `tokio::spawn_blocking`.
Expand All @@ -183,7 +183,7 @@ pub async fn run_tests_from_crate(
for case in test_cases {
let case_name = case.name.clone();

if !tests_filter.should_be_run(case) {
if !tests_filter.should_be_run(&case) {
tasks.push(tokio::task::spawn(async {
// TODO TestCaseType should also be encoded in the test case definition
Ok(AnyTestCaseSummary::Single(TestCaseSummary::Ignored {
Expand All @@ -201,7 +201,7 @@ pub async fn run_tests_from_crate(

let args = function_args(function, &BUILTINS);

let case = Arc::new(case.clone());
let case = Arc::new(case);
let args: Vec<ConcreteTypeId> = args.into_iter().cloned().collect();

tasks.push(choose_test_strategy_and_run(
Expand Down
2 changes: 1 addition & 1 deletion crates/forge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub async fn run(

let compiled_test_crate =
to_runnable(compiled_test_crate, fork_targets, block_number_map).await?;
let compiled_test_crate = Arc::new(compiled_test_crate);
let compiled_test_crate = compiled_test_crate;
let runner_config = runner_config.clone();
let runner_params = runner_params.clone();

Expand Down
42 changes: 42 additions & 0 deletions crates/forge/tests/data/contracts/too_many_events.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use starknet::ContractAddress;

#[starknet::interface]
trait ITooManyEvents<TContractState> {
fn emit_too_many_events(self: @TContractState, count: felt252);
fn emit_too_many_keys(self: @TContractState, count: felt252);
fn emit_too_many_data(self: @TContractState, count: felt252);
}

#[starknet::contract]
mod TooManyEvents {
#[storage]
struct Storage {}

#[abi(embed_v0)]
impl TooManyEventsImpl of super::ITooManyEvents<ContractState> {
fn emit_too_many_events(self: @ContractState, mut count: felt252) {
while count != 0 {
starknet::emit_event_syscall(array![0].span(), array![0].span()).unwrap();
count -= 1;
};
}
fn emit_too_many_keys(self: @ContractState, mut count: felt252) {
let mut arr = array![];
while count != 0 {
arr.append(0);
count -= 1;
};

starknet::emit_event_syscall(arr.span(), array![0].span()).unwrap();
}
fn emit_too_many_data(self: @ContractState, mut count: felt252) {
let mut arr = array![];
while count != 0 {
arr.append(0);
count -= 1;
};

starknet::emit_event_syscall(array![0].span(), arr.span()).unwrap();
}
}
}
1 change: 1 addition & 0 deletions crates/forge/tests/integration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ mod spy_events;
mod store_load;
mod syscalls;
mod test_state;
mod too_many_events;
mod trace;
mod warp;
153 changes: 153 additions & 0 deletions crates/forge/tests/integration/too_many_events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use blockifier::versioned_constants::{EventLimits, VersionedConstants};
use indoc::formatdoc;
use std::path::Path;
use test_utils::runner::{assert_case_output_contains, assert_failed, assert_passed, Contract};
use test_utils::running_tests::run_test_case;

#[test]
fn ok_events() {
let EventLimits {
max_data_length,
max_keys_length,
max_n_emitted_events,
} = VersionedConstants::latest_constants().tx_event_limits;

let test = test_utils::test_case!(
&formatdoc!(
r#"
use starknet::ContractAddress;
use snforge_std::{{ declare, ContractClassTrait, store, load }};
#[starknet::interface]
trait ITooManyEvents<TContractState> {{
fn emit_too_many_events(self: @TContractState, count: felt252);
fn emit_too_many_keys(self: @TContractState, count: felt252);
fn emit_too_many_data(self: @TContractState, count: felt252);
}}
fn deploy_contract() -> ITooManyEventsDispatcher {{
let contract = declare("TooManyEvents");
let contract_address = contract.deploy(@array![]).unwrap();
ITooManyEventsDispatcher {{ contract_address }}
}}
#[test]
fn emit_ok_many_events() {{
let deployed = deploy_contract();
deployed.emit_too_many_events({max_n_emitted_events});
assert(1 == 1, '');
}}
#[test]
fn emit_ok_many_keys() {{
let deployed = deploy_contract();
deployed.emit_too_many_keys({max_keys_length});
assert(1 == 1, '');
}}
#[test]
fn emit_ok_many_data() {{
let deployed = deploy_contract();
deployed.emit_too_many_data({max_data_length});
assert(1 == 1, '');
}}
"#
),
Contract::from_code_path(
"TooManyEvents".to_string(),
Path::new("tests/data/contracts/too_many_events.cairo"),
)
.unwrap()
);

let result = run_test_case(&test);

assert_passed(&result);
}
#[test]
fn too_many_events() {
let EventLimits {
max_data_length,
max_keys_length,
max_n_emitted_events,
} = VersionedConstants::latest_constants().tx_event_limits;

let emit_too_many_events = max_n_emitted_events + 1;
let emit_too_many_keys = max_keys_length + 1;
let emit_too_many_data = max_data_length + 1;

let test = test_utils::test_case!(
&formatdoc!(
r#"
use starknet::ContractAddress;
use snforge_std::{{ declare, ContractClassTrait, store, load }};
#[starknet::interface]
trait ITooManyEvents<TContractState> {{
fn emit_too_many_events(self: @TContractState, count: felt252);
fn emit_too_many_keys(self: @TContractState, count: felt252);
fn emit_too_many_data(self: @TContractState, count: felt252);
}}
fn deploy_contract() -> ITooManyEventsDispatcher {{
let contract = declare("TooManyEvents");
let contract_address = contract.deploy(@array![]).unwrap();
ITooManyEventsDispatcher {{ contract_address }}
}}
#[test]
fn emit_too_many_events() {{
let deployed = deploy_contract();
deployed.emit_too_many_events({emit_too_many_events});
assert(1 == 1, '');
}}
#[test]
fn emit_too_many_keys() {{
let deployed = deploy_contract();
deployed.emit_too_many_keys({emit_too_many_keys});
assert(1 == 1, '');
}}
#[test]
fn emit_too_many_data() {{
let deployed = deploy_contract();
deployed.emit_too_many_data({emit_too_many_data});
assert(1 == 1, '');
}}
"#
),
Contract::from_code_path(
"TooManyEvents".to_string(),
Path::new("tests/data/contracts/too_many_events.cairo"),
)
.unwrap()
);

let result = run_test_case(&test);

assert_failed(&result);
assert_case_output_contains(
&result,
"emit_too_many_events",
&format!("Got an exception while executing a hint: Exceeded the maximum number of events, number events: {emit_too_many_events}, max number events: {max_n_emitted_events}."),
);
assert_case_output_contains(
&result,
"emit_too_many_data",
&format!("Got an exception while executing a hint: Exceeded the maximum data length, data length: {emit_too_many_data}, max data length: {max_data_length}."),
);
assert_case_output_contains(
&result,
"emit_too_many_keys",
&format!("Got an exception while executing a hint: Exceeded the maximum keys length, keys length: {emit_too_many_keys}, max keys length: {max_keys_length}."),
);
}
9 changes: 5 additions & 4 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,13 @@ impl<Extension: ExtensionLogic> ExtendedRuntime<Extension> {
self.propagate_system_call_signal(selector, vm);
Ok(())
} else {
let res = self
.extended_runtime
.execute_hint(vm, exec_scopes, hint_data, constants);
self.extended_runtime
.execute_hint(vm, exec_scopes, hint_data, constants)?;

self.extension
.post_syscall_hook(&selector, &mut self.extended_runtime);
res

Ok(())
}
}
}
Expand Down

0 comments on commit b08fc03

Please sign in to comment.