From 4c3614337536868b094f0acac7930fe0e059f55c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bastian=20K=C3=B6cher?= <bkchr@users.noreply.github.com>
Date: Wed, 29 Jan 2020 16:24:40 +0100
Subject: [PATCH] Add `get_global` for `Sandbox` (#4756)

* Add `get_global` for `Sandbox`

This pr adds `get_global` to retrieve a `global` variable from an
instantiated sandbox wasm blob.

* Bump `spec_version`

* Update primitives/wasm-interface/src/lib.rs

Co-Authored-By: Sergei Pepyakin <sergei@parity.io>

* `get_global` -> `get_global_val`

Co-authored-by: Sergei Pepyakin <s.pepyakin@gmail.com>
Co-authored-by: Gavin Wood <github@gavwood.com>
---
 substrate/Cargo.lock                          |  9 +-
 substrate/bin/node/runtime/src/lib.rs         |  2 +-
 .../client/executor/common/src/sandbox.rs     | 17 +++-
 .../client/executor/runtime-test/src/lib.rs   | 34 +++++--
 .../executor/src/integration_tests/mod.rs     |  4 +-
 .../executor/src/integration_tests/sandbox.rs | 23 +++++
 substrate/client/executor/wasmi/src/lib.rs    | 15 ++-
 .../wasmtime/src/function_executor.rs         | 15 ++-
 .../contracts/src/wasm/env_def/macros.rs      | 20 ++--
 .../frame/contracts/src/wasm/env_def/mod.rs   | 30 +++---
 substrate/frame/contracts/src/wasm/runtime.rs |  6 +-
 substrate/primitives/core/src/sandbox.rs      | 93 -------------------
 substrate/primitives/io/Cargo.toml            |  2 +
 substrate/primitives/io/src/lib.rs            |  8 ++
 .../primitives/runtime-interface/Cargo.toml   |  4 +-
 .../primitives/runtime-interface/src/impls.rs | 10 +-
 substrate/primitives/runtime/Cargo.toml       |  2 +-
 substrate/primitives/sandbox/Cargo.toml       |  2 +
 substrate/primitives/sandbox/src/lib.rs       | 14 ++-
 substrate/primitives/sandbox/with_std.rs      | 67 ++++++-------
 substrate/primitives/sandbox/without_std.rs   | 14 ++-
 .../primitives/wasm-interface/Cargo.toml      |  3 +-
 .../primitives/wasm-interface/src/lib.rs      | 76 ++++++++++++++-
 23 files changed, 275 insertions(+), 195 deletions(-)

diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 88b73133f9c..0ad431f9d39 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -4206,13 +4206,13 @@ dependencies = [
  "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "byte-slice-cast 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "parity-scale-codec-derive 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parity-scale-codec-derive 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "parity-scale-codec-derive"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -6594,6 +6594,7 @@ dependencies = [
  "sp-state-machine 0.8.0",
  "sp-std 2.0.0",
  "sp-trie 2.0.0",
+ "sp-wasm-interface 2.0.0",
 ]
 
 [[package]]
@@ -6724,6 +6725,7 @@ dependencies = [
  "sp-core 2.0.0",
  "sp-io 2.0.0",
  "sp-std 2.0.0",
+ "sp-wasm-interface 2.0.0",
  "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "wasmi 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -6857,6 +6859,7 @@ name = "sp-wasm-interface"
 version = "2.0.0"
 dependencies = [
  "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "sp-std 2.0.0",
  "wasmi 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -8700,7 +8703,7 @@ dependencies = [
 "checksum parity-multihash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df3a17dc27848fd99e4f87eb0f8c9baba6ede0a6d555400c850ca45254ef4ce3"
 "checksum parity-multihash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70a4d7b05e51bff5ae2c29c7b8c3d889985bbd8f4e15b3542fcc1f6f9666d292"
 "checksum parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f747c06d9f3b2ad387ac881b9667298c81b1243aa9833f086e05996937c35507"
-"checksum parity-scale-codec-derive 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "492ac3aa93d6caa5d20e4e3e0b75d08e2dcd9dd8a50d19529548b6fe11b3f295"
+"checksum parity-scale-codec-derive 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34e513ff3e406f3ede6796dcdc83d0b32ffb86668cea1ccf7363118abeb00476"
 "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-util-mem 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "900dd84654b048e5bad420bb341658fc2c4d7fea628c22bcf4621733e54859b4"
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index bad1ea41749..0d4b094c79b 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -81,7 +81,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
 	spec_version: 208,
-	impl_version: 0,
+	impl_version: 1,
 	apis: RUNTIME_API_VERSIONS,
 };
 
diff --git a/substrate/client/executor/common/src/sandbox.rs b/substrate/client/executor/common/src/sandbox.rs
index e48afd48917..89285a75fc9 100644
--- a/substrate/client/executor/common/src/sandbox.rs
+++ b/substrate/client/executor/common/src/sandbox.rs
@@ -224,7 +224,8 @@ fn trap(msg: &'static str) -> Trap {
 }
 
 fn deserialize_result(serialized_result: &[u8]) -> std::result::Result<Option<RuntimeValue>, Trap> {
-	use self::sandbox_primitives::{HostError, ReturnValue};
+	use self::sandbox_primitives::HostError;
+	use sp_wasm_interface::ReturnValue;
 	let result_val = std::result::Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
 		.map_err(|_| trap("Decoding Result<ReturnValue, HostError> failed!"))?;
 
@@ -260,7 +261,7 @@ impl<'a, FE: SandboxCapabilities + 'a> Externals for GuestExternals<'a, FE> {
 		let invoke_args_data: Vec<u8> = args.as_ref()
 			.iter()
 			.cloned()
-			.map(sandbox_primitives::TypedValue::from)
+			.map(sp_wasm_interface::Value::from)
 			.collect::<Vec<_>>()
 			.encode();
 
@@ -362,6 +363,18 @@ impl<FR> SandboxInstance<FR> {
 			},
 		)
 	}
+
+	/// Get the value from a global with the given `name`.
+	///
+	/// Returns `Some(_)` if the global could be found.
+	pub fn get_global_val(&self, name: &str) -> Option<sp_wasm_interface::Value> {
+		let global = self.instance
+			.export_by_name(name)?
+			.as_global()?
+			.get();
+
+		Some(global.into())
+	}
 }
 
 /// Error occurred during instantiation of a sandboxed module.
