@@ -3,6 +3,7 @@ trait IOrchestrator<TContractState> {
33 fn pop_front (ref self : TContractState ) -> felt252 ;
44 fn get_index (ref self : TContractState ) -> felt252 ;
55 fn set_index (ref self : TContractState , index : felt252 );
6+ fn should_fail_invalid_scenario_panic_message (ref self : TContractState ) -> felt252 ;
67 fn should_fail_undeployed_panic_message (ref self : TContractState ) -> felt252 ;
78 fn should_fail_call_no_entrypoint_panic_message (ref self : TContractState ) -> felt252 ;
89 fn should_fail_libcall_no_entrypoint_panic_message (ref self : TContractState ) -> felt252 ;
@@ -20,25 +21,51 @@ mod FuzzRevertContract {
2021 use starknet :: info :: SyscallResultTrait ;
2122
2223 // Scenarios.
23- // The RETURN scenario *must* be zero, as the zero value also indicates end of scenario stream
24- // (when cairo0 fuzz contracts get the None value from the orchestrator).
25- // TODO(Dori): Convert to enum.
26- const SCENARIO_RETURN : felt252 = 0 ;
27- const SCENARIO_CALL : felt252 = 1 ;
28- const SCENARIO_LIBRARY_CALL : felt252 = 2 ;
29- const SCENARIO_WRITE : felt252 = 3 ;
30- const SCENARIO_REPLACE_CLASS : felt252 = 4 ;
31- const SCENARIO_DEPLOY : felt252 = 5 ;
32- const SCENARIO_PANIC : felt252 = 6 ;
33- const SCENARIO_INCREMENT_COUNTER : felt252 = 7 ;
34- const SCENARIO_SEND_MESSAGE : felt252 = 8 ;
35- const SCENARIO_DEPLOY_NON_EXISTING : felt252 = 9 ;
36- const SCENARIO_LIBRARY_CALL_NON_EXISTING : felt252 = 10 ;
37- const SCENARIO_SHA256 : felt252 = 11 ;
38- const SCENARIO_KECCAK : felt252 = 12 ;
39- const SCENARIO_CALL_UNDEPLOYED : felt252 = 13 ;
40- const SCENARIO_CALL_NON_EXISTING_ENTRY_POINT : felt252 = 14 ;
41- const SCENARIO_LIBRARY_CALL_NON_EXISTING_ENTRY_POINT : felt252 = 15 ;
24+ enum Scenario {
25+ Return ,
26+ Call ,
27+ LibraryCall ,
28+ Write ,
29+ ReplaceClass ,
30+ Deploy ,
31+ Panic ,
32+ IncrementCounter ,
33+ SendMessage ,
34+ DeployNonExisting ,
35+ LibraryCallNonExisting ,
36+ Sha256 ,
37+ Keccak ,
38+ CallUndeployed ,
39+ CallNonExistingEntryPoint ,
40+ LibraryCallNonExistingEntryPoint ,
41+ }
42+
43+ impl FeltTryIntoScenario of TryInto <felt252 , Scenario > {
44+ fn try_into (self : felt252 ) -> Option <Scenario > {
45+ match self {
46+ // The RETURN scenario *must* be zero, as the zero value also indicates end of
47+ // scenario stream (when cairo0 fuzz contracts get the None value from the
48+ // orchestrator).
49+ 0 => Some (Scenario :: Return ),
50+ 1 => Some (Scenario :: Call ),
51+ 2 => Some (Scenario :: LibraryCall ),
52+ 3 => Some (Scenario :: Write ),
53+ 4 => Some (Scenario :: ReplaceClass ),
54+ 5 => Some (Scenario :: Deploy ),
55+ 6 => Some (Scenario :: Panic ),
56+ 7 => Some (Scenario :: IncrementCounter ),
57+ 8 => Some (Scenario :: SendMessage ),
58+ 9 => Some (Scenario :: DeployNonExisting ),
59+ 10 => Some (Scenario :: LibraryCallNonExisting ),
60+ 11 => Some (Scenario :: Sha256 ),
61+ 12 => Some (Scenario :: Keccak ),
62+ 13 => Some (Scenario :: CallUndeployed ),
63+ 14 => Some (Scenario :: CallNonExistingEntryPoint ),
64+ 15 => Some (Scenario :: LibraryCallNonExistingEntryPoint ),
65+ _ => None ,
66+ }
67+ }
68+ }
4269
4370 #[storage]
4471 struct Storage {
@@ -122,128 +149,116 @@ mod FuzzRevertContract {
122149 let orchestrator = self . orchestrator ();
123150
124151 // Get next scenario; None means done.
125- let scenario = orchestrator . pop_front ();
126-
127- if scenario == SCENARIO_RETURN {
128- return ;
129- }
130-
131- if scenario == SCENARIO_CALL {
132- let address : ContractAddress = orchestrator . pop_front (). try_into (). unwrap ();
133- let selector = orchestrator . pop_front ();
134- let should_unwrap : bool = orchestrator . pop_front () != 0 ;
135- let result = syscalls :: call_contract_syscall (address , selector , array! []. span ());
136- self . handle_error_catch (result , should_unwrap );
137- }
138-
139- if scenario == SCENARIO_LIBRARY_CALL {
140- let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
141- let selector = orchestrator . pop_front ();
142- let should_unwrap : bool = orchestrator . pop_front () != 0 ;
143- let result = syscalls :: library_call_syscall (class_hash , selector , array! []. span ());
144- self . handle_error_catch (result , should_unwrap );
145- }
146-
147- if scenario == SCENARIO_WRITE {
148- let key : StorageAddress = orchestrator . pop_front (). try_into (). unwrap ();
149- let value = orchestrator . pop_front ();
150- let address_domain = 0 ;
151- syscalls :: storage_write_syscall (address_domain , key , value ). unwrap_syscall ();
152- }
153-
154- if scenario == SCENARIO_REPLACE_CLASS {
155- let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
156- syscalls :: replace_class_syscall (class_hash ). unwrap_syscall ();
157- }
158-
159- if scenario == SCENARIO_DEPLOY {
160- // The class hash is assumed to be a fuzz test class hash.
161- // Deploy it with a non-trivial orchestrator address.
162- let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
163- let salt = orchestrator . pop_front ();
164- let deploy_from_zero : bool = true ;
165- let ctor_calldata = array! [self . orchestrator_address. read (). into ()];
166- // Deploy errors cannot be caught. Just unwrap the syscall.
167- syscalls :: deploy_syscall (class_hash , salt , ctor_calldata . span (), deploy_from_zero )
168- . unwrap_syscall ();
169- }
170-
171- if scenario == SCENARIO_PANIC {
172- // Panic message is part of the scenario data.
173- let message = orchestrator . pop_front ();
174- panic (array! [orchestrator . get_index (), message ]);
175- }
176-
177- if scenario == SCENARIO_INCREMENT_COUNTER {
178- let value = self . counter. read ();
179- self . counter. write (value + 1 );
180- }
181-
182- if scenario == SCENARIO_SEND_MESSAGE {
183- let payload = array! [orchestrator . pop_front ()];
184- syscalls :: send_message_to_l1_syscall (0xadd1 , payload . span ()). unwrap_syscall ();
185- }
186-
187- if scenario == SCENARIO_DEPLOY_NON_EXISTING {
188- let class_hash : ClassHash = 0xde6107000c1 . try_into (). unwrap ();
189- let salt = 0 ;
190- let deploy_from_zero : bool = true ;
191- // Unrecoverable error (we do not prove class hashes do not exist), no option to catch
192- // error.
193- syscalls :: deploy_syscall (class_hash , salt , array! []. span (), deploy_from_zero )
194- . unwrap_syscall ();
195- }
196-
197- if scenario == SCENARIO_LIBRARY_CALL_NON_EXISTING {
198- let class_hash : ClassHash = 0x11bca11000c1 . try_into (). unwrap ();
199- // Unrecoverable error (we do not prove class hashes do not exist), no option to catch
200- // error.
201- syscalls :: library_call_syscall (class_hash , 0 , array! []. span ()). unwrap_syscall ();
202- }
203-
204- if scenario == SCENARIO_SHA256 {
205- let preimage : u32 = orchestrator . pop_front (). try_into (). unwrap ();
206- compute_sha256_u32_array (array! [preimage ], 0 , 0 );
207- }
208-
209- if scenario == SCENARIO_KECCAK {
210- let preimage : u128 = orchestrator . pop_front (). try_into (). unwrap ();
211- let mut input : Array :: <u256 > = Default :: default ();
212- input . append (u256 { low : preimage , high : preimage });
213- keccak :: keccak_u256s_le_inputs (input . span ());
214- }
215-
216- if scenario == SCENARIO_CALL_UNDEPLOYED {
217- let address : ContractAddress = orchestrator . pop_front (). try_into (). unwrap ();
218- let selector = orchestrator . pop_front ();
219- let _should_unwrap = orchestrator . pop_front ();
220- // Calling an undeployed contract should be an uncatchable fail.
221- syscalls :: call_contract_syscall (address , selector , array! []. span ()). unwrap_err ();
222- panic_with_felt252 (orchestrator . should_fail_undeployed_panic_message ());
223- }
224-
225- if scenario == SCENARIO_CALL_NON_EXISTING_ENTRY_POINT {
226- let address : ContractAddress = orchestrator . pop_front (). try_into (). unwrap ();
227- let selector = orchestrator . pop_front ();
228- let should_unwrap = orchestrator . pop_front ();
229- self
230- . handle_syscall_immediate_failure (
231- syscalls :: call_contract_syscall (address , selector , array! []. span ()),
232- orchestrator . should_fail_call_no_entrypoint_panic_message (),
233- should_unwrap != 0
234- );
235- }
152+ let scenario : Scenario = match orchestrator . pop_front (). try_into () {
153+ Some (scenario ) => scenario ,
154+ None => panic_with_felt252 (orchestrator . should_fail_invalid_scenario_panic_message ()),
155+ };
236156
237- if scenario == SCENARIO_LIBRARY_CALL_NON_EXISTING_ENTRY_POINT {
238- let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
239- let selector = orchestrator . pop_front ();
240- let should_unwrap = orchestrator . pop_front ();
241- self
242- . handle_syscall_immediate_failure (
243- syscalls :: library_call_syscall (class_hash , selector , array! []. span ()),
244- orchestrator . should_fail_libcall_no_entrypoint_panic_message (),
245- should_unwrap != 0
246- );
157+ match scenario {
158+ Scenario :: Return => { return ; },
159+ Scenario :: Call => {
160+ let address : ContractAddress = orchestrator . pop_front (). try_into (). unwrap ();
161+ let selector = orchestrator . pop_front ();
162+ let should_unwrap : bool = orchestrator . pop_front () != 0 ;
163+ let result = syscalls :: call_contract_syscall (address , selector , array! []. span ());
164+ self . handle_error_catch (result , should_unwrap );
165+ },
166+ Scenario :: LibraryCall => {
167+ let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
168+ let selector = orchestrator . pop_front ();
169+ let should_unwrap : bool = orchestrator . pop_front () != 0 ;
170+ let result = syscalls :: library_call_syscall (class_hash , selector , array! []. span ());
171+ self . handle_error_catch (result , should_unwrap );
172+ },
173+ Scenario :: Write => {
174+ let key : StorageAddress = orchestrator . pop_front (). try_into (). unwrap ();
175+ let value = orchestrator . pop_front ();
176+ let address_domain = 0 ;
177+ syscalls :: storage_write_syscall (address_domain , key , value ). unwrap_syscall ();
178+ },
179+ Scenario :: ReplaceClass => {
180+ let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
181+ syscalls :: replace_class_syscall (class_hash ). unwrap_syscall ();
182+ },
183+ Scenario :: Deploy => {
184+ // The class hash is assumed to be a fuzz test class hash.
185+ // Deploy it with a non-trivial orchestrator address.
186+ let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
187+ let salt = orchestrator . pop_front ();
188+ let deploy_from_zero : bool = true ;
189+ let ctor_calldata = array! [self . orchestrator_address. read (). into ()];
190+ // Deploy errors cannot be caught. Just unwrap the syscall.
191+ syscalls :: deploy_syscall (class_hash , salt , ctor_calldata . span (), deploy_from_zero )
192+ . unwrap_syscall ();
193+ },
194+ Scenario :: Panic => {
195+ // Panic message is part of the scenario data.
196+ let message = orchestrator . pop_front ();
197+ panic (array! [orchestrator . get_index (), message ]);
198+ },
199+ Scenario :: IncrementCounter => {
200+ let value = self . counter. read ();
201+ self . counter. write (value + 1 );
202+ },
203+ Scenario :: SendMessage => {
204+ let payload = array! [orchestrator . pop_front ()];
205+ syscalls :: send_message_to_l1_syscall (0xadd1 , payload . span ()). unwrap_syscall ();
206+ },
207+ Scenario :: DeployNonExisting => {
208+ let class_hash : ClassHash = 0xde6107000c1 . try_into (). unwrap ();
209+ let salt = 0 ;
210+ let deploy_from_zero : bool = true ;
211+ // Unrecoverable error (we do not prove class hashes do not exist), no option to
212+ // catch error.
213+ syscalls :: deploy_syscall (class_hash , salt , array! []. span (), deploy_from_zero )
214+ . unwrap_syscall ();
215+ },
216+ Scenario :: LibraryCallNonExisting => {
217+ let class_hash : ClassHash = 0x11bca11000c1 . try_into (). unwrap ();
218+ // Unrecoverable error (we do not prove class hashes do not exist), no option to
219+ // catch error.
220+ syscalls :: library_call_syscall (class_hash , 0 , array! []. span ()). unwrap_syscall ();
221+ },
222+ Scenario :: Sha256 => {
223+ let preimage : u32 = orchestrator . pop_front (). try_into (). unwrap ();
224+ compute_sha256_u32_array (array! [preimage ], 0 , 0 );
225+ },
226+ Scenario :: Keccak => {
227+ let preimage : u128 = orchestrator . pop_front (). try_into (). unwrap ();
228+ let mut input : Array :: <u256 > = Default :: default ();
229+ input . append (u256 { low : preimage , high : preimage });
230+ keccak :: keccak_u256s_le_inputs (input . span ());
231+ },
232+ Scenario :: CallUndeployed => {
233+ let address : ContractAddress = orchestrator . pop_front (). try_into (). unwrap ();
234+ let selector = orchestrator . pop_front ();
235+ let _should_unwrap = orchestrator . pop_front ();
236+ // Calling an undeployed contract should be an uncatchable fail.
237+ syscalls :: call_contract_syscall (address , selector , array! []. span ()). unwrap_err ();
238+ panic_with_felt252 (orchestrator . should_fail_undeployed_panic_message ());
239+ },
240+ Scenario :: CallNonExistingEntryPoint => {
241+ let address : ContractAddress = orchestrator . pop_front (). try_into (). unwrap ();
242+ let selector = orchestrator . pop_front ();
243+ let should_unwrap = orchestrator . pop_front ();
244+ self
245+ . handle_syscall_immediate_failure (
246+ syscalls :: call_contract_syscall (address , selector , array! []. span ()),
247+ orchestrator . should_fail_call_no_entrypoint_panic_message (),
248+ should_unwrap != 0
249+ );
250+ },
251+ Scenario :: LibraryCallNonExistingEntryPoint => {
252+ let class_hash : ClassHash = orchestrator . pop_front (). try_into (). unwrap ();
253+ let selector = orchestrator . pop_front ();
254+ let should_unwrap = orchestrator . pop_front ();
255+ self
256+ . handle_syscall_immediate_failure (
257+ syscalls :: library_call_syscall (class_hash , selector , array! []. span ()),
258+ orchestrator . should_fail_libcall_no_entrypoint_panic_message (),
259+ should_unwrap != 0
260+ );
261+ },
247262 }
248263
249264 // Unless explicitly stated otherwise, the next operation should be in the current call
0 commit comments