@@ -57,91 +57,7 @@ use crate::execution::syscalls::{
5757} ;
5858use crate :: utils:: u64_from_usize;
5959
60- #[ allow( dead_code) ]
6160pub trait SyscallExecutor {
62- fn execute_syscall_from_selector (
63- & mut self ,
64- vm : & mut VirtualMachine ,
65- selector : SyscallSelector ,
66- ) -> HintExecutionResult {
67- match selector {
68- SyscallSelector :: CallContract => {
69- self . execute_syscall ( vm, selector, Self :: call_contract)
70- }
71- SyscallSelector :: Deploy => self . execute_syscall ( vm, selector, Self :: deploy) ,
72- SyscallSelector :: EmitEvent => self . execute_syscall ( vm, selector, Self :: emit_event) ,
73- SyscallSelector :: GetBlockHash => {
74- self . execute_syscall ( vm, selector, Self :: get_block_hash)
75- }
76- SyscallSelector :: GetClassHashAt => {
77- self . execute_syscall ( vm, selector, Self :: get_class_hash_at)
78- }
79- SyscallSelector :: GetExecutionInfo => {
80- self . execute_syscall ( vm, selector, Self :: get_execution_info)
81- }
82- SyscallSelector :: Keccak => self . execute_syscall ( vm, selector, Self :: keccak) ,
83- SyscallSelector :: Sha256ProcessBlock => {
84- self . execute_syscall ( vm, selector, Self :: sha256_process_block)
85- }
86- SyscallSelector :: LibraryCall => self . execute_syscall ( vm, selector, Self :: library_call) ,
87- SyscallSelector :: MetaTxV0 => self . execute_syscall ( vm, selector, Self :: meta_tx_v0) ,
88- SyscallSelector :: ReplaceClass => {
89- self . execute_syscall ( vm, selector, Self :: replace_class)
90- }
91- SyscallSelector :: Secp256k1Add => {
92- self . execute_syscall ( vm, selector, Self :: secp256k1_add)
93- }
94- SyscallSelector :: Secp256k1GetPointFromX => {
95- self . execute_syscall ( vm, selector, Self :: secp256k1_get_point_from_x)
96- }
97- SyscallSelector :: Secp256k1GetXy => {
98- self . execute_syscall ( vm, selector, Self :: secp256k1_get_xy)
99- }
100- SyscallSelector :: Secp256k1Mul => {
101- self . execute_syscall ( vm, selector, Self :: secp256k1_mul)
102- }
103- SyscallSelector :: Secp256k1New => {
104- self . execute_syscall ( vm, selector, Self :: secp256k1_new)
105- }
106- SyscallSelector :: Secp256r1Add => {
107- self . execute_syscall ( vm, selector, Self :: secp256r1_add)
108- }
109- SyscallSelector :: Secp256r1GetPointFromX => {
110- self . execute_syscall ( vm, selector, Self :: secp256r1_get_point_from_x)
111- }
112- SyscallSelector :: Secp256r1GetXy => {
113- self . execute_syscall ( vm, selector, Self :: secp256r1_get_xy)
114- }
115- SyscallSelector :: Secp256r1Mul => {
116- self . execute_syscall ( vm, selector, Self :: secp256r1_mul)
117- }
118- SyscallSelector :: Secp256r1New => {
119- self . execute_syscall ( vm, selector, Self :: secp256r1_new)
120- }
121- SyscallSelector :: SendMessageToL1 => {
122- self . execute_syscall ( vm, selector, Self :: send_message_to_l1)
123- }
124- SyscallSelector :: StorageRead => self . execute_syscall ( vm, selector, Self :: storage_read) ,
125- SyscallSelector :: StorageWrite => {
126- self . execute_syscall ( vm, selector, Self :: storage_write)
127- }
128- // Explicitly list unsupported syscalls, so compiler can catch if a syscall is missing.
129- SyscallSelector :: DelegateCall
130- | SyscallSelector :: DelegateL1Handler
131- | SyscallSelector :: GetBlockNumber
132- | SyscallSelector :: GetBlockTimestamp
133- | SyscallSelector :: GetCallerAddress
134- | SyscallSelector :: GetContractAddress
135- | SyscallSelector :: GetSequencerAddress
136- | SyscallSelector :: GetTxInfo
137- | SyscallSelector :: GetTxSignature
138- | SyscallSelector :: KeccakRound
139- | SyscallSelector :: LibraryCallL1Handler => Err ( HintError :: UnknownHint (
140- format ! ( "Unsupported syscall selector {selector:?}." ) . into ( ) ,
141- ) ) ,
142- }
143- }
144-
14561 fn get_gas_cost_from_selector (
14662 & self ,
14763 selector : & SyscallSelector ,
@@ -153,89 +69,6 @@ pub trait SyscallExecutor {
15369
15470 fn update_revert_gas_with_next_remaining_gas ( & mut self , next_remaining_gas : GasAmount ) ;
15571
156- fn execute_syscall < Request , Response , ExecuteCallback > (
157- & mut self ,
158- vm : & mut VirtualMachine ,
159- selector : SyscallSelector ,
160- execute_callback : ExecuteCallback ,
161- ) -> HintExecutionResult
162- where
163- Request : SyscallRequest + std:: fmt:: Debug ,
164- Response : SyscallResponse + std:: fmt:: Debug ,
165- ExecuteCallback : FnOnce (
166- Request ,
167- & mut VirtualMachine ,
168- & mut Self ,
169- & mut u64 , // Remaining gas.
170- ) -> SyscallResult < Response > ,
171- {
172- let syscall_gas_cost = self . get_gas_cost_from_selector ( & selector) . map_err ( |e| {
173- HintError :: CustomHint (
174- format ! ( "Failed to get gas cost for syscall selector {selector:?}. Error: {e:?}" )
175- . into ( ) ,
176- )
177- } ) ?;
178-
179- let SyscallRequestWrapper { gas_counter, request } =
180- SyscallRequestWrapper :: < Request > :: read ( vm, self . get_mut_syscall_ptr ( ) ) ?;
181-
182- let syscall_gas_cost =
183- syscall_gas_cost. get_syscall_cost ( u64_from_usize ( request. get_linear_factor_length ( ) ) ) ;
184- let syscall_base_cost = self . get_syscall_base_gas_cost ( ) ;
185-
186- // Sanity check for preventing underflow.
187- assert ! (
188- syscall_gas_cost >= syscall_base_cost,
189- "Syscall gas cost must be greater than base syscall gas cost"
190- ) ;
191-
192- // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged.
193- let required_gas = syscall_gas_cost - syscall_base_cost;
194-
195- if gas_counter < required_gas {
196- // Out of gas failure.
197- let out_of_gas_error =
198- Felt :: from_hex ( OUT_OF_GAS_ERROR ) . map_err ( SyscallExecutionError :: from) ?;
199- let response: SyscallResponseWrapper < Response > =
200- SyscallResponseWrapper :: Failure { gas_counter, error_data : vec ! [ out_of_gas_error] } ;
201- response. write ( vm, self . get_mut_syscall_ptr ( ) ) ?;
202-
203- return Ok ( ( ) ) ;
204- }
205-
206- // Execute.
207- let mut remaining_gas = gas_counter - required_gas;
208-
209- // To support sierra gas charge for blockifier revert flow, we track the remaining gas left
210- // before executing a syscall if the current tracked resource is gas.
211- // 1. If the syscall does not run Cairo code (i.e. not library call, not call contract, and
212- // not a deploy), any failure will not run in the OS, so no need to charge - the value
213- // before entering the callback is good enough to charge.
214- // 2. If the syscall runs Cairo code, but the tracked resource is steps (and not gas), the
215- // additional charge of reverted cairo steps will cover the inner cost, and the outer
216- // cost we track here will be the additional reverted gas.
217- // 3. If the syscall runs Cairo code and the tracked resource is gas, either the inner
218- // failure will be a Cairo1 revert (and the gas consumed on the call info will override
219- // the current tracked value), or we will pass through another syscall before failing -
220- // and by induction (we will reach this point again), the gas will be charged correctly.
221- self . update_revert_gas_with_next_remaining_gas ( GasAmount ( remaining_gas) ) ;
222-
223- let original_response = execute_callback ( request, vm, self , & mut remaining_gas) ;
224- let response = match original_response {
225- Ok ( response) => {
226- SyscallResponseWrapper :: Success { gas_counter : remaining_gas, response }
227- }
228- Err ( SyscallExecutionError :: Revert { error_data : data } ) => {
229- SyscallResponseWrapper :: Failure { gas_counter : remaining_gas, error_data : data }
230- }
231- Err ( error) => return Err ( error. into ( ) ) ,
232- } ;
233-
234- response. write ( vm, self . get_mut_syscall_ptr ( ) ) ?;
235-
236- Ok ( ( ) )
237- }
238-
23972 fn call_contract (
24073 request : CallContractRequest ,
24174 vm : & mut VirtualMachine ,
@@ -404,3 +237,174 @@ pub trait SyscallExecutor {
404237 remaining_gas : & mut u64 ,
405238 ) -> SyscallResult < StorageWriteResponse > ;
406239}
240+
241+ pub ( crate ) fn execute_syscall_from_selector < T : SyscallExecutor > (
242+ syscall_executor : & mut T ,
243+ vm : & mut VirtualMachine ,
244+ selector : SyscallSelector ,
245+ ) -> HintExecutionResult {
246+ match selector {
247+ SyscallSelector :: CallContract => {
248+ execute_syscall ( syscall_executor, vm, selector, T :: call_contract)
249+ }
250+ SyscallSelector :: Deploy => execute_syscall ( syscall_executor, vm, selector, T :: deploy) ,
251+ SyscallSelector :: EmitEvent => {
252+ execute_syscall ( syscall_executor, vm, selector, T :: emit_event)
253+ }
254+ SyscallSelector :: GetBlockHash => {
255+ execute_syscall ( syscall_executor, vm, selector, T :: get_block_hash)
256+ }
257+ SyscallSelector :: GetClassHashAt => {
258+ execute_syscall ( syscall_executor, vm, selector, T :: get_class_hash_at)
259+ }
260+ SyscallSelector :: GetExecutionInfo => {
261+ execute_syscall ( syscall_executor, vm, selector, T :: get_execution_info)
262+ }
263+ SyscallSelector :: Keccak => execute_syscall ( syscall_executor, vm, selector, T :: keccak) ,
264+ SyscallSelector :: Sha256ProcessBlock => {
265+ execute_syscall ( syscall_executor, vm, selector, T :: sha256_process_block)
266+ }
267+ SyscallSelector :: LibraryCall => {
268+ execute_syscall ( syscall_executor, vm, selector, T :: library_call)
269+ }
270+ SyscallSelector :: MetaTxV0 => execute_syscall ( syscall_executor, vm, selector, T :: meta_tx_v0) ,
271+ SyscallSelector :: ReplaceClass => {
272+ execute_syscall ( syscall_executor, vm, selector, T :: replace_class)
273+ }
274+ SyscallSelector :: Secp256k1Add => {
275+ execute_syscall ( syscall_executor, vm, selector, T :: secp256k1_add)
276+ }
277+ SyscallSelector :: Secp256k1GetPointFromX => {
278+ execute_syscall ( syscall_executor, vm, selector, T :: secp256k1_get_point_from_x)
279+ }
280+ SyscallSelector :: Secp256k1GetXy => {
281+ execute_syscall ( syscall_executor, vm, selector, T :: secp256k1_get_xy)
282+ }
283+ SyscallSelector :: Secp256k1Mul => {
284+ execute_syscall ( syscall_executor, vm, selector, T :: secp256k1_mul)
285+ }
286+ SyscallSelector :: Secp256k1New => {
287+ execute_syscall ( syscall_executor, vm, selector, T :: secp256k1_new)
288+ }
289+ SyscallSelector :: Secp256r1Add => {
290+ execute_syscall ( syscall_executor, vm, selector, T :: secp256r1_add)
291+ }
292+ SyscallSelector :: Secp256r1GetPointFromX => {
293+ execute_syscall ( syscall_executor, vm, selector, T :: secp256r1_get_point_from_x)
294+ }
295+ SyscallSelector :: Secp256r1GetXy => {
296+ execute_syscall ( syscall_executor, vm, selector, T :: secp256r1_get_xy)
297+ }
298+ SyscallSelector :: Secp256r1Mul => {
299+ execute_syscall ( syscall_executor, vm, selector, T :: secp256r1_mul)
300+ }
301+ SyscallSelector :: Secp256r1New => {
302+ execute_syscall ( syscall_executor, vm, selector, T :: secp256r1_new)
303+ }
304+ SyscallSelector :: SendMessageToL1 => {
305+ execute_syscall ( syscall_executor, vm, selector, T :: send_message_to_l1)
306+ }
307+ SyscallSelector :: StorageRead => {
308+ execute_syscall ( syscall_executor, vm, selector, T :: storage_read)
309+ }
310+ SyscallSelector :: StorageWrite => {
311+ execute_syscall ( syscall_executor, vm, selector, T :: storage_write)
312+ }
313+ // Explicitly list unsupported syscalls, so compiler can catch if a syscall is missing.
314+ SyscallSelector :: DelegateCall
315+ | SyscallSelector :: DelegateL1Handler
316+ | SyscallSelector :: GetBlockNumber
317+ | SyscallSelector :: GetBlockTimestamp
318+ | SyscallSelector :: GetCallerAddress
319+ | SyscallSelector :: GetContractAddress
320+ | SyscallSelector :: GetSequencerAddress
321+ | SyscallSelector :: GetTxInfo
322+ | SyscallSelector :: GetTxSignature
323+ | SyscallSelector :: KeccakRound
324+ | SyscallSelector :: LibraryCallL1Handler => Err ( HintError :: UnknownHint (
325+ format ! ( "Unsupported syscall selector {selector:?}." ) . into ( ) ,
326+ ) ) ,
327+ }
328+ }
329+
330+ fn execute_syscall < Request , Response , ExecuteCallback , Executor > (
331+ syscall_executor : & mut Executor ,
332+ vm : & mut VirtualMachine ,
333+ selector : SyscallSelector ,
334+ execute_callback : ExecuteCallback ,
335+ ) -> HintExecutionResult
336+ where
337+ Executor : SyscallExecutor ,
338+ Request : SyscallRequest + std:: fmt:: Debug ,
339+ Response : SyscallResponse + std:: fmt:: Debug ,
340+ ExecuteCallback : FnOnce (
341+ Request ,
342+ & mut VirtualMachine ,
343+ & mut Executor ,
344+ & mut u64 , // Remaining gas.
345+ ) -> SyscallResult < Response > ,
346+ {
347+ let syscall_gas_cost = syscall_executor. get_gas_cost_from_selector ( & selector) . map_err ( |e| {
348+ HintError :: CustomHint (
349+ format ! ( "Failed to get gas cost for syscall selector {selector:?}. Error: {e:?}" )
350+ . into ( ) ,
351+ )
352+ } ) ?;
353+
354+ let SyscallRequestWrapper { gas_counter, request } =
355+ SyscallRequestWrapper :: < Request > :: read ( vm, syscall_executor. get_mut_syscall_ptr ( ) ) ?;
356+
357+ let syscall_gas_cost =
358+ syscall_gas_cost. get_syscall_cost ( u64_from_usize ( request. get_linear_factor_length ( ) ) ) ;
359+ let syscall_base_cost = syscall_executor. get_syscall_base_gas_cost ( ) ;
360+
361+ // Sanity check for preventing underflow.
362+ assert ! (
363+ syscall_gas_cost >= syscall_base_cost,
364+ "Syscall gas cost must be greater than base syscall gas cost"
365+ ) ;
366+
367+ // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged.
368+ let required_gas = syscall_gas_cost - syscall_base_cost;
369+
370+ if gas_counter < required_gas {
371+ // Out of gas failure.
372+ let out_of_gas_error =
373+ Felt :: from_hex ( OUT_OF_GAS_ERROR ) . map_err ( SyscallExecutionError :: from) ?;
374+ let response: SyscallResponseWrapper < Response > =
375+ SyscallResponseWrapper :: Failure { gas_counter, error_data : vec ! [ out_of_gas_error] } ;
376+ response. write ( vm, syscall_executor. get_mut_syscall_ptr ( ) ) ?;
377+
378+ return Ok ( ( ) ) ;
379+ }
380+
381+ // Execute.
382+ let mut remaining_gas = gas_counter - required_gas;
383+
384+ // To support sierra gas charge for blockifier revert flow, we track the remaining gas left
385+ // before executing a syscall if the current tracked resource is gas.
386+ // 1. If the syscall does not run Cairo code (i.e. not library call, not call contract, and not
387+ // a deploy), any failure will not run in the OS, so no need to charge - the value before
388+ // entering the callback is good enough to charge.
389+ // 2. If the syscall runs Cairo code, but the tracked resource is steps (and not gas), the
390+ // additional charge of reverted cairo steps will cover the inner cost, and the outer cost we
391+ // track here will be the additional reverted gas.
392+ // 3. If the syscall runs Cairo code and the tracked resource is gas, either the inner failure
393+ // will be a Cairo1 revert (and the gas consumed on the call info will override the current
394+ // tracked value), or we will pass through another syscall before failing - and by induction
395+ // (we will reach this point again), the gas will be charged correctly.
396+ syscall_executor. update_revert_gas_with_next_remaining_gas ( GasAmount ( remaining_gas) ) ;
397+
398+ let original_response = execute_callback ( request, vm, syscall_executor, & mut remaining_gas) ;
399+ let response = match original_response {
400+ Ok ( response) => SyscallResponseWrapper :: Success { gas_counter : remaining_gas, response } ,
401+ Err ( SyscallExecutionError :: Revert { error_data : data } ) => {
402+ SyscallResponseWrapper :: Failure { gas_counter : remaining_gas, error_data : data }
403+ }
404+ Err ( error) => return Err ( error. into ( ) ) ,
405+ } ;
406+
407+ response. write ( vm, syscall_executor. get_mut_syscall_ptr ( ) ) ?;
408+
409+ Ok ( ( ) )
410+ }
0 commit comments