11use std:: collections:: { HashMap , HashSet } ;
2- use std:: sync:: LazyLock ;
2+ use std:: sync:: { Arc , LazyLock } ;
33
44use blockifier:: blockifier_versioned_constants:: {
5+ CallDataFactor ,
56 RawStepGasCost ,
67 RawVersionedConstants ,
78 ResourcesParams ,
@@ -12,6 +13,7 @@ use blockifier::blockifier_versioned_constants::{
1213use blockifier:: context:: BlockContext ;
1314use blockifier:: execution:: deprecated_syscalls:: DeprecatedSyscallSelector as Selector ;
1415use blockifier:: test_utils:: dict_state_reader:: DictStateReader ;
16+ use blockifier:: transaction:: objects:: ExecutionResourcesTraits ;
1517use blockifier_test_utils:: cairo_versions:: RunnableCairo1 ;
1618use blockifier_test_utils:: contracts:: FeatureContract ;
1719use cairo_vm:: vm:: runners:: cairo_runner:: ExecutionResources ;
@@ -20,9 +22,9 @@ use indexmap::IndexMap;
2022use starknet_api:: block:: StarknetVersion ;
2123use starknet_api:: contract_class:: SierraVersion ;
2224use starknet_api:: core:: { ClassHash , ContractAddress , EthAddress } ;
23- use starknet_api:: executable_transaction:: InvokeTransaction ;
25+ use starknet_api:: executable_transaction:: { InvokeTransaction , TransactionType } ;
2426use starknet_api:: test_utils:: invoke:: invoke_tx;
25- use starknet_api:: transaction:: fields:: ContractAddressSalt ;
27+ use starknet_api:: transaction:: fields:: { Calldata , ContractAddressSalt } ;
2628use starknet_api:: transaction:: { L2ToL1Payload , MessageToL1 } ;
2729use starknet_api:: versioned_constants_logic:: VersionedConstantsTrait ;
2830use starknet_api:: { calldata, declare_tx_args, invoke_tx_args} ;
@@ -180,7 +182,7 @@ async fn setup_test_builder(raw_vc: Option<&RawVersionedConstants>) -> OsResourc
180182 ) ;
181183 test_builder. add_fund_address_tx_with_default_amount ( os_resources_contract_address) ;
182184
183- // Declare and deploy an instance of the stable contract.
185+ // Declare and deploy an instance of the stable contract. Also, fund it.
184186 let stable_contract_sierra = & DEPLOYABLE_FOR_RESOURCE_MEASUREMENT_CONTRACT_SIERRA ;
185187 let stable_contract_casm = & DEPLOYABLE_FOR_RESOURCE_MEASUREMENT_CONTRACT_CASM ;
186188 let stable_contract_class_hash = stable_contract_sierra. calculate_class_hash ( ) ;
@@ -206,6 +208,7 @@ async fn setup_test_builder(raw_vc: Option<&RawVersionedConstants>) -> OsResourc
206208 deploy_from_zero,
207209 ) ;
208210 test_builder. add_invoke_tx ( deploy_tx, None , None ) ;
211+ test_builder. add_fund_address_tx_with_default_amount ( stable_contract_address) ;
209212
210213 // Move on to the next block, so the measurement txs are in their own block.
211214 test_builder. move_to_next_block ( ) ;
@@ -218,6 +221,13 @@ async fn setup_test_builder(raw_vc: Option<&RawVersionedConstants>) -> OsResourc
218221 }
219222}
220223
224+ /// Utility method to create dummy calldata to a cairo Span argument.
225+ fn span_calldata ( n_elements : usize ) -> Calldata {
226+ let mut calldata = vec ! [ Felt :: from( n_elements) ] ;
227+ calldata. extend ( vec ! [ Felt :: ZERO ; n_elements] ) ;
228+ Calldata ( Arc :: new ( calldata) )
229+ }
230+
221231/// Regression test for the list of syscalls called during the fee transfer phase of a transaction.
222232#[ tokio:: test]
223233async fn test_fee_transfer_syscalls ( ) {
@@ -485,3 +495,123 @@ async fn test_os_resources_regression() {
485495 expect_file ! [ VersionedConstants :: json_path( & version) . unwrap( ) ]
486496 . assert_eq ( & raw_vc. to_string_pretty ( ) ) ;
487497}
498+
499+ /// Measures the per-transaction-type overhead of `execute_transaction_inner` in the OS and
500+ /// compares it against the versioned constants.
501+ ///
502+ /// Methodology:
503+ /// - Run a minimal transaction of the given type through the full OS.
504+ /// - Compute: overhead = OS trace resources − blockifier business-logic resources
505+ /// (execute_call_info + validate_call_info).
506+ /// - The remainder is the pure OS scaffolding cost stored under `execute_txs_inner`.
507+ #[ tokio:: test]
508+ async fn test_execute_txs_inner_resources ( ) {
509+ let version = StarknetVersion :: LATEST ;
510+ let mut raw_vc: RawVersionedConstants =
511+ serde_json:: from_str ( VersionedConstants :: json_str ( & version) . unwrap ( ) ) . unwrap ( ) ;
512+ // TODO(Dori): Declare, DeployAccount, L1Handler.
513+ const N_TXS : usize = 2 ;
514+
515+ // For linear factor measurements, it's not enough to just add one more calldata element; the
516+ // increase is not the same per element. The linear scale is on average.
517+ const INVOKE_SCALING_FACTOR : usize = 2 ;
518+ const INVOKE_EXTRA_ARGS : usize = 10 ;
519+
520+ let OsResourcesTestSetup { stable_contract_address, mut test_builder, .. } =
521+ setup_test_builder ( Some ( & raw_vc) ) . await ;
522+
523+ // Invoke.
524+ let invoke_args = invoke_tx_args ! {
525+ sender_address: stable_contract_address,
526+ calldata: calldata![ Felt :: ZERO ] ,
527+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
528+ nonce: test_builder. next_nonce( stable_contract_address) ,
529+ } ;
530+ test_builder. add_invoke_tx (
531+ InvokeTransaction :: create ( invoke_tx ( invoke_args) , & test_builder. chain_id ( ) ) . unwrap ( ) ,
532+ None ,
533+ None ,
534+ ) ;
535+ // Invoke: scale-factor more calldata elements.
536+ let invoke_args = invoke_tx_args ! {
537+ sender_address: stable_contract_address,
538+ calldata: span_calldata( INVOKE_EXTRA_ARGS ) ,
539+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
540+ nonce: test_builder. next_nonce( stable_contract_address) ,
541+ } ;
542+ test_builder. add_invoke_tx (
543+ InvokeTransaction :: create ( invoke_tx ( invoke_args) , & test_builder. chain_id ( ) ) . unwrap ( ) ,
544+ None ,
545+ None ,
546+ ) ;
547+
548+ // Execute the business logic and extract the business logic resources for each tx.
549+ let test_runner = test_builder. build ( ) . await ;
550+ let business_logic_resources: [ ExecutionResources ; N_TXS ] = test_runner
551+ . os_hints
552+ . os_input
553+ . os_block_inputs
554+ . last ( )
555+ . unwrap ( )
556+ . tx_execution_infos
557+ . iter ( )
558+ . map ( |exec_info| {
559+ let mut business_logic_resources =
560+ [ exec_info. execute_call_info . as_ref ( ) , exec_info. validate_call_info . as_ref ( ) ]
561+ . into_iter ( )
562+ . flatten ( )
563+ . map ( |ci| ci. resources . vm_resources . clone ( ) )
564+ . fold ( ExecutionResources :: default ( ) , |acc, resources| & acc + & resources) ;
565+ // TODO(Dori): Consider supporting memory-hole counting in the OsLogger. Until then, we
566+ // cannot subtract inner calls with positive memory-hole counts from the OsLogger
567+ // resources.
568+ business_logic_resources. n_memory_holes = 0 ;
569+ business_logic_resources
570+ } )
571+ . collect :: < Vec < _ > > ( )
572+ . try_into ( )
573+ . unwrap ( ) ;
574+
575+ // Run the OS part.
576+ let test_output = test_runner. run ( ) ;
577+ test_output. perform_default_validations ( ) ;
578+
579+ // Fetch the OS resources for each tx.
580+ let [ invoke_first, invoke_second] : [ ExecutionResources ; N_TXS ] = test_output
581+ . runner_output
582+ . txs_trace
583+ . iter ( )
584+ . rev ( )
585+ . take ( N_TXS )
586+ . rev ( )
587+ . map ( |trace| trace. get_resources ( ) . unwrap ( ) . clone ( ) )
588+ . zip ( business_logic_resources)
589+ . map ( |( os_resources, business_logic_resources) | {
590+ ( & os_resources - & business_logic_resources) . filter_unused_builtins ( )
591+ } )
592+ . collect :: < Vec < _ > > ( )
593+ . try_into ( )
594+ . unwrap ( ) ;
595+
596+ // Update the VC with the measurements.
597+ // For transaction types with linear factors, the first call has one linear element (calldata
598+ // length, of zero), so one linear cost must be subtracted from the first measurement to get the
599+ // base cost.
600+ let invoke_linear_factor = ( & ( & invoke_second - & invoke_first) . filter_unused_builtins ( )
601+ * INVOKE_SCALING_FACTOR )
602+ . div_ceil ( INVOKE_EXTRA_ARGS ) ;
603+ raw_vc. os_resources . execute_txs_inner . extend ( [ (
604+ TransactionType :: InvokeFunction ,
605+ VariableResourceParams :: WithFactor ( ResourcesParams {
606+ constant : ( & invoke_first - & invoke_linear_factor) . filter_unused_builtins ( ) ,
607+ calldata_factor : VariableCallDataFactor :: Scaled ( CallDataFactor {
608+ resources : invoke_linear_factor,
609+ scaling_factor : INVOKE_SCALING_FACTOR ,
610+ } ) ,
611+ } ) ,
612+ ) ] ) ;
613+
614+ // Verify computation.
615+ expect_file ! [ VersionedConstants :: json_path( & version) . unwrap( ) ]
616+ . assert_eq ( & raw_vc. to_string_pretty ( ) ) ;
617+ }
0 commit comments