Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pop logs to testing #3300

Merged
merged 18 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from 9 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
7 changes: 7 additions & 0 deletions corelib/src/starknet/testing.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use starknet::ContractAddress;

#[derive(Drop)]
struct Log {
keys: Array<felt252>,
data: Array<felt252>,
}

extern fn set_caller_address(address: ContractAddress) implicits() nopanic;
extern fn set_contract_address(address: ContractAddress) implicits() nopanic;
extern fn set_sequencer_address(address: ContractAddress) implicits() nopanic;
Expand All @@ -12,3 +18,4 @@ extern fn set_transaction_hash(hash: felt252) implicits() nopanic;
extern fn set_chain_id(chain_id: felt252) implicits() nopanic;
extern fn set_nonce(nonce: felt252) implicits() nopanic;
extern fn set_signature(signature: Span<felt252>) implicits() nopanic;
extern fn pop_log(address: ContractAddress) -> Option<Log> implicits() nopanic;
14 changes: 14 additions & 0 deletions crates/cairo-lang-casm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,20 @@ macro_rules! casm_build_extend {
);
$crate::casm_build_extend!($builder, $($tok)*)
};
($builder:ident, hint $hint_lead:ident::$hint_name:ident {
$($input_name:ident : $input_value:ident),*
} into {
$($output_name:ident : $output_value:ident),*
}; $($tok:tt)*) => {
$builder.add_hint(
|[$($input_name),*], [$($output_name),*]| $hint_lead::$hint_name {
$($input_name,)* $($output_name,)*
},
[$($input_value,)*],
[$($output_value,)*],
);
$crate::casm_build_extend!($builder, $($tok)*)
};
($builder:ident, rescope { $($new_var:ident = $value_var:ident),* }; $($tok:tt)*) => {
$builder.rescope([$(($new_var, $value_var)),*]);
$crate::casm_build_extend!($builder, $($tok)*)
Expand Down
19 changes: 19 additions & 0 deletions crates/cairo-lang-casm/src/hints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ pub enum StarknetHint {
SetNonce { value: ResOperand },
#[codec(index = 12)]
SetSignature { start: ResOperand, end: ResOperand },
#[codec(index = 13)]
PopLog {
value: ResOperand,
opt_variant: CellRef,
keys_start: CellRef,
keys_end: CellRef,
data_start: CellRef,
data_end: CellRef,
},
}

// Represents a cairo core hint.
Expand Down Expand Up @@ -759,6 +768,16 @@ impl Display for StarknetHint {
ResOperandFormatter(end)
)
}
StarknetHint::PopLog {
value,
opt_variant: _,
keys_start: _,
keys_end: _,
data_start: _,
data_end: _,
} => {
write!(f, "Get log from address: {}", ResOperandFormatter(value),)
}
}
}
}
62 changes: 57 additions & 5 deletions crates/cairo-lang-runner/src/casm_run/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::any::Any;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::{HashMap, VecDeque};
use std::ops::{Deref, Shl};

use ark_ff::fields::{Fp256, MontBackend, MontConfig};
Expand Down Expand Up @@ -147,6 +147,8 @@ pub struct StarknetState {
/// A mapping from contract address to class hash.
#[allow(dead_code)]
deployed_contracts: HashMap<Felt252, Felt252>,
/// A mapping from contract address to logs.
logs: HashMap<Felt252, VecDeque<Log>>,
/// The simulated execution info.
exec_info: ExecutionInfo,
next_id: Felt252,
Expand All @@ -158,6 +160,12 @@ impl StarknetState {
}
}

#[derive(Clone, Default)]
struct Log {
keys: Vec<Felt252>,
data: Vec<Felt252>,
}

