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

Authoring with WASM runtime #2

Merged
merged 5 commits into from
Sep 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = ["Parity Technologies <[email protected]>"]

[dependencies]
error-chain = "0.12"
log = "0.3"
polkadot-executor = { path = "../executor" }
polkadot-runtime = { path = "../runtime" }
polkadot-primitives = { path = "../primitives" }
Expand All @@ -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" }
150 changes: 73 additions & 77 deletions api/src/full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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> {
Expand All @@ -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)
})
}
}
Expand Down
11 changes: 7 additions & 4 deletions api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,26 @@ 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>) {
description("Other error")
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<_>)),
}
}
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10 changes: 9 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);
}

Expand Down
Loading