Skip to content

Commit 2265a80

Browse files
test(starknet_os): hint consistency test with local program objects
1 parent 394fb8f commit 2265a80

File tree

2 files changed

+61
-45
lines changed

2 files changed

+61
-45
lines changed
Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
1-
use std::collections::HashSet;
2-
31
use blake2s::encode_felts_to_u32s;
4-
use cairo_vm::hint_processor::builtin_hint_processor::hint_code::HINT_CODES;
5-
use cairo_vm::hint_processor::builtin_hint_processor::kzg_da::WRITE_DIVMOD_SEGMENT;
6-
use cairo_vm::hint_processor::builtin_hint_processor::secp::cairo0_hints::CAIRO0_HINT_CODES;
7-
use starknet_os::hints::enum_definition::{AggregatorHint, HintExtension, OsHint};
8-
use starknet_os::hints::types::HintEnum;
92
use starknet_types_core::felt::Felt;
10-
use strum::IntoEnumIterator;
113

124
use crate::os_cli::commands::{validate_input, Input};
135
use crate::os_cli::tests::aliases::aliases_test;
@@ -19,7 +11,6 @@ use crate::shared_utils::types::{PythonTestError, PythonTestRunner};
1911
pub enum OsPythonTestRunner {
2012
AliasesTest,
2113
BlsFieldTest,
22-
CompareOsHints,
2314
InputDeserialization,
2415
EncodeFelts,
2516
}
@@ -32,7 +23,6 @@ impl TryFrom<String> for OsPythonTestRunner {
3223
match value.as_str() {
3324
"aliases_test" => Ok(Self::AliasesTest),
3425
"bls_field_test" => Ok(Self::BlsFieldTest),
35-
"compare_os_hints" => Ok(Self::CompareOsHints),
3626
"input_deserialization" => Ok(Self::InputDeserialization),
3727
"encode_felts" => Ok(Self::EncodeFelts),
3828
_ => Err(PythonTestError::UnknownTestName(value)),
@@ -47,7 +37,6 @@ impl PythonTestRunner for OsPythonTestRunner {
4737
match self {
4838
Self::AliasesTest => aliases_test(Self::non_optional_input(input)?),
4939
Self::BlsFieldTest => test_bls_field(Self::non_optional_input(input)?),
50-
Self::CompareOsHints => compare_os_hints(Self::non_optional_input(input)?),
5140
Self::InputDeserialization => input_deserialization(Self::non_optional_input(input)?),
5241
Self::EncodeFelts => {
5342
let felts: Vec<Felt> = serde_json::from_str(Self::non_optional_input(input)?)?;
@@ -57,44 +46,10 @@ impl PythonTestRunner for OsPythonTestRunner {
5746
}
5847
}
5948

60-
#[allow(clippy::result_large_err)]
61-
fn compare_os_hints(input: &str) -> OsPythonTestResult {
62-
let unfiltered_python_hints: HashSet<String> = serde_json::from_str(input)?;
63-
64-
// Remove VM hints.
65-
let vm_hints = vm_hints();
66-
let python_os_hints: HashSet<String> = unfiltered_python_hints
67-
.into_iter()
68-
.filter(|hint| !vm_hints.contains(hint.as_str()))
69-
.collect();
70-
71-
// We ignore `SyscallHint`s here, as they are not part of the compiled OS.
72-
let rust_os_hints: HashSet<String> = OsHint::iter()
73-
.map(|hint| hint.to_str().to_string())
74-
.chain(HintExtension::iter().map(|hint| hint.to_str().to_string()))
75-
.chain(AggregatorHint::iter().map(|hint| hint.to_str().to_string()))
76-
.collect();
77-
78-
let mut only_in_python: Vec<String> =
79-
python_os_hints.difference(&rust_os_hints).cloned().collect();
80-
only_in_python.sort();
81-
let mut only_in_rust: Vec<String> =
82-
rust_os_hints.difference(&python_os_hints).cloned().collect();
83-
only_in_rust.sort();
84-
Ok(serde_json::to_string(&(only_in_python, only_in_rust))?)
85-
}
86-
8749
/// Deserialize the input string into an `Input` struct.
8850
#[allow(clippy::result_large_err)]
8951
fn input_deserialization(input_str: &str) -> OsPythonTestResult {
9052
let input = serde_json::from_str::<Input>(input_str)?;
9153
validate_input(&input.os_hints.os_input);
9254
Ok("Deserialization successful".to_string())
9355
}
94-
95-
fn vm_hints() -> HashSet<&'static str> {
96-
let mut vm_hints = HashSet::from([WRITE_DIVMOD_SEGMENT]);
97-
vm_hints.extend(HINT_CODES.values());
98-
vm_hints.extend(CAIRO0_HINT_CODES.values());
99-
vm_hints
100-
}

crates/starknet_os/src/hints/enum_definition_test.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,40 @@
11
use std::collections::HashSet;
2+
use std::sync::LazyLock;
23

4+
use apollo_starknet_os_program::{AGGREGATOR_PROGRAM, OS_PROGRAM};
35
use blockifier::execution::hint_code::SYSCALL_HINTS;
6+
use cairo_vm::hint_processor::builtin_hint_processor::hint_code::HINT_CODES;
7+
use cairo_vm::hint_processor::builtin_hint_processor::kzg_da::WRITE_DIVMOD_SEGMENT;
8+
use cairo_vm::hint_processor::builtin_hint_processor::secp::cairo0_hints::CAIRO0_HINT_CODES;
9+
use cairo_vm::types::program::Program;
410
use strum::IntoEnumIterator;
511

612
use crate::hints::enum_definition::{AllHints, DeprecatedSyscallHint};
713
use crate::hints::types::HintEnum;
814

15+
static VM_HINTS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
16+
let mut vm_hints = HashSet::from([WRITE_DIVMOD_SEGMENT]);
17+
vm_hints.extend(HINT_CODES.values());
18+
vm_hints.extend(CAIRO0_HINT_CODES.values());
19+
vm_hints
20+
});
21+
22+
fn program_hints(program: &Program) -> HashSet<String> {
23+
program
24+
.shared_program_data
25+
.hints_collection
26+
.iter_hints()
27+
.map(|hint| hint.code.clone())
28+
.collect()
29+
}
30+
31+
fn unknown_hints_for_program(program: &Program) -> HashSet<String> {
32+
program_hints(program)
33+
.into_iter()
34+
.filter(|hint| AllHints::from_str(&hint).is_err() && !VM_HINTS.contains(hint.as_str()))
35+
.collect()
36+
}
37+
938
#[test]
1039
fn test_hint_strings_are_unique() {
1140
let all_hints = AllHints::all_iter().map(|hint| hint.to_str()).collect::<Vec<_>>();
@@ -34,3 +63,35 @@ fn test_syscall_compatibility_with_blockifier() {
3463
the implementation."
3564
);
3665
}
66+
67+
#[test]
68+
fn test_all_hints_are_known() {
69+
let unknown_os_hints = unknown_hints_for_program(&OS_PROGRAM);
70+
let unknown_aggregator_hints = unknown_hints_for_program(&AGGREGATOR_PROGRAM);
71+
let unknown_hints: HashSet<String> =
72+
unknown_os_hints.union(&unknown_aggregator_hints).cloned().collect();
73+
74+
assert!(
75+
unknown_hints.is_empty(),
76+
"The following hints are not known in 'starknet_os': {unknown_hints:#?}."
77+
);
78+
}
79+
80+
#[test]
81+
fn test_all_hints_are_used() {
82+
let os_hints = program_hints(&OS_PROGRAM);
83+
let aggregator_hints = program_hints(&AGGREGATOR_PROGRAM);
84+
let all_program_hints: HashSet<&String> = os_hints.union(&aggregator_hints).collect();
85+
let redundant_hints: HashSet<_> = AllHints::all_iter()
86+
.filter(|hint| {
87+
// Skip syscalls; they do not appear in the OS code.
88+
!matches!(hint, AllHints::DeprecatedSyscallHint(_))
89+
&& !all_program_hints.contains(&hint.to_str().to_string())
90+
})
91+
.collect();
92+
assert!(
93+
redundant_hints.is_empty(),
94+
"The following hints are not used in the OS or Aggregator programs: {redundant_hints:#?}. \
95+
Please remove them from the enum definition."
96+
);
97+
}

0 commit comments

Comments
 (0)