Skip to content

Commit 2cac124

Browse files
starknet_os: aliases test (#7680)
1 parent 04caed8 commit 2cac124

File tree

7 files changed

+215
-22
lines changed

7 files changed

+215
-22
lines changed

crates/blockifier/src/state/stateful_compression_test.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use std::collections::{HashMap, HashSet};
2-
use std::sync::LazyLock;
32

43
use assert_matches::assert_matches;
54
use rstest::rstest;
6-
use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey};
5+
use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce};
76
use starknet_api::felt;
87
use starknet_api::state::StorageKey;
98
use starknet_types_core::felt::Felt;
@@ -23,9 +22,7 @@ use crate::state::cached_state::{CachedState, StateMaps, StorageEntry};
2322
use crate::state::state_api::{State, StateReader};
2423
use crate::state::stateful_compression::{AliasCompressor, CompressionError};
2524
use crate::test_utils::dict_state_reader::DictStateReader;
26-
27-
static ALIAS_CONTRACT_ADDRESS: LazyLock<ContractAddress> =
28-
LazyLock::new(|| ContractAddress(PatriciaKey::try_from(Felt::TWO).unwrap()));
25+
use crate::test_utils::ALIAS_CONTRACT_ADDRESS;
2926

3027
/// Decompresses the state diff by replacing the aliases with addresses and storage keys.
3128
fn decompress<S: StateReader>(

crates/blockifier/src/test_utils.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ pub mod test_templates;
1010
pub mod transfers_generator;
1111
use std::collections::HashMap;
1212
use std::slice::Iter;
13+
use std::sync::LazyLock;
1314

1415
use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1};
1516
use blockifier_test_utils::contracts::FeatureContract;
1617
use cairo_vm::types::builtin_name::BuiltinName;
1718
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
1819
use starknet_api::abi::abi_utils::{get_fee_token_var_address, selector_from_name};
1920
use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber};
20-
use starknet_api::core::{ClassHash, ContractAddress};
21+
use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey};
2122
use starknet_api::executable_transaction::TransactionType;
2223
use starknet_api::execution_resources::{GasAmount, GasVector};
2324
use starknet_api::hash::StarkHash;
@@ -65,6 +66,9 @@ pub const ERC20_CONTRACT_PATH: &str = "../blockifier_test_utils/resources/ERC20/
6566
ERC20_without_some_syscalls/ERC20/\
6667
erc20_contract_without_some_syscalls_compiled.json";
6768

69+
pub static ALIAS_CONTRACT_ADDRESS: LazyLock<ContractAddress> =
70+
LazyLock::new(|| ContractAddress(PatriciaKey::try_from(Felt::TWO).unwrap()));
71+
6872
#[derive(Clone, Copy, EnumCountMacro, PartialEq, Eq, Debug)]
6973
pub enum CompilerBasedVersion {
7074
CairoVersion(CairoVersion),

crates/starknet_os/src/hint_processor/snos_hint_processor.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,17 @@ impl<'a> SnosHintProcessor<'a, DictStateReader> {
341341
let state_inputs = vec![os_state_input.unwrap_or_default()];
342342
let os_hints_config = os_hints_config.unwrap_or_default();
343343

344-
SnosHintProcessor::new(
344+
let mut hint_processor = SnosHintProcessor::new(
345345
os_program,
346346
os_hints_config,
347347
block_inputs,
348348
state_inputs,
349349
BTreeMap::new(),
350350
BTreeMap::new(),
351351
vec![state_reader],
352-
)
352+
)?;
353+
hint_processor.execution_helpers_manager.increment_current_helper_index();
354+
Ok(hint_processor)
353355
}
354356
}
355357

crates/starknet_os/src/test_utils/cairo_runner.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::any::Any;
22
use std::collections::{HashMap, HashSet};
33