/// Copy of the cairo `ExecutionInfo` struct.
#[derive(Clone, Default)]
struct ExecutionInfo {
Expand Down Expand Up @@ -380,6 +388,39 @@ impl HintProcessor for CairoHintProcessor<'_> {
let end = get_ptr(vm, cell, &offset)?;
self.starknet_state.exec_info.tx_info.signature = vm_get_range(vm, start, end)?;
}
StarknetHint::PopLog {
value,
opt_variant,
keys_start,
keys_end,
data_start,
data_end,
} => {
let contract_address = get_val(vm, value)?;
let mut res_segment = MemBuffer::new_segment(vm);
let logs = self.starknet_state.logs.entry(contract_address.clone()).or_default();

let log = logs.pop_front();
if let Some(l) = log {
let keys_start_ptr = res_segment.ptr;
res_segment.write_data(l.keys.iter())?;
let keys_end_ptr = res_segment.ptr;

let data_start_ptr = res_segment.ptr;
res_segment.write_data(l.data.iter())?;
let data_end_ptr = res_segment.ptr;

// Option::Some variant
insert_value_to_cellref!(vm, opt_variant, 0)?;
insert_value_to_cellref!(vm, keys_start, keys_start_ptr)?;
insert_value_to_cellref!(vm, keys_end, keys_end_ptr)?;
insert_value_to_cellref!(vm, data_start, data_start_ptr)?;
insert_value_to_cellref!(vm, data_end, data_end_ptr)?;
} else {
// Option::None variant
insert_value_to_cellref!(vm, opt_variant, 1)?;
}
}
};
Ok(())
}
Expand Down Expand Up @@ -590,10 +631,7 @@ impl<'a> CairoHintProcessor<'a> {
self.get_execution_info(gas_counter, system_buffer)
}),
"EmitEvent" => execute_handle_helper(&mut |system_buffer, gas_counter| {
let _keys = system_buffer.next_arr()?;
let _values = system_buffer.next_arr()?;
deduct_gas!(gas_counter, 50);
Ok(SyscallResult::Success(vec![]))
self.emit_event(gas_counter, system_buffer.next_arr()?, system_buffer.next_arr()?)
}),
"SendMessageToL1" => execute_handle_helper(&mut |system_buffer, gas_counter| {
let _to_address = system_buffer.next_felt252()?;
Expand Down Expand Up @@ -794,6 +832,20 @@ impl<'a> CairoHintProcessor<'a> {
Ok(SyscallResult::Success(vec![exec_info_ptr.into()]))
}

/// Executes the `emit_event_syscall` syscall.
fn emit_event(
&mut self,
gas_counter: &mut usize,
keys: Vec<Felt252>,
data: Vec<Felt252>,
) -> Result<SyscallResult, HintError> {
deduct_gas!(gas_counter, 50);
let log = Log { keys, data };
let contract = self.starknet_state.exec_info.contract_address.clone();
self.starknet_state.logs.entry(contract).or_default().push_front(log);
Ok(SyscallResult::Success(vec![]))
}

/// Executes the `deploy_syscall` syscall.
fn deploy(
&mut self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use cairo_lang_sierra::extensions::mem::MemConcreteLibfunc;
use cairo_lang_sierra::extensions::nullable::NullableConcreteLibfunc;
use cairo_lang_sierra::extensions::pedersen::PedersenConcreteLibfunc;
use cairo_lang_sierra::extensions::poseidon::PoseidonConcreteLibfunc;
use cairo_lang_sierra::extensions::starknet::testing::TestingConcreteLibfunc;
use cairo_lang_sierra::extensions::starknet::StarkNetConcreteLibfunc;
use cairo_lang_sierra::extensions::structure::StructConcreteLibfunc;
use cairo_lang_sierra::ids::ConcreteTypeId;
Expand Down Expand Up @@ -241,7 +242,10 @@ pub fn core_libfunc_ap_change<InfoProvider: InvocationApChangeInfoProvider>(
| StarkNetConcreteLibfunc::Secp256(_) => {
vec![ApChange::Known(2), ApChange::Known(2)]
}
StarkNetConcreteLibfunc::Testing(_) => vec![ApChange::Known(0)],
StarkNetConcreteLibfunc::Testing(libfunc) => match libfunc {
TestingConcreteLibfunc::PopLog(_) => vec![ApChange::Known(5), ApChange::Known(5)],
_ => vec![ApChange::Known(0)],
},
},
CoreConcreteLibfunc::Nullable(libfunc) => match libfunc {
NullableConcreteLibfunc::Null(_) => vec![ApChange::Known(0)],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::vec;
use cairo_lang_sierra::extensions::starknet::secp256::{
Secp256ConcreteLibfunc, Secp256OpConcreteLibfunc,
};
use cairo_lang_sierra::extensions::starknet::testing::TestingConcreteLibfunc;
use cairo_lang_sierra::extensions::starknet::StarkNetConcreteLibfunc;

use crate::objects::ConstCost;
Expand Down Expand Up @@ -46,7 +47,10 @@ pub fn starknet_libfunc_cost_base(libfunc: &StarkNetConcreteLibfunc) -> Vec<Cons
StarkNetConcreteLibfunc::LibraryCall(_) => syscall_cost(4),
StarkNetConcreteLibfunc::ReplaceClass(_) => syscall_cost(1),
StarkNetConcreteLibfunc::SendMessageToL1(_) => syscall_cost(3),
StarkNetConcreteLibfunc::Testing(_) => vec![steps(1)],
StarkNetConcreteLibfunc::Testing(libfunc) => match libfunc {
TestingConcreteLibfunc::PopLog(_) => vec![steps(2), steps(2)],
_ => vec![steps(1)],
},
StarkNetConcreteLibfunc::Secp256(libfunc) => {
match libfunc {
Secp256ConcreteLibfunc::K1(libfunc) => match libfunc {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use cairo_lang_casm::hints::StarknetHint;
use cairo_lang_sierra::extensions::starknet::testing::TestingConcreteLibfunc;

use crate::invocations::{
add_input_variables, CompiledInvocation, CompiledInvocationBuilder, CostValidationInfo,
InvocationError,
add_input_variables, get_non_fallthrough_statement_id, CompiledInvocation,
CompiledInvocationBuilder, CostValidationInfo, InvocationError,
};

/// Builds instructions for starknet test setup operations.
Expand Down Expand Up @@ -72,8 +72,39 @@ pub fn build(
hint StarknetHint::SetSignature { start: start, end: end };
};
}
TestingConcreteLibfunc::PopLog(_) => {
let address = declare_single_value()?;

casm_build_extend! {casm_builder,
tempvar variant;
tempvar keys_start;
tempvar keys_end;
tempvar data_start;
tempvar data_end;
hint StarknetHint::PopLog {
value: address
} into {
opt_variant: variant, keys_start: keys_start,
keys_end: keys_end, data_start: data_start,
data_end: data_end
};
ap += 5;
jump None if variant != 0;
};

let none_variant_id = get_non_fallthrough_statement_id(&builder);
return Ok(builder.build_from_casm_builder(
casm_builder,
[
("Fallthrough", &[&[keys_start, keys_end, data_start, data_end]], None),
("None", &[], Some(none_variant_id)),
],
CostValidationInfo::default(),
));
}
}
casm_build_extend! {casm_builder, ap += 0; };

Ok(builder.build_from_casm_builder(
casm_builder,
[("Fallthrough", &[], None)],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
use std::marker::PhantomData;

use super::felt252_span_ty;
use super::interoperability::ContractAddressType;
use super::{felt252_span_ty, ArrayType};
use crate::define_libfunc_hierarchy;
use crate::extensions::felt252::Felt252Type;
use crate::extensions::int::unsigned::Uint64Type;
use crate::extensions::int::unsigned128::Uint128Type;
use crate::extensions::lib_func::{
LibfuncSignature, SierraApChange, SignatureSpecializationContext,
BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
SierraApChange, SignatureSpecializationContext,
};
use crate::extensions::structure::StructType;
use crate::extensions::{
NamedType, NoGenericArgsGenericLibfunc, NoGenericArgsGenericType, SpecializationError,
NamedType, NoGenericArgsGenericLibfunc, NoGenericArgsGenericType, OutputVarReferenceInfo,
SpecializationError,
};
use crate::ids::ConcreteTypeId;
use crate::ids::{ConcreteTypeId, UserTypeId};
use crate::program::GenericArg;
/// Trait for implementing test setters.
pub trait TestSetterTraits: Default {
/// The generic libfunc id for the setter libfunc.
Expand Down Expand Up @@ -151,6 +155,62 @@ impl TestSetterTraits for SetSignatureTrait {
}
}

#[derive(Default)]
pub struct PopLogLibfunc {}

impl NoGenericArgsGenericLibfunc for PopLogLibfunc {
const STR_ID: &'static str = "pop_log";

fn specialize_signature(
&self,
context: &dyn SignatureSpecializationContext,
) -> Result<LibfuncSignature, SpecializationError> {
let contract_address_ty = context.get_concrete_type(ContractAddressType::id(), &[])?;
Ok(LibfuncSignature {
param_signatures: vec![ParamSignature::new(contract_address_ty)],
branch_signatures: vec![
// Some variant branch.
BranchSignature {
vars: vec![
// Log
OutputVarInfo {
ty: get_log_type(context)?,
ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
},
],
ap_change: SierraApChange::Known { new_vars_only: false },
},
// None variant branch.
BranchSignature {
vars: vec![],
ap_change: SierraApChange::Known { new_vars_only: false },
},
],
fallthrough: Some(0),
})
}
}

/// Helper for Log type def.
fn get_log_type(
context: &dyn SignatureSpecializationContext,
) -> Result<ConcreteTypeId, SpecializationError> {
let felt252_array_ty = context.get_wrapped_concrete_type(
ArrayType::id(),
context.get_concrete_type(Felt252Type::id(), &[])?,
)?;
context.get_concrete_type(
StructType::id(),
&[
GenericArg::UserType(UserTypeId::from_string("core::starknet::testing::Log")),
// keys
GenericArg::Type(felt252_array_ty.clone()),
// data
GenericArg::Type(felt252_array_ty),
],
)
}

define_libfunc_hierarchy! {
pub enum TestingLibfunc {
SetBlockNumber(TestSetterLibfunc<SetBlockNumberTrait>),
Expand All @@ -165,5 +225,6 @@ define_libfunc_hierarchy! {
SetChainId(TestSetterLibfunc<SetChainIdTrait>),
SetNonce(TestSetterLibfunc<SetNonceTrait>),
SetSignature(TestSetterLibfunc<SetSignatureTrait>),
PopLog(PopLogLibfunc),
}, TestingConcreteLibfunc
}
26 changes: 26 additions & 0 deletions crates/cairo-lang-starknet/cairo_level_tests/contract_tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,32 @@ fn test_get_signature() {
assert_eq(*read_signature.at(1), 'signature', 'unexpected element 1');
}

#[test]
#[available_gas(300000)]
fn test_pop_log() {
let contract_address = starknet::contract_address_const::<0x1234>();
starknet::testing::set_contract_address(contract_address);
let mut keys = Default::default();
let mut data = Default::default();
keys.append(1234);
data.append(2345);
starknet::emit_event_syscall(keys.span(), data.span());
let log = starknet::testing::pop_log(contract_address).unwrap();

assert_eq(log.keys.len(), 1, 'unexpected keys size');
assert_eq(log.data.len(), 1, 'unexpected data size');
assert_eq(*log.keys.at(0), 1234, 'unexpected key');
assert_eq(*log.data.at(0), 2345, 'unexpected data');
}

#[test]
#[available_gas(300000)]
#[should_panic]
fn test_pop_log_empty_logs() {
let contract_address = starknet::contract_address_const::<0x1234>();
starknet::testing::pop_log(contract_address).unwrap();
}

#[test]
#[should_panic]
fn test_out_of_range_storage_address_from_felt252() -> starknet::StorageAddress {
Expand Down