diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index 00096abb39d15abe046bc707957e3417d57b041a..c50f2e0b0d6ab4226f0a62bb49619282b52a14d6 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -29,7 +29,8 @@ dependencies = [
  "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "exit-future 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "polkadot-collator 0.7.15",
  "polkadot-parachain 0.7.15",
  "polkadot-primitives 0.7.15",
@@ -2623,7 +2624,6 @@ name = "lock_api"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -3500,14 +3500,6 @@ dependencies = [
  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "parity-wasm"
-version = "0.31.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "parity-wasm"
 version = "0.41.0"
@@ -3542,6 +3534,15 @@ dependencies = [
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "parking_lot"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "parking_lot_core"
 version = "0.4.0"
@@ -3583,6 +3584,19 @@ dependencies = [
  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "parking_lot_core"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "paste"
 version = "0.1.6"
@@ -3803,18 +3817,21 @@ name = "polkadot-parachain"
 version = "0.7.15"
 dependencies = [
  "adder 0.7.15",
- "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "halt 0.7.15",
  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sc-executor 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
  "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
- "shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shared_memory 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "sp-core 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
+ "sp-externalities 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
+ "sp-io 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
+ "sp-runtime-interface 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
  "sp-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
  "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -5412,19 +5429,32 @@ dependencies = [
 
 [[package]]
 name = "shared_memory"
-version = "0.8.2"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "memrange 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shared_memory_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "theban_interval_tree 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "shared_memory_derive"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "shell32-sys"
 version = "0.1.2"
@@ -6897,16 +6927,6 @@ dependencies = [
  "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "wasmi"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "wasmi"
 version = "0.6.2"
@@ -6920,14 +6940,6 @@ dependencies = [
  "wasmi-validation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "wasmi-validation"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "wasmi-validation"
 version = "0.3.0"
@@ -7556,14 +7568,15 @@ dependencies = [
 "checksum parity-scale-codec-derive 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "492ac3aa93d6caa5d20e4e3e0b75d08e2dcd9dd8a50d19529548b6fe11b3f295"
 "checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f"
 "checksum parity-util-mem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8174d85e62c4d615fddd1ef67966bdc5757528891d0742f15b131ad04667b3f9"
-"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc"
 "checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865"
+"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc"
 "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
 "checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
 "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
 "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
 "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
 "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
+"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1"
 "checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49"
 "checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
 "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
@@ -7683,7 +7696,8 @@ dependencies = [
 "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
 "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
 "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
-"checksum shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be289420c5900abb177b756f39625ca7a0df68069cfb242fb31feb6e8c480f04"
+"checksum shared_memory 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3ab0cdff84d6c66fc9e268010ea6508e58ee942575afb66f2cf194bb218bb4"
+"checksum shared_memory_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767a14f1304be2f0b04e69860252f8ae9cfae0afaa9cc07b675147c43425dd3a"
 "checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
 "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
 "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
@@ -7829,9 +7843,7 @@ dependencies = [
 "checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d"
 "checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5"
 "checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac"
-"checksum wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aebbaef470840d157a5c47c8c49f024da7b1b80e90ff729ca982b2b80447e78b"
 "checksum wasmi 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff"
-"checksum wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab380192444b3e8522ae79c0a1976e42a82920916ccdfbce3def89f456ea33f3"
 "checksum wasmi-validation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93"
 "checksum wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470"
 "checksum wasmtime-debug 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5008729ad53f75020f28fa0d682269335d6f0eac0b3ffafe31f185b2f33aca74"
diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml
index 7c0af4f8d9744901c4b52d357d870e72bcb6f4f9..a5fdb4cd0ec966b86c118e3042f7c1c9ccc5e7e2 100644
--- a/polkadot/parachain/Cargo.toml
+++ b/polkadot/parachain/Cargo.toml
@@ -7,17 +7,20 @@ edition = "2018"
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "1.1.0", default-features = false, features = [ "derive" ] }
-wasmi = { version = "0.4.5", optional = true }
-derive_more = { version = "0.14.1", optional = true }
-serde = { version = "1.0.102", default-features = false, features = [ "derive" ] }
+derive_more = { version = "0.99.2", optional = true }
+serde = { version = "1.0.102", default-features = false, features = [ "derive" ], optional = true }
 rstd = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
 sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
+sp-runtime-interface = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
+sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", optional = true }
+sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", optional = true }
+sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", optional = true }
 lazy_static = { version = "1.4.0", optional = true }
-parking_lot = { version = "0.7.1", optional = true }
+parking_lot = { version = "0.10.0", optional = true }
 log = { version = "0.4.8", optional = true }
 
 [target.'cfg(not(target_os = "unknown"))'.dependencies]
-shared_memory = { version = "0.8.2", optional = true }
+shared_memory = { version = "0.10.0", optional = true }
 
 [dev-dependencies]
 tiny-keccak = "1.5.0"
@@ -29,7 +32,6 @@ default = ["std"]
 wasm-api = []
 std = [
 	"codec/std",
-	"wasmi",
 	"derive_more",
 	"serde/std",
 	"rstd/std",
@@ -37,5 +39,9 @@ std = [
 	"sp-core/std",
 	"lazy_static",
 	"parking_lot",
-	"log"
+	"log",
+	"sp-runtime-interface/std",
+	"sp-externalities",
+	"sc-executor",
+	"sp-io",
 ]
diff --git a/polkadot/parachain/src/lib.rs b/polkadot/parachain/src/lib.rs
index 19d176c7f4f45e413336e3a70fdfb958db841eb3..3f1993a23e550749d17ae4a2c257e3f0420b9b22 100644
--- a/polkadot/parachain/src/lib.rs
+++ b/polkadot/parachain/src/lib.rs
@@ -22,40 +22,40 @@
 //! ## Parachain WASM
 //!
 //! Polkadot parachain WASM is in the form of a module which imports a memory
-//! instance and exports a function `validate`.
+//! instance and exports a function `validate_block`.
 //!
 //! `validate` accepts as input two `i32` values, representing a pointer/length pair
-//! respectively, that encodes `ValidationParams`.
+//! respectively, that encodes [`ValidationParams`].
 //!
-//! `validate` returns an `i32` which is a pointer to a little-endian 32-bit integer denoting a length.
-//! Subtracting the length from the initial pointer will give a new pointer to the actual return data,
+//! `validate` returns an `u64` which is a pointer to an `u8` array and its length.
+//! The data in the array is expected to be a SCALE encoded [`ValidationResult`].
 //!
 //! ASCII-diagram demonstrating the return data format:
 //!
 //! ```ignore
-//! [return data][len (LE-u32)]
-//!              ^~~returned pointer
+//! [pointer][length]
+//!   32bit   32bit
+//!         ^~~ returned pointer & length
 //! ```
 //!
-//! The `wasm_api` module (enabled only with the wasm-api feature) provides utilities
-//!  for setting up a parachain WASM module in Rust.
+//! The wasm-api (enabled only when `std` feature is not enabled and `wasm-api` feature is enabled)
+//! provides utilities for setting up a parachain WASM module in Rust.
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
-/// Re-export of parity-codec.
-pub use codec;
-
 #[cfg(feature = "std")]
 pub mod wasm_executor;
 
-#[cfg(feature = "wasm-api")]
-pub mod wasm_api;
+mod wasm_api;
 
-use rstd::vec::Vec;
+use rstd::{vec::Vec, cmp::Ordering};
 
 use codec::{Encode, Decode, CompactAs};
 use sp_core::{RuntimeDebug, TypeId};
 
+#[cfg(all(not(feature = "std"), feature = "wasm-api"))]
+pub use wasm_api::*;
+
 /// Validation parameters for evaluating the parachain validity function.
 // TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
 #[derive(PartialEq, Eq, Decode)]
@@ -155,7 +155,8 @@ pub trait AccountIdConversion<AccountId>: Sized {
 	fn try_from_account(a: &AccountId) -> Option<Self>;
 }
 
- /// Format is b"para" ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to fill AccountId.
+/// Format is b"para" ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing
+/// zeroes to fill AccountId.
 impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
 	fn into_account(&self) -> T {
 		(b"para", self).using_encoded(|b|
@@ -177,24 +178,6 @@ impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
 	}
 }
 
-/// An incoming message.
-#[derive(PartialEq, Eq, Decode)]
-#[cfg_attr(feature = "std", derive(Debug, Encode))]
-pub struct IncomingMessage {
-	/// The source parachain.
-	pub source: Id,
-	/// The data of the message.
-	pub data: Vec<u8>,
-}
-
-/// A reference to a message.
-pub struct MessageRef<'a> {
-	/// The target parachain.
-	pub target: Id,
-	/// Underlying data of the message.
-	pub data: &'a [u8],
-}
-
 /// Which origin a parachain's message to the relay chain should be dispatched from.
 #[derive(Clone, PartialEq, Eq, Encode, Decode)]
 #[cfg_attr(feature = "std", derive(Debug))]
@@ -224,16 +207,8 @@ impl rstd::convert::TryFrom<u8> for ParachainDispatchOrigin {
 	}
 }
 
-/// A reference to an upward message.
-pub struct UpwardMessageRef<'a> {
-	/// The origin type.
-	pub origin: ParachainDispatchOrigin,
-	/// Underlying data of the message.
-	pub data: &'a [u8],
-}
-
 /// A message from a parachain to its Relay Chain.
-#[derive(Clone, PartialEq, Eq, Encode, Decode)]
+#[derive(Clone, PartialEq, Eq, Encode, Decode, sp_runtime_interface::pass_by::PassByCodec)]
 #[cfg_attr(feature = "std", derive(Debug))]
 pub struct UpwardMessage {
 	/// The origin for the message to be sent from.
@@ -241,3 +216,43 @@ pub struct UpwardMessage {
 	/// The message data.
 	pub data: Vec<u8>,
 }
+
+/// An incoming message.
+#[derive(PartialEq, Eq, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Encode))]
+pub struct IncomingMessage {
+	/// The source parachain.
+	pub source: Id,
+	/// The data of the message.
+	pub data: Vec<u8>,
+}
+
+/// A message targeted to a specific parachain.
+#[derive(Clone, PartialEq, Eq, Encode, Decode, sp_runtime_interface::pass_by::PassByCodec)]
+#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Debug))]
+#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
+#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
+pub struct TargetedMessage {
+	/// The target parachain.
+	pub target: Id,
+	/// The message data.
+	pub data: Vec<u8>,
+}
+
+impl AsRef<[u8]> for TargetedMessage {
+	fn as_ref(&self) -> &[u8] {
+		&self.data[..]
+	}
+}
+
+impl PartialOrd for TargetedMessage {
+	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+		Some(self.target.cmp(&other.target))
+	}
+}
+
+impl Ord for TargetedMessage {
+	fn cmp(&self, other: &Self) -> Ordering {
+		self.target.cmp(&other.target)
+	}
+}
diff --git a/polkadot/parachain/src/wasm_api.rs b/polkadot/parachain/src/wasm_api.rs
index 808cd2ef9285476b0422206d08f8278d145b664c..89cbcd6b37b034f032d1c8c4ede9d54af7978277 100644
--- a/polkadot/parachain/src/wasm_api.rs
+++ b/polkadot/parachain/src/wasm_api.rs
@@ -16,13 +16,31 @@
 
 //! Utilities for writing parachain WASM.
 
-use codec::{Encode, Decode};
-use super::{ValidationParams, ValidationResult, MessageRef, UpwardMessageRef};
+use crate::{TargetedMessage, UpwardMessage};
+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 another parachain.
+	fn post_message(&mut self, msg: TargetedMessage) {
+		self.extension::<crate::wasm_executor::ParachainExt>()
+			.expect("No `ParachainExt` associated with the current context.")
+			.post_message(msg)
+			.expect("Failed to post message")
+	}
 
-mod ll {
-	extern "C" {
-		pub(super) fn ext_post_message(target: u32, data_ptr: *const u8, data_len: u32);
-		pub(super) fn ext_post_upward_message(origin: u32, data_ptr: *const u8, data_len: u32);
+	/// Post a message to this parachain's relay chain.
+	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")
 	}
 }
 
@@ -30,43 +48,18 @@ mod ll {
 ///
 /// Offset and length must have been provided by the validation
 /// function's entry point.
-pub unsafe fn load_params(params: *const u8, len: usize) -> ValidationParams {
+#[cfg(not(feature = "std"))]
+pub unsafe fn load_params(params: *const u8, len: usize) -> crate::ValidationParams {
 	let mut slice = rstd::slice::from_raw_parts(params, len);
 
-	ValidationParams::decode(&mut slice).expect("Invalid input data")
+	codec::Decode::decode(&mut slice).expect("Invalid input data")
 }
 
 /// Allocate the validation result in memory, getting the return-pointer back.
 ///
 /// As described in the crate docs, this is a pointer to the appended length
 /// of the vector.
-pub fn write_result(result: ValidationResult) -> usize {
-	let mut encoded = result.encode();
-	let len = encoded.len();
-
-	assert!(len <= u32::max_value() as usize, "Len too large for parachain-WASM abi");
-	(len as u32).using_encoded(|s| encoded.extend(s));
-
-	// do not alter `encoded` beyond this point. may reallocate.
-	let end_ptr = &encoded[len] as *const u8 as usize;
-
-	// leak so it doesn't get zeroed.
-	rstd::mem::forget(encoded);
-	end_ptr
-}
-
-/// Post a message to another parachain.
-pub fn post_message(message: MessageRef) {
-	let data_ptr = message.data.as_ptr();
-	let data_len = message.data.len();
-
-	unsafe { ll::ext_post_message(message.target.into(), data_ptr, data_len as u32) }
-}
-
-/// Post a message to this parachain's relay chain.
-pub fn post_upward_message(message: UpwardMessageRef) {
-	let data_ptr = message.data.as_ptr();
-	let data_len = message.data.len();
-
-	unsafe { ll::ext_post_upward_message(u32::from(message.origin as u8), data_ptr, data_len as u32) }
+#[cfg(not(feature = "std"))]
+pub fn write_result(result: &crate::ValidationResult) -> u64 {
+	sp_core::to_substrate_wasm_fn_return_value(&result)
 }
diff --git a/polkadot/parachain/src/wasm_executor/mod.rs b/polkadot/parachain/src/wasm_executor/mod.rs
index aeae386eb17089d4aedb65f9a646f8293e75b8f2..00bf3e6b0d6cf722924784c55ab750563988df97 100644
--- a/polkadot/parachain/src/wasm_executor/mod.rs
+++ b/polkadot/parachain/src/wasm_executor/mod.rs
@@ -20,16 +20,10 @@
 //! Assuming the parameters are correct, this module provides a wrapper around
 //! a WASM VM for re-execution of a parachain candidate.
 
-use std::{cell::RefCell, fmt, convert::TryInto};
-use crate::codec::{Decode, Encode};
-use wasmi::{
-	self, Module, ModuleInstance, Trap, MemoryInstance, MemoryDescriptor, MemoryRef,
-	ModuleImportResolver, RuntimeValue, Externals, Error as WasmError, ValueType,
-	memory_units::{self, Bytes, Pages, RoundUpTo}
-};
-use super::{
-	ValidationParams, ValidationResult, MessageRef, UpwardMessageRef,
-	UpwardMessage, IncomingMessage};
+use std::any::{TypeId, Any};
+use crate::{ValidationParams, ValidationResult, UpwardMessage, TargetedMessage};
+use codec::{Decode, Encode};
+use sp_core::storage::{ChildStorageKey, ChildInfo};
 
 #[cfg(not(target_os = "unknown"))]
 pub use validation_host::{run_worker, EXECUTION_TIMEOUT_SEC};
@@ -40,12 +34,16 @@ mod validation_host;
 const MAX_RUNTIME_MEM: usize = 1024 * 1024 * 1024; // 1 GiB
 const MAX_CODE_MEM: usize = 16 * 1024 * 1024; // 16 MiB
 
-mod ids {
-	/// Post a message to another parachain.
-	pub const POST_MESSAGE: usize = 1;
+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>);
+}
 
-	/// Post a message to this parachain's relay chain.
-	pub const POST_UPWARD_MESSAGE: usize = 2;
+impl ParachainExt {
+	pub fn new<T: Externalities + 'static>(ext: T) -> Self {
+		Self(Box::new(ext))
+	}
 }
 
 /// WASM code execution mode.
@@ -63,16 +61,16 @@ pub enum ExecutionMode {
 /// Error type for the wasm executor
 #[derive(Debug, derive_more::Display, derive_more::From)]
 pub enum Error {
-	/// Wasm error
-	Wasm(WasmError),
-	/// Externalities error
-	Externalities(ExternalitiesError),
-	/// Code size it too large.
-	#[display(fmt = "WASM code is {} bytes, max allowed is {}", _0, MAX_CODE_MEM)]
-	CodeTooLarge(usize),
+	/// Wasm executor error.
+	#[display(fmt = "WASM executor error: {:?}", _0)]
+	WasmExecutor(sc_executor::error::Error),
 	/// Call data is too large.
 	#[display(fmt = "Validation parameters are {} bytes, max allowed is {}", _0, MAX_RUNTIME_MEM)]
+	#[from(ignore)]
 	ParamsTooLarge(usize),
+	/// Code size it too large.
+	#[display(fmt = "WASM code is {} bytes, max allowed is {}", _0, MAX_CODE_MEM)]
+	CodeTooLarge(usize),
 	/// Bad return data or type.
 	#[display(fmt = "Validation function returned invalid data.")]
 	BadReturn,
@@ -84,372 +82,177 @@ pub enum Error {
 	System(Box<dyn std::error::Error>),
 	#[display(fmt = "WASM worker error: {}", _0)]
 	External(String),
+	#[display(fmt = "Shared memory error: {}", _0)]
+	#[cfg(not(target_os = "unknown"))]
+	SharedMem(shared_memory::SharedMemError),
 }
 
 impl std::error::Error for Error {
 	fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
 		match self {
-			Error::Wasm(ref err) => Some(err),
-			Error::Externalities(ref err) => Some(err),
+			Error::WasmExecutor(ref err) => Some(err),
 			Error::Io(ref err) => Some(err),
 			Error::System(ref err) => Some(&**err),
+			#[cfg(not(target_os = "unknown"))]
+			Error::SharedMem(ref err) => Some(err),
 			_ => None,
 		}
 	}
 }
 
-/// Errors that can occur in externalities of parachain validation.
-#[derive(Debug, Clone)]
-pub enum ExternalitiesError {
-	/// Unable to post a message due to the given reason.
-	CannotPostMessage(&'static str),
-}
-
 /// Externalities for parachain validation.
-pub trait Externalities {
+pub trait Externalities: Send {
 	/// Called when a message is to be posted to another parachain.
-	fn post_message(&mut self, message: MessageRef) -> Result<(), ExternalitiesError>;
+	fn post_message(&mut self, message: TargetedMessage) -> Result<(), String>;
 
 	/// Called when a message is to be posted to the parachain's relay chain.
-	fn post_upward_message(&mut self, message: UpwardMessageRef) -> Result<(), ExternalitiesError>;
+	fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String>;
 }
 
-impl fmt::Display for ExternalitiesError {
-	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-		match *self {
-			ExternalitiesError::CannotPostMessage(ref s)
-				=> write!(f, "Cannot post message: {}", s),
-		}
+/// 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>(
+	validation_code: &[u8],
+	params: ValidationParams,
+	ext: E,
+	options: ExecutionMode,
+) -> Result<ValidationResult, Error> {
+	match options {
+		ExecutionMode::Local => {
+			validate_candidate_internal(validation_code, &params.encode(), ext)
+		},
+		#[cfg(not(target_os = "unknown"))]
+		ExecutionMode::Remote => {
+			validation_host::validate_candidate(validation_code, params, ext, false)
+		},
+		#[cfg(not(target_os = "unknown"))]
+		ExecutionMode::RemoteTest => {
+			validation_host::validate_candidate(validation_code, params, ext, true)
+		},
+		#[cfg(target_os = "unknown")]
+		ExecutionMode::Remote =>
+			Err(Error::System("Remote validator not available".to_string().into())),
+		#[cfg(target_os = "unknown")]
+		ExecutionMode::RemoteTest =>
+			Err(Error::System("Remote validator not available".to_string().into())),
 	}
 }
 
-impl wasmi::HostError for ExternalitiesError {}
-impl std::error::Error for ExternalitiesError {}
+/// The host functions provided by the wasm executor to the parachain wasm blob.
+type HostFunctions = (sp_io::SubstrateHostFunctions, crate::wasm_api::parachain::HostFunctions);
+
+/// 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>(
+	validation_code: &[u8],
+	encoded_call_data: &[u8],
+	externalities: E,
+) -> Result<ValidationResult, Error> {
+	let mut ext = ValidationExternalities(ParachainExt::new(externalities));
 
-struct Resolver {
-	max_memory: u32, // in pages.
-	memory: RefCell<Option<MemoryRef>>,
+	let res = sc_executor::call_in_wasm::<_, HostFunctions>(
+		"validate_block",
+		encoded_call_data,
+		sc_executor::WasmExecutionMethod::Interpreted,
+		&mut ext,
+		validation_code,
+		// TODO: Make sure we don't use more than 1GB: https://github.com/paritytech/polkadot/issues/699
+		1024,
+	)?;
+
+	ValidationResult::decode(&mut &res[..]).map_err(|_| Error::BadReturn.into())
 }
 
-impl ModuleImportResolver for Resolver {
-	fn resolve_func(
-		&self,
-		field_name: &str,
-		signature: &wasmi::Signature
-	) -> Result<wasmi::FuncRef, WasmError> {
-		match field_name {
-			"ext_post_message" => {
-				let index = ids::POST_MESSAGE;
-				let (params, ret_ty): (&[ValueType], Option<ValueType>) =
-					(&[ValueType::I32, ValueType::I32, ValueType::I32], None);
-
-				if signature.params() != params || signature.return_type() != ret_ty {
-					Err(WasmError::Instantiation(
-						format!("Export {} has a bad signature", field_name)
-					))
-				} else {
-					Ok(wasmi::FuncInstance::alloc_host(
-						wasmi::Signature::new(&params[..], ret_ty),
-						index,
-					))
-				}
-			}
-			"ext_upwards_post_message" => {
-				let index = ids::POST_UPWARD_MESSAGE;
-				let (params, ret_ty): (&[ValueType], Option<ValueType>) =
-					(&[ValueType::I32, ValueType::I32], None);
-
-				if signature.params() != params || signature.return_type() != ret_ty {
-					Err(WasmError::Instantiation(
-						format!("Export {} has a bad signature", field_name)
-					))
-				} else {
-					Ok(wasmi::FuncInstance::alloc_host(
-						wasmi::Signature::new(&params[..], ret_ty),
-						index,
-					))
-				}
-			}
-			_ => {
-				Err(WasmError::Instantiation(
-					format!("Export {} not found", field_name),
-				))
-			}
-		}
+/// The validation externalities that will panic on any storage related access. They just provide
+/// access to the parachain extension.
+struct ValidationExternalities(ParachainExt);
 
+impl sp_externalities::Externalities for ValidationExternalities {
+	fn storage(&self, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("storage: unsupported feature for parachain validation")
 	}
 
-	fn resolve_memory(
-		&self,
-		field_name: &str,
-		descriptor: &MemoryDescriptor,
-	) -> Result<MemoryRef, WasmError> {
-		if field_name == "memory" {
-			let effective_max = descriptor.maximum().unwrap_or(self.max_memory);
-			if descriptor.initial() > self.max_memory || effective_max > self.max_memory {
-				Err(WasmError::Instantiation("Module requested too much memory".to_owned()))
-			} else {
-				let mem = MemoryInstance::alloc(
-					memory_units::Pages(descriptor.initial() as usize),
-					descriptor.maximum().map(|x| memory_units::Pages(x as usize)),
-				)?;
-				*self.memory.borrow_mut() = Some(mem.clone());
-				Ok(mem)
-			}
-		} else {
-			Err(WasmError::Instantiation("Memory imported under unknown name".to_owned()))
-		}
+	fn storage_hash(&self, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("storage_hash: unsupported feature for parachain validation")
 	}
-}
 
-struct ValidationExternals<'a, E: 'a> {
-	externalities: &'a mut E,
-	memory: &'a MemoryRef,
-}
+	fn child_storage_hash(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("child_storage_hash: unsupported feature for parachain validation")
+	}
 
-impl<'a, E: 'a + Externalities> ValidationExternals<'a, E> {
-	/// Signature: post_message(u32, *const u8, u32) -> None
-	/// usage: post_message(target parachain, data ptr, data len).
-	/// Data is the raw data of the message.
-	fn ext_post_message(&mut self, args: ::wasmi::RuntimeArgs) -> Result<(), Trap> {
-		let target: u32 = args.nth_checked(0)?;
-		let data_ptr: u32 = args.nth_checked(1)?;
-		let data_len: u32 = args.nth_checked(2)?;
-
-		let (data_ptr, data_len) = (data_ptr as usize, data_len as usize);
-
-		self.memory.with_direct_access(|mem| {
-			if mem.len() < (data_ptr + data_len) {
-				Err(Trap::new(wasmi::TrapKind::MemoryAccessOutOfBounds))
-			} else {
-				let res = self.externalities.post_message(MessageRef {
-					target: target.into(),
-					data: &mem[data_ptr..][..data_len],
-				});
-
-				res.map_err(|e| Trap::new(wasmi::TrapKind::Host(
-					Box::new(e) as Box<_>
-				)))
-			}
-		})
+	fn original_storage(&self, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("original_sorage: unsupported feature for parachain validation")
 	}
-	/// Signature: post_upward_message(u32, *const u8, u32) -> None
-	/// usage: post_upward_message(origin, data ptr, data len).
-	/// Origin is the integer representation of the dispatch origin.
-	/// Data is the raw data of the message.
-	fn ext_post_upward_message(&mut self, args: ::wasmi::RuntimeArgs) -> Result<(), Trap> {
-		let origin: u32 = args.nth_checked(0)?;
-		let data_ptr: u32 = args.nth_checked(1)?;
-		let data_len: u32 = args.nth_checked(2)?;
-
-		let (data_ptr, data_len) = (data_ptr as usize, data_len as usize);
-
-		self.memory.with_direct_access(|mem| {
-			if mem.len() < (data_ptr + data_len) {
-				Err(Trap::new(wasmi::TrapKind::MemoryAccessOutOfBounds))
-			} else {
-				let origin = (origin as u8).try_into()
-					.map_err(|_| Trap::new(wasmi::TrapKind::UnexpectedSignature))?;
-				let message = UpwardMessageRef { origin, data: &mem[data_ptr..][..data_len] };
-				let res = self.externalities.post_upward_message(message);
-				res.map_err(|e| Trap::new(wasmi::TrapKind::Host(
-					Box::new(e) as Box<_>
-				)))
-			}
-		})
+
+	fn original_child_storage(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("original_child_storage: unsupported feature for parachain validation")
 	}
-}
 
-impl<'a, E: 'a + Externalities> Externals for ValidationExternals<'a, E> {
-	fn invoke_index(
-		&mut self,
-		index: usize,
-		args: ::wasmi::RuntimeArgs,
-	) -> Result<Option<RuntimeValue>, Trap> {
-		match index {
-			ids::POST_MESSAGE => self.ext_post_message(args).map(|_| None),
-			ids::POST_UPWARD_MESSAGE => self.ext_post_upward_message(args).map(|_| None),
-			_ => panic!("no externality at given index"),
-		}
+	fn original_storage_hash(&self, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("original_storage_hash: unsupported feature for parachain validation")
 	}
-}
 
-/// Params header in shared memory. All offsets should be aligned to WASM page size.
-#[derive(Encode, Decode, Debug)]
-struct ValidationHeader {
-	code_size: u64,
-	params_size: u64,
-}
+	fn original_child_storage_hash(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("original_child_storage_hash: unsupported feature for parachain validation")
+	}
 
-#[derive(Encode, Decode, Debug)]
-pub enum ValidationResultHeader {
-	Ok {
-		result: ValidationResult,
-		egress_message_count: u64,
-		up_message_count: u64,
-	},
-	Error(String),
-}
+	fn child_storage(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("child_storage: unsupported feature for parachain validation")
+	}
 
+	fn kill_child_storage(&mut self, _: ChildStorageKey, _: ChildInfo) {
+		panic!("kill_child_storage: unsupported feature for parachain validation")
+	}
 
-#[derive(Default)]
-struct WorkerExternalities {
-	egress_data: Vec<u8>,
-	egress_message_count: usize,
-	up_data: Vec<u8>,
-	up_message_count: usize,
-}
+	fn clear_prefix(&mut self, _: &[u8]) {
+		panic!("clear_prefix: unsupported feature for parachain validation")
+	}
 
-impl Externalities for WorkerExternalities {
-	fn post_message(&mut self, message: MessageRef) -> Result<(), ExternalitiesError> {
-		IncomingMessage {
-			source: message.target,
-			data: message.data.to_vec(),
-		}
-		.encode_to(&mut self.egress_data);
-		self.egress_message_count += 1;
-		Ok(())
+	fn clear_child_prefix(&mut self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) {
+		panic!("clear_child_prefix: unsupported feature for parachain validation")
 	}
 
-	fn post_upward_message(&mut self, message: UpwardMessageRef) -> Result<(), ExternalitiesError> {
-		UpwardMessage {
-			origin: message.origin,
-			data: message.data.to_vec(),
-		}
-		.encode_to(&mut self.up_data);
-		self.up_message_count += 1;
-		Ok(())
+	fn place_storage(&mut self, _: Vec<u8>, _: Option<Vec<u8>>) {
+		panic!("place_storage: unsupported feature for parachain validation")
 	}
-}
 
-/// 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>(
-	validation_code: &[u8],
-	params: ValidationParams,
-	externalities: &mut E,
-	options: ExecutionMode,
-	) -> Result<ValidationResult, Error>
-{
-	match options {
-		ExecutionMode::Local => {
-			validate_candidate_internal(validation_code, &params.encode(), externalities)
-		},
-		#[cfg(not(target_os = "unknown"))]
-		ExecutionMode::Remote =>
-			validation_host::validate_candidate(validation_code, params, externalities, false),
-		#[cfg(not(target_os = "unknown"))]
-		ExecutionMode::RemoteTest =>
-			validation_host::validate_candidate(validation_code, params, externalities, true),
-		#[cfg(target_os = "unknown")]
-		ExecutionMode::Remote =>
-			Err(Error::System("Remote validator not available".to_string().into())),
-		#[cfg(target_os = "unknown")]
-		ExecutionMode::RemoteTest =>
-			Err(Error::System("Remote validator not available".to_string().into())),
+	fn place_child_storage(&mut self, _: ChildStorageKey, _: ChildInfo, _: Vec<u8>, _: Option<Vec<u8>>) {
+		panic!("place_child_storage: unsupported feature for parachain validation")
 	}
-}
 
-/// 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>(
-	validation_code: &[u8],
-	encoded_call_data: &[u8],
-	externalities: &mut E,
-	) -> Result<ValidationResult, Error> {
-	use wasmi::LINEAR_MEMORY_PAGE_SIZE;
-
-	// instantiate the module.
-	let memory;
-	let mut externals;
-	let module = {
-		let module = Module::from_buffer(validation_code)?;
-
-		let module_resolver = Resolver {
-			max_memory: (MAX_RUNTIME_MEM / LINEAR_MEMORY_PAGE_SIZE.0) as u32,
-			memory: RefCell::new(None),
-		};
-
-		let module = ModuleInstance::new(
-			&module,
-			&wasmi::ImportsBuilder::new().with_resolver("env", &module_resolver),
-		)?;
-
-		memory = module_resolver.memory.borrow()
-			.as_ref()
-			.ok_or_else(|| WasmError::Instantiation("No imported memory instance".to_owned()))?
-			.clone();
-
-		externals = ValidationExternals {
-			externalities,
-			memory: &memory,
-		};
-
-		module.run_start(&mut externals).map_err(WasmError::Trap)?
-	};
-
-	// allocate call data in memory.
-	// we guarantee that:
-	// - `offset` has alignment at least of 8,
-	// - `len` is not zero.
-	let (offset, len) = {
-		// hard limit from WASM.
-		if encoded_call_data.len() > i32::max_value() as usize {
-			return Err(Error::ParamsTooLarge(encoded_call_data.len()));
-		}
+	fn chain_id(&self) -> u64 {
+		panic!("chain_id: unsupported feature for parachain validation")
+	}
 
-		// allocate sufficient amount of wasm pages to fit encoded call data.
-		let call_data_pages: Pages = Bytes(encoded_call_data.len()).round_up_to();
-		let allocated_mem_start: Bytes = memory.grow(call_data_pages)?.into();
+	fn storage_root(&mut self) -> Vec<u8> {
+		panic!("storage_root: unsupported feature for parachain validation")
+	}
 
-		memory.set(allocated_mem_start.0 as u32, &encoded_call_data)
-			.expect(
-				"enough memory allocated just before this; \
-				copying never fails if memory is large enough; qed"
-			);
+	fn child_storage_root(&mut self, _: ChildStorageKey) -> Vec<u8> {
+		panic!("child_storage_root: unsupported feature for parachain validation")
+	}
 
-		(allocated_mem_start.0, encoded_call_data.len())
-	};
+	fn storage_changes_root(&mut self, _: &[u8]) -> Result<Option<Vec<u8>>, ()> {
+		panic!("storage_changes_root: unsupported feature for parachain validation")
+	}
 
-	let output = module.invoke_export(
-		"validate_block",
-		&[RuntimeValue::I32(offset as i32), RuntimeValue::I32(len as i32)],
-		&mut externals,
-	).map_err(|e| -> Error {
-		e.as_host_error()
-			.and_then(|he| he.downcast_ref::<ExternalitiesError>())
-			.map(|ee| Error::Externalities(ee.clone()))
-			.unwrap_or_else(move || e.into())
-	})?;
-
-	match output {
-		Some(RuntimeValue::I32(len_offset)) => {
-			let len_offset = len_offset as u32;
-
-			let mut len_bytes = [0u8; 4];
-			memory.get_into(len_offset, &mut len_bytes)?;
-			let len_offset = len_offset as usize;
-
-			let len = u32::decode(&mut &len_bytes[..])
-				.map_err(|_| Error::BadReturn)? as usize;
-
-			let return_offset = if len > len_offset {
-				return Err(Error::BadReturn);
-			} else {
-				len_offset - len
-			};
-
-			memory.with_direct_access(|mem| {
-				if mem.len() < return_offset + len {
-					return Err(Error::BadReturn);
-				}
-
-				ValidationResult::decode(&mut &mem[return_offset..][..len])
-					.map_err(|_| Error::BadReturn.into())
-			})
+	fn next_child_storage_key(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("next_child_storage_key: unsupported feature for parachain validation")
+	}
+
+	fn next_storage_key(&self, _: &[u8]) -> Option<Vec<u8>> {
+		panic!("next_storage_key: unsupported feature for parachain validation")
+	}
+}
+
+impl sp_externalities::ExtensionStore for ValidationExternalities {
+	fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
+		if type_id == TypeId::of::<ParachainExt>() {
+			Some(&mut self.0)
+		} else {
+			None
 		}
-		_ => Err(Error::BadReturn),
 	}
 }
diff --git a/polkadot/parachain/src/wasm_executor/validation_host.rs b/polkadot/parachain/src/wasm_executor/validation_host.rs
index 19e4999ec15ed90a9f0f7b5d7c92ec59f1828feb..a92a00f5612e11ce6be1735c6c7689a1ff06117d 100644
--- a/polkadot/parachain/src/wasm_executor/validation_host.rs
+++ b/polkadot/parachain/src/wasm_executor/validation_host.rs
@@ -16,11 +16,10 @@
 
 #![cfg(not(target_os = "unknown"))]
 
-use std::{process, env, sync::Arc, sync::atomic};
-use crate::codec::{Decode, Encode};
-use crate::{ValidationParams, ValidationResult, MessageRef,
-	UpwardMessageRef, UpwardMessage, IncomingMessage};
-use super::{validate_candidate_internal, Error, Externalities, WorkerExternalities};
+use std::{process, env, sync::Arc, sync::atomic, mem};
+use codec::{Decode, Encode, EncodeAppend};
+use crate::{ValidationParams, ValidationResult, UpwardMessage, TargetedMessage};
+use super::{validate_candidate_internal, Error, Externalities};
 use super::{MAX_CODE_MEM, MAX_RUNTIME_MEM};
 use shared_memory::{SharedMem, SharedMemConf, EventState, WriteLockable, EventWait, EventSet};
 use parking_lot::Mutex;
@@ -39,6 +38,37 @@ const NUM_HOSTS: usize = 8;
 /// Execution timeout in seconds;
 pub const EXECUTION_TIMEOUT_SEC: u64 =  5;
 
+#[derive(Default)]
+struct WorkerExternalitiesInner {
+	egress_data: Vec<u8>,
+	up_data: Vec<u8>,
+}
+
+#[derive(Default, Clone)]
+struct WorkerExternalities {
+	inner: Arc<Mutex<WorkerExternalitiesInner>>,
+}
+
+impl Externalities for WorkerExternalities {
+	fn post_message(&mut self, message: TargetedMessage) -> Result<(), String> {
+		let mut inner = self.inner.lock();
+		inner.egress_data = <Vec::<TargetedMessage> as EncodeAppend>::append_or_new(
+			mem::replace(&mut inner.egress_data, Vec::new()),
+			std::iter::once(message),
+		).map_err(|e| e.what())?;
+		Ok(())
+	}
+
+	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,
@@ -59,7 +89,8 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
 			return Err(format!("Error opening shared memory: {:?}", e));
 		}
 	};
-	let mut externalities = WorkerExternalities::default();
+
+	let worker_ext = WorkerExternalities::default();
 
 	let exit = Arc::new(atomic::AtomicBool::new(false));
 	// spawn parent monitor thread
@@ -67,7 +98,8 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
 	std::thread::spawn(move || {
 		use std::io::Read;
 		let mut in_data = Vec::new();
-		std::io::stdin().read_to_end(&mut in_data).ok(); // pipe terminates when parent process exits
+ 		// pipe terminates when parent process exits
+		std::io::stdin().read_to_end(&mut in_data).ok();
 		debug!("Parent process is dead. Exiting");
 		exit.store(true, atomic::Ordering::Relaxed);
 	});
@@ -109,23 +141,25 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
 				let (call_data, _) = call_data.split_at_mut(header.params_size as usize);
 				let message_data = rest;
 
-				let result = validate_candidate_internal(code, call_data, &mut externalities);
+				let result = validate_candidate_internal(code, call_data, worker_ext.clone());
 				debug!("Candidate validated: {:?}", result);
 
 				match result {
 					Ok(r) => {
-						if externalities.egress_data.len() + externalities.up_data.len() > MAX_MESSAGE_MEM {
+						let inner = worker_ext.inner.lock();
+						let egress_data = &inner.egress_data;
+						let e_len = egress_data.len();
+						let up_data = &inner.up_data;
+						let up_len = up_data.len();
+
+						if e_len + up_len > MAX_MESSAGE_MEM {
 							ValidationResultHeader::Error("Message data is too large".into())
 						} else {
-							let e_len = externalities.egress_data.len();
-							let up_len = externalities.up_data.len();
-							message_data[0..e_len].copy_from_slice(&externalities.egress_data);
-							message_data[e_len..(e_len + up_len)].copy_from_slice(&externalities.up_data);
-							ValidationResultHeader::Ok {
-								result: r,
-								egress_message_count: externalities.egress_message_count as u64,
-								up_message_count: externalities.up_message_count as u64,
-							}
+							message_data[0..e_len].copy_from_slice(egress_data);
+
+							message_data[e_len..(e_len + up_len)].copy_from_slice(&up_data);
+
+							ValidationResultHeader::Ok(r)
 						}
 					},
 					Err(e) => ValidationResultHeader::Error(e.to_string()),
@@ -150,11 +184,7 @@ struct ValidationHeader {
 
 #[derive(Encode, Decode, Debug)]
 pub enum ValidationResultHeader {
-	Ok {
-		result: ValidationResult,
-		egress_message_count: u64,
-		up_message_count: u64,
-	},
+	Ok(ValidationResult),
 	Error(String),
 }
 
@@ -166,14 +196,13 @@ struct ValidationHost {
 	memory: Option<SharedMem>,
 }
 
-
 /// 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>(
 	validation_code: &[u8],
 	params: ValidationParams,
-	externalities: &mut E,
+	externalities: E,
 	test_mode: bool,
 ) -> Result<ValidationResult, Error> {
 	for host in HOSTS.iter() {
@@ -197,7 +226,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_config = SharedMemConf::new()
+		let mem_config = SharedMemConf::default()
 			.set_size(mem_size)
 			.add_lock(shared_memory::LockType::Mutex, 0, mem_size)?
 			.add_event(shared_memory::EventType::Auto)?  // Event::CandidateReady
@@ -226,7 +255,10 @@ impl ValidationHost {
 			.spawn()?;
 		self.worker = Some(worker);
 
-		memory.wait(Event::WorkerReady as usize, shared_memory::Timeout::Sec(EXECUTION_TIMEOUT_SEC as usize))?;
+		memory.wait(
+			Event::WorkerReady as usize,
+			shared_memory::Timeout::Sec(EXECUTION_TIMEOUT_SEC as usize),
+		)?;
 		self.memory = Some(memory);
 		Ok(())
 	}
@@ -238,7 +270,7 @@ impl ValidationHost {
 		&mut self,
 		validation_code: &[u8],
 		params: ValidationParams,
-		externalities: &mut E,
+		mut externalities: E,
 		test_mode: bool,
 	) -> Result<ValidationResult, Error> {
 		if validation_code.len() > MAX_CODE_MEM {
@@ -246,7 +278,8 @@ impl ValidationHost {
 		}
 		// First, check if need to spawn the child process
 		self.start_worker(test_mode)?;
-		let memory = self.memory.as_mut().expect("memory is always `Some` after `start_worker` completes successfully");
+		let memory = self.memory.as_mut()
+			.expect("memory is always `Some` after `start_worker` completes successfully");
 		{
 			// Put data in shared mem
 			let data: &mut[u8] = &mut **memory.wlock_as_slice(0)?;
@@ -293,23 +326,23 @@ impl ValidationHost {
 			let mut message_data: &[u8] = message_data;
 			let header = ValidationResultHeader::decode(&mut header_buf).unwrap();
 			match header {
-				ValidationResultHeader::Ok { result, egress_message_count, up_message_count } => {
-					for _ in 0 .. egress_message_count {
-						let message = IncomingMessage::decode(&mut message_data).unwrap();
-						let message_ref = MessageRef {
-							target: message.source,
-							data: &message.data,
-						};
-						externalities.post_message(message_ref)?;
-					}
-					for _ in 0 .. up_message_count {
-						let message = UpwardMessage::decode(&mut message_data).unwrap();
-						let message_ref = UpwardMessageRef {
-							origin: message.origin,
-							data: &message.data,
-						};
-						externalities.post_upward_message(message_ref)?;
-					}
+				ValidationResultHeader::Ok(result) => {
+					let egress = Vec::<TargetedMessage>::decode(&mut message_data)
+						.map_err(|e|
+							Error::External(
+								format!("Could not decode egress messages: {}", e.what())
+							)
+						)?;
+					egress.into_iter().try_for_each(|msg| externalities.post_message(msg))?;
+
+					let upwards = Vec::<UpwardMessage>::decode(&mut message_data)
+						.map_err(|e|
+							Error::External(
+								format!("Could not decode upward messages: {}", e.what())
+							)
+						)?;
+					upwards.into_iter().try_for_each(|msg| externalities.post_upward_message(msg))?;
+
 					Ok(result)
 				}
 				ValidationResultHeader::Error(message) => {
diff --git a/polkadot/parachain/tests/adder/mod.rs b/polkadot/parachain/tests/adder/mod.rs
index 20e0d08fbdafbfbec6450c8cd5dfbc9b96467a8e..ba99659f440aa997364ef0171a52bb5e3c437c46 100644
--- a/polkadot/parachain/tests/adder/mod.rs
+++ b/polkadot/parachain/tests/adder/mod.rs
@@ -18,8 +18,7 @@
 
 use polkadot_parachain as parachain;
 
-use crate::parachain::{IncomingMessage, ValidationParams};
-use crate::DummyExt;
+use crate::{DummyExt, parachain::{IncomingMessage, ValidationParams}};
 use codec::{Decode, Encode};
 
 /// Head data for this parachain.
@@ -78,7 +77,7 @@ pub fn execute_good_on_parent() {
 			block_data: block_data.encode(),
 			ingress: Vec::new(),
 		},
-		&mut DummyExt,
+		DummyExt,
 		parachain::wasm_executor::ExecutionMode::RemoteTest,
 	).unwrap();
 
@@ -114,7 +113,7 @@ fn execute_good_chain_on_parent() {
 				block_data: block_data.encode(),
 				ingress: Vec::new(),
 			},
-			&mut DummyExt,
+			DummyExt,
 			parachain::wasm_executor::ExecutionMode::RemoteTest,
 		).unwrap();
 
@@ -150,7 +149,7 @@ fn execute_bad_on_parent() {
 			block_data: block_data.encode(),
 			ingress: Vec::new(),
 		},
-		&mut DummyExt,
+		DummyExt,
 		parachain::wasm_executor::ExecutionMode::RemoteTest,
 	).unwrap_err();
 }
@@ -182,7 +181,7 @@ fn processes_messages() {
 				IncomingMessage { source: 3.into(), data: (AddMessage { amount: 256 }).encode() },
 			],
 		},
-		&mut DummyExt,
+		DummyExt,
 		parachain::wasm_executor::ExecutionMode::RemoteTest,
 	).unwrap();
 
diff --git a/polkadot/parachain/tests/lib.rs b/polkadot/parachain/tests/lib.rs
index 976a62b0490d72afc548e20282ce36fb8f17cd02..4fa252ac5891ac644319dffacd36ec1310f25821 100644
--- a/polkadot/parachain/tests/lib.rs
+++ b/polkadot/parachain/tests/lib.rs
@@ -19,16 +19,15 @@ mod wasm_executor;
 
 use polkadot_parachain as parachain;
 use crate::parachain::{
-	MessageRef, UpwardMessageRef,
-	wasm_executor::{Externalities, ExternalitiesError, run_worker},
+	TargetedMessage, UpwardMessage, wasm_executor::{Externalities, run_worker},
 };
 
 struct DummyExt;
 impl Externalities for DummyExt {
-	fn post_message(&mut self, _message: MessageRef) -> Result<(), ExternalitiesError> {
+	fn post_message(&mut self, _: TargetedMessage) -> Result<(), String> {
 		Ok(())
 	}
-	fn post_upward_message(&mut self, _message: UpwardMessageRef) -> Result<(), ExternalitiesError> {
+	fn post_upward_message(&mut self, _: UpwardMessage) -> Result<(), String> {
 		Ok(())
 	}
 }
diff --git a/polkadot/parachain/tests/wasm_executor/mod.rs b/polkadot/parachain/tests/wasm_executor/mod.rs
index e4ecfa3b1ec37228017b6d93cbbbbce0da04f6f9..8873427d151619c8edaa551a92f88603fd66c128 100644
--- a/polkadot/parachain/tests/wasm_executor/mod.rs
+++ b/polkadot/parachain/tests/wasm_executor/mod.rs
@@ -32,7 +32,7 @@ fn terminates_on_timeout() {
 			block_data: Vec::new(),
 			ingress: Vec::new(),
 		},
-		&mut DummyExt,
+		DummyExt,
 		parachain::wasm_executor::ExecutionMode::RemoteTest,
 	);
 	match result {
@@ -55,7 +55,7 @@ fn parallel_execution() {
 			block_data: Vec::new(),
 			ingress: Vec::new(),
 		},
-		&mut DummyExt,
+		DummyExt,
 		parachain::wasm_executor::ExecutionMode::RemoteTest,
 	).ok());
 	let _ = parachain::wasm_executor::validate_candidate(
@@ -65,7 +65,7 @@ fn parallel_execution() {
 			block_data: Vec::new(),
 			ingress: Vec::new(),
 		},
-		&mut DummyExt,
+		DummyExt,
 		parachain::wasm_executor::ExecutionMode::RemoteTest,
 	);
 	thread.join().unwrap();
diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/parachain.rs
index 32c5f6b5d65223363e3ea86df96f0f06846eba17..6f77b41589210c032ee346078f60086b1c4d40b8 100644
--- a/polkadot/primitives/src/parachain.rs
+++ b/polkadot/primitives/src/parachain.rs
@@ -35,7 +35,7 @@ use application_crypto::KeyTypeId;
 use trie::TrieConfiguration;
 
 pub use polkadot_parachain::{
-	Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage,
+	Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage, TargetedMessage,
 };
 
 /// The key type ID for a collator key.
@@ -164,36 +164,6 @@ pub struct DutyRoster {
 	pub validator_duty: Vec<Chain>,
 }
 
-/// A message targeted to a specific parachain.
-#[derive(Clone, PartialEq, Eq, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
-#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
-#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
-pub struct TargetedMessage {
-	/// The target parachain.
-	pub target: Id,
-	/// The message data.
-	pub data: Vec<u8>,
-}
-
-impl AsRef<[u8]> for TargetedMessage {
-	fn as_ref(&self) -> &[u8] {
-		&self.data[..]
-	}
-}
-
-impl PartialOrd for TargetedMessage {
-	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-		Some(self.target.cmp(&other.target))
-	}
-}
-
-impl Ord for TargetedMessage {
-	fn cmp(&self, other: &Self) -> Ordering {
-		self.target.cmp(&other.target)
-	}
-}
-
 /// Outgoing message data for a parachain candidate.
 ///
 /// This is data produced by evaluating the candidate. It contains
diff --git a/polkadot/test-parachains/adder/build.rs b/polkadot/test-parachains/adder/build.rs
index f57cf711a737c5e9dab1c462631eacc8fef08272..d6b0652e85fe76b40bf1f5f3a9beefd52ddfcd64 100644
--- a/polkadot/test-parachains/adder/build.rs
+++ b/polkadot/test-parachains/adder/build.rs
@@ -20,6 +20,6 @@ fn main() {
 	build_current_project_with_rustflags(
 		"wasm_binary.rs",
 		WasmBuilderSource::Crates("1.0.7"),
-		"-C link-arg=--import-memory",
+		"-C link-arg=--export=__heap_base",
 	);
 }
diff --git a/polkadot/test-parachains/adder/collator/Cargo.toml b/polkadot/test-parachains/adder/collator/Cargo.toml
index b694bd6f937f81903018c418d2c096a9a4e55978..54761a425fb8148b6d47e40e7d37769b8a857bde 100644
--- a/polkadot/test-parachains/adder/collator/Cargo.toml
+++ b/polkadot/test-parachains/adder/collator/Cargo.toml
@@ -12,7 +12,8 @@ primitives = { package = "polkadot-primitives", path = "../../../primitives" }
 sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
 client = { package = "sc-client", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
 client-api = { package = "sc-client-api", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
-parking_lot = "0.9.0"
+parking_lot = "0.10.0"
+codec = { package = "parity-scale-codec", version = "1.1.0" }
 ctrlc = { version = "3.1.3", features = ["termination"] }
 futures = "0.3.1"
 exit-future = "0.2.0"
diff --git a/polkadot/test-parachains/adder/collator/src/main.rs b/polkadot/test-parachains/adder/collator/src/main.rs
index e2783ca626e2c55a1723875b2621b264628e8c49..00f11851a8e5fb9179761b24fbcd1f6587f018fd 100644
--- a/polkadot/test-parachains/adder/collator/src/main.rs
+++ b/polkadot/test-parachains/adder/collator/src/main.rs
@@ -22,7 +22,7 @@ use std::sync::Arc;
 
 use adder::{HeadData as AdderHead, BlockData as AdderBody};
 use sp_core::{Pair, Blake2Hasher};
-use parachain::codec::{Encode, Decode};
+use codec::{Encode, Decode};
 use primitives::{
 	Hash, Block,
 	parachain::{
diff --git a/polkadot/test-parachains/adder/src/wasm_validation.rs b/polkadot/test-parachains/adder/src/wasm_validation.rs
index 1f41257235d55b7496cd822dfcb9816bba02faf7..52775b009d7119574e798b9432ad2691cb2147ac 100644
--- a/polkadot/test-parachains/adder/src/wasm_validation.rs
+++ b/polkadot/test-parachains/adder/src/wasm_validation.rs
@@ -19,7 +19,7 @@
 use crate::{HeadData, BlockData};
 use core::{intrinsics, panic};
 use parachain::ValidationResult;
-use parachain::codec::{Encode, Decode};
+use codec::{Encode, Decode};
 
 #[panic_handler]
 #[no_mangle]
@@ -38,8 +38,8 @@ pub fn oom(_: core::alloc::Layout) -> ! {
 }
 
 #[no_mangle]
-pub extern fn validate_block(params: *const u8, len: usize) -> usize {
-	let params = unsafe { parachain::wasm_api::load_params(params, len) };
+pub extern fn validate_block(params: *const u8, len: usize) -> u64 {
+	let params = unsafe { parachain::load_params(params, len) };
 	let parent_head = HeadData::decode(&mut &params.parent_head[..])
 		.expect("invalid parent head format.");
 
@@ -55,9 +55,9 @@ pub extern fn validate_block(params: *const u8, len: usize) -> usize {
 	);
 
 	match crate::execute(parent_hash, parent_head, &block_data, from_messages) {
-		Ok(new_head) => parachain::wasm_api::write_result(
-			ValidationResult { head_data: new_head.encode() }
+		Ok(new_head) => parachain::write_result(
+			&ValidationResult { head_data: new_head.encode() }
 		),
 		Err(_) => panic!("execution failure"),
 	}
-}
\ No newline at end of file
+}
diff --git a/polkadot/test-parachains/halt/build.rs b/polkadot/test-parachains/halt/build.rs
index f57cf711a737c5e9dab1c462631eacc8fef08272..d6b0652e85fe76b40bf1f5f3a9beefd52ddfcd64 100644
--- a/polkadot/test-parachains/halt/build.rs
+++ b/polkadot/test-parachains/halt/build.rs
@@ -20,6 +20,6 @@ fn main() {
 	build_current_project_with_rustflags(
 		"wasm_binary.rs",
 		WasmBuilderSource::Crates("1.0.7"),
-		"-C link-arg=--import-memory",
+		"-C link-arg=--export=__heap_base",
 	);
 }
diff --git a/polkadot/validation/src/collation.rs b/polkadot/validation/src/collation.rs
index dee15f161fe22a83d90fba301e67069377bb91c4..08a1eb6fcf4e1f4ab45f322303078352b1e3878b 100644
--- a/polkadot/validation/src/collation.rs
+++ b/polkadot/validation/src/collation.rs
@@ -21,17 +21,23 @@
 
 use std::sync::Arc;
 
-use polkadot_primitives::{BlakeTwo256, Block, Hash, HashT, BlockId, Balance, parachain::{
-	CollatorId, ConsolidatedIngress, StructuredUnroutedIngress, CandidateReceipt, CollationInfo, ParachainHost,
-	Id as ParaId, Collation, TargetedMessage, OutgoingMessages, UpwardMessage, FeeSchedule, ErasureChunk,
-	HeadData, PoVBlock,
-}};
-use polkadot_erasure_coding::{self as erasure};
+use polkadot_primitives::{
+	BlakeTwo256, Block, Hash, HashT, BlockId, Balance,
+	parachain::{
+		CollatorId, ConsolidatedIngress, StructuredUnroutedIngress, CandidateReceipt, CollationInfo,
+		ParachainHost, Id as ParaId, Collation, OutgoingMessages, FeeSchedule, ErasureChunk,
+		HeadData, PoVBlock,
+	},
+};
+use polkadot_erasure_coding as erasure;
 use runtime_primitives::traits::ProvideRuntimeApi;
-use parachain::{wasm_executor::{self, ExternalitiesError, ExecutionMode}, MessageRef, UpwardMessageRef};
+use parachain::{
+	wasm_executor::{self, ExecutionMode}, TargetedMessage, UpwardMessage,
+};
 use trie::TrieConfiguration;
 use futures::prelude::*;
 use log::debug;
+use parking_lot::Mutex;
 
 /// Encapsulates connections to collators and allows collation on any parachain.
 ///
@@ -239,7 +245,7 @@ fn check_egress(
 	Ok(OutgoingMessages { outgoing_messages: outgoing })
 }
 
-struct Externalities {
+struct ExternalitiesInner {
 	parachain_index: ParaId,
 	outgoing: Vec<TargetedMessage>,
 	upward: Vec<UpwardMessage>,
@@ -248,41 +254,44 @@ struct Externalities {
 	fee_schedule: FeeSchedule,
 }
 
-impl wasm_executor::Externalities for Externalities {
-	fn post_message(&mut self, message: MessageRef) -> Result<(), ExternalitiesError> {
-		let target: ParaId = message.target.into();
-		if target == self.parachain_index {
-			return Err(ExternalitiesError::CannotPostMessage("posted message to self"));
+impl wasm_executor::Externalities for ExternalitiesInner {
+	fn post_message(&mut self, message: TargetedMessage) -> Result<(), String> {
+		if message.target == self.parachain_index {
+			return Err("posted message to self".into())
 		}
 
 		self.apply_message_fee(message.data.len())?;
-		self.outgoing.push(TargetedMessage {
-			target,
-			data: message.data.to_vec(),
-		});
+		self.outgoing.push(message);
 
 		Ok(())
 	}
 
-	fn post_upward_message(&mut self, message: UpwardMessageRef)
-		-> Result<(), ExternalitiesError>
-	{
+	fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String> {
 		self.apply_message_fee(message.data.len())?;
 
-		self.upward.push(UpwardMessage {
-			origin: message.origin,
-			data: message.data.to_vec(),
-		});
+		self.upward.push(message);
+
 		Ok(())
 	}
 }
 
-impl Externalities {
-	fn apply_message_fee(&mut self, message_len: usize) -> Result<(), ExternalitiesError> {
+impl ExternalitiesInner {
+	fn new(parachain_index: ParaId, free_balance: Balance, fee_schedule: FeeSchedule) -> Self {
+		Self {
+			parachain_index,
+			free_balance,
+			fee_schedule,
+			fees_charged: 0,
+			upward: Vec::new(),
+			outgoing: Vec::new(),
+		}
+	}
+
+	fn apply_message_fee(&mut self, message_len: usize) -> Result<(), String> {
 		let fee = self.fee_schedule.compute_fee(message_len);
 		let new_fees_charged = self.fees_charged.saturating_add(fee);
 		if new_fees_charged > self.free_balance {
-			Err(ExternalitiesError::CannotPostMessage("could not cover fee."))
+			Err("could not cover fee.".into())
 		} else {
 			self.fees_charged = new_fees_charged;
 			Ok(())
@@ -291,7 +300,7 @@ impl Externalities {
 
 	// Performs final checks of validity, producing the outgoing message data.
 	fn final_checks(
-		self,
+		&mut self,
 		upward_messages: &[UpwardMessage],
 		egress_queue_roots: &[(ParaId, Hash)],
 		fees_charged: Option<Balance>,
@@ -313,7 +322,7 @@ impl Externalities {
 		}
 
 		let messages = check_egress(
-			self.outgoing,
+			std::mem::replace(&mut self.outgoing, Vec::new()),
 			&egress_queue_roots[..],
 		)?;
 
@@ -321,6 +330,27 @@ impl Externalities {
 	}
 }
 
+#[derive(Clone)]
+struct Externalities(Arc<Mutex<ExternalitiesInner>>);
+
+impl Externalities {
+	fn new(parachain_index: ParaId, free_balance: Balance, fee_schedule: FeeSchedule) -> Self {
+		Self(Arc::new(Mutex::new(
+			ExternalitiesInner::new(parachain_index, free_balance, fee_schedule)
+		)))
+	}
+}
+
+impl wasm_executor::Externalities for Externalities {
+	fn post_message(&mut self, message: TargetedMessage) -> Result<(), String> {
+		self.0.lock().post_message(message)
+	}
+
+	fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String> {
+		self.0.lock().post_upward_message(message)
+	}
+}
+
 /// Validate an erasure chunk against an expected root.
 pub fn validate_chunk(
 	root: &Hash,
@@ -425,19 +455,17 @@ fn do_validation<P>(
 			.collect()
 	};
 
-	let mut ext = Externalities {
-		parachain_index: para_id.clone(),
-		outgoing: Vec::new(),
-		upward: Vec::new(),
-		free_balance: chain_status.balance,
-		fee_schedule: chain_status.fee_schedule,
-		fees_charged: 0,
-	};
+	let ext = Externalities::new(para_id.clone(), chain_status.balance, chain_status.fee_schedule);
 
-	match wasm_executor::validate_candidate(&validation_code, params, &mut ext, ExecutionMode::Remote) {
+	match wasm_executor::validate_candidate(
+		&validation_code,
+		params,
+		ext.clone(),
+		ExecutionMode::Remote,
+	) {
 		Ok(result) => {
 			if result.head_data == head_data.0 {
-				let (messages, fees) = ext.final_checks(
+				let (messages, fees) = ext.0.lock().final_checks(
 					upward_messages,
 					queue_roots,
 					fees_charged
@@ -634,7 +662,7 @@ mod tests {
 
 	#[test]
 	fn ext_rejects_local_message() {
-		let mut ext = Externalities {
+		let mut ext = ExternalitiesInner {
 			parachain_index: 5.into(),
 			outgoing: Vec::new(),
 			upward: Vec::new(),
@@ -646,13 +674,13 @@ mod tests {
 			},
 		};
 
-		assert!(ext.post_message(MessageRef { target: 1.into(), data: &[] }).is_ok());
-		assert!(ext.post_message(MessageRef { target: 5.into(), data: &[] }).is_err());
+		assert!(ext.post_message(TargetedMessage { target: 1.into(), data: Vec::new() }).is_ok());
+		assert!(ext.post_message(TargetedMessage { target: 5.into(), data: Vec::new() }).is_err());
 	}
 
 	#[test]
 	fn ext_checks_upward_messages() {
-		let ext = || Externalities {
+		let ext = || ExternalitiesInner {
 			parachain_index: 5.into(),
 			outgoing: Vec::new(),
 			upward: vec![
@@ -742,7 +770,7 @@ mod tests {
 
 	#[test]
 	fn ext_checks_fees_and_updates_correctly() {
-		let mut ext = Externalities {
+		let mut ext = ExternalitiesInner {
 			parachain_index: 5.into(),
 			outgoing: Vec::new(),
 			upward: vec![
@@ -759,15 +787,15 @@ mod tests {
 		ext.apply_message_fee(100).unwrap();
 		assert_eq!(ext.fees_charged, 2000);
 
-		ext.post_message(MessageRef {
+		ext.post_message(TargetedMessage {
 			target: 1.into(),
-			data: &[0u8; 100],
+			data: vec![0u8; 100],
 		}).unwrap();
 		assert_eq!(ext.fees_charged, 4000);
 
-		ext.post_upward_message(UpwardMessageRef {
+		ext.post_upward_message(UpwardMessage {
 			origin: ParachainDispatchOrigin::Signed,
-			data: &[0u8; 100],
+			data: vec![0u8; 100],
 		}).unwrap();
 		assert_eq!(ext.fees_charged, 6000);