arb_stylus/
run.rs

1use arbos::programs::types::UserOutcome;
2
3use crate::{
4    config::StylusConfig,
5    error::StylusError,
6    evm_api::EvmApi,
7    ink::Ink,
8    meter::{DepthCheckedMachine, MachineMeter, MeteredMachine, STYLUS_ENTRY_POINT},
9    native::NativeInstance,
10};
11
12/// Trait for running Stylus WASM programs.
13pub trait RunProgram {
14    fn run_main(
15        &mut self,
16        args: &[u8],
17        config: StylusConfig,
18        ink: Ink,
19    ) -> Result<UserOutcome, StylusError>;
20}
21
22impl<E: EvmApi> RunProgram for NativeInstance<E> {
23    fn run_main(
24        &mut self,
25        args: &[u8],
26        config: StylusConfig,
27        ink: Ink,
28    ) -> Result<UserOutcome, StylusError> {
29        self.set_ink(ink);
30        self.set_stack(config.max_depth);
31
32        {
33            let store = &mut self.store;
34            let env = self.env.as_mut(store);
35            env.args = args.to_owned();
36            env.outs.clear();
37            env.config = Some(config);
38
39            if env.evm_data.tracing {
40                let args_len = args.len() as u32;
41                env.evm_api.capture_hostio(
42                    STYLUS_ENTRY_POINT,
43                    &args_len.to_be_bytes(),
44                    &[],
45                    ink,
46                    ink,
47                );
48            }
49        }
50
51        self.sync_meter_to_globals();
52
53        let status = {
54            let store = &mut self.store;
55            let exports = &self.instance.exports;
56            let main = exports
57                .get_typed_function::<u32, u32>(store, STYLUS_ENTRY_POINT)
58                .map_err(|e| StylusError::MissingGlobal(e.to_string()))?;
59            match main.call(store, args.len() as u32) {
60                Ok(status) => status,
61                Err(outcome) => {
62                    self.sync_meter_from_globals();
63
64                    if self.stack_left() == 0 {
65                        return Ok(UserOutcome::OutOfStack);
66                    }
67                    if self.ink_left() == MachineMeter::Exhausted {
68                        return Ok(UserOutcome::OutOfInk);
69                    }
70
71                    let ink_left_now = match self.ink_left() {
72                        MachineMeter::Ready(i) => i.0,
73                        MachineMeter::Exhausted => 0,
74                    };
75                    if std::env::var("STYLUS_HOSTIO_TRACE").is_ok() {
76                        let consumed = ink.0.saturating_sub(ink_left_now);
77                        eprintln!(
78                            "[hostio] wasm_trap ink_start={} ink_left={ink_left_now} ink_consumed_total={consumed} stack_left={}",
79                            ink.0,
80                            self.stack_left(),
81                        );
82                    }
83                    tracing::warn!(target: "stylus",
84                        ink = ?self.ink_left(), stack = self.stack_left(),
85                        "WASM trap");
86                    let escape: StylusError = match outcome.downcast() {
87                        Ok(escape) => escape,
88                        Err(error) => {
89                            tracing::warn!(target: "stylus", err = %error, "WASM trap detail");
90                            return Ok(UserOutcome::Failure);
91                        }
92                    };
93                    match escape {
94                        StylusError::OutOfInk => return Ok(UserOutcome::OutOfInk),
95                        StylusError::Exit(status) => status,
96                        _ => return Ok(UserOutcome::Failure),
97                    }
98                }
99            }
100        };
101
102        self.sync_meter_from_globals();
103
104        if std::env::var("STYLUS_HOSTIO_TRACE").is_ok() {
105            let ink_left = match self.ink_left() {
106                MachineMeter::Ready(i) => i.0,
107                MachineMeter::Exhausted => 0,
108            };
109            let consumed = ink.0.saturating_sub(ink_left);
110            eprintln!(
111                "[hostio] user_returned status={status} ink_start={} ink_left={ink_left} ink_consumed_total={consumed}",
112                ink.0,
113            );
114        }
115
116        let env = self.env_mut();
117        if env.evm_data.tracing {
118            env.evm_api
119                .capture_hostio("user_returned", &[], &status.to_be_bytes(), ink, ink);
120        }
121
122        Ok(match status {
123            0 => UserOutcome::Success,
124            _ => UserOutcome::Revert,
125        })
126    }
127}