mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 19:21:13 +00:00
Implement runtime api client side directly in the runtime (#1094)
* Move `initialise_block` into `Core` trait as it is crucial calling the API functions * Switch to first version of new runtime API implementation * Fixes bug in tests * Reenable asserts * Directly use the `TestAPI` in the tests * Start improving the api traits :100644 100644 898aadc7 49217199 M Cargo.lock :100644 10064461570436465ed664 M core/client/src/backend.rs :100644 100644 5d0c886b 64d710fd M core/client/src/block_builder.rs :100644 100644 c447855e 5ecbe474 M core/client/src/client.rs :100644 100644139cef13f90dbf3d M core/client/src/error.rs :100644 100644 2800c503 3298e66a M core/client/src/runtime_api.rs :100644 100644affa1c5c809b08bc M core/primitives/src/lib.rs :100644 1006442877dfa9d5547413 M core/sr-api/Cargo.toml :100644 100644 9a49784d 6a625a03 M core/sr-api/src/lib.rs :100644 100644 7c28e1c7 a1a444a9 M core/sr-primitives/src/traits.rs :100644 1006442e113ab6dcc01a6d M srml/metadata/Cargo.toml :100644 100644ea722a700809531aM srml/metadata/src/lib.rs * Refactoring * Move `sr-api` into client and more refactoring * Fixes tests * Some documentation and cleanup * Fixes compilation after rebase * More refactoring and more documentation * Makes `substrate-client` compilable on `wasm` On `wasm` it basically just exports the runtime api stuff. * Fixes grumbles * Updates wasm files after rebasing the master * Remove TODO comment * Remove whitespaces * Fixes after rebasing master * Another rebase, another fix commit
This commit is contained in:
+204
-232
@@ -16,8 +16,8 @@
|
||||
|
||||
//! Substrate Client
|
||||
|
||||
use std::sync::Arc;
|
||||
use error::{Error, ErrorKind};
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use error::Error;
|
||||
use futures::sync::mpsc;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use primitives::AuthorityId;
|
||||
@@ -27,25 +27,29 @@ use runtime_primitives::{
|
||||
transaction_validity::{TransactionValidity, TransactionTag},
|
||||
};
|
||||
use consensus::{ImportBlock, ImportResult, BlockOrigin};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash};
|
||||
use runtime_primitives::{ApplyResult, BuildStorage};
|
||||
use runtime_api as api;
|
||||
use runtime_primitives::traits::{
|
||||
Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash,
|
||||
ApiRef, ProvideRuntimeApi
|
||||
};
|
||||
use runtime_primitives::BuildStorage;
|
||||
use runtime_api::{Core as CoreAPI, CallApiAt, TaggedTransactionQueue, ConstructRuntimeApi};
|
||||
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash};
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use primitives::storage::well_known_keys;
|
||||
use codec::{Encode, Decode};
|
||||
use codec::Decode;
|
||||
use state_machine::{
|
||||
Backend as StateBackend, CodeExecutor,
|
||||
ExecutionStrategy, ExecutionManager, ChangesTrieAnchorBlockId,
|
||||
prove_read, key_changes, key_changes_proof, OverlayedChanges
|
||||
Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
|
||||
ExecutionStrategy, ExecutionManager, prove_read,
|
||||
key_changes, key_changes_proof, OverlayedChanges
|
||||
};
|
||||
use codec::Encode;
|
||||
|
||||
use backend::{self, BlockImportOperation};
|
||||
use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend};
|
||||
use call_executor::{CallExecutor, LocalCallExecutor};
|
||||
use executor::{RuntimeVersion, RuntimeInfo};
|
||||
use notifications::{StorageNotifications, StorageEventStream};
|
||||
use {cht, error, in_mem, block_builder, genesis, consensus};
|
||||
use {cht, error, in_mem, block_builder::{self, api::BlockBuilder as BlockBuilderAPI}, genesis, consensus};
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotification<Block>>;
|
||||
@@ -54,7 +58,7 @@ pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotific
|
||||
pub type FinalityNotifications<Block> = mpsc::UnboundedReceiver<FinalityNotification<Block>>;
|
||||
|
||||
/// Substrate Client
|
||||
pub struct Client<B, E, Block> where Block: BlockT {
|
||||
pub struct Client<B, E, Block, RA> where Block: BlockT {
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
storage_notifications: Mutex<StorageNotifications<Block>>,
|
||||
@@ -65,6 +69,7 @@ pub struct Client<B, E, Block> where Block: BlockT {
|
||||
block_execution_strategy: ExecutionStrategy,
|
||||
api_execution_strategy: ExecutionStrategy,
|
||||
changes_trie_config: Option<ChangesTrieConfiguration>,
|
||||
_phantom: PhantomData<RA>,
|
||||
}
|
||||
|
||||
/// A source of blockchain events.
|
||||
@@ -180,36 +185,36 @@ impl<H> PrePostHeader<H> {
|
||||
}
|
||||
|
||||
/// Create an instance of in-memory client.
|
||||
pub fn new_in_mem<E, Block, S>(
|
||||
pub fn new_in_mem<E, Block, S, RA>(
|
||||
executor: E,
|
||||
genesis_storage: S,
|
||||
) -> error::Result<Client<in_mem::Backend<Block, Blake2Hasher>, LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>, Block>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
) -> error::Result<Client<in_mem::Backend<Block, Blake2Hasher>, LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>, Block, RA>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage)
|
||||
}
|
||||
|
||||
/// Create a client with the explicitely provided backend.
|
||||
/// This is useful for testing backend implementations.
|
||||
pub fn new_with_backend<B, E, Block, S>(
|
||||
pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
build_genesis_storage: S,
|
||||
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
B: backend::LocalBackend<Block, Blake2Hasher>
|
||||
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block, RA>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
B: backend::LocalBackend<Block, Blake2Hasher>
|
||||
{
|
||||
let call_executor = LocalCallExecutor::new(backend.clone(), executor);
|
||||
Client::new(backend, call_executor, build_genesis_storage, ExecutionStrategy::NativeWhenPossible, ExecutionStrategy::NativeWhenPossible)
|
||||
}
|
||||
|
||||
impl<B, E, Block> Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -255,6 +260,7 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
block_execution_strategy,
|
||||
api_execution_strategy,
|
||||
changes_trie_config,
|
||||
_phantom: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -323,6 +329,36 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
self.header_proof_with_cht_size(id, cht::SIZE)
|
||||
}
|
||||
|
||||
pub(crate) fn call_at_state(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: Vec<u8>,
|
||||
changes: &mut OverlayedChanges
|
||||
) -> error::Result<Vec<u8>> {
|
||||
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, execution_manager())
|
||||
.map(|res| res.0)
|
||||
}
|
||||
|
||||
/// Get block hash by number.
|
||||
pub fn block_hash(&self, block_number: <<Block as BlockT>::Header as HeaderT>::Number) -> error::Result<Option<Block::Hash>> {
|
||||
self.backend.blockchain().hash(block_number)
|
||||
}
|
||||
|
||||
/// Reads given header and generates CHT-based header proof for CHT of given size.
|
||||
pub fn header_proof_with_cht_size(&self, id: &BlockId<Block>, cht_size: u64) -> error::Result<(Block::Header, Vec<Vec<u8>>)> {
|
||||
let proof_error = || error::ErrorKind::Backend(format!("Failed to generate header proof for {:?}", id));
|
||||
@@ -402,88 +438,41 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
|
||||
/// Create a new block, built on the head of the chain.
|
||||
pub fn new_block(&self) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
|
||||
where E: Clone
|
||||
pub fn new_block(
|
||||
&self
|
||||
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
|
||||
E: Clone + Send + Sync,
|
||||
RA: BlockBuilderAPI<Block>
|
||||
{
|
||||
block_builder::BlockBuilder::new(self)
|
||||
}
|
||||
|
||||
/// Create a new block, built on top of `parent`.
|
||||
pub fn new_block_at(&self, parent: &BlockId<Block>) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
|
||||
where E: Clone
|
||||
pub fn new_block_at(
|
||||
&self, parent: &BlockId<Block>
|
||||
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
|
||||
E: Clone + Send + Sync,
|
||||
RA: BlockBuilderAPI<Block>
|
||||
{
|
||||
block_builder::BlockBuilder::at_block(parent, &self)
|
||||
}
|
||||
|
||||
/// Set up the native execution environment to call into a native runtime code.
|
||||
pub fn call_api<A, R>(&self, function: &'static str, args: &A) -> error::Result<R>
|
||||
where A: Encode, R: Decode
|
||||
{
|
||||
self.call_api_at(&BlockId::Number(self.info()?.chain.best_number), function, args)
|
||||
}
|
||||
|
||||
/// Call a runtime function at given block.
|
||||
pub fn call_api_at<A, R>(&self, at: &BlockId<Block>, function: &'static str, args: &A) -> error::Result<R>
|
||||
where A: Encode, R: Decode
|
||||
{
|
||||
let parent = at;
|
||||
let header = <<Block as BlockT>::Header as HeaderT>::new(
|
||||
self.block_number_from_id(&parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))? + As::sa(1),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
self.block_hash_from_id(&parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
|
||||
Default::default()
|
||||
);
|
||||
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)))
|
||||
)
|
||||
}
|
||||
|
||||
// TODO [ToDr] Optimize and re-use tags from the pool.
|
||||
fn transaction_tags(&self, at: Block::Hash, body: &Option<Vec<Block::Extrinsic>>) -> error::Result<Vec<TransactionTag>> {
|
||||
fn transaction_tags(
|
||||
&self,
|
||||
at: Block::Hash,
|
||||
body: &Option<Vec<Block::Extrinsic>>
|
||||
) -> error::Result<Vec<TransactionTag>> where
|
||||
RA: TaggedTransactionQueue<Block>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
||||
{
|
||||
let id = BlockId::Hash(at);
|
||||
Ok(match body {
|
||||
None => vec![],
|
||||
Some(ref extrinsics) => {
|
||||
let mut tags = vec![];
|
||||
for tx in extrinsics {
|
||||
let tx = api::TaggedTransactionQueue::validate_transaction(self, &id, &tx)?;
|
||||
let tx = self.runtime_api().validate_transaction(&id, &tx)?;
|
||||
match tx {
|
||||
TransactionValidity::Valid { mut provides, .. } => {
|
||||
tags.append(&mut provides);
|
||||
@@ -508,7 +497,10 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
body: Option<Vec<Block::Extrinsic>>,
|
||||
authorities: Option<Vec<AuthorityId>>,
|
||||
finalized: bool,
|
||||
) -> error::Result<ImportResult> {
|
||||
) -> error::Result<ImportResult> where
|
||||
RA: TaggedTransactionQueue<Block>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
||||
{
|
||||
let parent_hash = import_headers.post().parent_hash().clone();
|
||||
match self.backend.blockchain().status(BlockId::Hash(hash))? {
|
||||
blockchain::BlockStatus::InChain => return Ok(ImportResult::AlreadyInChain),
|
||||
@@ -737,30 +729,9 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get block hash by number.
|
||||
pub fn block_hash(&self, block_number: <<Block as BlockT>::Header as HeaderT>::Number) -> error::Result<Option<Block::Hash>> {
|
||||
self.backend.blockchain().hash(block_number)
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash.
|
||||
pub fn block_hash_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<Block::Hash>> {
|
||||
match *id {
|
||||
BlockId::Hash(h) => Ok(Some(h)),
|
||||
BlockId::Number(n) => self.block_hash(n),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash.
|
||||
pub fn block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<NumberFor<Block>>> {
|
||||
match *id {
|
||||
BlockId::Hash(_) => Ok(self.header(id)?.map(|h| h.number().clone())),
|
||||
BlockId::Number(n) => Ok(Some(n)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash, returning error if the block is unknown.
|
||||
fn require_block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<NumberFor<Block>> {
|
||||
self.block_number_from_id(id)
|
||||
self.backend.blockchain().block_number_from_id(id)
|
||||
.and_then(|n| n.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", id)).into()))
|
||||
}
|
||||
|
||||
@@ -896,11 +867,87 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> ChainHeaderBackend<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: Send + Sync
|
||||
{
|
||||
fn header(&self, id: BlockId<Block>) -> error::Result<Option<Block::Header>> {
|
||||
self.backend.blockchain().header(id)
|
||||
}
|
||||
|
||||
fn info(&self) -> error::Result<blockchain::Info<Block>> {
|
||||
self.backend.blockchain().info()
|
||||
}
|
||||
|
||||
fn status(&self, id: BlockId<Block>) -> error::Result<blockchain::BlockStatus> {
|
||||
self.backend.blockchain().status(id)
|
||||
}
|
||||
|
||||
fn number(&self, hash: Block::Hash) -> error::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
|
||||
self.backend.blockchain().number(hash)
|
||||
}
|
||||
|
||||
fn hash(&self, number: NumberFor<Block>) -> error::Result<Option<Block::Hash>> {
|
||||
self.backend.blockchain().hash(number)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: CoreAPI<Block>
|
||||
{
|
||||
type Api = RA;
|
||||
|
||||
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
|
||||
Self::Api::construct_runtime_api(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: CoreAPI<Block>
|
||||
{
|
||||
fn call_api_at(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: Vec<u8>,
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
) -> error::Result<Vec<u8>> {
|
||||
//TODO: Find a better way to prevent double block initialization
|
||||
if function != "initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) {
|
||||
let parent = at;
|
||||
let header = <<Block as BlockT>::Header as HeaderT>::new(
|
||||
self.block_number_from_id(parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?
|
||||
+ As::sa(1),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
self.block_hash_from_id(&parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
|
||||
Default::default()
|
||||
);
|
||||
self.call_at_state(at, "initialise_block", header.encode(), changes)?;
|
||||
*initialised_block = Some(*at);
|
||||
}
|
||||
|
||||
self.call_at_state(at, function, args, changes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: TaggedTransactionQueue<Block>
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
@@ -963,7 +1010,7 @@ impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> consensus::Authorities<Block> for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> consensus::Authorities<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -974,7 +1021,7 @@ impl<B, E, Block> consensus::Authorities<Block> for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> CurrentHeight for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> CurrentHeight for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -985,7 +1032,7 @@ impl<B, E, Block> CurrentHeight for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> BlockNumberToHash for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -998,7 +1045,7 @@ impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block> BlockchainEvents<Block> for Client<B, E, Block>
|
||||
impl<B, E, Block, RA> BlockchainEvents<Block> for Client<B, E, Block, RA>
|
||||
where
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -1022,7 +1069,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> ChainHead<Block> for Client<B, E, Block>
|
||||
impl<B, E, Block, RA> ChainHead<Block> for Client<B, E, Block, RA>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
@@ -1033,116 +1080,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> BlockBody<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
impl<B, E, Block, RA> BlockBody<Block> for Client<B, E, Block, RA>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
fn block_body(&self, id: &BlockId<Block>) -> error::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
|
||||
self.body(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::Core<Block, AuthorityId> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, Self::Error> {
|
||||
self.call_api_at(at, "version", &())
|
||||
}
|
||||
|
||||
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, Self::Error> {
|
||||
self.authorities_at(at)
|
||||
}
|
||||
|
||||
fn execute_block(&self, at: &BlockId<Block>, block: &Block) -> Result<(), Self::Error> {
|
||||
self.call_api_at(at, "execute_block", &(block))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::Metadata<Block, Vec<u8>> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn metadata(&self, at: &BlockId<Block>) -> Result<Vec<u8>, Self::Error> {
|
||||
self.executor.call(at, "metadata",&[]).map(|v| v.return_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::BlockBuilder<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
type OverlayedChanges = OverlayedChanges;
|
||||
|
||||
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>,
|
||||
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>,
|
||||
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
|
||||
) -> Result<Vec<UncheckedExtrinsic>, Self::Error> {
|
||||
self.call_api_at(at, "inherent_extrinsics", &(inherent))
|
||||
}
|
||||
|
||||
fn check_inherents<InherentData: Encode + Decode, InherentError: Encode + Decode>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
block: &Block,
|
||||
data: &InherentData
|
||||
) -> Result<Result<(), InherentError>, Self::Error> {
|
||||
self.call_api_at(at, "check_inherents", &(block, data))
|
||||
}
|
||||
|
||||
fn random_seed(&self, at: &BlockId<Block>) -> Result<<Block as BlockT>::Hash, Self::Error> {
|
||||
self.call_api_at(at, "random_seed", &())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::TaggedTransactionQueue<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn validate_transaction<TransactionValidity: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>, tx: &<Block as BlockT>::Extrinsic
|
||||
) -> Result<TransactionValidity, Self::Error> {
|
||||
self.call_api_at(at, "validate_transaction", &(tx))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::collections::HashMap;
|
||||
@@ -1155,14 +1103,14 @@ pub(crate) mod tests {
|
||||
use consensus::BlockOrigin;
|
||||
use test_client::client::backend::Backend as TestBackend;
|
||||
use test_client::BlockBuilderExt;
|
||||
use test_client::runtime::{self, Block, Transfer};
|
||||
use test_client::runtime::{self, Block, Transfer, ClientWithApi, test_api::TestAPI};
|
||||
|
||||
/// Returns tuple, consisting of:
|
||||
/// 1) test client pre-filled with blocks changing balances;
|
||||
/// 2) roots of changes tries for these blocks
|
||||
/// 3) test cases in form (begin, end, key, vec![(block, extrinsic)]) that are required to pass
|
||||
pub fn prepare_client_with_key_changes() -> (
|
||||
test_client::client::Client<test_client::Backend, test_client::Executor, Block>,
|
||||
test_client::client::Client<test_client::Backend, test_client::Executor, Block, ClientWithApi>,
|
||||
Vec<H256>,
|
||||
Vec<(u64, u64, Vec<u8>, Vec<(u64, u32)>)>,
|
||||
) {
|
||||
@@ -1234,8 +1182,20 @@ pub(crate) mod tests {
|
||||
fn client_initialises_from_genesis_ok() {
|
||||
let client = test_client::new();
|
||||
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Alice.to_raw_public()).unwrap(), 1000);
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Ferdie.to_raw_public()).unwrap(), 0);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Alice.to_raw_public()
|
||||
).unwrap(),
|
||||
1000
|
||||
);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Ferdie.to_raw_public()
|
||||
).unwrap(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1278,8 +1238,20 @@ pub(crate) mod tests {
|
||||
|
||||
assert_eq!(client.info().unwrap().chain.best_number, 1);
|
||||
assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap());
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Alice.to_raw_public()).unwrap(), 958);
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Ferdie.to_raw_public()).unwrap(), 42);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Alice.to_raw_public()
|
||||
).unwrap(),
|
||||
958
|
||||
);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Ferdie.to_raw_public()
|
||||
).unwrap(),
|
||||
42
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user