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, SyncCryptoStore,
vrf::{VRFTranscriptData, VRFSignature, make_transcript}, 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}; use crate::{Result, Error};
@@ -57,6 +57,14 @@ impl LocalKeystore {
let inner = KeystoreInner::new_in_memory(); let inner = KeystoreInner::new_in_memory();
Self(RwLock::new(inner)) 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] #[async_trait]
@@ -470,6 +478,11 @@ impl KeystoreInner {
Ok(public_keys) 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 tempfile::TempDir;
use sp_core::{ use sp_core::{
Pair, Pair,
crypto::{IsWrappedBy, Ss58Codec}, crypto::Ss58Codec,
testing::SR25519, testing::SR25519,
}; };
use sp_application_crypto::{ed25519, sr25519, AppPublic, AppKey, AppPair}; use sp_application_crypto::{ed25519, sr25519, AppPublic};
use std::{ use std::{
fs, fs,
str::FromStr, str::FromStr,
}; };
/// Generate a new key. impl KeystoreInner {
/// fn insert_ephemeral_from_seed<Pair: AppPair>(&mut self, seed: &str) -> Result<Pair> {
/// Places it into the file system store. self.insert_ephemeral_from_seed_by_type::<Pair::Generic>(seed, Pair::ID).map(Into::into)
fn generate<Pair: AppPair>(store: &KeystoreInner) -> Result<Pair> { }
store.generate_by_type::<Pair::Generic>(Pair::ID).map(Into::into)
}
/// Create a new key from seed. fn public_keys<Public: AppPublic>(&self) -> Result<Vec<Public>> {
/// self.raw_public_keys(Public::ID)
/// Does not place it into the file system store. .map(|v| {
fn insert_ephemeral_from_seed<Pair: AppPair>(store: &mut KeystoreInner, seed: &str) -> Result<Pair> { v.into_iter()
store.insert_ephemeral_from_seed_by_type::<Pair::Generic>(seed, Pair::ID).map(Into::into) .map(|k| Public::from_slice(k.as_slice()))
} .collect()
})
}
/// Get public keys of all stored keys that match the key type. fn generate<Pair: AppPair>(&self) -> Result<Pair> {
/// self.generate_by_type::<Pair::Generic>(Pair::ID).map(Into::into)
/// 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)
} }
#[test] #[test]
@@ -527,14 +525,14 @@ mod tests {
let temp_dir = TempDir::new().unwrap(); let temp_dir = TempDir::new().unwrap();
let store = KeystoreInner::open(temp_dir.path(), None).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 key: ed25519::AppPair = store.generate().unwrap();
let key2: ed25519::AppPair = key_pair(&store, &key.public()).unwrap(); let key2: ed25519::AppPair = store.key_pair(&key.public()).unwrap();
assert_eq!(key.public(), key2.public()); 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] #[test]
@@ -542,8 +540,7 @@ mod tests {
let temp_dir = TempDir::new().unwrap(); let temp_dir = TempDir::new().unwrap();
let mut store = KeystoreInner::open(temp_dir.path(), None).unwrap(); let mut store = KeystoreInner::open(temp_dir.path(), None).unwrap();
let pair: ed25519::AppPair = insert_ephemeral_from_seed( let pair: ed25519::AppPair = store.insert_ephemeral_from_seed(
&mut store,
"0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc" "0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc"
).unwrap(); ).unwrap();
assert_eq!( assert_eq!(
@@ -554,7 +551,7 @@ mod tests {
drop(store); drop(store);
let store = KeystoreInner::open(temp_dir.path(), None).unwrap(); let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
// Keys generated from seed should not be persisted! // 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] #[test]
@@ -566,15 +563,15 @@ mod tests {
Some(FromStr::from_str(password.as_str()).unwrap()), Some(FromStr::from_str(password.as_str()).unwrap()),
).unwrap(); ).unwrap();
let pair: ed25519::AppPair = generate(&store).unwrap(); let pair: ed25519::AppPair = store.generate().unwrap();
assert_eq!( assert_eq!(
pair.public(), 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 // Without the password the key should not be retrievable
let store = KeystoreInner::open(temp_dir.path(), None).unwrap(); 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( let store = KeystoreInner::open(
temp_dir.path(), temp_dir.path(),
@@ -582,7 +579,7 @@ mod tests {
).unwrap(); ).unwrap();
assert_eq!( assert_eq!(
pair.public(), 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(); let mut keys = Vec::new();
for i in 0..10 { for i in 0..10 {
keys.push(generate::<ed25519::AppPair>(&store).unwrap().public()); keys.push(store.generate::<ed25519::AppPair>().unwrap().public());
keys.push(insert_ephemeral_from_seed::<ed25519::AppPair>( keys.push(store.insert_ephemeral_from_seed::<ed25519::AppPair>(
&mut store,
&format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i), &format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i),
).unwrap().public()); ).unwrap().public());
} }
// Generate a key of a different type // Generate a key of a different type
generate::<sr25519::AppPair>(&store).unwrap(); store.generate::<sr25519::AppPair>().unwrap();
keys.sort(); 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(); store_pubs.sort();
assert_eq!(keys, store_pubs); assert_eq!(keys, store_pubs);
+26 -11
View File
@@ -205,12 +205,13 @@ pub type TLightClientWithBackend<TBl, TRtApi, TExecDisp, TBackend> = Client<
TRtApi, TRtApi,
>; >;
/// Construct and hold different layers of Keystore wrappers enum KeystoreContainerInner {
pub struct KeystoreContainer { Local(Arc<LocalKeystore>)
keystore: Arc<dyn CryptoStore>,
sync_keystore: SyncCryptoStorePtr,
} }
/// Construct and hold different layers of Keystore wrappers
pub struct KeystoreContainer(KeystoreContainerInner);
impl KeystoreContainer { impl KeystoreContainer {
/// Construct KeystoreContainer /// Construct KeystoreContainer
pub fn new(config: &KeystoreConfig) -> Result<Self, Error> { pub fn new(config: &KeystoreConfig) -> Result<Self, Error> {
@@ -221,22 +222,36 @@ impl KeystoreContainer {
)?, )?,
KeystoreConfig::InMemory => LocalKeystore::in_memory(), KeystoreConfig::InMemory => LocalKeystore::in_memory(),
}); });
let sync_keystore = keystore.clone() as SyncCryptoStorePtr;
Ok(Self { Ok(Self(KeystoreContainerInner::Local(keystore)))
keystore,
sync_keystore,
})
} }
/// Returns an adapter to the asynchronous keystore that implements `CryptoStore` /// Returns an adapter to the asynchronous keystore that implements `CryptoStore`
pub fn keystore(&self) -> Arc<dyn 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 /// Returns the synchrnous keystore wrapper
pub fn sync_keystore(&self) -> SyncCryptoStorePtr { 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()),
}
} }
} }