polkadot_node_core_pvf_common/
executor_interface.rs1use crate::error::ExecuteError;
20use polkadot_primitives::{
21 executor_params::{DEFAULT_LOGICAL_STACK_MAX, DEFAULT_NATIVE_STACK_MAX},
22 ExecutorParam, ExecutorParams,
23};
24use sc_executor_common::{
25 error::WasmError,
26 runtime_blob::RuntimeBlob,
27 wasm_runtime::{HeapAllocStrategy, WasmModule as _},
28};
29use sc_executor_wasmtime::{Config, DeterministicStackLimit, Semantics, WasmtimeRuntime};
30use sp_core::storage::{ChildInfo, TrackedStorageKey};
31use sp_externalities::MultiRemovalResults;
32use std::any::{Any, TypeId};
33
34const DEFAULT_HEAP_PAGES_ESTIMATE: u32 = 32;
47const EXTRA_HEAP_PAGES: u32 = 2048;
48
49pub const DEFAULT_CONFIG: Config = Config {
54 allow_missing_func_imports: true,
55 cache_path: None,
56 semantics: Semantics {
57 heap_alloc_strategy: sc_executor_common::wasm_runtime::HeapAllocStrategy::Dynamic {
58 maximum_pages: Some(DEFAULT_HEAP_PAGES_ESTIMATE + EXTRA_HEAP_PAGES),
59 },
60
61 instantiation_strategy:
62 sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite,
63
64 deterministic_stack_limit: Some(DeterministicStackLimit {
77 logical_max: DEFAULT_LOGICAL_STACK_MAX,
78 native_stack_max: DEFAULT_NATIVE_STACK_MAX,
79 }),
80 canonicalize_nans: true,
81 parallel_compilation: false,
88
89 wasm_reference_types: false,
93 wasm_simd: false,
94 wasm_bulk_memory: false,
95 wasm_multi_value: false,
96 },
97};
98
99pub unsafe fn execute_artifact(
110 compiled_artifact_blob: &[u8],
111 executor_params: &ExecutorParams,
112 params: &[u8],
113) -> Result<Vec<u8>, ExecuteError> {
114 let mut extensions = sp_externalities::Extensions::new();
115
116 extensions.register(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion));
117
118 let mut ext = ValidationExternalities(extensions);
119
120 match sc_executor::with_externalities_safe(&mut ext, || {
121 let runtime = create_runtime_from_artifact_bytes(compiled_artifact_blob, executor_params)?;
122 runtime.new_instance()?.call("validate_block", params)
123 }) {
124 Ok(Ok(ok)) => Ok(ok),
125 Ok(Err(err)) | Err(err) => Err(err),
126 }
127}
128
129pub unsafe fn create_runtime_from_artifact_bytes(
139 compiled_artifact_blob: &[u8],
140 executor_params: &ExecutorParams,
141) -> Result<WasmtimeRuntime, WasmError> {
142 let mut config = DEFAULT_CONFIG.clone();
143 config.semantics = params_to_wasmtime_semantics(executor_params).0;
144
145 sc_executor_wasmtime::create_runtime_from_artifact_bytes::<HostFunctions>(
146 compiled_artifact_blob,
147 config,
148 )
149}
150
151pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> (Semantics, DeterministicStackLimit) {
155 let mut sem = DEFAULT_CONFIG.semantics.clone();
156 let mut stack_limit = sem
157 .deterministic_stack_limit
158 .expect("There is a comment to not change the default stack limit; it should always be available; qed")
159 .clone();
160
161 for p in par.iter() {
162 match p {
163 ExecutorParam::MaxMemoryPages(max_pages) =>
164 sem.heap_alloc_strategy = HeapAllocStrategy::Dynamic {
165 maximum_pages: Some((*max_pages).saturating_add(DEFAULT_HEAP_PAGES_ESTIMATE)),
166 },
167 ExecutorParam::StackLogicalMax(slm) => stack_limit.logical_max = *slm,
168 ExecutorParam::StackNativeMax(snm) => stack_limit.native_stack_max = *snm,
169 ExecutorParam::WasmExtBulkMemory => sem.wasm_bulk_memory = true,
170 ExecutorParam::PrecheckingMaxMemory(_) |
171 ExecutorParam::PvfPrepTimeout(_, _) |
172 ExecutorParam::PvfExecTimeout(_, _) => (), }
174 }
175 sem.deterministic_stack_limit = Some(stack_limit.clone());
176 (sem, stack_limit)
177}
178
179pub fn prevalidate(code: &[u8]) -> Result<RuntimeBlob, sc_executor_common::error::WasmError> {
181 let blob = RuntimeBlob::new(code)?;
183 Ok(blob)
185}
186
187pub fn prepare(
190 blob: RuntimeBlob,
191 executor_params: &ExecutorParams,
192) -> Result<Vec<u8>, sc_executor_common::error::WasmError> {
193 let (semantics, _) = params_to_wasmtime_semantics(executor_params);
194 sc_executor_wasmtime::prepare_runtime_artifact(blob, &semantics)
195}
196
197type HostFunctions = (
205 sp_io::misc::HostFunctions,
206 sp_io::crypto::HostFunctions,
207 sp_io::hashing::HostFunctions,
208 sp_io::allocator::HostFunctions,
209 sp_io::logging::HostFunctions,
210 sp_io::trie::HostFunctions,
211);
212
213struct ValidationExternalities(sp_externalities::Extensions);
216
217impl sp_externalities::Externalities for ValidationExternalities {
218 fn storage(&mut self, _: &[u8]) -> Option<Vec<u8>> {
219 panic!("storage: unsupported feature for parachain validation")
220 }
221
222 fn storage_hash(&mut self, _: &[u8]) -> Option<Vec<u8>> {
223 panic!("storage_hash: unsupported feature for parachain validation")
224 }
225
226 fn child_storage_hash(&mut self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
227 panic!("child_storage_hash: unsupported feature for parachain validation")
228 }
229
230 fn child_storage(&mut self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
231 panic!("child_storage: unsupported feature for parachain validation")
232 }
233
234 fn kill_child_storage(
235 &mut self,
236 _child_info: &ChildInfo,
237 _maybe_limit: Option<u32>,
238 _maybe_cursor: Option<&[u8]>,
239 ) -> MultiRemovalResults {
240 panic!("kill_child_storage: unsupported feature for parachain validation")
241 }
242
243 fn clear_prefix(
244 &mut self,
245 _prefix: &[u8],
246 _maybe_limit: Option<u32>,
247 _maybe_cursor: Option<&[u8]>,
248 ) -> MultiRemovalResults {
249 panic!("clear_prefix: unsupported feature for parachain validation")
250 }
251
252 fn clear_child_prefix(
253 &mut self,
254 _child_info: &ChildInfo,
255 _prefix: &[u8],
256 _maybe_limit: Option<u32>,
257 _maybe_cursor: Option<&[u8]>,
258 ) -> MultiRemovalResults {
259 panic!("clear_child_prefix: unsupported feature for parachain validation")
260 }
261
262 fn place_storage(&mut self, _: Vec<u8>, _: Option<Vec<u8>>) {
263 panic!("place_storage: unsupported feature for parachain validation")
264 }
265
266 fn place_child_storage(&mut self, _: &ChildInfo, _: Vec<u8>, _: Option<Vec<u8>>) {
267 panic!("place_child_storage: unsupported feature for parachain validation")
268 }
269
270 fn storage_root(&mut self, _: sp_core::storage::StateVersion) -> Vec<u8> {
271 panic!("storage_root: unsupported feature for parachain validation")
272 }
273
274 fn child_storage_root(&mut self, _: &ChildInfo, _: sp_core::storage::StateVersion) -> Vec<u8> {
275 panic!("child_storage_root: unsupported feature for parachain validation")
276 }
277
278 fn next_child_storage_key(&mut self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
279 panic!("next_child_storage_key: unsupported feature for parachain validation")
280 }
281
282 fn next_storage_key(&mut self, _: &[u8]) -> Option<Vec<u8>> {
283 panic!("next_storage_key: unsupported feature for parachain validation")
284 }
285
286 fn storage_append(&mut self, _key: Vec<u8>, _value: Vec<u8>) {
287 panic!("storage_append: unsupported feature for parachain validation")
288 }
289
290 fn storage_start_transaction(&mut self) {
291 panic!("storage_start_transaction: unsupported feature for parachain validation")
292 }
293
294 fn storage_rollback_transaction(&mut self) -> Result<(), ()> {
295 panic!("storage_rollback_transaction: unsupported feature for parachain validation")
296 }
297
298 fn storage_commit_transaction(&mut self) -> Result<(), ()> {
299 panic!("storage_commit_transaction: unsupported feature for parachain validation")
300 }
301
302 fn wipe(&mut self) {
303 panic!("wipe: unsupported feature for parachain validation")
304 }
305
306 fn commit(&mut self) {
307 panic!("commit: unsupported feature for parachain validation")
308 }
309
310 fn read_write_count(&self) -> (u32, u32, u32, u32) {
311 panic!("read_write_count: unsupported feature for parachain validation")
312 }
313
314 fn reset_read_write_count(&mut self) {
315 panic!("reset_read_write_count: unsupported feature for parachain validation")
316 }
317
318 fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
319 panic!("get_whitelist: unsupported feature for parachain validation")
320 }
321
322 fn set_whitelist(&mut self, _: Vec<TrackedStorageKey>) {
323 panic!("set_whitelist: unsupported feature for parachain validation")
324 }
325
326 fn set_offchain_storage(&mut self, _: &[u8], _: std::option::Option<&[u8]>) {
327 panic!("set_offchain_storage: unsupported feature for parachain validation")
328 }
329
330 fn get_read_and_written_keys(&self) -> Vec<(Vec<u8>, u32, u32, bool)> {
331 panic!("get_read_and_written_keys: unsupported feature for parachain validation")
332 }
333}
334
335impl sp_externalities::ExtensionStore for ValidationExternalities {
336 fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
337 self.0.get_mut(type_id)
338 }
339
340 fn register_extension_with_type_id(
341 &mut self,
342 type_id: TypeId,
343 extension: Box<dyn sp_externalities::Extension>,
344 ) -> Result<(), sp_externalities::Error> {
345 self.0.register_with_type_id(type_id, extension)
346 }
347
348 fn deregister_extension_by_type_id(
349 &mut self,
350 type_id: TypeId,
351 ) -> Result<(), sp_externalities::Error> {
352 if self.0.deregister(type_id) {
353 Ok(())
354 } else {
355 Err(sp_externalities::Error::ExtensionIsNotRegistered(type_id))
356 }
357 }
358}
359
360struct ReadRuntimeVersion;
361
362impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion {
363 fn read_runtime_version(
364 &self,
365 wasm_code: &[u8],
366 _ext: &mut dyn sp_externalities::Externalities,
367 ) -> Result<Vec<u8>, String> {
368 let blob = RuntimeBlob::uncompress_if_needed(wasm_code)
369 .map_err(|e| format!("Failed to read the PVF runtime blob: {:?}", e))?;
370
371 match sc_executor::read_embedded_version(&blob)
372 .map_err(|e| format!("Failed to read the static section from the PVF blob: {:?}", e))?
373 {
374 Some(version) => {
375 use codec::Encode;
376 Ok(version.encode())
377 },
378 None => Err("runtime version section is not found".to_string()),
379 }
380 }
381}