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