Skip to content

Commit

Permalink
Support authors api.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvc94ch committed Jul 1, 2020
1 parent 4265dd6 commit 1b84b38
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 9 deletions.
12 changes: 9 additions & 3 deletions client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ use jsonrpsee::{
};
use sc_network::config::TransportConfig;
pub use sc_service::{
config::DatabaseConfig,
config::{
DatabaseConfig,
KeystoreConfig,
},
Error as ServiceError,
};
use sc_service::{
config::{
KeystoreConfig,
NetworkConfiguration,
TaskType,
},
Expand Down Expand Up @@ -119,6 +121,8 @@ pub struct SubxtClientConfig<C: ChainSpec + 'static, S: AbstractService> {
pub copyright_start_year: i32,
/// Database configuration.
pub db: DatabaseConfig,
/// Keystore configuration.
pub keystore: KeystoreConfig,
/// Service builder.
pub builder: fn(Configuration) -> Result<S, sc_service::Error>,
/// Chain specification.
Expand Down Expand Up @@ -216,7 +220,7 @@ fn start_subxt_client<C: ChainSpec + 'static, S: AbstractService>(
})
.into(),
database: config.db,
keystore: KeystoreConfig::InMemory,
keystore: config.keystore,
max_runtime_instances: 8,
announce_block: true,
dev_key_seed: config.role.into(),
Expand Down Expand Up @@ -342,6 +346,7 @@ mod tests {
path: tmp.path().into(),
cache_size: 64,
},
keystore: KeystoreConfig::InMemory,
builder: test_node::service::new_light,
chain_spec,
role: Role::Light,
Expand Down Expand Up @@ -372,6 +377,7 @@ mod tests {
path: tmp.path().into(),
cache_size: 128,
},
keystore: KeystoreConfig::InMemory,
builder: test_node::service::new_full,
chain_spec: test_node::chain_spec::development_config(),
role: Role::Authority(AccountKeyring::Alice),
Expand Down
85 changes: 79 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ use codec::Decode;
use futures::future;
use jsonrpsee::client::Subscription;
use sc_rpc_api::state::ReadProof;
use sp_core::storage::{
StorageChangeSet,
StorageKey,
use sp_core::{
storage::{
StorageChangeSet,
StorageKey,
},
Bytes,
};
pub use sp_runtime::traits::SignedExtension;
use sp_version::RuntimeVersion;
Expand Down Expand Up @@ -425,6 +428,41 @@ impl<T: Runtime> Client<T> {
let decoder = self.events_decoder::<C>();
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
Expand Down Expand Up @@ -456,6 +494,7 @@ mod tests {
use sp_runtime::MultiSignature;
use substrate_subxt_client::{
DatabaseConfig,
KeystoreConfig,
Role,
SubxtClient,
SubxtClientConfig,
Expand All @@ -464,7 +503,9 @@ mod tests {

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();
let tmp = TempDir::new("subxt-").expect("failed to create tempdir");
let config = SubxtClientConfig {
Expand All @@ -473,12 +514,16 @@ mod tests {
author: "substrate subxt",
copyright_start_year: 2020,
db: DatabaseConfig::RocksDb {
path: tmp.path().into(),
path: tmp.path().join("db"),
cache_size: 128,
},
keystore: KeystoreConfig::Path {
path: tmp.path().join("keystore"),
password: None,
},
builder: test_node::service::new_full,
chain_spec: test_node::chain_spec::development_config(),
role: Role::Authority(AccountKeyring::Alice),
role: Role::Authority(key),
};
let client = ClientBuilder::new()
.set_client(SubxtClient::new(config).expect("Error creating subxt client"))
Expand All @@ -488,6 +533,34 @@ mod tests {
(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 fn test_tx_transfer_balance() {
let mut signer = PairSigner::new(AccountKeyring::Alice.pair());
Expand Down
47 changes: 47 additions & 0 deletions src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,53 @@ impl<T: Runtime> Rpc<T> {
}
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
Expand Down

0 comments on commit 1b84b38

Please sign in to comment.