1use crate::{
19 CompileStatus, DestroyError, ExecError, InstanceId, InstantiateError, MemoryError, ModuleError,
20 ModuleId, SyscallSymbol,
21};
22use core::mem;
23use num_enum::{IntoPrimitive, TryFromPrimitive};
24use sp_runtime_interface::{
25 pass_by::{
26 ConvertAndReturnAs, PassAs, PassFatPointerAndRead, PassFatPointerAndReadOption,
27 PassFatPointerAndWrite, PassPointerAndWrite,
28 },
29 runtime_interface,
30};
31
32#[derive(Debug, Default)]
38#[repr(C)]
39pub struct ExecBuffer {
40 pub gas_left: i64,
42 pub syscall_symbol: SyscallSymbol,
44 pub a0: u64,
46 pub a1: u64,
47 pub a2: u64,
48 pub a3: u64,
49 pub a4: u64,
50 pub a5: u64,
51}
52
53impl AsRef<[u8]> for ExecBuffer {
54 fn as_ref(&self) -> &[u8] {
55 unsafe {
58 core::slice::from_raw_parts(self as *const Self as *const u8, mem::size_of::<Self>())
59 }
60 }
61}
62
63impl AsMut<[u8]> for ExecBuffer {
64 fn as_mut(&mut self) -> &mut [u8] {
65 unsafe {
68 core::slice::from_raw_parts_mut(self as *mut Self as *mut u8, mem::size_of::<Self>())
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
75#[repr(u32)]
76pub enum ExecStatus {
77 Finished = 0,
79 Syscall = 1,
81}
82
83macro_rules! impl_ri_error_encoding {
91 ($($t:ty),+ $(,)?) => {$(
92 impl From<$t> for i64 {
93 fn from(error: $t) -> Self {
94 i32::from(error) as i64
95 }
96 }
97
98 impl TryFrom<i64> for $t {
99 type Error = ();
100 fn try_from(value: i64) -> Result<Self, Self::Error> {
101 let v = i32::try_from(value).map_err(|_| ())?;
102 Self::try_from(v).map_err(|_| ())
103 }
104 }
105 )+};
106}
107
108impl_ri_error_encoding!(ModuleError, InstantiateError, ExecError, DestroyError, MemoryError);
109
110impl From<u32> for ModuleId {
111 fn from(id: u32) -> Self {
112 Self(id)
113 }
114}
115
116impl From<ModuleId> for u32 {
117 fn from(id: ModuleId) -> Self {
118 id.0
119 }
120}
121
122impl IntoI64 for ModuleId {
123 const MAX: i64 = u32::MAX as i64;
124}
125
126impl From<ModuleId> for i64 {
127 fn from(id: ModuleId) -> Self {
128 u32::from(id) as i64
129 }
130}
131
132impl TryFrom<i64> for ModuleId {
133 type Error = ();
134 fn try_from(value: i64) -> Result<Self, Self::Error> {
135 u32::try_from(value).map(ModuleId::from).map_err(|_| ())
136 }
137}
138
139pub struct CompiledModule {
150 pub id: ModuleId,
151 pub status: CompileStatus,
152}
153
154impl IntoI64 for CompiledModule {
155 const MAX: i64 = (1i64 << 40) - 1;
156}
157
158impl From<CompiledModule> for i64 {
159 fn from(m: CompiledModule) -> Self {
160 let status = u8::from(m.status) as i64;
161 (status << 32) | (u32::from(m.id) as i64)
162 }
163}
164
165impl TryFrom<i64> for CompiledModule {
166 type Error = ();
167 fn try_from(value: i64) -> Result<Self, Self::Error> {
168 let id = ModuleId::from(value as u32);
169 let status = CompileStatus::try_from((value >> 32) as u8).map_err(|_| ())?;
170 Ok(Self { id, status })
171 }
172}
173
174impl From<u32> for InstanceId {
175 fn from(id: u32) -> Self {
176 Self(id)
177 }
178}
179
180impl From<InstanceId> for u32 {
181 fn from(id: InstanceId) -> Self {
182 id.0
183 }
184}
185
186impl IntoI64 for InstanceId {
187 const MAX: i64 = u32::MAX as i64;
188}
189
190impl From<InstanceId> for i64 {
191 fn from(id: InstanceId) -> Self {
192 u32::from(id) as i64
193 }
194}
195
196impl TryFrom<i64> for InstanceId {
197 type Error = ();
198 fn try_from(value: i64) -> Result<Self, Self::Error> {
199 u32::try_from(value).map(InstanceId::from).map_err(|_| ())
200 }
201}
202
203pub enum RIIntResult<R, E> {
209 Ok(R),
211 Err(E),
213}
214
215impl<R, E, OR, OE> From<Result<OR, OE>> for RIIntResult<R, E>
216where
217 R: From<OR>,
218 E: From<OE>,
219{
220 fn from(result: Result<OR, OE>) -> Self {
221 match result {
222 Ok(value) => Self::Ok(value.into()),
223 Err(error) => Self::Err(error.into()),
224 }
225 }
226}
227
228impl<R, E, OR, OE> From<RIIntResult<R, E>> for Result<OR, OE>
229where
230 OR: From<R>,
231 OE: From<E>,
232{
233 fn from(result: RIIntResult<R, E>) -> Self {
234 match result {
235 RIIntResult::Ok(value) => Ok(value.into()),
236 RIIntResult::Err(error) => Err(error.into()),
237 }
238 }
239}
240
241trait IntoI64: Into<i64> {
242 const MAX: i64;
243}
244
245impl IntoI64 for u32 {
246 const MAX: i64 = u32::MAX as i64;
247}
248
249impl<R: Into<i64> + IntoI64, E: Into<i64> + strum::EnumCount> From<RIIntResult<R, E>> for i64 {
250 fn from(result: RIIntResult<R, E>) -> Self {
251 match result {
252 RIIntResult::Ok(value) => value.into(),
253 RIIntResult::Err(e) => {
254 let error_code: i64 = e.into();
255 assert!(
256 error_code < 0 && error_code >= -(E::COUNT as i64),
257 "Error variant index out of bounds"
258 );
259 error_code
260 },
261 }
262 }
263}
264
265impl<R: TryFrom<i64> + IntoI64, E: TryFrom<i64> + strum::EnumCount> TryFrom<i64>
266 for RIIntResult<R, E>
267{
268 type Error = ();
269
270 fn try_from(value: i64) -> Result<Self, Self::Error> {
271 if value >= 0 && value <= R::MAX.into() {
272 Ok(RIIntResult::Ok(value.try_into().map_err(|_| ())?))
273 } else if value < 0 && value >= -(E::COUNT as i64) {
274 Ok(RIIntResult::Err(value.try_into().map_err(|_| ())?))
275 } else {
276 Err(())
277 }
278 }
279}
280
281pub struct VoidResult;
282
283impl IntoI64 for VoidResult {
284 const MAX: i64 = 0;
285}
286
287impl From<()> for VoidResult {
288 fn from(_: ()) -> Self {
289 VoidResult
290 }
291}
292
293impl From<VoidResult> for () {
294 fn from(_: VoidResult) -> Self {
295 ()
296 }
297}
298
299impl From<VoidResult> for i64 {
300 fn from(_: VoidResult) -> Self {
301 0
302 }
303}
304
305impl TryFrom<i64> for VoidResult {
306 type Error = ();
307
308 fn try_from(value: i64) -> Result<Self, Self::Error> {
309 if value == 0 {
310 Ok(VoidResult)
311 } else {
312 Err(())
313 }
314 }
315}
316
317#[runtime_interface]
337pub trait Virtualization {
338 fn compile_from_bytes(
347 &mut self,
348 program: PassFatPointerAndRead<&[u8]>,
349 identifier: PassFatPointerAndReadOption<&[u8]>,
350 ) -> ConvertAndReturnAs<
351 Result<CompiledModule, ModuleError>,
352 RIIntResult<CompiledModule, ModuleError>,
353 i64,
354 > {
355 use sp_externalities::ExternalitiesExt as _;
356 use std::sync::Once;
357 static WARN_ONCE: Once = Once::new();
358 WARN_ONCE.call_once(|| {
359 log::warn!(
360 target: crate::LOG_TARGET,
361 "Virtualization host functions are UNSTABLE and subject to breaking changes. \
362 They are NOT available on Polkadot and using them in production will cause breakage. \
363 Only use for testing and experimentation.",
364 );
365 });
366
367 if let Some(identifier) = identifier {
369 let cache_result = self
370 .extension::<crate::VirtManagerExt>()
371 .expect("VirtManagerExt not registered in externalities")
372 .lookup(identifier);
373 match cache_result {
374 Ok(id) => return Ok(CompiledModule { id, status: CompileStatus::Cached }),
375 Err(ModuleError::NotCached) => {},
376 Err(err) => return Err(err),
377 }
378 }
379
380 let id = self
381 .extension::<crate::VirtManagerExt>()
382 .expect("VirtManagerExt not registered in externalities")
383 .compile_from_bytes(program, identifier)?;
384 Ok(CompiledModule { id, status: CompileStatus::Compiled })
385 }
386
387 fn lookup(
393 &mut self,
394 identifier: PassFatPointerAndRead<&[u8]>,
395 ) -> ConvertAndReturnAs<Result<ModuleId, ModuleError>, RIIntResult<ModuleId, ModuleError>, i64>
396 {
397 use sp_externalities::ExternalitiesExt as _;
398 self.extension::<crate::VirtManagerExt>()
399 .expect("VirtManagerExt not registered in externalities")
400 .lookup(identifier)
401 }
402
403 fn compile_from_storage_key(
411 &mut self,
412 storage_key: PassFatPointerAndRead<&[u8]>,
413 child_trie: PassFatPointerAndRead<&[u8]>,
414 ) -> ConvertAndReturnAs<
415 Result<CompiledModule, ModuleError>,
416 RIIntResult<CompiledModule, ModuleError>,
417 i64,
418 > {
419 use sp_externalities::ExternalitiesExt as _;
420
421 let cache_result = self
423 .extension::<crate::VirtManagerExt>()
424 .expect("VirtManagerExt not registered in externalities")
425 .lookup(storage_key);
426
427 match cache_result {
428 Ok(id) => return Ok(CompiledModule { id, status: CompileStatus::Cached }),
429 Err(ModuleError::NotCached) => {},
430 Err(err) => return Err(err),
431 }
432
433 let code = if child_trie.is_empty() {
435 self.storage(storage_key)
436 } else {
437 let child_info = sp_storage::ChildInfo::new_default(child_trie);
438 self.child_storage(&child_info, storage_key)
439 };
440
441 let code = match code {
442 Some(code) => code,
443 None => return Err(ModuleError::NotFound),
444 };
445
446 let id = self
448 .extension::<crate::VirtManagerExt>()
449 .expect("VirtManagerExt not registered in externalities")
450 .compile_from_bytes(&code, Some(storage_key))?;
451 Ok(CompiledModule { id, status: CompileStatus::Compiled })
452 }
453
454 fn instantiate(
459 &mut self,
460 module_id: PassAs<ModuleId, u32>,
461 ) -> ConvertAndReturnAs<
462 Result<InstanceId, InstantiateError>,
463 RIIntResult<InstanceId, InstantiateError>,
464 i64,
465 > {
466 use sp_externalities::ExternalitiesExt as _;
467 self.extension::<crate::VirtManagerExt>()
468 .expect("VirtManagerExt not registered in externalities")
469 .instantiate(module_id)
470 }
471
472 fn prepare(
477 &mut self,
478 instance_id: PassAs<InstanceId, u32>,
479 function: PassFatPointerAndRead<&[u8]>,
480 ) -> ConvertAndReturnAs<Result<(), ExecError>, RIIntResult<VoidResult, ExecError>, i64> {
481 use sp_externalities::ExternalitiesExt as _;
482 self.extension::<crate::VirtManagerExt>()
483 .expect("VirtManagerExt not registered in externalities")
484 .prepare(instance_id, function)
485 }
486
487 fn run(
493 &mut self,
494 instance_id: PassAs<InstanceId, u32>,
495 gas_left: i64,
496 a0: u64,
497 exec_buffer: PassPointerAndWrite<&mut ExecBuffer, { mem::size_of::<ExecBuffer>() }>,
498 ) -> ConvertAndReturnAs<Result<u32, ExecError>, RIIntResult<u32, ExecError>, i64> {
499 use sp_externalities::ExternalitiesExt as _;
500 self.extension::<crate::VirtManagerExt>()
501 .expect("VirtManagerExt not registered in externalities")
502 .run(instance_id, gas_left, a0)
503 .map(|(status, buf)| {
504 *exec_buffer = buf;
505 u32::from(status)
506 })
507 }
508
509 fn destroy(
513 &mut self,
514 instance_id: PassAs<InstanceId, u32>,
515 ) -> ConvertAndReturnAs<Result<(), DestroyError>, RIIntResult<VoidResult, DestroyError>, i64> {
516 use sp_externalities::ExternalitiesExt as _;
517 self.extension::<crate::VirtManagerExt>()
518 .expect("VirtManagerExt not registered in externalities")
519 .destroy(instance_id)
520 }
521
522 fn read_memory(
524 &mut self,
525 instance_id: PassAs<InstanceId, u32>,
526 offset: u32,
527 dest: PassFatPointerAndWrite<&mut [u8]>,
528 ) -> ConvertAndReturnAs<Result<(), MemoryError>, RIIntResult<VoidResult, MemoryError>, i64> {
529 use sp_externalities::ExternalitiesExt as _;
530 self.extension::<crate::VirtManagerExt>()
531 .expect("VirtManagerExt not registered in externalities")
532 .read_memory(instance_id, offset, dest)
533 }
534
535 fn write_memory(
537 &mut self,
538 instance_id: PassAs<InstanceId, u32>,
539 offset: u32,
540 src: PassFatPointerAndRead<&[u8]>,
541 ) -> ConvertAndReturnAs<Result<(), MemoryError>, RIIntResult<VoidResult, MemoryError>, i64> {
542 use sp_externalities::ExternalitiesExt as _;
543 self.extension::<crate::VirtManagerExt>()
544 .expect("VirtManagerExt not registered in externalities")
545 .write_memory(instance_id, offset, src)
546 }
547}
548
549#[cfg(not(substrate_runtime))]
554pub trait VirtManagerBackend: Send + 'static {
555 fn compile_from_bytes(
562 &mut self,
563 program: &[u8],
564 identifier: Option<&[u8]>,
565 ) -> Result<ModuleId, ModuleError>;
566
567 fn lookup(&mut self, identifier: &[u8]) -> Result<ModuleId, ModuleError>;
572
573 fn instantiate(&mut self, module_id: ModuleId) -> Result<InstanceId, InstantiateError>;
574
575 fn prepare(&mut self, instance_id: InstanceId, function: &[u8]) -> Result<(), ExecError>;
576
577 fn run(
578 &mut self,
579 instance_id: InstanceId,
580 gas_left: i64,
581 a0: u64,
582 ) -> Result<(ExecStatus, ExecBuffer), ExecError>;
583
584 fn destroy(&mut self, instance_id: InstanceId) -> Result<(), DestroyError>;
585
586 fn read_memory(
587 &mut self,
588 instance_id: InstanceId,
589 offset: u32,
590 dest: &mut [u8],
591 ) -> Result<(), MemoryError>;
592
593 fn write_memory(
594 &mut self,
595 instance_id: InstanceId,
596 offset: u32,
597 src: &[u8],
598 ) -> Result<(), MemoryError>;
599}
600
601#[cfg(not(substrate_runtime))]
602sp_externalities::decl_extension! {
603 pub struct VirtManagerExt(Box<dyn VirtManagerBackend>);
606}
607
608#[cfg(not(substrate_runtime))]
609impl VirtManagerExt {
610 pub fn new<B: VirtManagerBackend>(backend: B) -> Self {
612 Self(Box::new(backend))
613 }
614}