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                    tracing::warn!(target: "stylus",
61                        ink = ?self.ink_left(), stack = self.stack_left(),
62                        "WASM trap");
63                    let escape: Escape = match outcome.downcast() {
64                        Ok(escape) => escape,
65                        Err(error) => {
66                            tracing::warn!(target: "stylus", err = %error, "WASM trap detail");
67                            return Ok(UserOutcome::Failure);
68                        }
69                    };
70                    match escape {
71                        Escape::OutOfInk => return Ok(UserOutcome::OutOfInk),
72                        Escape::Memory(_) | Escape::Internal(_) | Escape::Logical(_) => {
73                            return Ok(UserOutcome::Failure);
74                        }
75                        Escape::Exit(status) => status,
76                    }
77                }
78            }
79        };
80
81        self.sync_meter_from_globals();
82
83        let env = self.env_mut();
84        if env.evm_data.tracing {
85            env.evm_api
86                .capture_hostio("user_returned", &[], &status.to_be_bytes(), ink, ink);
87        }
88
89        Ok(match status {
90            0 => UserOutcome::Success,
91            _ => UserOutcome::Revert,
92        })
93    }
94}