@@ -29,6 +29,7 @@ use starknet_types_core::felt::Felt;
2929
3030use crate :: hints:: hint_implementation:: compiled_class:: utils:: create_bytecode_segment_structure;
3131use crate :: hints:: vars:: Const ;
32+ use crate :: opcode_instances:: { get_opcode_instances, OpcodeInstanceCounts } ;
3233use crate :: test_utils:: cairo_runner:: {
3334 initialize_cairo_runner,
3435 run_cairo_0_entrypoint,
@@ -68,6 +69,7 @@ const EXPECTED_BUILTIN_USAGE_PARTIAL_CONTRACT_V2_HASH: expect_test::Expect =
6869const EXPECTED_N_STEPS_PARTIAL_CONTRACT_V2_HASH : Expect = expect ! [ "41697" ] ;
6970// Allowed margin between estimated and actual execution resources.
7071const ALLOWED_MARGIN_BLAKE_N_STEPS : usize = 267 ;
72+ const ALLOWED_MARGIN_BLAKE_OPCODE_COUNT : usize = 4 ;
7173
7274/// Specifies the expected inputs and outputs for testing a class hash version.
7375/// Includes entrypoint, bytecode, and expected runtime behavior.
@@ -88,12 +90,20 @@ trait HashVersionTestSpec {
8890 fn expected_hash ( & self ) -> Expect ;
8991 /// The allowed margin for the number of steps.
9092 fn allowed_margin_n_steps ( & self ) -> usize ;
93+ /// The allowed margin for the number of Blake opcodes.
94+ fn allowed_margin_blake_opcode_count ( & self ) -> usize ;
9195 /// Estimates the execution resources for the compiled class hash function.
9296 fn estimate_execution_resources (
9397 & self ,
9498 bytecode_segment_felt_sizes : & NestedFeltCounts ,
9599 entry_points_by_type : & EntryPointsByType < EntryPointV1 > ,
96100 ) -> ExecutionResources ;
101+ /// Estimates the number of Blake opcodes used for the compiled class hash function.
102+ fn estimated_blake_opcode_count (
103+ & self ,
104+ bytecode_segment_felt_sizes : & NestedFeltCounts ,
105+ entry_points_by_type : & EntryPointsByType < EntryPointV1 > ,
106+ ) -> usize ;
97107}
98108
99109impl HashVersionTestSpec for HashVersion {
@@ -156,6 +166,12 @@ impl HashVersionTestSpec for HashVersion {
156166 HashVersion :: V2 => ALLOWED_MARGIN_BLAKE_N_STEPS ,
157167 }
158168 }
169+ fn allowed_margin_blake_opcode_count ( & self ) -> usize {
170+ match self {
171+ HashVersion :: V1 => 0 ,
172+ HashVersion :: V2 => ALLOWED_MARGIN_BLAKE_OPCODE_COUNT ,
173+ }
174+ }
159175 fn estimate_execution_resources (
160176 & self ,
161177 bytecode_segment_felt_sizes : & NestedFeltCounts ,
@@ -178,6 +194,22 @@ impl HashVersionTestSpec for HashVersion {
178194 }
179195 }
180196 }
197+ fn estimated_blake_opcode_count (
198+ & self ,
199+ bytecode_segment_felt_sizes : & NestedFeltCounts ,
200+ entry_points_by_type : & EntryPointsByType < EntryPointV1 > ,
201+ ) -> usize {
202+ match self {
203+ HashVersion :: V1 => 0 ,
204+ HashVersion :: V2 => {
205+ CasmV2HashResourceEstimate :: estimated_resources_of_compiled_class_hash (
206+ bytecode_segment_felt_sizes,
207+ entry_points_by_type,
208+ )
209+ . blake_count ( )
210+ }
211+ }
212+ }
181213}
182214
183215/// Runs the compiled class hash entry point for the given contract class,
@@ -187,11 +219,11 @@ fn run_compiled_class_hash_entry_point(
187219 contract_class : & CasmContractClass ,
188220 load_full_contract : bool ,
189221 hash_version : & HashVersion ,
190- ) -> ( ExecutionResources , Felt ) {
222+ ) -> ( ExecutionResources , OpcodeInstanceCounts , Felt ) {
191223 // Set up the entry point runner configuration.
192224 let runner_config = EntryPointRunnerConfig {
193225 layout : LayoutName :: all_cairo,
194- trace_enabled : false ,
226+ trace_enabled : true ,
195227 verify_secure : false ,
196228 proof_mode : false ,
197229 add_main_prefix_to_entrypoint : false , // Set to false since we're using full path.
@@ -256,15 +288,15 @@ fn run_compiled_class_hash_entry_point(
256288
257289 // Get the actual execution resources, and compare with expected values.
258290 let actual_execution_resources = runner. get_execution_resources ( ) . unwrap ( ) ;
259-
291+ let opcode_instances = get_opcode_instances ( & runner ) ;
260292 // Get the hash result from the explicit return values.
261293 let EndpointArg :: Value ( ValueArg :: Single ( MaybeRelocatable :: Int ( hash_computed_by_cairo) ) ) =
262294 explicit_return_values[ 0 ]
263295 else {
264296 panic ! ( "Expected a single felt return value" ) ;
265297 } ;
266298
267- ( actual_execution_resources, hash_computed_by_cairo)
299+ ( actual_execution_resources, opcode_instances , hash_computed_by_cairo)
268300}
269301
270302#[ rstest]
@@ -280,7 +312,7 @@ fn test_compiled_class_hash(
280312 _ => panic ! ( "Expected ContractClass::V1" ) ,
281313 } ;
282314 // Run the compiled class hash entry point.
283- let ( actual_execution_resources, hash_computed_by_cairo) =
315+ let ( actual_execution_resources, _ , hash_computed_by_cairo) =
284316 run_compiled_class_hash_entry_point ( & contract_class, load_full_contract, & hash_version) ;
285317
286318 // Format builtin usage statistics for comparison with expected values.
@@ -376,7 +408,7 @@ fn compare_estimated_vs_actual_casm_hash_resources(
376408 hash_version : & HashVersion ,
377409) {
378410 // Run the compiled class hash entry point with full contract loading.
379- let ( actual_execution_resources, _) =
411+ let ( actual_execution_resources, actual_opcode_instances , _) =
380412 run_compiled_class_hash_entry_point ( & contract_class, true , hash_version) ;
381413
382414 let bytecode_segments = NestedFeltCounts :: new (
@@ -387,7 +419,7 @@ fn compare_estimated_vs_actual_casm_hash_resources(
387419 // Estimate resources.
388420 let execution_resources_estimation = hash_version. estimate_execution_resources (
389421 & bytecode_segments,
390- & contract_class. entry_points_by_type . into ( ) ,
422+ & contract_class. entry_points_by_type . clone ( ) . into ( ) ,
391423 ) ;
392424
393425 // Compare n_steps.
@@ -406,4 +438,18 @@ fn compare_estimated_vs_actual_casm_hash_resources(
406438 actual_execution_resources. filter_unused_builtins( ) . builtin_instance_counter,
407439 "{contract_name}: Estimated builtins do not match actual builtins"
408440 ) ;
441+
442+ // Compare Blake opcode count.
443+ let estimated_blake_opcode_count = hash_version. estimated_blake_opcode_count (
444+ & bytecode_segments,
445+ & contract_class. entry_points_by_type . into ( ) ,
446+ ) ;
447+ let blake_opcode_count_margin =
448+ estimated_blake_opcode_count. abs_diff ( actual_opcode_instances. blake_opcode_count ) ;
449+ let allowed_blake_opcode_count_margin = hash_version. allowed_margin_blake_opcode_count ( ) ;
450+ assert ! (
451+ blake_opcode_count_margin <= allowed_blake_opcode_count_margin,
452+ "{contract_name}: Estimated Blake opcode count differs from actual by more than \
453+ {allowed_blake_opcode_count_margin}. Margin: {blake_opcode_count_margin}"
454+ ) ;
409455}
0 commit comments