Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion frame/aura/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system"
sp-timestamp = { version = "2.0.0", default-features = false, path = "../../primitives/timestamp" }
pallet-timestamp = { version = "2.0.0", default-features = false, path = "../timestamp" }


[dev-dependencies]
sp-core = { version = "2.0.0", default-features = false, path = "../../primitives/core" }
sp-io ={ version = "2.0.0", path = "../../primitives/io" }
Expand Down
129 changes: 74 additions & 55 deletions frame/aura/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,52 +44,77 @@

#![cfg_attr(not(feature = "std"), no_std)]

use pallet_timestamp;

use sp_std::{result, prelude::*};
use codec::{Encode, Decode};
use frame_support::{
decl_storage, decl_module, Parameter, traits::{Get, FindAuthor},
ConsensusEngineId,
};
use frame_support::{Parameter, traits::{Get, FindAuthor}, ConsensusEngineId};
use sp_runtime::{
RuntimeAppPublic,
traits::{SaturatedConversion, Saturating, Zero, Member, IsMember}, generic::DigestItem,
};
use sp_timestamp::OnTimestampSet;
use sp_inherents::{InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
use sp_consensus_aura::{
AURA_ENGINE_ID, ConsensusLog, AuthorityIndex,
AURA_ENGINE_ID, ConsensusLog, AuthorityIndex, Slot,
inherents::{INHERENT_IDENTIFIER, AuraInherentData},
};

mod mock;
mod tests;

pub trait Config: pallet_timestamp::Config {
/// The identifier type for an authority.
type AuthorityId: Member + Parameter + RuntimeAppPublic + Default;
}
pub use pallet::*;

decl_storage! {
trait Store for Module<T: Config> as Aura {
/// The last timestamp.
LastTimestamp get(fn last): T::Moment;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

/// The current authorities
pub Authorities get(fn authorities): Vec<T::AuthorityId>;
#[pallet::config]
pub trait Config: pallet_timestamp::Config + frame_system::Config {
/// The identifier type for an authority.
type AuthorityId: Member + Parameter + RuntimeAppPublic + Default + MaybeSerializeDeserialize;
}
add_extra_genesis {
config(authorities): Vec<T::AuthorityId>;
build(|config| Module::<T>::initialize_authorities(&config.authorities))

#[pallet::pallet]
pub struct Pallet<T>(sp_std::marker::PhantomData<T>);

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}

#[pallet::call]
impl<T: Config> Pallet<T> {}

/// The current authority set.
#[pallet::storage]
#[pallet::getter(fn authorities)]
pub(super) type Authorities<T: Config> = StorageValue<_, Vec<T::AuthorityId>, ValueQuery>;

/// The last timestamp we have been notified of.
#[pallet::storage]
#[pallet::getter(fn last_timestamp)]
pub(super) type LastTimestamp<T: Config> = StorageValue<_, T::Moment, ValueQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub authorities: Vec<T::AuthorityId>,
}

#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self { authorities: Vec::new() }
}
}
}

decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin { }
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
Pallet::<T>::initialize_authorities(&self.authorities);
}
}
}

