1
1
use std:: marker:: PhantomData ;
2
2
3
+ use crate :: state:: CheatnetState ;
3
4
use blockifier:: execution:: entry_point:: { CallEntryPoint , CallType } ;
4
- use blockifier:: execution:: execution_utils:: felt_from_ptr;
5
- use blockifier:: execution:: syscalls:: hint_processor:: SyscallHintProcessor ;
5
+ use blockifier:: execution:: syscalls:: hint_processor:: { OUT_OF_GAS_ERROR , SyscallHintProcessor } ;
6
6
use blockifier:: execution:: syscalls:: syscall_executor:: SyscallExecutor ;
7
7
use blockifier:: execution:: syscalls:: vm_syscall_utils:: {
8
8
CallContractRequest , LibraryCallRequest , RevertData , SingleSegmentResponse ,
9
- SyscallRequestWrapper , SyscallSelector ,
9
+ SyscallExecutorBaseError , SyscallRequestWrapper , SyscallSelector ,
10
10
} ;
11
11
use blockifier:: execution:: {
12
12
execution_utils:: ReadOnlySegment ,
13
13
syscalls:: vm_syscall_utils:: { SyscallRequest , SyscallResponse , SyscallResponseWrapper } ,
14
14
} ;
15
+ use blockifier:: utils:: u64_from_usize;
15
16
use cairo_vm:: types:: relocatable:: MaybeRelocatable ;
16
17
use cairo_vm:: vm:: { errors:: hint_errors:: HintError , vm_core:: VirtualMachine } ;
17
- use runtime:: { ExtendedRuntime , ExtensionLogic , SyscallHandlingResult , SyscallPtrAccess } ;
18
+ use runtime:: { ExtendedRuntime , ExtensionLogic , SyscallHandlingResult } ;
18
19
use starknet_api:: contract_class:: EntryPointType ;
19
20
use starknet_api:: core:: ContractAddress ;
20
-
21
- use crate :: state:: CheatnetState ;
21
+ use starknet_types_core:: felt:: Felt ;
22
22
23
23
use crate :: runtime_extensions:: call_to_blockifier_runtime_extension:: rpc:: {
24
24
AddressOrClassHash , call_entry_point,
@@ -53,26 +53,14 @@ impl<'a> ExtensionLogic for CallToBlockifierExtension<'a> {
53
53
match selector {
54
54
// We execute contract calls and library calls with modified blockifier
55
55
// This is redirected to drop ForgeRuntimeExtension
56
- // and to enable handling call errors with safe dispatchers in the test code
57
- // since call errors cannot be handled on real starknet
58
- // https://docs.starknet.io/architecture-and-concepts/smart-contracts/system-calls-cairo1/#call_contract
56
+ // and to enable executing outer calls in tests as non-revertible.
59
57
SyscallSelector :: CallContract => {
60
- execute_syscall :: < CallContractRequest > ( vm, extended_runtime) ?;
61
-
62
- extended_runtime
63
- . extended_runtime
64
- . hint_handler
65
- . increment_syscall_count_by ( & selector, 1 ) ;
58
+ execute_syscall :: < CallContractRequest > ( selector, vm, extended_runtime) ?;
66
59
67
60
Ok ( SyscallHandlingResult :: Handled )
68
61
}
69
62
SyscallSelector :: LibraryCall => {
70
- execute_syscall :: < LibraryCallRequest > ( vm, extended_runtime) ?;
71
-
72
- extended_runtime
73
- . extended_runtime
74
- . hint_handler
75
- . increment_syscall_count_by ( & selector, 1 ) ;
63
+ execute_syscall :: < LibraryCallRequest > ( selector, vm, extended_runtime) ?;
76
64
77
65
Ok ( SyscallHandlingResult :: Handled )
78
66
}
89
77
self ,
90
78
syscall_handler : & mut SyscallHintProcessor ,
91
79
cheatnet_state : & mut CheatnetState ,
80
+ remaining_gas : & mut u64 ,
92
81
) -> CallResult ;
93
82
}
94
83
@@ -97,6 +86,7 @@ impl ExecuteCall for CallContractRequest {
97
86
self : CallContractRequest ,
98
87
syscall_handler : & mut SyscallHintProcessor ,
99
88
cheatnet_state : & mut CheatnetState ,
89
+ remaining_gas : & mut u64 ,
100
90
) -> CallResult {
101
91
let contract_address = self . contract_address ;
102
92
@@ -109,7 +99,7 @@ impl ExecuteCall for CallContractRequest {
109
99
storage_address : contract_address,
110
100
caller_address : TryFromHexStr :: try_from_hex_str ( TEST_ADDRESS ) . unwrap ( ) ,
111
101
call_type : CallType :: Call ,
112
- initial_gas : i64 :: MAX as u64 ,
102
+ initial_gas : * remaining_gas ,
113
103
} ;
114
104
115
105
call_entry_point (
@@ -126,6 +116,7 @@ impl ExecuteCall for LibraryCallRequest {
126
116
self : LibraryCallRequest ,
127
117
syscall_handler : & mut SyscallHintProcessor ,
128
118
cheatnet_state : & mut CheatnetState ,
119
+ remaining_gas : & mut u64 ,
129
120
) -> CallResult {
130
121
let class_hash = self . class_hash ;
131
122
@@ -138,7 +129,7 @@ impl ExecuteCall for LibraryCallRequest {
138
129
storage_address : TryFromHexStr :: try_from_hex_str ( TEST_ADDRESS ) . unwrap ( ) ,
139
130
caller_address : ContractAddress :: default ( ) ,
140
131
call_type : CallType :: Delegate ,
141
- initial_gas : u64 :: MAX ,
132
+ initial_gas : * remaining_gas ,
142
133
} ;
143
134
144
135
call_entry_point (
@@ -151,24 +142,55 @@ impl ExecuteCall for LibraryCallRequest {
151
142
}
152
143
153
144
fn execute_syscall < Request : ExecuteCall + SyscallRequest > (
145
+ selector : SyscallSelector ,
154
146
vm : & mut VirtualMachine ,
155
147
cheatable_starknet_runtime : & mut CheatableStarknetRuntime ,
156
148
) -> Result < ( ) , HintError > {
157
- let _selector = felt_from_ptr ( vm, cheatable_starknet_runtime. get_mut_syscall_ptr ( ) ) ?;
149
+ let syscall_handler = & mut cheatable_starknet_runtime. extended_runtime . hint_handler ;
150
+ let cheatnet_state = & mut * cheatable_starknet_runtime. extension . cheatnet_state ;
151
+
152
+ // Increment, since the selector was peeked into before
153
+ syscall_handler. syscall_ptr += 1 ;
154
+ syscall_handler. increment_syscall_count_by ( & selector, 1 ) ;
158
155
159
156
let SyscallRequestWrapper {
160
157
gas_counter,
161
158
request,
162
- } = SyscallRequestWrapper :: < Request > :: read (
163
- vm,
164
- cheatable_starknet_runtime. get_mut_syscall_ptr ( ) ,
165
- ) ?;
159
+ } = SyscallRequestWrapper :: < Request > :: read ( vm, syscall_handler. get_mut_syscall_ptr ( ) ) ?;
160
+
161
+ let syscall_gas_cost = syscall_handler
162
+ . get_gas_cost_from_selector ( & selector)
163
+ . map_err ( |error| SyscallExecutorBaseError :: GasCost { error, selector } ) ?;
164
+ let syscall_gas_cost =
165
+ syscall_gas_cost. get_syscall_cost ( u64_from_usize ( request. get_linear_factor_length ( ) ) ) ;
166
+ let syscall_base_cost = syscall_handler. get_syscall_base_gas_cost ( ) ;
167
+
168
+ // Sanity check for preventing underflow.
169
+ assert ! (
170
+ syscall_gas_cost >= syscall_base_cost,
171
+ "Syscall gas cost must be greater than base syscall gas cost"
172
+ ) ;
173
+
174
+ // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged.
175
+ let required_gas = syscall_gas_cost - syscall_base_cost;
176
+
177
+ if gas_counter < required_gas {
178
+ let out_of_gas_error =
179
+ Felt :: from_hex ( OUT_OF_GAS_ERROR ) . map_err ( SyscallExecutorBaseError :: from) ?;
180
+ let response: SyscallResponseWrapper < SingleSegmentResponse > =
181
+ SyscallResponseWrapper :: Failure {
182
+ gas_counter,
183
+ revert_data : RevertData :: new_normal ( vec ! [ out_of_gas_error] ) ,
184
+ } ;
185
+ response. write ( vm, syscall_handler. get_mut_syscall_ptr ( ) ) ?;
166
186
167
- let cheatnet_state = & mut * cheatable_starknet_runtime. extension . cheatnet_state ;
168
- let syscall_handler = & mut cheatable_starknet_runtime. extended_runtime . hint_handler ;
187
+ return Ok ( ( ) ) ;
188
+ }
189
+
190
+ let mut remaining_gas = gas_counter - required_gas;
169
191
170
- let call_result = request. execute_call ( syscall_handler, cheatnet_state) ;
171
- write_call_response ( syscall_handler, vm, gas_counter , call_result) ?;
192
+ let call_result = request. execute_call ( syscall_handler, cheatnet_state, & mut remaining_gas ) ;
193
+ write_call_response ( syscall_handler, vm, remaining_gas , call_result) ?;
172
194
Ok ( ( ) )
173
195
}
174
196
0 commit comments