Introduce a Slot type (#7997)

* Introduce a `Slot` type

Instead of having some type definition that only was used in half of the
code or directly using `u64`, this adds a new unit type wrapper `Slot`.
This makes it especially easy for the outside api to know what type is
expected/returned.

* Change epoch duratioC

* rename all instances of slot number to slot

* Make the constructor private

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-01-28 20:44:22 +01:00
committed by GitHub
parent 6c2dd28dfb
commit b6294418f8
34 changed files with 549 additions and 445 deletions
@@ -24,6 +24,7 @@
use sp_core::Pair;
use sp_consensus_aura::AURA_ENGINE_ID;
use sp_runtime::generic::{DigestItem, OpaqueDigestItemId};
use sp_consensus_slots::Slot;
use codec::{Encode, Codec};
use std::fmt::Debug;
@@ -38,10 +39,10 @@ pub trait CompatibleDigestItem<P: Pair>: Sized {
fn as_aura_seal(&self) -> Option<Signature<P>>;
/// Construct a digest item which contains the slot number
fn aura_pre_digest(slot_num: u64) -> Self;
fn aura_pre_digest(slot: Slot) -> Self;
/// If this item is an AuRa pre-digest, return the slot number
fn as_aura_pre_digest(&self) -> Option<u64>;
fn as_aura_pre_digest(&self) -> Option<Slot>;
}
impl<P, Hash> CompatibleDigestItem<P> for DigestItem<Hash> where
@@ -57,11 +58,11 @@ impl<P, Hash> CompatibleDigestItem<P> for DigestItem<Hash> where
self.try_to(OpaqueDigestItemId::Seal(&AURA_ENGINE_ID))
}
fn aura_pre_digest(slot_num: u64) -> Self {
DigestItem::PreRuntime(AURA_ENGINE_ID, slot_num.encode())
fn aura_pre_digest(slot: Slot) -> Self {
DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())
}
fn as_aura_pre_digest(&self) -> Option<u64> {
fn as_aura_pre_digest(&self) -> Option<Slot> {
self.try_to(OpaqueDigestItemId::PreRuntime(&AURA_ENGINE_ID))
}
}
+45 -46
View File
@@ -43,11 +43,11 @@ use prometheus_endpoint::Registry;
use codec::{Encode, Decode, Codec};
use sp_consensus::{
self, BlockImport, Environment, Proposer, CanAuthorWith, ForkChoiceStrategy, BlockImportParams,
BlockOrigin, Error as ConsensusError, SelectChain, SlotData, BlockCheckParams, ImportResult
};
use sp_consensus::import_queue::{
Verifier, BasicQueue, DefaultImportQueue, BoxJustificationImport,
BlockImport, Environment, Proposer, CanAuthorWith, ForkChoiceStrategy, BlockImportParams,
BlockOrigin, Error as ConsensusError, SelectChain, SlotData, BlockCheckParams, ImportResult,
import_queue::{
Verifier, BasicQueue, DefaultImportQueue, BoxJustificationImport,
},
};
use sc_client_api::{backend::AuxStore, BlockOf};
use sp_blockchain::{
@@ -57,10 +57,7 @@ use sp_blockchain::{
use sp_block_builder::BlockBuilder as BlockBuilderApi;
use sp_core::crypto::Public;
use sp_application_crypto::{AppKey, AppPublic};
use sp_runtime::{
generic::{BlockId, OpaqueDigestItemId},
traits::NumberFor, Justification,
};
use sp_runtime::{generic::{BlockId, OpaqueDigestItemId}, traits::NumberFor, Justification};
use sp_runtime::traits::{Block as BlockT, Header, DigestItemFor, Zero, Member};
use sp_api::ProvideRuntimeApi;
use sp_core::crypto::Pair;
@@ -75,6 +72,7 @@ use sc_consensus_slots::{
CheckedHeader, SlotInfo, SlotCompatible, StorageChanges, check_equivocation,
BackoffAuthoringBlocksStrategy,
};
use sp_consensus_slots::Slot;
use sp_api::ApiExt;
@@ -106,10 +104,10 @@ pub fn slot_duration<A, B, C>(client: &C) -> CResult<SlotDuration> where
}
/// Get slot author for given block along with authorities.
fn slot_author<P: Pair>(slot_num: u64, authorities: &[AuthorityId<P>]) -> Option<&AuthorityId<P>> {
fn slot_author<P: Pair>(slot: Slot, authorities: &[AuthorityId<P>]) -> Option<&AuthorityId<P>> {
if authorities.is_empty() { return None }
let idx = slot_num % (authorities.len() as u64);
let idx = *slot % (authorities.len() as u64);
assert!(
idx <= usize::max_value() as u64,
"It is impossible to have a vector with length beyond the address space; qed",
@@ -239,7 +237,7 @@ where
fn epoch_data(
&self,
header: &B::Header,
_slot_number: u64,
_slot: Slot,
) -> Result<Self::EpochData, sp_consensus::Error> {
authorities(self.client.as_ref(), &BlockId::Hash(header.hash()))
}
@@ -251,10 +249,10 @@ where
fn claim_slot(
&self,
_header: &B::Header,
slot_number: u64,
slot: Slot,
epoch_data: &Self::EpochData,
) -> Option<Self::Claim> {
let expected_author = slot_author::<P>(slot_number, epoch_data);
let expected_author = slot_author::<P>(slot, epoch_data);
expected_author.and_then(|p| {
if SyncCryptoStore::has_keys(
&*self.keystore,
@@ -269,11 +267,11 @@ where
fn pre_digest_data(
&self,
slot_number: u64,
slot: Slot,
_claim: &Self::Claim,
) -> Vec<sp_runtime::DigestItem<B::Hash>> {
vec![
<DigestItemFor<B> as CompatibleDigestItem<P>>::aura_pre_digest(slot_number),
<DigestItemFor<B> as CompatibleDigestItem<P>>::aura_pre_digest(slot),
]
}
@@ -323,14 +321,14 @@ where
self.force_authoring
}
fn should_backoff(&self, slot_number: u64, chain_head: &B::Header) -> bool {
fn should_backoff(&self, slot: Slot, chain_head: &B::Header) -> bool {
if let Some(ref strategy) = self.backoff_authoring_blocks {
if let Ok(chain_head_slot) = find_pre_digest::<B, P>(chain_head) {
return strategy.should_backoff(
*chain_head.number(),
chain_head_slot,
self.client.info().finalized_number,
slot_number,
slot,
self.logging_target(),
);
}
@@ -363,9 +361,10 @@ where
if let Some(slot_lenience) =
sc_consensus_slots::slot_lenience_exponential(parent_slot, slot_info)
{
debug!(target: "aura",
debug!(
target: "aura",
"No block for {} slots. Applying linear lenience of {}s",
slot_info.number.saturating_sub(parent_slot + 1),
slot_info.slot.saturating_sub(parent_slot + 1),
slot_lenience.as_secs(),
);
@@ -401,7 +400,7 @@ enum Error<B: BlockT> {
DataProvider(String),
Runtime(String),
#[display(fmt = "Slot number must increase: parent slot: {}, this slot: {}", _0, _1)]
SlotNumberMustIncrease(u64, u64),
SlotMustIncrease(Slot, Slot),
#[display(fmt = "Parent ({}) of {} unavailable. Cannot import", _0, _1)]
ParentUnavailable(B::Hash, B::Hash),
}
@@ -412,16 +411,16 @@ impl<B: BlockT> std::convert::From<Error<B>> for String {
}
}
fn find_pre_digest<B: BlockT, P: Pair>(header: &B::Header) -> Result<u64, Error<B>>
fn find_pre_digest<B: BlockT, P: Pair>(header: &B::Header) -> Result<Slot, Error<B>>
where DigestItemFor<B>: CompatibleDigestItem<P>,
P::Signature: Decode,
P::Public: Encode + Decode + PartialEq + Clone,
{
if header.number().is_zero() {
return Ok(0);
return Ok(0.into());
}
let mut pre_digest: Option<u64> = None;
let mut pre_digest: Option<Slot> = None;
for log in header.digest().logs() {
trace!(target: "aura", "Checking log {:?}", log);
match (log.as_aura_pre_digest(), pre_digest.is_some()) {
@@ -440,11 +439,11 @@ fn find_pre_digest<B: BlockT, P: Pair>(header: &B::Header) -> Result<u64, Error<
//
fn check_header<C, B: BlockT, P: Pair>(
client: &C,
slot_now: u64,
slot_now: Slot,
mut header: B::Header,
hash: B::Hash,
authorities: &[AuthorityId<P>],
) -> Result<CheckedHeader<B::Header, (u64, DigestItemFor<B>)>, Error<B>> where
) -> Result<CheckedHeader<B::Header, (Slot, DigestItemFor<B>)>, Error<B>> where
DigestItemFor<B>: CompatibleDigestItem<P>,
P::Signature: Decode,
C: sc_client_api::backend::AuxStore,
@@ -459,15 +458,15 @@ fn check_header<C, B: BlockT, P: Pair>(
aura_err(Error::HeaderBadSeal(hash))
})?;
let slot_num = find_pre_digest::<B, _>(&header)?;
let slot = find_pre_digest::<B, _>(&header)?;
if slot_num > slot_now {
if slot > slot_now {
header.digest_mut().push(seal);
Ok(CheckedHeader::Deferred(header, slot_num))
Ok(CheckedHeader::Deferred(header, slot))
} else {
// check the signature is valid under the expected authority and
// chain state.
let expected_author = match slot_author::<P>(slot_num, &authorities) {
let expected_author = match slot_author::<P>(slot, &authorities) {
None => return Err(Error::SlotAuthorNotFound),
Some(author) => author,
};
@@ -478,19 +477,19 @@ fn check_header<C, B: BlockT, P: Pair>(
if let Some(equivocation_proof) = check_equivocation(
client,
slot_now,
slot_num,
slot,
&header,
expected_author,
).map_err(Error::Client)? {
info!(
"Slot author is equivocating at slot {} with headers {:?} and {:?}",
slot_num,
slot,
equivocation_proof.first_header.hash(),
equivocation_proof.second_header.hash(),
);
}
Ok(CheckedHeader::Checked(header, (slot_num, seal)))
Ok(CheckedHeader::Checked(header, (slot, seal)))
} else {
Err(Error::BadSignature(hash))
}
@@ -614,12 +613,12 @@ impl<B: BlockT, C, P, CAW> Verifier<B> for AuraVerifier<C, P, CAW> where
&authorities[..],
).map_err(|e| e.to_string())?;
match checked_header {
CheckedHeader::Checked(pre_header, (slot_num, seal)) => {
CheckedHeader::Checked(pre_header, (slot, seal)) => {
// if the body is passed through, we need to use the runtime
// to check that the internally-set timestamp in the inherents
// actually matches the slot set in the seal.
if let Some(inner_body) = body.take() {
inherent_data.aura_replace_inherent_data(slot_num);
inherent_data.aura_replace_inherent_data(slot);
let block = B::new(pre_header.clone(), inner_body);
// skip the inherents verification if the runtime API is old.
@@ -803,7 +802,7 @@ impl<Block: BlockT, C, I, P> BlockImport<Block> for AuraBlockImport<Block, C, I,
new_cache: HashMap<CacheKeyId, Vec<u8>>,
) -> Result<ImportResult, Self::Error> {
let hash = block.post_hash();
let slot_number = find_pre_digest::<Block, P>(&block.header)
let slot = find_pre_digest::<Block, P>(&block.header)
.expect("valid Aura headers must contain a predigest; \
header has been already verified; qed");
@@ -819,10 +818,10 @@ impl<Block: BlockT, C, I, P> BlockImport<Block> for AuraBlockImport<Block, C, I,
parent header has already been verified; qed");
// make sure that slot number is strictly increasing
if slot_number <= parent_slot {
if slot <= parent_slot {
return Err(
ConsensusError::ClientImport(aura_err(
Error::<Block>::SlotNumberMustIncrease(parent_slot, slot_number)
Error::<Block>::SlotMustIncrease(parent_slot, slot)
).into())
);
}
@@ -1113,13 +1112,13 @@ mod tests {
Default::default(),
Default::default()
);
assert!(worker.claim_slot(&head, 0, &authorities).is_none());
assert!(worker.claim_slot(&head, 1, &authorities).is_none());
assert!(worker.claim_slot(&head, 2, &authorities).is_none());
assert!(worker.claim_slot(&head, 3, &authorities).is_some());
assert!(worker.claim_slot(&head, 4, &authorities).is_none());
assert!(worker.claim_slot(&head, 5, &authorities).is_none());
assert!(worker.claim_slot(&head, 6, &authorities).is_none());
assert!(worker.claim_slot(&head, 7, &authorities).is_some());
assert!(worker.claim_slot(&head, 0.into(), &authorities).is_none());
assert!(worker.claim_slot(&head, 1.into(), &authorities).is_none());
assert!(worker.claim_slot(&head, 2.into(), &authorities).is_none());
assert!(worker.claim_slot(&head, 3.into(), &authorities).is_some());
assert!(worker.claim_slot(&head, 4.into(), &authorities).is_none());
assert!(worker.claim_slot(&head, 5.into(), &authorities).is_none());
assert!(worker.claim_slot(&head, 6.into(), &authorities).is_none());
assert!(worker.claim_slot(&head, 7.into(), &authorities).is_some());
}
}