diff --git a/Cargo.lock b/Cargo.lock index 2d17000bf4953..4920d3e6677da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -957,6 +957,19 @@ dependencies = [ "polkadot-cli 0.1.0", ] +[[package]] +name = "polkadot-api" +version = "0.1.0" +dependencies = [ + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-executor 0.1.0", + "polkadot-primitives 0.1.0", + "polkadot-runtime 0.1.0", + "substrate-client 0.1.0", + "substrate-executor 0.1.0", + "substrate-state-machine 0.1.0", +] + [[package]] name = "polkadot-candidate-agreement" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index aecab804f1a5c..a0db795c2e911 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,21 +13,22 @@ polkadot-cli = { path = "polkadot/cli" } [workspace] members = [ - "substrate/client", - "substrate/codec", - "substrate/environmental", - "substrate/executor", + "polkadot/api", "polkadot/candidate-agreement", "polkadot/cli", "polkadot/collator", "polkadot/executor", - "polkadot/runtime", "polkadot/primitives", + "polkadot/runtime", "polkadot/validator", + "substrate/client", + "substrate/codec", + "substrate/environmental", + "substrate/executor", "substrate/network", "substrate/primitives", - "substrate/rpc", "substrate/rpc-servers", + "substrate/rpc", "substrate/runtime-io", "substrate/runtime-std", "substrate/serializer", diff --git a/polkadot/api/Cargo.toml b/polkadot/api/Cargo.toml new file mode 100644 index 0000000000000..de3e082548a75 --- /dev/null +++ b/polkadot/api/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "polkadot-api" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +error-chain = "0.11" +polkadot-executor = { path = "../executor" } +polkadot-runtime = { path = "../runtime" } +polkadot-primitives = { path = "../primitives" } +substrate-client = { path = "../../substrate/client" } +substrate-executor = { path = "../../substrate/executor" } +substrate-state-machine = { path = "../../substrate/state-machine" } diff --git a/polkadot/api/src/lib.rs b/polkadot/api/src/lib.rs new file mode 100644 index 0000000000000..c79295823a7dd --- /dev/null +++ b/polkadot/api/src/lib.rs @@ -0,0 +1,118 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Strongly typed API for Polkadot based around the locally-compiled native +//! runtime. + +extern crate polkadot_executor as polkadot_executor; +extern crate polkadot_runtime ; +extern crate polkadot_primitives as primitives; +extern crate substrate_client as client; +extern crate substrate_executor as substrate_executor; +extern crate substrate_state_machine as state_machine; + +#[macro_use] +extern crate error_chain; + +use client::backend::Backend; +use client::blockchain::BlockId; +use client::Client; +use polkadot_runtime::runtime; +use polkadot_executor::LocalNativeExecutionDispatch as LocalDispatch; +use substrate_executor::{NativeExecutionDispatch, NativeExecutor}; +use primitives::{AccountId, SessionKey}; +use primitives::parachain::DutyRoster; + +error_chain! { + errors { + /// Unknown runtime code. + UnknownRuntime { + description("Unknown runtime code") + display("Unknown runtime code") + } + UnknownBlock(b: BlockId) { + description("Unknown block") + display("Unknown block") + } + /// Some other error. + // TODO: allow to be specified as associated type of PolkadotApi + Other(e: Box<::std::error::Error + Send>) { + description("Other error") + display("Other error: {}", e.description()) + } + } + + links { + Executor(substrate_executor::error::Error, substrate_executor::error::ErrorKind); + } +} + +/// Trait encapsulating the Polkadot API. +/// +/// All calls should fail when the exact runtime is unknown. +pub trait PolkadotApi { + /// Get authorities at a given block. + fn authorities(&self, at: &BlockId) -> Result>; + + /// Get validators at a given block. + fn validators(&self, at: &BlockId) -> Result>; + + /// Get the authority duty roster at a block. + fn duty_roster(&self, at: &BlockId) -> Result; +} + +fn convert_client_error(e: client::error::Error) -> Error { + match e { + client::error::Error(client::error::ErrorKind::UnknownBlock(b), _) => Error::from_kind(ErrorKind::UnknownBlock(b)), + other => Error::from_kind(ErrorKind::Other(Box::new(other) as Box<_>)), + } +} + +// set up the necessary scaffolding to execute the runtime. +macro_rules! with_runtime { + ($client: ident, $at: expr, $exec: expr) => {{ + // bail if the code is not the same as the natively linked. + if $client.code_at($at).map_err(convert_client_error)? != LocalDispatch::native_equivalent() { + bail!(ErrorKind::UnknownRuntime); + } + + $client.state_at($at).map_err(convert_client_error).and_then(|state| { + let mut changes = Default::default(); + let mut ext = state_machine::Ext { + overlay: &mut changes, + backend: &state, + }; + + ::substrate_executor::with_native_environment(&mut ext, $exec).map_err(Into::into) + }) + }} +} + +impl PolkadotApi for Client> + where ::client::error::Error: From<<::State as state_machine::backend::Backend>::Error> +{ + fn authorities(&self, at: &BlockId) -> Result> { + with_runtime!(self, at, ::runtime::consensus::authorities) + } + + fn validators(&self, at: &BlockId) -> Result> { + with_runtime!(self, at, ::runtime::session::validators) + } + + fn duty_roster(&self, at: &BlockId) -> Result { + with_runtime!(self, at, ::runtime::parachains::calculate_duty_roster) + } +} diff --git a/polkadot/cli/src/genesis.rs b/polkadot/cli/src/genesis.rs index 74e6ff6a3a281..5e82d9a507bab 100644 --- a/polkadot/cli/src/genesis.rs +++ b/polkadot/cli/src/genesis.rs @@ -89,7 +89,7 @@ mod tests { "execute_transaction", &vec![].join(&header).join(tx) ).unwrap(); - header = Header::from_slice(&mut &ret_data[..]).unwrap(); + header = Header::decode(&mut &ret_data[..]).unwrap(); } let ret_data = execute( @@ -99,7 +99,7 @@ mod tests { "finalise_block", &vec![].join(&header) ).unwrap(); - header = Header::from_slice(&mut &ret_data[..]).unwrap(); + header = Header::decode(&mut &ret_data[..]).unwrap(); (vec![].join(&Block { header, transactions }), hash.into()) } diff --git a/polkadot/cli/src/lib.rs b/polkadot/cli/src/lib.rs index fdfe35b822121..ac452bfef38a0 100644 --- a/polkadot/cli/src/lib.rs +++ b/polkadot/cli/src/lib.rs @@ -83,7 +83,7 @@ pub fn run(args: I) -> error::Result<()> where storage = genesis_config.genesis_map(); let block = genesis::construct_genesis_block(&storage); storage.extend(additional_storage_with_genesis(&block)); - (primitives::block::Header::from_slice(&mut block.header.to_vec().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) + (primitives::block::Header::decode(&mut block.header.to_vec().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) }; let client = client::new_in_mem(executor, prepare_genesis)?; diff --git a/polkadot/executor/src/lib.rs b/polkadot/executor/src/lib.rs index 1c2ec994b61fb..f4d5af026f55d 100644 --- a/polkadot/executor/src/lib.rs +++ b/polkadot/executor/src/lib.rs @@ -31,7 +31,9 @@ extern crate triehash; extern crate hex_literal; use polkadot_runtime as runtime; +use substrate_executor::error::{Error, ErrorKind}; use substrate_executor::{NativeExecutionDispatch, NativeExecutor}; +use state_machine::Externalities; /// A null struct which implements `NativeExecutionDispatch` feeding in the hard-coded runtime. pub struct LocalNativeExecutionDispatch; @@ -43,8 +45,9 @@ impl NativeExecutionDispatch for LocalNativeExecutionDispatch { include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm") } - fn dispatch(method: &str, data: &[u8]) -> Option> { - runtime::dispatch(method, data) + fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> Result, Error> { + ::substrate_executor::with_native_environment(ext, move || runtime::api::dispatch(method, data))? + .ok_or_else(|| ErrorKind::MethodNotFound(method.to_owned()).into()) } } @@ -236,14 +239,6 @@ mod tests { ) } - #[test] - fn test_execution_works() { - let mut t = new_test_ext(); - println!("Testing Wasm..."); - let r = WasmExecutor.call(&mut t, COMPACT_CODE, "run_tests", &block2().0); - assert!(r.is_ok()); - } - #[test] fn full_native_block_import_works() { let mut t = new_test_ext(); diff --git a/polkadot/primitives/src/block.rs b/polkadot/primitives/src/block.rs index 5ebe53007ff06..489411351759b 100644 --- a/polkadot/primitives/src/block.rs +++ b/polkadot/primitives/src/block.rs @@ -20,7 +20,7 @@ use primitives::bytes; use primitives::H256; use rstd::vec::Vec; -use codec::Slicable; +use codec::{Input, Slicable}; use transaction::UncheckedTransaction; /// Used to refer to a block number. @@ -38,8 +38,8 @@ pub type TransactionHash = H256; pub struct Log(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); impl Slicable for Log { - fn from_slice(value: &mut &[u8]) -> Option { - Vec::::from_slice(value).map(Log) + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(Log) } fn as_slice_then R>(&self, f: F) -> R { @@ -58,8 +58,8 @@ pub struct Digest { } impl Slicable for Digest { - fn from_slice(value: &mut &[u8]) -> Option { - Vec::::from_slice(value).map(|logs| Digest { logs }) + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(|logs| Digest { logs }) } fn as_slice_then R>(&self, f: F) -> R { @@ -81,11 +81,9 @@ pub struct Block { } impl Slicable for Block { - fn from_slice(value: &mut &[u8]) -> Option { - Some(Block { - header: try_opt!(Slicable::from_slice(value)), - transactions: try_opt!(Slicable::from_slice(value)), - }) + fn decode(input: &mut I) -> Option { + let (header, transactions) = try_opt!(Slicable::decode(input)); + Some(Block { header, transactions }) } fn to_vec(&self) -> Vec { @@ -136,13 +134,13 @@ impl Header { } impl Slicable for Header { - fn from_slice(value: &mut &[u8]) -> Option { + fn decode(input: &mut I) -> Option { Some(Header { - parent_hash: try_opt!(Slicable::from_slice(value)), - number: try_opt!(Slicable::from_slice(value)), - state_root: try_opt!(Slicable::from_slice(value)), - transaction_root: try_opt!(Slicable::from_slice(value)), - digest: try_opt!(Slicable::from_slice(value)), + parent_hash: try_opt!(Slicable::decode(input)), + number: try_opt!(Slicable::decode(input)), + state_root: try_opt!(Slicable::decode(input)), + transaction_root: try_opt!(Slicable::decode(input)), + digest: try_opt!(Slicable::decode(input)), }) } @@ -192,6 +190,6 @@ mod tests { }"#); let v = header.to_vec(); - assert_eq!(Header::from_slice(&mut &v[..]).unwrap(), header); + assert_eq!(Header::decode(&mut &v[..]).unwrap(), header); } } diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 83cb3be1cd93c..14b8e78d30f40 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -29,11 +29,12 @@ extern crate serde_derive; extern crate serde; extern crate substrate_runtime_std as rstd; -extern crate substrate_codec as codec; extern crate substrate_primitives as primitives; #[cfg(test)] extern crate substrate_serializer; +extern crate substrate_codec as codec; + macro_rules! try_opt { ($e: expr) => { match $e { diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/parachain.rs index 75d5b6a326acd..6535e0f0e04f1 100644 --- a/polkadot/primitives/src/parachain.rs +++ b/polkadot/primitives/src/parachain.rs @@ -19,24 +19,25 @@ #[cfg(feature = "std")] use primitives::bytes; use primitives; +use codec::{Input, Slicable, NonTrivialSlicable}; use rstd::vec::Vec; /// Unique identifier of a parachain. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -pub struct Id(u64); +pub struct Id(u32); -impl From for u64 { +impl From for u32 { fn from(x: Id) -> Self { x.0 } } -impl From for Id { - fn from(x: u64) -> Self { Id(x) } +impl From for Id { + fn from(x: u32) -> Self { Id(x) } } -impl ::codec::Slicable for Id { - fn from_slice(value: &mut &[u8]) -> Option { - u64::from_slice(value).map(Id) +impl Slicable for Id { + fn decode(input: &mut I) -> Option { + u32::decode(input).map(Id) } fn as_slice_then R>(&self, f: F) -> R { @@ -44,6 +45,80 @@ impl ::codec::Slicable for Id { } } +/// Identifier for a chain, either one of a number of parachains or the relay chain. +#[derive(Copy, Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum Chain { + /// The relay chain. + Relay, + /// A parachain of the given index. + Parachain(Id), +} + +impl Slicable for Chain { + fn decode(input: &mut I) -> Option { + let disc = try_opt!(u8::decode(input)); + + match disc { + 0 => Some(Chain::Relay), + 1 => Some(Chain::Parachain(try_opt!(Slicable::decode(input)))), + _ => None, + } + } + + fn to_vec(&self) -> Vec { + let mut v = Vec::new(); + match *self { + Chain::Relay => { 0u8.as_slice_then(|s| v.extend(s)); } + Chain::Parachain(id) => { + 1u8.as_slice_then(|s| v.extend(s)); + id.as_slice_then(|s| v.extend(s)); + } + } + + v + } + + fn as_slice_then R>(&self, f: F) -> R { + f(&self.to_vec().as_slice()) + } +} + +impl NonTrivialSlicable for Chain { } + +/// The duty roster specifying what jobs each validator must do. +#[derive(Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Default, Debug))] +pub struct DutyRoster { + /// Lookup from validator index to chain on which that validator has a duty to validate. + pub validator_duty: Vec, + /// Lookup from validator index to chain on which that validator has a duty to guarantee + /// availability. + pub guarantor_duty: Vec, +} + +impl Slicable for DutyRoster { + fn decode(input: &mut I) -> Option { + Some(DutyRoster { + validator_duty: try_opt!(Slicable::decode(input)), + guarantor_duty: try_opt!(Slicable::decode(input)), + }) + } + + fn to_vec(&self) -> Vec { + let mut v = Vec::new(); + + v.extend(self.validator_duty.to_vec()); + v.extend(self.guarantor_duty.to_vec()); + + v + } + + fn as_slice_then R>(&self, f: F) -> R { + f(&self.to_vec().as_slice()) + } +} + /// Candidate parachain block. /// /// https://github.com/w3f/polkadot-spec/blob/master/spec.md#candidate-para-chain-block @@ -124,9 +199,9 @@ pub struct ValidationCode(#[cfg_attr(feature = "std", serde(with="bytes"))] pub #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] pub struct Activity(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); -impl ::codec::Slicable for Activity { - fn from_slice(value: &mut &[u8]) -> Option { - Vec::::from_slice(value).map(Activity) +impl Slicable for Activity { + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(Activity) } fn as_slice_then R>(&self, f: F) -> R { diff --git a/polkadot/primitives/src/transaction.rs b/polkadot/primitives/src/transaction.rs index 062d8c563dc29..0a68256f744d7 100644 --- a/polkadot/primitives/src/transaction.rs +++ b/polkadot/primitives/src/transaction.rs @@ -17,7 +17,7 @@ //! Transaction type. use rstd::vec::Vec; -use codec::Slicable; +use codec::{Input, Slicable}; #[cfg(feature = "std")] use std::fmt; @@ -91,23 +91,23 @@ pub enum Proposal { } impl Slicable for Proposal { - fn from_slice(value: &mut &[u8]) -> Option { - let id = try_opt!(u8::from_slice(value).and_then(InternalFunctionId::from_u8)); + fn decode(input: &mut I) -> Option { + let id = try_opt!(u8::decode(input).and_then(InternalFunctionId::from_u8)); let function = match id { InternalFunctionId::SystemSetCode => - Proposal::SystemSetCode(try_opt!(Slicable::from_slice(value))), + Proposal::SystemSetCode(try_opt!(Slicable::decode(input))), InternalFunctionId::SessionSetLength => - Proposal::SessionSetLength(try_opt!(Slicable::from_slice(value))), + Proposal::SessionSetLength(try_opt!(Slicable::decode(input))), InternalFunctionId::SessionForceNewSession => Proposal::SessionForceNewSession, InternalFunctionId::StakingSetSessionsPerEra => - Proposal::StakingSetSessionsPerEra(try_opt!(Slicable::from_slice(value))), + Proposal::StakingSetSessionsPerEra(try_opt!(Slicable::decode(input))), InternalFunctionId::StakingSetBondingDuration => - Proposal::StakingSetBondingDuration(try_opt!(Slicable::from_slice(value))), + Proposal::StakingSetBondingDuration(try_opt!(Slicable::decode(input))), InternalFunctionId::StakingSetValidatorCount => - Proposal::StakingSetValidatorCount(try_opt!(Slicable::from_slice(value))), + Proposal::StakingSetValidatorCount(try_opt!(Slicable::decode(input))), InternalFunctionId::StakingForceNewEra => Proposal::StakingForceNewEra, InternalFunctionId::GovernanceSetApprovalPpmRequired => - Proposal::GovernanceSetApprovalPpmRequired(try_opt!(Slicable::from_slice(value))), + Proposal::GovernanceSetApprovalPpmRequired(try_opt!(Slicable::decode(input))), }; Some(function) @@ -210,25 +210,25 @@ pub enum Function { } impl Slicable for Function { - fn from_slice(value: &mut &[u8]) -> Option { - let id = try_opt!(u8::from_slice(value).and_then(FunctionId::from_u8)); + fn decode(input: &mut I) -> Option { + let id = try_opt!(u8::decode(input).and_then(FunctionId::from_u8)); Some(match id { FunctionId::TimestampSet => - Function::TimestampSet(try_opt!(Slicable::from_slice(value))), + Function::TimestampSet(try_opt!(Slicable::decode(input))), FunctionId::SessionSetKey => - Function::SessionSetKey(try_opt!(Slicable::from_slice(value))), + Function::SessionSetKey(try_opt!(Slicable::decode(input))), FunctionId::StakingStake => Function::StakingStake, FunctionId::StakingUnstake => Function::StakingUnstake, FunctionId::StakingTransfer => { - let to = try_opt!(Slicable::from_slice(value)); - let amount = try_opt!(Slicable::from_slice(value)); + let to = try_opt!(Slicable::decode(input)); + let amount = try_opt!(Slicable::decode(input)); Function::StakingTransfer(to, amount) } FunctionId::GovernancePropose => - Function::GovernancePropose(try_opt!(Slicable::from_slice(value))), + Function::GovernancePropose(try_opt!(Slicable::decode(input))), FunctionId::GovernanceApprove => - Function::GovernanceApprove(try_opt!(Slicable::from_slice(value))), + Function::GovernanceApprove(try_opt!(Slicable::decode(input))), }) } @@ -285,11 +285,11 @@ pub struct Transaction { } impl Slicable for Transaction { - fn from_slice(value: &mut &[u8]) -> Option { + fn decode(input: &mut I) -> Option { Some(Transaction { - signed: try_opt!(Slicable::from_slice(value)), - nonce: try_opt!(Slicable::from_slice(value)), - function: try_opt!(Slicable::from_slice(value)), + signed: try_opt!(Slicable::decode(input)), + nonce: try_opt!(Slicable::decode(input)), + function: try_opt!(Slicable::decode(input)), }) } @@ -321,16 +321,16 @@ pub struct UncheckedTransaction { } impl Slicable for UncheckedTransaction { - fn from_slice(value: &mut &[u8]) -> Option { + fn decode(input: &mut I) -> Option { // This is a little more complicated than usua since the binary format must be compatible // with substrate's generic `Vec` type. Basically this just means accepting that there // will be a prefix of u32, which has the total number of bytes following (we don't need // to use this). - let _length_do_not_remove_me_see_above: u32 = try_opt!(Slicable::from_slice(value)); + let _length_do_not_remove_me_see_above: u32 = try_opt!(Slicable::decode(input)); Some(UncheckedTransaction { - transaction: try_opt!(Slicable::from_slice(value)), - signature: try_opt!(Slicable::from_slice(value)), + transaction: try_opt!(Slicable::decode(input)), + signature: try_opt!(Slicable::decode(input)), }) } @@ -398,6 +398,6 @@ mod tests { let v = Slicable::to_vec(&tx); println!("{}", HexDisplay::from(&v)); - assert_eq!(UncheckedTransaction::from_slice(&mut &v[..]).unwrap(), tx); + assert_eq!(UncheckedTransaction::decode(&mut &v[..]).unwrap(), tx); } } diff --git a/polkadot/runtime/src/api.rs b/polkadot/runtime/src/api.rs new file mode 100644 index 0000000000000..3f9ff71473dac --- /dev/null +++ b/polkadot/runtime/src/api.rs @@ -0,0 +1,27 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use runtime::{system, parachains, consensus, session}; + +impl_stubs!( + execute_block => |block| system::internal::execute_block(block), + execute_transaction => |(header, utx)| system::internal::execute_transaction(utx, header), + finalise_block => |header| system::internal::finalise_block(header), + validator_count => |()| session::validator_count(), + validators => |()| session::validators(), + authorities => |()| consensus::authorities(), + duty_roster => |()| parachains::calculate_duty_roster() +); diff --git a/polkadot/runtime/src/genesismap.rs b/polkadot/runtime/src/genesismap.rs index a12086cc47d7b..7cb0aba5b63ea 100644 --- a/polkadot/runtime/src/genesismap.rs +++ b/polkadot/runtime/src/genesismap.rs @@ -16,12 +16,12 @@ //! Tool for creating the genesis block. -use std::collections::HashMap; -use runtime_io::twox_128; use codec::{KeyedVec, Joiner}; -use support::Hashable; use polkadot_primitives::{BlockNumber, Block, AccountId}; +use std::collections::HashMap; +use runtime_io::twox_128; use runtime::staking::Balance; +use support::Hashable; /// Configuration of a general Polkadot genesis block. pub struct GenesisConfig { diff --git a/polkadot/runtime/src/lib.rs b/polkadot/runtime/src/lib.rs index 46e4b6c860051..10d37aacaeadc 100644 --- a/polkadot/runtime/src/lib.rs +++ b/polkadot/runtime/src/lib.rs @@ -37,14 +37,11 @@ extern crate hex_literal; #[macro_use] pub mod support; pub mod runtime; +pub mod api; #[cfg(feature = "std")] pub mod genesismap; -use rstd::prelude::*; -use codec::Slicable; -use polkadot_primitives::{Header, Block, UncheckedTransaction}; - /// Type definitions and helpers for transactions. pub mod transaction { use rstd::ops; @@ -83,39 +80,3 @@ pub mod transaction { } } } - -/// Execute a block, with `input` being the canonical serialisation of the block. Returns the -/// empty vector. -pub fn execute_block(mut input: &[u8]) -> Vec { - runtime::system::internal::execute_block(Block::from_slice(&mut input).unwrap()); - Vec::new() -} - -/// Execute a given, serialised, transaction. Returns the empty vector. -pub fn execute_transaction(mut input: &[u8]) -> Vec { - let header = Header::from_slice(&mut input).unwrap(); - let utx = UncheckedTransaction::from_slice(&mut input).unwrap(); - let header = runtime::system::internal::execute_transaction(utx, header); - header.to_vec() -} - -/// Execute a given, serialised, transaction. Returns the empty vector. -pub fn finalise_block(mut input: &[u8]) -> Vec { - let header = Header::from_slice(&mut input).unwrap(); - let header = runtime::system::internal::finalise_block(header); - header.to_vec() -} - -/// Run whatever tests we have. -pub fn run_tests(mut input: &[u8]) -> Vec { - use runtime_io::print; - - print("run_tests..."); - let block = Block::from_slice(&mut input).unwrap(); - print("deserialised block."); - let stxs = block.transactions.iter().map(Slicable::to_vec).collect::>(); - print("reserialised transactions."); - [stxs.len() as u8].to_vec() -} - -impl_stubs!(execute_block, execute_transaction, finalise_block, run_tests); diff --git a/polkadot/runtime/src/runtime/parachains.rs b/polkadot/runtime/src/runtime/parachains.rs index d0c4f5c845247..c039892c03bfc 100644 --- a/polkadot/runtime/src/runtime/parachains.rs +++ b/polkadot/runtime/src/runtime/parachains.rs @@ -17,34 +17,13 @@ //! Main parachains logic. For now this is just the determination of which validators do what. use rstd::prelude::*; -use rstd::mem; use codec::{Slicable, Joiner}; -use support::{Hashable, with_env, storage}; use runtime::session; +use support::{Hashable, with_env, storage}; +use polkadot_primitives::parachain::{Id, Chain, DutyRoster}; const PARACHAIN_COUNT: &[u8] = b"par:cou"; -/// Identifier for a chain, either one of a number of parachains or the relay chain. -#[derive(Copy, Clone, PartialEq)] -#[cfg_attr(test, derive(Debug))] -pub enum Chain { - /// The relay chain. - Relay, - /// A parachain of the given index. - Parachain(u32), -} - -/// The duty roster specifying what jobs each validator must do. -#[derive(Clone, PartialEq)] -#[cfg_attr(test, derive(Default, Debug))] -pub struct DutyRoster { - /// Lookup from validator index to chain on which that validator has a duty to validate. - pub validator_duty: Vec, - /// Lookup from validator index to chain on which that validator has a duty to guarantee - /// availability. - pub guarantor_duty: Vec, -} - /// Get the number of parachains registered at present. pub fn parachain_count() -> u32 { storage::get_or(PARACHAIN_COUNT, 0) @@ -57,7 +36,8 @@ pub fn calculate_duty_roster() -> DutyRoster { let validators_per_parachain = (validator_count - 1) / parachain_count; let mut roles_val = (0..validator_count).map(|i| match i { - i if i < parachain_count * validators_per_parachain => Chain::Parachain(i / validators_per_parachain as u32), + i if i < parachain_count * validators_per_parachain => + Chain::Parachain(Id::from(i / validators_per_parachain as u32)), _ => Chain::Relay, }).collect::>(); let mut roles_gua = roles_val.clone(); @@ -74,8 +54,8 @@ pub fn calculate_duty_roster() -> DutyRoster { let remaining = (validator_count - i) as usize; // 4 * 2 32-bit ints per 256-bit seed. - let val_index = u32::from_slice(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining; - let gua_index = u32::from_slice(&mut &seed[offset + 4..offset + 8]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining; + let val_index = u32::decode(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining; + let gua_index = u32::decode(&mut &seed[offset + 4..offset + 8]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining; if offset == 24 { // into the last 8 bytes - rehash to gather new entropy @@ -115,7 +95,7 @@ mod tests { let check_roster = |duty_roster: &DutyRoster| { assert_eq!(duty_roster.validator_duty.len(), 8); assert_eq!(duty_roster.guarantor_duty.len(), 8); - for i in 0..2 { + for i in (0..2).map(Id::from) { assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3); assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3); } diff --git a/polkadot/runtime/src/runtime/session.rs b/polkadot/runtime/src/runtime/session.rs index 2e3f81b6450ee..56a12f05c085c 100644 --- a/polkadot/runtime/src/runtime/session.rs +++ b/polkadot/runtime/src/runtime/session.rs @@ -35,7 +35,7 @@ impl StorageVec for ValidatorStorageVec { const PREFIX: &'static[u8] = b"ses:val:"; } -/// Get the current set of authorities. These are the session keys. +/// Get the current set of validators. pub fn validators() -> Vec { ValidatorStorageVec::items() } diff --git a/polkadot/runtime/src/support/storage.rs b/polkadot/runtime/src/support/storage.rs index 5878113b133fa..8306906914b87 100644 --- a/polkadot/runtime/src/support/storage.rs +++ b/polkadot/runtime/src/support/storage.rs @@ -18,14 +18,33 @@ use rstd::prelude::*; use runtime_io::{self, twox_128}; -use codec::{Slicable, KeyedVec}; +use codec::{Input, Slicable, KeyedVec}; // TODO: consider using blake256 to avoid possible preimage attack. +struct IncrementalInput<'a> { + key: &'a [u8], + pos: usize, +} + +impl<'a> Input for IncrementalInput<'a> { + fn read(&mut self, into: &mut [u8]) -> usize { + let len = runtime_io::read_storage(self.key, into, self.pos); + let read = ::rstd::cmp::min(len, into.len()); + self.pos += read; + read + } +} + /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(key: &[u8]) -> Option { - let raw = runtime_io::storage(&twox_128(key)[..]); - Slicable::from_slice(&mut &raw[..]) + let key = twox_128(key); + let mut input = IncrementalInput { + key: &key[..], + pos: 0, + }; + + Slicable::decode(&mut input) } /// Return the value of the item in storage under `key`, or the type's default if there is no @@ -142,12 +161,16 @@ pub trait StorageVec { } pub mod unhashed { - use super::{runtime_io, Slicable, KeyedVec, Vec}; + use super::{runtime_io, Slicable, KeyedVec, Vec, IncrementalInput}; /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(key: &[u8]) -> Option { - let raw = runtime_io::storage(key); - T::from_slice(&mut &raw[..]) + let mut input = IncrementalInput { + key, + pos: 0, + }; + + T::decode(&mut input) } /// Return the value of the item in storage under `key`, or the type's default if there is no diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index 3afbce2059eec..5418e0432c20b 100644 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 940a1e2910cf4..98dabfb1bbd67 100644 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ diff --git a/substrate/client/src/lib.rs b/substrate/client/src/lib.rs index 76a7ef0ffc137..2db1455f7c8da 100644 --- a/substrate/client/src/lib.rs +++ b/substrate/client/src/lib.rs @@ -1,20 +1,20 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Substrate. -// Polkadot is free software: you can redistribute it and/or modify +// Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// Polkadot is distributed in the hope that it will be useful, +// Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// along with Substrate. If not, see . -//! Polkadot Client +//! Substrate Client #![warn(missing_docs)] @@ -139,8 +139,9 @@ impl Client where }) } - fn state_at(&self, id: BlockId) -> error::Result { - self.backend.state_at(id) + /// Get a reference to the state at a given block. + pub fn state_at(&self, block: &BlockId) -> error::Result { + self.backend.state_at(*block) } /// Expose backend reference. To be used in tests only @@ -148,28 +149,33 @@ impl Client where &self.backend } - /// Return single storage entry of contract under given address in state in a block of given id. + /// Return single storage entry of contract under given address in state in a block of given hash. pub fn storage(&self, id: &BlockId, key: &StorageKey) -> error::Result { - Ok(self.state_at(*id)? + Ok(self.state_at(id)? .storage(&key.0) .map(|x| StorageData(x.to_vec()))?) } - /// Execute a call to a contract on top of state in a block of given id. + /// Get the code at a given block. + pub fn code_at(&self, id: &BlockId) -> error::Result> { + self.storage(id, &StorageKey(b":code:".to_vec())).map(|data| data.0) + } + + /// Execute a call to a contract on top of state in a block of given hash. /// /// No changes are made. pub fn call(&self, id: &BlockId, method: &str, call_data: &[u8]) -> error::Result { - let state = self.state_at(*id)?; let mut changes = state_machine::OverlayedChanges::default(); + let state = self.state_at(id)?; - let _ = state_machine::execute( + let return_data = state_machine::execute( &state, &mut changes, &self.executor, method, call_data, )?; - Ok(CallResult { return_data: vec![], changes }) + Ok(CallResult { return_data, changes }) } /// Queue a block for import. diff --git a/substrate/codec/src/lib.rs b/substrate/codec/src/lib.rs index 0a672161e9f9a..92df92d44927e 100644 --- a/substrate/codec/src/lib.rs +++ b/substrate/codec/src/lib.rs @@ -20,6 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc))] +#[cfg_attr(not(feature = "std"), macro_use)] extern crate substrate_runtime_std as rstd; mod endiansensitive; @@ -28,6 +29,6 @@ mod joiner; mod keyedvec; pub use self::endiansensitive::EndianSensitive; -pub use self::slicable::{Slicable, NonTrivialSlicable}; +pub use self::slicable::{Input, Slicable, NonTrivialSlicable}; pub use self::joiner::Joiner; pub use self::keyedvec::KeyedVec; diff --git a/substrate/codec/src/slicable.rs b/substrate/codec/src/slicable.rs index 653bbb7b168e5..003e49c5f125e 100644 --- a/substrate/codec/src/slicable.rs +++ b/substrate/codec/src/slicable.rs @@ -21,13 +21,25 @@ use rstd::vec::Vec; use super::joiner::Joiner; use super::endiansensitive::EndianSensitive; +/// Trait that allows reading of data into a slice. +pub trait Input { + /// Read into the provided input slice. Returns the number of bytes read. + fn read(&mut self, into: &mut [u8]) -> usize; +} + +impl<'a> Input for &'a [u8] { + fn read(&mut self, into: &mut [u8]) -> usize { + let len = ::rstd::cmp::min(into.len(), self.len()); + into[..len].copy_from_slice(&self[..len]); + *self = &self[len..]; + len + } +} + /// Trait that allows zero-copy read/write of value-references to/from slices in LE format. pub trait Slicable: Sized { - /// Attempt to deserialise the value from a slice. Ignore trailing bytes and - /// set the slice's start to just after the last byte consumed. - /// - /// If `None` is returned, then the slice should be unmodified. - fn from_slice(value: &mut &[u8]) -> Option; + /// Attempt to deserialise the value from input. + fn decode(value: &mut I) -> Option; /// Convert self to an owned vector. fn to_vec(&self) -> Vec { self.as_slice_then(|s| s.to_vec()) @@ -40,16 +52,19 @@ pub trait Slicable: Sized { pub trait NonTrivialSlicable: Slicable {} impl Slicable for T { - fn from_slice(value: &mut &[u8]) -> Option { + fn decode(input: &mut I) -> Option { let size = mem::size_of::(); assert!(size > 0, "EndianSensitive can never be implemented for a zero-sized type."); - if value.len() >= size { - let x: T = unsafe { ::rstd::ptr::read(value.as_ptr() as *const T) }; - *value = &value[size..]; - Some(x.from_le()) - } else { - None + let mut val: T = unsafe { mem::zeroed() }; + + unsafe { + let raw: &mut [u8] = slice::from_raw_parts_mut( + &mut val as *mut T as *mut u8, + size + ); + if input.read(raw) != size { return None } } + Some(val.from_le()) } fn as_slice_then R>(&self, f: F) -> R { @@ -70,12 +85,15 @@ impl Slicable for T { } impl Slicable for Vec { - fn from_slice(value: &mut &[u8]) -> Option { - u32::from_slice(value).map(move |len| { + fn decode(input: &mut I) -> Option { + u32::decode(input).and_then(move |len| { let len = len as usize; - let res = value[..len].to_vec(); - *value = &value[len..]; - res + let mut vec = vec![0; len]; + if input.read(&mut vec[..len]) != len { + None + } else { + Some(vec) + } }) } fn as_slice_then R>(&self, f: F) -> R { @@ -92,18 +110,60 @@ impl Slicable for Vec { } } +macro_rules! impl_vec_simple_array { + ($($size:expr),*) => { + $( + impl Slicable for Vec<[T; $size]> + where [T; $size]: EndianSensitive + { + fn decode(input: &mut I) -> Option { + u32::decode(input).and_then(move |len| { + let mut r = Vec::with_capacity(len as usize); + for _ in 0..len { + r.push(match Slicable::decode(input) { + Some(x) => x, + None => return None, + }); + } + + Some(r) + }) + } + + fn as_slice_then R>(&self, f: F) -> R { + f(&self.to_vec()) + } + + fn to_vec(&self) -> Vec { + use rstd::iter::Extend; + + let len = self.len(); + assert!(len <= u32::max_value() as usize, "Attempted to serialize vec with too many elements."); + + let mut r: Vec = Vec::new().join(&(len as u32)); + for item in self { + r.extend(item.to_vec()); + } + r + } + } + )* + } +} + +impl_vec_simple_array!(1, 2, 4, 8, 16, 32, 64); + impl NonTrivialSlicable for Vec where Vec: Slicable {} impl Slicable for Vec { - fn from_slice(value: &mut &[u8]) -> Option { - u32::from_slice(value).and_then(move |len| { - let len = len as usize; - let mut r = Vec::with_capacity(len); + fn decode(input: &mut I) -> Option { + u32::decode(input).and_then(move |len| { + let mut r = Vec::with_capacity(len as usize); for _ in 0..len { - match T::from_slice(value) { + r.push(match T::decode(input) { + Some(x) => x, None => return None, - Some(v) => r.push(v), - } + }); } Some(r) @@ -128,6 +188,82 @@ impl Slicable for Vec { } } +impl Slicable for () { + fn decode(_: &mut I) -> Option<()> { + Some(()) + } + + fn as_slice_then R>(&self, f: F) -> R { + f(&[]) + } + + fn to_vec(&self) -> Vec { + Vec::new() + } +} + +macro_rules! tuple_impl { + ($one:ident,) => { + impl<$one: Slicable> Slicable for ($one,) { + fn decode(input: &mut I) -> Option { + match $one::decode(input) { + None => None, + Some($one) => Some(($one,)), + } + } + + fn as_slice_then R>(&self, f: F) -> R { + self.0.as_slice_then(f) + } + } + }; + ($first:ident, $($rest:ident,)+) => { + impl<$first: Slicable, $($rest: Slicable),+> + Slicable for + ($first, $($rest),+) { + fn decode(input: &mut INPUT) -> Option { + Some(( + match $first::decode(input) { + Some(x) => x, + None => return None, + }, + $(match $rest::decode(input) { + Some(x) => x, + None => return None, + },)+ + )) + } + + fn as_slice_then(&self, f: PROCESS) -> RETURN + where PROCESS: FnOnce(&[u8]) -> RETURN + { + let mut v = Vec::new(); + + let ( + ref $first, + $(ref $rest),+ + ) = *self; + + $first.as_slice_then(|s| v.extend(s)); + $($rest.as_slice_then(|s| v.extend(s));)+ + + f(v.as_slice()) + } + } + + tuple_impl!($($rest,)+); + } +} + +#[allow(non_snake_case)] +mod inner_tuple_impl { + use rstd::vec::Vec; + + use super::{Input, Slicable}; + tuple_impl!(A, B, C, D, E, F, G, H, I, J, K,); +} + + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/executor/src/lib.rs b/substrate/executor/src/lib.rs index 266373f2b2297..d520048e74964 100644 --- a/substrate/executor/src/lib.rs +++ b/substrate/executor/src/lib.rs @@ -61,4 +61,4 @@ mod native_executor; pub mod error; pub use wasm_executor::WasmExecutor; -pub use native_executor::{NativeExecutionDispatch, NativeExecutor}; +pub use native_executor::{with_native_environment, NativeExecutor, NativeExecutionDispatch}; diff --git a/substrate/executor/src/native_executor.rs b/substrate/executor/src/native_executor.rs index 0ee6a66864be2..0855e78e85869 100644 --- a/substrate/executor/src/native_executor.rs +++ b/substrate/executor/src/native_executor.rs @@ -15,11 +15,23 @@ // along with Substrate. If not, see . use error::{Error, ErrorKind, Result}; -use runtime_io; use state_machine::{Externalities, CodeExecutor}; use wasm_executor::WasmExecutor; -use std::panic::catch_unwind; +fn safe_call(f: F) -> Result + where F: ::std::panic::UnwindSafe + FnOnce() -> U +{ + ::std::panic::catch_unwind(f).map_err(|_| ErrorKind::Runtime.into()) +} + +/// Set up the externalities and safe calling environment to execute calls to a native runtime. +/// +/// If the inner closure panics, it will be caught and return an error. +pub fn with_native_environment(ext: &mut Externalities, f: F) -> Result + where F: ::std::panic::UnwindSafe + FnOnce() -> U +{ + ::runtime_io::with_externalities(ext, move || safe_call(f)) +} /// Delegate for dispatching a CodeExecutor call to native code. pub trait NativeExecutionDispatch { @@ -28,7 +40,7 @@ pub trait NativeExecutionDispatch { /// Dispatch a method and input data to be executed natively. Returns `Some` result or `None` /// if the `method` is unknown. Panics if there's an unrecoverable error. - fn dispatch(method: &str, data: &[u8]) -> Option>; + fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> Result>; } /// A generic `CodeExecutor` implementation that uses a delegate to determine wasm code equivalence @@ -38,10 +50,6 @@ pub struct NativeExecutor { pub _dummy: ::std::marker::PhantomData, } -fn safe_call Option>>(f: F) -> Result>> { - catch_unwind(f).map_err(|_| ErrorKind::Runtime.into()) -} - impl CodeExecutor for NativeExecutor { type Error = Error; @@ -53,8 +61,8 @@ impl CodeExecutor for NativeExecutor Result> { if code == D::native_equivalent() { - runtime_io::with_externalities(ext, || safe_call(|| D::dispatch(method, data)))? - .ok_or(ErrorKind::MethodNotFound(method.to_owned()).into()) + // call native + D::dispatch(ext, method, data) } else { // call into wasm. WasmExecutor.call(ext, code, method, data) diff --git a/substrate/primitives/src/block.rs b/substrate/primitives/src/block.rs index 4ac11f9c461f2..41957f577464a 100644 --- a/substrate/primitives/src/block.rs +++ b/substrate/primitives/src/block.rs @@ -19,7 +19,7 @@ #[cfg(feature = "std")] use bytes; use rstd::vec::Vec; -use codec::Slicable; +use codec::{Input, Slicable}; use hash::H256; /// Used to refer to a block number. @@ -37,8 +37,8 @@ pub type TransactionHash = H256; pub struct Transaction(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); impl Slicable for Transaction { - fn from_slice(value: &mut &[u8]) -> Option { - Vec::::from_slice(value).map(Transaction) + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(Transaction) } fn as_slice_then R>(&self, f: F) -> R { @@ -54,8 +54,8 @@ impl ::codec::NonTrivialSlicable for Transaction { } pub struct Log(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); impl Slicable for Log { - fn from_slice(value: &mut &[u8]) -> Option { - Vec::::from_slice(value).map(Log) + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(Log) } fn as_slice_then R>(&self, f: F) -> R { @@ -74,8 +74,8 @@ pub struct Digest { } impl Slicable for Digest { - fn from_slice(value: &mut &[u8]) -> Option { - Vec::::from_slice(value).map(|logs| Digest { logs }) + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(|logs| Digest { logs }) } fn as_slice_then R>(&self, f: F) -> R { @@ -97,10 +97,10 @@ pub struct Block { } impl Slicable for Block { - fn from_slice(value: &mut &[u8]) -> Option { + fn decode(input: &mut I) -> Option { Some(Block { - header: try_opt!(Slicable::from_slice(value)), - transactions: try_opt!(Slicable::from_slice(value)), + header: try_opt!(Slicable::decode(input)), + transactions: try_opt!(Slicable::decode(input)), }) } @@ -152,13 +152,13 @@ impl Header { } impl Slicable for Header { - fn from_slice(value: &mut &[u8]) -> Option { + fn decode(input: &mut I) -> Option { Some(Header { - parent_hash: try_opt!(Slicable::from_slice(value)), - number: try_opt!(Slicable::from_slice(value)), - state_root: try_opt!(Slicable::from_slice(value)), - transaction_root: try_opt!(Slicable::from_slice(value)), - digest: try_opt!(Slicable::from_slice(value)), + parent_hash: try_opt!(Slicable::decode(input)), + number: try_opt!(Slicable::decode(input)), + state_root: try_opt!(Slicable::decode(input)), + transaction_root: try_opt!(Slicable::decode(input)), + digest: try_opt!(Slicable::decode(input)), }) } @@ -208,6 +208,6 @@ mod tests { }"#); let v = header.to_vec(); - assert_eq!(Header::from_slice(&mut &v[..]).unwrap(), header); + assert_eq!(Header::decode(&mut &v[..]).unwrap(), header); } } diff --git a/substrate/primitives/src/hash.rs b/substrate/primitives/src/hash.rs index 7a529b1a0c28b..b3c069f4a55d0 100644 --- a/substrate/primitives/src/hash.rs +++ b/substrate/primitives/src/hash.rs @@ -40,8 +40,8 @@ macro_rules! impl_rest { } impl ::codec::Slicable for $name { - fn from_slice(value: &mut &[u8]) -> Option { - <[u8; $len] as ::codec::Slicable>::from_slice(value).map($name) + fn decode(input: &mut I) -> Option { + <[u8; $len] as ::codec::Slicable>::decode(input).map($name) } fn as_slice_then R>(&self, f: F) -> R { diff --git a/substrate/runtime-io/with_std.rs b/substrate/runtime-io/with_std.rs index 40c1fe754d8d1..bcedb481162b5 100644 --- a/substrate/runtime-io/with_std.rs +++ b/substrate/runtime-io/with_std.rs @@ -22,6 +22,8 @@ extern crate substrate_primitives as primitives; extern crate triehash; extern crate ed25519; +#[doc(hidden)] +pub extern crate substrate_codec as codec; // re-export hashing functions. pub use primitives::{blake2_256, twox_128, twox_256}; @@ -40,7 +42,7 @@ pub fn storage(key: &[u8]) -> Vec { } /// Get `key` from storage, placing the value into `value_out` (as much as possible) and return -/// the number of bytes that the key in storage was. +/// the number of bytes that the key in storage was beyond the offset. pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> usize { ext::with(|ext| { if let Ok(value) = ext.storage(key) { @@ -124,11 +126,20 @@ pub fn print(value: T) { #[macro_export] macro_rules! impl_stubs { - ($( $name:ident ),*) => { - pub fn dispatch(method: &str, data: &[u8]) -> Option> { + ( $( $name:ident => $invoke:expr ),* ) => { + /// Dispatch logic for the native runtime. + pub fn dispatch(method: &str, mut data: &[u8]) -> Option> { match method { $( - stringify!($name) => Some($name(data)), + stringify!($name) => { + let input = match $crate::codec::Slicable::decode(&mut data) { + Some(input) => input, + None => panic!("Bad input data provided to {}", stringify!($name)), + }; + + let output = $invoke(input); + Some($crate::codec::Slicable::to_vec(&output)) + } )* _ => None, } diff --git a/substrate/runtime-io/without_std.rs b/substrate/runtime-io/without_std.rs index e5db2c7753ccb..a4d8e4076d5ee 100644 --- a/substrate/runtime-io/without_std.rs +++ b/substrate/runtime-io/without_std.rs @@ -17,6 +17,9 @@ extern crate substrate_runtime_std as rstd; extern crate substrate_primitives as primitives; +#[doc(hidden)] +pub extern crate substrate_codec as codec; + use rstd::intrinsics; use rstd::vec::Vec; pub use rstd::{mem, slice}; @@ -68,7 +71,7 @@ pub fn set_storage(key: &[u8], value: &[u8]) { } /// Get `key` from storage, placing the value into `value_out` (as much as possible) and return -/// the number of bytes that the key in storage was. +/// the number of bytes that the key in storage was beyond the offset. pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> usize { unsafe { ext_get_storage_into( @@ -178,25 +181,33 @@ pub fn print(value: T) { #[macro_export] macro_rules! impl_stubs { - ( $( $name:ident ),* ) => { - pub mod _internal { - $( - #[no_mangle] - pub fn $name(input_data: *mut u8, input_len: usize) -> u64 { - let input = if input_len == 0 { - &[0u8; 0] - } else { - unsafe { - $crate::slice::from_raw_parts(input_data, input_len) - } - }; - - let output = super::$name(input); - let r = output.as_ptr() as u64 + ((output.len() as u64) << 32); - $crate::mem::forget(output); - r - } - )* - } + ( $( $new_name:ident => $invoke:expr ),* ) => { + $( + #[no_mangle] + pub fn $new_name(input_data: *mut u8, input_len: usize) -> u64 { + let mut input = if input_len == 0 { + &[0u8; 0] + } else { + unsafe { + $crate::slice::from_raw_parts(input_data, input_len) + } + }; + + let input = match $crate::codec::Slicable::decode(&mut input) { + Some(input) => input, + None => panic!("Bad input data provided to {}", stringify!($name)), + }; + + let output = ($invoke)(input); + let output = $crate::codec::Slicable::to_vec(&output); + let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); + + // Leak the output vector to avoid it being freed. + // This is fine in a WASM context since the heap + // will be discarded after the call. + ::core::mem::forget(output); + res + } + )* } } diff --git a/substrate/runtime-std/src/lib.rs b/substrate/runtime-std/src/lib.rs index 2dde712473aee..0128ebd31ae61 100644 --- a/substrate/runtime-std/src/lib.rs +++ b/substrate/runtime-std/src/lib.rs @@ -21,6 +21,7 @@ #![cfg_attr(not(feature = "std"), feature(lang_items))] #![cfg_attr(not(feature = "std"), feature(core_intrinsics))] #![cfg_attr(not(feature = "std"), feature(alloc))] +#![cfg_attr(not(feature = "std"), feature(macro_reexport))] #![cfg_attr(feature = "std", doc = "Polkadot runtime standard library as compiled when linked with Rust's standard library.")] #![cfg_attr(not(feature = "std"), doc = "Polkadot's runtime standard library as compiled without Rust's standard library.")] diff --git a/substrate/runtime-std/with_std.rs b/substrate/runtime-std/with_std.rs index 01212679fc43e..960871665e2c4 100644 --- a/substrate/runtime-std/with_std.rs +++ b/substrate/runtime-std/with_std.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -pub use std::vec; -pub use std::rc; -pub use std::cell; pub use std::boxed; -pub use std::slice; +pub use std::cell; +pub use std::cmp; +pub use std::iter; pub use std::mem; pub use std::ops; -pub use std::iter; pub use std::ptr; +pub use std::rc; +pub use std::slice; +pub use std::vec; diff --git a/substrate/runtime-std/without_std.rs b/substrate/runtime-std/without_std.rs index 4aff3153ca20e..b27db9bc7d217 100644 --- a/substrate/runtime-std/without_std.rs +++ b/substrate/runtime-std/without_std.rs @@ -15,19 +15,21 @@ // along with Substrate. If not, see . #[cfg(feature = "nightly")] +#[macro_reexport(vec)] extern crate alloc; #[cfg(feature = "nightly")] extern crate pwasm_libc; #[cfg(feature = "nightly")] extern crate pwasm_alloc; -pub use alloc::vec; pub use alloc::boxed; pub use alloc::rc; -pub use core::mem; -pub use core::slice; +pub use alloc::vec; pub use core::cell; -pub use core::ops; +pub use core::cmp; +pub use core::intrinsics; pub use core::iter; +pub use core::mem; +pub use core::ops; pub use core::ptr; -pub use core::intrinsics; +pub use core::slice;