Runtime API clean up (#892)

* Rename `NewTxQueue` to `TaggedTransactionQueue`

* Remove `BlockBuilder` API and support adding documentation to the API functions

* Adds new `BlockBuilder` API

* Fixes compilation with new `BlockBuilder` API

* Some more cleanup

* Cargo.lock update

* Try to fix on stable
This commit is contained in:
Bastian Köcher
2018-10-09 14:01:23 +02:00
committed by GitHub
parent 2c65ad6c7b
commit 6b4b8b8f8e
9 changed files with 240 additions and 170 deletions
+26 -36
View File
@@ -17,20 +17,22 @@
//! Utility struct to build a block.
use std::vec::Vec;
use codec::{Decode, Encode};
use state_machine::{self, native_when_possible};
use std::marker::PhantomData;
use codec::Encode;
use state_machine;
use runtime_primitives::traits::{Header as HeaderT, Hash, Block as BlockT, One, HashFor};
use runtime_primitives::generic::BlockId;
use runtime_api::BlockBuilder as BlockBuilderAPI;
use {backend, error, Client, CallExecutor};
use runtime_primitives::{ApplyResult, ApplyOutcome};
use runtime_primitives::ApplyOutcome;
use primitives::{Blake2Hasher};
use hash_db::Hasher;
/// Utility for building new (valid) blocks from a stream of extrinsics.
pub struct BlockBuilder<B, E, Block, H>
pub struct BlockBuilder<'a, B, E, Block, H>
where
B: backend::Backend<Block, H>,
E: CallExecutor<Block, H> + Clone,
B: backend::Backend<Block, H> + 'a,
E: CallExecutor<Block, H> + Clone + 'a,
Block: BlockT,
H: Hasher,
H::Out: Ord,
@@ -38,25 +40,26 @@ where
{
header: <Block as BlockT>::Header,
extrinsics: Vec<<Block as BlockT>::Extrinsic>,
executor: E,
state: B::State,
client: &'a Client<B, E, Block>,
block_id: BlockId<Block>,
changes: state_machine::OverlayedChanges,
_marker: PhantomData<H>,
}
impl<B, E, Block> BlockBuilder<B, E, Block, Blake2Hasher>
impl<'a, B, E, Block> BlockBuilder<'a, B, E, Block, Blake2Hasher>
where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher> + Clone,
B: backend::Backend<Block, Blake2Hasher> + 'a,
E: CallExecutor<Block, Blake2Hasher> + Clone + 'a,
Block: BlockT,
{
/// Create a new instance of builder from the given client, building on the latest block.
pub fn new(client: &Client<B, E, Block>) -> error::Result<Self> {
pub fn new(client: &'a Client<B, E, Block>) -> error::Result<Self> {
client.info().and_then(|i| Self::at_block(&BlockId::Hash(i.chain.best_hash), client))
}
/// Create a new instance of builder from the given client using a particular block's ID to
/// build upon.
pub fn at_block(block_id: &BlockId<Block>, client: &Client<B, E, Block>) -> error::Result<Self> {
pub fn at_block(block_id: &BlockId<Block>, client: &'a Client<B, E, Block>) -> error::Result<Self> {
let number = client.block_number_from_id(block_id)?
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", block_id)))?
+ One::one();
@@ -64,8 +67,6 @@ where
let parent_hash = client.block_hash_from_id(block_id)?
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", block_id)))?;
let executor = client.executor().clone();
let state = client.state_at(block_id)?;
let mut changes = Default::default();
let header = <<Block as BlockT>::Header as HeaderT>::new(
number,
@@ -75,15 +76,16 @@ where
Default::default()
);
executor.call_at_state(&state, &mut changes, "initialise_block", &header.encode(), native_when_possible())?;
client.initialise_block(block_id, &mut changes, &header)?;
changes.commit_prospective();
Ok(BlockBuilder {
header,
extrinsics: Vec::new(),
executor,
state,
client,
block_id: *block_id,
changes,
_marker: Default::default(),
})
}
@@ -91,22 +93,18 @@ where
/// can be validly executed (by executing it); if it is invalid, it'll be returned along with
/// the error. Otherwise, it will return a mutable reference to self (in order to chain).
pub fn push(&mut self, xt: <Block as BlockT>::Extrinsic) -> error::Result<()> {
match self.executor.call_at_state(&self.state, &mut self.changes, "apply_extrinsic", &xt.encode(), native_when_possible()) {
Ok((result, _, _)) => {
match ApplyResult::decode(&mut result.as_slice()) {
Some(Ok(ApplyOutcome::Success)) | Some(Ok(ApplyOutcome::Fail)) => {
match self.client.apply_extrinsic(&self.block_id, &mut self.changes, &xt) {
Ok(result) => {
match result {
Ok(ApplyOutcome::Success) | Ok(ApplyOutcome::Fail) => {
self.extrinsics.push(xt);
self.changes.commit_prospective();
Ok(())
}
Some(Err(e)) => {
Err(e) => {
self.changes.discard_prospective();
Err(error::ErrorKind::ApplyExtinsicFailed(e).into())
}
None => {
self.changes.discard_prospective();
Err(error::ErrorKind::CallResultDecode("apply_extrinsic").into())
}
}
}
Err(e) => {
@@ -118,15 +116,7 @@ where
/// Consume the builder to return a valid `Block` containing all pushed extrinsics.
pub fn bake(mut self) -> error::Result<Block> {
let (output, _, _) = self.executor.call_at_state(
&self.state,
&mut self.changes,
"finalise_block",
&[],
native_when_possible(),
)?;
self.header = <<Block as BlockT>::Header as Decode>::decode(&mut &output[..])
.expect("Header came straight out of runtime so must be valid");
self.header = self.client.finalise_block(&self.block_id, &mut self.changes)?;
debug_assert_eq!(
self.header.extrinsics_root().clone(),
+66 -45
View File
@@ -17,7 +17,7 @@
//! Substrate Client
use std::sync::Arc;
use error::Error;
use error::{Error, ErrorKind};
use futures::sync::mpsc;
use parking_lot::{Mutex, RwLock};
use primitives::AuthorityId;
@@ -32,7 +32,7 @@ use codec::{Encode, Decode};
use state_machine::{
Backend as StateBackend, CodeExecutor,
ExecutionStrategy, ExecutionManager, prove_read,
key_changes, key_changes_proof,
key_changes, key_changes_proof, OverlayedChanges
};
use backend::{self, BlockImportOperation};
@@ -441,37 +441,43 @@ impl<B, E, Block> Client<B, E, Block> where
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
Default::default()
);
self.state_at(&parent).and_then(|state| {
let mut overlay = Default::default();
let execution_manager = || match self.api_execution_strategy {
ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm,
ExecutionStrategy::Both => 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
}),
};
self.executor().call_at_state(
&state,
&mut overlay,
"initialise_block",
&header.encode(),
execution_manager()
)?;
let (r, _, _) = args.using_encoded(|input|
self.executor().call_at_state(
&state,
&mut overlay,
function,
input,
execution_manager()
))?;
Ok(R::decode(&mut &r[..])
.ok_or_else(|| error::Error::from(error::ErrorKind::CallResultDecode(function)))?)
})
let mut overlay = Default::default();
self.call_at_state(at, "initialise_block", &header, &mut overlay)?;
self.call_at_state(at, function, args, &mut overlay)
}
fn call_at_state<A: Encode, R: Decode>(
&self,
at: &BlockId<Block>,
function: &'static str,
args: &A,
changes: &mut OverlayedChanges
) -> error::Result<R> {
let state = self.state_at(at)?;
let execution_manager = || match self.api_execution_strategy {
ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm,
ExecutionStrategy::Both => 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
}),
};
self.executor.call_at_state(
&state,
changes,
function,
&args.encode(),
execution_manager()
).and_then(|res|
R::decode(&mut &res.0[..])
.ok_or_else(|| Error::from(ErrorKind::CallResultDecode(function)))
)
}
/// Check a header's justification.
@@ -1060,7 +1066,7 @@ impl<B, E, Block> api::Core<Block, AuthorityId> for Client<B, E, Block> where
bft::Authorities::authorities(self, at).map_err(Into::into)
}
fn execute_block(&self, at: &BlockId<Block>, block: Block) -> Result<(), Self::Error> {
fn execute_block(&self, at: &BlockId<Block>, block: &Block) -> Result<(), Self::Error> {
self.call_api_at(at, "execute_block", &(block))
}
}
@@ -1083,21 +1089,36 @@ impl<B, E, Block> api::BlockBuilder<Block> for Client<B, E, Block> where
Block: BlockT,
{
type Error = Error;
type OverlayedChanges = OverlayedChanges;
fn initialise_block(&self, at: &BlockId<Block>, header: <Block as BlockT>::Header) -> Result<(), Self::Error> {
self.call_api_at(at, "initialise_block", &(header))
fn initialise_block(
&self,
at: &BlockId<Block>,
changes: &mut OverlayedChanges,
header: &<Block as BlockT>::Header
) -> Result<(), Self::Error> {
self.call_at_state(at, "initialise_block", header, changes)
}
fn apply_extrinsic(&self, at: &BlockId<Block>, extrinsic: <Block as BlockT>::Extrinsic) -> Result<ApplyResult, Self::Error> {
self.call_api_at(at, "apply_extrinsic", &(extrinsic))
fn apply_extrinsic(
&self,
at: &BlockId<Block>,
changes: &mut OverlayedChanges,
extrinsic: &<Block as BlockT>::Extrinsic
) -> Result<ApplyResult, Self::Error> {
self.call_at_state(at, "apply_extrinsic", extrinsic, changes)
}
fn finalise_block(&self, at: &BlockId<Block>) -> Result<<Block as BlockT>::Header, Self::Error> {
self.call_api_at(at, "finalise_block", &())
fn finalise_block(
&self,
at: &BlockId<Block>,
changes: &mut OverlayedChanges
) -> Result<<Block as BlockT>::Header, Self::Error> {
self.call_at_state(at, "finalise_block", &(), changes)
}
fn inherent_extrinsics<InherentExtrinsic: Encode + Decode, UncheckedExtrinsic: Encode + Decode>(
&self, at: &BlockId<Block>, inherent: InherentExtrinsic
&self, at: &BlockId<Block>, inherent: &InherentExtrinsic
) -> Result<Vec<UncheckedExtrinsic>, Self::Error> {
self.call_api_at(at, "inherent_extrinsics", &(inherent))
}
@@ -1115,19 +1136,19 @@ impl<B, E, Block> api::OldTxQueue<Block> for Client<B, E, Block> where
type Error = Error;
fn account_nonce<AccountId: Encode + Decode, Index: Encode + Decode>(
&self, at: &BlockId<Block>, account: AccountId
&self, at: &BlockId<Block>, account: &AccountId
) -> Result<Index, Self::Error> {
self.call_api_at(at, "account_nonce", &(account))
}
fn lookup_address<Address: Encode + Decode, AccountId: Encode + Decode>(
&self, at: &BlockId<Block>, address: Address
&self, at: &BlockId<Block>, address: &Address
) -> Result<Option<AccountId>, Self::Error> {
self.call_api_at(at, "lookup_address", &(address))
}
}
impl<B, E, Block> api::NewTxQueue<Block> for Client<B, E, Block> where
impl<B, E, Block> api::TaggedTransactionQueue<Block> for Client<B, E, Block> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>,
Block: BlockT,
@@ -1135,7 +1156,7 @@ impl<B, E, Block> api::NewTxQueue<Block> for Client<B, E, Block> where
type Error = Error;
fn validate_transaction<TransactionValidity: Encode + Decode>(
&self, at: &BlockId<Block>, tx: <Block as BlockT>::Extrinsic
&self, at: &BlockId<Block>, tx: &<Block as BlockT>::Extrinsic
) -> Result<TransactionValidity, Self::Error> {
self.call_api_at(at, "validate_transaction", &(tx))
}