Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
use std::collections::HashSet;

use blake2s::encode_felts_to_u32s;
use cairo_vm::hint_processor::builtin_hint_processor::hint_code::HINT_CODES;
use cairo_vm::hint_processor::builtin_hint_processor::kzg_da::WRITE_DIVMOD_SEGMENT;
use cairo_vm::hint_processor::builtin_hint_processor::secp::cairo0_hints::CAIRO0_HINT_CODES;
use starknet_os::hints::enum_definition::{AggregatorHint, HintExtension, OsHint};
use starknet_os::hints::types::HintEnum;
use starknet_types_core::felt::Felt;
use strum::IntoEnumIterator;

use crate::os_cli::commands::{validate_input, Input};
use crate::os_cli::tests::aliases::aliases_test;
Expand All @@ -19,7 +11,6 @@ use crate::shared_utils::types::{PythonTestError, PythonTestRunner};
pub enum OsPythonTestRunner {
AliasesTest,
BlsFieldTest,
CompareOsHints,
InputDeserialization,
EncodeFelts,
}
Expand All @@ -32,7 +23,6 @@ impl TryFrom<String> for OsPythonTestRunner {
match value.as_str() {
"aliases_test" => Ok(Self::AliasesTest),
"bls_field_test" => Ok(Self::BlsFieldTest),
"compare_os_hints" => Ok(Self::CompareOsHints),
"input_deserialization" => Ok(Self::InputDeserialization),
"encode_felts" => Ok(Self::EncodeFelts),
_ => Err(PythonTestError::UnknownTestName(value)),
Expand All @@ -47,7 +37,6 @@ impl PythonTestRunner for OsPythonTestRunner {
match self {
Self::AliasesTest => aliases_test(Self::non_optional_input(input)?),
Self::BlsFieldTest => test_bls_field(Self::non_optional_input(input)?),
Self::CompareOsHints => compare_os_hints(Self::non_optional_input(input)?),
Self::InputDeserialization => input_deserialization(Self::non_optional_input(input)?),
Self::EncodeFelts => {
let felts: Vec<Felt> = serde_json::from_str(Self::non_optional_input(input)?)?;
Expand All @@ -57,44 +46,10 @@ impl PythonTestRunner for OsPythonTestRunner {
}
}

#[allow(clippy::result_large_err)]
fn compare_os_hints(input: &str) -> OsPythonTestResult {
let unfiltered_python_hints: HashSet<String> = serde_json::from_str(input)?;

// Remove VM hints.
let vm_hints = vm_hints();
let python_os_hints: HashSet<String> = unfiltered_python_hints
.into_iter()
.filter(|hint| !vm_hints.contains(hint.as_str()))
.collect();

// We ignore `SyscallHint`s here, as they are not part of the compiled OS.
let rust_os_hints: HashSet<String> = OsHint::iter()
.map(|hint| hint.to_str().to_string())
.chain(HintExtension::iter().map(|hint| hint.to_str().to_string()))
.chain(AggregatorHint::iter().map(|hint| hint.to_str().to_string()))
.collect();

let mut only_in_python: Vec<String> =
python_os_hints.difference(&rust_os_hints).cloned().collect();
only_in_python.sort();
let mut only_in_rust: Vec<String> =
rust_os_hints.difference(&python_os_hints).cloned().collect();
only_in_rust.sort();
Ok(serde_json::to_string(&(only_in_python, only_in_rust))?)
}

/// Deserialize the input string into an `Input` struct.
#[allow(clippy::result_large_err)]
fn input_deserialization(input_str: &str) -> OsPythonTestResult {
let input = serde_json::from_str::<Input>(input_str)?;
validate_input(&input.os_hints.os_input);
Ok("Deserialization successful".to_string())
}

fn vm_hints() -> HashSet<&'static str> {
let mut vm_hints = HashSet::from([WRITE_DIVMOD_SEGMENT]);
vm_hints.extend(HINT_CODES.values());
vm_hints.extend(CAIRO0_HINT_CODES.values());
vm_hints
}
61 changes: 61 additions & 0 deletions crates/starknet_os/src/hints/enum_definition_test.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
use std::collections::HashSet;
use std::sync::LazyLock;

use apollo_starknet_os_program::{AGGREGATOR_PROGRAM, OS_PROGRAM};
use blockifier::execution::hint_code::SYSCALL_HINTS;
use cairo_vm::hint_processor::builtin_hint_processor::hint_code::HINT_CODES;
use cairo_vm::hint_processor::builtin_hint_processor::kzg_da::WRITE_DIVMOD_SEGMENT;
use cairo_vm::hint_processor::builtin_hint_processor::secp::cairo0_hints::CAIRO0_HINT_CODES;
use cairo_vm::types::program::Program;
use strum::IntoEnumIterator;

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

static VM_HINTS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
let mut vm_hints = HashSet::from([WRITE_DIVMOD_SEGMENT]);
vm_hints.extend(HINT_CODES.values());
vm_hints.extend(CAIRO0_HINT_CODES.values());
vm_hints
});

fn program_hints(program: &Program) -> HashSet<String> {
program
.shared_program_data
.hints_collection
.iter_hints()
.map(|hint| hint.code.clone())
.collect()
}

fn unknown_hints_for_program(program: &Program) -> HashSet<String> {
program_hints(program)
.into_iter()
.filter(|hint| AllHints::from_str(hint).is_err() && !VM_HINTS.contains(hint.as_str()))
.collect()
}

#[test]
fn test_hint_strings_are_unique() {
let all_hints = AllHints::all_iter().map(|hint| hint.to_str()).collect::<Vec<_>>();
Expand Down Expand Up @@ -34,3 +63,35 @@ fn test_syscall_compatibility_with_blockifier() {
the implementation."
);
}

#[test]
fn test_all_hints_are_known() {
let unknown_os_hints = unknown_hints_for_program(&OS_PROGRAM);
let unknown_aggregator_hints = unknown_hints_for_program(&AGGREGATOR_PROGRAM);
let unknown_hints: HashSet<String> =
unknown_os_hints.union(&unknown_aggregator_hints).cloned().collect();

assert!(
unknown_hints.is_empty(),
"The following hints are not known in 'starknet_os': {unknown_hints:#?}."
);
}

#[test]
fn test_all_hints_are_used() {
let os_hints = program_hints(&OS_PROGRAM);
let aggregator_hints = program_hints(&AGGREGATOR_PROGRAM);
let all_program_hints: HashSet<&String> = os_hints.union(&aggregator_hints).collect();
let redundant_hints: HashSet<_> = AllHints::all_iter()
.filter(|hint| {
// Skip syscalls; they do not appear in the OS code.
!matches!(hint, AllHints::DeprecatedSyscallHint(_))
&& !all_program_hints.contains(&String::from(hint.to_str()))
})
.collect();
assert!(
redundant_hints.is_empty(),
"The following hints are not used in the OS or Aggregator programs: {redundant_hints:#?}. \
Please remove them from the enum definition."
);
}
Loading