diff --git a/substrate/client/executor/runtime-test/src/lib.rs b/substrate/client/executor/runtime-test/src/lib.rs
index f6d37abf942..b183398c02f 100644
--- a/substrate/client/executor/runtime-test/src/lib.rs
+++ b/substrate/client/executor/runtime-test/src/lib.rs
@@ -17,6 +17,8 @@ use sp_io::{
 use sp_runtime::{print, traits::{BlakeTwo256, Hash}};
 #[cfg(not(feature = "std"))]
 use sp_core::{ed25519, sr25519};
+#[cfg(not(feature = "std"))]
+use sp_sandbox::Value;
 
 extern "C" {
 	#[allow(dead_code)]
@@ -133,8 +135,8 @@ sp_core::wasm_export_functions! {
 		execute_sandboxed(
 			&code,
 			&[
-				sp_sandbox::TypedValue::I32(0x12345678),
-				sp_sandbox::TypedValue::I64(0x1234567887654321),
+				Value::I32(0x12345678),
+				Value::I64(0x1234567887654321),
 			],
 		).is_ok()
 	}
@@ -143,10 +145,10 @@ sp_core::wasm_export_functions! {
 		let ok = match execute_sandboxed(
 			&code,
 			&[
-				sp_sandbox::TypedValue::I32(0x1336),
+				Value::I32(0x1336),
 			]
 		) {
-			Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::TypedValue::I32(0x1337))) => true,
+			Ok(sp_sandbox::ReturnValue::Value(Value::I32(0x1337))) => true,
 			_ => false,
 		};
 
@@ -165,6 +167,22 @@ sp_core::wasm_export_functions! {
 		code
 	}
 
+
+	fn test_sandbox_get_global_val(code: Vec<u8>) -> i64 {
+		let env_builder = sp_sandbox::EnvironmentDefinitionBuilder::new();
+		let instance = if let Ok(i) = sp_sandbox::Instance::new(&code, &env_builder, &mut ()) {
+			i
+		} else {
+			return 20;
+		};
+
+		match instance.get_global_val("test_global") {
+			Some(sp_sandbox::Value::I64(val)) => val,
+			None => 30,
+			val => 40,
+		}
+	}
+
 	fn test_offchain_local_storage() -> bool {
 		let kind = sp_core::offchain::StorageKind::PERSISTENT;
 		assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), None);
@@ -262,7 +280,7 @@ sp_core::wasm_export_functions! {
 #[cfg(not(feature = "std"))]
 fn execute_sandboxed(
 	code: &[u8],
-	args: &[sp_sandbox::TypedValue],
+	args: &[Value],
 ) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> {
 	struct State {
 		counter: u32,
@@ -270,7 +288,7 @@ fn execute_sandboxed(
 
 	fn env_assert(
 		_e: &mut State,
-		args: &[sp_sandbox::TypedValue],
+		args: &[Value],
 	) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> {
 		if args.len() != 1 {
 			return Err(sp_sandbox::HostError);
@@ -284,14 +302,14 @@ fn execute_sandboxed(
 	}
 	fn env_inc_counter(
 		e: &mut State,
-		args: &[sp_sandbox::TypedValue],
+		args: &[Value],
 	) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> {
 		if args.len() != 1 {
 			return Err(sp_sandbox::HostError);
 		}
 		let inc_by = args[0].as_i32().ok_or_else(|| sp_sandbox::HostError)?;
 		e.counter += inc_by as u32;
-		Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::TypedValue::I32(e.counter as i32)))
+		Ok(sp_sandbox::ReturnValue::Value(Value::I32(e.counter as i32)))
 	}
 
 	let mut state = State { counter: 0 };
diff --git a/substrate/client/executor/src/integration_tests/mod.rs b/substrate/client/executor/src/integration_tests/mod.rs
index 02a5897ea42..3f3d9f69e13 100644
--- a/substrate/client/executor/src/integration_tests/mod.rs
+++ b/substrate/client/executor/src/integration_tests/mod.rs
@@ -88,7 +88,7 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) {
 				#[cfg(feature = "wasmtime")]
 				WasmExecutionMethod::Compiled => assert_eq!(
 					&format!("{:?}", e),
-					"Other(\"call to undefined external function with index 67\")"
+					"Other(\"call to undefined external function with index 68\")"
 				),
 			}
 		}
@@ -117,7 +117,7 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) {
 				#[cfg(feature = "wasmtime")]
 				WasmExecutionMethod::Compiled => assert_eq!(
 					&format!("{:?}", e),
-					"Other(\"call to undefined external function with index 68\")"
+					"Other(\"call to undefined external function with index 69\")"
 				),
 			}
 		}
diff --git a/substrate/client/executor/src/integration_tests/sandbox.rs b/substrate/client/executor/src/integration_tests/sandbox.rs
index 9458542e3a1..8e8b7896cf9 100644
--- a/substrate/client/executor/src/integration_tests/sandbox.rs
+++ b/substrate/client/executor/src/integration_tests/sandbox.rs
@@ -302,3 +302,26 @@ fn start_fn_traps(wasm_method: WasmExecutionMethod) {
 		2u8.encode(),
 	);
 }
