Skip to content

Commit

Permalink
Fix collecting events in cairo0 (#1836)
Browse files Browse the repository at this point in the history
<!-- Reference any GitHub issues resolved by this PR -->

Closes #1633

## Introduced changes

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

- Fixes events collecting in cairo0

## Checklist

<!-- Make sure all of these are complete -->

- [x] Linked relevant issue
- [x] Updated relevant documentation
- [x] Added relevant tests
- [x] Performed self-review of the code
- [x] Added changes to `CHANGELOG.md`
  • Loading branch information
Draggu authored Mar 8, 2024
1 parent 070f7b7 commit 9c89239
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 35 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Forge

#### Fixed

- Events emitted in cairo 0 contracts are now properly collected

## [0.19.0] - 2024-03-06

### Forge
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,50 @@
use blockifier::execution::syscalls::hint_processor::SyscallHintProcessor;

use crate::{
runtime_extensions::forge_runtime_extension::cheatcodes::spy_events::Event,
state::CheatnetState,
};
use blockifier::execution::{
call_info::OrderedEvent, deprecated_syscalls::hint_processor::DeprecatedSyscallHintProcessor,
syscalls::hint_processor::SyscallHintProcessor,
};
use starknet_api::core::ContractAddress;

pub trait SyscallHintProcessorExt {
fn contract_address(&self) -> ContractAddress;
fn last_event(&self) -> &OrderedEvent;
}

impl SyscallHintProcessorExt for SyscallHintProcessor<'_> {
fn contract_address(&self) -> ContractAddress {
self.call.code_address.unwrap_or(self.call.storage_address)
}
fn last_event(&self) -> &OrderedEvent {
self.events.last().unwrap()
}
}

impl SyscallHintProcessorExt for DeprecatedSyscallHintProcessor<'_> {
fn contract_address(&self) -> ContractAddress {
self.storage_address
}
fn last_event(&self) -> &OrderedEvent {
self.events.last().unwrap()
}
}

pub fn emit_event_hook(
syscall_handler: &SyscallHintProcessor<'_>,
syscall_handler: &impl SyscallHintProcessorExt,
cheatnet_state: &mut CheatnetState,
) {
let contract_address = syscall_handler
.call
.code_address
.unwrap_or(syscall_handler.call.storage_address);
let contract_address = syscall_handler.contract_address();
let last_event = syscall_handler.last_event();
let is_spied_on = cheatnet_state
.spies
.iter()
.any(|spy_on| spy_on.does_spy(contract_address));

for spy_on in &cheatnet_state.spies {
if spy_on.does_spy(contract_address) {
let event =
Event::from_ordered_event(syscall_handler.events.last().unwrap(), contract_address);
cheatnet_state.detected_events.push(event);
break;
}
if is_spied_on {
cheatnet_state
.detected_events
.push(Event::from_ordered_event(last_event, contract_address));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use self::runtime::{
};

use super::call_to_blockifier_runtime_extension::execution::entry_point::execute_call_entry_point;
use super::call_to_blockifier_runtime_extension::execution::syscall_hooks;
use super::call_to_blockifier_runtime_extension::RuntimeState;

pub mod runtime;
Expand Down Expand Up @@ -159,6 +160,17 @@ impl<'a> DeprecatedExtensionLogic for DeprecatedCheatableStarknetRuntimeExtensio
_ => Ok(SyscallHandlingResult::Forwarded),
}
}

fn post_syscall_hook(
&mut self,
selector: &DeprecatedSyscallSelector,
extended_runtime: &mut Self::Runtime,
) {
let syscall_handler = &extended_runtime.hint_handler;
if let DeprecatedSyscallSelector::EmitEvent = selector {
syscall_hooks::emit_event_hook(syscall_handler, self.cheatnet_state);
}
}
}

impl<'a> DeprecatedCheatableStarknetRuntimeExtension<'a> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use std::{any::Any, collections::HashMap};

