casper_executor_wasm_interface/
lib.rs1pub mod executor;
2
3use bytes::Bytes;
4use executor::ExecuteError;
5use thiserror::Error;
6
7use casper_executor_wasm_common::{
8 error::{CallError, TrapCode, CALLEE_SUCCEEDED},
9 flags::ReturnFlags,
10};
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
20pub struct InterfaceVersion(u32);
21
22impl From<u32> for InterfaceVersion {
23 fn from(value: u32) -> Self {
24 InterfaceVersion(value)
25 }
26}
27
28pub type HostResult = Result<(), CallError>;
29
30#[must_use]
32pub fn u32_from_host_result(result: HostResult) -> u32 {
33 match result {
34 Ok(()) => CALLEE_SUCCEEDED,
35 Err(host_error) => host_error.into_u32(),
36 }
37}
38
39#[derive(Debug, Error)]
41pub enum Resolver {
42 #[error("export {name} not found.")]
43 Export { name: String },
44 #[error("function pointer {index} not found.")]
46 Table { index: u32 },
47}
48
49#[derive(Error, Debug)]
50pub enum ExportError {
51 #[error("incompatible type")]
54 IncompatibleType,
55 #[error("missing export {0}")]
57 Missing(String),
58}
59
60#[derive(Error, Debug)]
61#[non_exhaustive]
62pub enum MemoryError {
63 #[error("memory access out of bounds")]
65 HeapOutOfBounds,
66 #[error("address calculation overflow")]
68 Overflow,
69 #[error("string is not valid utf-8")]
71 NonUtf8String,
72}
73
74#[derive(Error, Debug)]
75pub enum InternalHostError {
77 #[error("type conversion failure")]
78 TypeConversion,
79 #[error("contract already exists")]
80 ContractAlreadyExists,
81 #[error("tracking copy error")]
82 TrackingCopy,
83 #[error("failed building execution request")]
84 ExecuteRequestBuildFailure,
85 #[error("unexpected entity kind")]
86 UnexpectedEntityKind,
87 #[error("failed reading total balance")]
88 TotalBalanceReadFailure,
89 #[error("total balance exceeded u64::MAX")]
90 TotalBalanceOverflow,
91 #[error("remaining gas exceeded the gas limit")]
92 RemainingGasExceedsGasLimit,
93 #[error("account not found under key")]
94 AccountRecordNotFound,
95 #[error("message did not have a checksum")]
96 MessageChecksumMissing,
97}
98
99#[derive(Debug, Error)]
103pub enum VMError {
104 #[error("Return 0x{flags:?} {data:?}")]
105 Return {
106 flags: ReturnFlags,
107 data: Option<Bytes>,
108 },
109 #[error("export: {0}")]
110 Export(ExportError),
111 #[error("Out of gas")]
112 OutOfGas,
113 #[error("Trap: {0}")]
118 Trap(TrapCode),
119 #[error("Internal host error")]
120 Internal(#[from] InternalHostError),
121 #[error("Execute error: {0}")]
122 Execute(#[from] ExecuteError),
123}
124
125impl VMError {
126 pub fn into_output_data(self) -> Option<Bytes> {
128 match self {
129 VMError::Return { data, .. } => data,
130 _ => None,
131 }
132 }
133}
134
135pub type VMResult<T> = Result<T, VMError>;
137
138#[derive(Clone, Debug)]
140pub struct Config {
141 gas_limit: u64,
142 memory_limit: u32,
143}
144
145impl Config {
146 #[must_use]
147 pub fn gas_limit(&self) -> u64 {
148 self.gas_limit
149 }
150
151 #[must_use]
152 pub fn memory_limit(&self) -> u32 {
153 self.memory_limit
154 }
155}
156
157#[derive(Clone, Debug, Default)]
159pub struct ConfigBuilder {
160 gas_limit: Option<u64>,
161 memory_limit: Option<u32>,
163}
164
165impl ConfigBuilder {
166 #[must_use]
168 pub fn new() -> Self {
169 Self::default()
170 }
171
172 #[must_use]
174 pub fn with_gas_limit(mut self, gas_limit: u64) -> Self {
175 self.gas_limit = Some(gas_limit);
176 self
177 }
178
179 #[must_use]
181 pub fn with_memory_limit(mut self, memory_limit: u32) -> Self {
182 self.memory_limit = Some(memory_limit);
183 self
184 }
185
186 #[must_use]
188 pub fn build(self) -> Config {
189 let gas_limit = self.gas_limit.expect("Required field missing: gas_limit");
190 let memory_limit = self
191 .memory_limit
192 .expect("Required field missing: memory_limit");
193 Config {
194 gas_limit,
195 memory_limit,
196 }
197 }
198}
199
200#[derive(Debug, Copy, Clone, PartialEq, Eq)]
201pub enum MeteringPoints {
202 Remaining(u64),
203 Exhausted,
204}
205
206impl MeteringPoints {
207 pub fn try_into_remaining(self) -> Result<u64, Self> {
208 if let Self::Remaining(v) = self {
209 Ok(v)
210 } else {
211 Err(self)
212 }
213 }
214}
215
216pub trait Caller {
221 type Context;
222
223 fn context(&self) -> &Self::Context;
224 fn context_mut(&mut self) -> &mut Self::Context;
225 fn bytecode(&self) -> Bytes;
227
228 fn has_export(&self, name: &str) -> bool;
230
231 fn memory_read(&self, offset: u32, size: usize) -> VMResult<Vec<u8>> {
232 let mut vec = vec![0; size];
233 self.memory_read_into(offset, &mut vec)?;
234 Ok(vec)
235 }
236 fn memory_read_into(&self, offset: u32, output: &mut [u8]) -> VMResult<()>;
237 fn memory_write(&self, offset: u32, data: &[u8]) -> VMResult<()>;
238 fn alloc(&mut self, idx: u32, size: usize, ctx: u32) -> VMResult<u32>;
242 fn gas_consumed(&mut self) -> MeteringPoints;
244 fn consume_gas(&mut self, value: u64) -> VMResult<()>;
246}
247
248#[derive(Debug, Error)]
249pub enum WasmPreparationError {
250 #[error("Missing export {0}")]
251 MissingExport(String),
252 #[error("Compile error: {0}")]
253 Compile(String),
254 #[error("Memory instantiation error: {0}")]
255 Memory(String),
256 #[error("Instantiation error: {0}")]
257 Instantiation(String),
258}
259
260#[derive(Debug)]
261pub struct GasUsage {
262 gas_limit: u64,
264 remaining_points: u64,
266}
267
268impl GasUsage {
269 #[must_use]
270 pub fn new(gas_limit: u64, remaining_points: u64) -> Self {
271 GasUsage {
272 gas_limit,
273 remaining_points,
274 }
275 }
276
277 #[must_use]
278 pub fn gas_spent(&self) -> u64 {
279 debug_assert!(self.remaining_points <= self.gas_limit);
280 self.gas_limit - self.remaining_points
281 }
282
283 #[must_use]
284 pub fn gas_limit(&self) -> u64 {
285 self.gas_limit
286 }
287
288 #[must_use]
289 pub fn remaining_points(&self) -> u64 {
290 self.remaining_points
291 }
292}
293
294pub trait WasmInstance {
296 type Context;
297
298 fn call_export(&mut self, name: &str) -> (Result<(), VMError>, GasUsage);
299 fn teardown(self) -> Self::Context;
300}