Export app-crypto specific keystore functions (#7489)

* Export app-crypto specific keystore functions

* Also add back the insert function

* Switch KeystoreContainer to an enum

* Only export the bare minimal for LocalKeystore and fix service compile

* fix: should return Arc

* Add docs stating that functions only available in local keystore

* Remove insert and generate functions

* fix: generate function should be available in test

* Add keypair function to trait

* Revert "Add keypair function to trait"

This reverts commit ad921b09ca73d3c09298e3a51b562ef8e0067781.

* Add note for local_keystore function in service
This commit is contained in:
Wei Tang
2020-11-11 18:19:27 +01:00
committed by GitHub
parent 7cf78c166e
commit 2bd9486b0f
2 changed files with 71 additions and 60 deletions
+45 -49
View File
@@ -38,7 +38,7 @@ use sp_keystore::{
SyncCryptoStore,
vrf::{VRFTranscriptData, VRFSignature, make_transcript},
};
use sp_application_crypto::{ed25519, sr25519, ecdsa};
use sp_application_crypto::{ed25519, sr25519, ecdsa, AppPair, AppKey, IsWrappedBy};
use crate::{Result, Error};
@@ -57,6 +57,14 @@ impl LocalKeystore {
let inner = KeystoreInner::new_in_memory();
Self(RwLock::new(inner))
}
/// Get a key pair for the given public key.
///
/// This function is only available for a local keystore. If your application plans to work with
/// remote keystores, you do not want to depend on it.
pub fn key_pair<Pair: AppPair>(&self, public: &<Pair as AppKey>::Public) -> Result<Pair> {
self.0.read().key_pair::<Pair>(public)
}
}
#[async_trait]
@@ -470,6 +478,11 @@ impl KeystoreInner {
Ok(public_keys)
}
/// Get a key pair for the given public key.
pub fn key_pair<Pair: AppPair>(&self, public: &<Pair as AppKey>::Public) -> Result<Pair> {
self.key_pair_by_type::<Pair::Generic>(IsWrappedBy::from_ref(public), Pair::ID).map(Into::into)
}
}
@@ -479,47 +492,32 @@ mod tests {
use tempfile::TempDir;
use sp_core::{
Pair,
crypto::{IsWrappedBy, Ss58Codec},
crypto::Ss58Codec,
testing::SR25519,
};
use sp_application_crypto::{ed25519, sr25519, AppPublic, AppKey, AppPair};
use sp_application_crypto::{ed25519, sr25519, AppPublic};
use std::{
fs,
str::FromStr,
};
/// Generate a new key.
///
/// Places it into the file system store.
fn generate<Pair: AppPair>(store: &KeystoreInner) -> Result<Pair> {
store.generate_by_type::<Pair::Generic>(Pair::ID).map(Into::into)
}
impl KeystoreInner {
fn insert_ephemeral_from_seed<Pair: AppPair>(&mut self, seed: &str) -> Result<Pair> {
self.insert_ephemeral_from_seed_by_type::<Pair::Generic>(seed, Pair::ID).map(Into::into)
}
/// Create a new key from seed.
///
/// Does not place it into the file system store.
fn insert_ephemeral_from_seed<Pair: AppPair>(store: &mut KeystoreInner, seed: &str) -> Result<Pair> {
store.insert_ephemeral_from_seed_by_type::<Pair::Generic>(seed, Pair::ID).map(Into::into)
}
fn public_keys<Public: AppPublic>(&self) -> Result<Vec<Public>> {
self.raw_public_keys(Public::ID)
.map(|v| {
v.into_iter()
.map(|k| Public::from_slice(k.as_slice()))
.collect()
})
}
/// Get public keys of all stored keys that match the key type.
///
/// This will just use the type of the public key (a list of which to be returned) in order
/// to determine the key type. Unless you use a specialized application-type public key, then
/// this only give you keys registered under generic cryptography, and will not return keys
/// registered under the application type.
fn public_keys<Public: AppPublic>(store: &KeystoreInner) -> Result<Vec<Public>> {
store.raw_public_keys(Public::ID)
.map(|v| {
v.into_iter()
.map(|k| Public::from_slice(k.as_slice()))
.collect()
})
}
/// Get a key pair for the given public key.
fn key_pair<Pair: AppPair>(store: &KeystoreInner, public: &<Pair as AppKey>::Public) -> Result<Pair> {
store.key_pair_by_type::<Pair::Generic>(IsWrappedBy::from_ref(public), Pair::ID).map(Into::into)
fn generate<Pair: AppPair>(&self) -> Result<Pair> {
self.generate_by_type::<Pair::Generic>(Pair::ID).map(Into::into)
}
}
#[test]
@@ -527,14 +525,14 @@ mod tests {
let temp_dir = TempDir::new().unwrap();
let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
assert!(public_keys::<ed25519::AppPublic>(&store).unwrap().is_empty());
assert!(store.public_keys::<ed25519::AppPublic>().unwrap().is_empty());
let key: ed25519::AppPair = generate(&store).unwrap();
let key2: ed25519::AppPair = key_pair(&store, &key.public()).unwrap();
let key: ed25519::AppPair = store.generate().unwrap();
let key2: ed25519::AppPair = store.key_pair(&key.public()).unwrap();
assert_eq!(key.public(), key2.public());
assert_eq!(public_keys::<ed25519::AppPublic>(&store).unwrap()[0], key.public());
assert_eq!(store.public_keys::<ed25519::AppPublic>().unwrap()[0], key.public());
}
#[test]
@@ -542,8 +540,7 @@ mod tests {
let temp_dir = TempDir::new().unwrap();
let mut store = KeystoreInner::open(temp_dir.path(), None).unwrap();
let pair: ed25519::AppPair = insert_ephemeral_from_seed(
&mut store,
let pair: ed25519::AppPair = store.insert_ephemeral_from_seed(
"0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc"
).unwrap();
assert_eq!(
@@ -554,7 +551,7 @@ mod tests {
drop(store);
let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
// Keys generated from seed should not be persisted!
assert!(key_pair::<ed25519::AppPair>(&store, &pair.public()).is_err());
assert!(store.key_pair::<ed25519::AppPair>(&pair.public()).is_err());
}
#[test]
@@ -566,15 +563,15 @@ mod tests {
Some(FromStr::from_str(password.as_str()).unwrap()),
).unwrap();
let pair: ed25519::AppPair = generate(&store).unwrap();
let pair: ed25519::AppPair = store.generate().unwrap();
assert_eq!(
pair.public(),
key_pair::<ed25519::AppPair>(&store, &pair.public()).unwrap().public(),
store.key_pair::<ed25519::AppPair>(&pair.public()).unwrap().public(),
);
// Without the password the key should not be retrievable
let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
assert!(key_pair::<ed25519::AppPair>(&store, &pair.public()).is_err());
assert!(store.key_pair::<ed25519::AppPair>(&pair.public()).is_err());
let store = KeystoreInner::open(
temp_dir.path(),
@@ -582,7 +579,7 @@ mod tests {
).unwrap();
assert_eq!(
pair.public(),
key_pair::<ed25519::AppPair>(&store, &pair.public()).unwrap().public(),
store.key_pair::<ed25519::AppPair>(&pair.public()).unwrap().public(),
);
}
@@ -593,18 +590,17 @@ mod tests {
let mut keys = Vec::new();
for i in 0..10 {
keys.push(generate::<ed25519::AppPair>(&store).unwrap().public());
keys.push(insert_ephemeral_from_seed::<ed25519::AppPair>(
&mut store,
keys.push(store.generate::<ed25519::AppPair>().unwrap().public());
keys.push(store.insert_ephemeral_from_seed::<ed25519::AppPair>(
&format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i),
).unwrap().public());
}
// Generate a key of a different type
generate::<sr25519::AppPair>(&store).unwrap();
store.generate::<sr25519::AppPair>().unwrap();
keys.sort();
let mut store_pubs = public_keys::<ed25519::AppPublic>(&store).unwrap();
let mut store_pubs = store.public_keys::<ed25519::AppPublic>().unwrap();
store_pubs.sort();
assert_eq!(keys, store_pubs);
+26 -11
View File
@@ -205,12 +205,13 @@ pub type TLightClientWithBackend<TBl, TRtApi, TExecDisp, TBackend> = Client<
TRtApi,
>;
/// Construct and hold different layers of Keystore wrappers
pub struct KeystoreContainer {
keystore: Arc<dyn CryptoStore>,
sync_keystore: SyncCryptoStorePtr,
enum KeystoreContainerInner {
Local(Arc<LocalKeystore>)
}
/// Construct and hold different layers of Keystore wrappers
pub struct KeystoreContainer(KeystoreContainerInner);
impl KeystoreContainer {
/// Construct KeystoreContainer
pub fn new(config: &KeystoreConfig) -> Result<Self, Error> {
@@ -221,22 +222,36 @@ impl KeystoreContainer {
)?,
KeystoreConfig::InMemory => LocalKeystore::in_memory(),
});
let sync_keystore = keystore.clone() as SyncCryptoStorePtr;
Ok(Self {
keystore,
sync_keystore,
})
Ok(Self(KeystoreContainerInner::Local(keystore)))
}
/// Returns an adapter to the asynchronous keystore that implements `CryptoStore`
pub fn keystore(&self) -> Arc<dyn CryptoStore> {
self.keystore.clone()
match self.0 {
KeystoreContainerInner::Local(ref keystore) => keystore.clone(),
}
}
/// Returns the synchrnous keystore wrapper
pub fn sync_keystore(&self) -> SyncCryptoStorePtr {
self.sync_keystore.clone()
match self.0 {
KeystoreContainerInner::Local(ref keystore) => keystore.clone() as SyncCryptoStorePtr,
}
}
/// Returns the local keystore if available
///
/// The function will return None if the available keystore is not a local keystore.
///
/// # Note
///
/// Using the [`LocalKeystore`] will result in loosing the ability to use any other keystore implementation, like
/// a remote keystore for example. Only use this if you a certain that you require it!
pub fn local_keystore(&self) -> Option<Arc<LocalKeystore>> {
match self.0 {
KeystoreContainerInner::Local(ref keystore) => Some(keystore.clone()),
}
}
}