44
use blockifier::blockifier_versioned_constants::VersionedConstants;
5+
use blockifier::test_utils::dict_state_reader::DictStateReader;
56
use cairo_vm::serde::deserialize_program::Member;
67
use cairo_vm::types::builtin_name::BuiltinName;
78
use cairo_vm::types::layout_name::LayoutName;
@@ -553,6 +554,7 @@ fn get_return_values(
553554
/// Hint locals are added to the outermost exec scope.
554555
/// If the endpoint used builtins, the respective returned (implicit) arg is the builtin instance
555556
/// usage, unless the builtin is the output builtin, in which case the arg is the output.
557+
#[allow(clippy::too_many_arguments)]
556558
pub fn run_cairo_0_entry_point(
557559
runner_config: &EntryPointRunnerConfig,
558560
program_bytes: &[u8],
@@ -561,6 +563,7 @@ pub fn run_cairo_0_entry_point(
561563
implicit_args: &[ImplicitArg],
562564
expected_explicit_return_values: &[EndpointArg],
563565
hint_locals: HashMap<String, Box<dyn Any>>,
566+
state_reader: Option<DictStateReader>,
564567
) -> Cairo0EntryPointRunnerResult<(Vec<EndpointArg>, Vec<EndpointArg>, CairoRunner)> {
565568
let mut entrypoint = entrypoint.to_string();
566569
if runner_config.add_main_prefix_to_entrypoint {
@@ -571,7 +574,7 @@ pub fn run_cairo_0_entry_point(
571574
let program = inject_builtins(program_bytes, implicit_args)?;
572575
info!("Successfully injected builtins into program.");
573576

574-
let (state_reader, os_hints_config, os_state_input) = (None, None, None);
577+
let (os_hints_config, os_state_input) = (None, None);
575578
let os_block_input = OsBlockInput::default();
576579
let mut hint_processor = SnosHintProcessor::new_for_testing(
577580
state_reader,

crates/starknet_os/src/test_utils/utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::any::Any;
22
use std::collections::HashMap;
33
use std::sync::LazyLock;
44

5+
use cairo_vm::hint_processor::builtin_hint_processor::dict_hint_utils::DICT_ACCESS_SIZE;
6+
use cairo_vm::types::layout_name::LayoutName;
57
use ethnum::U256;
68
use num_bigint::{BigInt, Sign};
79
use rand::rngs::StdRng;
@@ -30,6 +32,7 @@ pub fn run_cairo_function_and_check_result(
3032
expected_implicit_retdata: &[EndpointArg],
3133
hint_locals: HashMap<String, Box<dyn Any>>,
3234
) -> Cairo0EntryPointRunnerResult<()> {
35+
let state_reader = None;
3336
let (actual_implicit_retdata, actual_explicit_retdata, _) = run_cairo_0_entry_point(
3437
runner_config,
3538
program_bytes,
@@ -38,6 +41,7 @@ pub fn run_cairo_function_and_check_result(
3841
implicit_args,
3942
expected_explicit_retdata,
4043
hint_locals,
44+
state_reader,
4145
)?;
4246
assert_eq!(expected_explicit_retdata, &actual_explicit_retdata);
4347
assert_eq!(expected_implicit_retdata, &actual_implicit_retdata);
@@ -62,6 +66,16 @@ pub fn create_squashed_cairo_dict(
6266
PointerArg::Composed(squashed_dict)
6367
}
6468

69+
pub fn parse_squashed_cairo_dict(squashed_dict: &[Felt]) -> HashMap<Felt, Felt> {
70+
assert!(squashed_dict.len() % DICT_ACCESS_SIZE == 0, "Invalid squashed dict length");
71+
let key_offset = 0;
72+
let new_val_offset = 2;
73+
squashed_dict
74+
.chunks(DICT_ACCESS_SIZE)
75+
.map(|chunk| (chunk[key_offset], chunk[new_val_offset]))
76+
.collect()
77+
}
78+
6579
// 2**251 + 17 * 2**192 + 1
6680
pub static DEFAULT_PRIME: LazyLock<BigInt> = LazyLock::new(|| {
6781
BigInt::from_bytes_be(
@@ -123,3 +137,11 @@ pub fn pack_bigint3(limbs: &[Felt]) -> BigInt {
123137
acc + as_int(&limb, &DEFAULT_PRIME) * BASE.pow(i.try_into().unwrap())
124138
})
125139
}
140+
141+
pub(crate) fn get_entrypoint_runner_config() -> EntryPointRunnerConfig {
142+
EntryPointRunnerConfig {
143+
layout: LayoutName::small,
144+
add_main_prefix_to_entrypoint: false,
145+
..Default::default()
146+
}
147+
}

crates/starknet_os/src/tests/aliases.rs

Lines changed: 175 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,31 @@
1-
use std::collections::HashMap;
1+
use std::collections::{HashMap, HashSet};
22

33
use apollo_starknet_os_program::test_programs::ALIASES_TEST_BYTES;
4+
use blockifier::state::stateful_compression::{ALIAS_COUNTER_STORAGE_KEY, INITIAL_AVAILABLE_ALIAS};
5+
use blockifier::test_utils::dict_state_reader::DictStateReader;
6+
use blockifier::test_utils::ALIAS_CONTRACT_ADDRESS;
7+
use cairo_vm::hint_processor::builtin_hint_processor::dict_hint_utils::DICT_ACCESS_SIZE;
8+
use cairo_vm::hint_processor::hint_processor_utils::felt_to_usize;
9+
use cairo_vm::types::builtin_name::BuiltinName;
10+
use rstest::rstest;
11+
use starknet_api::core::L2_ADDRESS_UPPER_BOUND;
12+
use starknet_api::state::StorageKey;
13+
use starknet_types_core::felt::Felt;
14+
15+
use crate::test_utils::cairo_runner::{
16+
run_cairo_0_entry_point,
17+
EndpointArg,
18+
EntryPointRunnerConfig,
19+
ImplicitArg,
20+
PointerArg,
21+
ValueArg,
22+
};
23+
use crate::test_utils::utils::{
24+
get_entrypoint_runner_config,
25+
parse_squashed_cairo_dict,
26+
test_cairo_function,
27+
};
428

5-
use crate::test_utils::cairo_runner::EntryPointRunnerConfig;
6-
use crate::test_utils::utils::test_cairo_function;
729
// TODO(Nimrod): Move this next to the stateful compression hints implementation.
830
// TODO(Amos): This test is incomplete. Add the rest of the test cases and remove this todo.
931

@@ -29,3 +51,153 @@ fn test_constants() {
2951
HashMap::new(),
3052
)
3153
}
54+
55+
#[rstest]
56+
#[case(
57+
Vec::new(),
58+
Vec::new(),
59+
HashMap::from([(0.into(), 128.into())])
60+
)]
61+
#[case(
62+
vec![Felt::from(&*L2_ADDRESS_UPPER_BOUND)],
63+
vec![128],
64+
HashMap::from([
65+
(0.into(), 129.into()),
66+
(Felt::from(&*L2_ADDRESS_UPPER_BOUND), 128.into())
67+
])
68+
)]
69+
#[case(
70+
vec![2000.into(), 1999999999.into(), 3000.into(), 2000.into()],
71+
vec![128, 129, 130, 128],
72+
HashMap::from([
73+
(0.into(), 131.into()),
74+
(2000.into(), 128.into()),
75+
(3000.into(), 130.into()),
76+
(1999999999.into(), 129.into())
77+
])
78+
)]
79+
#[case(
80+
Vec::from_iter((0..128).map(Felt::from)),
81+
(0..128).collect::<Vec<_>>(),
82+
HashMap::from_iter([(0.into(), 128.into())])
83+
)]
84+
#[case(
85+
Vec::from_iter((0..129).map(Felt::from)),
86+
(0..129).collect::<Vec<_>>(),
87+
HashMap::from_iter([
88+
(0.into(), 129.into()),
89+
(128.into(), 128.into())
90+
])
91+
)]
92+
#[case(
93+
vec![
94+
13.into(),
95+
500.into(),
96+
11.into(),
97+
2000.into(),
98+
2001.into(),
99+
13.into(),
100+
501.into(),
101+
98.into(),
102+
222.into(),
103+
2000.into(),
104+
127.into(),
105+
128.into()
106+
],
107+
vec![13, 128, 11, 129, 130, 13, 131, 98, 132, 129, 127, 133],
108+
HashMap::from([
109+
(0.into(), 134.into()),
110+
(128.into(), 133.into()),
111+
(222.into(), 132.into()),
112+
(500.into(), 128.into()),
113+
(501.into(), 131.into()),
114+
(2000.into(), 129.into()),
115+
(2001.into(), 130.into())
116+
])
117+
)]
118+
#[case(
119+
(0..150_u8)
120+
.map(|i| Felt::from(128) + Felt::TWO.pow(i))
121+
.chain((0..150_u8).map(|i| Felt::from(128) + Felt::TWO.pow(i)))
122+
.collect::<Vec<_>>(),
123+
(0..150_u128)
124+
.map(|i| i + 128)
125+
.chain((0..150_u128).map(|i| i + 128))
126+
.collect::<Vec<_>>(),
127+
HashMap::from_iter(
128+
(0..150_u128)
129+
.map(|i| (Felt::from(128) + Felt::TWO.pow(i), Felt::from(i + 128)))
130+
.chain([(0.into(), (128 + 150).into())])
131+
)
132+
)]
133+
fn allocate_and_replace_keys_from_empty_storage(
134+
#[case] keys: Vec<Felt>,
135+
#[case] expected_alias_per_key: Vec<u128>,
136+
#[case] expected_alias_storage: HashMap<Felt, Felt>,
137+
) {
138+
let expected_alias_per_key: Vec<_> =
139+
expected_alias_per_key.into_iter().map(Felt::from).collect();
140+
let (actual_alias_storage, actual_alias_per_key) =
141+
allocate_aliases_for_keys_and_replace(keys, HashMap::new());
142+
assert_eq!(actual_alias_storage, expected_alias_storage);
143+
assert_eq!(actual_alias_per_key, expected_alias_per_key);
144+
}
145+
146+
fn allocate_aliases_for_keys_and_replace(
147+
keys: Vec<Felt>,
148+
initial_storage: HashMap<StorageKey, Felt>,
149+
) -> (HashMap<Felt, Felt>, Vec<Felt>) {
150+
let runner_config = get_entrypoint_runner_config();
151+
let entrypoint = "__main__.allocate_alias_for_keys_and_replace";
152+
let implicit_args = [ImplicitArg::Builtin(BuiltinName::range_check)];
153+
let unique_keys: HashSet<Felt> = HashSet::from_iter(
154+
keys.iter()
155+
.filter(|key| key >= &&INITIAL_AVAILABLE_ALIAS)
156+
.copied()
157+
.chain([*ALIAS_COUNTER_STORAGE_KEY.key()]),
158+
);
159+
let expected_explicit_return_values = vec![
160+
EndpointArg::Value(ValueArg::Single(Felt::ZERO)), // Aliases.len
161+
EndpointArg::Pointer(PointerArg::Array(vec![ // Aliases.ptr
162+
Felt::ZERO;
163+
(unique_keys.len()) * DICT_ACCESS_SIZE
164+
])),
165+
// Aliases per-key ptr.
166+
EndpointArg::Pointer(PointerArg::Array(vec![Felt::ZERO; keys.len()])),
167+
];
168+
let n_keys_arg = EndpointArg::Value(ValueArg::Single(keys.len().into()));
169+
let keys_arg = EndpointArg::Pointer(PointerArg::Array(keys));
170+
let explicit_args = vec![n_keys_arg, keys_arg];
171+
let storage_view = initial_storage
172+
.into_iter()
173+
.map(|(key, value)| ((*ALIAS_CONTRACT_ADDRESS, key), value))
174+
.collect();
175+
176+
let state_reader = DictStateReader { storage_view, ..Default::default() };
177+
let (_, explicit_return_values, _) = run_cairo_0_entry_point(
178+
&runner_config,
179+
ALIASES_TEST_BYTES,
180+
entrypoint,
181+
&explicit_args,
182+
&implicit_args,
183+
&expected_explicit_return_values,
184+
HashMap::new(),
185+
Some(state_reader),
186+
)
187+
.unwrap();
188+
if let [
189+
EndpointArg::Value(ValueArg::Single(n_aliases)),
190+
EndpointArg::Pointer(PointerArg::Array(aliases_storage_updates)),
191+
EndpointArg::Pointer(PointerArg::Array(alias_per_key)),
192+
] = explicit_return_values.as_slice()
193+
{
194+
let n_aliases = felt_to_usize(n_aliases).unwrap();
195+
assert_eq!(n_aliases, aliases_storage_updates.len() / DICT_ACCESS_SIZE);
196+
let actual_alias_storage = parse_squashed_cairo_dict(aliases_storage_updates);
197+
(actual_alias_storage, alias_per_key.clone().to_vec())
198+
} else {
199+
panic!(
200+
"The return value doesn't match the given format.\n Got: {explicit_return_values:?}"
201+
);
202+
}
203+
}

