@@ -2,6 +2,7 @@ use std::cmp::min;
2
2
3
3
use cairo_vm:: vm:: runners:: cairo_runner:: ResourceTracker ;
4
4
use itertools:: concat;
5
+ use num_bigint:: BigUint ;
5
6
use starknet_api:: calldata;
6
7
use starknet_api:: core:: { ContractAddress , EntryPointSelector } ;
7
8
use starknet_api:: deprecated_contract_class:: EntryPointType ;
@@ -10,6 +11,7 @@ use starknet_api::transaction::{
10
11
Calldata , DeployAccountTransaction , Fee , InvokeTransaction , TransactionVersion ,
11
12
} ;
12
13
14
+ use super :: transaction_utils:: felt_to_biguint;
13
15
use crate :: abi:: abi_utils:: selector_from_name;
14
16
use crate :: abi:: constants as abi_constants;
15
17
use crate :: block_context:: BlockContext ;
@@ -26,6 +28,7 @@ use crate::state::cached_state::{
26
28
} ;
27
29
use crate :: state:: state_api:: { State , StateReader } ;
28
30
use crate :: transaction:: constants;
31
+ use crate :: transaction:: constants:: QUERY_VERSION_BASE_BIT ;
29
32
use crate :: transaction:: errors:: TransactionExecutionError ;
30
33
use crate :: transaction:: objects:: {
31
34
AccountTransactionContext , ResourcesMapping , TransactionExecutionInfo ,
@@ -34,7 +37,7 @@ use crate::transaction::objects::{
34
37
use crate :: transaction:: transaction_execution:: Transaction ;
35
38
use crate :: transaction:: transaction_types:: TransactionType ;
36
39
use crate :: transaction:: transaction_utils:: {
37
- calculate_l1_gas_usage, calculate_tx_resources, update_remaining_gas,
40
+ biguint_to_felt , calculate_l1_gas_usage, calculate_tx_resources, update_remaining_gas,
38
41
} ;
39
42
use crate :: transaction:: transactions:: { DeclareTransaction , Executable , ExecutableTransaction } ;
40
43
@@ -140,14 +143,33 @@ impl AccountTransaction {
140
143
}
141
144
}
142
145
143
- fn get_account_transaction_context ( & self ) -> AccountTransactionContext {
146
+ fn version ( & self ) -> TransactionVersion {
147
+ match self {
148
+ Self :: Declare ( tx) => tx. tx ( ) . version ( ) ,
149
+ Self :: DeployAccount ( tx) => tx. version ,
150
+ Self :: Invoke ( tx) => match tx {
151
+ InvokeTransaction :: V0 ( _) => TransactionVersion ( StarkFelt :: from ( 0_u8 ) ) ,
152
+ InvokeTransaction :: V1 ( _) => TransactionVersion ( StarkFelt :: from ( 1_u8 ) ) ,
153
+ } ,
154
+ }
155
+ }
156
+
157
+ fn get_account_transaction_context ( & self , simulate : bool ) -> AccountTransactionContext {
158
+ let mut version = self . version ( ) ;
159
+ if simulate {
160
+ let query_version_base = BigUint :: from ( 2_u8 ) . pow ( QUERY_VERSION_BASE_BIT ) ;
161
+ let simulate_version = query_version_base + felt_to_biguint ( version. 0 ) ;
162
+ version = TransactionVersion (
163
+ biguint_to_felt ( simulate_version) . expect ( "The version should be a field element." ) ,
164
+ ) ;
165
+ }
144
166
match self {
145
167
Self :: Declare ( tx) => {
146
168
let tx = & tx. tx ( ) ;
147
169
AccountTransactionContext {
148
170
transaction_hash : tx. transaction_hash ( ) ,
149
171
max_fee : tx. max_fee ( ) ,
150
- version : tx . version ( ) ,
172
+ version,
151
173
signature : tx. signature ( ) ,
152
174
nonce : tx. nonce ( ) ,
153
175
sender_address : tx. sender_address ( ) ,
@@ -156,26 +178,37 @@ impl AccountTransaction {
156
178
Self :: DeployAccount ( tx) => AccountTransactionContext {
157
179
transaction_hash : tx. transaction_hash ,
158
180
max_fee : tx. max_fee ,
159
- version : tx . version ,
181
+ version,
160
182
signature : tx. signature . clone ( ) ,
161
183
nonce : tx. nonce ,
162
184
sender_address : tx. contract_address ,
163
185
} ,
164
186
Self :: Invoke ( tx) => AccountTransactionContext {
165
187
transaction_hash : tx. transaction_hash ( ) ,
166
188
max_fee : tx. max_fee ( ) ,
167
- version : match tx {
168
- InvokeTransaction :: V0 ( _) => TransactionVersion ( StarkFelt :: from ( 0_u8 ) ) ,
169
- InvokeTransaction :: V1 ( _) => TransactionVersion ( StarkFelt :: from ( 1_u8 ) ) ,
170
- } ,
189
+ version,
171
190
signature : tx. signature ( ) ,
172
191
nonce : tx. nonce ( ) ,
173
192
sender_address : tx. sender_address ( ) ,
174
193
} ,
175
194
}
176
195
}
177
196
178
- fn verify_tx_version ( & self , version : TransactionVersion ) -> TransactionExecutionResult < ( ) > {
197
+ fn verify_tx_version (
198
+ & self ,
199
+ version : TransactionVersion ,
200
+ simulate : bool ,
201
+ ) -> TransactionExecutionResult < ( ) > {
202
+ let version = match simulate {
203
+ true => {
204
+ let query_version_base = BigUint :: from ( 2_u8 ) . pow ( QUERY_VERSION_BASE_BIT ) ;
205
+ let version = felt_to_biguint ( version. 0 ) - query_version_base;
206
+ TransactionVersion (
207
+ biguint_to_felt ( version) . expect ( "The version should be a field element." ) ,
208
+ )
209
+ }
210
+ false => version,
211
+ } ;
179
212
let allowed_versions: Vec < TransactionVersion > = match self {
180
213
// Support `Declare` of version 0 in order to allow bootstrapping of a new system.
181
214
Self :: Declare ( _) => {
@@ -204,7 +237,7 @@ impl AccountTransaction {
204
237
account_tx_context : & AccountTransactionContext ,
205
238
state : & mut dyn State ,
206
239
) -> TransactionExecutionResult < ( ) > {
207
- if account_tx_context. version == TransactionVersion ( StarkFelt :: from ( 0_u8 ) ) {
240
+ if account_tx_context. is_v0 ( ) {
208
241
return Ok ( ( ) ) ;
209
242
}
210
243
@@ -229,9 +262,10 @@ impl AccountTransaction {
229
262
remaining_gas : & mut u64 ,
230
263
block_context : & BlockContext ,
231
264
validate : bool ,
265
+ simulate : bool ,
232
266
) -> TransactionExecutionResult < Option < CallInfo > > {
233
267
if validate {
234
- self . validate_tx ( state, resources, remaining_gas, block_context)
268
+ self . validate_tx ( state, resources, remaining_gas, block_context, simulate )
235
269
} else {
236
270
Ok ( None )
237
271
}
@@ -243,8 +277,9 @@ impl AccountTransaction {
243
277
resources : & mut ExecutionResources ,
244
278
remaining_gas : & mut u64 ,
245
279
block_context : & BlockContext ,
280
+ simulate : bool ,
246
281
) -> TransactionExecutionResult < Option < CallInfo > > {
247
- let account_tx_context = self . get_account_transaction_context ( ) ;
282
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
248
283
let mut context =
249
284
EntryPointExecutionContext :: new_validate ( block_context, & account_tx_context) ;
250
285
if context. account_tx_context . is_v0 ( ) {
@@ -306,8 +341,9 @@ impl AccountTransaction {
306
341
& self ,
307
342
state : & mut TransactionalState < ' _ , S > ,
308
343
block_context : & BlockContext ,
344
+ simulate : bool ,
309
345
) -> TransactionExecutionResult < ( ) > {
310
- let account_tx_context = self . get_account_transaction_context ( ) ;
346
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
311
347
let max_fee = account_tx_context. max_fee ;
312
348
313
349
// Check fee balance.
@@ -341,14 +377,15 @@ impl AccountTransaction {
341
377
block_context : & BlockContext ,
342
378
actual_fee : Fee ,
343
379
charge_fee : bool ,
380
+ simulate : bool ,
344
381
) -> TransactionExecutionResult < Option < CallInfo > > {
345
382
if !charge_fee || actual_fee == Fee ( 0 ) {
346
383
// Fee charging is not enforced in some transaction simulations and tests.
347
384
return Ok ( None ) ;
348
385
}
349
386
350
387
// Charge fee.
351
- let account_tx_context = self . get_account_transaction_context ( ) ;
388
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
352
389
let fee_transfer_call_info =
353
390
Self :: execute_fee_transfer ( state, block_context, account_tx_context, actual_fee) ?;
354
391
@@ -409,6 +446,7 @@ impl AccountTransaction {
409
446
}
410
447
}
411
448
449
+ #[ allow( clippy:: too_many_arguments) ]
412
450
fn run_non_revertible < S : StateReader > (
413
451
& self ,
414
452
state : & mut TransactionalState < ' _ , S > ,
@@ -417,24 +455,37 @@ impl AccountTransaction {
417
455
block_context : & BlockContext ,
418
456
mut execution_context : EntryPointExecutionContext ,
419
457
validate : bool ,
458
+ simulate : bool ,
420
459
) -> TransactionExecutionResult < ValidateExecuteCallInfo > {
421
460
let validate_call_info: Option < CallInfo > ;
422
461
let execute_call_info: Option < CallInfo > ;
423
462
if matches ! ( self , Self :: DeployAccount ( _) ) {
424
463
// Handle `DeployAccount` transactions separately, due to different order of things.
425
464
execute_call_info =
426
465
self . run_execute ( state, resources, & mut execution_context, remaining_gas) ?;
427
- validate_call_info =
428
- self . handle_validate_tx ( state, resources, remaining_gas, block_context, validate) ?;
466
+ validate_call_info = self . handle_validate_tx (
467
+ state,
468
+ resources,
469
+ remaining_gas,
470
+ block_context,
471
+ validate,
472
+ simulate,
473
+ ) ?;
429
474
} else {
430
- validate_call_info =
431
- self . handle_validate_tx ( state, resources, remaining_gas, block_context, validate) ?;
475
+ validate_call_info = self . handle_validate_tx (
476
+ state,
477
+ resources,
478
+ remaining_gas,
479
+ block_context,
480
+ validate,
481
+ simulate,
482
+ ) ?;
432
483
execute_call_info =
433
484
self . run_execute ( state, resources, & mut execution_context, remaining_gas) ?;
434
485
}
435
486
let state_changes = state. get_actual_state_changes_for_fee_charge (
436
487
block_context. fee_token_address ,
437
- Some ( self . get_account_transaction_context ( ) . sender_address ) ,
488
+ Some ( self . get_account_transaction_context ( simulate ) . sender_address ) ,
438
489
) ?;
439
490
let ( actual_fee, actual_resources) = self . calculate_actual_fee_and_resources (
440
491
StateChangesCount :: from ( & state_changes) ,
@@ -444,6 +495,7 @@ impl AccountTransaction {
444
495
block_context,
445
496
false ,
446
497
0 ,
498
+ simulate,
447
499
) ?;
448
500
Ok ( ValidateExecuteCallInfo :: new_accepted (
449
501
validate_call_info,
@@ -463,11 +515,18 @@ impl AccountTransaction {
463
515
mut execution_context : EntryPointExecutionContext ,
464
516
charge_fee : bool ,
465
517
validate : bool ,
518
+ simulate : bool ,
466
519
) -> TransactionExecutionResult < ValidateExecuteCallInfo > {
467
- let account_tx_context = self . get_account_transaction_context ( ) ;
520
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
468
521
// Run the validation, and if execution later fails, only keep the validation diff.
469
- let validate_call_info =
470
- self . handle_validate_tx ( state, resources, remaining_gas, block_context, validate) ?;
522
+ let validate_call_info = self . handle_validate_tx (
523
+ state,
524
+ resources,
525
+ remaining_gas,
526
+ block_context,
527
+ validate,
528
+ simulate,
529
+ ) ?;
471
530
let validate_steps = if validate {
472
531
validate_call_info
473
532
. as_ref ( )
@@ -535,6 +594,7 @@ impl AccountTransaction {
535
594
block_context,
536
595
false ,
537
596
0 ,
597
+ simulate,
538
598
) ?;
539
599
540
600
// Check if as a result of tx execution the sender's fee token balance is maxed out,
@@ -576,6 +636,7 @@ impl AccountTransaction {
576
636
block_context,
577
637
true ,
578
638
n_reverted_steps,
639
+ simulate,
579
640
) ?;
580
641
581
642
return Ok ( ValidateExecuteCallInfo :: new_reverted (
@@ -614,6 +675,7 @@ impl AccountTransaction {
614
675
block_context,
615
676
true ,
616
677
n_reverted_steps,
678
+ simulate,
617
679
) ?;
618
680
619
681
Ok ( ValidateExecuteCallInfo :: new_reverted (
@@ -626,20 +688,21 @@ impl AccountTransaction {
626
688
}
627
689
}
628
690
629
- fn is_non_revertible ( & self ) -> bool {
691
+ fn is_non_revertible ( & self , simulate : bool ) -> bool {
630
692
// Reverting a Declare or Deploy transaction is not currently supported in the OS.
631
693
match self {
632
694
Self :: Declare ( _) => true ,
633
695
Self :: DeployAccount ( _) => true ,
634
696
Self :: Invoke ( _) => {
635
697
// V0 transactions do not have validation; we cannot deduct fee for execution. Thus,
636
698
// invoke transactions of are non-revertible iff they are of version 0.
637
- self . get_account_transaction_context ( ) . is_v0 ( )
699
+ self . get_account_transaction_context ( simulate ) . is_v0 ( )
638
700
}
639
701
}
640
702
}
641
703
642
704
/// Runs validation and execution.
705
+ #[ allow( clippy:: too_many_arguments) ]
643
706
fn run_or_revert < S : StateReader > (
644
707
& self ,
645
708
state : & mut TransactionalState < ' _ , S > ,
@@ -648,8 +711,9 @@ impl AccountTransaction {
648
711
block_context : & BlockContext ,
649
712
charge_fee : bool ,
650
713
validate : bool ,
714
+ simulate : bool ,
651
715
) -> TransactionExecutionResult < ValidateExecuteCallInfo > {
652
- let account_tx_context = self . get_account_transaction_context ( ) ;
716
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
653
717
let execution_context = if matches ! ( self , Self :: DeployAccount ( _) ) {
654
718
// Run constructor in validate mode, since it is executed before the transaction is
655
719
// validated.
@@ -658,14 +722,15 @@ impl AccountTransaction {
658
722
EntryPointExecutionContext :: new_invoke ( block_context, & account_tx_context)
659
723
} ;
660
724
661
- if self . is_non_revertible ( ) {
725
+ if self . is_non_revertible ( simulate ) {
662
726
return self . run_non_revertible (
663
727
state,
664
728
resources,
665
729
remaining_gas,
666
730
block_context,
667
731
execution_context,
668
732
validate,
733
+ simulate,
669
734
) ;
670
735
}
671
736
@@ -677,6 +742,7 @@ impl AccountTransaction {
677
742
execution_context,
678
743
charge_fee,
679
744
validate,
745
+ simulate,
680
746
)
681
747
}
682
748
@@ -690,8 +756,9 @@ impl AccountTransaction {
690
756
block_context : & BlockContext ,
691
757
is_reverted : bool ,
692
758
n_reverted_steps : usize ,
759
+ simulate : bool ,
693
760
) -> TransactionExecutionResult < ( Fee , ResourcesMapping ) > {
694
- let account_tx_context = self . get_account_transaction_context ( ) ;
761
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
695
762
696
763
let non_optional_call_infos = vec ! [ validate_call_info. as_ref( ) , execute_call_info. as_ref( ) ]
697
764
. into_iter ( )
@@ -724,16 +791,17 @@ impl<S: StateReader> ExecutableTransaction<S> for AccountTransaction {
724
791
block_context : & BlockContext ,
725
792
charge_fee : bool ,
726
793
validate : bool ,
794
+ simulate : bool ,
727
795
) -> TransactionExecutionResult < TransactionExecutionInfo > {
728
- let account_tx_context = self . get_account_transaction_context ( ) ;
729
- self . verify_tx_version ( account_tx_context. version ) ?;
796
+ let account_tx_context = self . get_account_transaction_context ( simulate ) ;
797
+ self . verify_tx_version ( account_tx_context. version , simulate ) ?;
730
798
731
799
let mut resources = ExecutionResources :: default ( ) ;
732
800
let mut remaining_gas = Transaction :: initial_gas ( ) ;
733
801
734
802
// Nonce and fee check should be done before running user code.
735
803
if charge_fee {
736
- self . check_fee_balance ( state, block_context) ?;
804
+ self . check_fee_balance ( state, block_context, simulate ) ?;
737
805
}
738
806
// Handle nonce.
739
807
Self :: handle_nonce ( & account_tx_context, state) ?;
@@ -752,10 +820,11 @@ impl<S: StateReader> ExecutableTransaction<S> for AccountTransaction {
752
820
block_context,
753
821
charge_fee,
754
822
validate,
823
+ simulate,
755
824
) ?;
756
825
757
826
let fee_transfer_call_info =
758
- self . handle_fee ( state, block_context, final_fee, charge_fee) ?;
827
+ self . handle_fee ( state, block_context, final_fee, charge_fee, simulate ) ?;
759
828
760
829
let tx_execution_info = TransactionExecutionInfo {
761
830
validate_call_info,
0 commit comments