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, ¶ms.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(¶ms[..], 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(¶ms[..], 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, ¶ms.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 ¶ms.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);