Unverified Commit bf12c659 authored by Gav Wood's avatar Gav Wood Committed by GitHub
Browse files

Merge pull request #2 from paritytech/a-wasm-authoring

Authoring with WASM runtime
parents bb5919da 36b831a1
......@@ -5,6 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.12"
log = "0.3"
polkadot-executor = { path = "../executor" }
polkadot-runtime = { path = "../runtime" }
polkadot-primitives = { path = "../primitives" }
......@@ -16,7 +17,6 @@ substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-executor = { git = "https://github.com/paritytech/substrate" }
substrate-state-machine = { git = "https://github.com/paritytech/substrate" }
log = "0.3"
[dev-dependencies]
substrate-keyring = { git = "https://github.com/paritytech/substrate" }
......@@ -18,47 +18,67 @@
use client::backend::LocalBackend;
use client::block_builder::BlockBuilder as ClientBlockBuilder;
use client::{Client, LocalCallExecutor};
use client::{self, Client, LocalCallExecutor, CallExecutor};
use codec::{Encode, Decode};
use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::NativeExecutor;
use state_machine;
use state_machine::ExecutionManager;
use runtime::Address;
use runtime_primitives::traits::AuxLookup;
use primitives::{
AccountId, Block, Header, BlockId, Hash, Index, InherentData,
SessionKey, Timestamp, UncheckedExtrinsic,
};
use primitives::parachain::{DutyRoster, Id as ParaId};
use substrate_primitives::{KeccakHasher, RlpCodec};
use {BlockBuilder, PolkadotApi, LocalPolkadotApi, ErrorKind, Error, Result};
// set up the necessary scaffolding to execute a set of calls to the runtime.
// this creates a new block on top of the given ID and initialises it.
macro_rules! with_runtime {
($client: ident, $at: expr, $exec: expr) => {{
let parent = $at;
let header = Header {
parent_hash: $client.block_hash_from_id(&parent)?
.ok_or_else(|| ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
number: $client.block_number_from_id(&parent)?
use {BlockBuilder, PolkadotApi, LocalPolkadotApi, Error, ErrorKind, Result};
fn call<B, R>(
client: &Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block>,
at: &BlockId,
function: &'static str,
input: &[u8])
-> Result<R>
where
R: Decode,
B: LocalBackend<Block, KeccakHasher, RlpCodec>,
{
let parent = at;
let header = Header {
parent_hash: client.block_hash_from_id(&parent)?
.ok_or_else(|| ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
number: client.block_number_from_id(&parent)?
.ok_or_else(|| ErrorKind::UnknownBlock(format!("{:?}", parent)))? + 1,
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
};
$client.state_at(&parent).map_err(Error::from).and_then(|state| {
let mut changes = Default::default();
let mut ext = state_machine::Ext::new(&mut changes, &state);
::substrate_executor::with_native_environment(&mut ext, || {
::runtime::Executive::initialise_block(&header);
($exec)()
}).map_err(Into::into)
})
}}
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
};
client.state_at(&parent).map_err(Error::from).and_then(|state| {
let mut overlay = Default::default();
let execution_manager = || ExecutionManager::Both(|wasm_result, native_result| {
warn!("Consensus error between wasm and native runtime execution at block {:?}", at);
warn!(" Function {:?}", function);
warn!(" Native result {:?}", native_result);
warn!(" Wasm result {:?}", wasm_result);
wasm_result
});
client.executor().call_at_state(
&state,
&mut overlay,
"initialise_block",
&header.encode(),
execution_manager()
)?;
let (r, _) = client.executor().call_at_state(
&state,
&mut overlay,
function,
input,
execution_manager()
)?;
Ok(R::decode(&mut &r[..])
.ok_or_else(|| client::error::Error::from(client::error::ErrorKind::CallResultDecode(function)))?)
})
}
impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> BlockBuilder for ClientBlockBuilder<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block, KeccakHasher, RlpCodec> {
......@@ -76,79 +96,63 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
type BlockBuilder = ClientBlockBuilder<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block, KeccakHasher, RlpCodec>;
fn session_keys(&self, at: &BlockId) -> Result<Vec<SessionKey>> {
with_runtime!(self, at, ::runtime::Consensus::authorities)
Ok(self.authorities_at(at)?)
}
fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>> {
with_runtime!(self, at, ::runtime::Session::validators)
call(self, at, "validators", &[])
}
fn random_seed(&self, at: &BlockId) -> Result<Hash> {
with_runtime!(self, at, ::runtime::System::random_seed)
call(self, at, "random_seed", &[])
}
fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster> {
with_runtime!(self, at, ::runtime::Parachains::calculate_duty_roster)
call(self, at, "duty_roster", &[])
}
fn timestamp(&self, at: &BlockId) -> Result<Timestamp> {
with_runtime!(self, at, ::runtime::Timestamp::get)
call(self, at, "timestamp", &[])
}
fn evaluate_block(&self, at: &BlockId, block: Block) -> Result<bool> {
use substrate_executor::error::ErrorKind as ExecErrorKind;
use codec::Encode;
use state_machine::ExecutionManager;
use client::CallExecutor;
let parent = at;
let res = self.state_at(&parent).map_err(Error::from).and_then(|state| {
let mut overlay = Default::default();
let execution_manager = || ExecutionManager::Both(|wasm_result, native_result| {
warn!("Consensus error between wasm and native runtime execution at block {:?}", at);
warn!(" While executing block {:?}", (block.header.number, block.header.hash()));
warn!(" Native result {:?}", native_result);
warn!(" Wasm result {:?}", wasm_result);
wasm_result
});
let (r, _) = self.executor().call_at_state(
&state,
&mut overlay,
"execute_block",
&block.encode(),
execution_manager()
)?;
Ok(r)
});
let encoded = block.encode();
let res: Result<()> = call(self, at, "execute_block", &encoded);
match res {
Ok(_) => Ok(true),
Err(err) => match err.kind() {
&ErrorKind::Executor(ExecErrorKind::Runtime) => Ok(false),
&ErrorKind::Execution(_) => Ok(false),
_ => Err(err)
}
}
}
fn index(&self, at: &BlockId, account: AccountId) -> Result<Index> {
with_runtime!(self, at, || ::runtime::System::account_nonce(account))
account.using_encoded(|encoded| {
call(self, at, "account_nonce", encoded)
})
}
fn lookup(&self, at: &BlockId, address: Address) -> Result<Option<AccountId>> {
with_runtime!(self, at, || <::runtime::Balances as AuxLookup>::lookup(address).ok())
address.using_encoded(|encoded| {
call(self, at, "lookup_address", encoded)
})
}
fn active_parachains(&self, at: &BlockId) -> Result<Vec<ParaId>> {
with_runtime!(self, at, ::runtime::Parachains::active_parachains)
call(self, at, "active_parachains", &[])
}
fn parachain_code(&self, at: &BlockId, parachain: ParaId) -> Result<Option<Vec<u8>>> {
with_runtime!(self, at, || ::runtime::Parachains::parachain_code(parachain))
parachain.using_encoded(|encoded| {
call(self, at, "parachain_code", encoded)
})
}
fn parachain_head(&self, at: &BlockId, parachain: ParaId) -> Result<Option<Vec<u8>>> {
with_runtime!(self, at, || ::runtime::Parachains::parachain_head(parachain))
parachain.using_encoded(|encoded| {
call(self, at, "parachain_head", encoded)
})
}
fn build_block(&self, at: &BlockId, inherent_data: InherentData) -> Result<Self::BlockBuilder> {
......@@ -161,17 +165,9 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
}
fn inherent_extrinsics(&self, at: &BlockId, inherent_data: InherentData) -> Result<Vec<UncheckedExtrinsic>> {
use codec::{Encode, Decode};
let runtime_version = self.runtime_version_at(at)?;
with_runtime!(self, at, || {
let extrinsics = ::runtime::inherent_extrinsics(inherent_data, runtime_version.spec_version);
extrinsics.into_iter()
.map(|x| x.encode()) // get encoded representation
.map(|x| Decode::decode(&mut &x[..])) // get byte-vec equivalent to extrinsic
.map(|x| x.expect("UncheckedExtrinsic has encoded representation equivalent to Vec<u8>; qed"))
.collect()
(inherent_data, runtime_version.spec_version).using_encoded(|encoded| {
call(self, at, "inherent_extrinsics", encoded)
})
}
}
......
......@@ -60,6 +60,11 @@ error_chain! {
description("Unknown block")
display("Unknown block {}", b)
}
/// Execution error.
Execution(e: String) {
description("Execution error")
display("Execution error: {}", e)
}
/// Some other error.
// TODO: allow to be specified as associated type of PolkadotApi
Other(e: Box<::std::error::Error + Send>) {
......@@ -67,16 +72,14 @@ error_chain! {
display("Other error: {}", e.description())
}
}
links {
Executor(substrate_executor::error::Error, substrate_executor::error::ErrorKind);
}
}
impl From<client::error::Error> for Error {
fn from(e: client::error::Error) -> Error {
match e {
client::error::Error(client::error::ErrorKind::UnknownBlock(b), _) => Error::from_kind(ErrorKind::UnknownBlock(b)),
client::error::Error(client::error::ErrorKind::Execution(e), _) =>
Error::from_kind(ErrorKind::Execution(format!("{}", e))),
other => Error::from_kind(ErrorKind::Other(Box::new(other) as Box<_>)),
}
}
......
......@@ -275,7 +275,15 @@ pub mod api {
finalise_block => |()| super::Executive::finalise_block(),
inherent_extrinsics => |(inherent, spec_version)| super::inherent_extrinsics(inherent, spec_version),
validator_count => |()| super::Session::validator_count(),
validators => |()| super::Session::validators()
validators => |()| super::Session::validators(),
duty_roster => |()| super::Parachains::calculate_duty_roster(),
active_parachains => |()| super::Parachains::active_parachains(),
parachain_head => |id| super::Parachains::parachain_head(&id),
parachain_code => |id| super::Parachains::parachain_code(&id),
timestamp => |()| super::Timestamp::get(),
random_seed => |()| super::System::random_seed(),
account_nonce => |account| super::System::account_nonce(&account),
lookup_address => |address| super::Balances::lookup_address(address)
);
}
......
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment