Newer
Older
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common 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.
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Substrate GRANDPA Pallet
//! This pallet is an on-chain GRANDPA light client for Substrate based chains.
//! This pallet achieves this by trustlessly verifying GRANDPA finality proofs on-chain. Once
//! verified, finalized headers are stored in the pallet, thereby creating a sparse header chain.
//! This sparse header chain can be used as a source of truth for other higher-level applications.
//! The pallet is responsible for tracking GRANDPA validator set hand-offs. We only import headers
//! with justifications signed by the current validator set we know of. The header is inspected for
//! a `ScheduledChanges` digest item, which is then used to update to next validator set.
//!
//! Since this pallet only tracks finalized headers it does not deal with forks. Forks can only
//! occur if the GRANDPA validator set on the bridged chain is either colluding or there is a severe
//! bug causing resulting in an equivocation. Such events are outside the scope of this pallet.
//! Shall the fork occur on the bridged chain governance intervention will be required to
//! re-initialize the bridge and track the right fork.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
pub use storage_types::StoredAuthoritySet;
Svyatoslav Nikolsky
committed
use bp_header_chain::{
justification::GrandpaJustification, AuthoritySet, ChainWithGrandpa, GrandpaConsensusLogReader,
HeaderChain, InitializationData, StoredHeaderData, StoredHeaderDataBuilder,
StoredHeaderGrandpaInfo,
use bp_runtime::{BlockNumberOf, HashOf, HasherOf, HeaderId, HeaderOf, OwnedBridgeModule};
use frame_support::{dispatch::PostDispatchInfo, ensure, DefaultNoBound};
use sp_consensus_grandpa::SetId;
use sp_runtime::{
traits::{Header as HeaderT, Zero},
SaturatedConversion,
};
use sp_std::{boxed::Box, convert::TryInto, prelude::*};
Svyatoslav Nikolsky
committed
mod storage_types;
Svyatoslav Nikolsky
committed
/// Module, containing weights for this pallet.
pub mod weights;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
// Re-export in crate namespace for `construct_runtime!`
pub use call_ext::*;
pub use weights::WeightInfo;
/// The target that will be used when publishing logs related to this pallet.
Svyatoslav Nikolsky
committed
pub const LOG_TARGET: &str = "runtime::bridge-grandpa";
/// Bridged chain from the pallet configuration.
pub type BridgedChain<T, I> = <T as Config<I>>::BridgedChain;
/// Block number of the bridged chain.
pub type BridgedBlockNumber<T, I> = BlockNumberOf<<T as Config<I>>::BridgedChain>;
/// Block hash of the bridged chain.
pub type BridgedBlockHash<T, I> = HashOf<<T as Config<I>>::BridgedChain>;
/// Block id of the bridged chain.
pub type BridgedBlockId<T, I> = HeaderId<BridgedBlockHash<T, I>, BridgedBlockNumber<T, I>>;
/// Hasher of the bridged chain.
pub type BridgedBlockHasher<T, I> = HasherOf<<T as Config<I>>::BridgedChain>;
/// Header of the bridged chain.
pub type BridgedHeader<T, I> = HeaderOf<<T as Config<I>>::BridgedChain>;
/// Header data of the bridged chain that is stored at this chain by this pallet.
pub type BridgedStoredHeaderData<T, I> =
StoredHeaderData<BridgedBlockNumber<T, I>, BridgedBlockHash<T, I>>;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use bp_runtime::BasicOperatingMode;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
Svyatoslav Nikolsky
committed
/// The overarching event type.
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// The chain we are bridging to here.
type BridgedChain: ChainWithGrandpa;
/// Maximal number of "free" header transactions per block.
Svyatoslav Nikolsky
committed
/// To be able to track the bridged chain, the pallet requires all headers that are
/// changing GRANDPA authorities set at the bridged chain (we call them mandatory).
/// So it is a common good deed to submit mandatory headers to the pallet.
///
/// The pallet may be configured (see `[Self::FreeHeadersInterval]`) to import some
/// non-mandatory headers for free as well. It also may be treated as a common good
/// deed, because it may help to reduce bridge fees - this cost may be deducted from
/// bridge fees, paid by message senders.
///
/// However, if the bridged chain gets compromised, its validators may generate as many
/// "free" headers as they want. And they may fill the whole block (at this chain) for
/// free. This constants limits number of calls that we may refund in a single block.
/// All calls above this limit are accepted, but are not refunded.
type MaxFreeHeadersPerBlock: Get<u32>;
/// The distance between bridged chain headers, that may be submitted for free. The
/// first free header is header number zero, the next one is header number
/// `FreeHeadersInterval::get()`. In other words, header with number that
/// is divisible by `FreeHeadersInterval` may be submitted for free.
#[pallet::constant]
type FreeHeadersInterval: Get<Option<u32>>;
/// Maximal number of finalized headers to keep in the storage.
///
/// The setting is there to prevent growing the on-chain state indefinitely. Note
/// the setting does not relate to block numbers - we will simply keep as much items
/// in the storage, so it doesn't guarantee any fixed timeframe for finality headers.
///
/// Incautious change of this constant may lead to orphan entries in the runtime storage.
#[pallet::constant]
type HeadersToKeep: Get<u32>;
/// Weights gathered through benchmarking.
type WeightInfo: WeightInfo;
#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
Svyatoslav Nikolsky
committed
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
FreeHeadersRemaining::<T, I>::put(T::MaxFreeHeadersPerBlock::get());
Svyatoslav Nikolsky
committed
Weight::zero()
}
Svyatoslav Nikolsky
committed
fn on_finalize(_n: BlockNumberFor<T>) {
FreeHeadersRemaining::<T, I>::kill();
impl<T: Config<I>, I: 'static> OwnedBridgeModule<T> for Pallet<T, I> {
const LOG_TARGET: &'static str = LOG_TARGET;
type OwnerStorage = PalletOwner<T, I>;
type OperatingMode = BasicOperatingMode;
type OperatingModeStorage = PalletOperatingMode<T, I>;
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// This call is deprecated and will be removed around May 2024. Use the
/// `submit_finality_proof_ex` instead. Semantically, this call is an equivalent of the
/// `submit_finality_proof_ex` call without current authority set id check.
#[pallet::call_index(0)]
#[pallet::weight(<T::WeightInfo as WeightInfo>::submit_finality_proof(
justification.commit.precommits.len().saturated_into(),
justification.votes_ancestries.len().saturated_into(),
))]
#[allow(deprecated)]
#[deprecated(
note = "`submit_finality_proof` will be removed in May 2024. Use `submit_finality_proof_ex` instead."
)]
pub fn submit_finality_proof(
origin: OriginFor<T>,
finality_target: Box<BridgedHeader<T, I>>,
justification: GrandpaJustification<BridgedHeader<T, I>>,
) -> DispatchResultWithPostInfo {
Self::submit_finality_proof_ex(
origin,
finality_target,
justification,
// the `submit_finality_proof_ex` also reads this value, but it is done from the
// cache, so we don't treat it as an additional db access
<CurrentAuthoritySet<T, I>>::get().set_id,
Svyatoslav Nikolsky
committed
// cannot enforce free execution using this call
false,
)
}
/// Bootstrap the bridge pallet with an initial header and authority set from which to sync.
///
/// The initial configuration provided does not need to be the genesis header of the bridged
/// chain, it can be any arbitrary header. You can also provide the next scheduled set
Loading full blame...