1use crate::{DestroyError, ExecBuffer, ExecError, InstantiateError, MemoryError, EXEC_BUFFER_SIZE};
19use sp_runtime_interface::{
20 pass_by::{
21 ConvertAndReturnAs, PassFatPointerAndRead, PassFatPointerAndWrite, PassPointerAndWrite,
22 },
23 runtime_interface,
24};
25use strum::EnumCount;
26
27#[cfg(not(substrate_runtime))]
28use crate::ExecStatus;
29
30#[derive(EnumCount)]
31#[repr(i8)]
32pub enum RIInstantiateError {
33 InvalidImage = -1,
34}
35
36impl From<RIInstantiateError> for i64 {
37 fn from(error: RIInstantiateError) -> Self {
38 error as i64
39 }
40}
41
42impl TryFrom<i64> for RIInstantiateError {
43 type Error = ();
44
45 fn try_from(value: i64) -> Result<Self, Self::Error> {
46 match value {
47 -1 => Ok(RIInstantiateError::InvalidImage),
48 _ => Err(()),
49 }
50 }
51}
52
53impl From<InstantiateError> for RIInstantiateError {
54 fn from(error: InstantiateError) -> Self {
55 match error {
56 InstantiateError::InvalidImage => RIInstantiateError::InvalidImage,
57 }
58 }
59}
60
61impl From<RIInstantiateError> for InstantiateError {
62 fn from(error: RIInstantiateError) -> Self {
63 match error {
64 RIInstantiateError::InvalidImage => InstantiateError::InvalidImage,
65 }
66 }
67}
68
69#[derive(EnumCount)]
70#[repr(i8)]
71pub enum RIExecError {
72 InvalidInstance = -1,
73 InvalidImage = -2,
74 OutOfGas = -3,
75 Trap = -4,
76}
77
78impl From<RIExecError> for i64 {
79 fn from(error: RIExecError) -> Self {
80 error as i64
81 }
82}
83
84impl TryFrom<i64> for RIExecError {
85 type Error = ();
86
87 fn try_from(value: i64) -> Result<Self, Self::Error> {
88 match value {
89 -1 => Ok(RIExecError::InvalidInstance),
90 -2 => Ok(RIExecError::InvalidImage),
91 -3 => Ok(RIExecError::OutOfGas),
92 -4 => Ok(RIExecError::Trap),
93 _ => Err(()),
94 }
95 }
96}
97
98impl From<RIExecError> for ExecError {
99 fn from(error: RIExecError) -> Self {
100 match error {
101 RIExecError::InvalidInstance => ExecError::InvalidInstance,
102 RIExecError::InvalidImage => ExecError::InvalidImage,
103 RIExecError::OutOfGas => ExecError::OutOfGas,
104 RIExecError::Trap => ExecError::Trap,
105 }
106 }
107}
108
109impl From<ExecError> for RIExecError {
110 fn from(error: ExecError) -> Self {
111 match error {
112 ExecError::InvalidInstance => RIExecError::InvalidInstance,
113 ExecError::InvalidImage => RIExecError::InvalidImage,
114 ExecError::OutOfGas => RIExecError::OutOfGas,
115 ExecError::Trap => RIExecError::Trap,
116 }
117 }
118}
119
120#[derive(EnumCount)]
121#[repr(i8)]
122pub enum RIDestroyError {
123 InvalidInstance = -1,
124}
125
126impl From<RIDestroyError> for i64 {
127 fn from(error: RIDestroyError) -> Self {
128 error as i64
129 }
130}
131
132impl TryFrom<i64> for RIDestroyError {
133 type Error = ();
134
135 fn try_from(value: i64) -> Result<Self, Self::Error> {
136 match value {
137 -1 => Ok(RIDestroyError::InvalidInstance),
138 _ => Err(()),
139 }
140 }
141}
142
143impl From<RIDestroyError> for DestroyError {
144 fn from(error: RIDestroyError) -> Self {
145 match error {
146 RIDestroyError::InvalidInstance => DestroyError::InvalidInstance,
147 }
148 }
149}
150
151impl From<DestroyError> for RIDestroyError {
152 fn from(error: DestroyError) -> Self {
153 match error {
154 DestroyError::InvalidInstance => RIDestroyError::InvalidInstance,
155 }
156 }
157}
158
159#[derive(EnumCount)]
160#[repr(i8)]
161pub enum RIMemoryError {
162 InvalidInstance = -1,
163 OutOfBounds = -2,
164}
165
166impl From<RIMemoryError> for i64 {
167 fn from(error: RIMemoryError) -> Self {
168 error as i64
169 }
170}
171
172impl TryFrom<i64> for RIMemoryError {
173 type Error = ();
174
175 fn try_from(value: i64) -> Result<Self, Self::Error> {
176 match value {
177 -1 => Ok(RIMemoryError::InvalidInstance),
178 -2 => Ok(RIMemoryError::OutOfBounds),
179 _ => Err(()),
180 }
181 }
182}
183
184impl From<RIMemoryError> for MemoryError {
185 fn from(error: RIMemoryError) -> Self {
186 match error {
187 RIMemoryError::InvalidInstance => MemoryError::InvalidInstance,
188 RIMemoryError::OutOfBounds => MemoryError::OutOfBounds,
189 }
190 }
191}
192
193impl From<MemoryError> for RIMemoryError {
194 fn from(error: MemoryError) -> Self {
195 match error {
196 MemoryError::InvalidInstance => RIMemoryError::InvalidInstance,
197 MemoryError::OutOfBounds => RIMemoryError::OutOfBounds,
198 }
199 }
200}
201
202pub enum RIIntResult<R, E> {
208 Ok(R),
210 Err(E),
212}
213
214impl<R, E, OR, OE> From<Result<OR, OE>> for RIIntResult<R, E>
215where
216 R: From<OR>,
217 E: From<OE>,
218{
219 fn from(result: Result<OR, OE>) -> Self {
220 match result {
221 Ok(value) => Self::Ok(value.into()),
222 Err(error) => Self::Err(error.into()),
223 }
224 }
225}
226
227impl<R, E, OR, OE> From<RIIntResult<R, E>> for Result<OR, OE>
228where
229 OR: From<R>,
230 OE: From<E>,
231{
232 fn from(result: RIIntResult<R, E>) -> Self {
233 match result {
234 RIIntResult::Ok(value) => Ok(value.into()),
235 RIIntResult::Err(error) => Err(error.into()),
236 }
237 }
238}
239
240trait IntoI64: Into<i64> {
241 const MAX: i64;
242}
243
244impl IntoI64 for u8 {
245 const MAX: i64 = u8::MAX as i64;
246}
247impl IntoI64 for u32 {
248 const MAX: i64 = u32::MAX as i64;
249}
250
251impl<R: Into<i64> + IntoI64, E: Into<i64> + strum::EnumCount> From<RIIntResult<R, E>> for i64 {
252 fn from(result: RIIntResult<R, E>) -> Self {
253 match result {
254 RIIntResult::Ok(value) => value.into(),
255 RIIntResult::Err(e) => {
256 let error_code: i64 = e.into();
257 assert!(
258 error_code < 0 && error_code >= -(E::COUNT as i64),
259 "Error variant index out of bounds"
260 );
261 error_code
262 },
263 }
264 }
265}
266
267impl<R: TryFrom<i64> + IntoI64, E: TryFrom<i64> + strum::EnumCount> TryFrom<i64>
268 for RIIntResult<R, E>
269{
270 type Error = ();
271
272 fn try_from(value: i64) -> Result<Self, Self::Error> {
273 if value >= 0 && value <= R::MAX.into() {
274 Ok(RIIntResult::Ok(value.try_into().map_err(|_| ())?))
275 } else if value < 0 && value >= -(E::COUNT as i64) {
276 Ok(RIIntResult::Err(value.try_into().map_err(|_| ())?))
277 } else {
278 Err(())
279 }
280 }
281}
282
283pub struct VoidResult;
284
285impl IntoI64 for VoidResult {
286 const MAX: i64 = 0;
287}
288
289impl From<VoidResult> for u32 {
290 fn from(_: VoidResult) -> Self {
291 0
292 }
293}
294
295impl From<u32> for VoidResult {
296 fn from(_: u32) -> Self {
297 VoidResult
298 }
299}
300
301impl From<()> for VoidResult {
302 fn from(_: ()) -> Self {
303 VoidResult
304 }
305}
306
307impl From<VoidResult> for () {
308 fn from(_: VoidResult) -> Self {
309 ()
310 }
311}
312
313impl From<VoidResult> for i64 {
314 fn from(_: VoidResult) -> Self {
315 0
316 }
317}
318
319impl TryFrom<i64> for VoidResult {
320 type Error = ();
321
322 fn try_from(value: i64) -> Result<Self, Self::Error> {
323 if value == 0 {
324 Ok(VoidResult)
325 } else {
326 Err(())
327 }
328 }
329}
330
331#[runtime_interface(wasm_only)]
349pub trait Virtualization {
350 fn instantiate(
355 &mut self,
356 program: PassFatPointerAndRead<&[u8]>,
357 ) -> ConvertAndReturnAs<Result<u32, InstantiateError>, RIIntResult<u32, RIInstantiateError>, i64>
358 {
359 use std::sync::Once;
360 static WARN_ONCE: Once = Once::new();
361 WARN_ONCE.call_once(|| {
362 log::warn!(
363 target: crate::LOG_TARGET,
364 "Virtualization host functions are UNSTABLE and subject to breaking changes. \
365 They are NOT available on Polkadot and using them in production will cause breakage. \
366 Only use for testing and experimentation.",
367 );
368 });
369 self.virtualization()
370 .instantiate(program)
371 .expect("instantiation failed")
372 .map(|id| id.0)
373 .map_err(|err| TryFrom::try_from(err).expect("Invalid error"))
374 }
375
376 fn execute(
382 &mut self,
383 instance_id: u32,
384 function: PassFatPointerAndRead<&str>,
385 gas_left: i64,
386 exec_buffer: PassPointerAndWrite<&mut ExecBuffer, { EXEC_BUFFER_SIZE }>,
387 ) -> ConvertAndReturnAs<Result<u8, ExecError>, RIIntResult<u8, RIExecError>, i64> {
388 let instance_id = sp_wasm_interface::InstanceId(instance_id);
389 self.virtualization()
390 .run(instance_id, gas_left, sp_wasm_interface::ExecAction::Execute(function))
391 .expect("execution failed")
392 .map(|outcome| {
393 *exec_buffer = ExecBuffer::from_outcome(&outcome);
394 ExecStatus::from_outcome(&outcome).into()
395 })
396 .map_err(|err| TryFrom::try_from(err).expect("Invalid error"))
397 }
398
399 fn resume(
405 &mut self,
406 instance_id: u32,
407 gas_left: i64,
408 return_value: u64,
409 exec_buffer: PassPointerAndWrite<&mut ExecBuffer, { EXEC_BUFFER_SIZE }>,
410 ) -> ConvertAndReturnAs<Result<u8, ExecError>, RIIntResult<u8, RIExecError>, i64> {
411 let instance_id = sp_wasm_interface::InstanceId(instance_id);
412 self.virtualization()
413 .run(instance_id, gas_left, sp_wasm_interface::ExecAction::Resume(return_value))
414 .expect("resume failed")
415 .map(|outcome| {
416 *exec_buffer = ExecBuffer::from_outcome(&outcome);
417 ExecStatus::from_outcome(&outcome).into()
418 })
419 .map_err(|err| TryFrom::try_from(err).expect("Invalid error"))
420 }
421
422 fn destroy(
426 &mut self,
427 instance_id: u32,
428 ) -> ConvertAndReturnAs<Result<(), DestroyError>, RIIntResult<VoidResult, RIDestroyError>, i64>
429 {
430 let instance_id = sp_wasm_interface::InstanceId(instance_id);
431 self.virtualization()
432 .destroy(instance_id)
433 .expect("memory access error")
434 .map_err(|err| TryFrom::try_from(err).expect("Invalid error"))
435 }
436
437 fn read_memory(
439 &mut self,
440 instance_id: u32,
441 offset: u32,
442 dest: PassFatPointerAndWrite<&mut [u8]>,
443 ) -> ConvertAndReturnAs<Result<(), MemoryError>, RIIntResult<VoidResult, RIMemoryError>, i64> {
444 let instance_id = sp_wasm_interface::InstanceId(instance_id);
445 self.virtualization()
446 .read_memory(instance_id, offset, dest)
447 .expect("memory access error")
448 .map_err(|err| TryFrom::try_from(err).expect("Invalid error"))
449 }
450
451 fn write_memory(
453 &mut self,
454 instance_id: u32,
455 offset: u32,
456 src: PassFatPointerAndRead<&[u8]>,
457 ) -> ConvertAndReturnAs<Result<(), MemoryError>, RIIntResult<VoidResult, RIMemoryError>, i64> {
458 let instance_id = sp_wasm_interface::InstanceId(instance_id);
459 self.virtualization()
460 .write_memory(instance_id, offset, src)
461 .expect("memory access error")
462 .map_err(|err| TryFrom::try_from(err).expect("Invalid error"))
463 }
464}