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
12pub 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}