mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 03:01:02 +00:00
Keystore overhaul (final) (#13683)
* Introduce keystore specialized sign methods * Get rid of 'AppKey::UntypedGeneric' associated type. Untyped generics are accessible using associated types 'Generic' associated type. I.e. <T as AppKey>::Public::Generic * Get rid of 'CryptoTypePublicPair' * Trivial fix * Small refactory of local keystore implementations * Remove 'crypto_id' method from 'Public' * Trivial rename of 'AppKey' to 'AppCrypto' * Remove unused import * Improve docs * Better signature related errors for authority-discovery * Apply review suggestion * Apply review suggestions Co-authored-by: Koute <koute@users.noreply.github.com> * Authority discoverty signing error revisited * Signing error revisited for babe and aura as well * Further cleanup --------- Co-authored-by: Koute <koute@users.noreply.github.com>
This commit is contained in:
@@ -18,8 +18,6 @@
|
||||
|
||||
//! Authority discovery errors.
|
||||
|
||||
use sp_core::crypto::CryptoTypePublicPair;
|
||||
|
||||
/// AuthorityDiscovery Result.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -59,11 +57,8 @@ pub enum Error {
|
||||
#[error("Failed to parse a libp2p key.")]
|
||||
ParsingLibp2pIdentity(#[from] libp2p::identity::error::DecodingError),
|
||||
|
||||
#[error("Failed to sign using a specific public key.")]
|
||||
MissingSignature(CryptoTypePublicPair),
|
||||
|
||||
#[error("Failed to sign using all public keys.")]
|
||||
Signing,
|
||||
#[error("Failed to sign: {0}.")]
|
||||
CannotSign(String),
|
||||
|
||||
#[error("Failed to register Prometheus metric.")]
|
||||
Prometheus(#[from] prometheus_endpoint::PrometheusError),
|
||||
|
||||
@@ -32,7 +32,7 @@ use std::{
|
||||
use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt};
|
||||
|
||||
use addr_cache::AddrCache;
|
||||
use codec::Decode;
|
||||
use codec::{Decode, Encode};
|
||||
use ip_network::IpNetwork;
|
||||
use libp2p::{
|
||||
core::multiaddr,
|
||||
@@ -43,6 +43,7 @@ use log::{debug, error, log_enabled};
|
||||
use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64};
|
||||
use prost::Message;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
use sc_network::{
|
||||
event::DhtEvent, KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature,
|
||||
};
|
||||
@@ -51,8 +52,7 @@ use sp_authority_discovery::{
|
||||
AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature,
|
||||
};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
|
||||
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
|
||||
use sp_core::crypto::{key_types, ByteArray, Pair};
|
||||
use sp_keystore::{Keystore, KeystorePtr};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
@@ -127,7 +127,7 @@ pub struct Worker<Client, Network, Block, DhtEventStream> {
|
||||
publish_if_changed_interval: ExpIncInterval,
|
||||
/// List of keys onto which addresses have been published at the latest publication.
|
||||
/// Used to check whether they have changed.
|
||||
latest_published_keys: HashSet<CryptoTypePublicPair>,
|
||||
latest_published_keys: HashSet<AuthorityId>,
|
||||
/// Same value as in the configuration.
|
||||
publish_non_global_ips: bool,
|
||||
/// Same value as in the configuration.
|
||||
@@ -339,7 +339,7 @@ where
|
||||
let keys = Worker::<Client, Network, Block, DhtEventStream>::get_own_public_keys_within_authority_set(
|
||||
key_store.clone(),
|
||||
self.client.as_ref(),
|
||||
).await?.into_iter().map(Into::into).collect::<HashSet<_>>();
|
||||
).await?.into_iter().collect::<HashSet<_>>();
|
||||
|
||||
if only_if_changed && keys == self.latest_published_keys {
|
||||
return Ok(())
|
||||
@@ -654,7 +654,7 @@ fn sign_record_with_peer_id(
|
||||
) -> Result<schema::PeerSignature> {
|
||||
let signature = network
|
||||
.sign_with_local_identity(serialized_record)
|
||||
.map_err(|_| Error::Signing)?;
|
||||
.map_err(|e| Error::CannotSign(format!("{} (network packet)", e)))?;
|
||||
let public_key = signature.public_key.to_protobuf_encoding();
|
||||
let signature = signature.bytes;
|
||||
Ok(schema::PeerSignature { signature, public_key })
|
||||
@@ -664,15 +664,20 @@ fn sign_record_with_authority_ids(
|
||||
serialized_record: Vec<u8>,
|
||||
peer_signature: Option<schema::PeerSignature>,
|
||||
key_store: &dyn Keystore,
|
||||
keys: Vec<CryptoTypePublicPair>,
|
||||
keys: Vec<AuthorityId>,
|
||||
) -> Result<Vec<(KademliaKey, Vec<u8>)>> {
|
||||
let mut result = Vec::with_capacity(keys.len());
|
||||
|
||||
for key in keys.iter() {
|
||||
let auth_signature = key_store
|
||||
.sign_with(key_types::AUTHORITY_DISCOVERY, key, &serialized_record)
|
||||
.map_err(|_| Error::Signing)?
|
||||
.ok_or_else(|| Error::MissingSignature(key.clone()))?;
|
||||
.sr25519_sign(key_types::AUTHORITY_DISCOVERY, key.as_ref(), &serialized_record)
|
||||
.map_err(|e| Error::CannotSign(format!("{}. Key: {:?}", e, key)))?
|
||||
.ok_or_else(|| {
|
||||
Error::CannotSign(format!("Could not find key in keystore. Key: {:?}", key))
|
||||
})?;
|
||||
|
||||
// Scale encode
|
||||
let auth_signature = auth_signature.encode();
|
||||
|
||||
let signed_record = schema::SignedAuthorityRecord {
|
||||
record: serialized_record.clone(),
|
||||
@@ -681,7 +686,7 @@ fn sign_record_with_authority_ids(
|
||||
}
|
||||
.encode_to_vec();
|
||||
|
||||
result.push((hash_authority_id(&key.1), signed_record));
|
||||
result.push((hash_authority_id(key.as_slice()), signed_record));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
|
||||
@@ -45,7 +45,7 @@ use sc_consensus_slots::{
|
||||
};
|
||||
use sc_telemetry::TelemetryHandle;
|
||||
use sp_api::{Core, ProvideRuntimeApi};
|
||||
use sp_application_crypto::{AppKey, AppPublic};
|
||||
use sp_application_crypto::{AppCrypto, AppPublic};
|
||||
use sp_blockchain::{HeaderBackend, Result as CResult};
|
||||
use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain};
|
||||
use sp_consensus_slots::Slot;
|
||||
@@ -205,7 +205,7 @@ pub fn start_aura<P, B, C, SC, I, PF, SO, L, CIDP, BS, Error>(
|
||||
telemetry,
|
||||
compatibility_mode,
|
||||
}: StartAuraParams<C, SC, I, PF, SO, L, CIDP, BS, NumberFor<B>>,
|
||||
) -> Result<impl Future<Output = ()>, sp_consensus::Error>
|
||||
) -> Result<impl Future<Output = ()>, ConsensusError>
|
||||
where
|
||||
P: Pair + Send + Sync,
|
||||
P::Public: AppPublic + Hash + Member + Encode + Decode,
|
||||
@@ -222,7 +222,7 @@ where
|
||||
CIDP: CreateInherentDataProviders<B, ()> + Send + 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt + Send,
|
||||
BS: BackoffAuthoringBlocksStrategy<NumberFor<B>> + Send + Sync + 'static,
|
||||
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
|
||||
Error: std::error::Error + Send + From<ConsensusError> + 'static,
|
||||
{
|
||||
let worker = build_aura_worker::<P, _, _, _, _, _, _, _, _>(BuildAuraWorkerParams {
|
||||
client,
|
||||
@@ -320,7 +320,7 @@ where
|
||||
P::Public: AppPublic + Hash + Member + Encode + Decode,
|
||||
P::Signature: TryFrom<Vec<u8>> + Hash + Member + Encode + Decode,
|
||||
I: BlockImport<B, Transaction = sp_api::TransactionFor<C, B>> + Send + Sync + 'static,
|
||||
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
|
||||
Error: std::error::Error + Send + From<ConsensusError> + 'static,
|
||||
SO: SyncOracle + Send + Sync + Clone,
|
||||
L: sc_consensus::JustificationSyncLink<B>,
|
||||
BS: BackoffAuthoringBlocksStrategy<NumberFor<B>> + Send + Sync + 'static,
|
||||
@@ -374,13 +374,13 @@ where
|
||||
SO: SyncOracle + Send + Clone + Sync,
|
||||
L: sc_consensus::JustificationSyncLink<B>,
|
||||
BS: BackoffAuthoringBlocksStrategy<NumberFor<B>> + Send + Sync + 'static,
|
||||
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
|
||||
Error: std::error::Error + Send + From<ConsensusError> + 'static,
|
||||
{
|
||||
type BlockImport = I;
|
||||
type SyncOracle = SO;
|
||||
type JustificationSyncLink = L;
|
||||
type CreateProposer =
|
||||
Pin<Box<dyn Future<Output = Result<E::Proposer, sp_consensus::Error>> + Send + 'static>>;
|
||||
Pin<Box<dyn Future<Output = Result<E::Proposer, ConsensusError>> + Send + 'static>>;
|
||||
type Proposer = E::Proposer;
|
||||
type Claim = P::Public;
|
||||
type AuxData = Vec<AuthorityId<P>>;
|
||||
@@ -393,11 +393,7 @@ where
|
||||
&mut self.block_import
|
||||
}
|
||||
|
||||
fn aux_data(
|
||||
&self,
|
||||
header: &B::Header,
|
||||
_slot: Slot,
|
||||
) -> Result<Self::AuxData, sp_consensus::Error> {
|
||||
fn aux_data(&self, header: &B::Header, _slot: Slot) -> Result<Self::AuxData, ConsensusError> {
|
||||
authorities(
|
||||
self.client.as_ref(),
|
||||
header.hash(),
|
||||
@@ -406,17 +402,17 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
fn authorities_len(&self, epoch_data: &Self::AuxData) -> Option<usize> {
|
||||
Some(epoch_data.len())
|
||||
fn authorities_len(&self, authorities: &Self::AuxData) -> Option<usize> {
|
||||
Some(authorities.len())
|
||||
}
|
||||
|
||||
async fn claim_slot(
|
||||
&self,
|
||||
_header: &B::Header,
|
||||
slot: Slot,
|
||||
epoch_data: &Self::AuxData,
|
||||
authorities: &Self::AuxData,
|
||||
) -> Option<Self::Claim> {
|
||||
let expected_author = slot_author::<P>(slot, epoch_data);
|
||||
let expected_author = slot_author::<P>(slot, authorities);
|
||||
expected_author.and_then(|p| {
|
||||
if self
|
||||
.keystore
|
||||
@@ -440,29 +436,30 @@ where
|
||||
body: Vec<B::Extrinsic>,
|
||||
storage_changes: StorageChanges<<Self::BlockImport as BlockImport<B>>::Transaction, B>,
|
||||
public: Self::Claim,
|
||||
_epoch: Self::AuxData,
|
||||
_authorities: Self::AuxData,
|
||||
) -> Result<
|
||||
sc_consensus::BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
|
||||
sp_consensus::Error,
|
||||
ConsensusError,
|
||||
> {
|
||||
// sign the pre-sealed hash of the block and then
|
||||
// add it to a digest item.
|
||||
let public_type_pair = public.to_public_crypto_pair();
|
||||
let public = public.to_raw_vec();
|
||||
let signature = self
|
||||
.keystore
|
||||
.sign_with(<AuthorityId<P> as AppKey>::ID, &public_type_pair, header_hash.as_ref())
|
||||
.map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))?
|
||||
.sign_with(
|
||||
<AuthorityId<P> as AppCrypto>::ID,
|
||||
<AuthorityId<P> as AppCrypto>::CRYPTO_ID,
|
||||
public.as_slice(),
|
||||
header_hash.as_ref(),
|
||||
)
|
||||
.map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))?
|
||||
.ok_or_else(|| {
|
||||
sp_consensus::Error::CannotSign(
|
||||
public.clone(),
|
||||
"Could not find key in keystore.".into(),
|
||||
)
|
||||
ConsensusError::CannotSign(format!(
|
||||
"Could not find key in keystore. Key: {:?}",
|
||||
public
|
||||
))
|
||||
})?;
|
||||
let signature = signature
|
||||
.clone()
|
||||
.try_into()
|
||||
.map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?;
|
||||
.map_err(|_| ConsensusError::InvalidSignature(signature, public.to_raw_vec()))?;
|
||||
|
||||
let signature_digest_item =
|
||||
<DigestItem as CompatibleDigestItem<P::Signature>>::aura_seal(signature);
|
||||
@@ -507,7 +504,7 @@ where
|
||||
fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer {
|
||||
self.env
|
||||
.init(block)
|
||||
.map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)))
|
||||
.map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
@@ -620,14 +617,14 @@ where
|
||||
Default::default(),
|
||||
),
|
||||
)
|
||||
.map_err(|_| sp_consensus::Error::InvalidAuthoritiesSet)?;
|
||||
.map_err(|_| ConsensusError::InvalidAuthoritiesSet)?;
|
||||
},
|
||||
}
|
||||
|
||||
runtime_api
|
||||
.authorities(parent_hash)
|
||||
.ok()
|
||||
.ok_or(sp_consensus::Error::InvalidAuthoritiesSet)
|
||||
.ok_or(ConsensusError::InvalidAuthoritiesSet)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -30,7 +30,7 @@ use sc_consensus_epochs::{descendent_query, Epoch as EpochT, SharedEpochChanges}
|
||||
use sc_rpc_api::DenyUnsafe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_application_crypto::AppCrypto;
|
||||
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
|
||||
use sp_consensus::{Error as ConsensusError, SelectChain};
|
||||
use sp_consensus_babe::{
|
||||
|
||||
@@ -22,7 +22,7 @@ use super::Epoch;
|
||||
use codec::Encode;
|
||||
use sc_consensus_epochs::Epoch as EpochT;
|
||||
use schnorrkel::{keys::PublicKey, vrf::VRFInOut};
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_application_crypto::AppCrypto;
|
||||
use sp_consensus_babe::{
|
||||
digests::{PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest},
|
||||
make_transcript, make_transcript_data, AuthorityId, BabeAuthorityWeight, Slot, BABE_VRF_PREFIX,
|
||||
|
||||
@@ -108,7 +108,7 @@ use sc_consensus_slots::{
|
||||
};
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE};
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_application_crypto::AppCrypto;
|
||||
use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||
use sp_blockchain::{
|
||||
Backend as _, BlockStatus, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata,
|
||||
@@ -117,7 +117,7 @@ use sp_blockchain::{
|
||||
use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain};
|
||||
use sp_consensus_babe::inherents::BabeInherentData;
|
||||
use sp_consensus_slots::Slot;
|
||||
use sp_core::{crypto::ByteArray, ExecutionContext};
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
|
||||
use sp_keystore::KeystorePtr;
|
||||
use sp_runtime::{
|
||||
@@ -274,7 +274,7 @@ pub enum Error<B: BlockT> {
|
||||
MultipleConfigChangeDigests,
|
||||
/// Could not extract timestamp and slot
|
||||
#[error("Could not extract timestamp and slot: {0}")]
|
||||
Extraction(sp_consensus::Error),
|
||||
Extraction(ConsensusError),
|
||||
/// Could not fetch epoch
|
||||
#[error("Could not fetch epoch at {0:?}")]
|
||||
FetchEpoch(B::Hash),
|
||||
@@ -471,7 +471,7 @@ pub fn start_babe<B, C, SC, E, I, SO, CIDP, BS, L, Error>(
|
||||
max_block_proposal_slot_portion,
|
||||
telemetry,
|
||||
}: BabeParams<B, C, SC, E, I, SO, L, CIDP, BS>,
|
||||
) -> Result<BabeWorker<B>, sp_consensus::Error>
|
||||
) -> Result<BabeWorker<B>, ConsensusError>
|
||||
where
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi<B>
|
||||
@@ -739,7 +739,7 @@ where
|
||||
type SyncOracle = SO;
|
||||
type JustificationSyncLink = L;
|
||||
type CreateProposer =
|
||||
Pin<Box<dyn Future<Output = Result<E::Proposer, sp_consensus::Error>> + Send + 'static>>;
|
||||
Pin<Box<dyn Future<Output = Result<E::Proposer, ConsensusError>> + Send + 'static>>;
|
||||
type Proposer = E::Proposer;
|
||||
type BlockImport = I;
|
||||
type AuxData = ViableEpochDescriptor<B::Hash, NumberFor<B>, Epoch>;
|
||||
@@ -762,7 +762,7 @@ where
|
||||
slot,
|
||||
)
|
||||
.map_err(|e| ConsensusError::ChainLookup(e.to_string()))?
|
||||
.ok_or(sp_consensus::Error::InvalidAuthoritiesSet)
|
||||
.ok_or(ConsensusError::InvalidAuthoritiesSet)
|
||||
}
|
||||
|
||||
fn authorities_len(&self, epoch_descriptor: &Self::AuxData) -> Option<usize> {
|
||||
@@ -827,28 +827,21 @@ where
|
||||
(_, public): Self::Claim,
|
||||
epoch_descriptor: Self::AuxData,
|
||||
) -> Result<
|
||||
sc_consensus::BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
|
||||
sp_consensus::Error,
|
||||
BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
|
||||
ConsensusError,
|
||||
> {
|
||||
// sign the pre-sealed hash of the block and then
|
||||
// add it to a digest item.
|
||||
let public_type_pair = public.clone().into();
|
||||
let public = public.to_raw_vec();
|
||||
let signature = self
|
||||
.keystore
|
||||
.sign_with(<AuthorityId as AppKey>::ID, &public_type_pair, header_hash.as_ref())
|
||||
.map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))?
|
||||
.sr25519_sign(<AuthorityId as AppCrypto>::ID, public.as_ref(), header_hash.as_ref())
|
||||
.map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))?
|
||||
.ok_or_else(|| {
|
||||
sp_consensus::Error::CannotSign(
|
||||
public.clone(),
|
||||
"Could not find key in keystore.".into(),
|
||||
)
|
||||
ConsensusError::CannotSign(format!(
|
||||
"Could not find key in keystore. Key: {:?}",
|
||||
public
|
||||
))
|
||||
})?;
|
||||
let signature: AuthoritySignature = signature
|
||||
.clone()
|
||||
.try_into()
|
||||
.map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?;
|
||||
let digest_item = <DigestItem as CompatibleDigestItem>::babe_seal(signature);
|
||||
|
||||
let digest_item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
|
||||
|
||||
let mut import_block = BlockImportParams::new(BlockOrigin::Own, header);
|
||||
import_block.post_digests.push(digest_item);
|
||||
@@ -891,11 +884,7 @@ where
|
||||
}
|
||||
|
||||
fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer {
|
||||
Box::pin(
|
||||
self.env
|
||||
.init(block)
|
||||
.map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e))),
|
||||
)
|
||||
Box::pin(self.env.init(block).map_err(|e| ConsensusError::ClientImport(e.to_string())))
|
||||
}
|
||||
|
||||
fn telemetry(&self) -> Option<TelemetryHandle> {
|
||||
@@ -1182,7 +1171,7 @@ where
|
||||
.create_inherent_data_providers
|
||||
.create_inherent_data_providers(parent_hash, ())
|
||||
.await
|
||||
.map_err(|e| Error::<Block>::Client(sp_consensus::Error::from(e).into()))?;
|
||||
.map_err(|e| Error::<Block>::Client(ConsensusError::from(e).into()))?;
|
||||
|
||||
let slot_now = create_inherent_data_providers.slot();
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ use sc_network::types::ProtocolName;
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
|
||||
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_application_crypto::AppCrypto;
|
||||
use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult};
|
||||
use sp_consensus::SelectChain;
|
||||
use sp_consensus_grandpa::{
|
||||
|
||||
@@ -150,7 +150,7 @@ pub trait SimpleSlotWorker<B: BlockT> {
|
||||
body: Vec<B::Extrinsic>,
|
||||
storage_changes: StorageChanges<<Self::BlockImport as BlockImport<B>>::Transaction, B>,
|
||||
public: Self::Claim,
|
||||
epoch: Self::AuxData,
|
||||
aux_data: Self::AuxData,
|
||||
) -> Result<
|
||||
sc_consensus::BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
|
||||
sp_consensus::Error,
|
||||
|
||||
@@ -18,13 +18,10 @@
|
||||
//! Local keystore implementation
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use sp_application_crypto::{ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy};
|
||||
use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy};
|
||||
use sp_core::{
|
||||
crypto::{
|
||||
ByteArray, CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, SecretString,
|
||||
},
|
||||
sr25519::{Pair as Sr25519Pair, Public as Sr25519Public},
|
||||
Encode,
|
||||
crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString},
|
||||
ecdsa, ed25519, sr25519,
|
||||
};
|
||||
use sp_keystore::{
|
||||
vrf::{make_transcript, VRFSignature, VRFTranscriptData},
|
||||
@@ -62,67 +59,13 @@ impl LocalKeystore {
|
||||
/// `Err(_)` when something failed.
|
||||
pub fn key_pair<Pair: AppPair>(
|
||||
&self,
|
||||
public: &<Pair as AppKey>::Public,
|
||||
public: &<Pair as AppCrypto>::Public,
|
||||
) -> Result<Option<Pair>> {
|
||||
self.0.read().key_pair::<Pair>(public)
|
||||
}
|
||||
}
|
||||
|
||||
impl Keystore for LocalKeystore {
|
||||
fn keys(&self, id: KeyTypeId) -> std::result::Result<Vec<CryptoTypePublicPair>, TraitError> {
|
||||
let raw_keys = self.0.read().raw_public_keys(id)?;
|
||||
Ok(raw_keys.into_iter().fold(Vec::new(), |mut v, k| {
|
||||
v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone()));
|
||||
v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone()));
|
||||
v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k));
|
||||
v
|
||||
}))
|
||||
}
|
||||
|
||||
fn sign_with(
|
||||
&self,
|
||||
id: KeyTypeId,
|
||||
key: &CryptoTypePublicPair,
|
||||
msg: &[u8],
|
||||
) -> std::result::Result<Option<Vec<u8>>, TraitError> {
|
||||
match key.0 {
|
||||
ed25519::CRYPTO_ID => {
|
||||
let pub_key = ed25519::Public::from_slice(key.1.as_slice()).map_err(|()| {
|
||||
TraitError::Other("Corrupted public key - Invalid size".into())
|
||||
})?;
|
||||
let key_pair = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<ed25519::Pair>(&pub_key, id)
|
||||
.map_err(TraitError::from)?;
|
||||
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
|
||||
},
|
||||
sr25519::CRYPTO_ID => {
|
||||
let pub_key = sr25519::Public::from_slice(key.1.as_slice()).map_err(|()| {
|
||||
TraitError::Other("Corrupted public key - Invalid size".into())
|
||||
})?;
|
||||
let key_pair = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<sr25519::Pair>(&pub_key, id)
|
||||
.map_err(TraitError::from)?;
|
||||
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
|
||||
},
|
||||
ecdsa::CRYPTO_ID => {
|
||||
let pub_key = ecdsa::Public::from_slice(key.1.as_slice()).map_err(|()| {
|
||||
TraitError::Other("Corrupted public key - Invalid size".into())
|
||||
})?;
|
||||
let key_pair = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<ecdsa::Pair>(&pub_key, id)
|
||||
.map_err(TraitError::from)?;
|
||||
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
|
||||
},
|
||||
_ => Err(TraitError::KeyNotSupported(id)),
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
self.0
|
||||
.read()
|
||||
@@ -140,19 +83,49 @@ impl Keystore for LocalKeystore {
|
||||
/// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory.
|
||||
fn sr25519_generate_new(
|
||||
&self,
|
||||
id: KeyTypeId,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> std::result::Result<sr25519::Public, TraitError> {
|
||||
let pair = match seed {
|
||||
Some(seed) =>
|
||||
self.0.write().insert_ephemeral_from_seed_by_type::<sr25519::Pair>(seed, id),
|
||||
None => self.0.write().generate_by_type::<sr25519::Pair>(id),
|
||||
Some(seed) => self
|
||||
.0
|
||||
.write()
|
||||
.insert_ephemeral_from_seed_by_type::<sr25519::Pair>(seed, key_type),
|
||||
None => self.0.write().generate_by_type::<sr25519::Pair>(key_type),
|
||||
}
|
||||
.map_err(|e| -> TraitError { e.into() })?;
|
||||
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn sr25519_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &sr25519::Public,
|
||||
msg: &[u8],
|
||||
) -> std::result::Result<Option<sr25519::Signature>, TraitError> {
|
||||
let res = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<sr25519::Pair>(public, key_type)?
|
||||
.map(|pair| pair.sign(msg));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn sr25519_vrf_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &sr25519::Public,
|
||||
transcript_data: VRFTranscriptData,
|
||||
) -> std::result::Result<Option<VRFSignature>, TraitError> {
|
||||
let res = self.0.read().key_pair_by_type::<sr25519::Pair>(public, key_type)?.map(|pair| {
|
||||
let transcript = make_transcript(transcript_data);
|
||||
let (inout, proof, _) = pair.as_ref().vrf_sign(transcript);
|
||||
VRFSignature { output: inout.to_output(), proof }
|
||||
});
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
self.0
|
||||
.read()
|
||||
@@ -170,19 +143,35 @@ impl Keystore for LocalKeystore {
|
||||
/// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory.
|
||||
fn ed25519_generate_new(
|
||||
&self,
|
||||
id: KeyTypeId,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> std::result::Result<ed25519::Public, TraitError> {
|
||||
let pair = match seed {
|
||||
Some(seed) =>
|
||||
self.0.write().insert_ephemeral_from_seed_by_type::<ed25519::Pair>(seed, id),
|
||||
None => self.0.write().generate_by_type::<ed25519::Pair>(id),
|
||||
Some(seed) => self
|
||||
.0
|
||||
.write()
|
||||
.insert_ephemeral_from_seed_by_type::<ed25519::Pair>(seed, key_type),
|
||||
None => self.0.write().generate_by_type::<ed25519::Pair>(key_type),
|
||||
}
|
||||
.map_err(|e| -> TraitError { e.into() })?;
|
||||
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn ed25519_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &ed25519::Public,
|
||||
msg: &[u8],
|
||||
) -> std::result::Result<Option<ed25519::Signature>, TraitError> {
|
||||
let res = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<ed25519::Pair>(public, key_type)?
|
||||
.map(|pair| pair.sign(msg));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public> {
|
||||
self.0
|
||||
.read()
|
||||
@@ -200,19 +189,47 @@ impl Keystore for LocalKeystore {
|
||||
/// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory.
|
||||
fn ecdsa_generate_new(
|
||||
&self,
|
||||
id: KeyTypeId,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> std::result::Result<ecdsa::Public, TraitError> {
|
||||
let pair = match seed {
|
||||
Some(seed) =>
|
||||
self.0.write().insert_ephemeral_from_seed_by_type::<ecdsa::Pair>(seed, id),
|
||||
None => self.0.write().generate_by_type::<ecdsa::Pair>(id),
|
||||
self.0.write().insert_ephemeral_from_seed_by_type::<ecdsa::Pair>(seed, key_type),
|
||||
None => self.0.write().generate_by_type::<ecdsa::Pair>(key_type),
|
||||
}
|
||||
.map_err(|e| -> TraitError { e.into() })?;
|
||||
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn ecdsa_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &ecdsa::Public,
|
||||
msg: &[u8],
|
||||
) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
|
||||
let res = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<ecdsa::Pair>(public, key_type)?
|
||||
.map(|pair| pair.sign(msg));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn ecdsa_sign_prehashed(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &ecdsa::Public,
|
||||
msg: &[u8; 32],
|
||||
) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
|
||||
let res = self
|
||||
.0
|
||||
.read()
|
||||
.key_pair_by_type::<ecdsa::Pair>(public, key_type)?
|
||||
.map(|pair| pair.sign_prehashed(msg));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn insert(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
@@ -222,39 +239,15 @@ impl Keystore for LocalKeystore {
|
||||
self.0.write().insert(key_type, suri, public).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn keys(&self, key_type: KeyTypeId) -> std::result::Result<Vec<Vec<u8>>, TraitError> {
|
||||
self.0.read().raw_public_keys(key_type).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
|
||||
public_keys
|
||||
.iter()
|
||||
.all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some())
|
||||
}
|
||||
|
||||
fn sr25519_vrf_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &Sr25519Public,
|
||||
transcript_data: VRFTranscriptData,
|
||||
) -> std::result::Result<Option<VRFSignature>, TraitError> {
|
||||
let transcript = make_transcript(transcript_data);
|
||||
let pair = self.0.read().key_pair_by_type::<Sr25519Pair>(public, key_type)?;
|
||||
|
||||
if let Some(pair) = pair {
|
||||
let (inout, proof, _) = pair.as_ref().vrf_sign(transcript);
|
||||
Ok(Some(VRFSignature { output: inout.to_output(), proof }))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn ecdsa_sign_prehashed(
|
||||
&self,
|
||||
id: KeyTypeId,
|
||||
public: &ecdsa::Public,
|
||||
msg: &[u8; 32],
|
||||
) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
|
||||
let pair = self.0.read().key_pair_by_type::<ecdsa::Pair>(public, id)?;
|
||||
|
||||
pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<KeystorePtr> for LocalKeystore {
|
||||
@@ -305,7 +298,12 @@ impl KeystoreInner {
|
||||
/// Insert the given public/private key pair with the given key type.
|
||||
///
|
||||
/// Does not place it into the file system store.
|
||||
fn insert_ephemeral_pair<Pair: PairT>(&mut self, pair: &Pair, seed: &str, key_type: KeyTypeId) {
|
||||
fn insert_ephemeral_pair<Pair: CorePair>(
|
||||
&mut self,
|
||||
pair: &Pair,
|
||||
seed: &str,
|
||||
key_type: KeyTypeId,
|
||||
) {
|
||||
let key = (key_type, pair.public().to_raw_vec());
|
||||
self.additional.insert(key, seed.into());
|
||||
}
|
||||
@@ -325,7 +323,7 @@ impl KeystoreInner {
|
||||
///
|
||||
/// Places it into the file system store, if a path is configured. Otherwise insert
|
||||
/// it into the memory cache only.
|
||||
fn generate_by_type<Pair: PairT>(&mut self, key_type: KeyTypeId) -> Result<Pair> {
|
||||
fn generate_by_type<Pair: CorePair>(&mut self, key_type: KeyTypeId) -> Result<Pair> {
|
||||
let (pair, phrase, _) = Pair::generate_with_phrase(self.password());
|
||||
if let Some(path) = self.key_file_path(pair.public().as_slice(), key_type) {
|
||||
Self::write_to_file(path, &phrase)?;
|
||||
@@ -354,7 +352,7 @@ impl KeystoreInner {
|
||||
/// Create a new key from seed.
|
||||
///
|
||||
/// Does not place it into the file system store.
|
||||
fn insert_ephemeral_from_seed_by_type<Pair: PairT>(
|
||||
fn insert_ephemeral_from_seed_by_type<Pair: CorePair>(
|
||||
&mut self,
|
||||
seed: &str,
|
||||
key_type: KeyTypeId,
|
||||
@@ -386,7 +384,7 @@ impl KeystoreInner {
|
||||
}
|
||||
|
||||
/// Get a key pair for the given public key and key type.
|
||||
fn key_pair_by_type<Pair: PairT>(
|
||||
fn key_pair_by_type<Pair: CorePair>(
|
||||
&self,
|
||||
public: &Pair::Public,
|
||||
key_type: KeyTypeId,
|
||||
@@ -418,12 +416,12 @@ impl KeystoreInner {
|
||||
}
|
||||
|
||||
/// Returns a list of raw public keys filtered by `KeyTypeId`
|
||||
fn raw_public_keys(&self, id: KeyTypeId) -> Result<Vec<Vec<u8>>> {
|
||||
fn raw_public_keys(&self, key_type: KeyTypeId) -> Result<Vec<Vec<u8>>> {
|
||||
let mut public_keys: Vec<Vec<u8>> = self
|
||||
.additional
|
||||
.keys()
|
||||
.into_iter()
|
||||
.filter_map(|k| if k.0 == id { Some(k.1.clone()) } else { None })
|
||||
.filter_map(|k| if k.0 == key_type { Some(k.1.clone()) } else { None })
|
||||
.collect();
|
||||
|
||||
if let Some(path) = &self.path {
|
||||
@@ -435,7 +433,7 @@ impl KeystoreInner {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
match array_bytes::hex2bytes(name) {
|
||||
Ok(ref hex) if hex.len() > 4 => {
|
||||
if hex[0..4] != id.0 {
|
||||
if hex[0..4] != key_type.0 {
|
||||
continue
|
||||
}
|
||||
let public = hex[4..].to_vec();
|
||||
@@ -456,7 +454,7 @@ impl KeystoreInner {
|
||||
/// when something failed.
|
||||
pub fn key_pair<Pair: AppPair>(
|
||||
&self,
|
||||
public: &<Pair as AppKey>::Public,
|
||||
public: &<Pair as AppCrypto>::Public,
|
||||
) -> Result<Option<Pair>> {
|
||||
self.key_pair_by_type::<Pair::Generic>(IsWrappedBy::from_ref(public), Pair::ID)
|
||||
.map(|v| v.map(Into::into))
|
||||
|
||||
@@ -31,8 +31,8 @@ use sc_transaction_pool_api::TransactionStatus;
|
||||
use sp_core::{
|
||||
blake2_256,
|
||||
bytes::to_hex,
|
||||
crypto::{ByteArray, CryptoTypePublicPair, Pair},
|
||||
ed25519, sr25519,
|
||||
crypto::{ByteArray, Pair},
|
||||
ed25519,
|
||||
testing::{ED25519, SR25519},
|
||||
H256,
|
||||
};
|
||||
@@ -227,9 +227,7 @@ async fn author_should_insert_key() {
|
||||
api.call::<_, ()>("author_insertKey", params).await.unwrap();
|
||||
let pubkeys = setup.keystore.keys(ED25519).unwrap();
|
||||
|
||||
assert!(
|
||||
pubkeys.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, keypair.public().to_raw_vec()))
|
||||
);
|
||||
assert!(pubkeys.contains(&keypair.public().to_raw_vec()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -242,10 +240,8 @@ async fn author_should_rotate_keys() {
|
||||
SessionKeys::decode(&mut &new_pubkeys[..]).expect("SessionKeys decode successfully");
|
||||
let ed25519_pubkeys = setup.keystore.keys(ED25519).unwrap();
|
||||
let sr25519_pubkeys = setup.keystore.keys(SR25519).unwrap();
|
||||
assert!(ed25519_pubkeys
|
||||
.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, session_keys.ed25519.to_raw_vec())));
|
||||
assert!(sr25519_pubkeys
|
||||
.contains(&CryptoTypePublicPair(sr25519::CRYPTO_ID, session_keys.sr25519.to_raw_vec())));
|
||||
assert!(ed25519_pubkeys.contains(&session_keys.ed25519.to_raw_vec()));
|
||||
assert!(sr25519_pubkeys.contains(&session_keys.sr25519.to_raw_vec()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user