mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 19:51:05 +00:00
Make runtime api generate version and identifier information (#1226)
* Make `decl_runtime_apis!` implement `RuntimeApiInfo` for all runtime apis * Make the runtime side generate the info constants as well * Make `RuntimeApiInfo` implementation use the correct generics * Adds a test for the runtime api info stuff * Remove duplicated code by using block from `test-client` * Adds `compile_fail` tests for `api_version` * Adds documentation for `api_version` * Make `impl_runtime_apis!` generate `RUNTIME_API_VERSIONS` * Update documentation and tests for `RUNTIME_API_VERSIONS` * Implement `has_api` by using the `RuntimeApiInfo` * Make `impl_runtime_apis` check that trait identifiers are unique * Prefix all runtime api function with the corresponding trait So `execute_block` will be called `Core_execute_block`. This makes it possible to have traits implement a function with the same name. * Rebase master * Update after master rebase
This commit is contained in:
@@ -32,7 +32,7 @@ use runtime_primitives::traits::{
|
||||
ApiRef, ProvideRuntimeApi, Digest, DigestItem,
|
||||
};
|
||||
use runtime_primitives::BuildStorage;
|
||||
use runtime_api::{Core as CoreAPI, CallApiAt, TaggedTransactionQueue, ConstructRuntimeApi};
|
||||
use runtime_api::{Core as CoreAPI, CallRuntimeAt, TaggedTransactionQueue, ConstructRuntimeApi};
|
||||
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash};
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use primitives::storage::well_known_keys;
|
||||
@@ -288,7 +288,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
pub fn authorities_at(&self, id: &BlockId<Block>) -> error::Result<Vec<AuthorityId>> {
|
||||
match self.backend.blockchain().cache().and_then(|cache| cache.authorities_at(*id)) {
|
||||
Some(cached_value) => Ok(cached_value),
|
||||
None => self.executor.call(id, "authorities",&[])
|
||||
None => self.executor.call(id, "Core_authorities",&[])
|
||||
.and_then(|r| Vec::<AuthorityId>::decode(&mut &r.return_data[..])
|
||||
.ok_or(error::ErrorKind::InvalidAuthoritiesSet.into()))
|
||||
}
|
||||
@@ -635,7 +635,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
let mut r = self.executor.call_at_state(
|
||||
transaction_state,
|
||||
&mut overlay,
|
||||
"execute_block",
|
||||
"Core_execute_block",
|
||||
&<Block as BlockT>::new(import_headers.pre().clone(), body.clone().unwrap_or_default()).encode(),
|
||||
match (origin, self.block_execution_strategy) {
|
||||
(BlockOrigin::NetworkInitialSync, _) | (_, ExecutionStrategy::NativeWhenPossible) =>
|
||||
@@ -1034,7 +1034,7 @@ impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
||||
impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -1050,7 +1050,8 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
||||
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) {
|
||||
if function != "Core_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)?
|
||||
@@ -1062,12 +1063,16 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
|
||||
Default::default()
|
||||
);
|
||||
self.call_at_state(at, "initialise_block", header.encode(), changes)?;
|
||||
self.call_at_state(at, "Core_initialise_block", header.encode(), changes)?;
|
||||
*initialised_block = Some(*at);
|
||||
}
|
||||
|
||||
self.call_at_state(at, function, args, changes)
|
||||
}
|
||||
|
||||
fn runtime_version_at(&self, at: &BlockId<Block>) -> error::Result<RuntimeVersion> {
|
||||
self.runtime_version_at(at)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1238,7 +1243,7 @@ pub(crate) mod tests {
|
||||
use runtime_primitives::generic::DigestItem;
|
||||
use test_client::{self, TestClient};
|
||||
use consensus::BlockOrigin;
|
||||
use test_client::client::backend::Backend as TestBackend;
|
||||
use test_client::client::{backend::Backend as TestBackend, runtime_api::ApiExt};
|
||||
use test_client::BlockBuilderExt;
|
||||
use test_client::runtime::{self, Block, Transfer, RuntimeApi, test_api::TestAPI};
|
||||
|
||||
@@ -1335,6 +1340,17 @@ pub(crate) mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_api_has_test_api() {
|
||||
let client = test_client::new();
|
||||
|
||||
assert!(
|
||||
client.runtime_api().has_api::<TestAPI<Block>>(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authorities_call_works() {
|
||||
let client = test_client::new();
|
||||
|
||||
@@ -91,7 +91,7 @@ mod tests {
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"initialise_block",
|
||||
"Core_initialise_block",
|
||||
&header.encode(),
|
||||
ExecutionStrategy::NativeWhenPossible,
|
||||
).unwrap();
|
||||
@@ -102,7 +102,7 @@ mod tests {
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"apply_extrinsic",
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
&tx.encode(),
|
||||
ExecutionStrategy::NativeWhenPossible,
|
||||
).unwrap();
|
||||
@@ -113,7 +113,7 @@ mod tests {
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"finalise_block",
|
||||
"BlockBuilder_finalise_block",
|
||||
&[],
|
||||
ExecutionStrategy::NativeWhenPossible,
|
||||
).unwrap();
|
||||
@@ -157,7 +157,7 @@ mod tests {
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"execute_block",
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
ExecutionStrategy::NativeWhenPossible,
|
||||
).unwrap();
|
||||
@@ -182,7 +182,7 @@ mod tests {
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"execute_block",
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
ExecutionStrategy::AlwaysWasm,
|
||||
).unwrap();
|
||||
@@ -208,7 +208,7 @@ mod tests {
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
&mut overlay,
|
||||
&Executor::new(),
|
||||
"execute_block",
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
ExecutionStrategy::NativeWhenPossible,
|
||||
).unwrap();
|
||||
|
||||
@@ -166,7 +166,7 @@ mod tests {
|
||||
.unwrap().storage_root(::std::iter::empty()).0;
|
||||
|
||||
// 'fetch' execution proof from remote node
|
||||
let remote_execution_proof = remote_client.execution_proof(&remote_block_id, "authorities", &[]).unwrap().1;
|
||||
let remote_execution_proof = remote_client.execution_proof(&remote_block_id, "Core_authorities", &[]).unwrap().1;
|
||||
|
||||
// check remote execution proof locally
|
||||
let local_executor = test_client::LocalExecutor::new();
|
||||
@@ -179,7 +179,7 @@ mod tests {
|
||||
extrinsics_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
},
|
||||
method: "authorities".into(),
|
||||
method: "Core_authorities".into(),
|
||||
call_data: vec![],
|
||||
retry_count: None,
|
||||
}, remote_execution_proof).unwrap();
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
pub use state_machine::OverlayedChanges;
|
||||
#[doc(hidden)]
|
||||
pub use runtime_primitives::{
|
||||
traits::{Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef}, generic::BlockId,
|
||||
transaction_validity::TransactionValidity
|
||||
traits::{Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef, RuntimeApiInfo},
|
||||
generic::BlockId, transaction_validity::TransactionValidity
|
||||
};
|
||||
pub use runtime_version::{ApiId, RuntimeVersion};
|
||||
#[doc(hidden)]
|
||||
pub use rstd::slice;
|
||||
pub use runtime_version::{ApiId, RuntimeVersion, ApisVec, create_apis_vec};
|
||||
#[doc(hidden)]
|
||||
pub use rstd::{slice, mem};
|
||||
#[cfg(feature = "std")]
|
||||
use rstd::result;
|
||||
pub use codec::{Encode, Decode};
|
||||
@@ -38,14 +39,16 @@ use primitives::{AuthorityId, OpaqueMetadata};
|
||||
|
||||
/// Something that can be constructed to a runtime api.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait ConstructRuntimeApi<Block: BlockT>: Sized {
|
||||
pub trait ConstructRuntimeApi<Block: BlockT> {
|
||||
/// Construct an instance of the runtime api.
|
||||
fn construct_runtime_api<'a, T: CallApiAt<Block>>(call: &'a T) -> ApiRef<'a, Self>;
|
||||
fn construct_runtime_api<'a, T: CallRuntimeAt<Block>>(
|
||||
call: &'a T
|
||||
) -> ApiRef<'a, Self> where Self: Sized;
|
||||
}
|
||||
|
||||
/// An extension for the `RuntimeApi`.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait ApiExt {
|
||||
pub trait ApiExt<Block: BlockT> {
|
||||
/// The given closure will be called with api instance. Inside the closure any api call is
|
||||
/// allowed. After doing the api call, the closure is allowed to map the `Result` to a
|
||||
/// different `Result` type. This can be important, as the internal data structure that keeps
|
||||
@@ -54,12 +57,18 @@ pub trait ApiExt {
|
||||
fn map_api_result<F: FnOnce(&Self) -> result::Result<R, E>, R, E>(
|
||||
&self,
|
||||
map_call: F
|
||||
) -> result::Result<R, E>;
|
||||
) -> result::Result<R, E> where Self: Sized;
|
||||
|
||||
/// Checks if the given api is implemented and versions match.
|
||||
fn has_api<A: RuntimeApiInfo + ?Sized>(
|
||||
&self,
|
||||
at: &BlockId<Block>
|
||||
) -> error::Result<bool> where Self: Sized;
|
||||
}
|
||||
|
||||
/// Something that can call the runtime api at a given block.
|
||||
/// Something that can call into the runtime at a given block.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait CallApiAt<Block: BlockT> {
|
||||
pub trait CallRuntimeAt<Block: BlockT> {
|
||||
/// Calls the given api function with the given encoded arguments at the given block
|
||||
/// and returns the encoded result.
|
||||
fn call_api_at(
|
||||
@@ -71,43 +80,8 @@ pub trait CallApiAt<Block: BlockT> {
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
) -> error::Result<Vec<u8>>;
|
||||
|
||||
/// Call the given api function with strong arguments at the given block
|
||||
/// and returns the decoded result.
|
||||
fn call_api_at_strong<In: Encode, Out: Decode>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: &In,
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
) -> error::Result<Out> where Self: Sized {
|
||||
let raw = self.call_api_at(
|
||||
at,
|
||||
function,
|
||||
args.encode(),
|
||||
changes,
|
||||
initialised_block,
|
||||
)?;
|
||||
|
||||
match Out::decode(&mut &raw[..]) {
|
||||
Some(out) => Ok(out),
|
||||
None => bail!(error::ErrorKind::CallResultDecode(function)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ApiIds for the various standard runtime APIs.
|
||||
pub mod id {
|
||||
use super::ApiId;
|
||||
|
||||
/// ApiId for the BlockBuilder trait.
|
||||
pub const BLOCK_BUILDER: ApiId = *b"blkbuild";
|
||||
|
||||
/// ApiId for the TaggedTransactionQueue trait.
|
||||
pub const TAGGED_TRANSACTION_QUEUE: ApiId = *b"validatx";
|
||||
|
||||
/// ApiId for the Metadata trait.
|
||||
pub const METADATA: ApiId = *b"metadata";
|
||||
/// Returns the runtime version at the given block.
|
||||
fn runtime_version_at(&self, at: &BlockId<Block>) -> error::Result<RuntimeVersion>;
|
||||
}
|
||||
|
||||
decl_runtime_apis! {
|
||||
|
||||
Reference in New Issue
Block a user