Unverified Commit 90d5dbe5 authored by Bastian Köcher's avatar Bastian Köcher Committed by GitHub
Browse files

Downward & Upward messages (#1266)

* Downward messages, the front-end.

* Move types around to make them accessible from Parachains

* Fix compilation

* Fix branch

* Make it compile for Cumulus

* Update the branch names

* Add default generic parameter

* Implement `Partialeq`

* Move upward messages into the `ValidationResult`

* Support disabling of the runtime api

* Update branch

* Adds support for handling downward messages

* Implement sending XCMP messages as up/downward messages

* service: update to latest ServiceBuilder changes

* Make it compile

* Initial commit

Forked at: b2c9c149


Parent branch: origin/master

* Update substrate branch to cecton-update-polkadot-substrate

* Update substrate & polkadot to cumulus-branch

* Reset branch

* Update primitives/src/parachain.rs

Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>

* Update runtime/common/src/parachains.rs

Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>

* Update runtime/common/src/parachains.rs

Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>

* Minor fixes

* Fix wasm build

Co-authored-by: default avatarGav Wood <gavin@parity.io>
Co-authored-by: default avatarAndré Silva <andre.beat@gmail.com>
Co-authored-by: default avatarCecile Tonglet <cecile.tonglet@cecton.com>
Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>
parent c6b29c7b
Pipeline #99049 passed with stages
in 22 minutes and 4 seconds
......@@ -4319,6 +4319,16 @@ dependencies = [
"tokio 0.2.21",
]
[[package]]
name = "polkadot-core-primitives"
version = "0.7.30"
dependencies = [
"parity-scale-codec",
"sp-core",
"sp-runtime",
"sp-std",
]
[[package]]
name = "polkadot-erasure-coding"
version = "0.8.13"
......@@ -4446,13 +4456,13 @@ dependencies = [
"log 0.4.8",
"parity-scale-codec",
"parking_lot 0.10.2",
"polkadot-core-primitives",
"sc-executor",
"serde",
"shared_memory",
"sp-core",
"sp-externalities",
"sp-io",
"sp-runtime-interface",
"sp-std",
"sp-wasm-interface",
]
......@@ -4464,6 +4474,7 @@ dependencies = [
"bitvec",
"frame-system",
"parity-scale-codec",
"polkadot-core-primitives",
"polkadot-parachain",
"pretty_assertions",
"serde",
......@@ -8043,6 +8054,7 @@ dependencies = [
"parity-scale-codec",
"polkadot-parachain",
"sp-io",
"sp-std",
"substrate-wasm-builder-runner 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.5.0",
]
......@@ -8070,6 +8082,7 @@ dependencies = [
"parity-scale-codec",
"polkadot-parachain",
"sp-io",
"sp-std",
"substrate-wasm-builder-runner 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.5.0",
]
......
......@@ -26,6 +26,7 @@ members = [
"availability-store",
"cli",
"collator",
"core-primitives",
"erasure-coding",
"network",
"network/test",
......
......@@ -33,7 +33,7 @@ use polkadot_primitives::{
},
};
use sp_runtime::traits::HashFor;
use sp_blockchain::{Result as ClientResult};
use sp_blockchain::Result as ClientResult;
use client::{
BlockchainEvents, BlockBackend,
};
......@@ -58,7 +58,7 @@ use worker::{
Worker, WorkerHandle, IncludedParachainBlocks, WorkerMsg, MakeAvailable, Chunks
};
use store::{Store as InnerStore};
use store::Store as InnerStore;
const LOG_TARGET: &str = "availability";
......
......@@ -18,7 +18,7 @@
use kvdb_rocksdb::{Database, DatabaseConfig};
use kvdb::{KeyValueDB, DBTransaction};
use codec::{Encode, Decode};
use polkadot_erasure_coding::{self as erasure};
use polkadot_erasure_coding as erasure;
use polkadot_primitives::{
Hash,
parachain::{
......
......@@ -56,7 +56,7 @@ use sc_client_api::{StateBackend, BlockchainEvents};
use sp_blockchain::HeaderBackend;
use sp_core::Pair;
use polkadot_primitives::{
BlockId, Hash, Block,
BlockId, Hash, Block, DownwardMessage,
parachain::{
self, BlockData, DutyRoster, HeadData, Id as ParaId,
PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationSchedule,
......@@ -150,6 +150,7 @@ pub trait ParachainContext: Clone {
relay_parent: Hash,
global_validation: GlobalValidationSchedule,
local_validation: LocalValidationData,
downward_messages: Vec<DownwardMessage>,
) -> Self::ProduceCandidate;
}
......@@ -159,6 +160,7 @@ pub async fn collate<P>(
local_id: ParaId,
global_validation: GlobalValidationSchedule,
local_validation_data: LocalValidationData,
downward_messages: Vec<DownwardMessage>,
mut para_context: P,
key: Arc<CollatorPair>,
) -> Option<parachain::Collation>
......@@ -170,6 +172,7 @@ pub async fn collate<P>(
relay_parent,
global_validation,
local_validation_data,
downward_messages,
).await?;
let pov_block = PoVBlock {
......@@ -317,6 +320,7 @@ fn build_collator_service<P, C, R, Extrinsic>(
Some(local_validation) => local_validation,
None => return future::Either::Left(future::ok(())),
};
let downward_messages = try_fr!(api.downward_messages(&id, para_id));
let validators = try_fr!(api.validators(&id));
......@@ -331,6 +335,7 @@ fn build_collator_service<P, C, R, Extrinsic>(
para_id,
global_validation,
local_validation,
downward_messages,
parachain_context,
key,
).map(move |collation| {
......@@ -470,6 +475,7 @@ mod tests {
_relay_parent: Hash,
_global: GlobalValidationSchedule,
_local_validation: LocalValidationData,
_: Vec<DownwardMessage>,
) -> Self::ProduceCandidate {
// send messages right back.
future::ready(Some((
......
[package]
name = "polkadot-core-primitives"
version = "0.7.30"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = [ "derive" ] }
[features]
default = [ "std" ]
std = [
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"codec/std",
]
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
#![cfg_attr(not(feature = "std"), no_std)]
//! Core Polkadot types.
//!
//! These core Polkadot types are used by the relay chain and the Parachains.
use sp_runtime::{generic, MultiSignature, traits::{Verify, BlakeTwo256, IdentifyAccount}};
/// The block number type used by Polkadot.
/// 32-bits will allow for 136 years of blocks assuming 1 block per second.
pub type BlockNumber = u32;
/// An instant or duration in time.
pub type Moment = u64;
/// Alias to type for a signature for a transaction on the relay chain. This allows one of several
/// kinds of underlying crypto to be used, so isn't a fixed size when encoded.
pub type Signature = MultiSignature;
/// Alias to the public key used for this chain, actually a `MultiSigner`. Like the signature, this
/// also isn't a fixed size when encoded, as different cryptos have different size public keys.
pub type AccountPublic = <Signature as Verify>::Signer;
/// Alias to the opaque account ID type for this chain, actually a `AccountId32`. This is always
/// 32 bytes.
pub type AccountId = <AccountPublic as IdentifyAccount>::AccountId;
/// The type for looking up accounts. We don't expect more than 4 billion of them.
pub type AccountIndex = u32;
/// Identifier for a chain. 32-bit should be plenty.
pub type ChainId = u32;
/// A hash of some data used by the relay chain.
pub type Hash = sp_core::H256;
/// Index of a transaction in the relay chain. 32-bit should be plenty.
pub type Nonce = u32;
/// The balance of an account.
/// 128-bits (or 38 significant decimal figures) will allow for 10m currency (10^7) at a resolution
/// to all for one second's worth of an annualised 50% reward be paid to a unit holder (10^11 unit
/// denomination), or 10^18 total atomic units, to grow at 50%/year for 51 years (10^9 multiplier)
/// for an eventual total of 10^27 units (27 significant decimal figures).
/// We round denomination to 10^12 (12 sdf), and leave the other redundancy at the upper end so
/// that 32 bits may be multiplied with a balance in 128 bits without worrying about overflow.
pub type Balance = u128;
/// Header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Block ID.
pub type BlockId = generic::BlockId<Block>;
/// Opaque, encoded, unchecked extrinsic.
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
/// The information that goes alongside a transfer_into_parachain operation. Entirely opaque, it
/// will generally be used for identifying the reason for the transfer. Typically it will hold the
/// destination account to which the transfer should be credited. If still more information is
/// needed, then this should be a hash with the pre-image presented via an off-chain mechanism on
/// the parachain.
pub type Remark = [u8; 32];
/// These are special "control" messages that can be passed from the Relaychain to a parachain.
/// They should be handled by all parachains.
#[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq)]
pub enum DownwardMessage<AccountId = crate::AccountId> {
/// Some funds were transferred into the parachain's account. The hash is the identifier that
/// was given with the transfer.
TransferInto(AccountId, Balance, Remark),
/// An opaque blob of data. The relay chain must somehow know how to form this so that the
/// destination parachain does something sensible.
///
/// NOTE: Be very careful not to allow users to place arbitrary size information in here.
Opaque(sp_std::vec::Vec<u8>),
/// XCMP message for the Parachain.
XCMPMessage(sp_std::vec::Vec<u8>),
}
......@@ -185,6 +185,9 @@ sp_api::mock_impl_runtime_apis! {
parent_hash: Default::default(),
}
}
fn downward_messages(_: ParaId) -> Vec<polkadot_primitives::DownwardMessage> {
Vec::new()
}
}
}
......
......@@ -13,11 +13,11 @@ codec = { package = "parity-scale-codec", version = "1.1.0", default-features =
sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-wasm-interface = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
polkadot-core-primitives = { path = "../core-primitives", default-features = false }
# all optional crates.
derive_more = { version = "0.99.2", optional = true }
serde = { version = "1.0.102", default-features = false, features = [ "derive" ], optional = true }
sp-runtime-interface = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true, default-features = false }
sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
......@@ -29,7 +29,7 @@ shared_memory = { version = "0.10.0", optional = true }
[features]
default = ["std"]
wasm-api = ["sp-runtime-interface"]
wasm-api = []
std = [
"codec/std",
"derive_more",
......@@ -39,8 +39,8 @@ std = [
"sp-core/std",
"parking_lot",
"log",
"sp-runtime-interface/std",
"sp-externalities",
"sc-executor",
"sp-io",
"polkadot-core-primitives/std",
]
......@@ -28,9 +28,8 @@ use serde::{Serialize, Deserialize};
#[cfg(feature = "std")]
use sp_core::bytes;
/// The block number of the relay chain.
/// 32-bits will allow for 136 years of blocks assuming 1 block per second.
pub type RelayChainBlockNumber = u32;
/// Block number type used by the relay chain.
pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;
/// Parachain head data included in the chain.
#[derive(PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug)]
......@@ -186,10 +185,6 @@ impl sp_std::convert::TryFrom<u8> for ParachainDispatchOrigin {
/// A message from a parachain to its Relay Chain.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[cfg_attr(
any(feature = "std", feature = "wasm-api"),
derive(sp_runtime_interface::pass_by::PassByCodec,
))]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct UpwardMessage {
/// The origin for the message to be sent from.
......@@ -212,13 +207,13 @@ pub struct ValidationParams {
/// The maximum head-data size permitted, in bytes.
pub max_head_data_size: u32,
/// The current relay-chain block number.
pub relay_chain_height: RelayChainBlockNumber,
pub relay_chain_height: polkadot_core_primitives::BlockNumber,
/// Whether a code upgrade is allowed or not, and at which height the upgrade
/// would be applied after, if so. The parachain logic should apply any upgrade
/// issued in this block after the first block
/// with `relay_chain_height` at least this value, if `Some`. if `None`, issue
/// no upgrade.
pub code_upgrade_allowed: Option<RelayChainBlockNumber>,
pub code_upgrade_allowed: Option<polkadot_core_primitives::BlockNumber>,
}
/// The result of parachain validation.
......@@ -230,4 +225,10 @@ pub struct ValidationResult {
pub head_data: HeadData,
/// An update to the validation code that should be scheduled in the relay chain.
pub new_validation_code: Option<ValidationCode>,
/// Upward messages send by the Parachain.
pub upward_messages: Vec<UpwardMessage>,
/// Number of downward messages that were processed by the Parachain.
///
/// It is expected that the Parachain processes them from first to last.
pub processed_downward_messages: u32,
}
......@@ -16,29 +16,6 @@
//! Utilities for writing parachain WASM.
#[cfg(any(feature = "std", all(not(feature = "std"), feature = "wasm-api")))]
use crate::primitives::UpwardMessage;
#[cfg(any(feature = "std", all(not(feature = "std"), feature = "wasm-api")))]
use sp_runtime_interface::runtime_interface;
#[cfg(feature = "std")]
use sp_externalities::ExternalitiesExt;
/// The parachain api for posting messages.
// Either activate on `std` to get access to the `HostFunctions` or when `wasm-api` is given and on
// `no_std`.
#[cfg(any(feature = "std", all(not(feature = "std"), feature = "wasm-api")))]
#[runtime_interface]
pub trait Parachain {
/// Post a message to this parachain's relay chain.
#[allow(dead_code)]
fn post_upward_message(&mut self, msg: UpwardMessage) {
self.extension::<crate::wasm_executor::ParachainExt>()
.expect("No `ParachainExt` associated with the current context.")
.post_upward_message(msg)
.expect("Failed to post upward message")
}
}
/// Load the validation params from memory when implementing a Rust parachain.
///
/// Offset and length must have been provided by the validation
......
......@@ -21,12 +21,12 @@
//! a WASM VM for re-execution of a parachain candidate.
use std::any::{TypeId, Any};
use crate::primitives::{ValidationParams, ValidationResult, UpwardMessage};
use crate::primitives::{ValidationParams, ValidationResult};
use codec::{Decode, Encode};
use sp_core::storage::ChildInfo;
use sp_core::traits::CallInWasm;
use sp_wasm_interface::HostFunctions as _;
use sp_externalities::Extensions;
use sp_wasm_interface::HostFunctions as _;
#[cfg(not(any(target_os = "android", target_os = "unknown")))]
pub use validation_host::{run_worker, ValidationPool, EXECUTION_TIMEOUT_SEC};
......@@ -37,18 +37,6 @@ mod validation_host;
const MAX_RUNTIME_MEM: usize = 1024 * 1024 * 1024; // 1 GiB
const MAX_CODE_MEM: usize = 16 * 1024 * 1024; // 16 MiB
sp_externalities::decl_extension! {
/// The extension that is registered at the `Externalities` when validating a parachain state
/// transition.
pub(crate) struct ParachainExt(Box<dyn Externalities>);
}
impl ParachainExt {
pub fn new<T: Externalities + 'static>(ext: T) -> Self {
Self(Box::new(ext))
}
}
/// A stub validation-pool defined when compiling for Android or WASM.
#[cfg(any(target_os = "android", target_os = "unknown"))]
#[derive(Clone)]
......@@ -124,32 +112,25 @@ impl std::error::Error for Error {
}
}
/// Externalities for parachain validation.
pub trait Externalities: Send {
/// Called when a message is to be posted to the parachain's relay chain.
fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String>;
}
/// Validate a candidate under the given validation code.
///
/// This will fail if the validation code is not a proper parachain validation module.
pub fn validate_candidate<E: Externalities + 'static>(
pub fn validate_candidate(
validation_code: &[u8],
params: ValidationParams,
ext: E,
options: ExecutionMode<'_>,
) -> Result<ValidationResult, Error> {
match options {
ExecutionMode::Local => {
validate_candidate_internal(validation_code, &params.encode(), ext)
validate_candidate_internal(validation_code, &params.encode())
},
#[cfg(not(any(target_os = "android", target_os = "unknown")))]
ExecutionMode::Remote(pool) => {
pool.validate_candidate(validation_code, params, ext, false)
pool.validate_candidate(validation_code, params, false)
},
#[cfg(not(any(target_os = "android", target_os = "unknown")))]
ExecutionMode::RemoteTest(pool) => {
pool.validate_candidate(validation_code, params, ext, true)
pool.validate_candidate(validation_code, params, true)
},
#[cfg(any(target_os = "android", target_os = "unknown"))]
ExecutionMode::Remote(pool) =>
......@@ -165,21 +146,16 @@ pub fn validate_candidate<E: Externalities + 'static>(
}
/// The host functions provided by the wasm executor to the parachain wasm blob.
type HostFunctions = (
sp_io::SubstrateHostFunctions,
crate::wasm_api::parachain::HostFunctions,
);
type HostFunctions = sp_io::SubstrateHostFunctions;
/// Validate a candidate under the given validation code.
///
/// This will fail if the validation code is not a proper parachain validation module.
pub fn validate_candidate_internal<E: Externalities + 'static>(
pub fn validate_candidate_internal(
validation_code: &[u8],
encoded_call_data: &[u8],
externalities: E,
) -> Result<ValidationResult, Error> {
let mut extensions = Extensions::new();
extensions.register(ParachainExt::new(externalities));
extensions.register(sp_core::traits::TaskExecutorExt(sp_core::tasks::executor()));
let mut ext = ValidationExternalities(extensions);
......
......@@ -16,18 +16,15 @@
#![cfg(not(any(target_os = "android", target_os = "unknown")))]
use std::{process, env, sync::Arc, sync::atomic, mem};
use codec::{Decode, Encode, EncodeAppend};
use crate::primitives::{ValidationParams, ValidationResult, UpwardMessage};
use super::{validate_candidate_internal, Error, Externalities};
use std::{process, env, sync::Arc, sync::atomic};
use codec::{Decode, Encode};
use crate::primitives::{ValidationParams, ValidationResult};
use super::{validate_candidate_internal, Error};
use super::{MAX_CODE_MEM, MAX_RUNTIME_MEM};
use shared_memory::{SharedMem, SharedMemConf, EventState, WriteLockable, EventWait, EventSet};
use parking_lot::Mutex;
use log::{debug, trace};
// Message data limit
const MAX_MESSAGE_MEM: usize = 16 * 1024 * 1024; // 16 MiB
const WORKER_ARGS_TEST: &[&'static str] = &["--nocapture", "validation_worker"];
/// CLI Argument to start in validation worker mode.
const WORKER_ARG: &'static str = "validation-worker";
......@@ -40,27 +37,6 @@ pub const EXECUTION_TIMEOUT_SEC: u64 = 30;
#[cfg(not(debug_assertions))]
pub const EXECUTION_TIMEOUT_SEC: u64 = 5;
#[derive(Default)]
struct WorkerExternalitiesInner {
up_data: Vec<u8>,
}
#[derive(Default, Clone)]
struct WorkerExternalities {
inner: Arc<Mutex<WorkerExternalitiesInner>>,
}
impl Externalities for WorkerExternalities {
fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String> {
let mut inner = self.inner.lock();
inner.up_data = <Vec::<UpwardMessage> as EncodeAppend>::append_or_new(
mem::replace(&mut inner.up_data, Vec::new()),
std::iter::once(message),
).map_err(|e| e.what())?;
Ok(())
}
}
enum Event {
CandidateReady = 0,
ResultReady = 1,
......@@ -87,21 +63,20 @@ impl ValidationPool {
/// free validation host.
///
/// This will fail if the validation code is not a proper parachain validation module.
pub fn validate_candidate<E: Externalities>(
pub fn validate_candidate(
&self,
validation_code: &[u8],
params: ValidationParams,
externalities: E,
test_mode: bool,
) -> Result<ValidationResult, Error> {
for host in self.hosts.iter() {
if let Some(mut host) = host.try_lock() {
return host.validate_candidate(validation_code, params, externalities, test_mode);
return host.validate_candidate(validation_code, params, test_mode);
}
}
// all workers are busy, just wait for the first one
self.hosts[0].lock().validate_candidate(validation_code, params, externalities, test_mode)
self.hosts[0].lock().validate_candidate(validation_code, params, test_mode)
}
}
......@@ -116,8 +91,6 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
}
};
let worker_ext = WorkerExternalities::default();
let exit = Arc::new(atomic::AtomicBool::new(false));
// spawn parent monitor thread
let watch_exit = exit.clone();
......@@ -166,21 +139,11 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
let (call_data, _) = rest.split_at_mut(MAX_RUNTIME_MEM);
let (call_data, _) = call_data.split_at_mut(header.params_size as usize);
let result = validate_candidate_internal(code, call_data, worker_ext.clone());
let result = validate_candidate_internal(code, call_data);
debug!("{} Candidate validated: {:?}", process::id(), result);
match result {
Ok(r) => {
let inner = worker_ext.inner.lock();
let up_data = &inner.up_data;
let up_len = up_data.len();
if up_len > MAX_MESSAGE_MEM {
ValidationResultHeader::Error("Message data is too large".into())
} else {
ValidationResultHeader::Ok(r)
}
},
Ok(r) => ValidationResultHeader::Ok(r),
Err(e) => ValidationResultHeader::Error(e.to_string()),
}
};
......@@ -226,7 +189,7 @@ impl Drop for ValidationHost {
impl ValidationHost {
fn create_memory() -> Result<SharedMem, Error> {
let mem_size = MAX_RUNTIME_MEM + MAX_CODE_MEM + MAX_MESSAGE_MEM + 1024;
let mem_size = MAX_RUNTIME_MEM + MAX_CODE_MEM + 1024;
let mem_config = SharedMemConf::default()
.set_size(mem_size)
.add_lock(shared_memory::LockType::Mutex, 0, mem_size)?
......@@ -268,11 +231,10 @@ impl ValidationHost {
/// Validate a candidate under the given validation code.
///
/// This will fail if the validation code is not a proper parachain validation module.
pub fn validate_candidate<E: Externalities>(
pub fn validate_candidate(
&mut self,
validation_code: &[u8],
params: ValidationParams,
mut externalities: E,
test_mode: bool,
) -> Result<ValidationResult, Error> {
if validation_code.len() > MAX_CODE_MEM {
......@@ -322,24 +284,11 @@ impl ValidationHost {
{