use blockifier::execution::hint_code;
use crate::runtime_extensions::cheatable_starknet_runtime_extension::stark_felt_from_ptr_immutable;
use anyhow::Result;
use blockifier::execution::{
deprecated_syscalls::{
hint_processor::DeprecatedSyscallHintProcessor, DeprecatedSyscallSelector,
},
hint_code,
syscalls::{hint_processor::SyscallExecutionError, SyscallResult},
};
use cairo_felt::Felt252;
use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name;
use cairo_vm::{
hint_processor::{
builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData,
hint_processor_definition::{HintProcessorLogic, HintReference},
builtin_hint_processor::{
builtin_hint_processor_definition::HintProcessorData, hint_utils::get_ptr_from_var_name,
},
hint_processor_definition::{HintProcessor, HintProcessorLogic, HintReference},
},
serde::deserialize_program::ApTracking,
types::{exec_scope::ExecutionScopes, relocatable::Relocatable},
Expand All @@ -24,12 +27,6 @@ use cairo_vm::{
};
use runtime::{SyscallHandlingResult, SyscallPtrAccess};

use anyhow::Result;

use cairo_vm::hint_processor::hint_processor_definition::HintProcessor;

use crate::runtime_extensions::cheatable_starknet_runtime_extension::stark_felt_from_ptr_immutable;

pub struct DeprecatedStarknetRuntime<'a> {
pub hint_handler: DeprecatedSyscallHintProcessor<'a>,
}
Expand Down Expand Up @@ -161,8 +158,14 @@ impl<Extension: DeprecatedExtensionLogic> DeprecatedExtendedRuntime<Extension> {
{
Ok(())
} else {
self.extended_runtime
.execute_hint(vm, exec_scopes, hint_data, constants)
let res = self
.extended_runtime
.execute_hint(vm, exec_scopes, hint_data, constants);

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

res
}
}
}
Expand Down Expand Up @@ -208,4 +211,10 @@ pub trait DeprecatedExtensionLogic {
) -> Result<SyscallHandlingResult, HintError> {
Ok(SyscallHandlingResult::Forwarded)
}

