diff --git a/crates/blockifier/src/execution/native/syscall_handler.rs b/crates/blockifier/src/execution/native/syscall_handler.rs index 55e027ae28..ee03fce54c 100644 --- a/crates/blockifier/src/execution/native/syscall_handler.rs +++ b/crates/blockifier/src/execution/native/syscall_handler.rs @@ -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::{ @@ -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, @@ -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( diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs index 7bd8b7b18c..9dde7b2c2f 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs @@ -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; @@ -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()), @@ -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(); @@ -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(