Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Re-introduce zero copy codec and add minimal polkadot client API which uses linked native runtime #65

Merged
merged 12 commits into from
Feb 8, 2018
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
13 changes: 13 additions & 0 deletions polkadot/api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "polkadot-api"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]

[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" }
118 changes: 118 additions & 0 deletions polkadot/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

//! 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<Vec<SessionKey>>;

/// Get validators at a given block.
fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>>;

/// Get the authority duty roster at a block.
fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster>;
}

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<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
where ::client::error::Error: From<<<B as Backend>::State as state_machine::backend::Backend>::Error>
{
fn authorities(&self, at: &BlockId) -> Result<Vec<SessionKey>> {
with_runtime!(self, at, ::runtime::consensus::authorities)
}

fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>> {
with_runtime!(self, at, ::runtime::session::validators)
}

fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster> {
with_runtime!(self, at, ::runtime::parachains::calculate_duty_roster)
}
}
4 changes: 2 additions & 2 deletions polkadot/cli/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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())
}
Expand Down
2 changes: 1 addition & 1 deletion polkadot/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub fn run<I, T>(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)?;

Expand Down
15 changes: 5 additions & 10 deletions polkadot/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Vec<u8>> {
runtime::dispatch(method, data)
fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> Result<Vec<u8>, Error> {
::substrate_executor::with_native_environment(ext, move || runtime::api::dispatch(method, data))?
.ok_or_else(|| ErrorKind::MethodNotFound(method.to_owned()).into())
}
}

Expand Down Expand Up @@ -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();
Expand Down
32 changes: 15 additions & 17 deletions polkadot/primitives/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -38,8 +38,8 @@ pub type TransactionHash = H256;
pub struct Log(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);

impl Slicable for Log {
fn from_slice(value: &mut &[u8]) -> Option<Self> {
Vec::<u8>::from_slice(value).map(Log)
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<u8>::decode(input).map(Log)
}

fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
Expand All @@ -58,8 +58,8 @@ pub struct Digest {
}

impl Slicable for Digest {
fn from_slice(value: &mut &[u8]) -> Option<Self> {
Vec::<Log>::from_slice(value).map(|logs| Digest { logs })
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<Log>::decode(input).map(|logs| Digest { logs })
}

fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
Expand All @@ -81,11 +81,9 @@ pub struct Block {
}

impl Slicable for Block {
fn from_slice(value: &mut &[u8]) -> Option<Self> {
Some(Block {
header: try_opt!(Slicable::from_slice(value)),
transactions: try_opt!(Slicable::from_slice(value)),
})
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let (header, transactions) = try_opt!(Slicable::decode(input));
Some(Block { header, transactions })
}

fn to_vec(&self) -> Vec<u8> {
Expand Down Expand Up @@ -136,13 +134,13 @@ impl Header {
}

impl Slicable for Header {
fn from_slice(value: &mut &[u8]) -> Option<Self> {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
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)),
})
}

Expand Down Expand Up @@ -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);
}
}
3 changes: 2 additions & 1 deletion polkadot/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading