Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit ea8a0c6

Browse files
author
alexgparity
committed
Merge branch 'alex/parathreads_review' into alex/parathreads_vstaging
2 parents 42bc527 + be4f525 commit ea8a0c6

File tree

26 files changed

+1306
-688
lines changed

26 files changed

+1306
-688
lines changed

Cargo.lock

Lines changed: 3 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node/core/backing/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl Default for TestState {
109109
}),
110110
CoreState::Scheduled(ScheduledCore {
111111
para_id: thread_a,
112-
collator_restrictions: CollatorRestrictions::none(), // FIXME: Should be collator's PeerId
112+
collator_restrictions: CollatorRestrictions::none(),
113113
}),
114114
];
115115

node/core/candidate-validation/src/lib.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
#![warn(missing_docs)]
2525

2626
use polkadot_node_core_pvf::{
27-
InternalValidationError, InvalidCandidate as WasmInvalidCandidate, PrepareError, PrepareStats,
28-
PvfPrepData, ValidationError, ValidationHost,
27+
InternalValidationError, InvalidCandidate as WasmInvalidCandidate, PrepareError,
28+
PrepareJobKind, PrepareStats, PvfPrepData, ValidationError, ValidationHost,
2929
};
3030
use polkadot_node_primitives::{
3131
BlockData, InvalidCandidate, PoV, ValidationResult, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT,
@@ -356,7 +356,12 @@ where
356356
&validation_code.0,
357357
VALIDATION_CODE_BOMB_LIMIT,
358358
) {
359-
Ok(code) => PvfPrepData::from_code(code.into_owned(), executor_params, timeout),
359+
Ok(code) => PvfPrepData::from_code(
360+
code.into_owned(),
361+
executor_params,
362+
timeout,
363+
PrepareJobKind::Prechecking,
364+
),
360365
Err(e) => {
361366
gum::debug!(target: LOG_TARGET, err=?e, "precheck: cannot decompress validation code");
362367
return PreCheckOutcome::Invalid
@@ -727,7 +732,12 @@ trait ValidationBackend {
727732
) -> Result<WasmValidationResult, ValidationError> {
728733
let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepTimeoutKind::Lenient);
729734
// Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap.
730-
let pvf = PvfPrepData::from_code(raw_validation_code, executor_params, prep_timeout);
735+
let pvf = PvfPrepData::from_code(
736+
raw_validation_code,
737+
executor_params,
738+
prep_timeout,
739+
PrepareJobKind::Compilation,
740+
);
731741
// We keep track of the total time that has passed and stop retrying if we are taking too long.
732742
let total_time_start = Instant::now();
733743

node/core/pvf/common/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ parity-scale-codec = { version = "3.4.0", default-features = false, features = [
1616
polkadot-parachain = { path = "../../../../parachain" }
1717
polkadot-primitives = { path = "../../../../primitives" }
1818

19+
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
1920
sc-executor-common = { git = "https://github.com/paritytech/substrate", branch = "master" }
2021
sc-executor-wasmtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
2122

2223
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
24+
sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "master" }
25+
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
2326
sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
2427

2528
[build-dependencies]

node/core/pvf/common/src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub enum PrepareError {
2929
Prevalidation(String),
3030
/// Compilation failed for the given PVF.
3131
Preparation(String),
32+
/// Instantiation of the WASM module instance failed.
33+
RuntimeConstruction(String),
3234
/// An unexpected panic has occurred in the preparation worker.
3335
Panic(String),
3436
/// Failed to prepare the PVF due to the time limit.
@@ -55,6 +57,8 @@ impl PrepareError {
5557
match self {
5658
Prevalidation(_) | Preparation(_) | Panic(_) => true,
5759
TimedOut | IoErr(_) | CreateTmpFileErr(_) | RenameTmpFileErr(_) => false,
60+
// Can occur due to issues with the PVF, but also due to local errors.
61+
RuntimeConstruction(_) => false,
5862
}
5963
}
6064
}
@@ -65,6 +69,7 @@ impl fmt::Display for PrepareError {
6569
match self {
6670
Prevalidation(err) => write!(f, "prevalidation: {}", err),
6771
Preparation(err) => write!(f, "preparation: {}", err),
72+
RuntimeConstruction(err) => write!(f, "runtime construction: {}", err),
6873
Panic(err) => write!(f, "panic: {}", err),
6974
TimedOut => write!(f, "prepare: timeout"),
7075
IoErr(err) => write!(f, "prepare: io error while receiving response: {}", err),

node/core/pvf/common/src/executor_intf.rs

Lines changed: 261 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@
1717
//! Interface to the Substrate Executor
1818
1919
use polkadot_primitives::{ExecutorParam, ExecutorParams};
20-
use sc_executor_common::wasm_runtime::HeapAllocStrategy;
21-
use sc_executor_wasmtime::{Config, DeterministicStackLimit, Semantics};
20+
use sc_executor_common::{
21+
error::WasmError,
22+
runtime_blob::RuntimeBlob,
23+
wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmModule as _},
24+
};
25+
use sc_executor_wasmtime::{Config, DeterministicStackLimit, Semantics, WasmtimeRuntime};
26+
use sp_core::storage::{ChildInfo, TrackedStorageKey};
27+
use sp_externalities::MultiRemovalResults;
28+
use std::any::{Any, TypeId};
2229

2330
// Memory configuration
2431
//
@@ -112,3 +119,255 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result<Semantics, S
112119
sem.deterministic_stack_limit = Some(stack_limit);
113120
Ok(sem)
114121
}
122+
123+
/// A WASM executor with a given configuration. It is instantiated once per execute worker and is
124+
/// specific to that worker.
125+
#[derive(Clone)]
126+
pub struct Executor {
127+
config: Config,
128+
}
129+
130+
impl Executor {
131+
pub fn new(params: ExecutorParams) -> Result<Self, String> {
132+
let mut config = DEFAULT_CONFIG.clone();
133+
config.semantics = params_to_wasmtime_semantics(&params)?;
134+
135+
Ok(Self { config })
136+
}
137+
138+
/// Executes the given PVF in the form of a compiled artifact and returns the result of execution
139+
/// upon success.
140+
///
141+
/// # Safety
142+
///
143+
/// The caller must ensure that the compiled artifact passed here was:
144+
/// 1) produced by [`prepare`],
145+
/// 2) was not modified,
146+
///
147+
/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution.
148+
pub unsafe fn execute(
149+
&self,
150+
compiled_artifact_blob: &[u8],
151+
params: &[u8],
152+
) -> Result<Vec<u8>, String> {
153+
let mut extensions = sp_externalities::Extensions::new();
154+
155+
extensions.register(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion));
156+
157+
let mut ext = ValidationExternalities(extensions);
158+
159+
match sc_executor::with_externalities_safe(&mut ext, || {
160+
let runtime = self.create_runtime_from_bytes(compiled_artifact_blob)?;
161+
runtime.new_instance()?.call(InvokeMethod::Export("validate_block"), params)
162+
}) {
163+
Ok(Ok(ok)) => Ok(ok),
164+
Ok(Err(err)) | Err(err) => Err(err),
165+
}
166+
.map_err(|err| format!("execute error: {:?}", err))
167+
}
168+
169+
/// Constructs the runtime for the given PVF, given the artifact bytes.
170+
///
171+
/// # Safety
172+
///
173+
/// The caller must ensure that the compiled artifact passed here was:
174+
/// 1) produced by [`prepare`],
175+
/// 2) was not modified,
176+
///
177+
/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution.
178+
pub unsafe fn create_runtime_from_bytes(
179+
&self,
180+
compiled_artifact_blob: &[u8],
181+
) -> Result<WasmtimeRuntime, WasmError> {
182+
sc_executor_wasmtime::create_runtime_from_artifact_bytes::<HostFunctions>(
183+
compiled_artifact_blob,
184+
self.config.clone(),
185+
)
186+
}
187+
}
188+
189+
/// Available host functions. We leave out:
190+
///
191+
/// 1. storage related stuff (PVF doesn't have a notion of a persistent storage/trie)
192+
/// 2. tracing
193+
/// 3. off chain workers (PVFs do not have such a notion)
194+
/// 4. runtime tasks
195+
/// 5. sandbox
196+
type HostFunctions = (
197+
sp_io::misc::HostFunctions,
198+
sp_io::crypto::HostFunctions,
199+
sp_io::hashing::HostFunctions,
200+
sp_io::allocator::HostFunctions,
201+
sp_io::logging::HostFunctions,
202+
sp_io::trie::HostFunctions,
203+
);
204+
205+
/// The validation externalities that will panic on any storage related access. (PVFs should not
206+
/// have a notion of a persistent storage/trie.)
207+
struct ValidationExternalities(sp_externalities::Extensions);
208+
209+
impl sp_externalities::Externalities for ValidationExternalities {
210+
fn storage(&self, _: &[u8]) -> Option<Vec<u8>> {
211+
panic!("storage: unsupported feature for parachain validation")
212+
}
213+
214+
fn storage_hash(&self, _: &[u8]) -> Option<Vec<u8>> {
215+
panic!("storage_hash: unsupported feature for parachain validation")
216+
}
217+
218+
fn child_storage_hash(&self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
219+
panic!("child_storage_hash: unsupported feature for parachain validation")
220+
}
221+
222+
fn child_storage(&self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
223+
panic!("child_storage: unsupported feature for parachain validation")
224+
}
225+
226+
fn kill_child_storage(
227+
&mut self,
228+
_child_info: &ChildInfo,
229+
_maybe_limit: Option<u32>,
230+
_maybe_cursor: Option<&[u8]>,
231+
) -> MultiRemovalResults {
232+
panic!("kill_child_storage: unsupported feature for parachain validation")
233+
}
234+
235+
fn clear_prefix(
236+
&mut self,
237+
_prefix: &[u8],
238+
_maybe_limit: Option<u32>,
239+
_maybe_cursor: Option<&[u8]>,
240+
) -> MultiRemovalResults {
241+
panic!("clear_prefix: unsupported feature for parachain validation")
242+
}
243+
244+
fn clear_child_prefix(
245+
&mut self,
246+
_child_info: &ChildInfo,
247+
_prefix: &[u8],
248+
_maybe_limit: Option<u32>,
249+
_maybe_cursor: Option<&[u8]>,
250+
) -> MultiRemovalResults {
251+
panic!("clear_child_prefix: unsupported feature for parachain validation")
252+
}
253+
254+
fn place_storage(&mut self, _: Vec<u8>, _: Option<Vec<u8>>) {
255+
panic!("place_storage: unsupported feature for parachain validation")
256+
}
257+
258+
fn place_child_storage(&mut self, _: &ChildInfo, _: Vec<u8>, _: Option<Vec<u8>>) {
259+
panic!("place_child_storage: unsupported feature for parachain validation")
260+
}
261+
262+
fn storage_root(&mut self, _: sp_core::storage::StateVersion) -> Vec<u8> {
263+
panic!("storage_root: unsupported feature for parachain validation")
264+
}
265+
266+
fn child_storage_root(&mut self, _: &ChildInfo, _: sp_core::storage::StateVersion) -> Vec<u8> {
267+
panic!("child_storage_root: unsupported feature for parachain validation")
268+
}
269+
270+
fn next_child_storage_key(&self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
271+
panic!("next_child_storage_key: unsupported feature for parachain validation")
272+
}
273+
274+
fn next_storage_key(&self, _: &[u8]) -> Option<Vec<u8>> {
275+
panic!("next_storage_key: unsupported feature for parachain validation")
276+
}
277+
278+
fn storage_append(&mut self, _key: Vec<u8>, _value: Vec<u8>) {
279+
panic!("storage_append: unsupported feature for parachain validation")
280+
}
281+
282+
fn storage_start_transaction(&mut self) {
283+
panic!("storage_start_transaction: unsupported feature for parachain validation")
284+
}
285+
286+
fn storage_rollback_transaction(&mut self) -> Result<(), ()> {
287+
panic!("storage_rollback_transaction: unsupported feature for parachain validation")
288+
}
289+
290+
fn storage_commit_transaction(&mut self) -> Result<(), ()> {
291+
panic!("storage_commit_transaction: unsupported feature for parachain validation")
292+
}
293+
294+
fn wipe(&mut self) {
295+
panic!("wipe: unsupported feature for parachain validation")
296+
}
297+
298+
fn commit(&mut self) {
299+
panic!("commit: unsupported feature for parachain validation")
300+
}
301+
302+
fn read_write_count(&self) -> (u32, u32, u32, u32) {
303+
panic!("read_write_count: unsupported feature for parachain validation")
304+
}
305+
306+
fn reset_read_write_count(&mut self) {
307+
panic!("reset_read_write_count: unsupported feature for parachain validation")
308+
}
309+
310+
fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
311+
panic!("get_whitelist: unsupported feature for parachain validation")
312+
}
313+
314+
fn set_whitelist(&mut self, _: Vec<TrackedStorageKey>) {
315+
panic!("set_whitelist: unsupported feature for parachain validation")
316+
}
317+
318+
fn set_offchain_storage(&mut self, _: &[u8], _: std::option::Option<&[u8]>) {
319+
panic!("set_offchain_storage: unsupported feature for parachain validation")
320+
}
321+
322+
fn get_read_and_written_keys(&self) -> Vec<(Vec<u8>, u32, u32, bool)> {
323+
panic!("get_read_and_written_keys: unsupported feature for parachain validation")
324+
}
325+
}
326+
327+
impl sp_externalities::ExtensionStore for ValidationExternalities {
328+
fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
329+
self.0.get_mut(type_id)
330+
}
331+
332+
fn register_extension_with_type_id(
333+
&mut self,
334+
type_id: TypeId,
335+
extension: Box<dyn sp_externalities::Extension>,
336+
) -> Result<(), sp_externalities::Error> {
337+
self.0.register_with_type_id(type_id, extension)
338+
}
339+
340+
fn deregister_extension_by_type_id(
341+
&mut self,
342+
type_id: TypeId,
343+
) -> Result<(), sp_externalities::Error> {
344+
if self.0.deregister(type_id) {
345+
Ok(())
346+
} else {
347+
Err(sp_externalities::Error::ExtensionIsNotRegistered(type_id))
348+
}
349+
}
350+
}
351+
352+
struct ReadRuntimeVersion;
353+
354+
impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion {
355+
fn read_runtime_version(
356+
&self,
357+
wasm_code: &[u8],
358+
_ext: &mut dyn sp_externalities::Externalities,
359+
) -> Result<Vec<u8>, String> {
360+
let blob = RuntimeBlob::uncompress_if_needed(wasm_code)
361+
.map_err(|e| format!("Failed to read the PVF runtime blob: {:?}", e))?;
362+
363+
match sc_executor::read_embedded_version(&blob)
364+
.map_err(|e| format!("Failed to read the static section from the PVF blob: {:?}", e))?
365+
{
366+
Some(version) => {
367+
use parity_scale_codec::Encode;
368+
Ok(version.encode())
369+
},
370+
None => Err("runtime version section is not found".to_string()),
371+
}
372+
}
373+
}

0 commit comments

Comments
 (0)