1use super::{allocator, vm};
200use crate::{trie, util};
201
202use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec, vec::Vec};
203use core::{fmt, iter, str};
204use functions::HostFunction;
205
206pub mod runtime_version;
207
208pub use runtime_version::{
209 CoreVersion, CoreVersionApisFromSliceErr, CoreVersionError, CoreVersionRef,
210 FindEncodedEmbeddedRuntimeVersionApisError,
211};
212pub use trie::TrieEntryVersion;
213pub use vm::HeapPages;
214pub use zstd::Error as ModuleFormatError;
215
216mod functions;
217mod tests;
218mod zstd;
219
220pub struct Config<TModule> {
222 pub module: TModule,
226
227 pub heap_pages: HeapPages,
231
232 pub exec_hint: vm::ExecHint,
234
235 pub allow_unresolved_imports: bool,
240}
241
242#[derive(Debug, Clone, PartialEq, Eq)]
254pub enum StorageProofSizeBehavior {
255 Unimplemented,
257 ConstantReturnValue(u64),
259}
260
261impl StorageProofSizeBehavior {
262 pub fn proof_recording_disabled() -> Self {
265 StorageProofSizeBehavior::ConstantReturnValue(u64::MAX)
266 }
267}
268
269#[derive(Clone)]
274pub struct HostVmPrototype {
275 common: Box<VmCommon>,
277
278 vm_proto: vm::VirtualMachinePrototype,
280}
281
282#[derive(Clone)]
284struct VmCommon {
285 runtime_version: Option<CoreVersion>,
289
290 heap_base: u32,
293
294 registered_functions: Arc<[FunctionImport]>,
300
301 heap_pages: HeapPages,
303
304 memory_total_pages: HeapPages,
307}
308
309impl HostVmPrototype {
310 pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312 let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317 .map_err(NewErr::BadFormat)?;
318
319 let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328 Ok(Some(r)) => Some(r),
329 Ok(None) => None,
330 Err(
331 runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332 ) => None,
333 Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334 return Err(NewErr::RuntimeVersion(
335 FindEmbeddedRuntimeVersionError::FindSections(err),
336 ));
337 }
338 Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339 return Err(NewErr::RuntimeVersion(
340 FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341 ));
342 }
343 Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344 return Err(NewErr::RuntimeVersion(
345 FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346 ));
347 }
348 };
349
350 let (mut vm_proto, registered_functions) = {
355 let mut registered_functions = Vec::new();
356 let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357 module_bytes: &module_bytes[..],
358 exec_hint: config.exec_hint,
359 symbols: &mut |mod_name, f_name, signature| {
361 if mod_name != "env" {
362 return Err(());
363 }
364
365 let id = registered_functions.len();
366 registered_functions.push(match HostFunction::by_name(f_name) {
367 Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368 Some(_) | None if !config.allow_unresolved_imports => {
369 return Err(());
371 }
372 Some(_) | None => FunctionImport::Unresolved {
373 name: f_name.to_owned(),
374 module: mod_name.to_owned(),
375 },
376 });
377 Ok(id)
378 },
379 })?;
380 (vm_proto, registered_functions.into())
381 };
382
383 let heap_base = vm_proto
386 .global_value("__heap_base")
387 .map_err(|_| NewErr::HeapBaseNotFound)?;
388
389 let memory_total_pages = if heap_base == 0 {
390 config.heap_pages
391 } else {
392 HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393 };
394
395 if vm_proto
396 .memory_max_pages()
397 .map_or(false, |max| max < memory_total_pages)
398 {
399 return Err(NewErr::MemoryMaxSizeTooLow);
400 }
401
402 let mut host_vm_prototype = HostVmPrototype {
403 vm_proto,
404 common: Box::new(VmCommon {
405 runtime_version,
406 heap_base,
407 registered_functions,
408 heap_pages: config.heap_pages,
409 memory_total_pages,
410 }),
411 };
412
413 if host_vm_prototype.common.runtime_version.is_none() {
415 let mut vm: HostVm = match host_vm_prototype.run_no_param(
416 "Core_version",
417 StorageProofSizeBehavior::proof_recording_disabled(),
418 ) {
419 Ok(vm) => vm.into(),
420 Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421 };
422
423 loop {
424 match vm {
425 HostVm::ReadyToRun(r) => vm = r.run(),
426 HostVm::Finished(finished) => {
427 let version =
428 match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429 Ok(v) => v,
430 Err(_) => {
431 return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432 }
433 };
434
435 host_vm_prototype = finished.into_prototype();
436 host_vm_prototype.common.runtime_version = Some(version);
437 break;
438 }
439
440 HostVm::GetMaxLogLevel(resume) => {
442 vm = resume.resume(0); }
444 HostVm::LogEmit(log) => vm = log.resume(),
445
446 HostVm::Error { error, .. } => {
447 return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448 }
449
450 _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453 }
454 }
455 }
456
457 debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459 Ok(host_vm_prototype)
460 }
461
462 pub fn heap_pages(&self) -> HeapPages {
464 self.common.heap_pages
465 }
466
467 pub fn runtime_version(&self) -> &CoreVersion {
469 self.common
470 .runtime_version
471 .as_ref()
472 .unwrap_or_else(|| unreachable!())
473 }
474
475 pub fn run(
480 self,
481 function_to_call: &str,
482 storage_proof_size_behavior: StorageProofSizeBehavior,
483 data: &[u8],
484 ) -> Result<ReadyToRun, (StartErr, Self)> {
485 self.run_vectored(
486 function_to_call,
487 storage_proof_size_behavior,
488 iter::once(data),
489 )
490 }
491
492 pub fn run_no_param(
497 self,
498 function_to_call: &str,
499 storage_proof_size_behavior: StorageProofSizeBehavior,
500 ) -> Result<ReadyToRun, (StartErr, Self)> {
501 self.run_vectored(
502 function_to_call,
503 storage_proof_size_behavior,
504 iter::empty::<Vec<u8>>(),
505 )
506 }
507
508 pub fn run_vectored(
514 mut self,
515 function_to_call: &str,
516 storage_proof_size_behavior: StorageProofSizeBehavior,
517 data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518 ) -> Result<ReadyToRun, (StartErr, Self)> {
519 let mut data_len_u32: u32 = 0;
521 for data in data.clone() {
522 let len = match u32::try_from(data.as_ref().len()) {
523 Ok(v) => v,
524 Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525 };
526 data_len_u32 = match data_len_u32.checked_add(len) {
527 Some(v) => v,
528 None => return Err((StartErr::DataSizeOverflow, self)),
529 };
530 }
531
532 let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
537 let mut vm = self.vm_proto.prepare();
539
540 let data_ptr = match allocator.allocate(
542 &mut MemAccess {
543 vm: MemAccessVm::Prepare(&mut vm),
544 memory_total_pages: self.common.memory_total_pages,
545 },
546 data_len_u32,
547 ) {
548 Ok(p) => p,
549 Err(_) => {
550 self.vm_proto = vm.into_prototype();
551 return Err((StartErr::DataSizeOverflow, self));
552 }
553 };
554
555 if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558 .checked_sub(u32::from(vm.memory_size()))
559 {
560 vm.grow_memory(HeapPages::from(to_grow))
562 .unwrap_or_else(|_| unreachable!());
563 }
564
565 let mut data_ptr_iter = data_ptr;
567 for data in data {
568 let data = data.as_ref();
569 vm.write_memory(data_ptr_iter, data)
570 .unwrap_or_else(|_| unreachable!());
571 data_ptr_iter = data_ptr_iter
572 .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573 .unwrap_or_else(|| unreachable!());
574 }
575
576 let vm = match vm.start(
579 function_to_call,
580 &[
581 vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582 vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583 ],
584 ) {
585 Ok(vm) => vm,
586 Err((error, vm_proto)) => {
587 self.vm_proto = vm_proto;
588 return Err((error.into(), self));
589 }
590 };
591
592 Ok(ReadyToRun {
593 resume_value: None,
594 inner: Box::new(Inner {
595 common: self.common,
596 vm,
597 storage_transaction_depth: 0,
598 signatures_batch_verification: None,
599 allocator,
600 storage_proof_size_behavior,
601 }),
602 })
603 }
604}
605
606impl fmt::Debug for HostVmPrototype {
607 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
608 f.debug_tuple("HostVmPrototype").finish()
609 }
610}
611
612#[must_use]
614#[derive(derive_more::From, Debug)]
615pub enum HostVm {
616 #[from]
618 ReadyToRun(ReadyToRun),
619 #[from]
625 Finished(Finished),
626 Error {
628 prototype: HostVmPrototype,
630 error: Error,
632 },
633 #[from]
635 ExternalStorageGet(ExternalStorageGet),
636 #[from]
638 ExternalStorageSet(ExternalStorageSet),
639 #[from]
641 ExternalStorageAppend(ExternalStorageAppend),
642 #[from]
644 ExternalStorageClearPrefix(ExternalStorageClearPrefix),
645 #[from]
648 ExternalStorageRoot(ExternalStorageRoot),
649 #[from]
651 ExternalStorageNextKey(ExternalStorageNextKey),
652 #[from]
654 ExternalOffchainIndexSet(ExternalOffchainIndexSet),
655 #[from]
657 ExternalOffchainStorageGet(ExternalOffchainStorageGet),
658 #[from]
660 ExternalOffchainStorageSet(ExternalOffchainStorageSet),
661 #[from]
663 OffchainTimestamp(OffchainTimestamp),
664 #[from]
666 OffchainRandomSeed(OffchainRandomSeed),
667 #[from]
669 OffchainSubmitTransaction(OffchainSubmitTransaction),
670 #[from]
672 SignatureVerification(SignatureVerification),
673 #[from]
676 CallRuntimeVersion(CallRuntimeVersion),
677 #[from]
679 StartStorageTransaction(StartStorageTransaction),
680 EndStorageTransaction {
688 resume: EndStorageTransaction,
690 rollback: bool,
692 },
693 #[from]
695 GetMaxLogLevel(GetMaxLogLevel),
696 #[from]
698 LogEmit(LogEmit),
699}
700
701impl HostVm {
702 pub fn into_prototype(self) -> HostVmPrototype {
704 match self {
705 HostVm::ReadyToRun(inner) => inner.inner.into_prototype(),
706 HostVm::Finished(inner) => inner.inner.into_prototype(),
707 HostVm::Error { prototype, .. } => prototype,
708 HostVm::ExternalStorageGet(inner) => inner.inner.into_prototype(),
709 HostVm::ExternalStorageSet(inner) => inner.inner.into_prototype(),
710 HostVm::ExternalStorageAppend(inner) => inner.inner.into_prototype(),
711 HostVm::ExternalStorageClearPrefix(inner) => inner.inner.into_prototype(),
712 HostVm::ExternalStorageRoot(inner) => inner.inner.into_prototype(),
713 HostVm::ExternalStorageNextKey(inner) => inner.inner.into_prototype(),
714 HostVm::ExternalOffchainIndexSet(inner) => inner.inner.into_prototype(),
715 HostVm::ExternalOffchainStorageGet(inner) => inner.inner.into_prototype(),
716 HostVm::ExternalOffchainStorageSet(inner) => inner.inner.into_prototype(),
717 HostVm::OffchainTimestamp(inner) => inner.inner.into_prototype(),
718 HostVm::OffchainRandomSeed(inner) => inner.inner.into_prototype(),
719 HostVm::OffchainSubmitTransaction(inner) => inner.inner.into_prototype(),
720 HostVm::SignatureVerification(inner) => inner.inner.into_prototype(),
721 HostVm::CallRuntimeVersion(inner) => inner.inner.into_prototype(),
722 HostVm::StartStorageTransaction(inner) => inner.inner.into_prototype(),
723 HostVm::EndStorageTransaction { resume, .. } => resume.inner.into_prototype(),
724 HostVm::GetMaxLogLevel(inner) => inner.inner.into_prototype(),
725 HostVm::LogEmit(inner) => inner.inner.into_prototype(),
726 }
727 }
728}
729
730pub struct ReadyToRun {
732 inner: Box<Inner>,
733 resume_value: Option<vm::WasmValue>,
734}
735
736impl ReadyToRun {
737 pub fn run(mut self) -> HostVm {
741 loop {
742 match self.run_once() {
743 HostVm::ReadyToRun(r) => self = r,
744 other => return other,
745 }
746 }
747 }
748
749 fn run_once(mut self) -> HostVm {
750 let (id, params) = match self.inner.vm.run(self.resume_value) {
753 Ok(vm::ExecOutcome::Interrupted { id, params }) => (id, params),
754
755 Ok(vm::ExecOutcome::Finished {
756 return_value: Ok(Some(vm::WasmValue::I64(ret))),
757 }) => {
758 if self.inner.storage_transaction_depth > 0 {
761 return HostVm::Error {
762 prototype: self.inner.into_prototype(),
763 error: Error::FinishedWithPendingTransaction,
764 };
765 }
766
767 let ret = u64::from_ne_bytes(ret.to_ne_bytes());
769
770 let value_size = u32::try_from(ret >> 32).unwrap_or_else(|_| unreachable!());
774 let value_ptr = u32::try_from(ret & 0xffff_ffff).unwrap_or_else(|_| unreachable!());
775
776 if value_size.saturating_add(value_ptr)
777 <= u32::from(self.inner.vm.memory_size()) * 64 * 1024
778 {
779 return HostVm::Finished(Finished {
780 inner: self.inner,
781 value_ptr,
782 value_size,
783 });
784 }
785 let error = Error::ReturnedPtrOutOfRange {
786 pointer: value_ptr,
787 size: value_size,
788 memory_size: u32::from(self.inner.vm.memory_size()) * 64 * 1024,
789 };
790
791 return HostVm::Error {
792 prototype: self.inner.into_prototype(),
793 error,
794 };
795 }
796
797 Ok(vm::ExecOutcome::Finished {
798 return_value: Ok(return_value),
799 }) => {
800 return HostVm::Error {
803 prototype: self.inner.into_prototype(),
804 error: Error::BadReturnValue {
805 actual: return_value.map(|v| v.ty()),
806 },
807 };
808 }
809
810 Ok(vm::ExecOutcome::Finished {
811 return_value: Err(err),
812 }) => {
813 return HostVm::Error {
814 error: Error::Trap(err),
815 prototype: self.inner.into_prototype(),
816 };
817 }
818
819 Err(vm::RunErr::BadValueTy { .. }) => {
820 unreachable!()
824 }
825
826 Err(vm::RunErr::Poisoned) => {
827 unreachable!()
829 }
830 };
831
832 let host_fn = match self.inner.common.registered_functions.get(id) {
835 Some(FunctionImport::Resolved(f)) => *f,
836 Some(FunctionImport::Unresolved { name, module }) => {
837 return HostVm::Error {
838 error: Error::UnresolvedFunctionCalled {
839 function: name.clone(),
840 module_name: module.clone(),
841 },
842 prototype: self.inner.into_prototype(),
843 };
844 }
845 None => unreachable!(),
846 };
847
848 macro_rules! expect_pointer_size {
850 ($num:expr) => {{
851 let val = match ¶ms[$num] {
852 vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
853 _ => unreachable!(),
856 };
857
858 let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
859 let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
860
861 let result = self.inner.vm.read_memory(ptr, len);
862 match result {
863 Ok(v) => v,
864 Err(vm::OutOfBoundsError) => {
865 drop(result);
866 return HostVm::Error {
867 error: Error::ParamOutOfRange {
868 function: host_fn.name(),
869 param_num: $num,
870 pointer: ptr,
871 length: len,
872 },
873 prototype: self.inner.into_prototype(),
874 };
875 }
876 }
877 }};
878 }
879
880 macro_rules! expect_pointer_size_raw {
881 ($num:expr) => {{
882 let val = match ¶ms[$num] {
883 vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
884 _ => unreachable!(),
887 };
888
889 let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
890 let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
891
892 if len.saturating_add(ptr) > u32::from(self.inner.vm.memory_size()) * 64 * 1024 {
893 return HostVm::Error {
894 error: Error::ParamOutOfRange {
895 function: host_fn.name(),
896 param_num: $num,
897 pointer: ptr,
898 length: len,
899 },
900 prototype: self.inner.into_prototype(),
901 };
902 }
903
904 (ptr, len)
905 }};
906 }
907
908 macro_rules! expect_pointer_constant_size {
909 ($num:expr, $size:expr) => {{
910 let ptr = match params[$num] {
911 vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
912 _ => unreachable!(),
915 };
916
917 let result = self.inner.vm.read_memory(ptr, $size);
918 match result {
919 Ok(v) => {
920 *<&[u8; $size]>::try_from(v.as_ref()).unwrap_or_else(|_| unreachable!())
921 }
922 Err(vm::OutOfBoundsError) => {
923 drop(result);
924 return HostVm::Error {
925 error: Error::ParamOutOfRange {
926 function: host_fn.name(),
927 param_num: $num,
928 pointer: ptr,
929 length: $size,
930 },
931 prototype: self.inner.into_prototype(),
932 };
933 }
934 }
935 }};
936 }
937
938 macro_rules! expect_pointer_constant_size_raw {
939 ($num:expr, $size:expr) => {{
940 let ptr = match params[$num] {
941 vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
942 _ => unreachable!(),
945 };
946
947 if u32::saturating_add($size, ptr)
948 > u32::from(self.inner.vm.memory_size()) * 64 * 1024
949 {
950 return HostVm::Error {
951 error: Error::ParamOutOfRange {
952 function: host_fn.name(),
953 param_num: $num,
954 pointer: ptr,
955 length: $size,
956 },
957 prototype: self.inner.into_prototype(),
958 };
959 }
960
961 ptr
962 }};
963 }
964
965 macro_rules! expect_u32 {
966 ($num:expr) => {{
967 match ¶ms[$num] {
968 vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
969 _ => unreachable!(),
972 }
973 }};
974 }
975
976 macro_rules! expect_offchain_storage_kind {
977 ($num:expr) => {{
978 match ¶ms[$num] {
979 vm::WasmValue::I32(0) => true,
982 vm::WasmValue::I32(1) => false,
985 vm::WasmValue::I32(_) => {
986 return HostVm::Error {
987 error: Error::ParamDecodeError,
988 prototype: self.inner.into_prototype(),
989 };
990 }
991 _ => unreachable!(),
994 }
995 }};
996 }
997
998 macro_rules! expect_state_version {
999 ($num:expr) => {{
1000 match ¶ms[$num] {
1001 vm::WasmValue::I32(0) => TrieEntryVersion::V0,
1002 vm::WasmValue::I32(1) => TrieEntryVersion::V1,
1003 vm::WasmValue::I32(_) => {
1004 return HostVm::Error {
1005 error: Error::ParamDecodeError,
1006 prototype: self.inner.into_prototype(),
1007 };
1008 }
1009 _ => unreachable!(),
1012 }
1013 }};
1014 }
1015
1016 macro_rules! host_fn_not_implemented {
1018 () => {{
1019 return HostVm::Error {
1020 error: Error::HostFunctionNotImplemented {
1021 function: host_fn.name(),
1022 },
1023 prototype: self.inner.into_prototype(),
1024 };
1025 }};
1026 }
1027
1028 match host_fn {
1032 HostFunction::ext_storage_set_version_1 => {
1033 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1034 let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1035 HostVm::ExternalStorageSet(ExternalStorageSet {
1036 key_ptr,
1037 key_size,
1038 child_trie_ptr_size: None,
1039 value: Some((value_ptr, value_size)),
1040 inner: self.inner,
1041 })
1042 }
1043 HostFunction::ext_storage_get_version_1 => {
1044 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1045 HostVm::ExternalStorageGet(ExternalStorageGet {
1046 key_ptr,
1047 key_size,
1048 child_trie_ptr_size: None,
1049 calling: id,
1050 value_out_ptr: None,
1051 offset: 0,
1052 max_size: u32::MAX,
1053 inner: self.inner,
1054 })
1055 }
1056 HostFunction::ext_storage_read_version_1 => {
1057 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1058 let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(1);
1059 let offset = expect_u32!(2);
1060 HostVm::ExternalStorageGet(ExternalStorageGet {
1061 key_ptr,
1062 key_size,
1063 child_trie_ptr_size: None,
1064 calling: id,
1065 value_out_ptr: Some(value_out_ptr),
1066 offset,
1067 max_size: value_out_size,
1068 inner: self.inner,
1069 })
1070 }
1071 HostFunction::ext_storage_clear_version_1 => {
1072 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1073 HostVm::ExternalStorageSet(ExternalStorageSet {
1074 key_ptr,
1075 key_size,
1076 child_trie_ptr_size: None,
1077 value: None,
1078 inner: self.inner,
1079 })
1080 }
1081 HostFunction::ext_storage_exists_version_1 => {
1082 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1083 HostVm::ExternalStorageGet(ExternalStorageGet {
1084 key_ptr,
1085 key_size,
1086 child_trie_ptr_size: None,
1087 calling: id,
1088 value_out_ptr: None,
1089 offset: 0,
1090 max_size: 0,
1091 inner: self.inner,
1092 })
1093 }
1094 HostFunction::ext_storage_clear_prefix_version_1 => {
1095 let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1096 HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1097 prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1098 child_trie_ptr_size: None,
1099 inner: self.inner,
1100 max_keys_to_remove: None,
1101 calling: id,
1102 })
1103 }
1104 HostFunction::ext_storage_clear_prefix_version_2 => {
1105 let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1106
1107 let max_keys_to_remove = {
1108 let input = expect_pointer_size!(1);
1109 let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1110 nom::Parser::parse(
1111 &mut nom::combinator::all_consuming(util::nom_option_decode(
1112 nom::number::streaming::le_u32,
1113 )),
1114 input.as_ref(),
1115 )
1116 .map(|(_, parse_result)| parse_result);
1117
1118 match parsing_result {
1119 Ok(val) => Ok(val),
1120 Err(_) => Err(()),
1121 }
1122 };
1123
1124 let max_keys_to_remove = match max_keys_to_remove {
1125 Ok(l) => l,
1126 Err(()) => {
1127 return HostVm::Error {
1128 error: Error::ParamDecodeError,
1129 prototype: self.inner.into_prototype(),
1130 };
1131 }
1132 };
1133
1134 HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1135 prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1136 child_trie_ptr_size: None,
1137 inner: self.inner,
1138 max_keys_to_remove,
1139 calling: id,
1140 })
1141 }
1142 HostFunction::ext_storage_root_version_1 => {
1143 HostVm::ExternalStorageRoot(ExternalStorageRoot {
1144 inner: self.inner,
1145 calling: id,
1146 child_trie_ptr_size: None,
1147 })
1148 }
1149 HostFunction::ext_storage_root_version_2 => {
1150 let version_param = expect_state_version!(0);
1156 let version_spec = self
1157 .inner
1158 .common
1159 .runtime_version
1160 .as_ref()
1161 .unwrap_or_else(|| unreachable!())
1162 .decode()
1163 .state_version
1164 .unwrap_or(TrieEntryVersion::V0);
1165
1166 if version_param != version_spec {
1167 return HostVm::Error {
1168 error: Error::StateVersionMismatch {
1169 parameter: version_param,
1170 specification: version_spec,
1171 },
1172 prototype: self.inner.into_prototype(),
1173 };
1174 }
1175
1176 HostVm::ExternalStorageRoot(ExternalStorageRoot {
1177 inner: self.inner,
1178 calling: id,
1179 child_trie_ptr_size: None,
1180 })
1181 }
1182 HostFunction::ext_storage_changes_root_version_1 => {
1183 self.inner.alloc_write_and_return_pointer_size(
1193 HostFunction::ext_storage_changes_root_version_1.name(),
1194 iter::once(&[0][..]),
1195 )
1196 }
1197 HostFunction::ext_storage_next_key_version_1 => {
1198 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1199 HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1200 key_ptr,
1201 key_size,
1202 child_trie_ptr_size: None,
1203 inner: self.inner,
1204 })
1205 }
1206 HostFunction::ext_storage_append_version_1 => {
1207 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1208 let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1209 HostVm::ExternalStorageAppend(ExternalStorageAppend {
1210 key_ptr,
1211 key_size,
1212 value_ptr,
1213 value_size,
1214 inner: self.inner,
1215 })
1216 }
1217 HostFunction::ext_storage_start_transaction_version_1 => {
1218 self.inner.storage_transaction_depth += 1;
1220 HostVm::StartStorageTransaction(StartStorageTransaction { inner: self.inner })
1221 }
1222 HostFunction::ext_storage_rollback_transaction_version_1 => {
1223 if self.inner.storage_transaction_depth == 0 {
1224 return HostVm::Error {
1225 error: Error::NoActiveTransaction,
1226 prototype: self.inner.into_prototype(),
1227 };
1228 }
1229
1230 self.inner.storage_transaction_depth -= 1;
1231 HostVm::EndStorageTransaction {
1232 resume: EndStorageTransaction { inner: self.inner },
1233 rollback: true,
1234 }
1235 }
1236 HostFunction::ext_storage_commit_transaction_version_1 => {
1237 if self.inner.storage_transaction_depth == 0 {
1238 return HostVm::Error {
1239 error: Error::NoActiveTransaction,
1240 prototype: self.inner.into_prototype(),
1241 };
1242 }
1243
1244 self.inner.storage_transaction_depth -= 1;
1245 HostVm::EndStorageTransaction {
1246 resume: EndStorageTransaction { inner: self.inner },
1247 rollback: false,
1248 }
1249 }
1250 HostFunction::ext_storage_proof_size_storage_proof_size_version_1 => {
1251 match self.inner.storage_proof_size_behavior {
1252 StorageProofSizeBehavior::ConstantReturnValue(value) => {
1253 HostVm::ReadyToRun(ReadyToRun {
1254 inner: self.inner,
1255 resume_value: Some(vm::WasmValue::I64(i64::from_ne_bytes(
1256 value.to_ne_bytes(),
1257 ))),
1258 })
1259 }
1260 StorageProofSizeBehavior::Unimplemented => HostVm::Error {
1261 error: Error::HostFunctionNotImplemented {
1262 function: host_fn.name(),
1263 },
1264 prototype: self.inner.into_prototype(),
1265 },
1266 }
1267 }
1268 HostFunction::ext_default_child_storage_get_version_1 => {
1269 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1270 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1271 HostVm::ExternalStorageGet(ExternalStorageGet {
1272 key_ptr,
1273 key_size,
1274 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1275 calling: id,
1276 value_out_ptr: None,
1277 offset: 0,
1278 max_size: u32::MAX,
1279 inner: self.inner,
1280 })
1281 }
1282 HostFunction::ext_default_child_storage_read_version_1 => {
1283 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1284 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1285 let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(2);
1286 let offset = expect_u32!(3);
1287 HostVm::ExternalStorageGet(ExternalStorageGet {
1288 key_ptr,
1289 key_size,
1290 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1291 calling: id,
1292 value_out_ptr: Some(value_out_ptr),
1293 offset,
1294 max_size: value_out_size,
1295 inner: self.inner,
1296 })
1297 }
1298 HostFunction::ext_default_child_storage_storage_kill_version_1 => {
1299 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1300 HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1301 prefix_ptr_size: None,
1302 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1303 inner: self.inner,
1304 max_keys_to_remove: None,
1305 calling: id,
1306 })
1307 }
1308 HostFunction::ext_default_child_storage_storage_kill_version_2
1309 | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
1310 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1311
1312 let max_keys_to_remove = {
1313 let input = expect_pointer_size!(1);
1314 let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1315 nom::Parser::parse(
1316 &mut nom::combinator::all_consuming(util::nom_option_decode(
1317 nom::number::streaming::le_u32,
1318 )),
1319 input.as_ref(),
1320 )
1321 .map(|(_, parse_result)| parse_result);
1322
1323 match parsing_result {
1324 Ok(val) => Ok(val),
1325 Err(_) => Err(()),
1326 }
1327 };
1328
1329 let max_keys_to_remove = match max_keys_to_remove {
1330 Ok(l) => l,
1331 Err(()) => {
1332 return HostVm::Error {
1333 error: Error::ParamDecodeError,
1334 prototype: self.inner.into_prototype(),
1335 };
1336 }
1337 };
1338
1339 HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1340 prefix_ptr_size: None,
1341 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1342 inner: self.inner,
1343 max_keys_to_remove,
1344 calling: id,
1345 })
1346 }
1347 HostFunction::ext_default_child_storage_clear_prefix_version_1 => {
1348 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1349 let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1350 HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1351 prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1352 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1353 inner: self.inner,
1354 max_keys_to_remove: None,
1355 calling: id,
1356 })
1357 }
1358 HostFunction::ext_default_child_storage_clear_prefix_version_2 => {
1359 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1360 let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1361
1362 let max_keys_to_remove = {
1363 let input = expect_pointer_size!(2);
1364 let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1365 nom::Parser::parse(
1366 &mut nom::combinator::all_consuming(util::nom_option_decode(
1367 nom::number::streaming::le_u32,
1368 )),
1369 input.as_ref(),
1370 )
1371 .map(|(_, parse_result)| parse_result);
1372
1373 match parsing_result {
1374 Ok(val) => Ok(val),
1375 Err(_) => Err(()),
1376 }
1377 };
1378
1379 let max_keys_to_remove = match max_keys_to_remove {
1380 Ok(l) => l,
1381 Err(()) => {
1382 return HostVm::Error {
1383 error: Error::ParamDecodeError,
1384 prototype: self.inner.into_prototype(),
1385 };
1386 }
1387 };
1388
1389 HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1390 prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1391 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1392 inner: self.inner,
1393 max_keys_to_remove,
1394 calling: id,
1395 })
1396 }
1397 HostFunction::ext_default_child_storage_set_version_1 => {
1398 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1399 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1400 let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1401 HostVm::ExternalStorageSet(ExternalStorageSet {
1402 key_ptr,
1403 key_size,
1404 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1405 value: Some((value_ptr, value_size)),
1406 inner: self.inner,
1407 })
1408 }
1409 HostFunction::ext_default_child_storage_clear_version_1 => {
1410 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1411 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1412 HostVm::ExternalStorageSet(ExternalStorageSet {
1413 key_ptr,
1414 key_size,
1415 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1416 value: None,
1417 inner: self.inner,
1418 })
1419 }
1420 HostFunction::ext_default_child_storage_exists_version_1 => {
1421 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1422 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1423 HostVm::ExternalStorageGet(ExternalStorageGet {
1424 key_ptr,
1425 key_size,
1426 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1427 calling: id,
1428 value_out_ptr: None,
1429 offset: 0,
1430 max_size: 0,
1431 inner: self.inner,
1432 })
1433 }
1434 HostFunction::ext_default_child_storage_next_key_version_1 => {
1435 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1436 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1437 HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1438 key_ptr,
1439 key_size,
1440 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1441 inner: self.inner,
1442 })
1443 }
1444 HostFunction::ext_default_child_storage_root_version_1 => {
1445 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1446 HostVm::ExternalStorageRoot(ExternalStorageRoot {
1447 inner: self.inner,
1448 calling: id,
1449 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1450 })
1451 }
1452 HostFunction::ext_default_child_storage_root_version_2 => {
1453 let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1454
1455 let version_param = expect_state_version!(1);
1461 let version_spec = self
1462 .inner
1463 .common
1464 .runtime_version
1465 .as_ref()
1466 .unwrap_or_else(|| unreachable!())
1467 .decode()
1468 .state_version
1469 .unwrap_or(TrieEntryVersion::V0);
1470
1471 if version_param != version_spec {
1472 return HostVm::Error {
1473 error: Error::StateVersionMismatch {
1474 parameter: version_param,
1475 specification: version_spec,
1476 },
1477 prototype: self.inner.into_prototype(),
1478 };
1479 }
1480
1481 HostVm::ExternalStorageRoot(ExternalStorageRoot {
1482 inner: self.inner,
1483 calling: id,
1484 child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1485 })
1486 }
1487 HostFunction::ext_crypto_ed25519_public_keys_version_1 => host_fn_not_implemented!(),
1488 HostFunction::ext_crypto_ed25519_generate_version_1 => host_fn_not_implemented!(),
1489 HostFunction::ext_crypto_ed25519_sign_version_1 => host_fn_not_implemented!(),
1490 HostFunction::ext_crypto_ed25519_verify_version_1
1491 | HostFunction::ext_crypto_ed25519_batch_verify_version_1 => {
1492 let is_batch_verification = matches!(
1493 host_fn,
1494 HostFunction::ext_crypto_ed25519_batch_verify_version_1
1495 );
1496
1497 if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1498 return HostVm::Error {
1499 error: Error::BatchVerifyWithoutStarting,
1500 prototype: self.inner.into_prototype(),
1501 };
1502 }
1503
1504 let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1505 HostVm::SignatureVerification(SignatureVerification {
1506 algorithm: SignatureVerificationAlgorithm::Ed25519,
1507 signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1508 public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1509 message_ptr,
1510 message_size,
1511 inner: self.inner,
1512 is_batch_verification,
1513 })
1514 }
1515 HostFunction::ext_crypto_sr25519_public_keys_version_1 => host_fn_not_implemented!(),
1516 HostFunction::ext_crypto_sr25519_generate_version_1 => host_fn_not_implemented!(),
1517 HostFunction::ext_crypto_sr25519_sign_version_1 => host_fn_not_implemented!(),
1518 HostFunction::ext_crypto_sr25519_verify_version_1
1519 | HostFunction::ext_crypto_sr25519_batch_verify_version_1 => {
1520 let is_batch_verification = matches!(
1521 host_fn,
1522 HostFunction::ext_crypto_sr25519_batch_verify_version_1
1523 );
1524
1525 if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1526 return HostVm::Error {
1527 error: Error::BatchVerifyWithoutStarting,
1528 prototype: self.inner.into_prototype(),
1529 };
1530 }
1531
1532 let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1533 HostVm::SignatureVerification(SignatureVerification {
1534 algorithm: SignatureVerificationAlgorithm::Sr25519V1,
1535 signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1536 public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1537 message_ptr,
1538 message_size,
1539 inner: self.inner,
1540 is_batch_verification,
1541 })
1542 }
1543 HostFunction::ext_crypto_sr25519_verify_version_2 => {
1544 let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1545 HostVm::SignatureVerification(SignatureVerification {
1546 algorithm: SignatureVerificationAlgorithm::Sr25519V2,
1547 signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1548 public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1549 message_ptr,
1550 message_size,
1551 inner: self.inner,
1552 is_batch_verification: false,
1553 })
1554 }
1555 HostFunction::ext_crypto_ecdsa_generate_version_1 => host_fn_not_implemented!(),
1556 HostFunction::ext_crypto_ecdsa_sign_version_1 => {
1557 let data = <[u8; 32]>::try_from(
1559 blake2_rfc::blake2b::blake2b(32, &[], expect_pointer_size!(0).as_ref())
1560 .as_bytes(),
1561 )
1562 .unwrap_or_else(|_| unreachable!());
1563 let message = libsecp256k1::Message::parse(&data);
1564
1565 if let Ok(sc) =
1566 libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1567 {
1568 let (sig, ri) = libsecp256k1::sign(&message, &sc);
1569
1570 self.inner.alloc_write_and_return_pointer(
1572 host_fn.name(),
1573 [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1574 )
1575 } else {
1576 HostVm::Error {
1577 error: Error::ParamDecodeError,
1578 prototype: self.inner.into_prototype(),
1579 }
1580 }
1581 }
1582 HostFunction::ext_crypto_ecdsa_public_keys_version_1 => host_fn_not_implemented!(),
1583 HostFunction::ext_crypto_ecdsa_verify_version_1
1584 | HostFunction::ext_crypto_ecdsa_batch_verify_version_1 => {
1585 let is_batch_verification = matches!(
1586 host_fn,
1587 HostFunction::ext_crypto_ecdsa_batch_verify_version_1
1588 );
1589
1590 if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1591 return HostVm::Error {
1592 error: Error::BatchVerifyWithoutStarting,
1593 prototype: self.inner.into_prototype(),
1594 };
1595 }
1596
1597 let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1598 HostVm::SignatureVerification(SignatureVerification {
1599 algorithm: SignatureVerificationAlgorithm::Ecdsa,
1600 signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1601 public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1602 message_ptr,
1603 message_size,
1604 inner: self.inner,
1605 is_batch_verification,
1606 })
1607 }
1608 HostFunction::ext_crypto_ecdsa_verify_version_2 => host_fn_not_implemented!(),
1609 HostFunction::ext_crypto_ecdsa_sign_prehashed_version_1 => {
1610 let message = libsecp256k1::Message::parse(&expect_pointer_constant_size!(0, 32));
1612
1613 if let Ok(sc) =
1614 libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1615 {
1616 let (sig, ri) = libsecp256k1::sign(&message, &sc);
1617
1618 self.inner.alloc_write_and_return_pointer(
1620 host_fn.name(),
1621 [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1622 )
1623 } else {
1624 HostVm::Error {
1625 error: Error::ParamDecodeError,
1626 prototype: self.inner.into_prototype(),
1627 }
1628 }
1629 }
1630 HostFunction::ext_crypto_ecdsa_verify_prehashed_version_1 => {
1631 HostVm::SignatureVerification(SignatureVerification {
1632 algorithm: SignatureVerificationAlgorithm::EcdsaPrehashed,
1633 signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1634 public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1635 message_ptr: expect_pointer_constant_size_raw!(1, 32),
1636 message_size: 32,
1637 inner: self.inner,
1638 is_batch_verification: false,
1639 })
1640 }
1641
1642 HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_1
1643 | HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2 => {
1644 let sig = expect_pointer_constant_size!(0, 65);
1645 let msg = expect_pointer_constant_size!(1, 32);
1646 let is_v2 = matches!(
1647 host_fn,
1648 HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2
1649 );
1650
1651 let result = {
1652 let rs = if is_v2 {
1653 libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1654 } else {
1655 libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1656 };
1657
1658 if let Ok(rs) = rs {
1659 let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1660 sig[64] - 27
1661 } else {
1662 sig[64]
1663 });
1664
1665 if let Ok(v) = v {
1666 let pubkey = libsecp256k1::recover(
1667 &libsecp256k1::Message::parse_slice(&msg)
1668 .unwrap_or_else(|_| unreachable!()),
1669 &rs,
1670 &v,
1671 );
1672
1673 if let Ok(pubkey) = pubkey {
1674 let mut res = Vec::with_capacity(65);
1675 res.push(0);
1676 res.extend_from_slice(&pubkey.serialize()[1..65]);
1677 res
1678 } else {
1679 vec![1, 2]
1680 }
1681 } else {
1682 vec![1, 1]
1683 }
1684 } else {
1685 vec![1, 0]
1686 }
1687 };
1688
1689 self.inner
1690 .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1691 }
1692 HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_1
1693 | HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2 => {
1694 let sig = expect_pointer_constant_size!(0, 65);
1695 let msg = expect_pointer_constant_size!(1, 32);
1696 let is_v2 = matches!(
1697 host_fn,
1698 HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2
1699 );
1700
1701 let result = {
1702 let rs = if is_v2 {
1703 libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1704 } else {
1705 libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1706 };
1707
1708 if let Ok(rs) = rs {
1709 let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1710 sig[64] - 27
1711 } else {
1712 sig[64]
1713 });
1714
1715 if let Ok(v) = v {
1716 let pubkey = libsecp256k1::recover(
1717 &libsecp256k1::Message::parse_slice(&msg)
1718 .unwrap_or_else(|_| unreachable!()),
1719 &rs,
1720 &v,
1721 );
1722
1723 if let Ok(pubkey) = pubkey {
1724 let mut res = Vec::with_capacity(34);
1725 res.push(0);
1726 res.extend_from_slice(&pubkey.serialize_compressed());
1727 res
1728 } else {
1729 vec![1, 2]
1730 }
1731 } else {
1732 vec![1, 1]
1733 }
1734 } else {
1735 vec![1, 0]
1736 }
1737 };
1738
1739 self.inner
1740 .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1741 }
1742 HostFunction::ext_crypto_start_batch_verify_version_1 => {
1743 if self.inner.signatures_batch_verification.is_some() {
1744 return HostVm::Error {
1745 error: Error::AlreadyBatchVerify,
1746 prototype: self.inner.into_prototype(),
1747 };
1748 }
1749
1750 self.inner.signatures_batch_verification = Some(true);
1751
1752 HostVm::ReadyToRun(ReadyToRun {
1753 resume_value: None,
1754 inner: self.inner,
1755 })
1756 }
1757 HostFunction::ext_crypto_finish_batch_verify_version_1 => {
1758 let Some(outcome) = self.inner.signatures_batch_verification.take() else {
1759 return HostVm::Error {
1760 error: Error::NoBatchVerify,
1761 prototype: self.inner.into_prototype(),
1762 };
1763 };
1764
1765 HostVm::ReadyToRun(ReadyToRun {
1766 resume_value: Some(vm::WasmValue::I32(if outcome { 1 } else { 0 })),
1767 inner: self.inner,
1768 })
1769 }
1770 HostFunction::ext_hashing_keccak_256_version_1 => {
1771 let hash =
1772 <sha3::Keccak256 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1773 self.inner
1774 .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1775 }
1776 HostFunction::ext_hashing_keccak_512_version_1 => {
1777 let hash =
1778 <sha3::Keccak512 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1779 self.inner
1780 .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1781 }
1782 HostFunction::ext_hashing_sha2_256_version_1 => {
1783 let hash = <sha2::Sha256 as sha2::Digest>::digest(expect_pointer_size!(0).as_ref());
1784 self.inner
1785 .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1786 }
1787 HostFunction::ext_hashing_blake2_128_version_1 => {
1788 let out = {
1789 let data = expect_pointer_size!(0);
1790 blake2_rfc::blake2b::blake2b(16, &[], data.as_ref())
1791 };
1792
1793 self.inner
1794 .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1795 }
1796 HostFunction::ext_hashing_blake2_256_version_1 => {
1797 let out = {
1798 let data = expect_pointer_size!(0);
1799 blake2_rfc::blake2b::blake2b(32, &[], data.as_ref())
1800 };
1801
1802 self.inner
1803 .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1804 }
1805 HostFunction::ext_hashing_twox_64_version_1 => {
1806 let r0 = {
1807 let data = expect_pointer_size!(0);
1808 twox_hash::XxHash64::oneshot(0, data.as_ref())
1809 };
1810
1811 self.inner
1812 .alloc_write_and_return_pointer(host_fn.name(), iter::once(&r0.to_le_bytes()))
1813 }
1814 HostFunction::ext_hashing_twox_128_version_1 => {
1815 let [r0, r1] = {
1816 let data = expect_pointer_size!(0);
1817 let data = data.as_ref();
1818 [
1819 twox_hash::XxHash64::oneshot(0, data),
1820 twox_hash::XxHash64::oneshot(1, data),
1821 ]
1822 };
1823
1824 self.inner.alloc_write_and_return_pointer(
1825 host_fn.name(),
1826 iter::once(&r0.to_le_bytes()).chain(iter::once(&r1.to_le_bytes())),
1827 )
1828 }
1829 HostFunction::ext_hashing_twox_256_version_1 => {
1830 let [r0, r1, r2, r3] = {
1831 let data = expect_pointer_size!(0);
1832 let data = data.as_ref();
1833 [
1834 twox_hash::XxHash64::oneshot(0, data),
1835 twox_hash::XxHash64::oneshot(1, data),
1836 twox_hash::XxHash64::oneshot(2, data),
1837 twox_hash::XxHash64::oneshot(3, data),
1838 ]
1839 };
1840
1841 self.inner.alloc_write_and_return_pointer(
1842 host_fn.name(),
1843 iter::once(&r0.to_le_bytes())
1844 .chain(iter::once(&r1.to_le_bytes()))
1845 .chain(iter::once(&r2.to_le_bytes()))
1846 .chain(iter::once(&r3.to_le_bytes())),
1847 )
1848 }
1849 HostFunction::ext_offchain_index_set_version_1 => {
1850 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1851 let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1852 HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1853 key_ptr,
1854 key_size,
1855 value: Some((value_ptr, value_size)),
1856 inner: self.inner,
1857 })
1858 }
1859 HostFunction::ext_offchain_index_clear_version_1 => {
1860 let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1861 HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1862 key_ptr,
1863 key_size,
1864 value: None,
1865 inner: self.inner,
1866 })
1867 }
1868 HostFunction::ext_offchain_is_validator_version_1 => HostVm::ReadyToRun(ReadyToRun {
1869 inner: self.inner,
1870 resume_value: Some(vm::WasmValue::I32(1)), }),
1872 HostFunction::ext_offchain_submit_transaction_version_1 => {
1873 let (tx_ptr, tx_size) = expect_pointer_size_raw!(0);
1874 HostVm::OffchainSubmitTransaction(OffchainSubmitTransaction {
1875 inner: self.inner,
1876 calling: id,
1877 tx_ptr,
1878 tx_size,
1879 })
1880 }
1881 HostFunction::ext_offchain_network_state_version_1 => {
1882 host_fn_not_implemented!()
1883 }
1884 HostFunction::ext_offchain_timestamp_version_1 => {
1885 HostVm::OffchainTimestamp(OffchainTimestamp { inner: self.inner })
1886 }
1887 HostFunction::ext_offchain_sleep_until_version_1 => {
1888 host_fn_not_implemented!()
1889 }
1890 HostFunction::ext_offchain_random_seed_version_1 => {
1891 HostVm::OffchainRandomSeed(OffchainRandomSeed {
1892 inner: self.inner,
1893 calling: id,
1894 })
1895 }
1896 HostFunction::ext_offchain_local_storage_set_version_1 => {
1897 if expect_offchain_storage_kind!(0) {
1898 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1899 let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1900 HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1901 key_ptr,
1902 key_size,
1903 value: Some((value_ptr, value_size)),
1904 old_value: None,
1905 inner: self.inner,
1906 })
1907 } else {
1908 HostVm::ReadyToRun(ReadyToRun {
1909 inner: self.inner,
1910 resume_value: None,
1911 })
1912 }
1913 }
1914 HostFunction::ext_offchain_local_storage_compare_and_set_version_1 => {
1915 if expect_offchain_storage_kind!(0) {
1916 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1917 let (old_value_ptr, old_value_size) = expect_pointer_size_raw!(2);
1918 let (value_ptr, value_size) = expect_pointer_size_raw!(3);
1919 HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1920 key_ptr,
1921 key_size,
1922 value: Some((value_ptr, value_size)),
1923 old_value: Some((old_value_ptr, old_value_size)),
1924 inner: self.inner,
1925 })
1926 } else {
1927 HostVm::ReadyToRun(ReadyToRun {
1928 inner: self.inner,
1929 resume_value: Some(vm::WasmValue::I32(0)),
1930 })
1931 }
1932 }
1933 HostFunction::ext_offchain_local_storage_get_version_1 => {
1934 if expect_offchain_storage_kind!(0) {
1935 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1936 HostVm::ExternalOffchainStorageGet(ExternalOffchainStorageGet {
1937 key_ptr,
1938 key_size,
1939 calling: id,
1940 inner: self.inner,
1941 })
1942 } else {
1943 self.inner
1945 .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
1946 }
1947 }
1948 HostFunction::ext_offchain_local_storage_clear_version_1 => {
1949 if expect_offchain_storage_kind!(0) {
1950 let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1951 HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1952 key_ptr,
1953 key_size,
1954 value: None,
1955 old_value: None,
1956 inner: self.inner,
1957 })
1958 } else {
1959 HostVm::ReadyToRun(ReadyToRun {
1960 inner: self.inner,
1961 resume_value: None,
1962 })
1963 }
1964 }
1965 HostFunction::ext_offchain_http_request_start_version_1 => host_fn_not_implemented!(),
1966 HostFunction::ext_offchain_http_request_add_header_version_1 => {
1967 host_fn_not_implemented!()
1968 }
1969 HostFunction::ext_offchain_http_request_write_body_version_1 => {
1970 host_fn_not_implemented!()
1971 }
1972 HostFunction::ext_offchain_http_response_wait_version_1 => host_fn_not_implemented!(),
1973 HostFunction::ext_offchain_http_response_headers_version_1 => {
1974 host_fn_not_implemented!()
1975 }
1976 HostFunction::ext_offchain_http_response_read_body_version_1 => {
1977 host_fn_not_implemented!()
1978 }
1979 HostFunction::ext_trie_blake2_256_root_version_1
1980 | HostFunction::ext_trie_blake2_256_root_version_2
1981 | HostFunction::ext_trie_keccak_256_root_version_1
1982 | HostFunction::ext_trie_keccak_256_root_version_2 => {
1983 let state_version = if matches!(
1984 host_fn,
1985 HostFunction::ext_trie_blake2_256_root_version_2
1986 | HostFunction::ext_trie_keccak_256_root_version_2
1987 ) {
1988 expect_state_version!(1)
1989 } else {
1990 TrieEntryVersion::V0
1991 };
1992
1993 let result = {
1994 let input = expect_pointer_size!(0);
1995 let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1996 nom::Parser::parse(
1997 &mut nom::combinator::all_consuming(nom::combinator::flat_map(
1998 crate::util::nom_scale_compact_usize,
1999 |num_elems| {
2000 nom::multi::many_m_n(
2001 num_elems,
2002 num_elems,
2003 (
2004 nom::combinator::flat_map(
2005 crate::util::nom_scale_compact_usize,
2006 nom::bytes::streaming::take,
2007 ),
2008 nom::combinator::flat_map(
2009 crate::util::nom_scale_compact_usize,
2010 nom::bytes::streaming::take,
2011 ),
2012 ),
2013 )
2014 },
2015 )),
2016 input.as_ref(),
2017 )
2018 .map(|(_, parse_result)| parse_result);
2019
2020 match parsing_result {
2021 Ok(elements) => Ok(trie::trie_root(
2022 state_version,
2023 if matches!(
2024 host_fn,
2025 HostFunction::ext_trie_blake2_256_root_version_1
2026 | HostFunction::ext_trie_blake2_256_root_version_2
2027 ) {
2028 trie::HashFunction::Blake2
2029 } else {
2030 trie::HashFunction::Keccak256
2031 },
2032 &elements[..],
2033 )),
2034 Err(_) => Err(()),
2035 }
2036 };
2037
2038 match result {
2039 Ok(out) => self
2040 .inner
2041 .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2042 Err(()) => HostVm::Error {
2043 error: Error::ParamDecodeError,
2044 prototype: self.inner.into_prototype(),
2045 },
2046 }
2047 }
2048 HostFunction::ext_trie_blake2_256_ordered_root_version_1
2049 | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2050 | HostFunction::ext_trie_keccak_256_ordered_root_version_1
2051 | HostFunction::ext_trie_keccak_256_ordered_root_version_2 => {
2052 let state_version = if matches!(
2053 host_fn,
2054 HostFunction::ext_trie_blake2_256_ordered_root_version_2
2055 | HostFunction::ext_trie_keccak_256_ordered_root_version_2
2056 ) {
2057 expect_state_version!(1)
2058 } else {
2059 TrieEntryVersion::V0
2060 };
2061
2062 let result = {
2063 let input = expect_pointer_size!(0);
2064 let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
2065 nom::Parser::parse(
2066 &mut nom::combinator::all_consuming(nom::combinator::flat_map(
2067 crate::util::nom_scale_compact_usize,
2068 |num_elems| {
2069 nom::multi::many_m_n(
2070 num_elems,
2071 num_elems,
2072 nom::combinator::flat_map(
2073 crate::util::nom_scale_compact_usize,
2074 nom::bytes::streaming::take,
2075 ),
2076 )
2077 },
2078 )),
2079 input.as_ref(),
2080 )
2081 .map(|(_, parse_result)| parse_result);
2082
2083 match parsing_result {
2084 Ok(elements) => Ok(trie::ordered_root(
2085 state_version,
2086 if matches!(
2087 host_fn,
2088 HostFunction::ext_trie_blake2_256_ordered_root_version_1
2089 | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2090 ) {
2091 trie::HashFunction::Blake2
2092 } else {
2093 trie::HashFunction::Keccak256
2094 },
2095 &elements[..],
2096 )),
2097 Err(_) => Err(()),
2098 }
2099 };
2100
2101 match result {
2102 Ok(out) => self
2103 .inner
2104 .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2105 Err(()) => HostVm::Error {
2106 error: Error::ParamDecodeError,
2107 prototype: self.inner.into_prototype(),
2108 },
2109 }
2110 }
2111 HostFunction::ext_trie_blake2_256_verify_proof_version_1 => host_fn_not_implemented!(),
2112 HostFunction::ext_trie_blake2_256_verify_proof_version_2 => host_fn_not_implemented!(),
2113 HostFunction::ext_trie_keccak_256_verify_proof_version_1 => host_fn_not_implemented!(),
2114 HostFunction::ext_trie_keccak_256_verify_proof_version_2 => host_fn_not_implemented!(),
2115 HostFunction::ext_misc_print_num_version_1 => {
2116 let num = match params[0] {
2117 vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
2118 _ => unreachable!(),
2121 };
2122
2123 HostVm::LogEmit(LogEmit {
2124 inner: self.inner,
2125 log_entry: LogEmitInner::Num(num),
2126 })
2127 }
2128 HostFunction::ext_misc_print_utf8_version_1 => {
2129 let (str_ptr, str_size) = expect_pointer_size_raw!(0);
2130
2131 let utf8_check = str::from_utf8(
2132 self.inner
2133 .vm
2134 .read_memory(str_ptr, str_size)
2135 .unwrap_or_else(|_| unreachable!())
2136 .as_ref(),
2137 )
2138 .map(|_| ());
2139 if let Err(error) = utf8_check {
2140 return HostVm::Error {
2141 error: Error::Utf8Error {
2142 function: host_fn.name(),
2143 param_num: 2,
2144 error,
2145 },
2146 prototype: self.inner.into_prototype(),
2147 };
2148 }
2149
2150 HostVm::LogEmit(LogEmit {
2151 inner: self.inner,
2152 log_entry: LogEmitInner::Utf8 { str_ptr, str_size },
2153 })
2154 }
2155 HostFunction::ext_misc_print_hex_version_1 => {
2156 let (data_ptr, data_size) = expect_pointer_size_raw!(0);
2157 HostVm::LogEmit(LogEmit {
2158 inner: self.inner,
2159 log_entry: LogEmitInner::Hex {
2160 data_ptr,
2161 data_size,
2162 },
2163 })
2164 }
2165 HostFunction::ext_misc_runtime_version_version_1 => {
2166 let (wasm_blob_ptr, wasm_blob_size) = expect_pointer_size_raw!(0);
2167 HostVm::CallRuntimeVersion(CallRuntimeVersion {
2168 inner: self.inner,
2169 wasm_blob_ptr,
2170 wasm_blob_size,
2171 })
2172 }
2173 HostFunction::ext_allocator_malloc_version_1 => {
2174 let size = expect_u32!(0);
2175
2176 let ptr = match self.inner.alloc(host_fn.name(), size) {
2177 Ok(p) => p,
2178 Err(error) => {
2179 return HostVm::Error {
2180 error,
2181 prototype: self.inner.into_prototype(),
2182 };
2183 }
2184 };
2185
2186 let ptr_i32 = i32::from_ne_bytes(ptr.to_ne_bytes());
2187 HostVm::ReadyToRun(ReadyToRun {
2188 resume_value: Some(vm::WasmValue::I32(ptr_i32)),
2189 inner: self.inner,
2190 })
2191 }
2192 HostFunction::ext_allocator_free_version_1 => {
2193 let pointer = expect_u32!(0);
2194 match self.inner.allocator.deallocate(
2195 &mut MemAccess {
2196 vm: MemAccessVm::Running(&mut self.inner.vm),
2197 memory_total_pages: self.inner.common.memory_total_pages,
2198 },
2199 pointer,
2200 ) {
2201 Ok(()) => {}
2202 Err(_) => {
2203 return HostVm::Error {
2204 error: Error::FreeError { pointer },
2205 prototype: self.inner.into_prototype(),
2206 };
2207 }
2208 };
2209
2210 HostVm::ReadyToRun(ReadyToRun {
2211 resume_value: None,
2212 inner: self.inner,
2213 })
2214 }
2215 HostFunction::ext_logging_log_version_1 => {
2216 let log_level = expect_u32!(0);
2217
2218 let (target_str_ptr, target_str_size) = expect_pointer_size_raw!(1);
2219 let target_utf8_check = str::from_utf8(
2220 self.inner
2221 .vm
2222 .read_memory(target_str_ptr, target_str_size)
2223 .unwrap_or_else(|_| unreachable!())
2224 .as_ref(),
2225 )
2226 .map(|_| ());
2227 if let Err(error) = target_utf8_check {
2228 return HostVm::Error {
2229 error: Error::Utf8Error {
2230 function: host_fn.name(),
2231 param_num: 1,
2232 error,
2233 },
2234 prototype: self.inner.into_prototype(),
2235 };
2236 }
2237
2238 let (msg_str_ptr, msg_str_size) = expect_pointer_size_raw!(2);
2239 let msg_utf8_check = str::from_utf8(
2240 self.inner
2241 .vm
2242 .read_memory(msg_str_ptr, msg_str_size)
2243 .unwrap_or_else(|_| unreachable!())
2244 .as_ref(),
2245 )
2246 .map(|_| ());
2247 if let Err(error) = msg_utf8_check {
2248 return HostVm::Error {
2249 error: Error::Utf8Error {
2250 function: host_fn.name(),
2251 param_num: 2,
2252 error,
2253 },
2254 prototype: self.inner.into_prototype(),
2255 };
2256 }
2257
2258 HostVm::LogEmit(LogEmit {
2259 inner: self.inner,
2260 log_entry: LogEmitInner::Log {
2261 log_level,
2262 target_str_ptr,
2263 target_str_size,
2264 msg_str_ptr,
2265 msg_str_size,
2266 },
2267 })
2268 }
2269 HostFunction::ext_logging_max_level_version_1 => {
2270 HostVm::GetMaxLogLevel(GetMaxLogLevel { inner: self.inner })
2271 }
2272 HostFunction::ext_panic_handler_abort_on_panic_version_1 => {
2273 let message = {
2274 let message_bytes = expect_pointer_size!(0);
2275 str::from_utf8(message_bytes.as_ref()).map(|msg| msg.to_owned())
2276 };
2277
2278 match message {
2279 Ok(message) => HostVm::Error {
2280 error: Error::AbortOnPanic { message },
2281 prototype: self.inner.into_prototype(),
2282 },
2283 Err(error) => HostVm::Error {
2284 error: Error::Utf8Error {
2285 function: host_fn.name(),
2286 param_num: 0,
2287 error,
2288 },
2289 prototype: self.inner.into_prototype(),
2290 },
2291 }
2292 }
2293 HostFunction::ext_transaction_index_index_version_1 => {
2294 let _tx_ptr = expect_pointer_size_raw!(0);
2296 HostVm::ReadyToRun(ReadyToRun {
2297 inner: self.inner,
2298 resume_value: None,
2299 })
2300 }
2301 HostFunction::ext_transaction_index_renew_version_1 => {
2302 let _tx_ptr = expect_pointer_size_raw!(0);
2304 HostVm::ReadyToRun(ReadyToRun {
2305 inner: self.inner,
2306 resume_value: None,
2307 })
2308 }
2309 }
2310 }
2311}
2312
2313impl fmt::Debug for ReadyToRun {
2314 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2315 f.debug_tuple("ReadyToRun").finish()
2316 }
2317}
2318
2319pub struct Finished {
2325 inner: Box<Inner>,
2326
2327 value_ptr: u32,
2329 value_size: u32,
2331}
2332
2333impl Finished {
2334 pub fn value(&self) -> impl AsRef<[u8]> {
2336 self.inner
2337 .vm
2338 .read_memory(self.value_ptr, self.value_size)
2339 .unwrap_or_else(|_| unreachable!())
2340 }
2341
2342 pub fn into_prototype(self) -> HostVmPrototype {
2344 self.inner.into_prototype()
2345 }
2346}
2347
2348impl fmt::Debug for Finished {
2349 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2350 f.debug_tuple("Finished").finish()
2351 }
2352}
2353
2354pub struct ExternalStorageGet {
2356 inner: Box<Inner>,
2357
2358 calling: usize,
2361
2362 value_out_ptr: Option<u32>,
2365
2366 key_ptr: u32,
2368 key_size: u32,
2370 child_trie_ptr_size: Option<(u32, u32)>,
2372 offset: u32,
2374 max_size: u32,
2376}
2377
2378impl ExternalStorageGet {
2379 pub fn key(&self) -> impl AsRef<[u8]> {
2381 self.inner
2382 .vm
2383 .read_memory(self.key_ptr, self.key_size)
2384 .unwrap_or_else(|_| unreachable!())
2385 }
2386
2387 pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2389 if let Some((child_trie_ptr, child_trie_size)) = self.child_trie_ptr_size {
2390 let child_trie = self
2391 .inner
2392 .vm
2393 .read_memory(child_trie_ptr, child_trie_size)
2394 .unwrap_or_else(|_| unreachable!());
2395 Some(child_trie)
2396 } else {
2397 None
2398 }
2399 }
2400
2401 pub fn offset(&self) -> u32 {
2403 self.offset
2404 }
2405
2406 pub fn max_size(&self) -> u32 {
2410 self.max_size
2411 }
2412
2413 pub fn resume_full_value(self, value: Option<&[u8]>) -> HostVm {
2419 if let Some(value) = value {
2420 if usize::try_from(self.offset).unwrap_or_else(|_| unreachable!()) < value.len() {
2421 let value_slice =
2422 &value[usize::try_from(self.offset).unwrap_or_else(|_| unreachable!())..];
2423 if usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())
2424 < value_slice.len()
2425 {
2426 let value_slice = &value_slice
2427 [..usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())];
2428 self.resume(Some((value_slice, value.len())))
2429 } else {
2430 self.resume(Some((value_slice, value.len())))
2431 }
2432 } else {
2433 self.resume(Some((&[], value.len())))
2434 }
2435 } else {
2436 self.resume(None)
2437 }
2438 }
2439
2440 pub fn resume(self, value: Option<(&[u8], usize)>) -> HostVm {
2460 self.resume_vectored(
2461 value
2462 .as_ref()
2463 .map(|(value, size)| (iter::once(&value[..]), *size)),
2464 )
2465 }
2466
2467 pub fn resume_vectored(
2478 mut self,
2479 value: Option<(impl Iterator<Item = impl AsRef<[u8]>> + Clone, usize)>,
2480 ) -> HostVm {
2481 let host_fn = match self.inner.common.registered_functions[self.calling] {
2482 FunctionImport::Resolved(f) => f,
2483 FunctionImport::Unresolved { .. } => unreachable!(),
2484 };
2485
2486 match host_fn {
2487 HostFunction::ext_storage_get_version_1
2488 | HostFunction::ext_default_child_storage_get_version_1 => {
2489 if let Some((value, value_total_len)) = value {
2490 debug_assert_eq!(
2492 value.clone().fold(0, |a, b| a + b.as_ref().len()),
2493 value_total_len
2494 );
2495 let value_len_enc = util::encode_scale_compact_usize(value_total_len);
2496 self.inner.alloc_write_and_return_pointer_size(
2497 host_fn.name(),
2498 iter::once(&[1][..])
2499 .chain(iter::once(value_len_enc.as_ref()))
2500 .map(either::Left)
2501 .chain(value.map(either::Right)),
2502 )
2503 } else {
2504 self.inner
2506 .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
2507 }
2508 }
2509 HostFunction::ext_storage_read_version_1
2510 | HostFunction::ext_default_child_storage_read_version_1 => {
2511 let outcome = if let Some((value, value_total_len)) = value {
2512 let mut remaining_max_allowed =
2513 usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!());
2514 let mut offset = self.value_out_ptr.unwrap_or_else(|| unreachable!());
2515 for value in value {
2516 let value = value.as_ref();
2517 assert!(value.len() <= remaining_max_allowed);
2518 remaining_max_allowed -= value.len();
2519 self.inner
2520 .vm
2521 .write_memory(offset, value)
2522 .unwrap_or_else(|_| unreachable!());
2523 offset += u32::try_from(value.len()).unwrap_or_else(|_| unreachable!());
2524 }
2525
2526 Some(
2529 u32::try_from(value_total_len).unwrap_or_else(|_| unreachable!())
2530 - self.offset,
2531 )
2532 } else {
2533 None
2534 };
2535
2536 return self.inner.alloc_write_and_return_pointer_size(
2537 host_fn.name(),
2538 if let Some(outcome) = outcome {
2539 either::Left(
2540 iter::once(either::Left([1u8]))
2541 .chain(iter::once(either::Right(outcome.to_le_bytes()))),
2542 )
2543 } else {
2544 either::Right(iter::once(either::Left([0u8])))
2545 },
2546 );
2547 }
2548 HostFunction::ext_storage_exists_version_1
2549 | HostFunction::ext_default_child_storage_exists_version_1 => {
2550 HostVm::ReadyToRun(ReadyToRun {
2551 inner: self.inner,
2552 resume_value: Some(if value.is_some() {
2553 vm::WasmValue::I32(1)
2554 } else {
2555 vm::WasmValue::I32(0)
2556 }),
2557 })
2558 }
2559 _ => unreachable!(),
2560 }
2561 }
2562}
2563
2564impl fmt::Debug for ExternalStorageGet {
2565 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2566 f.debug_tuple("ExternalStorageGet").finish()
2567 }
2568}
2569
2570pub struct ExternalStorageSet {
2580 inner: Box<Inner>,
2581
2582 key_ptr: u32,
2584 key_size: u32,
2586 child_trie_ptr_size: Option<(u32, u32)>,
2589
2590 value: Option<(u32, u32)>,
2592}
2593
2594impl ExternalStorageSet {
2595 pub fn key(&self) -> impl AsRef<[u8]> {
2597 self.inner
2598 .vm
2599 .read_memory(self.key_ptr, self.key_size)
2600 .unwrap_or_else(|_| unreachable!())
2601 }
2602
2603 pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2610 match &self.child_trie_ptr_size {
2611 Some((ptr, size)) => {
2612 let child_trie = self
2613 .inner
2614 .vm
2615 .read_memory(*ptr, *size)
2616 .unwrap_or_else(|_| unreachable!());
2617 Some(child_trie)
2618 }
2619 None => None,
2620 }
2621 }
2622
2623 pub fn value(&self) -> Option<impl AsRef<[u8]>> {
2627 self.value.map(|(ptr, size)| {
2628 self.inner
2629 .vm
2630 .read_memory(ptr, size)
2631 .unwrap_or_else(|_| unreachable!())
2632 })
2633 }
2634
2635 pub fn state_trie_version(&self) -> TrieEntryVersion {
2640 self.inner
2641 .common
2642 .runtime_version
2643 .as_ref()
2644 .unwrap_or_else(|| unreachable!())
2645 .decode()
2646 .state_version
2647 .unwrap_or(TrieEntryVersion::V0)
2648 }
2649
2650 pub fn resume(self) -> HostVm {
2652 HostVm::ReadyToRun(ReadyToRun {
2653 inner: self.inner,
2654 resume_value: None,
2655 })
2656 }
2657}
2658
2659impl fmt::Debug for ExternalStorageSet {
2660 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2661 f.debug_tuple("ExternalStorageSet").finish()
2662 }
2663}
2664
2665pub struct ExternalStorageAppend {
2691 inner: Box<Inner>,
2692
2693 key_ptr: u32,
2695 key_size: u32,
2697
2698 value_ptr: u32,
2700 value_size: u32,
2702}
2703
2704impl ExternalStorageAppend {
2705 pub fn key(&self) -> impl AsRef<[u8]> {
2707 self.inner
2708 .vm
2709 .read_memory(self.key_ptr, self.key_size)
2710 .unwrap_or_else(|_| unreachable!())
2711 }
2712
2713 pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2720 None::<&'static [u8]>
2722 }
2723
2724 pub fn value(&self) -> impl AsRef<[u8]> {
2726 self.inner
2727 .vm
2728 .read_memory(self.value_ptr, self.value_size)
2729 .unwrap_or_else(|_| unreachable!())
2730 }
2731
2732 pub fn resume(self) -> HostVm {
2734 HostVm::ReadyToRun(ReadyToRun {
2735 inner: self.inner,
2736 resume_value: None,
2737 })
2738 }
2739}
2740
2741impl fmt::Debug for ExternalStorageAppend {
2742 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2743 f.debug_tuple("ExternalStorageAppend").finish()
2744 }
2745}
2746
2747pub struct ExternalStorageClearPrefix {
2758 inner: Box<Inner>,
2759 calling: usize,
2762
2763 prefix_ptr_size: Option<(u32, u32)>,
2765 child_trie_ptr_size: Option<(u32, u32)>,
2767
2768 max_keys_to_remove: Option<u32>,
2770}
2771
2772impl ExternalStorageClearPrefix {
2773 pub fn prefix(&self) -> impl AsRef<[u8]> {
2775 if let Some((prefix_ptr, prefix_size)) = self.prefix_ptr_size {
2776 either::Left(
2777 self.inner
2778 .vm
2779 .read_memory(prefix_ptr, prefix_size)
2780 .unwrap_or_else(|_| unreachable!()),
2781 )
2782 } else {
2783 either::Right(&[][..])
2784 }
2785 }
2786
2787 pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2792 if let Some((child_trie_ptr, child_trie_size)) = self.child_trie_ptr_size {
2793 let child_trie = self
2794 .inner
2795 .vm
2796 .read_memory(child_trie_ptr, child_trie_size)
2797 .unwrap_or_else(|_| unreachable!());
2798 Some(child_trie)
2799 } else {
2800 None
2801 }
2802 }
2803
2804 pub fn max_keys_to_remove(&self) -> Option<u32> {
2806 self.max_keys_to_remove
2807 }
2808
2809 pub fn resume(self, num_cleared: u32, some_keys_remain: bool) -> HostVm {
2814 let host_fn = match self.inner.common.registered_functions[self.calling] {
2815 FunctionImport::Resolved(f) => f,
2816 FunctionImport::Unresolved { .. } => unreachable!(),
2817 };
2818
2819 match host_fn {
2820 HostFunction::ext_storage_clear_prefix_version_1
2821 | HostFunction::ext_default_child_storage_clear_prefix_version_1
2822 | HostFunction::ext_default_child_storage_storage_kill_version_1 => {
2823 HostVm::ReadyToRun(ReadyToRun {
2824 inner: self.inner,
2825 resume_value: None,
2826 })
2827 }
2828 HostFunction::ext_default_child_storage_storage_kill_version_2 => {
2829 HostVm::ReadyToRun(ReadyToRun {
2830 inner: self.inner,
2831 resume_value: Some(vm::WasmValue::I32(if some_keys_remain { 0 } else { 1 })),
2832 })
2833 }
2834 HostFunction::ext_storage_clear_prefix_version_2
2835 | HostFunction::ext_default_child_storage_clear_prefix_version_2
2836 | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
2837 self.inner.alloc_write_and_return_pointer_size(
2838 host_fn.name(),
2839 [
2840 either::Left(if some_keys_remain { [1u8] } else { [0u8] }),
2841 either::Right(num_cleared.to_le_bytes()),
2842 ]
2843 .into_iter(),
2844 )
2845 }
2846 _ => unreachable!(),
2847 }
2848 }
2849}
2850
2851impl fmt::Debug for ExternalStorageClearPrefix {
2852 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2853 f.debug_tuple("ExternalStorageClearPrefix").finish()
2854 }
2855}
2856
2857pub struct ExternalStorageRoot {
2870 inner: Box<Inner>,
2871
2872 calling: usize,
2875
2876 child_trie_ptr_size: Option<(u32, u32)>,
2878}
2879
2880impl ExternalStorageRoot {
2881 pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2883 if let Some((ptr, size)) = self.child_trie_ptr_size {
2884 let child_trie = self
2885 .inner
2886 .vm
2887 .read_memory(ptr, size)
2888 .unwrap_or_else(|_| unreachable!());
2889 Some(child_trie)
2890 } else {
2891 None
2892 }
2893 }
2894
2895 pub fn resume(self, hash: &[u8; 32]) -> HostVm {
2900 let host_fn = match self.inner.common.registered_functions[self.calling] {
2901 FunctionImport::Resolved(f) => f,
2902 FunctionImport::Unresolved { .. } => unreachable!(),
2903 };
2904
2905 self.inner
2906 .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(hash))
2907 }
2908}
2909
2910impl fmt::Debug for ExternalStorageRoot {
2911 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2912 f.debug_tuple("ExternalStorageRoot").finish()
2913 }
2914}
2915
2916pub struct ExternalStorageNextKey {
2918 inner: Box<Inner>,
2919
2920 key_ptr: u32,
2922 key_size: u32,
2924 child_trie_ptr_size: Option<(u32, u32)>,
2926}
2927
2928impl ExternalStorageNextKey {
2929 pub fn key(&self) -> impl AsRef<[u8]> {
2931 self.inner
2932 .vm
2933 .read_memory(self.key_ptr, self.key_size)
2934 .unwrap_or_else(|_| unreachable!())
2935 }
2936
2937 pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2939 if let Some((child_trie_ptr, child_trie_size)) = self.child_trie_ptr_size {
2940 let child_trie = self
2941 .inner
2942 .vm
2943 .read_memory(child_trie_ptr, child_trie_size)
2944 .unwrap_or_else(|_| unreachable!());
2945 Some(child_trie)
2946 } else {
2947 None
2948 }
2949 }
2950
2951 pub fn resume(self, follow_up: Option<&[u8]>) -> HostVm {
2956 let key = self
2957 .inner
2958 .vm
2959 .read_memory(self.key_ptr, self.key_size)
2960 .unwrap_or_else(|_| unreachable!());
2961
2962 match follow_up {
2963 Some(next) => {
2964 debug_assert!(key.as_ref() < next);
2965
2966 let value_len_enc = util::encode_scale_compact_usize(next.len());
2967 drop(key);
2968 self.inner.alloc_write_and_return_pointer_size(
2969 HostFunction::ext_storage_next_key_version_1.name(), iter::once(&[1][..])
2971 .chain(iter::once(value_len_enc.as_ref()))
2972 .chain(iter::once(next)),
2973 )
2974 }
2975 None => {
2976 drop(key);
2978 self.inner.alloc_write_and_return_pointer_size(
2979 HostFunction::ext_storage_next_key_version_1.name(), iter::once(&[0]),
2981 )
2982 }
2983 }
2984 }
2985}
2986
2987impl fmt::Debug for ExternalStorageNextKey {
2988 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2989 f.debug_tuple("ExternalStorageNextKey").finish()
2990 }
2991}
2992
2993pub struct SignatureVerification {
2995 inner: Box<Inner>,
2996 algorithm: SignatureVerificationAlgorithm,
2998 signature_ptr: u32,
3001 public_key_ptr: u32,
3004 message_ptr: u32,
3006 message_size: u32,
3008 is_batch_verification: bool,
3010}
3011
3012enum SignatureVerificationAlgorithm {
3013 Ed25519,
3014 Sr25519V1,
3015 Sr25519V2,
3016 Ecdsa,
3017 EcdsaPrehashed,
3018}
3019
3020impl SignatureVerification {
3021 pub fn message(&self) -> impl AsRef<[u8]> {
3023 self.inner
3024 .vm
3025 .read_memory(self.message_ptr, self.message_size)
3026 .unwrap_or_else(|_| unreachable!())
3027 }
3028
3029 pub fn signature(&self) -> impl AsRef<[u8]> {
3034 let signature_size = match self.algorithm {
3035 SignatureVerificationAlgorithm::Ed25519 => 64,
3036 SignatureVerificationAlgorithm::Sr25519V1 => 64,
3037 SignatureVerificationAlgorithm::Sr25519V2 => 64,
3038 SignatureVerificationAlgorithm::Ecdsa => 65,
3039 SignatureVerificationAlgorithm::EcdsaPrehashed => 65,
3040 };
3041
3042 self.inner
3043 .vm
3044 .read_memory(self.signature_ptr, signature_size)
3045 .unwrap_or_else(|_| unreachable!())
3046 }
3047
3048 pub fn public_key(&self) -> impl AsRef<[u8]> {
3053 let public_key_size = match self.algorithm {
3054 SignatureVerificationAlgorithm::Ed25519 => 32,
3055 SignatureVerificationAlgorithm::Sr25519V1 => 32,
3056 SignatureVerificationAlgorithm::Sr25519V2 => 32,
3057 SignatureVerificationAlgorithm::Ecdsa => 33,
3058 SignatureVerificationAlgorithm::EcdsaPrehashed => 33,
3059 };
3060
3061 self.inner
3062 .vm
3063 .read_memory(self.public_key_ptr, public_key_size)
3064 .unwrap_or_else(|_| unreachable!())
3065 }
3066
3067 pub fn is_valid(&self) -> bool {
3069 match self.algorithm {
3070 SignatureVerificationAlgorithm::Ed25519 => {
3071 let public_key =
3072 ed25519_zebra::VerificationKey::try_from(self.public_key().as_ref());
3073
3074 if let Ok(public_key) = public_key {
3075 let signature = ed25519_zebra::Signature::from(
3076 <[u8; 64]>::try_from(self.signature().as_ref())
3077 .unwrap_or_else(|_| unreachable!()),
3078 );
3079 public_key
3080 .verify(&signature, self.message().as_ref())
3081 .is_ok()
3082 } else {
3083 false
3084 }
3085 }
3086 SignatureVerificationAlgorithm::Sr25519V1 => {
3087 schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3088 pk.verify_simple_preaudit_deprecated(
3089 b"substrate",
3090 self.message().as_ref(),
3091 self.signature().as_ref(),
3092 )
3093 .is_ok()
3094 })
3095 }
3096 SignatureVerificationAlgorithm::Sr25519V2 => {
3097 let Ok(signature) = schnorrkel::Signature::from_bytes(self.signature().as_ref())
3098 else {
3099 return false;
3100 };
3101 schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3102 pk.verify_simple(b"substrate", self.message().as_ref(), &signature)
3103 .is_ok()
3104 })
3105 }
3106 SignatureVerificationAlgorithm::Ecdsa => {
3107 let data = <[u8; 32]>::try_from(
3109 blake2_rfc::blake2b::blake2b(32, &[], self.message().as_ref()).as_bytes(),
3110 )
3111 .unwrap_or_else(|_| unreachable!());
3112 let message = libsecp256k1::Message::parse(&data);
3113
3114 let sig_bytes = self.signature();
3116 libsecp256k1::Signature::parse_standard_slice(&sig_bytes.as_ref()[..64])
3117 .and_then(|sig| {
3118 libsecp256k1::RecoveryId::parse(sig_bytes.as_ref()[64])
3119 .and_then(|ri| libsecp256k1::recover(&message, &sig, &ri))
3120 })
3121 .map_or(false, |actual| {
3122 self.public_key().as_ref()[..] == actual.serialize_compressed()[..]
3123 })
3124 }
3125 SignatureVerificationAlgorithm::EcdsaPrehashed => {
3126 let message = libsecp256k1::Message::parse(
3129 &<[u8; 32]>::try_from(self.message().as_ref())
3130 .unwrap_or_else(|_| unreachable!()),
3131 );
3132
3133 let sig_bytes = self.signature();
3135 if let Ok(sig) =
3136 libsecp256k1::Signature::parse_standard_slice(&sig_bytes.as_ref()[..64])
3137 {
3138 if let Ok(ri) = libsecp256k1::RecoveryId::parse(sig_bytes.as_ref()[64]) {
3139 if let Ok(actual) = libsecp256k1::recover(&message, &sig, &ri) {
3140 self.public_key().as_ref()[..] == actual.serialize_compressed()[..]
3141 } else {
3142 false
3143 }
3144 } else {
3145 false
3146 }
3147 } else {
3148 false
3149 }
3150 }
3151 }
3152 }
3153
3154 pub fn verify_and_resume(self) -> HostVm {
3156 let success = self.is_valid();
3157 self.resume(success)
3158 }
3159
3160 pub fn resume_success(self) -> HostVm {
3166 self.resume(true)
3167 }
3168
3169 pub fn resume_failed(self) -> HostVm {
3175 self.resume(false)
3176 }
3177
3178 fn resume(mut self, success: bool) -> HostVm {
3179 debug_assert!(
3180 !self.is_batch_verification || self.inner.signatures_batch_verification.is_some()
3181 );
3182 if self.is_batch_verification && !success {
3183 self.inner.signatures_batch_verification = Some(false);
3184 }
3185
3186 HostVm::ReadyToRun(ReadyToRun {
3188 resume_value: Some(vm::WasmValue::I32(if success { 1 } else { 0 })),
3189 inner: self.inner,
3190 })
3191 }
3192}
3193
3194impl fmt::Debug for SignatureVerification {
3195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3196 f.debug_struct("SignatureVerification")
3197 .field("message", &self.message().as_ref())
3198 .field("signature", &self.signature().as_ref())
3199 .field("public_key", &self.public_key().as_ref())
3200 .finish()
3201 }
3202}
3203
3204pub struct CallRuntimeVersion {
3207 inner: Box<Inner>,
3208
3209 wasm_blob_ptr: u32,
3211 wasm_blob_size: u32,
3213}
3214
3215impl CallRuntimeVersion {
3216 pub fn wasm_code(&self) -> impl AsRef<[u8]> {
3218 self.inner
3219 .vm
3220 .read_memory(self.wasm_blob_ptr, self.wasm_blob_size)
3221 .unwrap_or_else(|_| unreachable!())
3222 }
3223
3224 pub fn resume(self, scale_encoded_runtime_version: Result<&[u8], ()>) -> HostVm {
3229 if let Ok(scale_encoded_runtime_version) = scale_encoded_runtime_version {
3230 self.inner.alloc_write_and_return_pointer_size(
3231 HostFunction::ext_misc_runtime_version_version_1.name(),
3232 iter::once(either::Left([1]))
3233 .chain(iter::once(either::Right(either::Left(
3234 util::encode_scale_compact_usize(scale_encoded_runtime_version.len()),
3235 ))))
3236 .chain(iter::once(either::Right(either::Right(
3237 scale_encoded_runtime_version,
3238 )))),
3239 )
3240 } else {
3241 self.inner.alloc_write_and_return_pointer_size(
3242 HostFunction::ext_misc_runtime_version_version_1.name(),
3243 iter::once([0]),
3244 )
3245 }
3246 }
3247}
3248
3249impl fmt::Debug for CallRuntimeVersion {
3250 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3251 f.debug_tuple("CallRuntimeVersion").finish()
3252 }
3253}
3254
3255pub struct ExternalOffchainIndexSet {
3257 inner: Box<Inner>,
3258
3259 key_ptr: u32,
3261 key_size: u32,
3263
3264 value: Option<(u32, u32)>,
3266}
3267
3268impl ExternalOffchainIndexSet {
3269 pub fn key(&self) -> impl AsRef<[u8]> {
3271 self.inner
3272 .vm
3273 .read_memory(self.key_ptr, self.key_size)
3274 .unwrap_or_else(|_| unreachable!())
3275 }
3276
3277 pub fn value(&self) -> Option<impl AsRef<[u8]>> {
3281 if let Some((ptr, size)) = self.value {
3282 Some(
3283 self.inner
3284 .vm
3285 .read_memory(ptr, size)
3286 .unwrap_or_else(|_| unreachable!()),
3287 )
3288 } else {
3289 None
3290 }
3291 }
3292
3293 pub fn resume(self) -> HostVm {
3295 HostVm::ReadyToRun(ReadyToRun {
3296 inner: self.inner,
3297 resume_value: None,
3298 })
3299 }
3300}
3301
3302impl fmt::Debug for ExternalOffchainIndexSet {
3303 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3304 f.debug_tuple("ExternalOffchainIndexSet").finish()
3305 }
3306}
3307
3308pub struct ExternalOffchainStorageSet {
3310 inner: Box<Inner>,
3311
3312 key_ptr: u32,
3314 key_size: u32,
3316
3317 value: Option<(u32, u32)>,
3319
3320 old_value: Option<(u32, u32)>,
3322}
3323
3324impl ExternalOffchainStorageSet {
3325 pub fn key(&self) -> impl AsRef<[u8]> {
3327 self.inner
3328 .vm
3329 .read_memory(self.key_ptr, self.key_size)
3330 .unwrap_or_else(|_| unreachable!())
3331 }
3332
3333 pub fn value(&self) -> Option<impl AsRef<[u8]>> {
3337 if let Some((ptr, size)) = self.value {
3338 Some(
3339 self.inner
3340 .vm
3341 .read_memory(ptr, size)
3342 .unwrap_or_else(|_| unreachable!()),
3343 )
3344 } else {
3345 None
3346 }
3347 }
3348
3349 pub fn old_value(&self) -> Option<impl AsRef<[u8]>> {
3351 if let Some((ptr, size)) = self.old_value {
3352 Some(
3353 self.inner
3354 .vm
3355 .read_memory(ptr, size)
3356 .unwrap_or_else(|_| unreachable!()),
3357 )
3358 } else {
3359 None
3360 }
3361 }
3362
3363 pub fn resume(self, replaced: bool) -> HostVm {
3365 if self.old_value.is_some() {
3366 HostVm::ReadyToRun(ReadyToRun {
3367 inner: self.inner,
3368 resume_value: Some(vm::WasmValue::I32(if replaced { 1 } else { 0 })),
3369 })
3370 } else {
3371 HostVm::ReadyToRun(ReadyToRun {
3372 inner: self.inner,
3373 resume_value: None,
3374 })
3375 }
3376 }
3377}
3378
3379impl fmt::Debug for ExternalOffchainStorageSet {
3380 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3381 f.debug_tuple("ExternalOffchainStorageSet").finish()
3382 }
3383}
3384
3385pub struct ExternalOffchainStorageGet {
3387 inner: Box<Inner>,
3388
3389 calling: usize,
3392
3393 key_ptr: u32,
3395 key_size: u32,
3397}
3398
3399impl ExternalOffchainStorageGet {
3400 pub fn key(&self) -> impl AsRef<[u8]> {
3402 self.inner
3403 .vm
3404 .read_memory(self.key_ptr, self.key_size)
3405 .unwrap_or_else(|_| unreachable!())
3406 }
3407
3408 pub fn resume(self, value: Option<&[u8]>) -> HostVm {
3410 let host_fn = match self.inner.common.registered_functions[self.calling] {
3411 FunctionImport::Resolved(f) => f,
3412 FunctionImport::Unresolved { .. } => unreachable!(),
3413 };
3414
3415 if let Some(value) = value {
3416 let value_len_enc = util::encode_scale_compact_usize(value.len());
3417 self.inner.alloc_write_and_return_pointer_size(
3418 host_fn.name(),
3419 iter::once(&[1][..])
3420 .chain(iter::once(value_len_enc.as_ref()))
3421 .map(either::Left)
3422 .chain(iter::once(value).map(either::Right)),
3423 )
3424 } else {
3425 self.inner
3427 .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
3428 }
3429 }
3430}
3431
3432impl fmt::Debug for ExternalOffchainStorageGet {
3433 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3434 f.debug_tuple("ExternalOffchainStorageGet").finish()
3435 }
3436}
3437
3438pub struct OffchainTimestamp {
3440 inner: Box<Inner>,
3441}
3442
3443impl OffchainTimestamp {
3444 pub fn resume(self, value: u64) -> HostVm {
3446 HostVm::ReadyToRun(ReadyToRun {
3447 inner: self.inner,
3448 resume_value: Some(vm::WasmValue::I64(i64::from_ne_bytes(value.to_ne_bytes()))),
3449 })
3450 }
3451}
3452
3453impl fmt::Debug for OffchainTimestamp {
3454 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3455 f.debug_tuple("OffchainTimestamp").finish()
3456 }
3457}
3458
3459pub struct OffchainRandomSeed {
3461 inner: Box<Inner>,
3462
3463 calling: usize,
3466}
3467
3468impl OffchainRandomSeed {
3469 pub fn resume(self, value: [u8; 32]) -> HostVm {
3471 let host_fn = match self.inner.common.registered_functions[self.calling] {
3472 FunctionImport::Resolved(f) => f,
3473 FunctionImport::Unresolved { .. } => unreachable!(),
3474 };
3475 self.inner
3476 .alloc_write_and_return_pointer(host_fn.name(), iter::once(value))
3477 }
3478}
3479
3480impl fmt::Debug for OffchainRandomSeed {
3481 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3482 f.debug_tuple("OffchainRandomSeed").finish()
3483 }
3484}
3485
3486pub struct OffchainSubmitTransaction {
3488 inner: Box<Inner>,
3489
3490 calling: usize,
3493
3494 tx_ptr: u32,
3496
3497 tx_size: u32,
3499}
3500
3501impl OffchainSubmitTransaction {
3502 pub fn transaction(&self) -> impl AsRef<[u8]> {
3504 self.inner
3505 .vm
3506 .read_memory(self.tx_ptr, self.tx_size)
3507 .unwrap_or_else(|_| unreachable!())
3508 }
3509
3510 pub fn resume(self, success: bool) -> HostVm {
3512 let host_fn = match self.inner.common.registered_functions[self.calling] {
3513 FunctionImport::Resolved(f) => f,
3514 FunctionImport::Unresolved { .. } => unreachable!(),
3515 };
3516
3517 self.inner.alloc_write_and_return_pointer_size(
3518 host_fn.name(),
3519 if success {
3520 iter::once(&[0x00])
3521 } else {
3522 iter::once(&[0x01])
3523 },
3524 )
3525 }
3526}
3527
3528impl fmt::Debug for OffchainSubmitTransaction {
3529 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3530 f.debug_tuple("OffchainSubmitTransaction").finish()
3531 }
3532}
3533
3534pub struct LogEmit {
3538 inner: Box<Inner>,
3539 log_entry: LogEmitInner,
3540}
3541
3542enum LogEmitInner {
3543 Num(u64),
3544 Utf8 {
3545 str_ptr: u32,
3547 str_size: u32,
3549 },
3550 Hex {
3551 data_ptr: u32,
3553 data_size: u32,
3555 },
3556 Log {
3557 log_level: u32,
3559 target_str_ptr: u32,
3561 target_str_size: u32,
3563 msg_str_ptr: u32,
3565 msg_str_size: u32,
3567 },
3568}
3569
3570impl LogEmit {
3571 pub fn info(&'_ self) -> LogEmitInfo<'_> {
3573 match self.log_entry {
3574 LogEmitInner::Num(n) => LogEmitInfo::Num(n),
3575 LogEmitInner::Utf8 { str_ptr, str_size } => LogEmitInfo::Utf8(LogEmitInfoStr {
3576 data: Box::new(
3577 self.inner
3578 .vm
3579 .read_memory(str_ptr, str_size)
3580 .unwrap_or_else(|_| unreachable!()),
3581 ),
3582 }),
3583 LogEmitInner::Hex {
3584 data_ptr,
3585 data_size,
3586 } => LogEmitInfo::Hex(LogEmitInfoHex {
3587 data: Box::new(
3588 self.inner
3589 .vm
3590 .read_memory(data_ptr, data_size)
3591 .unwrap_or_else(|_| unreachable!()),
3592 ),
3593 }),
3594 LogEmitInner::Log {
3595 msg_str_ptr,
3596 msg_str_size,
3597 target_str_ptr,
3598 target_str_size,
3599 log_level,
3600 } => LogEmitInfo::Log {
3601 log_level,
3602 target: LogEmitInfoStr {
3603 data: Box::new(
3604 self.inner
3605 .vm
3606 .read_memory(target_str_ptr, target_str_size)
3607 .unwrap_or_else(|_| unreachable!()),
3608 ),
3609 },
3610 message: LogEmitInfoStr {
3611 data: Box::new(
3612 self.inner
3613 .vm
3614 .read_memory(msg_str_ptr, msg_str_size)
3615 .unwrap_or_else(|_| unreachable!()),
3616 ),
3617 },
3618 },
3619 }
3620 }
3621
3622 pub fn resume(self) -> HostVm {
3624 HostVm::ReadyToRun(ReadyToRun {
3625 inner: self.inner,
3626 resume_value: None,
3627 })
3628 }
3629}
3630
3631impl fmt::Debug for LogEmit {
3632 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3633 f.debug_struct("LogEmit")
3634 .field("info", &self.info())
3635 .finish()
3636 }
3637}
3638
3639#[derive(Debug)]
3641pub enum LogEmitInfo<'a> {
3642 Num(u64),
3644 Utf8(LogEmitInfoStr<'a>),
3646 Hex(LogEmitInfoHex<'a>),
3648 Log {
3650 log_level: u32,
3652 target: LogEmitInfoStr<'a>,
3655 message: LogEmitInfoStr<'a>,
3657 },
3658}
3659
3660pub struct LogEmitInfoHex<'a> {
3662 data: Box<dyn AsRef<[u8]> + Send + Sync + 'a>,
3664}
3665
3666impl<'a> AsRef<[u8]> for LogEmitInfoHex<'a> {
3667 fn as_ref(&self) -> &[u8] {
3668 (*self.data).as_ref()
3669 }
3670}
3671
3672impl<'a> fmt::Debug for LogEmitInfoHex<'a> {
3673 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3674 fmt::Debug::fmt(self.as_ref(), f)
3675 }
3676}
3677
3678impl<'a> fmt::Display for LogEmitInfoHex<'a> {
3679 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3680 fmt::Debug::fmt(&hex::encode(self.as_ref()), f)
3681 }
3682}
3683
3684pub struct LogEmitInfoStr<'a> {
3686 data: Box<dyn AsRef<[u8]> + Send + Sync + 'a>,
3688}
3689
3690impl<'a> AsRef<str> for LogEmitInfoStr<'a> {
3691 fn as_ref(&self) -> &str {
3692 let data = (*self.data).as_ref();
3693 str::from_utf8(data).unwrap_or_else(|_| unreachable!())
3696 }
3697}
3698
3699impl<'a> fmt::Debug for LogEmitInfoStr<'a> {
3700 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3701 fmt::Debug::fmt(self.as_ref(), f)
3702 }
3703}
3704
3705impl<'a> fmt::Display for LogEmitInfoStr<'a> {
3706 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3707 fmt::Display::fmt(self.as_ref(), f)
3708 }
3709}
3710
3711pub struct GetMaxLogLevel {
3713 inner: Box<Inner>,
3714}
3715
3716impl GetMaxLogLevel {
3717 pub fn resume(self, max_level: u32) -> HostVm {
3721 HostVm::ReadyToRun(ReadyToRun {
3722 inner: self.inner,
3723 resume_value: Some(vm::WasmValue::I32(i32::from_ne_bytes(
3724 max_level.to_ne_bytes(),
3725 ))),
3726 })
3727 }
3728}
3729
3730impl fmt::Debug for GetMaxLogLevel {
3731 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3732 f.debug_tuple("GetMaxLogLevel").finish()
3733 }
3734}
3735
3736pub struct StartStorageTransaction {
3738 inner: Box<Inner>,
3739}
3740
3741impl StartStorageTransaction {
3742 pub fn resume(self) -> HostVm {
3744 HostVm::ReadyToRun(ReadyToRun {
3745 inner: self.inner,
3746 resume_value: None,
3747 })
3748 }
3749}
3750
3751impl fmt::Debug for StartStorageTransaction {
3752 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3753 f.debug_tuple("StartStorageTransaction").finish()
3754 }
3755}
3756
3757pub struct EndStorageTransaction {
3759 inner: Box<Inner>,
3760}
3761
3762impl EndStorageTransaction {
3763 pub fn resume(self) -> HostVm {
3765 HostVm::ReadyToRun(ReadyToRun {
3766 inner: self.inner,
3767 resume_value: None,
3768 })
3769 }
3770}
3771
3772impl fmt::Debug for EndStorageTransaction {
3773 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3774 f.debug_tuple("EndStorageTransaction").finish()
3775 }
3776}
3777
3778#[derive(Clone)]
3779enum FunctionImport {
3780 Resolved(HostFunction),
3781 Unresolved { module: String, name: String },
3782}
3783
3784struct Inner {
3786 vm: vm::VirtualMachine,
3788
3789 storage_transaction_depth: u32,
3791
3792 signatures_batch_verification: Option<bool>,
3800
3801 allocator: allocator::FreeingBumpHeapAllocator,
3803
3804 storage_proof_size_behavior: StorageProofSizeBehavior,
3806
3807 common: Box<VmCommon>,
3809}
3810
3811impl Inner {
3812 fn alloc_write_and_return_pointer_size(
3824 mut self: Box<Self>,
3825 function_name: &'static str,
3826 data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3827 ) -> HostVm {
3828 let mut data_len = 0u32;
3829 for chunk in data.clone() {
3830 data_len =
3831 data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3832 }
3833
3834 let dest_ptr = match self.alloc(function_name, data_len) {
3835 Ok(p) => p,
3836 Err(error) => {
3837 return HostVm::Error {
3838 error,
3839 prototype: self.into_prototype(),
3840 };
3841 }
3842 };
3843
3844 let mut ptr_iter = dest_ptr;
3845 for chunk in data {
3846 let chunk = chunk.as_ref();
3847 self.vm
3848 .write_memory(ptr_iter, chunk)
3849 .unwrap_or_else(|_| unreachable!());
3850 ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3851 }
3852
3853 let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3854 let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3855
3856 ReadyToRun {
3857 inner: self,
3858 resume_value: Some(vm::WasmValue::I64(ret_val)),
3859 }
3860 .into()
3861 }
3862
3863 fn alloc_write_and_return_pointer(
3875 mut self: Box<Self>,
3876 function_name: &'static str,
3877 data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3878 ) -> HostVm {
3879 let mut data_len = 0u32;
3880 for chunk in data.clone() {
3881 data_len =
3882 data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3883 }
3884
3885 let dest_ptr = match self.alloc(function_name, data_len) {
3886 Ok(p) => p,
3887 Err(error) => {
3888 return HostVm::Error {
3889 error,
3890 prototype: self.into_prototype(),
3891 };
3892 }
3893 };
3894
3895 let mut ptr_iter = dest_ptr;
3896 for chunk in data {
3897 let chunk = chunk.as_ref();
3898 self.vm
3899 .write_memory(ptr_iter, chunk)
3900 .unwrap_or_else(|_| unreachable!());
3901 ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3902 }
3903
3904 let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3905 ReadyToRun {
3906 inner: self,
3907 resume_value: Some(vm::WasmValue::I32(ret_val)),
3908 }
3909 .into()
3910 }
3911
3912 fn alloc(&mut self, function_name: &'static str, size: u32) -> Result<u32, Error> {
3921 let dest_ptr = match self.allocator.allocate(
3923 &mut MemAccess {
3924 vm: MemAccessVm::Running(&mut self.vm),
3925 memory_total_pages: self.common.memory_total_pages,
3926 },
3927 size,
3928 ) {
3929 Ok(p) => p,
3930 Err(_) => {
3931 return Err(Error::OutOfMemory {
3932 function: function_name,
3933 requested_size: size,
3934 });
3935 }
3936 };
3937
3938 let last_byte_memory_page = HeapPages::new((dest_ptr + size - 1) / (64 * 1024));
3946
3947 let current_num_pages = self.vm.memory_size();
3951 debug_assert!(current_num_pages <= self.common.memory_total_pages);
3952 if current_num_pages <= last_byte_memory_page {
3953 let to_grow = last_byte_memory_page - current_num_pages + HeapPages::new(1);
3958
3959 self.vm
3962 .grow_memory(to_grow)
3963 .unwrap_or_else(|_| unreachable!());
3964 }
3965
3966 Ok(dest_ptr)
3967 }
3968
3969 fn into_prototype(self) -> HostVmPrototype {
3971 HostVmPrototype {
3972 vm_proto: self.vm.into_prototype(),
3973 common: self.common,
3974 }
3975 }
3976}
3977
3978#[derive(Debug, derive_more::From, derive_more::Display, derive_more::Error, Clone)]
3980pub enum NewErr {
3981 #[display("{_0}")]
3983 BadFormat(ModuleFormatError),
3984 #[display("{_0}")]
3986 VirtualMachine(vm::NewErr),
3987 #[display("Error in runtime spec Wasm sections: {_0}")]
3989 RuntimeVersion(FindEmbeddedRuntimeVersionError),
3990 #[display("Error while calling Core_version: {_0}")]
3992 CoreVersion(CoreVersionError),
3993 HeapBaseNotFound,
3995 MemoryMaxSizeTooLow,
3998}
3999
4000#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
4002pub enum FindEmbeddedRuntimeVersionError {
4003 #[display("{_0}")]
4005 FindSections(FindEncodedEmbeddedRuntimeVersionApisError),
4006 RuntimeVersionDecode,
4008 #[display("{_0}")]
4010 RuntimeApisDecode(CoreVersionApisFromSliceErr),
4011}
4012
4013#[derive(Debug, Clone, derive_more::From, derive_more::Display, derive_more::Error)]
4015pub enum StartErr {
4016 #[display("{_0}")]
4018 VirtualMachine(vm::StartErr),
4019 DataSizeOverflow,
4021}
4022
4023#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4025pub enum Error {
4026 #[display("{_0}")]
4028 Trap(vm::Trap),
4029 #[display("Runtime has aborted: {message:?}")]
4031 AbortOnPanic {
4032 message: String,
4034 },
4035 #[display("A non-I64 value has been returned: {actual:?}")]
4037 BadReturnValue {
4038 actual: Option<vm::ValueType>,
4040 },
4041 #[display("The pointer and size returned by the function are invalid")]
4043 ReturnedPtrOutOfRange {
4044 pointer: u32,
4046 size: u32,
4048 memory_size: u32,
4050 },
4051 #[display("Called unresolved function `{module_name}`:`{function}`")]
4055 UnresolvedFunctionCalled {
4056 function: String,
4058 module_name: String,
4060 },
4061 ParamDecodeError,
4063 #[display(
4066 "Bad pointer for parameter of index {param_num} of {function}: 0x{pointer:x}, \
4067 len = 0x{length:x}"
4068 )]
4069 ParamOutOfRange {
4070 function: &'static str,
4072 param_num: usize,
4074 pointer: u32,
4076 length: u32,
4081 },
4082 #[display("UTF-8 error for parameter of index {param_num} of {function}: {error}")]
4085 Utf8Error {
4086 function: &'static str,
4088 param_num: usize,
4090 #[error(source)]
4092 error: core::str::Utf8Error,
4093 },
4094 #[display("Attempted to end a transaction while none is in progress")]
4097 NoActiveTransaction,
4098 #[display("Execution returned with a pending storage transaction")]
4101 FinishedWithPendingTransaction,
4102 #[display("Out of memory allocating 0x{requested_size:x} bytes during {function}")]
4104 OutOfMemory {
4105 function: &'static str,
4107 requested_size: u32,
4109 },
4110 #[display("Bad pointer passed to ext_allocator_free_version_1: 0x{pointer:x}")]
4112 FreeError {
4113 pointer: u32,
4115 },
4116 #[display(
4119 "Mismatch between the state trie version provided as parameter ({parameter:?}) and \
4120 the state trie version found in the runtime specification ({specification:?})."
4121 )]
4122 StateVersionMismatch {
4123 parameter: TrieEntryVersion,
4125 specification: TrieEntryVersion,
4127 },
4128 #[display(
4131 "Called `ext_default_child_storage_root_version_1` or
4132 `ext_default_child_storage_root_version_2` on a child trie that doesn't exist."
4133 )]
4134 ChildStorageRootTrieDoesntExist,
4135 BatchVerifyWithoutStarting,
4138 AlreadyBatchVerify,
4141 NoBatchVerify,
4143 #[display("Host function not implemented: {function}")]
4146 HostFunctionNotImplemented {
4147 function: &'static str,
4149 },
4150}
4151
4152struct MemAccess<'a> {
4158 vm: MemAccessVm<'a>,
4159 memory_total_pages: HeapPages,
4160}
4161
4162enum MemAccessVm<'a> {
4163 Prepare(&'a mut vm::Prepare),
4164 Running(&'a mut vm::VirtualMachine),
4165}
4166
4167impl<'a> allocator::Memory for MemAccess<'a> {
4168 fn read_le_u64(&self, ptr: u32) -> Result<u64, allocator::Error> {
4169 if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4170 return Err(allocator::Error::Other);
4171 }
4172
4173 let accessed_memory_page_start = HeapPages::new(ptr / (64 * 1024));
4182 let accessed_memory_page_end = HeapPages::new((ptr + 7) / (64 * 1024));
4184 let current_num_pages = match self.vm {
4186 MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4187 MemAccessVm::Running(ref vm) => vm.memory_size(),
4188 };
4189 debug_assert!(current_num_pages <= self.memory_total_pages);
4190
4191 if accessed_memory_page_end < current_num_pages {
4192 match self.vm {
4194 MemAccessVm::Prepare(ref vm) => {
4195 let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4196 Ok(u64::from_le_bytes(
4197 <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4198 ))
4199 }
4200 MemAccessVm::Running(ref vm) => {
4201 let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4202 Ok(u64::from_le_bytes(
4203 <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4204 ))
4205 }
4206 }
4207 } else if accessed_memory_page_start < current_num_pages {
4208 match self.vm {
4210 MemAccessVm::Prepare(ref vm) => {
4211 let partial_bytes = vm
4212 .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4213 .unwrap_or_else(|_| unreachable!());
4214 let partial_bytes = partial_bytes.as_ref();
4215 debug_assert!(partial_bytes.len() < 8);
4216
4217 let mut out = [0; 8];
4218 out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4219 Ok(u64::from_le_bytes(out))
4220 }
4221 MemAccessVm::Running(ref vm) => {
4222 let partial_bytes = vm
4223 .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4224 .unwrap_or_else(|_| unreachable!());
4225 let partial_bytes = partial_bytes.as_ref();
4226 debug_assert!(partial_bytes.len() < 8);
4227
4228 let mut out = [0; 8];
4229 out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4230 Ok(u64::from_le_bytes(out))
4231 }
4232 }
4233 } else {
4234 Ok(0)
4236 }
4237 }
4238
4239 fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), allocator::Error> {
4240 if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4241 return Err(allocator::Error::Other);
4242 }
4243
4244 let bytes = val.to_le_bytes();
4245
4246 let written_memory_page = HeapPages::new((ptr + 7) / (64 * 1024));
4248
4249 let current_num_pages = match self.vm {
4253 MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4254 MemAccessVm::Running(ref vm) => vm.memory_size(),
4255 };
4256 debug_assert!(current_num_pages <= self.memory_total_pages);
4257 if current_num_pages <= written_memory_page {
4258 let to_grow = written_memory_page - current_num_pages + HeapPages::new(1);
4263
4264 match self.vm {
4267 MemAccessVm::Prepare(ref mut vm) => {
4268 vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4269 }
4270 MemAccessVm::Running(ref mut vm) => {
4271 vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4272 }
4273 }
4274 }
4275
4276 match self.vm {
4277 MemAccessVm::Prepare(ref mut vm) => vm
4278 .write_memory(ptr, &bytes)
4279 .unwrap_or_else(|_| unreachable!()),
4280 MemAccessVm::Running(ref mut vm) => vm
4281 .write_memory(ptr, &bytes)
4282 .unwrap_or_else(|_| unreachable!()),
4283 }
4284 Ok(())
4285 }
4286
4287 fn size(&self) -> u32 {
4288 u32::from(self.memory_total_pages)
4290 .saturating_mul(64)
4291 .saturating_mul(1024)
4292 }
4293}