1use crate::{ExecError, ExecResult, Execution, Instance, Module, ModuleError};
33
34pub const GAS_MAX: i64 = i64::MAX;
36
37pub fn run(program: &[u8]) {
51 counter_start_at_0(program);
52 counter_start_at_7(program);
53 counter_multiple_calls(program);
54 panic_works(program);
55 exit_works(program);
56 run_out_of_gas_works(program);
57 gas_consumption_works(program);
58 memory_reset_on_instantiate(program);
59 memory_persistent(program);
60 counter_in_subcall(program);
61 from_storage_key_not_found(program);
62}
63
64pub enum RunResult {
66 Ok(Instance),
68 Exit,
70 Err(ExecError),
72}
73
74pub fn run_loop(
79 mut execution: Execution,
80 gas_left: &mut i64,
81 mut handler: impl FnMut(&mut Execution, &[u8], u64, u64, u64, u64, u64, u64) -> Result<u64, ()>,
82) -> RunResult {
83 let mut a0 = 0u64;
84 loop {
85 match execution.run(*gas_left, a0) {
86 ExecResult::Finished { instance, gas_left: g } => {
87 *gas_left = g;
88 return RunResult::Ok(instance);
89 },
90 ExecResult::Syscall {
91 execution: e,
92 gas_left: g,
93 syscall_symbol,
94 a0: sa0,
95 a1,
96 a2,
97 a3,
98 a4,
99 a5,
100 } => {
101 execution = e;
102 *gas_left = g;
103 match handler(&mut execution, syscall_symbol.as_ref(), sa0, a1, a2, a3, a4, a5) {
104 Ok(result) => a0 = result,
105 Err(()) => return RunResult::Exit,
106 }
107 },
108 ExecResult::Error { instance: _, error: ExecError::OutOfGas } => {
109 *gas_left = 0;
110 return RunResult::Err(ExecError::OutOfGas);
111 },
112 ExecResult::Error { instance: _, error } => return RunResult::Err(error),
113 }
114 }
115}
116
117pub fn make_handler<'a>(
122 counter: &'a mut u64,
123) -> impl FnMut(&mut Execution, &[u8], u64, u64, u64, u64, u64, u64) -> Result<u64, ()> + 'a {
124 move |execution, syscall_symbol, a0, _a1, _a2, _a3, _a4, _a5| match syscall_symbol {
125 b"read_counter" => {
126 let buf = counter.to_le_bytes();
127 execution.write_memory(a0 as u32, buf.as_ref()).unwrap();
128 Ok(1)
129 },
130 b"increment_counter" => {
131 let mut buf = [0u8; 8];
132 execution.read_memory(a0 as u32, buf.as_mut()).unwrap();
133 *counter += u64::from_le_bytes(buf);
134 Ok(2u64 << 56)
135 },
136 b"exit" => Err(()),
137 _ => panic!("unknown syscall: {:?}", syscall_symbol),
138 }
139}
140
141fn counter_start_at_0(program: &[u8]) {
143 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
144 let execution = instance.prepare(b"counter").unwrap();
145 let mut gas_left = GAS_MAX;
146 let mut counter: u64 = 0;
147 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
148 assert!(matches!(result, RunResult::Ok(_)));
149 assert_eq!(counter, 8);
150}
151
152fn counter_start_at_7(program: &[u8]) {
154 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
155 let execution = instance.prepare(b"counter").unwrap();
156 let mut gas_left = GAS_MAX;
157 let mut counter: u64 = 7;
158 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
159 assert!(matches!(result, RunResult::Ok(_)));
160 assert_eq!(counter, 15);
161}
162
163fn counter_multiple_calls(program: &[u8]) {
165 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
166 let execution = instance.prepare(b"counter").unwrap();
167 let mut gas_left = GAS_MAX;
168 let mut counter: u64 = 7;
169
170 let instance = match run_loop(execution, &mut gas_left, make_handler(&mut counter)) {
171 RunResult::Ok(instance) => instance,
172 _ => panic!("expected Ok"),
173 };
174 assert_eq!(counter, 15);
175
176 let execution = instance.prepare(b"counter").unwrap();
177 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
178 assert!(matches!(result, RunResult::Ok(_)));
179 assert_eq!(counter, 23);
180}
181
182fn panic_works(program: &[u8]) {
184 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
185 let execution = instance.prepare(b"do_panic").unwrap();
186 let mut gas_left = GAS_MAX;
187 let mut counter: u64 = 0;
188 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
189 assert!(matches!(result, RunResult::Err(ExecError::Trap)));
190 assert_eq!(counter, 0);
191}
192
193fn exit_works(program: &[u8]) {
195 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
196 let execution = instance.prepare(b"do_exit").unwrap();
197 let mut gas_left = GAS_MAX;
198 let mut counter: u64 = 0;
199 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
200 assert!(matches!(result, RunResult::Exit));
201 assert_eq!(counter, 0);
202}
203
204fn run_out_of_gas_works(program: &[u8]) {
206 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
207 let execution = instance.prepare(b"increment_forever").unwrap();
208 let mut gas_left: i64 = 100_000;
209 let mut counter: u64 = 0;
210 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
211 assert!(matches!(result, RunResult::Err(ExecError::OutOfGas)));
212 assert_eq!(counter, 793);
213 assert_eq!(gas_left, 0);
214}
215
216fn gas_consumption_works(program: &[u8]) {
218 let gas_limit_0 = GAS_MAX;
219 let gas_limit_1 = gas_limit_0 / 2;
220
221 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
222 let execution = instance.prepare(b"counter").unwrap();
223 let mut gas_left = gas_limit_0;
224 let mut counter: u64 = 0;
225 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
226 assert!(matches!(result, RunResult::Ok(_)));
227 let gas_consumed = gas_limit_0 - gas_left;
228
229 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
230 let execution = instance.prepare(b"counter").unwrap();
231 let mut gas_left = gas_limit_1;
232 let mut counter: u64 = 0;
233 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
234 assert!(matches!(result, RunResult::Ok(_)));
235 assert_eq!(gas_consumed, gas_limit_1 - gas_left);
236}
237
238fn memory_reset_on_instantiate(program: &[u8]) {
240 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
241 let execution = instance.prepare(b"offset").unwrap();
242 let mut gas_left = GAS_MAX;
243 let mut counter: u64 = 0;
244 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
245 assert!(matches!(result, RunResult::Ok(_)));
246 assert_eq!(counter, 3);
247
248 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
249 let execution = instance.prepare(b"offset").unwrap();
250 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
251 assert!(matches!(result, RunResult::Ok(_)));
252 assert_eq!(counter, 6);
253}
254
255fn memory_persistent(program: &[u8]) {
257 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
258 let execution = instance.prepare(b"offset").unwrap();
259 let mut gas_left = GAS_MAX;
260 let mut counter: u64 = 0;
261
262 let instance = match run_loop(execution, &mut gas_left, make_handler(&mut counter)) {
263 RunResult::Ok(instance) => instance,
264 _ => panic!("expected Ok"),
265 };
266 assert_eq!(counter, 3);
267
268 let execution = instance.prepare(b"offset").unwrap();
269 let result = run_loop(execution, &mut gas_left, make_handler(&mut counter));
270 assert!(matches!(result, RunResult::Ok(_)));
271 assert_eq!(counter, 7);
272}
273
274fn counter_in_subcall(program: &[u8]) {
276 let instance = Module::from_bytes(program, None).unwrap().0.instantiate().unwrap();
277 let execution = instance.prepare(b"do_subcall").unwrap();
278 let mut gas_left = GAS_MAX;
279 let mut counter: u64 = 0;
280 let program = program.to_vec();
281 let result =
282 run_loop(execution, &mut gas_left, |execution, syscall_symbol, a0, a1, a2, a3, a4, a5| {
283 match syscall_symbol {
284 b"read_counter" | b"increment_counter" | b"exit" => {
285 make_handler(&mut counter)(execution, syscall_symbol, a0, a1, a2, a3, a4, a5)
286 },
287 b"subcall" => {
289 let sub_instance = Module::from_bytes(program.as_ref(), None)
290 .unwrap()
291 .0
292 .instantiate()
293 .unwrap();
294 let sub_execution = sub_instance.prepare(b"counter").unwrap();
295 let mut sub_gas = GAS_MAX;
296 let mut sub_counter: u64 = 0;
297 let result =
298 run_loop(sub_execution, &mut sub_gas, make_handler(&mut sub_counter));
299 assert!(matches!(result, RunResult::Ok(_)));
300 assert_eq!(sub_counter, 8);
301 Ok(0)
302 },
303 _ => panic!("unknown syscall: {:?}", syscall_symbol),
304 }
305 });
306 assert!(matches!(result, RunResult::Ok(_)));
307 assert_eq!(counter, 0);
309}
310
311fn from_storage_key_not_found(_program: &[u8]) {
313 let storage_key = b"::missing::";
314 assert!(matches!(Module::from_storage_key(storage_key, b""), Err(ModuleError::NotFound)));
315}