+
+#[test_case(WasmExecutionMethod::Interpreted)]
+#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
+fn get_global_val_works(wasm_method: WasmExecutionMethod) {
+	let mut ext = TestExternalities::default();
+	let mut ext = ext.ext();
+
+	let code = wabt::wat2wasm(r#"
+		(module
+			(global (export "test_global") i64 (i64.const 500))
+		)
+		"#).unwrap().encode();
+
+	assert_eq!(
+		call_in_wasm(
+			"test_sandbox_get_global_val",
+			&code,
+			wasm_method,
+			&mut ext,
+		).unwrap(),
+		500i64.encode(),
+	);
+}
diff --git a/substrate/client/executor/wasmi/src/lib.rs b/substrate/client/executor/wasmi/src/lib.rs
index c4701fd8275..1bcb1aab8af 100644
--- a/substrate/client/executor/wasmi/src/lib.rs
+++ b/substrate/client/executor/wasmi/src/lib.rs
@@ -213,7 +213,7 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
 		trace!(target: "sp-sandbox", "invoke, instance_idx={}", instance_id);
 
 		// Deserialize arguments and convert them into wasmi types.
-		let args = Vec::<sandbox_primitives::TypedValue>::decode(&mut &args[..])
+		let args = Vec::<sp_wasm_interface::Value>::decode(&mut &args[..])
 			.map_err(|_| "Can't decode serialized arguments for the invocation")?
 			.into_iter()
 			.map(Into::into)
@@ -226,7 +226,7 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
 			Ok(None) => Ok(sandbox_primitives::ERR_OK),
 			Ok(Some(val)) => {
 				// Serialize return value and write it back into the memory.
-				sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| {
+				sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| {
 					if val.len() > return_val_len as usize {
 						Err("Return value buffer is too small")?;
 					}
@@ -269,6 +269,17 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
 
 		Ok(instance_idx_or_err_code as u32)
 	}
+
+	fn get_global_val(
+		&self,
+		instance_idx: u32,
+		name: &str,
+	) -> WResult<Option<sp_wasm_interface::Value>> {
+		self.sandbox_store
+			.instance(instance_idx)
+			.map(|i| i.get_global_val(name))
+			.map_err(|e| e.to_string())
+	}
 }
 
 /// Will be used on initialization of a module to resolve function and memory imports.
diff --git a/substrate/client/executor/wasmtime/src/function_executor.rs b/substrate/client/executor/wasmtime/src/function_executor.rs
index bc665f18e47..7bbf5a456bf 100644
--- a/substrate/client/executor/wasmtime/src/function_executor.rs
+++ b/substrate/client/executor/wasmtime/src/function_executor.rs
@@ -286,7 +286,7 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
 		trace!(target: "sp-sandbox", "invoke, instance_idx={}", instance_id);
 
 		// Deserialize arguments and convert them into wasmi types.
-		let args = Vec::<sandbox_primitives::TypedValue>::decode(&mut &args[..])
+		let args = Vec::<sp_wasm_interface::Value>::decode(&mut &args[..])
 			.map_err(|_| "Can't decode serialized arguments for the invocation")?
 			.into_iter()
 			.map(Into::into)
@@ -299,7 +299,7 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
 			Ok(None) => Ok(sandbox_primitives::ERR_OK),
 			Ok(Some(val)) => {
 				// Serialize return value and write it back into the memory.
-				sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| {
+				sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| {
 					if val.len() > return_val_len as usize {
 						Err("Return value buffer is too small")?;
 					}
@@ -337,6 +337,17 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
 
 		Ok(instance_idx_or_err_code as u32)
 	}
+
+	fn get_global_val(
+		&self,
+		instance_idx: u32,
+		name: &str,
+	) -> WResult<Option<sp_wasm_interface::Value>> {
+		self.sandbox_store
+			.instance(instance_idx)
+			.map(|i| i.get_global_val(name))
+			.map_err(|e| e.to_string())
+	}
 }
 
 // The storage for a Wasmtime invocation argument.
diff --git a/substrate/frame/contracts/src/wasm/env_def/macros.rs b/substrate/frame/contracts/src/wasm/env_def/macros.rs
index 89a147b2c6f..335d35f1e78 100644
--- a/substrate/frame/contracts/src/wasm/env_def/macros.rs
+++ b/substrate/frame/contracts/src/wasm/env_def/macros.rs
@@ -126,7 +126,7 @@ macro_rules! define_func {
 	( < E: $ext_ty:tt > $name:ident ( $ctx: ident $(, $names:ident : $params:ty)*) $(-> $returns:ty)* => $body:tt ) => {
 		fn $name< E: $ext_ty >(
 			$ctx: &mut $crate::wasm::Runtime<E>,
-			args: &[sp_sandbox::TypedValue],
+			args: &[sp_sandbox::Value],
 		) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> {
 			#[allow(unused)]
 			let mut args = args.iter();
@@ -196,7 +196,7 @@ mod tests {
 	use parity_wasm::elements::FunctionType;
 	use parity_wasm::elements::ValueType;
 	use sp_runtime::traits::Zero;
-	use sp_sandbox::{self, ReturnValue, TypedValue};
+	use sp_sandbox::{ReturnValue, Value};
 	use crate::wasm::tests::MockExt;
 	use crate::wasm::Runtime;
 	use crate::exec::Ext;
@@ -206,7 +206,7 @@ mod tests {
 	fn macro_unmarshall_then_body_then_marshall_value_or_trap() {
 		fn test_value(
 			_ctx: &mut u32,
-			args: &[sp_sandbox::TypedValue],
+			args: &[sp_sandbox::Value],
 		) -> Result<ReturnValue, sp_sandbox::HostError> {
 			let mut args = args.iter();
 			unmarshall_then_body_then_marshall!(
@@ -224,17 +224,17 @@ mod tests {
 
 		let ctx = &mut 0;
 		assert_eq!(
-			test_value(ctx, &[TypedValue::I32(15), TypedValue::I32(3)]).unwrap(),
-			ReturnValue::Value(TypedValue::I32(5)),
+			test_value(ctx, &[Value::I32(15), Value::I32(3)]).unwrap(),
+			ReturnValue::Value(Value::I32(5)),
 		);
-		assert!(test_value(ctx, &[TypedValue::I32(15), TypedValue::I32(0)]).is_err());
+		assert!(test_value(ctx, &[Value::I32(15), Value::I32(0)]).is_err());
 	}
 
 	#[test]
 	fn macro_unmarshall_then_body_then_marshall_unit() {
 		fn test_unit(
 			ctx: &mut u32,
-			args: &[sp_sandbox::TypedValue],
+			args: &[sp_sandbox::Value],
 		) -> Result<ReturnValue, sp_sandbox::HostError> {
 			let mut args = args.iter();
 			unmarshall_then_body_then_marshall!(
@@ -248,7 +248,7 @@ mod tests {
 		}
 
 		let ctx = &mut 0;
-		let result = test_unit(ctx, &[TypedValue::I32(2), TypedValue::I32(3)]).unwrap();
+		let result = test_unit(ctx, &[Value::I32(2), Value::I32(3)]).unwrap();
 		assert_eq!(result, ReturnValue::Unit);
 		assert_eq!(*ctx, 5);
 	}
@@ -263,7 +263,7 @@ mod tests {
 				Err(sp_sandbox::HostError)
 			}
 		});
-		let _f: fn(&mut Runtime<MockExt>, &[sp_sandbox::TypedValue])
+		let _f: fn(&mut Runtime<MockExt>, &[sp_sandbox::Value])
 			-> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError> = ext_gas::<MockExt>;
 	}
 
@@ -282,7 +282,7 @@ mod tests {
 
 	#[test]
 	fn macro_unmarshall_then_body() {
-		let args = vec![TypedValue::I32(5), TypedValue::I32(3)];
+		let args = vec![Value::I32(5), Value::I32(3)];
 		let mut args = args.iter();
 
 		let ctx: &mut u32 = &mut 0;
diff --git a/substrate/frame/contracts/src/wasm/env_def/mod.rs b/substrate/frame/contracts/src/wasm/env_def/mod.rs
index 004308da422..7b67f74ec95 100644
--- a/substrate/frame/contracts/src/wasm/env_def/mod.rs
+++ b/substrate/frame/contracts/src/wasm/env_def/mod.rs
@@ -17,7 +17,7 @@
 use super::Runtime;
 use crate::exec::Ext;
 
-use sp_sandbox::{self, TypedValue};
+use sp_sandbox::Value;
 use parity_wasm::elements::{FunctionType, ValueType};
 
 #[macro_use]
@@ -26,28 +26,28 @@ pub(crate) mod macros;
 pub trait ConvertibleToWasm: Sized {
 	const VALUE_TYPE: ValueType;
 	type NativeType;
-	fn to_typed_value(self) -> TypedValue;
-	fn from_typed_value(_: TypedValue) -> Option<Self>;
+	fn to_typed_value(self) -> Value;
+	fn from_typed_value(_: Value) -> Option<Self>;
 }
 impl ConvertibleToWasm for i32 {
 	type NativeType = i32;
 	const VALUE_TYPE: ValueType = ValueType::I32;
-	fn to_typed_value(self) -> TypedValue {
-		TypedValue::I32(self)
+	fn to_typed_value(self) -> Value {
+		Value::I32(self)
 	}
-	fn from_typed_value(v: TypedValue) -> Option<Self> {
+	fn from_typed_value(v: Value) -> Option<Self> {
 		v.as_i32()
 	}
 }
 impl ConvertibleToWasm for u32 {
 	type NativeType = u32;
 	const VALUE_TYPE: ValueType = ValueType::I32;
-	fn to_typed_value(self) -> TypedValue {
-		TypedValue::I32(self as i32)
+	fn to_typed_value(self) -> Value {
+		Value::I32(self as i32)
 	}
-	fn from_typed_value(v: TypedValue) -> Option<Self> {
+	fn from_typed_value(v: Value) -> Option<Self> {
 		match v {
-			TypedValue::I32(v) => Some(v as u32),
+			Value::I32(v) => Some(v as u32),
 			_ => None,
 		}
 	}
@@ -55,12 +55,12 @@ impl ConvertibleToWasm for u32 {
 impl ConvertibleToWasm for u64 {
 	type NativeType = u64;
 	const VALUE_TYPE: ValueType = ValueType::I64;
-	fn to_typed_value(self) -> TypedValue {
-		TypedValue::I64(self as i64)
+	fn to_typed_value(self) -> Value {
+		Value::I64(self as i64)
 	}
-	fn from_typed_value(v: TypedValue) -> Option<Self> {
+	fn from_typed_value(v: Value) -> Option<Self> {
 		match v {
-			TypedValue::I64(v) => Some(v as u64),
+			Value::I64(v) => Some(v as u64),
 			_ => None,
 		}
 	}
@@ -69,7 +69,7 @@ impl ConvertibleToWasm for u64 {
 pub(crate) type HostFunc<E> =
 	fn(
 		&mut Runtime<E>,
-		&[sp_sandbox::TypedValue]
+		&[sp_sandbox::Value]
 	) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>;
 
 pub(crate) trait FunctionImplProvider<E: Ext> {
diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs
index 07cb8cb524e..66ae8a4996c 100644
--- a/substrate/frame/contracts/src/wasm/runtime.rs
+++ b/substrate/frame/contracts/src/wasm/runtime.rs
@@ -23,9 +23,7 @@ use crate::exec::{
 use crate::gas::{Gas, GasMeter, Token, GasMeterResult, approx_gas_for_balance};
 use sp_sandbox;
 use frame_system;
-use sp_std::prelude::*;
-use sp_std::convert::TryInto;
-use sp_std::mem;
+use sp_std::{prelude::*, mem, convert::TryInto};
 use codec::{Decode, Encode};
 use sp_runtime::traits::{Bounded, SaturatedConversion};
 
@@ -89,7 +87,7 @@ pub(crate) fn to_execution_result<E: Ext>(
 			buffer.clear();
 			Ok(ExecReturnValue { status: STATUS_SUCCESS, data: buffer })
 		}
-		Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::TypedValue::I32(exit_code))) => {
+		Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::Value::I32(exit_code))) => {
 			let status = (exit_code & 0xFF).try_into()
 				.expect("exit_code is masked into the range of a u8; qed");
 			Ok(ExecReturnValue { status, data: runtime.scratch_buf })
diff --git a/substrate/primitives/core/src/sandbox.rs b/substrate/primitives/core/src/sandbox.rs
index a0673c49db1..73fbcfb572e 100644
--- a/substrate/primitives/core/src/sandbox.rs
+++ b/substrate/primitives/core/src/sandbox.rs
@@ -24,99 +24,6 @@ use sp_std::vec::Vec;
 #[derive(crate::RuntimeDebug)]
 pub struct HostError;
 
-/// Representation of a typed wasm value.
-#[derive(Clone, Copy, PartialEq, Encode, Decode)]
-#[derive(crate::RuntimeDebug)]
-pub enum TypedValue {
-	/// Value of 32-bit signed or unsigned integer.
-	#[codec(index = "1")]
-	I32(i32),
-
-	/// Value of 64-bit signed or unsigned integer.
-	#[codec(index = "2")]
-	I64(i64),
-
-	/// Value of 32-bit IEEE 754-2008 floating point number represented as a bit pattern.
-	#[codec(index = "3")]
-	F32(i32),
-
-	/// Value of 64-bit IEEE 754-2008 floating point number represented as a bit pattern.
-	#[codec(index = "4")]
-	F64(i64),
-}
-
-impl TypedValue {
-	/// Returns `Some` if this value of type `I32`.
-	pub fn as_i32(&self) -> Option<i32> {
-		match *self {
-			TypedValue::I32(v) => Some(v),
-			_ => None,
-		}
-	}
-}
-
-#[cfg(feature = "std")]
-impl From<::wasmi::RuntimeValue> for TypedValue {
-	fn from(val: ::wasmi::RuntimeValue) -> TypedValue {
-		use ::wasmi::RuntimeValue;
-		match val {
-			RuntimeValue::I32(v) => TypedValue::I32(v),
-			RuntimeValue::I64(v) => TypedValue::I64(v),
-			RuntimeValue::F32(v) => TypedValue::F32(v.to_bits() as i32),
-			RuntimeValue::F64(v) => TypedValue::F64(v.to_bits() as i64),
-		}
-	}
-}
-
-#[cfg(feature = "std")]
-impl From<TypedValue> for ::wasmi::RuntimeValue {
-	fn from(val: TypedValue) -> ::wasmi::RuntimeValue {
-		use ::wasmi::RuntimeValue;
-		use ::wasmi::nan_preserving_float::{F32, F64};
-		match val {
-			TypedValue::I32(v) => RuntimeValue::I32(v),
-			TypedValue::I64(v) => RuntimeValue::I64(v),
-			TypedValue::F32(v_bits) => RuntimeValue::F32(F32::from_bits(v_bits as u32)),
-			TypedValue::F64(v_bits) => RuntimeValue::F64(F64::from_bits(v_bits as u64)),
-		}
-	}
-}
-
-/// Typed value that can be returned from a function.
-///
-/// Basically a `TypedValue` plus `Unit`, for functions which return nothing.
-#[derive(Clone, Copy, PartialEq, Encode, Decode)]
-#[derive(crate::RuntimeDebug)]
-pub enum ReturnValue {
-	/// For returning nothing.
-	Unit,
-	/// For returning some concrete value.
-	Value(TypedValue),
-}
-
-impl From<TypedValue> for ReturnValue {
-	fn from(v: TypedValue) -> ReturnValue {
-		ReturnValue::Value(v)
-	}
-}
-
-impl ReturnValue {
-	/// Maximum number of bytes `ReturnValue` might occupy when serialized with
-	/// `Codec`.
-	///
-	/// Breakdown:
-	///  1 byte for encoding unit/value variant
-	///  1 byte for encoding value type
-	///  8 bytes for encoding the biggest value types available in wasm: f64, i64.
-	pub const ENCODED_MAX_SIZE: usize = 10;
-}
-
-#[test]
-fn return_value_encoded_max_size() {
-	let encoded = ReturnValue::Value(TypedValue::I64(-1)).encode();
-	assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
-}
-
 /// Describes an entity to define or import into the environment.
 #[derive(Clone, PartialEq, Eq, Encode, Decode)]
 #[derive(crate::RuntimeDebug)]
diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml
index 7d831cdfeb9..f494697b4b5 100644
--- a/substrate/primitives/io/Cargo.toml
+++ b/substrate/primitives/io/Cargo.toml
@@ -12,6 +12,7 @@ sp-core = { version = "2.0.0", default-features = false, path = "../core" }
 sp-std = { version = "2.0.0", default-features = false, path = "../std" }
 libsecp256k1 = { version = "0.3.4", optional = true }
 sp-state-machine = { version = "0.8", optional = true, path = "../../primitives/state-machine" }
+sp-wasm-interface = { version = "2.0.0", path = "../../primitives/wasm-interface", default-features = false }
 sp-runtime-interface = { version = "2.0.0", default-features = false, path = "../runtime-interface" }
 sp-trie = { version = "2.0.0", optional = true, path = "../../primitives/trie" }
 sp-externalities = { version = "0.8.0", optional = true, path = "../externalities" }
@@ -29,6 +30,7 @@ std = [
 	"libsecp256k1",
 	"sp-runtime-interface/std",
 	"sp-externalities",
+	"sp-wasm-interface/std",
 	"log",
 ]
 
diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs
index 704477b1fb2..dce67133d39 100644
--- a/substrate/primitives/io/src/lib.rs
+++ b/substrate/primitives/io/src/lib.rs
@@ -850,6 +850,14 @@ pub trait Sandbox {
 	fn instance_teardown(&mut self, instance_idx: u32) {
 		self.sandbox().instance_teardown(instance_idx).expect("Failed to teardown sandbox instance")
 	}
+
+	/// Get the value from a global with the given `name`. The sandbox is determined by the given
+	/// `instance_idx`.
+	///
+	/// Returns `Some(_)` when the requested global variable could be found.
+	fn get_global_val(&mut self, instance_idx: u32, name: &str) -> Option<sp_wasm_interface::Value> {
+		self.sandbox().get_global_val(instance_idx, name).expect("Failed to get global from sandbox")
+	}
 }
 
 /// Allocator used by Substrate when executing the Wasm runtime.
diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml
index 30e9ae6bd6b..3f20de1288d 100644
--- a/substrate/primitives/runtime-interface/Cargo.toml
+++ b/substrate/primitives/runtime-interface/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2018"
 license = "GPL-3.0"
 
 [dependencies]
-sp-wasm-interface = { version = "2.0.0", optional = true, path = "../wasm-interface" }
+sp-wasm-interface = { version = "2.0.0", path = "../wasm-interface", default-features = false }
 sp-std = { version = "2.0.0", default-features = false, path = "../std" }
 sp-runtime-interface-proc-macro = { version = "2.0.0", path = "proc-macro" }
 sp-externalities = { version = "0.8.0", optional = true, path = "../externalities" }
@@ -25,7 +25,7 @@ trybuild = "1.0.17"
 [features]
 default = [ "std" ]
 std = [
-	"sp-wasm-interface",
+	"sp-wasm-interface/std",
 	"sp-std/std",
 	"codec/std",
 	"sp-externalities",
diff --git a/substrate/primitives/runtime-interface/src/impls.rs b/substrate/primitives/runtime-interface/src/impls.rs
index cde8e60eea3..35bd96bd05e 100644
--- a/substrate/primitives/runtime-interface/src/impls.rs
+++ b/substrate/primitives/runtime-interface/src/impls.rs
@@ -17,7 +17,7 @@
 //! Provides implementations for the runtime interface traits.
 
 use crate::{
-	RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner},
+	RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner, Enum},
 	util::{unpack_ptr_and_len, pack_ptr_and_len},
 };
 #[cfg(feature = "std")]
@@ -523,3 +523,11 @@ macro_rules! for_u128_i128 {
 
 for_u128_i128!(u128);
 for_u128_i128!(i128);
+
+impl PassBy for sp_wasm_interface::ValueType {
+	type PassBy = Enum<sp_wasm_interface::ValueType>;
+}
+
+impl PassBy for sp_wasm_interface::Value {
+	type PassBy = Codec<sp_wasm_interface::Value>;
+}
diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml
index 70469754166..6f50a1a4d9a 100644
--- a/substrate/primitives/runtime/Cargo.toml
+++ b/substrate/primitives/runtime/Cargo.toml
@@ -7,7 +7,7 @@ license = "GPL-3.0"
 
 [dependencies]
 serde = { version = "1.0.101", optional = true, features = ["derive"] }
-codec = { package = "parity-scale-codec", version = "1.1.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "1.1.2", default-features = false, features = ["derive"] }
 sp-core = { version = "2.0.0", default-features = false, path = "../core" }
 sp-application-crypto = { version = "2.0.0", default-features = false, path = "../application-crypto" }
 sp-arithmetic = { version = "2.0.0", default-features = false, path = "../arithmetic" }
diff --git a/substrate/primitives/sandbox/Cargo.toml b/substrate/primitives/sandbox/Cargo.toml
index 071ac2ba7ba..c942e019fe6 100755
--- a/substrate/primitives/sandbox/Cargo.toml
+++ b/substrate/primitives/sandbox/Cargo.toml
@@ -10,6 +10,7 @@ wasmi = { version = "0.6.2", optional = true }
 sp-core = { version = "2.0.0", default-features = false, path = "../core" }
 sp-std = { version = "2.0.0", default-features = false, path = "../std" }
 sp-io = { version = "2.0.0", default-features = false, path = "../io" }
+sp-wasm-interface = { version = "2.0.0", default-features = false, path = "../wasm-interface" }
 codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false }
 
 [dev-dependencies]
@@ -24,5 +25,6 @@ std = [
 	"sp-std/std",
 	"codec/std",
 	"sp-io/std",
+	"sp-wasm-interface/std",
 ]
 strict = []
diff --git a/substrate/primitives/sandbox/src/lib.rs b/substrate/primitives/sandbox/src/lib.rs
index 2760a46b48d..17712ad3655 100755
--- a/substrate/primitives/sandbox/src/lib.rs
+++ b/substrate/primitives/sandbox/src/lib.rs
@@ -40,7 +40,8 @@
 
 use sp_std::prelude::*;
 
-pub use sp_core::sandbox::{TypedValue, ReturnValue, HostError};
+pub use sp_core::sandbox::HostError;
+pub use sp_wasm_interface::{Value, ReturnValue};
 
 mod imp {
 	#[cfg(feature = "std")]
@@ -75,7 +76,7 @@ impl From<Error> for HostError {
 /// supervisor in [`EnvironmentDefinitionBuilder`].
 ///
 /// [`EnvironmentDefinitionBuilder`]: struct.EnvironmentDefinitionBuilder.html
-pub type HostFuncType<T> = fn(&mut T, &[TypedValue]) -> Result<ReturnValue, HostError>;
+pub type HostFuncType<T> = fn(&mut T, &[Value]) -> Result<ReturnValue, HostError>;
 
 /// Reference to a sandboxed linear memory, that
 /// will be used by the guest module.
@@ -197,9 +198,16 @@ impl<T> Instance<T> {
 	pub fn invoke(
 		&mut self,
 		name: &str,
-		args: &[TypedValue],
+		args: &[Value],
 		state: &mut T,
 	) -> Result<ReturnValue, Error> {
 		self.inner.invoke(name, args, state)
 	}
+
+	/// Get the value from a global with the given `name`.
+	///
+	/// Returns `Some(_)` if the global could be found.
+	pub fn get_global_val(&self, name: &str) -> Option<Value> {
+		self.inner.get_global_val(name)
+	}
 }
diff --git a/substrate/primitives/sandbox/with_std.rs b/substrate/primitives/sandbox/with_std.rs
index 5f20342a5a9..cc3119003d1 100755
--- a/substrate/primitives/sandbox/with_std.rs
+++ b/substrate/primitives/sandbox/with_std.rs
@@ -23,7 +23,7 @@ use wasmi::{
 	RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, TrapKind
 };
 use wasmi::memory_units::Pages;
-use super::{Error, TypedValue, ReturnValue, HostFuncType, HostError};
+use super::{Error, Value, ReturnValue, HostFuncType, HostError};
 
 #[derive(Clone)]
 pub struct Memory {
@@ -88,27 +88,7 @@ impl fmt::Display for DummyHostError {
 	}
 }
 
-impl wasmi::HostError for DummyHostError {
-}
-
-fn from_runtime_value(v: RuntimeValue) -> TypedValue {
-	match v {
-		RuntimeValue::I32(v) => TypedValue::I32(v),
-		RuntimeValue::I64(v) => TypedValue::I64(v),
-		RuntimeValue::F32(v) => TypedValue::F32(v.to_bits() as i32),
-		RuntimeValue::F64(v) => TypedValue::F64(v.to_bits() as i64),
-	}
-}
-
-fn to_runtime_value(v: TypedValue) -> RuntimeValue {
-	use wasmi::nan_preserving_float::{F32, F64};
-	match v {
-		TypedValue::I32(v) => RuntimeValue::I32(v as i32),
-		TypedValue::I64(v) => RuntimeValue::I64(v as i64),
-		TypedValue::F32(v_bits) => RuntimeValue::F32(F32::from_bits(v_bits as u32)),
-		TypedValue::F64(v_bits) => RuntimeValue::F64(F64::from_bits(v_bits as u64)),
-	}
-}
+impl wasmi::HostError for DummyHostError {}
 
 struct GuestExternals<'a, T: 'a> {
 	state: &'a mut T,
@@ -124,13 +104,13 @@ impl<'a, T> Externals for GuestExternals<'a, T> {
 		let args = args.as_ref()
 			.iter()
 			.cloned()
-			.map(from_runtime_value)
+			.map(Into::into)
 			.collect::<Vec<_>>();
 
 		let result = (self.defined_host_functions.funcs[index])(self.state, &args);
 		match result {
 			Ok(value) => Ok(match value {
-				ReturnValue::Value(v) => Some(to_runtime_value(v)),
+				ReturnValue::Value(v) => Some(v.into()),
 				ReturnValue::Unit => None,
 			}),
 			Err(HostError) => Err(TrapKind::Host(Box::new(DummyHostError)).into()),
@@ -253,7 +233,7 @@ impl<T> ImportResolver for EnvironmentDefinitionBuilder<T> {
 pub struct Instance<T> {
 	instance: ModuleRef,
 	defined_host_functions: DefinedHostFunctions<T>,
-	_marker: ::std::marker::PhantomData<T>,
+	_marker: std::marker::PhantomData<T>,
 }
 
 impl<T> Instance<T> {
@@ -281,14 +261,14 @@ impl<T> Instance<T> {
 		Ok(Instance {
 			instance,
 			defined_host_functions,
-			_marker: ::std::marker::PhantomData::<T>,
+			_marker: std::marker::PhantomData::<T>,
 		})
 	}
 
 	pub fn invoke(
 		&mut self,
 		name: &str,
-		args: &[TypedValue],
+		args: &[Value],
 		state: &mut T,
 	) -> Result<ReturnValue, Error> {
 		let args = args.iter().cloned().map(Into::into).collect::<Vec<_>>();
@@ -306,20 +286,29 @@ impl<T> Instance<T> {
 			Err(_err) => Err(Error::Execution),
 		}
 	}
+
+	pub fn get_global_val(&self, name: &str) -> Option<Value> {
+		let global = self.instance
+			.export_by_name(name)?
+			.as_global()?
+			.get();
+
+		Some(global.into())
+	}
 }
 
 #[cfg(test)]
 mod tests {
 	use wabt;
-	use crate::{Error, TypedValue, ReturnValue, HostError, EnvironmentDefinitionBuilder, Instance};
+	use crate::{Error, Value, ReturnValue, HostError, EnvironmentDefinitionBuilder, Instance};
 	use assert_matches::assert_matches;
 
-	fn execute_sandboxed(code: &[u8], args: &[TypedValue]) -> Result<ReturnValue, HostError> {
+	fn execute_sandboxed(code: &[u8], args: &[Value]) -> Result<ReturnValue, HostError> {
 		struct State {
 			counter: u32,
 		}
 
-		fn env_assert(_e: &mut State, args: &[TypedValue]) -> Result<ReturnValue, HostError> {
+		fn env_assert(_e: &mut State, args: &[Value]) -> Result<ReturnValue, HostError> {
 			if args.len() != 1 {
 				return Err(HostError);
 			}
@@ -330,16 +319,16 @@ mod tests {
 				Err(HostError)
 			}
 		}
-		fn env_inc_counter(e: &mut State, args: &[TypedValue]) -> Result<ReturnValue, HostError> {
+		fn env_inc_counter(e: &mut State, args: &[Value]) -> Result<ReturnValue, HostError> {
 			if args.len() != 1 {
 				return Err(HostError);
 			}
 			let inc_by = args[0].as_i32().ok_or_else(|| HostError)?;
 			e.counter += inc_by as u32;
-			Ok(ReturnValue::Value(TypedValue::I32(e.counter as i32)))
+			Ok(ReturnValue::Value(Value::I32(e.counter as i32)))
 		}
 		/// Function that takes one argument of any type and returns that value.
-		fn env_polymorphic_id(_e: &mut State, args: &[TypedValue]) -> Result<ReturnValue, HostError> {
+		fn env_polymorphic_id(_e: &mut State, args: &[Value]) -> Result<ReturnValue, HostError> {
 			if args.len() != 1 {
 				return Err(HostError);
 			}
@@ -387,8 +376,8 @@ mod tests {
 		let result = execute_sandboxed(
 			&code,
 			&[
-				TypedValue::I32(0x12345678),
-				TypedValue::I64(0x1234567887654321),
+				Value::I32(0x12345678),
+				Value::I64(0x1234567887654321),
 			]
 		);
 		assert!(result.is_ok());
@@ -410,10 +399,10 @@ mod tests {
 		let return_val = execute_sandboxed(
 			&code,
 			&[
-				TypedValue::I32(0x1336),
+				Value::I32(0x1336),
 			]
 		).unwrap();
-		assert_eq!(return_val, ReturnValue::Value(TypedValue::I32(0x1337)));
+		assert_eq!(return_val, ReturnValue::Value(Value::I32(0x1337)));
 	}
 
 	#[test]
@@ -453,8 +442,8 @@ mod tests {
 
 	#[test]
 	fn cant_return_unmatching_type() {
-		fn env_returns_i32(_e: &mut (), _args: &[TypedValue]) -> Result<ReturnValue, HostError> {
-			Ok(ReturnValue::Value(TypedValue::I32(42)))
+		fn env_returns_i32(_e: &mut (), _args: &[Value]) -> Result<ReturnValue, HostError> {
+			Ok(ReturnValue::Value(Value::I32(42)))
 		}
 
 		let mut env_builder = EnvironmentDefinitionBuilder::new();
diff --git a/substrate/primitives/sandbox/without_std.rs b/substrate/primitives/sandbox/without_std.rs
index 901354aee34..c31c6fe3494 100755
--- a/substrate/primitives/sandbox/without_std.rs
+++ b/substrate/primitives/sandbox/without_std.rs
@@ -18,7 +18,7 @@ use codec::{Decode, Encode};
 use sp_core::sandbox as sandbox_primitives;
 use sp_io::sandbox;
 use sp_std::{prelude::*, slice, marker, mem, vec, rc::Rc};
-use super::{Error, TypedValue, ReturnValue, HostFuncType};
+use super::{Error, Value, ReturnValue, HostFuncType};
 
 mod ffi {
 	use sp_std::mem;
@@ -183,7 +183,7 @@ extern "C" fn dispatch_thunk<T>(
 			slice::from_raw_parts(serialized_args_ptr, serialized_args_len)
 		}
 	};
-	let args = Vec::<TypedValue>::decode(&mut &serialized_args[..]).expect(
+	let args = Vec::<Value>::decode(&mut &serialized_args[..]).expect(
 		"serialized args should be provided by the runtime;
 			correctly serialized data should be deserializable;
 			qed",
@@ -244,11 +244,11 @@ impl<T> Instance<T> {
 	pub fn invoke(
 		&mut self,
 		name: &str,
-		args: &[TypedValue],
+		args: &[Value],
 		state: &mut T,
 	) -> Result<ReturnValue, Error> {
 		let serialized_args = args.to_vec().encode();
-		let mut return_val = vec![0u8; sandbox_primitives::ReturnValue::ENCODED_MAX_SIZE];
+		let mut return_val = vec![0u8; ReturnValue::ENCODED_MAX_SIZE];
 
 		let result = sandbox::invoke(
 			self.instance_idx,
@@ -261,7 +261,7 @@ impl<T> Instance<T> {
 
 		match result {
 			sandbox_primitives::ERR_OK => {
-				let return_val = sandbox_primitives::ReturnValue::decode(&mut &return_val[..])
+				let return_val = ReturnValue::decode(&mut &return_val[..])
 					.map_err(|_| Error::Execution)?;
 				Ok(return_val)
 			}
@@ -269,6 +269,10 @@ impl<T> Instance<T> {
 			_ => unreachable!(),
 		}
 	}
+
+	pub fn get_global_val(&self, name: &str) -> Option<Value> {
+		sandbox::get_global_val(self.instance_idx, name)
+	}
 }
 
 impl<T> Drop for Instance<T> {
diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml
index b97e3040aa4..bb9ea85872a 100644
--- a/substrate/primitives/wasm-interface/Cargo.toml
+++ b/substrate/primitives/wasm-interface/Cargo.toml
@@ -9,7 +9,8 @@ license = "GPL-3.0"
 wasmi = { version = "0.6.2", optional = true }
 impl-trait-for-tuples = "0.1.2"
 sp-std = { version = "2.0.0", path = "../std", default-features = false }
+codec = { package = "parity-scale-codec", version = "1.1.2", default-features = false, features = ["derive"] }
 
 [features]
 default = [ "std" ]
-std = [ "wasmi", "sp-std/std" ]
+std = [ "wasmi", "sp-std/std", "codec/std" ]
diff --git a/substrate/primitives/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs
index d6f9bbfbf09..7bb4469c771 100644
--- a/substrate/primitives/wasm-interface/src/lib.rs
+++ b/substrate/primitives/wasm-interface/src/lib.rs
@@ -44,8 +44,33 @@ pub enum ValueType {
 	F64,
 }
 
+impl From<ValueType> for u8 {
+	fn from(val: ValueType) -> u8 {
+		match val {
+			ValueType::I32 => 0,
+			ValueType::I64 => 1,
+			ValueType::F32 => 2,
+			ValueType::F64 => 3,
+		}
+	}
+}
+
+impl sp_std::convert::TryFrom<u8> for ValueType {
+	type Error = ();
+
+	fn try_from(val: u8) -> sp_std::result::Result<ValueType, ()> {
+		match val {
+			0 => Ok(Self::I32),
+			1 => Ok(Self::I64),
+			2 => Ok(Self::F32),
+			3 => Ok(Self::F64),
+			_ => Err(()),
+		}
+	}
+}
+
 /// Values supported by Substrate on the boundary between host/Wasm.
-#[derive(PartialEq, Debug, Clone, Copy)]
+#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
 pub enum Value {
 	/// A 32-bit integer.
 	I32(i32),
@@ -71,6 +96,14 @@ impl Value {
 			Value::F64(_) => ValueType::F64,
 		}
 	}
+
+	/// Return `Self` as `i32`.
+	pub fn as_i32(&self) -> Option<i32> {
+		match self {
+			Self::I32(val) => Some(*val),
+			_ => None,
+		}
+	}
 }
 
 /// Provides `Sealed` trait to prevent implementing trait `PointerType` outside of this crate.
@@ -298,6 +331,12 @@ pub trait Sandbox {
 		raw_env_def: &[u8],
 		state: u32,
 	) -> Result<u32>;
+
+	/// Get the value from a global with the given `name`. The sandbox is determined by the
+	/// given `instance_idx` instance.
+	///
+	/// Returns `Some(_)` when the requested global variable could be found.
+	fn get_global_val(&self, instance_idx: u32, name: &str) -> Result<Option<Value>>;
 }
 
 /// Something that provides implementations for host functions.
@@ -409,9 +448,37 @@ impl ReadPrimitive<u64> for &mut dyn FunctionContext {
 	}
 }
 
+/// Typed value that can be returned from a function.
+///
+/// Basically a `TypedValue` plus `Unit`, for functions which return nothing.
+#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
+pub enum ReturnValue {
+	/// For returning nothing.
+	Unit,
+	/// For returning some concrete value.
+	Value(Value),
+}
+
+impl From<Value> for ReturnValue {
+	fn from(v: Value) -> ReturnValue {
+		ReturnValue::Value(v)
+	}
+}
+
+impl ReturnValue {
+	/// Maximum number of bytes `ReturnValue` might occupy when serialized with `SCALE`.
+	///
+	/// Breakdown:
+	///  1 byte for encoding unit/value variant
+	///  1 byte for encoding value type
+	///  8 bytes for encoding the biggest value types available in wasm: f64, i64.
+	pub const ENCODED_MAX_SIZE: usize = 10;
+}
+
 #[cfg(test)]
 mod tests {
 	use super::*;
+	use codec::Encode;
 
 	#[test]
 	fn pointer_offset_works() {
@@ -425,4 +492,11 @@ mod tests {
 		assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
 		assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
 	}
+
+
+	#[test]
+	fn return_value_encoded_max_size() {
+		let encoded = ReturnValue::Value(Value::I64(-1)).encode();
+		assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
+	}
 }
-- 
GitLab