@@ -2,6 +2,8 @@ use crate::error::ExecutionError;
2
2
use crate :: juno_state_reader:: JunoStateReader ;
3
3
use blockifier:: execution:: contract_class:: TrackedResource ;
4
4
use blockifier:: state:: state_api:: { StateReader , StateResult , UpdatableState } ;
5
+ use blockifier:: transaction:: account_transaction:: ExecutionFlags ;
6
+ use blockifier:: transaction:: objects:: HasRelatedFeeType ;
5
7
use blockifier:: transaction:: transaction_execution:: Transaction ;
6
8
use blockifier:: transaction:: transactions:: ExecutableTransaction ;
7
9
use blockifier:: {
@@ -12,8 +14,14 @@ use blockifier::{
12
14
use starknet_api:: core:: ClassHash ;
13
15
use starknet_api:: executable_transaction:: AccountTransaction ;
14
16
use starknet_api:: execution_resources:: GasAmount ;
15
- use starknet_api:: transaction:: fields:: { GasVectorComputationMode , ValidResourceBounds } ;
16
- use starknet_api:: transaction:: { DeclareTransaction , DeployAccountTransaction , InvokeTransaction } ;
17
+ use starknet_api:: transaction:: fields:: {
18
+ AllResourceBounds , GasVectorComputationMode , ValidResourceBounds ,
19
+ } ;
20
+ use starknet_api:: transaction:: {
21
+ DeclareTransaction , DeclareTransactionV3 , DeployAccountTransaction , DeployAccountTransactionV3 ,
22
+ InvokeTransaction , InvokeTransactionV3 ,
23
+ } ;
24
+ use anyhow:: { Error , anyhow} ;
17
25
18
26
pub fn process_transaction (
19
27
txn : & mut Transaction ,
@@ -140,16 +148,12 @@ fn execute_transaction_with_binary_search<S>(
140
148
where
141
149
S : UpdatableState ,
142
150
{
143
- let initial_gas_limit = extract_l2_gas_limit ( transaction) ?;
144
- let mut original_transaction = transaction. clone ( ) ;
151
+ let initial_resource_bounds = extract_resource_bounds ( transaction) ?;
152
+ let initial_gas_limit = initial_resource_bounds. l2_gas . max_amount ;
153
+ let max_l2_gas_limit = calculate_max_l2_gas_covered ( transaction, block_context, state) ?;
145
154
146
155
// Simulate transaction execution with maximum possible gas to get actual gas usage.
147
- set_l2_gas_limit ( transaction, GasAmount :: MAX ) ?;
148
- // TODO: Consider getting the upper bound from the balance and not changing the execution flags
149
- if let Transaction :: Account ( account_transaction) = transaction {
150
- account_transaction. execution_flags . charge_fee = false ;
151
- account_transaction. execution_flags . validate = false ;
152
- }
156
+ set_l2_gas_limit ( transaction, max_l2_gas_limit) ?;
153
157
154
158
let simulation_result =
155
159
match simulate_execution ( transaction, state, block_context, error_on_revert) {
@@ -212,31 +216,35 @@ where
212
216
Err ( SimulationError :: ExecutionError ( error) ) => return Err ( error) ,
213
217
}
214
218
} ;
215
-
216
- ( current_l2_gas_limit, tx_info, tx_state)
217
- }
218
- Err ( SimulationError :: ExecutionError ( error) ) => return Err ( error) ,
219
- } ;
220
- tx_state. abort ( ) ;
219
+ ( current_l2_gas_limit, tx_info, tx_state)
220
+ }
221
+ Err ( SimulationError :: ExecutionError ( error) ) => return Err ( error) ,
222
+ } ;
221
223
222
224
// If the computed gas limit exceeds the initial limit, revert the transaction.
223
225
// The L2 gas limit is set to zero to prevent the transaction execution from succeeding
224
226
// in the case where the user defined gas limit is less than the required gas limit
225
- if l2_gas_limit > initial_gas_limit {
226
- set_l2_gas_limit ( & mut original_transaction, GasAmount ( 0 ) ) ?;
227
- return execute_transaction ( & original_transaction, state, block_context, error_on_revert) ;
227
+ if get_execution_flags ( transaction) . charge_fee && l2_gas_limit > initial_gas_limit {
228
+ tx_state. abort ( ) ;
229
+ set_l2_gas_limit ( transaction, initial_gas_limit) ?;
230
+ return execute_transaction ( & transaction, state, block_context, error_on_revert) ;
228
231
}
229
232
230
- set_l2_gas_limit ( & mut original_transaction, initial_gas_limit) ?;
231
- let mut exec_info =
232
- execute_transaction ( & original_transaction, state, block_context, error_on_revert) ?;
233
+ let mut exec_info = execute_transaction ( & transaction, state, block_context, error_on_revert) ?;
233
234
234
235
// Execute the transaction with the determined gas limit and update the estimate.
235
236
exec_info. receipt . gas . l2_gas = l2_gas_limit;
236
237
237
238
Ok ( exec_info)
238
239
}
239
240
241
+ fn get_execution_flags ( tx : & Transaction ) -> ExecutionFlags {
242
+ match tx {
243
+ Transaction :: Account ( account_transaction) => account_transaction. execution_flags . clone ( ) ,
244
+ Transaction :: L1Handler ( _) => Default :: default ( ) ,
245
+ }
246
+ }
247
+
240
248
fn calculate_midpoint ( a : GasAmount , b : GasAmount ) -> GasAmount {
241
249
let GasAmount ( a) = a;
242
250
let GasAmount ( b) = b;
@@ -286,7 +294,7 @@ where
286
294
fn set_l2_gas_limit (
287
295
transaction : & mut Transaction ,
288
296
gas_limit : GasAmount ,
289
- ) -> Result < ( ) , anyhow :: Error > {
297
+ ) -> Result < ( ) , Error > {
290
298
if let Transaction :: Account ( ref mut account_transaction) = transaction {
291
299
match & mut account_transaction. tx {
292
300
AccountTransaction :: Declare ( ref mut tx) => {
@@ -321,42 +329,95 @@ fn set_l2_gas_limit(
321
329
}
322
330
}
323
331
}
324
- Err ( anyhow:: anyhow !( "Failed to set L2 gas limit" ) )
332
+ Err ( anyhow ! ( "Failed to set L2 gas limit" ) )
325
333
}
326
334
327
- fn extract_l2_gas_limit ( transaction : & Transaction ) -> Result < GasAmount , anyhow:: Error > {
328
- if let Transaction :: Account ( account_transaction) = transaction {
329
- match & account_transaction. tx {
330
- AccountTransaction :: Declare ( tx) => {
331
- if let DeclareTransaction :: V3 ( tx) = & tx. tx {
332
- if let ValidResourceBounds :: AllResources ( all_resource_bounds) =
333
- & tx. resource_bounds
334
- {
335
- return Ok ( all_resource_bounds. l2_gas . max_amount ) ;
336
- }
337
- }
338
- }
339
- AccountTransaction :: DeployAccount ( tx) => {
340
- if let DeployAccountTransaction :: V3 ( tx) = & tx. tx {
341
- if let ValidResourceBounds :: AllResources ( all_resource_bounds) =
342
- & tx. resource_bounds
343
- {
344
- return Ok ( all_resource_bounds. l2_gas . max_amount ) ;
345
- }
346
- }
347
- }
348
- AccountTransaction :: Invoke ( tx) => {
349
- if let InvokeTransaction :: V3 ( tx) = & tx. tx {
350
- if let ValidResourceBounds :: AllResources ( all_resource_bounds) =
351
- & tx. resource_bounds
352
- {
353
- return Ok ( all_resource_bounds. l2_gas . max_amount ) ;
354
- }
355
- }
335
+ /// Retrieves the resource bounds for a given transaction.
336
+ fn extract_resource_bounds ( tx : & Transaction ) -> Result < AllResourceBounds , Error > {
337
+ match tx {
338
+ Transaction :: Account ( account_tx) => match & account_tx. tx {
339
+ AccountTransaction :: Declare ( declare_tx) => match & declare_tx. tx {
340
+ DeclareTransaction :: V3 ( DeclareTransactionV3 {
341
+ resource_bounds : ValidResourceBounds :: AllResources ( all_resources) ,
342
+ ..
343
+ } ) => Ok ( * all_resources) ,
344
+ _ => Err ( anyhow ! ( "Unsupported Declare transaction version" ) ) ,
345
+ } ,
346
+ AccountTransaction :: DeployAccount ( deploy_tx) => match & deploy_tx. tx {
347
+ DeployAccountTransaction :: V3 ( DeployAccountTransactionV3 {
348
+ resource_bounds : ValidResourceBounds :: AllResources ( all_resources) ,
349
+ ..
350
+ } ) => Ok ( * all_resources) ,
351
+ _ => Err ( anyhow ! (
352
+ "Unsupported DeployAccount transaction version"
353
+ ) ) ,
354
+ } ,
355
+ AccountTransaction :: Invoke ( invoke_tx) => match & invoke_tx. tx {
356
+ InvokeTransaction :: V3 ( InvokeTransactionV3 {
357
+ resource_bounds : ValidResourceBounds :: AllResources ( all_resources) ,
358
+ ..
359
+ } ) => Ok ( * all_resources) ,
360
+ _ => Err ( anyhow ! ( "Unsupported Invoke transaction version" ) ) ,
361
+ } ,
362
+ } ,
363
+ _ => Err ( anyhow ! ( "Unsupported transaction type" ) ) ,
364
+ }
365
+ }
366
+
367
+ /// Calculates the maximum amount of L2 gas that can be covered by the balance.
368
+ fn calculate_max_l2_gas_covered < S > (
369
+ tx : & Transaction ,
370
+ block_context : & blockifier:: context:: BlockContext ,
371
+ state : & mut S ,
372
+ ) -> Result < GasAmount , Error >
373
+ where
374
+ S : UpdatableState ,
375
+ {
376
+ // Extract initial resource bounds from the transaction.
377
+ let initial_resource_bounds = extract_resource_bounds ( tx) ?;
378
+
379
+ // Create resource bounds without L2 gas.
380
+ let resource_bounds_without_l2_gas = AllResourceBounds {
381
+ l2_gas : Default :: default ( ) ,
382
+ ..initial_resource_bounds
383
+ } ;
384
+
385
+ // Calculate the maximum possible fee without L2 gas.
386
+ let max_fee_without_l2_gas =
387
+ ValidResourceBounds :: AllResources ( resource_bounds_without_l2_gas) . max_possible_fee ( ) ;
388
+
389
+ match tx {
390
+ Transaction :: Account ( account_transaction) => {
391
+ // Retrieve the fee token address.
392
+ let fee_token_address = block_context
393
+ . chain_info ( )
394
+ . fee_token_address ( & account_transaction. fee_type ( ) ) ;
395
+
396
+ // Get the balance of the fee token.
397
+ let balance = state
398
+ . get_fee_token_balance ( account_transaction. sender_address ( ) , fee_token_address) ?;
399
+ let balance = ( balance. 1 . to_biguint ( ) << 128 ) + balance. 0 . to_biguint ( ) ;
400
+
401
+ if balance > max_fee_without_l2_gas. 0 . into ( ) {
402
+ // Calculate the maximum amount of L2 gas that can be bought with the balance.
403
+ let max_l2_gas = ( balance - max_fee_without_l2_gas. 0 )
404
+ / initial_resource_bounds
405
+ . l2_gas
406
+ . max_price_per_unit
407
+ . 0
408
+ . max ( 1u64 . into ( ) ) ;
409
+ Ok ( u64:: try_from ( max_l2_gas) . unwrap_or ( GasAmount :: MAX . 0 ) . into ( ) )
410
+ } else {
411
+ // Balance is less than committed L1 gas and L1 data gas, transaction will fail.
412
+ // Let it pass through here so that execution returns a detailed error.
413
+ Ok ( GasAmount :: ZERO )
356
414
}
357
415
}
416
+ Transaction :: L1Handler ( _) => {
417
+ // L1 handler transactions don't have L2 gas.
418
+ Err ( anyhow ! ( "L1 handler transactions don't have L2 gas" ) )
419
+ }
358
420
}
359
- Err ( anyhow:: anyhow!( "Failed to extract L2 gas limit" ) )
360
421
}
361
422
362
423
fn is_out_of_gas ( execution_info : & TransactionExecutionInfo ) -> bool {
0 commit comments