fn post_syscall_hook(
&mut self,
_selector: &DeprecatedSyscallSelector,
_extended_runtime: &mut Self::Runtime,
);
}
83 changes: 75 additions & 8 deletions crates/cheatnet/tests/cheatcodes/spy_events.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
use crate::common::state::{build_runtime_state, create_cached_state};
use crate::common::{call_contract, deploy_wrapper};
use crate::common::{deploy_contract, felt_selector_from_name, get_contracts};
use cairo_felt::Felt252;
use crate::common::{
call_contract, deploy_contract, deploy_wrapper, felt_selector_from_name, get_contracts,
state::{build_runtime_state, create_cached_state},
};
use blockifier::state::cached_state::{CachedState, GlobalContractCache};
use cairo_felt::{felt_str, Felt252};
use cairo_lang_starknet::contract::starknet_keccak;
use cairo_vm::hint_processor::hint_processor_utils::felt_to_usize;
use cheatnet::runtime_extensions::forge_runtime_extension::cheatcodes::declare::declare;
use cheatnet::runtime_extensions::forge_runtime_extension::cheatcodes::spy_events::{
Event, SpyTarget,
use cheatnet::{
constants::build_testing_state,
forking::state::ForkStateReader,
runtime_extensions::forge_runtime_extension::cheatcodes::{
declare::declare,
spy_events::{Event, SpyTarget},
},
state::{CheatnetState, ExtendedStateReader},
};
use cheatnet::state::CheatnetState;
use conversions::IntoConv;
use starknet_api::block::BlockNumber;
use std::vec;
use tempfile::TempDir;

pub fn felt_vec_to_event_vec(felts: &[Felt252]) -> Vec<Event> {
let mut events = vec![];
Expand Down Expand Up @@ -625,3 +633,62 @@ fn test_emitted_by_emit_events_syscall() {
"Wrong spy_events_checker event"
);
}
#[test]
fn capture_cairo0_event() {
let temp_dir = TempDir::new().unwrap();
let mut cached_state = CachedState::new(
ExtendedStateReader {
dict_state_reader: build_testing_state(),
fork_state_reader: Some(ForkStateReader::new(
"http://188.34.188.184:6060/rpc/v0_6".parse().unwrap(),
BlockNumber(960_107),
temp_dir.path().to_str().unwrap(),
)),
},
GlobalContractCache::default(),
);
let mut cheatnet_state = CheatnetState::default();
let mut runtime_state = build_runtime_state(&mut cheatnet_state);

let contract_address = deploy_contract(
&mut cached_state,
&mut runtime_state,
"SpyEventsCairo0",
&[],
);

let id = runtime_state.cheatnet_state.spy_events(SpyTarget::All);

let selector = felt_selector_from_name("test_cairo0_event_collection");

let cairo0_contract_address = felt_str!(
"1960625ba5c435bac113ecd15af3c60e327d550fc5dbb43f07cd0875ad2f54c",
16
);

call_contract(
&mut cached_state,
&mut runtime_state,
&contract_address,
&selector,
&[cairo0_contract_address.clone()],
);

let (length, serialized_events) = runtime_state
.cheatnet_state
.fetch_events(&Felt252::from(id));

let events = felt_vec_to_event_vec(&serialized_events);

assert_eq!(length, 1, "There should be one event");

assert_eq!(
events[0],
Event {
from: cairo0_contract_address.into_(),
keys: vec![starknet_keccak("my_event".as_ref()).into()],
data: vec![Felt252::from(123_456_789)]
},
"Wrong spy_events_checker event"
);
}
1 change: 1 addition & 0 deletions crates/cheatnet/tests/contracts/src/events.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ mod spy_events_order_checker;
mod spy_events_lib_call;
mod constructor_spy_events_checker;
mod spy_events_checker_proxy;
mod spy_events_cairo0;
34 changes: 34 additions & 0 deletions crates/cheatnet/tests/contracts/src/events/spy_events_cairo0.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use starknet::ContractAddress;

// https://testnet.starkscan.co/contract/0x1960625ba5c435bac113ecd15af3c60e327d550fc5dbb43f07cd0875ad2f54c
#[starknet::interface]
trait ICairo0Contract<TContractState> {
// this function only job is to emit `my_event` with single felt252 value
fn emit_one_cairo0_event(ref self: TContractState, contract_address: felt252);
}

#[starknet::interface]
trait ISpyEventsCairo0<TContractState> {
fn test_cairo0_event_collection(ref self: TContractState, cairo0_address: ContractAddress);
}

#[starknet::contract]
mod SpyEventsCairo0 {
use core::traits::Into;
use starknet::{get_contract_address, get_caller_address, ContractAddress};
use super::ICairo0ContractDispatcherTrait;

#[storage]
struct Storage {}

#[abi(embed_v0)]
impl ISpyEventsCairo0 of super::ISpyEventsCairo0<ContractState> {
fn test_cairo0_event_collection(ref self: ContractState, cairo0_address: ContractAddress) {
let cairo0_contract = super::ICairo0ContractDispatcher {
contract_address: cairo0_address
};

cairo0_contract.emit_one_cairo0_event(123456789);
}
}
}
20 changes: 19 additions & 1 deletion crates/forge/tests/data/contracts/spy_events_checker.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
use starknet::ContractAddress;

// https://testnet.starkscan.co/contract/0x1960625ba5c435bac113ecd15af3c60e327d550fc5dbb43f07cd0875ad2f54c
#[starknet::interface]
trait ICairo0Contract<TContractState> {
// this function only job is to emit `my_event` with single felt252 value
fn emit_one_cairo0_event(ref self: TContractState, contract_address: felt252);
}

#[starknet::interface]
trait ISpyEventsChecker<TContractState> {
fn do_not_emit(ref self: TContractState);
Expand All @@ -14,12 +21,14 @@ trait ISpyEventsChecker<TContractState> {
even_more_data: u256
);
fn emit_event_syscall(ref self: TContractState, some_key: felt252, some_data: felt252);
fn test_cairo0_event_collection(ref self: TContractState, cairo0_address: ContractAddress);
}

#[starknet::contract]
mod SpyEventsChecker {
use starknet::ContractAddress;
use starknet::SyscallResultTrait;
use super::ICairo0ContractDispatcherTrait;

#[storage]
struct Storage {}
Expand Down Expand Up @@ -78,7 +87,16 @@ mod SpyEventsChecker {
}

fn emit_event_syscall(ref self: ContractState, some_key: felt252, some_data: felt252) {
starknet::emit_event_syscall(array![some_key].span(), array![some_data].span()).unwrap_syscall();
starknet::emit_event_syscall(array![some_key].span(), array![some_data].span())
.unwrap_syscall();
}

fn test_cairo0_event_collection(ref self: ContractState, cairo0_address: ContractAddress) {
let cairo0_contract = super::ICairo0ContractDispatcher {
contract_address: cairo0_address
};

cairo0_contract.emit_one_cairo0_event(123456789);
}
}
}
Loading

0 comments on commit 9c89239

Please sign in to comment.