1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! Cumulus extension pallet for AuRa
//!
//! This pallets extends the Substrate AuRa pallet to make it compatible with parachains. It
//! provides the [`Pallet`], the [`Config`] and the [`GenesisConfig`].
//!
//! It is also required that the parachain runtime uses the provided [`BlockExecutor`] to properly
//! check the constructed block on the relay chain.
//!
//! ```
//!# struct Runtime;
//!# struct Executive;
//!# struct CheckInherents;
//! cumulus_pallet_parachain_system::register_validate_block! {
//! Runtime = Runtime,
//! BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
//! CheckInherents = CheckInherents,
//! }
//! ```
#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::traits::{ExecuteBlock, FindAuthor};
use sp_application_crypto::RuntimeAppPublic;
use sp_consensus_aura::digests::CompatibleDigestItem;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
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::*;
/// The configuration trait.
#[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>) {
// Update to the latest AuRa authorities.
Authorities::<T>::put(Aura::<T>::authorities());
}
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
// Fetch the authorities once to get them into the storage proof of the PoV.
Authorities::<T>::get();
T::DbWeight::get().reads_writes(2, 1)
}
}
/// Serves as cache for the authorities.
///
/// The authorities in AuRa are overwritten in `on_initialize` when we switch to a new session,
/// but we require the old authorities to verify the seal when validating a PoV. This will always
/// be updated to the latest AuRa authorities in `on_finalize`.
#[pallet::storage]
pub(crate) type Authorities<T: Config> = StorageValue<
_,
BoundedVec<T::AuthorityId, <T as pallet_aura::Config>::MaxAuthorities>,
ValueQuery,
>;
#[pallet::genesis_config]
#[derive(Default)]
pub struct GenesisConfig;
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig {
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);
}
}
}
/// The block executor used when validating a PoV at the relay chain.
///
/// When executing the block it will verify the block seal to ensure that the correct author created
/// the block.
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();
// We need to fetch the authorities before we execute the block, to get the authorities
// before any potential update.
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));
}
}