Skip to content

Commit

Permalink
feat(blockifier): add emit_event cairo native syscall (#1550)
Browse files Browse the repository at this point in the history
  • Loading branch information
PearsonWhite authored Nov 14, 2024
1 parent 216bd41 commit a07960d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 14 deletions.
29 changes: 24 additions & 5 deletions crates/blockifier/src/execution/native/syscall_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use starknet_api::core::{
};
use starknet_api::state::StorageKey;
use starknet_api::transaction::fields::{Calldata, ContractAddressSalt};
use starknet_api::transaction::L2ToL1Payload;
use starknet_api::transaction::{EventContent, EventData, EventKey, L2ToL1Payload};
use starknet_types_core::felt::Felt;

use crate::execution::call_info::{
Expand All @@ -45,6 +45,7 @@ use crate::execution::entry_point::{
use crate::execution::errors::EntryPointExecutionError;
use crate::execution::execution_utils::execute_deployment;
use crate::execution::native::utils::{calculate_resource_bounds, default_tx_v2_info};
use crate::execution::syscalls::exceeds_event_size_limit;
use crate::execution::syscalls::hint_processor::{
SyscallExecutionError,
INVALID_INPUT_LENGTH_ERROR,
Expand Down Expand Up @@ -492,11 +493,29 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> {

fn emit_event(
&mut self,
_keys: &[Felt],
_data: &[Felt],
_remaining_gas: &mut u128,
keys: &[Felt],
data: &[Felt],
remaining_gas: &mut u128,
) -> SyscallResult<()> {
todo!("Implement emit_event syscall.");
self.pre_execute_syscall(remaining_gas, self.context.gas_costs().emit_event_gas_cost)?;

let order = self.context.n_emitted_events;
let event = EventContent {
keys: keys.iter().copied().map(EventKey).collect(),
data: EventData(data.to_vec()),
};

exceeds_event_size_limit(
self.context.versioned_constants(),
self.context.n_emitted_events + 1,
&event,
)
.map_err(|e| self.handle_error(remaining_gas, e.into()))?;

self.events.push(OrderedEvent { order, event });
self.context.n_emitted_events += 1;

Ok(())
}

fn send_message_to_l1(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use itertools::concat;
#[cfg(feature = "cairo_native")]
use pretty_assertions::assert_eq;
use starknet_api::felt;
use starknet_api::transaction::fields::Calldata;
Expand All @@ -25,11 +26,14 @@ const DATA: [Felt; 3] = [
];
const N_EMITTED_EVENTS: [Felt; 1] = [Felt::from_hex_unchecked("0x1")];

#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native), 57430; "Native")
)]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 47330; "VM")]
fn positive_flow(test_contract: FeatureContract, expected_gas: u64) {
// TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion
// works.
let call_info = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &DATA).unwrap();
let call_info = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &DATA)
.expect("emit_events failed with valued parameters");
let event = EventContent {
keys: KEYS.into_iter().map(EventKey).collect(),
data: EventData(DATA.to_vec()),
Expand All @@ -45,35 +49,53 @@ fn positive_flow(test_contract: FeatureContract, expected_gas: u64) {
);
}

#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native); "Native")
)]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")]
fn data_length_exceeds_limit(test_contract: FeatureContract) {
let versioned_constants = VersionedConstants::create_for_testing();

let max_event_data_length = versioned_constants.tx_event_limits.max_data_length;
let data_too_long = vec![felt!(2_u16); max_event_data_length + 1];
let error = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &data_too_long).unwrap_err();

let call_result = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &data_too_long);

let error_message = call_result.unwrap_err().to_string();

let expected_error = EmitEventError::ExceedsMaxDataLength {
data_length: max_event_data_length + 1,
max_data_length: max_event_data_length,
};
assert!(error.to_string().contains(&expected_error.to_string()));
assert!(error_message.contains(&expected_error.to_string()));
}

#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native); "Native")
)]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")]
fn keys_length_exceeds_limit(test_contract: FeatureContract) {
let versioned_constants = VersionedConstants::create_for_testing();

let max_event_keys_length = versioned_constants.tx_event_limits.max_keys_length;
let keys_too_long = vec![felt!(1_u16); max_event_keys_length + 1];
let error = emit_events(test_contract, &N_EMITTED_EVENTS, &keys_too_long, &DATA).unwrap_err();

let call_result = emit_events(test_contract, &N_EMITTED_EVENTS, &keys_too_long, &DATA);

let error_message = call_result.unwrap_err().to_string();

let expected_error = EmitEventError::ExceedsMaxKeysLength {
keys_length: max_event_keys_length + 1,
max_keys_length: max_event_keys_length,
};

assert!(error.to_string().contains(&expected_error.to_string()));
assert!(error_message.contains(&expected_error.to_string()));
}

#[cfg(feature = "cairo_native")]
#[test_case(FeatureContract::TestContract(CairoVersion::Native); "Native")]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")]
fn event_number_exceeds_limit(test_contract: FeatureContract) {
let versioned_constants = VersionedConstants::create_for_testing();
Expand All @@ -82,12 +104,15 @@ fn event_number_exceeds_limit(test_contract: FeatureContract) {
let n_emitted_events_too_big = vec![felt!(
u16::try_from(max_n_emitted_events + 1).expect("Failed to convert usize to u16.")
)];
let error = emit_events(test_contract, &n_emitted_events_too_big, &KEYS, &DATA).unwrap_err();
let call_result = emit_events(test_contract, &n_emitted_events_too_big, &KEYS, &DATA);

let error_message = call_result.unwrap_err().to_string();

let expected_error = EmitEventError::ExceedsMaxNumberOfEmittedEvents {
n_emitted_events: max_n_emitted_events + 1,
max_n_emitted_events,
};
assert!(error.to_string().contains(&expected_error.to_string()));
assert!(error_message.contains(&expected_error.to_string()));
}

fn emit_events(
Expand Down

0 comments on commit a07960d

Please sign in to comment.