arb_stylus/
run.rs

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
13/// Trait for running Stylus WASM programs.
14pub 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}