1// This file is part of Substrate.
23// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
56// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
1011// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
1516// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
1819//! Defines data and logic needed for interaction with an WebAssembly instance of a substrate
20//! runtime module.
2122use std::sync::Arc;
2324use crate::runtime::{InstanceCounter, ReleaseInstanceHandle, Store, StoreData};
25use sc_executor_common::error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError};
26use sp_wasm_interface::{Pointer, WordSize};
27use wasmtime::{AsContext, AsContextMut, Engine, Instance, InstancePre, Memory};
2829/// Wasm blob entry point.
30pub struct EntryPoint(wasmtime::TypedFunc<(u32, u32), u64>);
3132impl EntryPoint {
33/// Call this entry point.
34pub(crate) fn call(
35&self,
36 store: &mut Store,
37 data_ptr: Pointer<u8>,
38 data_len: WordSize,
39 ) -> Result<u64> {
40let data_ptr = u32::from(data_ptr);
41let data_len = u32::from(data_len);
4243self.0.call(&mut *store, (data_ptr, data_len)).map_err(|trap| {
44let host_state = store
45 .data_mut()
46 .host_state
47 .as_mut()
48 .expect("host state cannot be empty while a function is being called; qed");
4950let backtrace = trap.downcast_ref::<wasmtime::WasmBacktrace>().map(|backtrace| {
51// The logic to print out a backtrace is somewhat complicated,
52 // so let's get wasmtime to print it out for us.
53Backtrace { backtrace_string: backtrace.to_string() }
54 });
5556if let Some(message) = host_state.take_panic_message() {
57 Error::AbortedDueToPanic(MessageWithBacktrace { message, backtrace })
58 } else {
59let message = trap.root_cause().to_string();
60 Error::AbortedDueToTrap(MessageWithBacktrace { message, backtrace })
61 }
62 })
63 }
6465pub fn direct(
66 func: wasmtime::Func,
67 ctx: impl AsContext,
68 ) -> std::result::Result<Self, &'static str> {
69let entrypoint = func
70 .typed::<(u32, u32), u64>(ctx)
71 .map_err(|_| "Invalid signature for direct entry point")?;
72Ok(Self(entrypoint))
73 }
74}
7576/// Wrapper around [`Memory`] that implements [`sc_allocator::Memory`].
77pub(crate) struct MemoryWrapper<'a, C>(pub &'a wasmtime::Memory, pub &'a mut C);
7879impl<C: AsContextMut> sc_allocator::Memory for MemoryWrapper<'_, C> {
80fn with_access_mut<R>(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R {
81 run(self.0.data_mut(&mut self.1))
82 }
8384fn with_access<R>(&self, run: impl FnOnce(&[u8]) -> R) -> R {
85 run(self.0.data(&self.1))
86 }
8788fn grow(&mut self, additional: u32) -> std::result::Result<(), ()> {
89self.0
90.grow(&mut self.1, additional as u64)
91 .map_err(|e| {
92log::error!(
93 target: "wasm-executor",
94"Failed to grow memory by {} pages: {}",
95 additional,
96 e,
97 )
98 })
99 .map(drop)
100 }
101102fn pages(&self) -> u32 {
103self.0.size(&self.1) as u32
104 }
105106fn max_pages(&self) -> Option<u32> {
107self.0.ty(&self.1).maximum().map(|p| p as _)
108 }
109}
110111/// Wrap the given WebAssembly Instance of a wasm module with Substrate-runtime.
112///
113/// This struct is a handy wrapper around a wasmtime `Instance` that provides substrate specific
114/// routines.
115pub struct InstanceWrapper {
116 instance: Instance,
117 store: Store,
118// NOTE: We want to decrement the instance counter *after* the store has been dropped
119 // to avoid a potential race condition, so this field must always be kept
120 // as the last field in the struct!
121_release_instance_handle: ReleaseInstanceHandle,
122}
123124impl InstanceWrapper {
125pub(crate) fn new(
126 engine: &Engine,
127 instance_pre: &InstancePre<StoreData>,
128 instance_counter: Arc<InstanceCounter>,
129 ) -> Result<Self> {
130let _release_instance_handle = instance_counter.acquire_instance();
131let mut store = Store::new(engine, Default::default());
132let instance = instance_pre.instantiate(&mut store).map_err(|error| {
133 WasmError::Other(format!(
134"failed to instantiate a new WASM module instance: {:#}",
135 error,
136 ))
137 })?;
138139let memory = get_linear_memory(&instance, &mut store)?;
140141 store.data_mut().memory = Some(memory);
142143Ok(InstanceWrapper { instance, store, _release_instance_handle })
144 }
145146/// Resolves a substrate entrypoint by the given name.
147 ///
148 /// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return
149 /// an error.
150pub fn resolve_entrypoint(&mut self, method: &str) -> Result<EntryPoint> {
151// Resolve the requested method and verify that it has a proper signature.
152let export = self
153.instance
154 .get_export(&mut self.store, method)
155 .ok_or_else(|| Error::from(format!("Exported method {} is not found", method)))?;
156let func = export
157 .into_func()
158 .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?;
159 EntryPoint::direct(func, &self.store).map_err(|_| {
160 Error::from(format!("Exported function '{}' has invalid signature.", method))
161 })
162 }
163164/// Reads `__heap_base: i32` global variable and returns it.
165 ///
166 /// If it doesn't exist, not a global or of not i32 type returns an error.
167pub fn extract_heap_base(&mut self) -> Result<u32> {
168let heap_base_export = self
169.instance
170 .get_export(&mut self.store, "__heap_base")
171 .ok_or_else(|| Error::from("__heap_base is not found"))?;
172173let heap_base_global = heap_base_export
174 .into_global()
175 .ok_or_else(|| Error::from("__heap_base is not a global"))?;
176177let heap_base = heap_base_global
178 .get(&mut self.store)
179 .i32()
180 .ok_or_else(|| Error::from("__heap_base is not a i32"))?;
181182Ok(heap_base as u32)
183 }
184}
185186/// Extract linear memory instance from the given instance.
187fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result<Memory> {
188let memory_export = instance
189 .get_export(ctx, "memory")
190 .ok_or_else(|| Error::from("memory is not exported under `memory` name"))?;
191192let memory = memory_export
193 .into_memory()
194 .ok_or_else(|| Error::from("the `memory` export should have memory type"))?;
195196Ok(memory)
197}
198199/// Functions related to memory.
200impl InstanceWrapper {
201pub(crate) fn store(&self) -> &Store {
202&self.store
203 }
204205pub(crate) fn store_mut(&mut self) -> &mut Store {
206&mut self.store
207 }
208}