mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 18:07:58 +00:00
More secure Signed implementation (#2963)
* Remove signature verification in backing. `SignedFullStatement` now signals that the signature has already been checked. * Remove unused check_payload function. * Introduced unchecked signed variants. * Fix inclusion to use unchecked variant. * More unchecked variants. * Use unchecked variants in protocols. * Start fixing statement-distribution. * Fixup statement distribution. * Fix inclusion. * Fix warning. * Fix backing properly. * Fix bitfield distribution. * Make crypto store optional for `RuntimeInfo`. * Factor out utility functions. * get_group_rotation_info * WIP: Collator cleanup + check signatures. * Convenience signature checking functions. * Check signature on collator-side. * Fix warnings. * Fix collator side tests. * Get rid of warnings. * Better Signed/UncheckedSigned implementation. Also get rid of Encode/Decode for Signed! *party* * Get rid of dead code. * Move Signed in its own module. * into_checked -> try_into_checked * Fix merge.
This commit is contained in:
@@ -18,15 +18,18 @@
|
||||
|
||||
use lru::LruCache;
|
||||
|
||||
use parity_scale_codec::Encode;
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_core::crypto::Public;
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
||||
|
||||
use polkadot_primitives::v1::{GroupIndex, Hash, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex};
|
||||
use polkadot_primitives::v1::{CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, OccupiedCore, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ValidatorId, ValidatorIndex};
|
||||
use polkadot_node_subsystem::SubsystemContext;
|
||||
|
||||
use crate::{
|
||||
request_session_index_for_child, request_session_info,
|
||||
request_availability_cores,
|
||||
request_validator_groups,
|
||||
};
|
||||
|
||||
/// Errors that can happen on runtime fetches.
|
||||
@@ -49,7 +52,7 @@ pub struct RuntimeInfo {
|
||||
session_info_cache: LruCache<SessionIndex, ExtendedSessionInfo>,
|
||||
|
||||
/// Key store for determining whether we are a validator and what `ValidatorIndex` we have.
|
||||
keystore: SyncCryptoStorePtr,
|
||||
keystore: Option<SyncCryptoStorePtr>,
|
||||
}
|
||||
|
||||
/// SessionInfo with additional useful data for validator nodes.
|
||||
@@ -72,7 +75,7 @@ pub struct ValidatorInfo {
|
||||
|
||||
impl RuntimeInfo {
|
||||
/// Create a new `RuntimeInfo` for convenient runtime fetches.
|
||||
pub fn new(keystore: SyncCryptoStorePtr) -> Self {
|
||||
pub fn new(keystore: Option<SyncCryptoStorePtr>) -> Self {
|
||||
Self {
|
||||
// Adjust, depending on how many forks we want to support.
|
||||
session_index_cache: LruCache::new(10),
|
||||
@@ -150,6 +153,23 @@ impl RuntimeInfo {
|
||||
)
|
||||
}
|
||||
|
||||
/// Convenience function for checking the signature of something signed.
|
||||
pub async fn check_signature<Context, Payload, RealPayload>(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
parent: Hash,
|
||||
signed: UncheckedSigned<Payload, RealPayload>,
|
||||
) -> Result<std::result::Result<Signed<Payload, RealPayload>, UncheckedSigned<Payload, RealPayload>>>
|
||||
where
|
||||
Context: SubsystemContext,
|
||||
Payload: EncodeAs<RealPayload> + Clone,
|
||||
RealPayload: Encode + Clone,
|
||||
{
|
||||
let session_index = self.get_session_index(ctx, parent).await?;
|
||||
let info = self.get_session_info_by_index(ctx, parent, session_index).await?;
|
||||
Ok(check_signature(session_index, &info.session_info, parent, signed))
|
||||
}
|
||||
|
||||
/// Build `ValidatorInfo` for the current session.
|
||||
///
|
||||
///
|
||||
@@ -187,8 +207,9 @@ impl RuntimeInfo {
|
||||
///
|
||||
/// Returns: None if we are not a validator.
|
||||
async fn get_our_index(&self, validators: &[ValidatorId]) -> Option<ValidatorIndex> {
|
||||
let keystore = self.keystore.as_ref()?;
|
||||
for (i, v) in validators.iter().enumerate() {
|
||||
if CryptoStore::has_keys(&*self.keystore, &[(v.to_raw_vec(), ValidatorId::ID)])
|
||||
if CryptoStore::has_keys(&**keystore, &[(v.to_raw_vec(), ValidatorId::ID)])
|
||||
.await
|
||||
{
|
||||
return Some(ValidatorIndex(i as u32));
|
||||
@@ -197,3 +218,69 @@ impl RuntimeInfo {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function for quickly checking the signature on signed data.
|
||||
pub fn check_signature<Payload, RealPayload>(
|
||||
session_index: SessionIndex,
|
||||
session_info: &SessionInfo,
|
||||
relay_parent: Hash,
|
||||
signed: UncheckedSigned<Payload, RealPayload>,
|
||||
) -> std::result::Result<Signed<Payload, RealPayload>, UncheckedSigned<Payload, RealPayload>>
|
||||
where
|
||||
Payload: EncodeAs<RealPayload> + Clone,
|
||||
RealPayload: Encode + Clone,
|
||||
{
|
||||
let signing_context = SigningContext {
|
||||
session_index,
|
||||
parent_hash: relay_parent,
|
||||
};
|
||||
|
||||
session_info.validators
|
||||
.get(signed.unchecked_validator_index().0 as usize)
|
||||
.ok_or_else(|| signed.clone())
|
||||
.and_then(|v| signed.try_into_checked(&signing_context, v))
|
||||
}
|
||||
|
||||
/// Request availability cores from the runtime.
|
||||
pub async fn get_availability_cores<Context>(ctx: &mut Context, relay_parent: Hash)
|
||||
-> Result<Vec<CoreState>>
|
||||
where
|
||||
Context: SubsystemContext,
|
||||
{
|
||||
recv_runtime(request_availability_cores(relay_parent, ctx.sender()).await).await
|
||||
}
|
||||
|
||||
/// Variant of `request_availability_cores` that only returns occupied ones.
|
||||
pub async fn get_occupied_cores<Context>(
|
||||
ctx: &mut Context,
|
||||
relay_parent: Hash,
|
||||
) -> Result<Vec<OccupiedCore>>
|
||||
where
|
||||
Context: SubsystemContext,
|
||||
{
|
||||
let cores = get_availability_cores(ctx, relay_parent).await?;
|
||||
|
||||
Ok(cores
|
||||
.into_iter()
|
||||
.filter_map(|core_state| {
|
||||
if let CoreState::Occupied(occupied) = core_state {
|
||||
Some(occupied)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
/// Get group rotation info based on the given relay_parent.
|
||||
pub async fn get_group_rotation_info<Context>(ctx: &mut Context, relay_parent: Hash)
|
||||
-> Result<GroupRotationInfo>
|
||||
where
|
||||
Context: SubsystemContext
|
||||
{
|
||||
// We drop `groups` here as we don't need them, because of `RuntimeInfo`. Ideally we would not
|
||||
// fetch them in the first place.
|
||||
let (_, info) = recv_runtime(request_validator_groups(relay_parent, ctx.sender()).await).await?;
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user