1use arbos::programs::types::UserOutcome;
2use eyre::Result;
3
4use crate::{
5 config::StylusConfig,
6 error::Escape,
7 evm_api::EvmApi,
8 ink::Ink,
9 meter::{DepthCheckedMachine, MachineMeter, MeteredMachine, STYLUS_ENTRY_POINT},
10 native::NativeInstance,
11};
12
13pub trait RunProgram {
15 fn run_main(&mut self, args: &[u8], config: StylusConfig, ink: Ink) -> Result<UserOutcome>;
16}
17
18impl<E: EvmApi> RunProgram for NativeInstance<E> {
19 fn run_main(&mut self, args: &[u8], config: StylusConfig, ink: Ink) -> Result<UserOutcome> {
20 self.set_ink(ink);
21 self.set_stack(config.max_depth);
22
23 {
24 let store = &mut self.store;
25 let env = self.env.as_mut(store);
26 env.args = args.to_owned();
27 env.outs.clear();
28 env.config = Some(config);
29
30 if env.evm_data.tracing {
31 let args_len = args.len() as u32;
32 env.evm_api.capture_hostio(
33 STYLUS_ENTRY_POINT,
34 &args_len.to_be_bytes(),
35 &[],
36 ink,
37 ink,
38 );
39 }
40 }
41
42 self.sync_meter_to_globals();
43
44 let status = {
45 let store = &mut self.store;
46 let exports = &self.instance.exports;
47 let main = exports.get_typed_function::<u32, u32>(store, STYLUS_ENTRY_POINT)?;
48 match main.call(store, args.len() as u32) {
49 Ok(status) => status,
50 Err(outcome) => {
51 self.sync_meter_from_globals();
52
53 if self.stack_left() == 0 {
54 return Ok(UserOutcome::OutOfStack);
55 }
56 if self.ink_left() == MachineMeter::Exhausted {
57 return Ok(UserOutcome::OutOfInk);
58 }
59
60 let escape: Escape = match outcome.downcast() {
61 Ok(escape) => escape,
62 Err(_error) => {
63 return Ok(UserOutcome::Failure);
64 }
65 };
66 match escape {
67 Escape::OutOfInk => return Ok(UserOutcome::OutOfInk),
68 Escape::Memory(_) | Escape::Internal(_) | Escape::Logical(_) => {
69 return Ok(UserOutcome::Failure);
70 }
71 Escape::Exit(status) => status,
72 }
73 }
74 }
75 };
76
77 self.sync_meter_from_globals();
78
79 let env = self.env_mut();
80 if env.evm_data.tracing {
81 env.evm_api
82 .capture_hostio("user_returned", &[], &status.to_be_bytes(), ink, ink);
83 }
84
85 Ok(match status {
86 0 => UserOutcome::Success,
87 _ => UserOutcome::Revert,
88 })
89 }
90}