@@ -79,6 +79,21 @@ const UNMEASURABLE_SYSCALLS: [Selector; 31] = [
7979
8080const SYSCALLS_WITH_LINEAR_FACTOR : [ Selector ; 2 ] = [ Selector :: Deploy , Selector :: MetaTxV0 ] ;
8181
82+ /// Expected syscalls in the fee transfer call. Should be removed from the list of syscalls during
83+ /// measurement iteration - only the syscalls called during __execute__ should be measured.
84+ const FEE_TRANSFER_SYSCALLS : [ Selector ; 10 ] = [
85+ Selector :: GetExecutionInfo ,
86+ Selector :: StorageRead ,
87+ Selector :: StorageRead ,
88+ Selector :: StorageWrite ,
89+ Selector :: StorageWrite ,
90+ Selector :: StorageRead ,
91+ Selector :: StorageRead ,
92+ Selector :: StorageWrite ,
93+ Selector :: StorageWrite ,
94+ Selector :: EmitEvent ,
95+ ] ;
96+
8297/// Measure the OS overhead for each syscall, and compare the results with the latest VC.
8398///
8499/// This test relies on the [starknet_os::hint_processor::os_logger::OsLogger] to capture the
@@ -104,6 +119,46 @@ const SYSCALLS_WITH_LINEAR_FACTOR: [Selector; 2] = [Selector::Deploy, Selector::
104119/// the measurements, we use a stable dummy contract (that is not recompiled when the Cairo1
105120/// compiler's version changes), and we set the `deploy_from_zero` flag to `true` to make sure
106121/// changes in the deploying contract address are not reflected in the measurements.
122+ #[ tokio:: test]
123+ async fn test_fee_transfer_syscalls ( ) {
124+ let os_resources_contract = FeatureContract :: OsResourcesTest ( RunnableCairo1 :: Casm ) ;
125+ let ( mut builder, [ os_resources_contract_address] ) =
126+ TestBuilder :: create_standard ( [ ( os_resources_contract, calldata ! [ Felt :: ZERO ] ) ] ) . await ;
127+
128+ // Fund the contract - it will be used as the account.
129+ // Then, move on to the next block, so the syscall-measurement tx is in it's own block.
130+ builder. add_fund_address_tx_with_default_amount ( os_resources_contract_address) ;
131+
132+ // Invoke from the OS resources contract, with zeros as calldata, to make the __execute__ do
133+ // nothing. All resulting events should be from the fee transfer call.
134+ builder. add_invoke_tx (
135+ InvokeTransaction :: create (
136+ invoke_tx ( invoke_tx_args ! {
137+ sender_address: os_resources_contract_address,
138+ calldata: calldata![ Felt :: ZERO , Felt :: ZERO , Felt :: ZERO ] ,
139+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
140+ } ) ,
141+ & builder. chain_id ( ) ,
142+ )
143+ . unwrap ( ) ,
144+ None ,
145+ None ,
146+ ) ;
147+
148+ // Build, run, and get the syscalls list.
149+ let test_output = builder. build_and_run ( ) . await ;
150+ let syscalls = test_output
151+ . runner_output
152+ . txs_trace
153+ . last ( )
154+ . unwrap ( )
155+ . get_syscalls ( )
156+ . iter ( )
157+ . map ( |syscall_trace| syscall_trace. get_selector ( ) )
158+ . collect :: < Vec < _ > > ( ) ;
159+ assert_eq ! ( syscalls, FEE_TRANSFER_SYSCALLS . to_vec( ) ) ;
160+ }
161+
107162#[ tokio:: test]
108163async fn test_os_resources_regression ( ) {
109164 let os_resources_contract = FeatureContract :: OsResourcesTest ( RunnableCairo1 :: Casm ) ;
@@ -212,19 +267,19 @@ async fn test_os_resources_regression() {
212267 test_output. perform_default_validations ( ) ;
213268
214269 // Extract syscall resources consumed, per (measurable) syscall.
215- // There should be two events emitted: the first is the syscall we are measuring, and the second
216- // is the last syscall in the tx, emitted from the fee transfer. Pop the second event.
217- let mut syscall_traces =
218- test_output. runner_output . txs_trace . last ( ) . unwrap ( ) . get_syscalls ( ) . clone ( ) ;
219- assert ! ( !UNMEASURABLE_SYSCALLS . contains( & Selector :: EmitEvent ) ) ;
270+ // Remove the fee transfer syscalls from the list by splitting the iterator into two. The second
271+ // part is the last `FEE_TRANSFER_SYSCALLS.len()` syscalls, and the first part should be the
272+ // rest.
273+ let all_syscalls = test_output. runner_output . txs_trace . last ( ) . unwrap ( ) . get_syscalls ( ) . clone ( ) ;
274+ let ( syscall_traces, fee_transfer_syscall_traces) =
275+ all_syscalls. split_at ( all_syscalls. len ( ) - FEE_TRANSFER_SYSCALLS . len ( ) ) ;
220276 assert_eq ! (
221- syscall_traces
277+ fee_transfer_syscall_traces
222278 . iter( )
223- . filter ( |syscall_trace| syscall_trace. get_selector( ) == Selector :: EmitEvent )
224- . count ( ) ,
225- 2
279+ . map ( |syscall_trace| syscall_trace. get_selector( ) )
280+ . collect :: < Vec <_>> ( ) ,
281+ FEE_TRANSFER_SYSCALLS . to_vec ( )
226282 ) ;
227- assert_eq ! ( syscall_traces. pop( ) . unwrap( ) . get_selector( ) , Selector :: EmitEvent ) ;
228283
229284 // Measure each syscall overhead. If the syscall incurs an inner call, subtract the inner call
230285 // overhead.
@@ -301,6 +356,13 @@ async fn test_os_resources_regression() {
301356 . collect:: <HashSet <_>>( )
302357 ) ;
303358
359+ // Make sure there are no more dangling syscalls.
360+ let dangling_syscall = syscalls_iter. next ( ) ;
361+ assert ! (
362+ dangling_syscall. is_none( ) ,
363+ "There are more syscalls than expected. Dangling syscall: {dangling_syscall:?}."
364+ ) ;
365+
304366 // Compare the measurements with the expected values on the latest VC.
305367 let version = StarknetVersion :: LATEST ;
306368 let mut raw_vc: RawVersionedConstants =
0 commit comments