impl<T: Config> Module<T> {
impl<T: Config> Pallet<T> {
fn change_authorities(new: Vec<T::AuthorityId>) {
<Authorities<T>>::put(&new);

Expand All @@ -106,13 +131,20 @@ impl<T: Config> Module<T> {
<Authorities<T>>::put(authorities);
}
}

/// Determine the Aura slot-duration based on the Timestamp module configuration.
pub fn slot_duration() -> T::Moment {
// we double the minimum block-period so each author can always propose within
// the majority of its slot.
<T as pallet_timestamp::Config>::MinimumPeriod::get().saturating_mul(2u32.into())
}
}

impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Module<T> {
impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
type Public = T::AuthorityId;
}

impl<T: Config> pallet_session::OneSessionHandler<T::AccountId> for Module<T> {
impl<T: Config> pallet_session::OneSessionHandler<T::AccountId> for Pallet<T> {
type Key = T::AuthorityId;

fn on_genesis_session<'a, I: 'a>(validators: I)
Expand All @@ -128,7 +160,7 @@ impl<T: Config> pallet_session::OneSessionHandler<T::AccountId> for Module<T> {
// instant changes
if changed {
let next_authorities = validators.map(|(_, k)| k).collect::<Vec<_>>();
let last_authorities = <Module<T>>::authorities();
let last_authorities = Self::authorities();
if next_authorities != last_authorities {
Self::change_authorities(next_authorities);
}
Expand All @@ -145,24 +177,23 @@ impl<T: Config> pallet_session::OneSessionHandler<T::AccountId> for Module<T> {
}
}

impl<T: Config> FindAuthor<u32> for Module<T> {
impl<T: Config> FindAuthor<u32> for Pallet<T> {
fn find_author<'a, I>(digests: I) -> Option<u32> where
I: 'a + IntoIterator<Item=(ConsensusEngineId, &'a [u8])>
{
for (id, mut data) in digests.into_iter() {
if id == AURA_ENGINE_ID {
if let Ok(slot) = u64::decode(&mut data) {
let author_index = slot % Self::authorities().len() as u64;
return Some(author_index as u32)
}
let slot = Slot::decode(&mut data).ok()?;
let author_index = *slot % Self::authorities().len() as u64;
return Some(author_index as u32)
}
}

None
}
}

/// We can not implement `FindAuthor` twice, because the compiler does not know if
/// We can not implement `FindAuthor` twice, because the compiler does not know if
/// `u32 == T::AuthorityId` and thus, prevents us to implement the trait twice.
#[doc(hidden)]
pub struct FindAccountFromAuthorIndex<T, Inner>(sp_std::marker::PhantomData<(T, Inner)>);
Expand All @@ -175,56 +206,44 @@ impl<T: Config, Inner: FindAuthor<u32>> FindAuthor<T::AuthorityId>
{
let i = Inner::find_author(digests)?;

let validators = <Module<T>>::authorities();
let validators = <Pallet<T>>::authorities();
validators.get(i as usize).map(|k| k.clone())
}
}

/// Find the authority ID of the Aura authority who authored the current block.
pub type AuraAuthorId<T> = FindAccountFromAuthorIndex<T, Module<T>>;
pub type AuraAuthorId<T> = FindAccountFromAuthorIndex<T, Pallet<T>>;

impl<T: Config> IsMember<T::AuthorityId> for Module<T> {
impl<T: Config> IsMember<T::AuthorityId> for Pallet<T> {
fn is_member(authority_id: &T::AuthorityId) -> bool {
Self::authorities()
.iter()
.any(|id| id == authority_id)
}
}

impl<T: Config> Module<T> {
/// Determine the Aura slot-duration based on the Timestamp module configuration.
pub fn slot_duration() -> T::Moment {
// we double the minimum block-period so each author can always propose within
// the majority of its slot.
<T as pallet_timestamp::Config>::MinimumPeriod::get().saturating_mul(2u32.into())
}

fn on_timestamp_set(now: T::Moment, slot_duration: T::Moment) {
let last = Self::last();
<Self as Store>::LastTimestamp::put(now);
impl<T: Config> OnTimestampSet<T::Moment> for Pallet<T> {
fn on_timestamp_set(moment: T::Moment) {
let last = Self::last_timestamp();
LastTimestamp::<T>::put(moment);

if last.is_zero() {
return;
}

let slot_duration = Self::slot_duration();
assert!(!slot_duration.is_zero(), "Aura slot duration cannot be zero.");

let last_slot = last / slot_duration;
let cur_slot = now / slot_duration;
let cur_slot = moment / slot_duration;

assert!(last_slot < cur_slot, "Only one block may be authored per slot.");

// TODO [#3398] Generate offence report for all authorities that skipped their slots.
}
}

impl<T: Config> OnTimestampSet<T::Moment> for Module<T> {
fn on_timestamp_set(moment: T::Moment) {
Self::on_timestamp_set(moment, Self::slot_duration())
}
}

impl<T: Config> ProvideInherent for Module<T> {
impl<T: Config> ProvideInherent for Pallet<T> {
type Call = pallet_timestamp::Call<T>;
type Error = MakeFatalError<sp_inherents::Error>;
const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
Expand Down
2 changes: 1 addition & 1 deletion frame/aura/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use sp_runtime::{
traits::IdentityLookup,
testing::{Header, UintAuthorityId},
};
use frame_support::parameter_types;
use frame_support::{parameter_types, traits::GenesisBuild};
use sp_io;
use sp_core::H256;

Expand Down
2 changes: 1 addition & 1 deletion frame/aura/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::mock::{Aura, new_test_ext};
#[test]
fn initial_values() {
new_test_ext(vec![0, 1, 2, 3]).execute_with(|| {
assert_eq!(Aura::last(), 0u64);
assert_eq!(Aura::last_timestamp(), 0u64);
assert_eq!(Aura::authorities().len(), 4);
});
}
2 changes: 2 additions & 0 deletions primitives/consensus/aura/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub mod ed25519 {
pub type AuthorityId = app_ed25519::Public;
}

pub use sp_consensus_slots::Slot;

/// The `ConsensusEngineId` of AuRa.
pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a'];

Expand Down