Support authors api. (#134)

This commit is contained in:
David Craven
2020-07-01 16:27:14 +02:00
committed by GitHub
parent 4265dd6a69
commit c6350fcc11
3 changed files with 135 additions and 9 deletions
+9 -3
View File
@@ -43,12 +43,14 @@ use jsonrpsee::{
}; };
use sc_network::config::TransportConfig; use sc_network::config::TransportConfig;
pub use sc_service::{ pub use sc_service::{
config::DatabaseConfig, config::{
DatabaseConfig,
KeystoreConfig,
},
Error as ServiceError, Error as ServiceError,
}; };
use sc_service::{ use sc_service::{
config::{ config::{
KeystoreConfig,
NetworkConfiguration, NetworkConfiguration,
TaskType, TaskType,
}, },
@@ -119,6 +121,8 @@ pub struct SubxtClientConfig<C: ChainSpec + 'static, S: AbstractService> {
pub copyright_start_year: i32, pub copyright_start_year: i32,
/// Database configuration. /// Database configuration.
pub db: DatabaseConfig, pub db: DatabaseConfig,
/// Keystore configuration.
pub keystore: KeystoreConfig,
/// Service builder. /// Service builder.
pub builder: fn(Configuration) -> Result<S, sc_service::Error>, pub builder: fn(Configuration) -> Result<S, sc_service::Error>,
/// Chain specification. /// Chain specification.
@@ -216,7 +220,7 @@ fn start_subxt_client<C: ChainSpec + 'static, S: AbstractService>(
}) })
.into(), .into(),
database: config.db, database: config.db,
keystore: KeystoreConfig::InMemory, keystore: config.keystore,
max_runtime_instances: 8, max_runtime_instances: 8,
announce_block: true, announce_block: true,
dev_key_seed: config.role.into(), dev_key_seed: config.role.into(),
@@ -342,6 +346,7 @@ mod tests {
path: tmp.path().into(), path: tmp.path().into(),
cache_size: 64, cache_size: 64,
}, },
keystore: KeystoreConfig::InMemory,
builder: test_node::service::new_light, builder: test_node::service::new_light,
chain_spec, chain_spec,
role: Role::Light, role: Role::Light,
@@ -372,6 +377,7 @@ mod tests {
path: tmp.path().into(), path: tmp.path().into(),
cache_size: 128, cache_size: 128,
}, },
keystore: KeystoreConfig::InMemory,
builder: test_node::service::new_full, builder: test_node::service::new_full,
chain_spec: test_node::chain_spec::development_config(), chain_spec: test_node::chain_spec::development_config(),
role: Role::Authority(AccountKeyring::Alice), role: Role::Authority(AccountKeyring::Alice),
+79 -6
View File
@@ -52,9 +52,12 @@ use codec::Decode;
use futures::future; use futures::future;
use jsonrpsee::client::Subscription; use jsonrpsee::client::Subscription;
use sc_rpc_api::state::ReadProof; use sc_rpc_api::state::ReadProof;
use sp_core::storage::{ use sp_core::{
StorageChangeSet, storage::{
StorageKey, StorageChangeSet,
StorageKey,
},
Bytes,
}; };
pub use sp_runtime::traits::SignedExtension; pub use sp_runtime::traits::SignedExtension;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
@@ -425,6 +428,41 @@ impl<T: Runtime> Client<T> {
let decoder = self.events_decoder::<C>(); let decoder = self.events_decoder::<C>();
self.submit_and_watch_extrinsic(extrinsic, decoder).await self.submit_and_watch_extrinsic(extrinsic, decoder).await
} }
/// Insert a key into the keystore.
pub async fn insert_key(
&self,
key_type: String,
suri: String,
public: Bytes,
) -> Result<(), Error> {
self.rpc.insert_key(key_type, suri, public).await
}
/// Generate new session keys and returns the corresponding public keys.
pub async fn rotate_keys(&self) -> Result<Bytes, Error> {
self.rpc.rotate_keys().await
}
/// Checks if the keystore has private keys for the given session public keys.
///
/// `session_keys` is the SCALE encoded session keys object from the runtime.
///
/// Returns `true` iff all private keys could be found.
pub async fn has_session_keys(&self, session_keys: Bytes) -> Result<bool, Error> {
self.rpc.has_session_keys(session_keys).await
}
/// Checks if the keystore has private keys for the given public key and key type.
///
/// Returns `true` if a private key could be found.
pub async fn has_key(
&self,
public_key: Bytes,
key_type: String,
) -> Result<bool, Error> {
self.rpc.has_key(public_key, key_type).await
}
} }
/// Wraps an already encoded byte vector, prevents being encoded as a raw byte vector as part of /// Wraps an already encoded byte vector, prevents being encoded as a raw byte vector as part of
@@ -456,6 +494,7 @@ mod tests {
use sp_runtime::MultiSignature; use sp_runtime::MultiSignature;
use substrate_subxt_client::{ use substrate_subxt_client::{
DatabaseConfig, DatabaseConfig,
KeystoreConfig,
Role, Role,
SubxtClient, SubxtClient,
SubxtClientConfig, SubxtClientConfig,
@@ -464,7 +503,9 @@ mod tests {
pub(crate) type TestRuntime = crate::NodeTemplateRuntime; pub(crate) type TestRuntime = crate::NodeTemplateRuntime;
pub(crate) async fn test_client() -> (Client<TestRuntime>, TempDir) { pub(crate) async fn test_client_with(
key: AccountKeyring,
) -> (Client<TestRuntime>, TempDir) {
env_logger::try_init().ok(); env_logger::try_init().ok();
let tmp = TempDir::new("subxt-").expect("failed to create tempdir"); let tmp = TempDir::new("subxt-").expect("failed to create tempdir");
let config = SubxtClientConfig { let config = SubxtClientConfig {
@@ -473,12 +514,16 @@ mod tests {
author: "substrate subxt", author: "substrate subxt",
copyright_start_year: 2020, copyright_start_year: 2020,
db: DatabaseConfig::RocksDb { db: DatabaseConfig::RocksDb {
path: tmp.path().into(), path: tmp.path().join("db"),
cache_size: 128, cache_size: 128,
}, },
keystore: KeystoreConfig::Path {
path: tmp.path().join("keystore"),
password: None,
},
builder: test_node::service::new_full, builder: test_node::service::new_full,
chain_spec: test_node::chain_spec::development_config(), chain_spec: test_node::chain_spec::development_config(),
role: Role::Authority(AccountKeyring::Alice), role: Role::Authority(key),
}; };
let client = ClientBuilder::new() let client = ClientBuilder::new()
.set_client(SubxtClient::new(config).expect("Error creating subxt client")) .set_client(SubxtClient::new(config).expect("Error creating subxt client"))
@@ -488,6 +533,34 @@ mod tests {
(client, tmp) (client, tmp)
} }
pub(crate) async fn test_client() -> (Client<TestRuntime>, TempDir) {
test_client_with(AccountKeyring::Alice).await
}
#[async_std::test]
async fn test_insert_key() {
// Bob is not an authority, so block production should be disabled.
let (client, _tmp) = test_client_with(AccountKeyring::Bob).await;
let mut blocks = client.subscribe_blocks().await.unwrap();
// get the genesis block.
assert_eq!(blocks.next().await.number, 0);
let public = AccountKeyring::Alice.public().as_array_ref().to_vec();
client
.insert_key(
"aura".to_string(),
"//Alice".to_string(),
public.clone().into(),
)
.await
.unwrap();
assert!(client
.has_key(public.clone().into(), "aura".to_string())
.await
.unwrap());
// Alice is an authority, so blocks should be produced.
assert_eq!(blocks.next().await.number, 1);
}
#[async_std::test] #[async_std::test]
async fn test_tx_transfer_balance() { async fn test_tx_transfer_balance() {
let mut signer = PairSigner::new(AccountKeyring::Alice.pair()); let mut signer = PairSigner::new(AccountKeyring::Alice.pair());
+47
View File
@@ -396,6 +396,53 @@ impl<T: Runtime> Rpc<T> {
} }
unreachable!() unreachable!()
} }
/// Insert a key into the keystore.
pub async fn insert_key(
&self,
key_type: String,
suri: String,
public: Bytes,
) -> Result<(), Error> {
let params = Params::Array(vec![
to_json_value(key_type)?,
to_json_value(suri)?,
to_json_value(public)?,
]);
self.client.request("author_insertKey", params).await?;
Ok(())
}
/// Generate new session keys and returns the corresponding public keys.
pub async fn rotate_keys(&self) -> Result<Bytes, Error> {
Ok(self
.client
.request("author_rotateKeys", Params::None)
.await?)
}
/// Checks if the keystore has private keys for the given session public keys.
///
/// `session_keys` is the SCALE encoded session keys object from the runtime.
///
/// Returns `true` iff all private keys could be found.
pub async fn has_session_keys(&self, session_keys: Bytes) -> Result<bool, Error> {
let params = Params::Array(vec![to_json_value(session_keys)?]);
Ok(self.client.request("author_hasSessionKeys", params).await?)
}
/// Checks if the keystore has private keys for the given public key and key type.
///
/// Returns `true` if a private key could be found.
pub async fn has_key(
&self,
public_key: Bytes,
key_type: String,
) -> Result<bool, Error> {
let params =
Params::Array(vec![to_json_value(public_key)?, to_json_value(key_type)?]);
Ok(self.client.request("author_hasKey", params).await?)
}
} }
/// Captures data for when an extrinsic is successfully included in a block /// Captures data for when an extrinsic is successfully included in a block