@@ -2,8 +2,13 @@ use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution::
2
2
use crate :: state:: CheatnetState ;
3
3
use blockifier:: execution:: call_info:: { CallInfo , Retdata } ;
4
4
use blockifier:: execution:: common_hints:: ExecutionMode ;
5
- use blockifier:: execution:: entry_point:: { CallEntryPoint , CallType } ;
6
- use blockifier:: execution:: errors:: EntryPointExecutionError ;
5
+ use blockifier:: execution:: entry_point:: {
6
+ CallEntryPoint , CallType , ConstructorContext , ConstructorEntryPointExecutionResult ,
7
+ EntryPointExecutionContext , handle_empty_constructor,
8
+ } ;
9
+ use blockifier:: execution:: errors:: {
10
+ ConstructorEntryPointExecutionError , EntryPointExecutionError ,
11
+ } ;
7
12
use blockifier:: execution:: execution_utils:: update_remaining_gas;
8
13
use blockifier:: execution:: native:: syscall_handler:: NativeSyscallHandler ;
9
14
use blockifier:: execution:: syscalls:: hint_processor:: {
@@ -13,15 +18,20 @@ use blockifier::execution::syscalls::syscall_base::SyscallHandlerBase;
13
18
use blockifier:: execution:: syscalls:: vm_syscall_utils:: {
14
19
SelfOrRevert , SyscallExecutorBaseError , SyscallSelector , TryExtractRevert ,
15
20
} ;
21
+ use blockifier:: state:: errors:: StateError ;
22
+ use blockifier:: state:: state_api:: State ;
23
+ use blockifier:: utils:: u64_from_usize;
16
24
use cairo_native:: starknet:: {
17
25
BlockInfo , ExecutionInfo , ExecutionInfoV2 , ResourceBounds , Secp256k1Point , Secp256r1Point ,
18
26
StarknetSyscallHandler , SyscallResult , TxV2Info , U256 ,
19
27
} ;
20
28
use num_traits:: ToPrimitive ;
21
29
use starknet_api:: contract_class:: EntryPointType ;
22
- use starknet_api:: core:: { ClassHash , ContractAddress , EntryPointSelector } ;
30
+ use starknet_api:: core:: {
31
+ ClassHash , ContractAddress , EntryPointSelector , calculate_contract_address,
32
+ } ;
23
33
use starknet_api:: execution_resources:: GasAmount ;
24
- use starknet_api:: transaction:: fields:: Calldata ;
34
+ use starknet_api:: transaction:: fields:: { Calldata , ContractAddressSalt } ;
25
35
use starknet_types_core:: felt:: Felt ;
26
36
use std:: sync:: Arc ;
27
37
@@ -87,6 +97,152 @@ pub fn execute_inner_call(
87
97
Ok ( raw_retdata)
88
98
}
89
99
100
+ #[ allow( clippy:: result_large_err) ]
101
+ pub fn execute_constructor_entry_point (
102
+ state : & mut dyn State ,
103
+ cheatnet_state : & mut CheatnetState ,
104
+ context : & mut EntryPointExecutionContext ,
105
+ ctor_context : ConstructorContext ,
106
+ calldata : Calldata ,
107
+ remaining_gas : & mut u64 ,
108
+ ) -> ConstructorEntryPointExecutionResult < CallInfo > {
109
+ // Ensure the class is declared (by reading it).
110
+ let compiled_class = state
111
+ . get_compiled_class ( ctor_context. class_hash )
112
+ . map_err ( |error| {
113
+ ConstructorEntryPointExecutionError :: new ( error. into ( ) , & ctor_context, None )
114
+ } ) ?;
115
+ let Some ( constructor_selector) = compiled_class. constructor_selector ( ) else {
116
+ // Contract has no constructor.
117
+ return handle_empty_constructor (
118
+ compiled_class,
119
+ context,
120
+ & ctor_context,
121
+ calldata,
122
+ * remaining_gas,
123
+ )
124
+ . map_err ( |error| ConstructorEntryPointExecutionError :: new ( error, & ctor_context, None ) ) ;
125
+ } ;
126
+
127
+ let mut constructor_call = CallEntryPoint {
128
+ class_hash : None ,
129
+ code_address : ctor_context. code_address ,
130
+ entry_point_type : EntryPointType :: Constructor ,
131
+ entry_point_selector : constructor_selector,
132
+ calldata,
133
+ storage_address : ctor_context. storage_address ,
134
+ caller_address : ctor_context. caller_address ,
135
+ call_type : CallType :: Call ,
136
+ initial_gas : * remaining_gas,
137
+ } ;
138
+
139
+ let call_info =
140
+ execute_call_entry_point ( & mut constructor_call, state, cheatnet_state, context, false )
141
+ . map_err ( |error| {
142
+ ConstructorEntryPointExecutionError :: new (
143
+ error,
144
+ & ctor_context,
145
+ Some ( constructor_selector) ,
146
+ )
147
+ } ) ?;
148
+
149
+ Ok ( call_info)
150
+ }
151
+
152
+ pub fn execute_deployment (
153
+ state : & mut dyn State ,
154
+ cheatnet_state : & mut CheatnetState ,
155
+ context : & mut EntryPointExecutionContext ,
156
+ ctor_context : ConstructorContext ,
157
+ constructor_calldata : Calldata ,
158
+ remaining_gas : & mut u64 ,
159
+ ) -> ConstructorEntryPointExecutionResult < CallInfo > {
160
+ // Address allocation in the state is done before calling the constructor, so that it is
161
+ // visible from it.
162
+ let deployed_contract_address = ctor_context. storage_address ;
163
+ let current_class_hash =
164
+ state
165
+ . get_class_hash_at ( deployed_contract_address)
166
+ . map_err ( |error| {
167
+ ConstructorEntryPointExecutionError :: new ( error. into ( ) , & ctor_context, None )
168
+ } ) ?;
169
+ if current_class_hash != ClassHash :: default ( ) {
170
+ return Err ( ConstructorEntryPointExecutionError :: new (
171
+ StateError :: UnavailableContractAddress ( deployed_contract_address) . into ( ) ,
172
+ & ctor_context,
173
+ None ,
174
+ ) ) ;
175
+ }
176
+
177
+ state
178
+ . set_class_hash_at ( deployed_contract_address, ctor_context. class_hash )
179
+ . map_err ( |error| {
180
+ ConstructorEntryPointExecutionError :: new ( error. into ( ) , & ctor_context, None )
181
+ } ) ?;
182
+
183
+ execute_constructor_entry_point (
184
+ state,
185
+ cheatnet_state,
186
+ context,
187
+ ctor_context,
188
+ constructor_calldata,
189
+ remaining_gas,
190
+ )
191
+ }
192
+
193
+ fn deploy (
194
+ syscall_handler_base : & mut SyscallHandlerBase ,
195
+ cheatnet_state : & mut CheatnetState ,
196
+ class_hash : ClassHash ,
197
+ contract_address_salt : ContractAddressSalt ,
198
+ constructor_calldata : Calldata ,
199
+ deploy_from_zero : bool ,
200
+ remaining_gas : & mut u64 ,
201
+ ) -> BaseSyscallResult < ( ContractAddress , CallInfo ) > {
202
+ syscall_handler_base
203
+ . increment_syscall_linear_factor_by ( & SyscallSelector :: Deploy , constructor_calldata. 0 . len ( ) ) ;
204
+ // let versioned_constants = &syscall_handler_base
205
+ // .context
206
+ // .tx_context
207
+ // .block_context
208
+ // .versioned_constants;
209
+ // TODO support for reject
210
+ // if should_reject_deploy(
211
+ // versioned_constants.disable_deploy_in_validation_mode,
212
+ // syscall_handler_base.context.execution_mode,
213
+ // ) {
214
+ // syscall_handler_base.reject_syscall_in_validate_mode("deploy")?;
215
+ // }
216
+
217
+ let deployer_address = syscall_handler_base. call . storage_address ;
218
+ let deployer_address_for_calculation = match deploy_from_zero {
219
+ true => ContractAddress :: default ( ) ,
220
+ false => deployer_address,
221
+ } ;
222
+ let deployed_contract_address = calculate_contract_address (
223
+ contract_address_salt,
224
+ class_hash,
225
+ & constructor_calldata,
226
+ deployer_address_for_calculation,
227
+ ) ?;
228
+
229
+ let ctor_context = ConstructorContext {
230
+ class_hash,
231
+ code_address : Some ( deployed_contract_address) ,
232
+ storage_address : deployed_contract_address,
233
+ caller_address : deployer_address,
234
+ } ;
235
+ let call_info = execute_deployment (
236
+ syscall_handler_base. state ,
237
+ cheatnet_state,
238
+ syscall_handler_base. context ,
239
+ ctor_context,
240
+ constructor_calldata,
241
+ remaining_gas,
242
+ ) ?;
243
+ Ok ( ( deployed_contract_address, call_info) )
244
+ }
245
+
90
246
impl CheatableNativeSyscallHandler < ' _ > {
91
247
// TODO consider modifying this so it doesn't use take
92
248
pub fn unrecoverable_error ( & mut self ) -> Option < SyscallExecutionError > {
@@ -378,13 +534,32 @@ impl StarknetSyscallHandler for &mut CheatableNativeSyscallHandler<'_> {
378
534
deploy_from_zero : bool ,
379
535
remaining_gas : & mut u64 ,
380
536
) -> SyscallResult < ( Felt , Vec < Felt > ) > {
381
- self . native_syscall_handler . deploy (
382
- class_hash,
383
- contract_address_salt,
384
- calldata,
537
+ // The cost of deploying a contract is the base cost plus the linear cost of the calldata
538
+ // len.
539
+ let total_gas_cost = self
540
+ . native_syscall_handler
541
+ . gas_costs ( )
542
+ . syscalls
543
+ . deploy
544
+ . get_syscall_cost ( u64_from_usize ( calldata. len ( ) ) ) ;
545
+
546
+ self . pre_execute_syscall ( remaining_gas, total_gas_cost, SyscallSelector :: Deploy ) ?;
547
+
548
+ let ( deployed_contract_address, call_info) = deploy (
549
+ & mut self . native_syscall_handler . base ,
550
+ & mut self . cheatnet_state ,
551
+ ClassHash ( class_hash) ,
552
+ ContractAddressSalt ( contract_address_salt) ,
553
+ Calldata ( Arc :: new ( calldata. to_vec ( ) ) ) ,
385
554
deploy_from_zero,
386
555
remaining_gas,
387
556
)
557
+ . map_err ( |err| self . handle_error ( remaining_gas, err) ) ?;
558
+
559
+ let constructor_retdata = call_info. execution . retdata . 0 [ ..] . to_vec ( ) ;
560
+ self . native_syscall_handler . base . inner_calls . push ( call_info) ;
561
+
562
+ Ok ( ( Felt :: from ( deployed_contract_address) , constructor_retdata) )
388
563
}
389
564
390
565
fn replace_class ( & mut self , class_hash : Felt , remaining_gas : & mut u64 ) -> SyscallResult < ( ) > {
0 commit comments