#![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(Aura::<T>::authorities());
}
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
Authorities::<T>::get();
let new_slot = Aura::<T>::current_slot();
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(2, 1)
}
}
#[pallet::storage]
pub(crate) type Authorities<T: Config> = StorageValue<
_,
BoundedVec<T::AuthorityId, <T as pallet_aura::Config>::MaxAuthorities>,
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn slot_info)]
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: sp_std::marker::PhantomData<T>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
let authorities = Aura::<T>::authorities();
assert!(
!authorities.is_empty(),
"AuRa authorities empty, maybe wrong order in `construct_runtime!`?",
);
Authorities::<T>::put(authorities);
}
}
}
pub struct BlockExecutorVer<T, I>(sp_std::marker::PhantomData<(T, I)>);
pub fn get_block_signer_pub_key<T: Config, Block: BlockT>(block: &Block) -> sp_std::vec::Vec<u8> {
let header = block.header();
let authorities = Authorities::<T>::get();
let author =
Aura::<T>::find_author(header.digest().logs().iter().filter_map(|d| d.as_pre_runtime()))
.expect("Could not find AuRa author index!");
return authorities
.get(author as usize)
.unwrap_or_else(|| {
panic!("Invalid AuRa author index {} for authorities: {:?}", author, authorities)
})
.to_raw_vec()
}
impl<Block, T, I> ExecuteBlock<Block> for BlockExecutorVer<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");
}
let public_key = authorities
.get(author as usize)
.unwrap_or_else(|| {
panic!("Invalid AuRa author index {} for authorities: {:?}", author, authorities)
})
.to_raw_vec();
I::execute_block_ver(Block::new(header, extrinsics), public_key);
}
}
pub struct BlockExecutor<T, I>(sp_std::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));
}
}