1#[cfg(feature = "wasm")]
2use crate::engine_access::EngineAccess;
3#[cfg(feature = "wasm")]
4use crate::wire::ActionWire;
5
6#[derive(Debug, Clone)]
7pub struct RawProviderEvent {
8 pub payload_type: String,
9 pub payload: Vec<u8>,
10}
11
12pub const DEFAULT_FUEL: u64 = 10_000_000;
14pub const DEFAULT_MAX_MEMORY: usize = 16 * 1024 * 1024;
16
17#[cfg(feature = "wasm")]
24pub struct StoreData {
25 pub engine_access: *const dyn EngineAccess,
26 pub now: f64,
27 pub injected_actions: Vec<ActionWire>,
28 pub log_messages: Vec<String>,
29 pub provider_events: Vec<RawProviderEvent>,
30 pub provider_events_enabled: bool,
31}
32
33#[cfg(feature = "wasm")]
37unsafe impl Send for StoreData {}
38#[cfg(feature = "wasm")]
39unsafe impl Sync for StoreData {}
40
41#[cfg(feature = "wasm")]
42impl StoreData {
43 pub unsafe fn engine(&self) -> &dyn EngineAccess {
48 &*self.engine_access
49 }
50
51 pub fn reset_per_call(
53 &mut self,
54 engine_access: *const dyn EngineAccess,
55 now: f64,
56 provider_events_enabled: bool,
57 ) {
58 self.engine_access = engine_access;
59 self.now = now;
60 self.injected_actions.clear();
61 self.log_messages.clear();
62 self.provider_events.clear();
63 self.provider_events_enabled = provider_events_enabled;
64 }
65}
66
67#[cfg(feature = "wasm")]
69pub struct WasmRuntime {
70 engine: wasmtime::Engine,
71 fuel: u64,
72}
73
74#[cfg(feature = "wasm")]
75impl WasmRuntime {
76 pub fn new() -> Result<Self, wasmtime::Error> {
77 let mut config = wasmtime::Config::new();
78 config.consume_fuel(true);
79 config.wasm_gc(false);
83 config.wasm_exceptions(false);
84 let engine = wasmtime::Engine::new(&config)?;
85 Ok(WasmRuntime {
86 engine,
87 fuel: DEFAULT_FUEL,
88 })
89 }
90
91 pub fn compile(&self, bytes: &[u8]) -> Result<wasmtime::Module, wasmtime::Error> {
92 wasmtime::Module::new(&self.engine, bytes)
93 }
94
95 pub fn engine(&self) -> &wasmtime::Engine {
96 &self.engine
97 }
98
99 pub fn fuel(&self) -> u64 {
100 self.fuel
101 }
102}
103
104#[cfg(all(test, feature = "wasm"))]
105mod tests {
106 use super::WasmRuntime;
107
108 #[test]
109 fn compiles_core_hook_instruction_set() {
110 let runtime = WasmRuntime::new().unwrap();
111 runtime
112 .compile(
113 br#"(module
114 (memory 2)
115 (func (export "bulk")
116 i32.const 0
117 i32.const 90
118 i32.const 4096
119 memory.fill
120 i32.const 8192
121 i32.const 0
122 i32.const 4096
123 memory.copy))"#,
124 )
125 .unwrap();
126 }
127
128 #[test]
129 fn rejects_webassembly_gc_modules() {
130 let runtime = WasmRuntime::new().unwrap();
131 let result = runtime.compile(
132 br#"(module
133 (type $record (struct (field i32)))
134 (func (export "make") (result (ref null $record))
135 ref.null $record))"#,
136 );
137
138 assert!(result.is_err(), "the hook sandbox must not enable Wasm GC");
139 }
140
141 #[test]
142 fn rejects_webassembly_exception_modules() {
143 let runtime = WasmRuntime::new().unwrap();
144 let result = runtime.compile(
145 br#"(module
146 (tag $failure)
147 (func (export "raise")
148 throw $failure))"#,
149 );
150
151 assert!(
152 result.is_err(),
153 "the hook sandbox must not enable Wasm exception handling"
154 );
155 }
156}