1use std::marker::PhantomData;
2
3use arbos::programs::types::EvmData;
4use wasmer::{FunctionEnvMut, Memory, MemoryView, Pages, StoreMut};
5
6use crate::{
7 config::{CompileConfig, StylusConfig},
8 error::Escape,
9 evm_api::EvmApi,
10 ink::Ink,
11 meter::{GasMeteredMachine, MachineMeter, MeteredMachine, HOSTIO_INK},
12};
13
14pub type WasmEnvMut<'a, E> = FunctionEnvMut<'a, WasmEnv<E>>;
15
16#[derive(Debug)]
21pub struct WasmEnv<E: EvmApi> {
22 pub args: Vec<u8>,
24 pub outs: Vec<u8>,
26 pub memory: Option<Memory>,
28 pub meter: Option<MeterData>,
30 pub evm_api: E,
32 pub evm_data: EvmData,
34 pub evm_return_data_len: u32,
36 pub compile: CompileConfig,
38 pub config: Option<StylusConfig>,
40 _phantom: PhantomData<E>,
41}
42
43impl<E: EvmApi> WasmEnv<E> {
44 pub fn new(
45 compile: CompileConfig,
46 config: Option<StylusConfig>,
47 evm_api: E,
48 evm_data: EvmData,
49 ) -> Self {
50 Self {
51 compile,
52 config,
53 evm_api,
54 evm_data,
55 args: vec![],
56 outs: vec![],
57 memory: None,
58 meter: None,
59 evm_return_data_len: 0,
60 _phantom: PhantomData,
61 }
62 }
63
64 pub fn start<'a>(
66 env: &'a mut WasmEnvMut<'_, E>,
67 ink: Ink,
68 ) -> Result<HostioInfo<'a, E>, Escape> {
69 let mut info = Self::program(env)?;
70 info.buy_ink(HOSTIO_INK.saturating_add(ink))?;
71 Ok(info)
72 }
73
74 pub fn program<'a>(env: &'a mut WasmEnvMut<'_, E>) -> Result<HostioInfo<'a, E>, Escape> {
76 let (env, store) = env.data_and_store_mut();
77 let memory = env.memory.clone().expect("WASM memory not initialized");
78 let mut info = HostioInfo {
79 env,
80 memory,
81 store,
82 start_ink: Ink(0),
83 };
84 if info.env.evm_data.tracing {
85 info.start_ink = info.ink_ready()?;
86 }
87 Ok(info)
88 }
89
90 pub fn meter_mut(&mut self) -> &mut MeterData {
91 self.meter.as_mut().expect("not metered")
92 }
93
94 pub fn meter(&self) -> &MeterData {
95 self.meter.as_ref().expect("not metered")
96 }
97}
98
99#[derive(Clone, Copy, Debug)]
104pub struct MeterData {
105 ink_left: u64,
106 ink_status: u32,
107}
108
109impl MeterData {
110 pub fn new() -> Self {
111 Self {
112 ink_left: 0,
113 ink_status: 0,
114 }
115 }
116
117 pub fn ink(&self) -> Ink {
118 Ink(self.ink_left)
119 }
120
121 pub fn status(&self) -> u32 {
122 self.ink_status
123 }
124
125 pub fn set_ink(&mut self, ink: Ink) {
126 self.ink_left = ink.0;
127 }
128
129 pub fn set_status(&mut self, status: u32) {
130 self.ink_status = status;
131 }
132}
133
134unsafe impl Send for MeterData {}
135
136pub struct HostioInfo<'a, E: EvmApi> {
141 pub env: &'a mut WasmEnv<E>,
142 pub memory: Memory,
143 pub store: StoreMut<'a>,
144 pub start_ink: Ink,
145}
146
147impl<E: EvmApi> HostioInfo<'_, E> {
148 pub fn config(&self) -> StylusConfig {
149 self.env.config.expect("no config")
150 }
151
152 pub fn pricing(&self) -> crate::config::PricingParams {
153 self.config().pricing
154 }
155
156 pub fn view(&self) -> MemoryView<'_> {
157 self.memory.view(&self.store)
158 }
159
160 pub fn memory_size(&self) -> Pages {
161 self.memory.ty(&self.store).minimum
162 }
163
164 pub fn read_fixed<const N: usize>(
165 &self,
166 ptr: u32,
167 ) -> Result<[u8; N], wasmer::MemoryAccessError> {
168 let mut data = [0u8; N];
169 self.view().read(ptr as u64, &mut data)?;
170 Ok(data)
171 }
172
173 pub fn read_slice(&self, ptr: u32, len: u32) -> Result<Vec<u8>, wasmer::MemoryAccessError> {
174 let mut data = vec![0u8; len as usize];
175 self.view().read(ptr as u64, &mut data)?;
176 Ok(data)
177 }
178
179 pub fn write_slice(&self, ptr: u32, data: &[u8]) -> Result<(), wasmer::MemoryAccessError> {
180 self.view().write(ptr as u64, data)
181 }
182
183 pub fn write_u32(&self, ptr: u32, value: u32) -> Result<(), wasmer::MemoryAccessError> {
184 self.view().write(ptr as u64, &value.to_le_bytes())
185 }
186}
187
188impl<E: EvmApi> MeteredMachine for HostioInfo<'_, E> {
189 fn ink_left(&self) -> MachineMeter {
190 let vm = self.env.meter();
191 match vm.status() {
192 0 => MachineMeter::Ready(vm.ink()),
193 _ => MachineMeter::Exhausted,
194 }
195 }
196
197 fn set_meter(&mut self, meter: MachineMeter) {
198 let vm = self.env.meter_mut();
199 vm.set_ink(meter.ink());
200 vm.set_status(meter.status());
201 }
202}
203
204impl<E: EvmApi> GasMeteredMachine for HostioInfo<'_, E> {
205 fn pricing(&self) -> crate::config::PricingParams {
206 self.config().pricing
207 }
208}
209
210impl<E: EvmApi> std::ops::Deref for HostioInfo<'_, E> {
211 type Target = WasmEnv<E>;
212 fn deref(&self) -> &Self::Target {
213 self.env
214 }
215}
216
217impl<E: EvmApi> std::ops::DerefMut for HostioInfo<'_, E> {
218 fn deref_mut(&mut self) -> &mut Self::Target {
219 self.env
220 }
221}