lib.rs 63.4 KiB
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/>.

//! Parachains finality module.
//!
//! This module needs to be deployed with GRANDPA module, which is syncing relay
//! chain blocks. The main entry point of this module is `submit_parachain_heads`, which
//! accepts storage proof of some parachain `Heads` entries from bridged relay chain.
//! It requires corresponding relay headers to be already synced.

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

pub use weights::WeightInfo;
pub use weights_ext::WeightInfoExt;

use bp_header_chain::{HeaderChain, HeaderChainError};
use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo, ParaStoredHeaderData};
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain, StorageProofError};
use frame_support::{dispatch::PostDispatchInfo, DefaultNoBound};
use pallet_bridge_grandpa::SubmitFinalityProofHelper;
use sp_std::{marker::PhantomData, vec::Vec};
#[cfg(feature = "runtime-benchmarks")]
use bp_parachains::ParaStoredHeaderDataBuilder;
#[cfg(feature = "runtime-benchmarks")]
use bp_runtime::HeaderOf;
#[cfg(feature = "runtime-benchmarks")]
use codec::Encode;

// Re-export in crate namespace for `construct_runtime!`.
pub use pallet::*;

pub mod weights;
pub mod weights_ext;

#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;

#[cfg(test)]
mod mock;

/// The target that will be used when publishing logs related to this pallet.
pub const LOG_TARGET: &str = "runtime::bridge-parachains";
/// Block hash of the bridged relay chain.
pub type RelayBlockHash = bp_polkadot_core::Hash;
/// Block number of the bridged relay chain.
pub type RelayBlockNumber = bp_polkadot_core::BlockNumber;
/// Hasher of the bridged relay chain.
pub type RelayBlockHasher = bp_polkadot_core::Hasher;

/// Artifacts of the parachains head update.
struct UpdateParachainHeadArtifacts {
	/// New best head of the parachain.
Serban Iorga's avatar
Serban Iorga committed
	pub best_head: ParaInfo,
	/// If `true`, some old parachain head has been pruned during update.
	pub prune_happened: bool,
}

#[frame_support::pallet]
pub mod pallet {
	use super::*;
	use bp_parachains::{
		BestParaHeadHash, ImportedParaHeadsKeyProvider, ParaStoredHeaderDataBuilder,
		ParasInfoKeyProvider,
	};
Serban Iorga's avatar
Serban Iorga committed
	use bp_runtime::{
		BasicOperatingMode, BoundedStorageValue, OwnedBridgeModule, StorageDoubleMapKeyProvider,
		StorageMapKeyProvider,
	use frame_support::pallet_prelude::*;
	use frame_system::pallet_prelude::*;

	/// Stored parachain head data of given parachains pallet.
	pub type StoredParaHeadDataOf<T, I> =
		BoundedStorageValue<<T as Config<I>>::MaxParaHeadDataSize, ParaStoredHeaderData>;
	/// Weight info of the given parachains pallet.
	pub type WeightInfoOf<T, I> = <T as Config<I>>::WeightInfo;
	/// Bridge GRANDPA pallet that is used to verify parachain proofs.
	pub type GrandpaPalletOf<T, I> =
		pallet_bridge_grandpa::Pallet<T, <T as Config<I>>::BridgesGrandpaPalletInstance>;
	#[pallet::event]
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
	pub enum Event<T: Config<I>, I: 'static = ()> {
		/// The caller has provided head of parachain that the pallet is not configured to track.
		UntrackedParachainRejected {
			/// Identifier of the parachain that is not tracked by the pallet.
			parachain: ParaId,
		},
		/// The caller has declared that he has provided given parachain head, but it is missing
		/// from the storage proof.
		MissingParachainHead {
			/// Identifier of the parachain with missing head.
			parachain: ParaId,
		},
		/// The caller has provided parachain head hash that is not matching the hash read from the
		/// storage proof.
		IncorrectParachainHeadHash {
			/// Identifier of the parachain with incorrect head hast.
			/// Specified parachain head hash.
			parachain_head_hash: ParaHash,
			/// Actual parachain head hash.
			actual_parachain_head_hash: ParaHash,
		},
		/// The caller has provided obsolete parachain head, which is already known to the pallet.
		RejectedObsoleteParachainHead {
			/// Identifier of the parachain with obsolete head.
			parachain: ParaId,
			/// Obsolete parachain head hash.
			parachain_head_hash: ParaHash,
		},
		/// The caller has provided parachain head that exceeds the maximal configured head size.
		RejectedLargeParachainHead {
			/// Identifier of the parachain with rejected head.
			parachain_head_hash: ParaHash,
		/// Parachain head has been updated.
		UpdatedParachainHead {
			/// Identifier of the parachain that has been updated.
			parachain: ParaId,
			/// Parachain head hash.
			parachain_head_hash: ParaHash,
		},
	#[pallet::error]
	pub enum Error<T, I = ()> {
		/// Relay chain block hash is unknown to us.
		UnknownRelayChainBlock,
		/// The number of stored relay block is different from what the relayer has provided.
		InvalidRelayChainBlockNumber,
		/// Parachain heads storage proof is invalid.
		HeaderChainStorageProof(HeaderChainError),
		/// Error generated by the `OwnedBridgeModule` trait.
		BridgeModule(bp_runtime::OwnedBridgeModuleError),
	/// Convenience trait for defining `BridgedChain` bounds.
	pub trait BoundedBridgeGrandpaConfig<I: 'static>:
		pallet_bridge_grandpa::Config<I, BridgedChain = Self::BridgedRelayChain>
	{
		/// Type of the bridged relay chain.
		type BridgedRelayChain: Chain<
			BlockNumber = RelayBlockNumber,
			Hash = RelayBlockHash,
			Hasher = RelayBlockHasher,
		>;
	}

	impl<T, I: 'static> BoundedBridgeGrandpaConfig<I> for T
	where
		T: pallet_bridge_grandpa::Config<I>,
		T::BridgedChain:
			Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>,
	{
		type BridgedRelayChain = T::BridgedChain;
	}

	#[pallet::config]
	#[pallet::disable_frame_system_supertrait_check]
	pub trait Config<I: 'static = ()>:
		BoundedBridgeGrandpaConfig<Self::BridgesGrandpaPalletInstance>
		/// The overarching event type.
		type RuntimeEvent: From<Event<Self, I>>
			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
		/// Benchmarks results from runtime we're plugged into.
		type WeightInfo: WeightInfoExt;

		/// Instance of bridges GRANDPA pallet (within this runtime) that this pallet is linked to.
		///
		/// The GRANDPA pallet instance must be configured to import headers of relay chain that
		/// we're interested in.
		///
		/// The associated GRANDPA pallet is also used to configure free parachain heads
		/// submissions. The parachain head submission will be free if:
		///
Loading full blame...