Skip to main content

sp_virtualization/
manager.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Manages virtualization instances. It is used by the host function **implementation**.
19
20use crate::{DestroyError, ExecError, Memory, MemoryError, MemoryT, Virt, VirtT};
21use sp_wasm_interface::{ExecAction, ExecOutcome, InstanceId, Virtualization};
22use std::collections::HashMap;
23
24/// A virtualization instance held by [`VirtManager`].
25struct VirtInstance {
26	virt: Virt,
27	memory: Memory,
28}
29
30/// Manages virtualization instances and their lifecycle.
31///
32/// Instance IDs are assigned deterministically from an incrementing counter,
33/// ensuring no non-determinism across different executions.
34pub struct VirtManager {
35	instances: HashMap<InstanceId, VirtInstance>,
36	counter: u32,
37}
38
39impl Default for VirtManager {
40	fn default() -> Self {
41		Self { instances: HashMap::new(), counter: 0 }
42	}
43}
44
45impl Virtualization for VirtManager {
46	fn instantiate(&mut self, program: &[u8]) -> sp_wasm_interface::Result<Result<InstanceId, u8>> {
47		let virt = match Virt::instantiate(program) {
48			Ok(virt) => virt,
49			Err(err) => return Ok(Err(err.into())),
50		};
51
52		let instance_id = InstanceId({
53			let old = self.counter;
54			self.counter = old + 1;
55			old
56		});
57
58		self.instances.insert(instance_id, VirtInstance { memory: virt.memory(), virt });
59
60		Ok(Ok(instance_id))
61	}
62
63	fn run(
64		&mut self,
65		instance_id: InstanceId,
66		gas_left: i64,
67		action: ExecAction<'_>,
68	) -> sp_wasm_interface::Result<Result<ExecOutcome, u8>> {
69		let instance = match self.instances.get_mut(&instance_id) {
70			Some(instance) => instance,
71			None => return Ok(Err(ExecError::InvalidInstance.into())),
72		};
73
74		let result = instance.virt.run(gas_left, action);
75		Ok(result.map_err(|err| err.into()))
76	}
77
78	fn destroy(&mut self, instance_id: InstanceId) -> sp_wasm_interface::Result<Result<(), u8>> {
79		if self.instances.remove(&instance_id).is_some() {
80			Ok(Ok(()))
81		} else {
82			Ok(Err(DestroyError::InvalidInstance.into()))
83		}
84	}
85
86	fn read_memory(
87		&mut self,
88		instance_id: InstanceId,
89		offset: u32,
90		dest: &mut [u8],
91	) -> sp_wasm_interface::Result<Result<(), u8>> {
92		let Some(instance) = self.instances.get_mut(&instance_id) else {
93			return Ok(Err(MemoryError::InvalidInstance.into()));
94		};
95		if let Err(err) = instance.memory.read(offset, dest) {
96			return Ok(Err(err.into()));
97		}
98		Ok(Ok(()))
99	}
100
101	fn write_memory(
102		&mut self,
103		instance_id: InstanceId,
104		offset: u32,
105		src: &[u8],
106	) -> sp_wasm_interface::Result<Result<(), u8>> {
107		let Some(instance) = self.instances.get_mut(&instance_id) else {
108			return Ok(Err(MemoryError::InvalidInstance.into()));
109		};
110		if let Err(err) = instance.memory.write(offset, src) {
111			return Ok(Err(err.into()));
112		}
113		Ok(Ok(()))
114	}
115}