#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::traits::{ExecuteBlock, FindAuthor};
use sp_application_crypto::RuntimeAppPublic;
use sp_consensus_aura::{digests::CompatibleDigestItem, Slot};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
pub mod consensus_hook;
pub use consensus_hook::FixedVelocityConsensusHook;
type Aura<T> = pallet_aura::Pallet<T>;
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::config]
pub trait Config: pallet_aura::Config + frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_finalize(_: BlockNumberFor<T>) {
Authorities::<T>::put(pallet_aura::Authorities::<T>::get());
}
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
Authorities::<T>::get();
let new_slot = pallet_aura::CurrentSlot::<T>::get();
let (new_slot, authored) = match SlotInfo::<T>::get() {
Some((slot, authored)) if slot == new_slot => (slot, authored + 1),
Some((slot, _)) if slot < new_slot => (new_slot, 1),
Some(..) => {
panic!("slot moved backwards")
},
None => (new_slot, 1),
};
SlotInfo::<T>::put((new_slot, authored));
T::DbWeight::get().reads_writes(4, 2)
}
}
#[pallet::storage]
pub(crate) type Authorities<T: Config> = StorageValue<
_,
BoundedVec<T::AuthorityId, <T as pallet_aura::Config>::MaxAuthorities>,
ValueQuery,
>;
#[pallet::storage]
pub(crate) type SlotInfo<T: Config> = StorageValue<_, (Slot, u32), OptionQuery>;
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
#[serde(skip)]
pub _config: core::marker::PhantomData<T>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
let authorities = pallet_aura::Authorities::<T>::get();
Authorities::<T>::put(authorities);
}
}
}
pub struct BlockExecutor<T, I>(core::marker::PhantomData<(T, I)>);
impl<Block, T, I> ExecuteBlock<Block> for BlockExecutor<T, I>
where
Block: BlockT,
T: Config,
I: ExecuteBlock<Block>,
{
fn execute_block(block: Block) {
let (mut header, extrinsics) = block.deconstruct();
let authorities = Authorities::<T>::get();
let mut seal = None;
header.digest_mut().logs.retain(|s| {
let s =
CompatibleDigestItem::<<T::AuthorityId as RuntimeAppPublic>::Signature>::as_aura_seal(s);
match (s, seal.is_some()) {
(Some(_), true) => panic!("Found multiple AuRa seal digests"),
(None, _) => true,
(Some(s), false) => {
seal = Some(s);
false
},
}
});
let seal = seal.expect("Could not find an AuRa seal digest!");
let author = Aura::<T>::find_author(
header.digest().logs().iter().filter_map(|d| d.as_pre_runtime()),
)
.expect("Could not find AuRa author index!");
let pre_hash = header.hash();
if !authorities
.get(author as usize)
.unwrap_or_else(|| {
panic!("Invalid AuRa author index {} for authorities: {:?}", author, authorities)
})
.verify(&pre_hash, &seal)
{
panic!("Invalid AuRa seal");
}
I::execute_block(Block::new(header, extrinsics));
}
}