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 (
@@ -150,25 +141,63 @@ impl ExecuteCall for LibraryCallRequest {
150
141
}
151
142
}
152
143
144
+ // crates/blockifier/src/execution/syscalls/vm_syscall_utils.rs:677 (execute_syscall)
153
145
fn execute_syscall < Request : ExecuteCall + SyscallRequest > (
146
+ selector : SyscallSelector ,
154
147
vm : & mut VirtualMachine ,
155
148
cheatable_starknet_runtime : & mut CheatableStarknetRuntime ,
156
149
) -> Result < ( ) , HintError > {
157
- let _selector = felt_from_ptr ( vm, cheatable_starknet_runtime. get_mut_syscall_ptr ( ) ) ?;
150
+ // region: Modified blockifier code
151
+ let syscall_handler = & mut cheatable_starknet_runtime. extended_runtime . hint_handler ;
152
+ let cheatnet_state = & mut * cheatable_starknet_runtime. extension . cheatnet_state ;
153
+
154
+ // Increment, since the selector was peeked into before
155
+ syscall_handler. syscall_ptr += 1 ;
156
+ syscall_handler. increment_syscall_count_by ( & selector, 1 ) ;
157
+ // endregion
158
+
159
+ let syscall_gas_cost = syscall_handler
160
+ . get_gas_cost_from_selector ( & selector)
161
+ . map_err ( |error| SyscallExecutorBaseError :: GasCost { error, selector } ) ?;
158
162
159
163
let SyscallRequestWrapper {
160
164
gas_counter,
161
165
request,
162
- } = SyscallRequestWrapper :: < Request > :: read (
163
- vm,
164
- cheatable_starknet_runtime. get_mut_syscall_ptr ( ) ,
165
- ) ?;
166
+ } = SyscallRequestWrapper :: < Request > :: read ( vm, syscall_handler. get_mut_syscall_ptr ( ) ) ?;
167
+
168
+ let syscall_gas_cost =
169
+ syscall_gas_cost. get_syscall_cost ( u64_from_usize ( request. get_linear_factor_length ( ) ) ) ;
170
+ let syscall_base_cost = syscall_handler. get_syscall_base_gas_cost ( ) ;
171
+
172
+ // Sanity check for preventing underflow.
173
+ assert ! (
174
+ syscall_gas_cost >= syscall_base_cost,
175
+ "Syscall gas cost must be greater than base syscall gas cost"
176
+ ) ;
177
+
178
+ // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged.
179
+ let required_gas = syscall_gas_cost - syscall_base_cost;
180
+
181
+ if gas_counter < required_gas {
182
+ let out_of_gas_error =
183
+ Felt :: from_hex ( OUT_OF_GAS_ERROR ) . map_err ( SyscallExecutorBaseError :: from) ?;
184
+ let response: SyscallResponseWrapper < SingleSegmentResponse > =
185
+ SyscallResponseWrapper :: Failure {
186
+ gas_counter,
187
+ revert_data : RevertData :: new_normal ( vec ! [ out_of_gas_error] ) ,
188
+ } ;
189
+ response. write ( vm, syscall_handler. get_mut_syscall_ptr ( ) ) ?;
166
190
167
- let cheatnet_state = & mut * cheatable_starknet_runtime. extension . cheatnet_state ;
168
- let syscall_handler = & mut cheatable_starknet_runtime. extended_runtime . hint_handler ;
191
+ return Ok ( ( ) ) ;
192
+ }
193
+
194
+ let mut remaining_gas = gas_counter - required_gas;
195
+
196
+ // region: Modified blockifier code
197
+ let call_result = request. execute_call ( syscall_handler, cheatnet_state, & mut remaining_gas) ;
198
+ write_call_response ( syscall_handler, vm, remaining_gas, call_result) ?;
199
+ // endregion
169
200
170
- let call_result = request. execute_call ( syscall_handler, cheatnet_state) ;
171
- write_call_response ( syscall_handler, vm, gas_counter, call_result) ?;
172
201
Ok ( ( ) )
173
202
}
174
203
0 commit comments