Only store header state root (pallet-bridge-parachains) (#1701)

* store block number ++ state root in parachains pallet

* fixed parachains finality APIs

* (test commit)

* removed test code

* deduplicated code a bit

* removed commented code

* spelling

* Update modules/parachains/src/lib.rs

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update modules/parachains/src/lib.rs

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update modules/parachains/src/mock.rs

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* added comment

Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
Svyatoslav Nikolsky
2022-12-12 09:15:36 +03:00
committed by Bastian Köcher
parent 2c5e2f09eb
commit d63a75697c
22 changed files with 446 additions and 176 deletions
+2
View File
@@ -16,6 +16,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
bp-messages = { path = "../../../primitives/messages", default-features = false } bp-messages = { path = "../../../primitives/messages", default-features = false }
bp-millau = { path = "../../../primitives/chain-millau", default-features = false } bp-millau = { path = "../../../primitives/chain-millau", default-features = false }
bp-parachains = { path = "../../../primitives/parachains", default-features = false }
bp-polkadot-core = { path = "../../../primitives/polkadot-core", default-features = false } bp-polkadot-core = { path = "../../../primitives/polkadot-core", default-features = false }
bp-relayers = { path = "../../../primitives/relayers", default-features = false } bp-relayers = { path = "../../../primitives/relayers", default-features = false }
bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false } bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false }
@@ -84,6 +85,7 @@ std = [
"beefy-primitives/std", "beefy-primitives/std",
"bp-messages/std", "bp-messages/std",
"bp-millau/std", "bp-millau/std",
"bp-parachains/std",
"bp-polkadot-core/std", "bp-polkadot-core/std",
"bp-relayers/std", "bp-relayers/std",
"bp-rialto/std", "bp-rialto/std",
+13 -21
View File
@@ -33,8 +33,8 @@ pub mod rialto_parachain_messages;
pub mod xcm_config; pub mod xcm_config;
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet}; use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
use bp_runtime::{HeaderId, HeaderIdProvider}; use bp_parachains::SingleParaStoredHeaderDataBuilder;
use codec::Decode; use bp_runtime::HeaderId;
use pallet_grandpa::{ use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
}; };
@@ -522,8 +522,8 @@ parameter_types! {
pub const RialtoParachainId: u32 = bp_rialto_parachain::RIALTO_PARACHAIN_ID; pub const RialtoParachainId: u32 = bp_rialto_parachain::RIALTO_PARACHAIN_ID;
pub const RialtoParasPalletName: &'static str = bp_rialto::PARAS_PALLET_NAME; pub const RialtoParasPalletName: &'static str = bp_rialto::PARAS_PALLET_NAME;
pub const WestendParasPalletName: &'static str = bp_westend::PARAS_PALLET_NAME; pub const WestendParasPalletName: &'static str = bp_westend::PARAS_PALLET_NAME;
pub const MaxRialtoParaHeadSize: u32 = bp_rialto::MAX_NESTED_PARACHAIN_HEAD_SIZE; pub const MaxRialtoParaHeadDataSize: u32 = bp_rialto::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE;
pub const MaxWestendParaHeadSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_SIZE; pub const MaxWestendParaHeadDataSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE;
} }
/// Instance of the with-Rialto parachains pallet. /// Instance of the with-Rialto parachains pallet.
@@ -534,9 +534,10 @@ impl pallet_bridge_parachains::Config<WithRialtoParachainsInstance> for Runtime
type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight<Runtime>; type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight<Runtime>;
type BridgesGrandpaPalletInstance = RialtoGrandpaInstance; type BridgesGrandpaPalletInstance = RialtoGrandpaInstance;
type ParasPalletName = RialtoParasPalletName; type ParasPalletName = RialtoParasPalletName;
type TrackedParachains = frame_support::traits::Everything; type ParaStoredHeaderDataBuilder =
SingleParaStoredHeaderDataBuilder<bp_rialto_parachain::RialtoParachain>;
type HeadsToKeep = HeadersToKeep; type HeadsToKeep = HeadersToKeep;
type MaxParaHeadSize = MaxRialtoParaHeadSize; type MaxParaHeadDataSize = MaxRialtoParaHeadDataSize;
} }
/// Instance of the with-Westend parachains pallet. /// Instance of the with-Westend parachains pallet.
@@ -547,9 +548,9 @@ impl pallet_bridge_parachains::Config<WithWestendParachainsInstance> for Runtime
type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight<Runtime>; type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight<Runtime>;
type BridgesGrandpaPalletInstance = WestendGrandpaInstance; type BridgesGrandpaPalletInstance = WestendGrandpaInstance;
type ParasPalletName = WestendParasPalletName; type ParasPalletName = WestendParasPalletName;
type TrackedParachains = frame_support::traits::Everything; type ParaStoredHeaderDataBuilder = SingleParaStoredHeaderDataBuilder<bp_westend::Westmint>;
type HeadsToKeep = HeadersToKeep; type HeadsToKeep = HeadersToKeep;
type MaxParaHeadSize = MaxWestendParaHeadSize; type MaxParaHeadDataSize = MaxWestendParaHeadDataSize;
} }
impl pallet_utility::Config for Runtime { impl pallet_utility::Config for Runtime {
@@ -902,28 +903,19 @@ impl_runtime_apis! {
impl bp_westend::WestmintFinalityApi<Block> for Runtime { impl bp_westend::WestmintFinalityApi<Block> for Runtime {
fn best_finalized() -> Option<HeaderId<bp_westend::Hash, bp_westend::BlockNumber>> { fn best_finalized() -> Option<HeaderId<bp_westend::Hash, bp_westend::BlockNumber>> {
// the parachains finality pallet is never decoding parachain heads, so it is pallet_bridge_parachains::Pallet::<
// only done in the integration code
use bp_westend::WESTMINT_PARACHAIN_ID;
let encoded_head = pallet_bridge_parachains::Pallet::<
Runtime, Runtime,
WithWestendParachainsInstance, WithWestendParachainsInstance,
>::best_parachain_head(WESTMINT_PARACHAIN_ID.into())?; >::best_parachain_head_id::<bp_westend::Westmint>().unwrap_or(None)
let head = bp_westend::Header::decode(&mut &encoded_head.0[..]).ok()?;
Some(head.id())
} }
} }
impl bp_rialto_parachain::RialtoParachainFinalityApi<Block> for Runtime { impl bp_rialto_parachain::RialtoParachainFinalityApi<Block> for Runtime {
fn best_finalized() -> Option<HeaderId<bp_rialto::Hash, bp_rialto::BlockNumber>> { fn best_finalized() -> Option<HeaderId<bp_rialto::Hash, bp_rialto::BlockNumber>> {
// the parachains finality pallet is never decoding parachain heads, so it is pallet_bridge_parachains::Pallet::<
// only done in the integration code
let encoded_head = pallet_bridge_parachains::Pallet::<
Runtime, Runtime,
WithRialtoParachainsInstance, WithRialtoParachainsInstance,
>::best_parachain_head(bp_rialto_parachain::RIALTO_PARACHAIN_ID.into())?; >::best_parachain_head_id::<bp_rialto_parachain::RialtoParachain>().unwrap_or(None)
let head = bp_rialto_parachain::Header::decode(&mut &encoded_head.0[..]).ok()?;
Some(head.id())
} }
} }
+1
View File
@@ -30,6 +30,7 @@ sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master",
[dev-dependencies] [dev-dependencies]
bp-header-chain = { path = "../../primitives/header-chain" } bp-header-chain = { path = "../../primitives/header-chain" }
bp-test-utils = { path = "../../primitives/test-utils" } bp-test-utils = { path = "../../primitives/test-utils" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features] [features]
+147 -82
View File
@@ -27,12 +27,10 @@ pub use weights::WeightInfo;
pub use weights_ext::WeightInfoExt; pub use weights_ext::WeightInfoExt;
use bp_header_chain::HeaderChain; use bp_header_chain::HeaderChain;
use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo}; use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo, ParaStoredHeaderData};
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
use bp_runtime::{HashOf, HeaderOf, Parachain, StorageProofError}; use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain, StorageProofError};
use codec::Decode; use frame_support::dispatch::PostDispatchInfo;
use frame_support::{dispatch::PostDispatchInfo, traits::Contains};
use sp_runtime::traits::Header as HeaderT;
use sp_std::{marker::PhantomData, vec::Vec}; use sp_std::{marker::PhantomData, vec::Vec};
// Re-export in crate namespace for `construct_runtime!`. // Re-export in crate namespace for `construct_runtime!`.
@@ -69,7 +67,10 @@ struct UpdateParachainHeadArtifacts {
#[frame_support::pallet] #[frame_support::pallet]
pub mod pallet { pub mod pallet {
use super::*; use super::*;
use bp_parachains::{BestParaHeadHash, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider}; use bp_parachains::{
BestParaHeadHash, ImportedParaHeadsKeyProvider, ParaStoredHeaderDataBuilder,
ParasInfoKeyProvider,
};
use bp_runtime::{ use bp_runtime::{
BasicOperatingMode, BoundedStorageValue, OwnedBridgeModule, StorageDoubleMapKeyProvider, BasicOperatingMode, BoundedStorageValue, OwnedBridgeModule, StorageDoubleMapKeyProvider,
StorageMapKeyProvider, StorageMapKeyProvider,
@@ -77,9 +78,9 @@ pub mod pallet {
use frame_support::pallet_prelude::*; use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
/// Stored parachain head of given parachains pallet. /// Stored parachain head data of given parachains pallet.
pub type StoredParaHeadOf<T, I> = pub type StoredParaHeadDataOf<T, I> =
BoundedStorageValue<<T as Config<I>>::MaxParaHeadSize, ParaHead>; BoundedStorageValue<<T as Config<I>>::MaxParaHeadDataSize, ParaStoredHeaderData>;
/// Weight info of the given parachains pallet. /// Weight info of the given parachains pallet.
pub type WeightInfoOf<T, I> = <T as Config<I>>::WeightInfo; pub type WeightInfoOf<T, I> = <T as Config<I>>::WeightInfo;
@@ -153,12 +154,18 @@ pub mod pallet {
#[pallet::constant] #[pallet::constant]
type ParasPalletName: Get<&'static str>; type ParasPalletName: Get<&'static str>;
/// Set of parachains that are tracked by this pallet. /// Parachain head data builder.
/// ///
/// The set may be extended easily, without requiring any runtime upgrades. Removing tracked /// We never store parachain heads here, since they may be too big (e.g. because of large
/// parachain requires special handling - pruning existing heads and cleaning related data /// digest items). Instead we're using the same approach as `pallet-bridge-grandpa`
/// structures. /// pallet - we are only storing `bp_messages::StoredHeaderData` (number and state root),
type TrackedParachains: Contains<ParaId>; /// which is enough for our applications. However, we work with different parachains here
/// and they can use different primitives (for block numbers and hash). So we can't store
/// it directly. Instead, we're storing `bp_messages::StoredHeaderData` in SCALE-encoded
/// form, wrapping it into `bp_parachains::ParaStoredHeaderData`.
///
/// This builder helps to convert from `HeadData` to `bp_parachains::ParaStoredHeaderData`.
type ParaStoredHeaderDataBuilder: ParaStoredHeaderDataBuilder;
/// Maximal number of single parachain heads to keep in the storage. /// Maximal number of single parachain heads to keep in the storage.
/// ///
@@ -170,16 +177,17 @@ pub mod pallet {
#[pallet::constant] #[pallet::constant]
type HeadsToKeep: Get<u32>; type HeadsToKeep: Get<u32>;
/// Maximal size (in bytes) of the SCALE-encoded parachain head. /// Maximal size (in bytes) of the SCALE-encoded parachain head data
/// (`bp_parachains::ParaStoredHeaderData`).
/// ///
/// Keep in mind that the size of any tracked parachain header must not exceed this value. /// Keep in mind that the size of any tracked parachain header data must not exceed this
/// So if you're going to track multiple parachains, one of which is storing large digests /// value. So if you're going to track multiple parachains, one of which is using large
/// in its headers, you shall choose this maximal value. /// hashes, you shall choose this maximal value.
/// ///
/// There's no mandatory headers in this pallet, so it can't stall if there's some header /// There's no mandatory headers in this pallet, so it can't stall if there's some header
/// that exceeds this bound. /// that exceeds this bound.
#[pallet::constant] #[pallet::constant]
type MaxParaHeadSize: Get<u32>; type MaxParaHeadDataSize: Get<u32>;
} }
/// Optional pallet owner. /// Optional pallet owner.
@@ -212,7 +220,7 @@ pub mod pallet {
<ParasInfoKeyProvider as StorageMapKeyProvider>::Value, <ParasInfoKeyProvider as StorageMapKeyProvider>::Value,
>; >;
/// Parachain heads which have been imported into the pallet. /// State roots of parachain heads which have been imported into the pallet.
#[pallet::storage] #[pallet::storage]
pub type ImportedParaHeads<T: Config<I>, I: 'static = ()> = StorageDoubleMap< pub type ImportedParaHeads<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
_, _,
@@ -220,7 +228,7 @@ pub mod pallet {
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key1, <ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key1,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Hasher2, <ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Hasher2,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key2, <ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key2,
StoredParaHeadOf<T, I>, StoredParaHeadDataOf<T, I>,
>; >;
/// A ring buffer of imported parachain head hashes. Ordered by the insertion time. /// A ring buffer of imported parachain head hashes. Ordered by the insertion time.
@@ -291,17 +299,6 @@ pub mod pallet {
sp_trie::StorageProof::new(parachain_heads_proof.0), sp_trie::StorageProof::new(parachain_heads_proof.0),
move |storage| { move |storage| {
for (parachain, parachain_head_hash) in parachains { for (parachain, parachain_head_hash) in parachains {
// if we're not tracking this parachain, we'll just ignore its head proof here
if !T::TrackedParachains::contains(&parachain) {
log::trace!(
target: LOG_TARGET,
"The head of parachain {:?} has been provided, but it is not tracked by the pallet",
parachain,
);
Self::deposit_event(Event::UntrackedParachainRejected { parachain });
continue;
}
let parachain_head = match Pallet::<T, I>::read_parachain_head(&storage, parachain) { let parachain_head = match Pallet::<T, I>::read_parachain_head(&storage, parachain) {
Ok(Some(parachain_head)) => parachain_head, Ok(Some(parachain_head)) => parachain_head,
Ok(None) => { Ok(None) => {
@@ -349,12 +346,26 @@ pub mod pallet {
continue; continue;
} }
// convert from parachain head into stored parachain head data
let parachain_head_data = match T::ParaStoredHeaderDataBuilder::try_build(parachain, &parachain_head) {
Some(parachain_head_data) => parachain_head_data,
None => {
log::trace!(
target: LOG_TARGET,
"The head of parachain {:?} has been provided, but it is not tracked by the pallet",
parachain,
);
Self::deposit_event(Event::UntrackedParachainRejected { parachain });
continue;
},
};
let update_result: Result<_, ()> = ParasInfo::<T, I>::try_mutate(parachain, |stored_best_head| { let update_result: Result<_, ()> = ParasInfo::<T, I>::try_mutate(parachain, |stored_best_head| {
let artifacts = Pallet::<T, I>::update_parachain_head( let artifacts = Pallet::<T, I>::update_parachain_head(
parachain, parachain,
stored_best_head.take(), stored_best_head.take(),
relay_block_number, relay_block_number,
parachain_head, parachain_head_data,
parachain_head_hash, parachain_head_hash,
)?; )?;
*stored_best_head = Some(artifacts.best_head); *stored_best_head = Some(artifacts.best_head);
@@ -406,14 +417,36 @@ pub mod pallet {
ParasInfo::<T, I>::get(parachain) ParasInfo::<T, I>::get(parachain)
} }
/// Get best finalized header of the given parachain. /// Get best finalized head data of the given parachain.
pub fn best_parachain_head(parachain: ParaId) -> Option<ParaHead> { pub fn best_parachain_head(parachain: ParaId) -> Option<ParaStoredHeaderData> {
let best_para_head_hash = ParasInfo::<T, I>::get(parachain)?.best_head_hash.head_hash; let best_para_head_hash = ParasInfo::<T, I>::get(parachain)?.best_head_hash.head_hash;
ImportedParaHeads::<T, I>::get(parachain, best_para_head_hash).map(|h| h.into_inner()) ImportedParaHeads::<T, I>::get(parachain, best_para_head_hash).map(|h| h.into_inner())
} }
/// Get parachain head with given hash. /// Get best finalized head hash of the given parachain.
pub fn parachain_head(parachain: ParaId, hash: ParaHash) -> Option<ParaHead> { pub fn best_parachain_head_hash(parachain: ParaId) -> Option<ParaHash> {
Some(ParasInfo::<T, I>::get(parachain)?.best_head_hash.head_hash)
}
/// Get best finalized head id of the given parachain.
pub fn best_parachain_head_id<C: Chain<Hash = ParaHash> + Parachain>(
) -> Result<Option<HeaderIdOf<C>>, codec::Error> {
let parachain = ParaId(C::PARACHAIN_ID);
let best_head_hash = match Self::best_parachain_head_hash(parachain) {
Some(best_head_hash) => best_head_hash,
None => return Ok(None),
};
let encoded_head = match Self::parachain_head(parachain, best_head_hash) {
Some(encoded_head) => encoded_head,
None => return Ok(None),
};
encoded_head
.decode_parachain_head_data::<C>()
.map(|data| Some(HeaderId(data.number, best_head_hash)))
}
/// Get parachain head data with given hash.
pub fn parachain_head(parachain: ParaId, hash: ParaHash) -> Option<ParaStoredHeaderData> {
ImportedParaHeads::<T, I>::get(parachain, hash).map(|h| h.into_inner()) ImportedParaHeads::<T, I>::get(parachain, hash).map(|h| h.into_inner())
} }
@@ -480,7 +513,7 @@ pub mod pallet {
parachain: ParaId, parachain: ParaId,
stored_best_head: Option<ParaInfo>, stored_best_head: Option<ParaInfo>,
updated_at_relay_block_number: RelayBlockNumber, updated_at_relay_block_number: RelayBlockNumber,
updated_head: ParaHead, updated_head_data: ParaStoredHeaderData,
updated_head_hash: ParaHash, updated_head_hash: ParaHash,
) -> Result<UpdateParachainHeadArtifacts, ()> { ) -> Result<UpdateParachainHeadArtifacts, ()> {
// check if head has been already updated at better relay chain block. Without this // check if head has been already updated at better relay chain block. Without this
@@ -501,28 +534,29 @@ pub mod pallet {
return Err(()) return Err(())
} }
// verify that the parachain head size is <= `MaxParaHeadSize` // verify that the parachain head data size is <= `MaxParaHeadDataSize`
let updated_head = match StoredParaHeadOf::<T, I>::try_from_inner(updated_head) { let updated_head_data =
Ok(updated_head) => updated_head, match StoredParaHeadDataOf::<T, I>::try_from_inner(updated_head_data) {
Err(e) => { Ok(updated_head_data) => updated_head_data,
log::trace!( Err(e) => {
target: LOG_TARGET, log::trace!(
"{}. The parachain head size for {:?} is {}. It exceeds maximal configured size {}.", target: LOG_TARGET,
err_log_prefix, "{}. The parachain head data size for {:?} is {}. It exceeds maximal configured size {}.",
parachain, err_log_prefix,
e.value_size, parachain,
e.maximal_size, e.value_size,
); e.maximal_size,
);
Self::deposit_event(Event::RejectedLargeParachainHead { Self::deposit_event(Event::RejectedLargeParachainHead {
parachain, parachain,
parachain_head_hash: updated_head_hash, parachain_head_hash: updated_head_hash,
parachain_head_size: e.value_size as _, parachain_head_size: e.value_size as _,
}); });
return Err(()) return Err(())
}, },
}; };
let next_imported_hash_position = stored_best_head let next_imported_hash_position = stored_best_head
.map_or(0, |stored_best_head| stored_best_head.next_imported_hash_position); .map_or(0, |stored_best_head| stored_best_head.next_imported_hash_position);
@@ -543,7 +577,7 @@ pub mod pallet {
next_imported_hash_position, next_imported_hash_position,
updated_head_hash, updated_head_hash,
); );
ImportedParaHeads::<T, I>::insert(parachain, updated_head_hash, updated_head); ImportedParaHeads::<T, I>::insert(parachain, updated_head_hash, updated_head_data);
log::trace!( log::trace!(
target: LOG_TARGET, target: LOG_TARGET,
"Updated head of parachain {:?} to {}", "Updated head of parachain {:?} to {}",
@@ -611,8 +645,8 @@ impl<T: Config<I>, I: 'static, C: Parachain<Hash = ParaHash>> HeaderChain<C>
{ {
fn finalized_header_state_root(hash: HashOf<C>) -> Option<HashOf<C>> { fn finalized_header_state_root(hash: HashOf<C>) -> Option<HashOf<C>> {
Pallet::<T, I>::parachain_head(ParaId(C::PARACHAIN_ID), hash) Pallet::<T, I>::parachain_head(ParaId(C::PARACHAIN_ID), hash)
.and_then(|head| HeaderOf::<C>::decode(&mut &head.0[..]).ok()) .and_then(|head| head.decode_parachain_head_data::<C>().ok())
.map(|h| *h.state_root()) .map(|h| h.state_root)
} }
} }
@@ -620,8 +654,9 @@ impl<T: Config<I>, I: 'static, C: Parachain<Hash = ParaHash>> HeaderChain<C>
mod tests { mod tests {
use super::*; use super::*;
use crate::mock::{ use crate::mock::{
run_test, test_relay_header, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime, run_test, test_relay_header, BigParachainHeader, RegularParachainHasher,
MAXIMAL_PARACHAIN_HEAD_SIZE, PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID, RegularParachainHeader, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime,
PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID,
}; };
use codec::Encode; use codec::Encode;
@@ -641,7 +676,8 @@ mod tests {
weights::Weight, weights::Weight,
}; };
use frame_system::{EventRecord, Pallet as System, Phase}; use frame_system::{EventRecord, Pallet as System, Phase};
use sp_runtime::DispatchError; use sp_core::Hasher;
use sp_runtime::{traits::Header as HeaderT, DispatchError};
use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut}; use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut};
type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1; type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
@@ -716,12 +752,42 @@ mod tests {
} }
fn head_data(parachain: u32, head_number: u32) -> ParaHead { fn head_data(parachain: u32, head_number: u32) -> ParaHead {
ParaHead((parachain, head_number).encode()) ParaHead(
RegularParachainHeader::new(
head_number as _,
Default::default(),
RegularParachainHasher::hash(&(parachain, head_number).encode()),
Default::default(),
Default::default(),
)
.encode(),
)
} }
fn large_head_data(parachain: u32, head_number: u32) -> ParaHead { fn stored_head_data(parachain: u32, head_number: u32) -> ParaStoredHeaderData {
ParaStoredHeaderData(
(head_number as u64, RegularParachainHasher::hash(&(parachain, head_number).encode()))
.encode(),
)
}
fn big_head_data(parachain: u32, head_number: u32) -> ParaHead {
ParaHead( ParaHead(
(parachain, head_number, vec![42u8; MAXIMAL_PARACHAIN_HEAD_SIZE as usize]).encode(), BigParachainHeader::new(
head_number as _,
Default::default(),
RegularParachainHasher::hash(&(parachain, head_number).encode()),
Default::default(),
Default::default(),
)
.encode(),
)
}
fn big_stored_head_data(parachain: u32, head_number: u32) -> ParaStoredHeaderData {
ParaStoredHeaderData(
(head_number as u128, RegularParachainHasher::hash(&(parachain, head_number).encode()))
.encode(),
) )
} }
@@ -823,7 +889,7 @@ mod tests {
initial_best_head(1).best_head_hash.head_hash initial_best_head(1).best_head_hash.head_hash
) )
.map(|h| h.into_inner()), .map(|h| h.into_inner()),
Some(head_data(1, 0)) Some(stored_head_data(1, 0))
); );
assert_eq!( assert_eq!(
ImportedParaHeads::<TestRuntime>::get( ImportedParaHeads::<TestRuntime>::get(
@@ -836,7 +902,7 @@ mod tests {
assert_eq!( assert_eq!(
ImportedParaHeads::<TestRuntime>::get(ParaId(3), head_hash(3, 10)) ImportedParaHeads::<TestRuntime>::get(ParaId(3), head_hash(3, 10))
.map(|h| h.into_inner()), .map(|h| h.into_inner()),
Some(head_data(3, 10)) Some(stored_head_data(3, 10))
); );
assert_eq!( assert_eq!(
@@ -886,7 +952,7 @@ mod tests {
assert_eq!( assert_eq!(
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 5).hash()) ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 5).hash())
.map(|h| h.into_inner()), .map(|h| h.into_inner()),
Some(head_data(1, 5)) Some(stored_head_data(1, 5))
); );
assert_eq!( assert_eq!(
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 10).hash()) ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 10).hash())
@@ -921,12 +987,12 @@ mod tests {
assert_eq!( assert_eq!(
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 5).hash()) ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 5).hash())
.map(|h| h.into_inner()), .map(|h| h.into_inner()),
Some(head_data(1, 5)) Some(stored_head_data(1, 5))
); );
assert_eq!( assert_eq!(
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 10).hash()) ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 10).hash())
.map(|h| h.into_inner()), .map(|h| h.into_inner()),
Some(head_data(1, 10)) Some(stored_head_data(1, 10))
); );
assert_eq!( assert_eq!(
System::<TestRuntime>::events(), System::<TestRuntime>::events(),
@@ -1153,10 +1219,9 @@ mod tests {
#[test] #[test]
fn does_nothing_when_parachain_head_is_too_large() { fn does_nothing_when_parachain_head_is_too_large() {
let (state_root, proof, parachains) = let (state_root, proof, parachains) =
prepare_parachain_heads_proof(vec![(1, head_data(1, 5)), (2, large_head_data(1, 5))]); prepare_parachain_heads_proof(vec![(1, head_data(1, 5)), (4, big_head_data(1, 5))]);
run_test(|| { run_test(|| {
// start with relay block #0 and try to import head#5 of parachain#1 and untracked // start with relay block #0 and try to import head#5 of parachain#1 and big parachain
// parachain
initialize(state_root); initialize(state_root);
let result = Pallet::<TestRuntime>::submit_parachain_heads( let result = Pallet::<TestRuntime>::submit_parachain_heads(
RuntimeOrigin::signed(1), RuntimeOrigin::signed(1),
@@ -1175,7 +1240,7 @@ mod tests {
next_imported_hash_position: 1, next_imported_hash_position: 1,
}) })
); );
assert_eq!(ParasInfo::<TestRuntime>::get(ParaId(2)), None); assert_eq!(ParasInfo::<TestRuntime>::get(ParaId(4)), None);
assert_eq!( assert_eq!(
System::<TestRuntime>::events(), System::<TestRuntime>::events(),
vec![ vec![
@@ -1190,9 +1255,9 @@ mod tests {
EventRecord { EventRecord {
phase: Phase::Initialization, phase: Phase::Initialization,
event: TestEvent::Parachains(Event::RejectedLargeParachainHead { event: TestEvent::Parachains(Event::RejectedLargeParachainHead {
parachain: ParaId(2), parachain: ParaId(4),
parachain_head_hash: large_head_data(1, 5).hash(), parachain_head_hash: big_head_data(1, 5).hash(),
parachain_head_size: large_head_data(1, 5).encoded_size() as u32, parachain_head_size: big_stored_head_data(1, 5).encoded_size() as u32,
}), }),
topics: vec![], topics: vec![],
}, },
@@ -1294,7 +1359,7 @@ mod tests {
import_parachain_1_head(0, state_root_5, parachains_5, proof_5).expect("ok"); import_parachain_1_head(0, state_root_5, parachains_5, proof_5).expect("ok");
assert_eq!( assert_eq!(
Pallet::<TestRuntime>::best_parachain_head(ParaId(1)), Pallet::<TestRuntime>::best_parachain_head(ParaId(1)),
Some(head_data(1, 5)) Some(stored_head_data(1, 5))
); );
// then if someone is pretending to provide updated head#10 of parachain#1 at relay // then if someone is pretending to provide updated head#10 of parachain#1 at relay
@@ -1310,7 +1375,7 @@ mod tests {
),); ),);
assert_eq!( assert_eq!(
Pallet::<TestRuntime>::best_parachain_head(ParaId(1)), Pallet::<TestRuntime>::best_parachain_head(ParaId(1)),
Some(head_data(1, 5)) Some(stored_head_data(1, 5))
); );
// then if someone is pretending to provide updated head#10 of parachain#1 at relay // then if someone is pretending to provide updated head#10 of parachain#1 at relay
@@ -1326,7 +1391,7 @@ mod tests {
),); ),);
assert_eq!( assert_eq!(
Pallet::<TestRuntime>::best_parachain_head(ParaId(1)), Pallet::<TestRuntime>::best_parachain_head(ParaId(1)),
Some(head_data(1, 10)) Some(stored_head_data(1, 10))
); );
}); });
} }
+109 -11
View File
@@ -15,16 +15,12 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use bp_polkadot_core::parachains::ParaId; use bp_polkadot_core::parachains::ParaId;
use bp_runtime::Chain; use bp_runtime::{Chain, Parachain};
use frame_support::{ use frame_support::{construct_runtime, parameter_types, traits::ConstU32, weights::Weight};
construct_runtime, parameter_types,
traits::{ConstU32, IsInVec},
weights::Weight,
};
use sp_runtime::{ use sp_runtime::{
testing::{Header, H256}, testing::{Header, H256},
traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, traits::{BlakeTwo256, Header as HeaderT, IdentityLookup},
Perbill, MultiSignature, Perbill,
}; };
use crate as pallet_bridge_parachains; use crate as pallet_bridge_parachains;
@@ -40,7 +36,109 @@ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRunt
pub const PARAS_PALLET_NAME: &str = "Paras"; pub const PARAS_PALLET_NAME: &str = "Paras";
pub const UNTRACKED_PARACHAIN_ID: u32 = 10; pub const UNTRACKED_PARACHAIN_ID: u32 = 10;
pub const MAXIMAL_PARACHAIN_HEAD_SIZE: u32 = 512; // use exact expected encoded size: `vec_len_size + header_number_size + state_root_hash_size`
pub const MAXIMAL_PARACHAIN_HEAD_DATA_SIZE: u32 = 1 + 8 + 32;
pub type RegularParachainHeader = sp_runtime::testing::Header;
pub type RegularParachainHasher = BlakeTwo256;
pub type BigParachainHeader = sp_runtime::generic::Header<u128, BlakeTwo256>;
pub struct Parachain1;
impl Chain for Parachain1 {
type BlockNumber = u64;
type Hash = H256;
type Hasher = RegularParachainHasher;
type Header = RegularParachainHeader;
type AccountId = u64;
type Balance = u64;
type Index = u64;
type Signature = MultiSignature;
fn max_extrinsic_size() -> u32 {
0
}
fn max_extrinsic_weight() -> Weight {
Weight::zero()
}
}
impl Parachain for Parachain1 {
const PARACHAIN_ID: u32 = 1;
}
pub struct Parachain2;
impl Chain for Parachain2 {
type BlockNumber = u64;
type Hash = H256;
type Hasher = RegularParachainHasher;
type Header = RegularParachainHeader;
type AccountId = u64;
type Balance = u64;
type Index = u64;
type Signature = MultiSignature;
fn max_extrinsic_size() -> u32 {
0
}
fn max_extrinsic_weight() -> Weight {
Weight::zero()
}
}
impl Parachain for Parachain2 {
const PARACHAIN_ID: u32 = 2;
}
pub struct Parachain3;
impl Chain for Parachain3 {
type BlockNumber = u64;
type Hash = H256;
type Hasher = RegularParachainHasher;
type Header = RegularParachainHeader;
type AccountId = u64;
type Balance = u64;
type Index = u64;
type Signature = MultiSignature;
fn max_extrinsic_size() -> u32 {
0
}
fn max_extrinsic_weight() -> Weight {
Weight::zero()
}
}
impl Parachain for Parachain3 {
const PARACHAIN_ID: u32 = 3;
}
// this parachain is using u128 as block number and stored head data size exceeds limit
pub struct BigParachain;
impl Chain for BigParachain {
type BlockNumber = u128;
type Hash = H256;
type Hasher = RegularParachainHasher;
type Header = BigParachainHeader;
type AccountId = u64;
type Balance = u64;
type Index = u64;
type Signature = MultiSignature;
fn max_extrinsic_size() -> u32 {
0
}
fn max_extrinsic_weight() -> Weight {
Weight::zero()
}
}
impl Parachain for BigParachain {
const PARACHAIN_ID: u32 = 4;
}
construct_runtime! { construct_runtime! {
pub enum TestRuntime where pub enum TestRuntime where
@@ -68,7 +166,7 @@ impl frame_system::Config for TestRuntime {
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
type BlockNumber = TestNumber; type BlockNumber = TestNumber;
type Hash = H256; type Hash = H256;
type Hashing = BlakeTwo256; type Hashing = RegularParachainHasher;
type AccountId = AccountId; type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>; type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header; type Header = Header;
@@ -122,9 +220,9 @@ impl pallet_bridge_parachains::Config for TestRuntime {
type WeightInfo = (); type WeightInfo = ();
type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1; type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
type ParasPalletName = ParasPalletName; type ParasPalletName = ParasPalletName;
type TrackedParachains = IsInVec<GetTenFirstParachains>; type ParaStoredHeaderDataBuilder = (Parachain1, Parachain2, Parachain3, BigParachain);
type HeadsToKeep = HeadsToKeep; type HeadsToKeep = HeadsToKeep;
type MaxParaHeadSize = frame_support::traits::ConstU32<MAXIMAL_PARACHAIN_HEAD_SIZE>; type MaxParaHeadDataSize = frame_support::traits::ConstU32<MAXIMAL_PARACHAIN_HEAD_DATA_SIZE>;
} }
#[derive(Debug)] #[derive(Debug)]
+6 -2
View File
@@ -70,8 +70,12 @@ pub const SESSION_LENGTH: BlockNumber = 4;
/// Maximal number of GRANDPA authorities at Rialto. /// Maximal number of GRANDPA authorities at Rialto.
pub const MAX_AUTHORITIES_COUNT: u32 = 5; pub const MAX_AUTHORITIES_COUNT: u32 = 5;
/// Maximal SCALE-encoded size of parachains headers that are stored at Rialto `Paras` pallet. /// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Rialto
pub const MAX_NESTED_PARACHAIN_HEAD_SIZE: u32 = 1024; /// parachains.
///
/// It includes the block number and state root, so it shall be near 40 bytes, but let's have some
/// reserve.
pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
/// Re-export `time_units` to make usage easier. /// Re-export `time_units` to make usage easier.
pub use time_units::*; pub use time_units::*;
+5 -5
View File
@@ -35,12 +35,12 @@ pub const PARAS_PALLET_NAME: &str = "Paras";
/// Name of the With-Rococo GRANDPA pallet instance that is deployed at bridged chains. /// Name of the With-Rococo GRANDPA pallet instance that is deployed at bridged chains.
pub const WITH_ROCOCO_GRANDPA_PALLET_NAME: &str = "BridgeRococoGrandpa"; pub const WITH_ROCOCO_GRANDPA_PALLET_NAME: &str = "BridgeRococoGrandpa";
/// Maximal SCALE-encoded size of parachains headers that are stored at Rococo `Paras` pallet. /// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Rococo
/// parachains.
/// ///
/// Let's assume that the largest header is header that enacts new authorities set with /// It includes the block number and state root, so it shall be near 40 bytes, but let's have some
/// `MAX_AUTHORITES_COUNT`. Every authority means 32-byte key and 8-byte weight. Let's also have /// reserve.
/// some fixed reserve for other things (digest, block hash and number, ...) as well. pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
pub const MAX_NESTED_PARACHAIN_HEAD_SIZE: u32 = 4096 + MAX_AUTHORITIES_COUNT * 40;
/// Maximal number of GRANDPA authorities at Rococo. /// Maximal number of GRANDPA authorities at Rococo.
/// ///
@@ -15,6 +15,7 @@ bp-runtime = { path = "../runtime", default-features = false }
# Substrate Based Dependencies # Substrate Based Dependencies
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
[features] [features]
@@ -22,5 +23,6 @@ default = ["std"]
std = [ std = [
"bp-polkadot-core/std", "bp-polkadot-core/std",
"bp-runtime/std", "bp-runtime/std",
"frame-support/std",
"sp-api/std", "sp-api/std",
] ]
+35 -5
View File
@@ -19,11 +19,42 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
pub use bp_polkadot_core::*; pub use bp_polkadot_core::*;
use bp_runtime::decl_bridge_finality_runtime_apis; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, Parachain};
use frame_support::weights::Weight;
/// Westend Chain /// Westend Chain
pub type Westend = PolkadotLike; pub type Westend = PolkadotLike;
/// Westmint parachain definition
#[derive(Debug, Clone, Copy)]
pub struct Westmint;
// Westmint seems to use the same configuration as all Polkadot-like chains, so we'll use Westend
// primitives here.
impl Chain for Westmint {
type BlockNumber = BlockNumber;
type Hash = Hash;
type Hasher = Hasher;
type Header = Header;
type AccountId = AccountId;
type Balance = Balance;
type Index = Nonce;
type Signature = Signature;
fn max_extrinsic_size() -> u32 {
Westend::max_extrinsic_size()
}
fn max_extrinsic_weight() -> Weight {
Westend::max_extrinsic_weight()
}
}
impl Parachain for Westmint {
const PARACHAIN_ID: u32 = WESTMINT_PARACHAIN_ID;
}
/// Name of the parachains pallet at the Westend runtime. /// Name of the parachains pallet at the Westend runtime.
pub const PARAS_PALLET_NAME: &str = "Paras"; pub const PARAS_PALLET_NAME: &str = "Paras";
@@ -39,10 +70,9 @@ pub const MAX_AUTHORITIES_COUNT: u32 = 100_000;
/// Maximal SCALE-encoded size of parachains headers that are stored at Westend `Paras` pallet. /// Maximal SCALE-encoded size of parachains headers that are stored at Westend `Paras` pallet.
/// ///
/// Let's assume that the largest header is header that enacts new authorities set with /// It includes the block number and state root, so it shall be near 40 bytes, but let's have some
/// `MAX_AUTHORITES_COUNT`. Every authority means 32-byte key and 8-byte weight. Let's also have /// reserve.
/// some fixed reserve for other things (digest, block hash and number, ...) as well. pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
pub const MAX_NESTED_PARACHAIN_HEAD_SIZE: u32 = 4096 + MAX_AUTHORITIES_COUNT * 40;
/// Identifier of Westmint parachain at the Westend relay chain. /// Identifier of Westmint parachain at the Westend relay chain.
pub const WESTMINT_PARACHAIN_ID: u32 = 2000; pub const WESTMINT_PARACHAIN_ID: u32 = 2000;
+1 -1
View File
@@ -20,7 +20,7 @@
pub use bp_polkadot_core::*; pub use bp_polkadot_core::*;
pub use bp_rococo::{ pub use bp_rococo::{
SS58Prefix, MAX_AUTHORITIES_COUNT, MAX_NESTED_PARACHAIN_HEAD_SIZE, PARAS_PALLET_NAME, SS58Prefix, MAX_AUTHORITIES_COUNT, MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE, PARAS_PALLET_NAME,
}; };
use bp_runtime::decl_bridge_finality_runtime_apis; use bp_runtime::decl_bridge_finality_runtime_apis;
+7
View File
@@ -8,10 +8,12 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies] [dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] }
impl-trait-for-tuples = "0.2"
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
# Bridge dependencies # Bridge dependencies
bp-header-chain = { path = "../header-chain", default-features = false }
bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false }
bp-runtime = { path = "../runtime", default-features = false } bp-runtime = { path = "../runtime", default-features = false }
@@ -19,14 +21,19 @@ bp-runtime = { path = "../runtime", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
[features] [features]
default = ["std"] default = ["std"]
std = [ std = [
"bp-header-chain/std",
"bp-polkadot-core/std", "bp-polkadot-core/std",
"bp-runtime/std", "bp-runtime/std",
"codec/std", "codec/std",
"frame-support/std", "frame-support/std",
"scale-info/std", "scale-info/std",
"sp-core/std", "sp-core/std",
"sp-runtime/std",
"sp-std/std",
] ]
+64 -2
View File
@@ -18,15 +18,22 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
pub use bp_header_chain::StoredHeaderData;
use bp_polkadot_core::{ use bp_polkadot_core::{
parachains::{ParaHash, ParaHead, ParaId}, parachains::{ParaHash, ParaHead, ParaId},
BlockNumber as RelayBlockNumber, BlockNumber as RelayBlockNumber,
}; };
use bp_runtime::{StorageDoubleMapKeyProvider, StorageMapKeyProvider}; use bp_runtime::{
BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider,
StorageMapKeyProvider,
};
use codec::{Decode, Encode, MaxEncodedLen}; use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat}; use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat};
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_core::storage::StorageKey; use sp_core::storage::StorageKey;
use sp_runtime::traits::Header as HeaderT;
use sp_std::{marker::PhantomData, prelude::*};
/// Best known parachain head hash. /// Best known parachain head hash.
#[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] #[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
@@ -86,5 +93,60 @@ impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider {
type Key1 = ParaId; type Key1 = ParaId;
type Hasher2 = Blake2_128Concat; type Hasher2 = Blake2_128Concat;
type Key2 = ParaHash; type Key2 = ParaHash;
type Value = ParaHead; type Value = ParaStoredHeaderData;
}
/// Stored data of the parachain head. It is encoded version of the
/// `bp_runtime::StoredHeaderData` structure.
///
/// We do not know exact structure of the parachain head, so we always store encoded version
/// of the `bp_runtime::StoredHeaderData`. It is only decoded when we talk about specific parachain.
#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
pub struct ParaStoredHeaderData(pub Vec<u8>);
impl ParaStoredHeaderData {
/// Decode stored parachain head data.
pub fn decode_parachain_head_data<C: Chain>(
&self,
) -> Result<StoredHeaderData<BlockNumberOf<C>, HashOf<C>>, codec::Error> {
StoredHeaderData::<BlockNumberOf<C>, HashOf<C>>::decode(&mut &self.0[..])
}
}
/// Stored parachain head data builder.
pub trait ParaStoredHeaderDataBuilder {
/// Try to build head data from self.
fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option<ParaStoredHeaderData>;
}
/// Helper for using single parachain as `ParaStoredHeaderDataBuilder`.
pub struct SingleParaStoredHeaderDataBuilder<C: Parachain>(PhantomData<C>);
impl<C: Parachain> ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBuilder<C> {
fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option<ParaStoredHeaderData> {
if para_id == ParaId(C::PARACHAIN_ID) {
let header = HeaderOf::<C>::decode(&mut &para_head.0[..]).ok()?;
return Some(ParaStoredHeaderData(
StoredHeaderData { number: *header.number(), state_root: *header.state_root() }
.encode(),
))
}
None
}
}
// Tries to build header data from each tuple member, short-circuiting on first successful one.
#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
#[tuple_types_custom_trait_bound(Parachain)]
impl ParaStoredHeaderDataBuilder for C {
fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option<ParaStoredHeaderData> {
for_tuples!( #(
let maybe_para_head = SingleParaStoredHeaderDataBuilder::<C>::try_build(para_id, para_head);
if let Some(maybe_para_head) = maybe_para_head {
return Some(maybe_para_head);
}
)* );
None
}
} }
@@ -66,9 +66,7 @@ impl From<u32> for ParaId {
/// ///
/// This is an equivalent of the `polkadot_parachain::HeadData`. /// This is an equivalent of the `polkadot_parachain::HeadData`.
/// ///
/// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header. Keep in mind /// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header.
/// that in Polkadot it is twice-encoded (so `header.encode().encode()`). We'll also do it to keep
/// it binary-compatible (implies hash-compatibility) with other parachain pallets.
#[derive( #[derive(
PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default, PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default,
)] )]
+1 -4
View File
@@ -111,10 +111,7 @@ pub trait Chain: Send + Sync + 'static {
+ AsPrimitive<usize> + AsPrimitive<usize>
+ Default + Default
+ Saturating + Saturating
+ MaxEncodedLen + MaxEncodedLen;
// original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but
// `sp_runtime::generic::Era` requires block number -> `u64` conversion.
+ Into<u64>;
/// A type that fulfills the abstract idea of what a Substrate hash is. /// A type that fulfills the abstract idea of what a Substrate hash is.
// Constraits come from the associated Hash type of `sp_runtime::traits::Header` // Constraits come from the associated Hash type of `sp_runtime::traits::Header`
+10 -3
View File
@@ -27,7 +27,7 @@ use frame_system::RawOrigin;
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_core::{hash::H256, storage::StorageKey}; use sp_core::{hash::H256, storage::StorageKey};
use sp_io::hashing::blake2_256; use sp_io::hashing::blake2_256;
use sp_runtime::traits::{BadOrigin, Header as HeaderT}; use sp_runtime::traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto};
use sp_std::{convert::TryFrom, fmt::Debug, vec, vec::Vec}; use sp_std::{convert::TryFrom, fmt::Debug, vec, vec::Vec};
pub use chain::{ pub use chain::{
@@ -124,6 +124,9 @@ impl<Hash: Copy, Number: Copy> HeaderId<Hash, Number> {
} }
} }
/// Header id used by the chain.
pub type HeaderIdOf<C> = HeaderId<HashOf<C>, BlockNumberOf<C>>;
/// Generic header id provider. /// Generic header id provider.
pub trait HeaderIdProvider<Header: HeaderT> { pub trait HeaderIdProvider<Header: HeaderT> {
// Get the header id. // Get the header id.
@@ -225,7 +228,9 @@ pub enum TransactionEra<BlockNumber, BlockHash> {
Mortal(HeaderId<BlockHash, BlockNumber>, u32), Mortal(HeaderId<BlockHash, BlockNumber>, u32),
} }
impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber, BlockHash> { impl<BlockNumber: Copy + UniqueSaturatedInto<u64>, BlockHash: Copy>
TransactionEra<BlockNumber, BlockHash>
{
/// Prepare transaction era, based on mortality period and current best block number. /// Prepare transaction era, based on mortality period and current best block number.
pub fn new( pub fn new(
best_block_id: HeaderId<BlockHash, BlockNumber>, best_block_id: HeaderId<BlockHash, BlockNumber>,
@@ -253,8 +258,10 @@ impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber,
pub fn frame_era(&self) -> sp_runtime::generic::Era { pub fn frame_era(&self) -> sp_runtime::generic::Era {
match *self { match *self {
TransactionEra::Immortal => sp_runtime::generic::Era::immortal(), TransactionEra::Immortal => sp_runtime::generic::Era::immortal(),
// `unique_saturated_into` is fine here - mortality `u64::MAX` is not something we
// expect to see on any chain
TransactionEra::Mortal(header_id, period) => TransactionEra::Mortal(header_id, period) =>
sp_runtime::generic::Era::mortal(period as _, header_id.0.into()), sp_runtime::generic::Era::mortal(period as _, header_id.0.unique_saturated_into()),
} }
} }
+2 -5
View File
@@ -44,13 +44,10 @@ pub use crate::{
transaction_tracker::TransactionTracker, transaction_tracker::TransactionTracker,
}; };
pub use bp_runtime::{ pub use bp_runtime::{
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderOf, AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderIdOf,
IndexOf, SignatureOf, TransactionEra, TransactionEraOf, HeaderOf, IndexOf, SignatureOf, TransactionEra, TransactionEraOf,
}; };
/// Header id used by the chain.
pub type HeaderIdOf<C> = relay_utils::HeaderId<HashOf<C>, BlockNumberOf<C>>;
/// Substrate-over-websocket connection params. /// Substrate-over-websocket connection params.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ConnectionParams { pub struct ConnectionParams {
@@ -16,7 +16,10 @@
//! Metrics for headers synchronization relay loop. //! Metrics for headers synchronization relay loop.
use relay_utils::metrics::{metric_name, register, IntGauge, Metric, PrometheusError, Registry}; use relay_utils::{
metrics::{metric_name, register, IntGauge, Metric, PrometheusError, Registry},
UniqueSaturatedInto,
};
/// Headers sync metrics. /// Headers sync metrics.
#[derive(Clone)] #[derive(Clone)]
@@ -61,13 +64,19 @@ impl SyncLoopMetrics {
} }
/// Update best block number at source. /// Update best block number at source.
pub fn update_best_block_at_source<Number: Into<u64>>(&self, source_best_number: Number) { pub fn update_best_block_at_source<Number: UniqueSaturatedInto<u64>>(
self.best_source_block_number.set(source_best_number.into()); &self,
source_best_number: Number,
) {
self.best_source_block_number.set(source_best_number.unique_saturated_into());
} }
/// Update best block number at target. /// Update best block number at target.
pub fn update_best_block_at_target<Number: Into<u64>>(&self, target_best_number: Number) { pub fn update_best_block_at_target<Number: UniqueSaturatedInto<u64>>(
self.best_target_block_number.set(target_best_number.into()); &self,
target_best_number: Number,
) {
self.best_target_block_number.set(target_best_number.unique_saturated_into());
} }
/// Update using-same-fork flag. /// Update using-same-fork flag.
@@ -33,12 +33,10 @@ use parachains_relay::{
}; };
use relay_substrate_client::{ use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf,
HeaderIdOf, HeaderOf, RelayChain, SignParam, TransactionEra, TransactionTracker, HeaderIdOf, RelayChain, SignParam, TransactionEra, TransactionTracker, UnsignedTransaction,
UnsignedTransaction,
}; };
use relay_utils::{relay_loop::Client as RelayClient, HeaderId}; use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
use sp_core::{Bytes, Pair}; use sp_core::{Bytes, Pair};
use sp_runtime::traits::Header as HeaderT;
/// Substrate client as parachain heads source. /// Substrate client as parachain heads source.
pub struct ParachainsTarget<P: SubstrateParachainsPipeline> { pub struct ParachainsTarget<P: SubstrateParachainsPipeline> {
@@ -132,7 +130,7 @@ where
.map(|para_info| para_info.best_head_hash); .map(|para_info| para_info.best_head_hash);
if let (Some(metrics), Some(best_para_head_hash)) = (metrics, &best_para_head_hash) { if let (Some(metrics), Some(best_para_head_hash)) = (metrics, &best_para_head_hash) {
let imported_para_head = self let imported_para_head_number = self
.client .client
.storage_double_map_value::<ImportedParaHeadsKeyProvider>( .storage_double_map_value::<ImportedParaHeadsKeyProvider>(
P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME, P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME,
@@ -142,10 +140,11 @@ where
) )
.await .await
.and_then(|maybe_encoded_head| match maybe_encoded_head { .and_then(|maybe_encoded_head| match maybe_encoded_head {
Some(encoded_head) => Some(encoded_head) => encoded_head
HeaderOf::<P::SourceParachain>::decode(&mut &encoded_head.0[..]) .decode_parachain_head_data::<P::SourceParachain>()
.map(Some) .map(|head| head.number)
.map_err(Self::Error::ResponseParseFailed), .map(Some)
.map_err(Self::Error::ResponseParseFailed),
None => Ok(None), None => Ok(None),
}) })
.map_err(|e| { .map_err(|e| {
@@ -159,9 +158,8 @@ where
e e
}) })
.unwrap_or(None); .unwrap_or(None);
if let Some(imported_para_head) = imported_para_head { if let Some(imported_para_head_number) = imported_para_head_number {
metrics metrics.update_best_parachain_block_at_target(para_id, imported_para_head_number);
.update_best_parachain_block_at_target(para_id, *imported_para_head.number());
} }
} }
+6 -8
View File
@@ -65,10 +65,9 @@ impl MessageLaneLoopMetrics {
/// Update source client state metrics. /// Update source client state metrics.
pub fn update_source_state<P: MessageLane>(&self, source_client_state: SourceClientState<P>) { pub fn update_source_state<P: MessageLane>(&self, source_client_state: SourceClientState<P>) {
self.source_to_target_finality_metrics self.source_to_target_finality_metrics
.update_best_block_at_source(source_client_state.best_self.0.into()); .update_best_block_at_source(source_client_state.best_self.0);
self.target_to_source_finality_metrics.update_best_block_at_target( self.target_to_source_finality_metrics
source_client_state.best_finalized_peer_at_best_self.0.into(), .update_best_block_at_target(source_client_state.best_finalized_peer_at_best_self.0);
);
self.target_to_source_finality_metrics.update_using_same_fork( self.target_to_source_finality_metrics.update_using_same_fork(
source_client_state.best_finalized_peer_at_best_self.1 == source_client_state.best_finalized_peer_at_best_self.1 ==
source_client_state.actual_best_finalized_peer_at_best_self.1, source_client_state.actual_best_finalized_peer_at_best_self.1,
@@ -78,10 +77,9 @@ impl MessageLaneLoopMetrics {
/// Update target client state metrics. /// Update target client state metrics.
pub fn update_target_state<P: MessageLane>(&self, target_client_state: TargetClientState<P>) { pub fn update_target_state<P: MessageLane>(&self, target_client_state: TargetClientState<P>) {
self.target_to_source_finality_metrics self.target_to_source_finality_metrics
.update_best_block_at_source(target_client_state.best_self.0.into()); .update_best_block_at_source(target_client_state.best_self.0);
self.source_to_target_finality_metrics.update_best_block_at_target( self.source_to_target_finality_metrics
target_client_state.best_finalized_peer_at_best_self.0.into(), .update_best_block_at_target(target_client_state.best_finalized_peer_at_best_self.0);
);
self.source_to_target_finality_metrics.update_using_same_fork( self.source_to_target_finality_metrics.update_using_same_fork(
target_client_state.best_finalized_peer_at_best_self.1 == target_client_state.best_finalized_peer_at_best_self.1 ==
target_client_state.actual_best_finalized_peer_at_best_self.1, target_client_state.actual_best_finalized_peer_at_best_self.1,
@@ -15,8 +15,9 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use bp_polkadot_core::parachains::ParaId; use bp_polkadot_core::parachains::ParaId;
use relay_utils::metrics::{ use relay_utils::{
metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, metrics::{metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64},
UniqueSaturatedInto,
}; };
/// Parachains sync metrics. /// Parachains sync metrics.
@@ -50,12 +51,12 @@ impl ParachainsLoopMetrics {
} }
/// Update best block number at source. /// Update best block number at source.
pub fn update_best_parachain_block_at_source<Number: Into<u64>>( pub fn update_best_parachain_block_at_source<Number: UniqueSaturatedInto<u64>>(
&self, &self,
parachain: ParaId, parachain: ParaId,
block_number: Number, block_number: Number,
) { ) {
let block_number = block_number.into(); let block_number = block_number.unique_saturated_into();
let label = parachain_label(&parachain); let label = parachain_label(&parachain);
log::trace!( log::trace!(
target: "bridge-metrics", target: "bridge-metrics",
@@ -67,12 +68,12 @@ impl ParachainsLoopMetrics {
} }
/// Update best block number at target. /// Update best block number at target.
pub fn update_best_parachain_block_at_target<Number: Into<u64>>( pub fn update_best_parachain_block_at_target<Number: UniqueSaturatedInto<u64>>(
&self, &self,
parachain: ParaId, parachain: ParaId,
block_number: Number, block_number: Number,
) { ) {
let block_number = block_number.into(); let block_number = block_number.unique_saturated_into();
let label = parachain_label(&parachain); let label = parachain_label(&parachain);
log::trace!( log::trace!(
target: "bridge-metrics", target: "bridge-metrics",
+1
View File
@@ -29,4 +29,5 @@ bp-runtime = { path = "../../primitives/runtime" }
# Substrate dependencies # Substrate dependencies
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
+3 -2
View File
@@ -19,6 +19,7 @@
pub use bp_runtime::HeaderId; pub use bp_runtime::HeaderId;
pub use error::Error; pub use error::Error;
pub use relay_loop::{relay_loop, relay_metrics}; pub use relay_loop::{relay_loop, relay_metrics};
pub use sp_runtime::traits::UniqueSaturatedInto;
use async_trait::async_trait; use async_trait::async_trait;
use backoff::{backoff::Backoff, ExponentialBackoff}; use backoff::{backoff::Backoff, ExponentialBackoff};
@@ -51,7 +52,7 @@ pub mod relay_loop;
pub trait BlockNumberBase: pub trait BlockNumberBase:
'static 'static
+ From<u32> + From<u32>
+ Into<u64> + UniqueSaturatedInto<u64>
+ Ord + Ord
+ Clone + Clone
+ Copy + Copy
@@ -73,7 +74,7 @@ pub trait BlockNumberBase:
impl<T> BlockNumberBase for T where impl<T> BlockNumberBase for T where
T: 'static T: 'static
+ From<u32> + From<u32>
+ Into<u64> + UniqueSaturatedInto<u64>
+ Ord + Ord
+ Clone + Clone
+ Copy + Copy