From 8174322223a0c68ab5d1768faad82200d31f583d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Oct 2019 17:09:19 +0200 Subject: [PATCH 1/2] Add message handler --- Cargo.lock | 3 + runtime/Cargo.toml | 4 + runtime/src/icmp.rs | 185 ++++++++++++++++++++++++++++++++++++++++++++ runtime/src/lib.rs | 2 + 4 files changed, 194 insertions(+) create mode 100644 runtime/src/icmp.rs diff --git a/Cargo.lock b/Cargo.lock index bf4bfa28517..51c70c0b785 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,10 +449,13 @@ dependencies = [ "memory-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "polkadot-parachain 0.6.0 (git+https://github.com/paritytech/polkadot?branch=bkchr-cumulus-branch)", + "polkadot-primitives 0.6.0 (git+https://github.com/paritytech/polkadot?branch=bkchr-cumulus-branch)", "sr-io 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", "sr-primitives 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", "sr-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", "srml-executive 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", + "srml-support 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", + "srml-system 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", "substrate-consensus-common 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", "substrate-executor 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", "substrate-keyring 2.0.0 (git+https://github.com/paritytech/substrate?branch=bkchr-cumulus-branch)", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 433c8fee635..c23105cae06 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -17,10 +17,13 @@ rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", de runtime-primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } rio = { package = "sr-io", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } +support = { package = "srml-support", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } +system = { package = "srml-system", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } executive = { package = "srml-executive", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } substrate-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } # Polkadot dependencies +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "bkchr-cumulus-branch" } parachain = { package = "polkadot-parachain", git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch", default-features = false, features = [ "wasm-api" ] } [dev-dependencies] @@ -42,5 +45,6 @@ std = [ "hash-db/std", "trie-db/std", "substrate-trie/std", + "polkadot-primitives/std", "parachain/std", ] diff --git a/runtime/src/icmp.rs b/runtime/src/icmp.rs new file mode 100644 index 00000000000..d26019af32b --- /dev/null +++ b/runtime/src/icmp.rs @@ -0,0 +1,185 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! The main entry point for messaging I/O of the runtime. +//! +//! This module includes: +//! - logic for creating inherent extrinsics on the client-side from a set of incoming messages; +//! - API to allow runtimes to configure the how messages are handled; +//! - API to allow runtimes to deposit outgoing messages. + +use codec::Codec; +use support::{decl_module, decl_storage, decl_event}; +use system::ensure_none; +use runtime_primitives::traits::Dispatchable; +use polkadot_primitives::parachain::{Chain, Id as ParaId}; + +/// Means of handling a bunch of "messages" (opaque blobs of data) coming in from other chains. +pub trait HandleMessages { + /// Messages have arrived: do something with them. The default implementation just forwards + /// each message to be handled by `handle_message`. + fn handle_messages(messages: &[(Chain, Vec)]) { + for (from, ref data) in messages.iter() { + Self::handle_message(*from, data) + } + } + + /// Handle an individual message of `_data` from endpoint `_from`. The default implementation + /// simply drops the message. + fn handle_message(_from: Chain, _data: &[u8]) {} +} + +/// Empty tuple drops all messages. +impl HandleMessages for () {} + +/// An origin for this module. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum Origin { + /// It comes from a parachain. + Parachain(ParaId), + + /// It comes from the Relay chain. + Relay, +} + +/// A message handler which treats each message as a `Call` and dispatches them as per `Call`s +/// with a corresponding `Origin`. +pub struct DispatchCall(::rstd::marker::PhantomData<(Origin, Call)>); + +impl< + Call: Codec + Dispatchable +> HandleMessages for DispatchCall where Call::Origin: From { + fn handle_message(from: Chain, mut data: &[u8]) { + if let Ok(call) = Call::decode(&mut data) { + let origin: Call::Origin = match from { + Chain::Parachain(id) => Origin::Parachain(id), + Chain::Relay => Origin::Relay, + }.into(); + // we disregard the result for now, much like transactions. If we eventually get some + // economic disincentive to spam the chain, then we could place events down here. + let _ = call.dispatch(origin); + } + } +} + +/// The module's configuration trait. +pub trait Trait: system::Trait { + /// The type which is used to handle incoming messages. + type OnIncoming: HandleMessages; + + /// The outer origin type. + type Origin: From + From>; + + /// The overarching event type. + type Event: From + Into<::Event>; +} + +// This module's storage items. +decl_storage! { + trait Store for Module as TemplateModule { + } +} + +// The module's dispatchable functions. +decl_module! { + /// The module declaration. + pub struct Module for enum Call where origin: ::Origin { + fn deposit_event() = default; + + /// Provide any incoming messages from external ICMP chains (i.e. parachains or the relay + /// chain) for this block to execute. + fn note_incoming(origin, messages: Vec<(Chain, Vec)>) { + ensure_none(origin)?; + + T::OnIncoming::handle_messages(&messages); + } + } +} + +decl_event!( + pub enum Event { + // Just a dummy event. + Dummy, + } +); + +/// tests for this module +#[cfg(test)] +mod tests { + use super::*; + + use primitives::H256; + use support::{impl_outer_origin, assert_ok, parameter_types}; + use sr_primitives::{ + traits::{BlakeTwo256, IdentityLookup}, testing::Header, weights::Weight, Perbill, + }; + + impl_outer_origin! { + pub enum Origin for Test {} + } + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); + } + impl system::Trait for Test { + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type WeightMultiplierUpdate = (); + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + } + impl Trait for Test { + type Event = (); + } + type TemplateModule = Module; + + // This function basically just builds a genesis storage key/value store according to + // our desired mockup. + fn new_test_ext() -> runtime_io::TestExternalities { + system::GenesisConfig::default().build_storage::().unwrap().into() + } + + #[test] + fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Just a dummy test for the dummy funtion `do_something` + // calling the `do_something` function with a value 42 + assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + // asserting that the stored value is equal to what we stored + assert_eq!(TemplateModule::something(), Some(42)); + }); + } +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 1bd76353116..5ffd2c124f1 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -29,6 +29,8 @@ pub use rstd::slice; #[macro_use] pub mod validate_block; +pub mod icmp; + /// The witness data type. type WitnessData = Vec>; From 292149b9d50c9d5e47539cbc7975b9a2faefabc5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Oct 2019 17:10:53 +0200 Subject: [PATCH 2/2] Build fix --- runtime/src/icmp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/src/icmp.rs b/runtime/src/icmp.rs index d26019af32b..1d1cfc6dca1 100644 --- a/runtime/src/icmp.rs +++ b/runtime/src/icmp.rs @@ -21,6 +21,7 @@ //! - API to allow runtimes to configure the how messages are handled; //! - API to allow runtimes to deposit outgoing messages. +use rstd::prelude::*; use codec::Codec; use support::{decl_module, decl_storage, decl_event}; use system::ensure_none;