crates/starknet_os/src/tests/bls_field.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::collections::HashMap;
33

44
use apollo_starknet_os_program::OS_PROGRAM_BYTES;
55
use cairo_vm::types::builtin_name::BuiltinName;
6-
use cairo_vm::types::layout_name::LayoutName;
76
use cairo_vm::types::program::Program;
87
use ethnum::U256;
98
use num_bigint::{BigInt, BigUint, RandBigInt, RandomBits, Sign, ToBigInt};
@@ -16,12 +15,12 @@ use crate::hints::hint_implementation::kzg::utils::{split_bigint3, BASE, BLS_PRI
1615
use crate::test_utils::cairo_runner::{
1716
run_cairo_0_entry_point,
1817
EndpointArg,
19-
EntryPointRunnerConfig,
2018
ImplicitArg,
2119
PointerArg,
2220
ValueArg,
2321
};
2422
use crate::test_utils::utils::{
23+
get_entrypoint_runner_config,
2524
pack_bigint3,
2625
seeded_random_prng,
2726
test_cairo_function,
@@ -32,14 +31,6 @@ const REDUCED_MUL_LIMB_BOUND: i128 = 2_i128.pow(104);
3231

3332
// TODO(Nimrod): Move this next to the BLS hints implementation.
3433

35-
fn get_entrypoint_runner_config() -> EntryPointRunnerConfig {
36-
EntryPointRunnerConfig {
37-
layout: LayoutName::small,
38-
add_main_prefix_to_entrypoint: false,
39-
..Default::default()
40-
}
41-
}
42-
4334
fn run_reduced_mul_test(a_split: &[Felt], b_split: &[Felt]) {
4435
let explicit_args = [
4536
EndpointArg::Value(ValueArg::Array(a_split.to_vec())),
@@ -151,6 +142,7 @@ fn test_horner_eval() {
151142
)));
152143
let implicit_args = [ImplicitArg::Builtin(BuiltinName::range_check)];
153144

145+
let state_reader = None;
154146
let (_, explicit_retdata, _) = run_cairo_0_entry_point(
155147
&entrypoint_runner_config,
156148
OS_PROGRAM_BYTES,
@@ -159,6 +151,7 @@ fn test_horner_eval() {
159151
&implicit_args,
160152
&[EndpointArg::Value(ValueArg::Array(vec![Felt::ZERO, Felt::ZERO, Felt::ZERO]))],
161153
HashMap::new(),
154+
state_reader,
162155
)
163156
.unwrap();
164157

0 commit comments

Comments
 (0)