mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 17:31:03 +00:00
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:
committed by
Bastian Köcher
parent
2c5e2f09eb
commit
d63a75697c
@@ -16,6 +16,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
|
||||
|
||||
bp-messages = { path = "../../../primitives/messages", 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-relayers = { path = "../../../primitives/relayers", default-features = false }
|
||||
bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false }
|
||||
@@ -84,6 +85,7 @@ std = [
|
||||
"beefy-primitives/std",
|
||||
"bp-messages/std",
|
||||
"bp-millau/std",
|
||||
"bp-parachains/std",
|
||||
"bp-polkadot-core/std",
|
||||
"bp-relayers/std",
|
||||
"bp-rialto/std",
|
||||
|
||||
@@ -33,8 +33,8 @@ pub mod rialto_parachain_messages;
|
||||
pub mod xcm_config;
|
||||
|
||||
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
|
||||
use bp_runtime::{HeaderId, HeaderIdProvider};
|
||||
use codec::Decode;
|
||||
use bp_parachains::SingleParaStoredHeaderDataBuilder;
|
||||
use bp_runtime::HeaderId;
|
||||
use pallet_grandpa::{
|
||||
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 RialtoParasPalletName: &'static str = bp_rialto::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 MaxWestendParaHeadSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_SIZE;
|
||||
pub const MaxRialtoParaHeadDataSize: u32 = bp_rialto::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE;
|
||||
pub const MaxWestendParaHeadDataSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE;
|
||||
}
|
||||
|
||||
/// 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 BridgesGrandpaPalletInstance = RialtoGrandpaInstance;
|
||||
type ParasPalletName = RialtoParasPalletName;
|
||||
type TrackedParachains = frame_support::traits::Everything;
|
||||
type ParaStoredHeaderDataBuilder =
|
||||
SingleParaStoredHeaderDataBuilder<bp_rialto_parachain::RialtoParachain>;
|
||||
type HeadsToKeep = HeadersToKeep;
|
||||
type MaxParaHeadSize = MaxRialtoParaHeadSize;
|
||||
type MaxParaHeadDataSize = MaxRialtoParaHeadDataSize;
|
||||
}
|
||||
|
||||
/// 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 BridgesGrandpaPalletInstance = WestendGrandpaInstance;
|
||||
type ParasPalletName = WestendParasPalletName;
|
||||
type TrackedParachains = frame_support::traits::Everything;
|
||||
type ParaStoredHeaderDataBuilder = SingleParaStoredHeaderDataBuilder<bp_westend::Westmint>;
|
||||
type HeadsToKeep = HeadersToKeep;
|
||||
type MaxParaHeadSize = MaxWestendParaHeadSize;
|
||||
type MaxParaHeadDataSize = MaxWestendParaHeadDataSize;
|
||||
}
|
||||
|
||||
impl pallet_utility::Config for Runtime {
|
||||
@@ -902,28 +903,19 @@ impl_runtime_apis! {
|
||||
|
||||
impl bp_westend::WestmintFinalityApi<Block> for Runtime {
|
||||
fn best_finalized() -> Option<HeaderId<bp_westend::Hash, bp_westend::BlockNumber>> {
|
||||
// the parachains finality pallet is never decoding parachain heads, so it is
|
||||
// only done in the integration code
|
||||
use bp_westend::WESTMINT_PARACHAIN_ID;
|
||||
let encoded_head = pallet_bridge_parachains::Pallet::<
|
||||
pallet_bridge_parachains::Pallet::<
|
||||
Runtime,
|
||||
WithWestendParachainsInstance,
|
||||
>::best_parachain_head(WESTMINT_PARACHAIN_ID.into())?;
|
||||
let head = bp_westend::Header::decode(&mut &encoded_head.0[..]).ok()?;
|
||||
Some(head.id())
|
||||
>::best_parachain_head_id::<bp_westend::Westmint>().unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_rialto_parachain::RialtoParachainFinalityApi<Block> for Runtime {
|
||||
fn best_finalized() -> Option<HeaderId<bp_rialto::Hash, bp_rialto::BlockNumber>> {
|
||||
// the parachains finality pallet is never decoding parachain heads, so it is
|
||||
// only done in the integration code
|
||||
let encoded_head = pallet_bridge_parachains::Pallet::<
|
||||
pallet_bridge_parachains::Pallet::<
|
||||
Runtime,
|
||||
WithRialtoParachainsInstance,
|
||||
>::best_parachain_head(bp_rialto_parachain::RIALTO_PARACHAIN_ID.into())?;
|
||||
let head = bp_rialto_parachain::Header::decode(&mut &encoded_head.0[..]).ok()?;
|
||||
Some(head.id())
|
||||
>::best_parachain_head_id::<bp_rialto_parachain::RialtoParachain>().unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master",
|
||||
[dev-dependencies]
|
||||
bp-header-chain = { path = "../../primitives/header-chain" }
|
||||
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" }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -27,12 +27,10 @@ pub use weights::WeightInfo;
|
||||
pub use weights_ext::WeightInfoExt;
|
||||
|
||||
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_runtime::{HashOf, HeaderOf, Parachain, StorageProofError};
|
||||
use codec::Decode;
|
||||
use frame_support::{dispatch::PostDispatchInfo, traits::Contains};
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain, StorageProofError};
|
||||
use frame_support::dispatch::PostDispatchInfo;
|
||||
use sp_std::{marker::PhantomData, vec::Vec};
|
||||
|
||||
// Re-export in crate namespace for `construct_runtime!`.
|
||||
@@ -69,7 +67,10 @@ struct UpdateParachainHeadArtifacts {
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use bp_parachains::{BestParaHeadHash, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider};
|
||||
use bp_parachains::{
|
||||
BestParaHeadHash, ImportedParaHeadsKeyProvider, ParaStoredHeaderDataBuilder,
|
||||
ParasInfoKeyProvider,
|
||||
};
|
||||
use bp_runtime::{
|
||||
BasicOperatingMode, BoundedStorageValue, OwnedBridgeModule, StorageDoubleMapKeyProvider,
|
||||
StorageMapKeyProvider,
|
||||
@@ -77,9 +78,9 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// Stored parachain head of given parachains pallet.
|
||||
pub type StoredParaHeadOf<T, I> =
|
||||
BoundedStorageValue<<T as Config<I>>::MaxParaHeadSize, ParaHead>;
|
||||
/// 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;
|
||||
|
||||
@@ -153,12 +154,18 @@ pub mod pallet {
|
||||
#[pallet::constant]
|
||||
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
|
||||
/// parachain requires special handling - pruning existing heads and cleaning related data
|
||||
/// structures.
|
||||
type TrackedParachains: Contains<ParaId>;
|
||||
/// We never store parachain heads here, since they may be too big (e.g. because of large
|
||||
/// digest items). Instead we're using the same approach as `pallet-bridge-grandpa`
|
||||
/// pallet - we are only storing `bp_messages::StoredHeaderData` (number and state root),
|
||||
/// 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.
|
||||
///
|
||||
@@ -170,16 +177,17 @@ pub mod pallet {
|
||||
#[pallet::constant]
|
||||
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.
|
||||
/// So if you're going to track multiple parachains, one of which is storing large digests
|
||||
/// in its headers, you shall choose this maximal value.
|
||||
/// Keep in mind that the size of any tracked parachain header data must not exceed this
|
||||
/// value. So if you're going to track multiple parachains, one of which is using large
|
||||
/// 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
|
||||
/// that exceeds this bound.
|
||||
#[pallet::constant]
|
||||
type MaxParaHeadSize: Get<u32>;
|
||||
type MaxParaHeadDataSize: Get<u32>;
|
||||
}
|
||||
|
||||
/// Optional pallet owner.
|
||||
@@ -212,7 +220,7 @@ pub mod pallet {
|
||||
<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]
|
||||
pub type ImportedParaHeads<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
|
||||
_,
|
||||
@@ -220,7 +228,7 @@ pub mod pallet {
|
||||
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key1,
|
||||
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Hasher2,
|
||||
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key2,
|
||||
StoredParaHeadOf<T, I>,
|
||||
StoredParaHeadDataOf<T, I>,
|
||||
>;
|
||||
|
||||
/// 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),
|
||||
move |storage| {
|
||||
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(¶chain) {
|
||||
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) {
|
||||
Ok(Some(parachain_head)) => parachain_head,
|
||||
Ok(None) => {
|
||||
@@ -349,12 +346,26 @@ pub mod pallet {
|
||||
continue;
|
||||
}
|
||||
|
||||
// convert from parachain head into stored parachain head data
|
||||
let parachain_head_data = match T::ParaStoredHeaderDataBuilder::try_build(parachain, ¶chain_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 artifacts = Pallet::<T, I>::update_parachain_head(
|
||||
parachain,
|
||||
stored_best_head.take(),
|
||||
relay_block_number,
|
||||
parachain_head,
|
||||
parachain_head_data,
|
||||
parachain_head_hash,
|
||||
)?;
|
||||
*stored_best_head = Some(artifacts.best_head);
|
||||
@@ -406,14 +417,36 @@ pub mod pallet {
|
||||
ParasInfo::<T, I>::get(parachain)
|
||||
}
|
||||
|
||||
/// Get best finalized header of the given parachain.
|
||||
pub fn best_parachain_head(parachain: ParaId) -> Option<ParaHead> {
|
||||
/// Get best finalized head data of the given parachain.
|
||||
pub fn best_parachain_head(parachain: ParaId) -> Option<ParaStoredHeaderData> {
|
||||
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())
|
||||
}
|
||||
|
||||
/// Get parachain head with given hash.
|
||||
pub fn parachain_head(parachain: ParaId, hash: ParaHash) -> Option<ParaHead> {
|
||||
/// Get best finalized head hash of the given parachain.
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -480,7 +513,7 @@ pub mod pallet {
|
||||
parachain: ParaId,
|
||||
stored_best_head: Option<ParaInfo>,
|
||||
updated_at_relay_block_number: RelayBlockNumber,
|
||||
updated_head: ParaHead,
|
||||
updated_head_data: ParaStoredHeaderData,
|
||||
updated_head_hash: ParaHash,
|
||||
) -> Result<UpdateParachainHeadArtifacts, ()> {
|
||||
// check if head has been already updated at better relay chain block. Without this
|
||||
@@ -501,13 +534,14 @@ pub mod pallet {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// verify that the parachain head size is <= `MaxParaHeadSize`
|
||||
let updated_head = match StoredParaHeadOf::<T, I>::try_from_inner(updated_head) {
|
||||
Ok(updated_head) => updated_head,
|
||||
// verify that the parachain head data size is <= `MaxParaHeadDataSize`
|
||||
let updated_head_data =
|
||||
match StoredParaHeadDataOf::<T, I>::try_from_inner(updated_head_data) {
|
||||
Ok(updated_head_data) => updated_head_data,
|
||||
Err(e) => {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"{}. The parachain head size for {:?} is {}. It exceeds maximal configured size {}.",
|
||||
"{}. The parachain head data size for {:?} is {}. It exceeds maximal configured size {}.",
|
||||
err_log_prefix,
|
||||
parachain,
|
||||
e.value_size,
|
||||
@@ -543,7 +577,7 @@ pub mod pallet {
|
||||
next_imported_hash_position,
|
||||
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!(
|
||||
target: LOG_TARGET,
|
||||
"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>> {
|
||||
Pallet::<T, I>::parachain_head(ParaId(C::PARACHAIN_ID), hash)
|
||||
.and_then(|head| HeaderOf::<C>::decode(&mut &head.0[..]).ok())
|
||||
.map(|h| *h.state_root())
|
||||
.and_then(|head| head.decode_parachain_head_data::<C>().ok())
|
||||
.map(|h| h.state_root)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,8 +654,9 @@ impl<T: Config<I>, I: 'static, C: Parachain<Hash = ParaHash>> HeaderChain<C>
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
run_test, test_relay_header, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime,
|
||||
MAXIMAL_PARACHAIN_HEAD_SIZE, PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID,
|
||||
run_test, test_relay_header, BigParachainHeader, RegularParachainHasher,
|
||||
RegularParachainHeader, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime,
|
||||
PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID,
|
||||
};
|
||||
use codec::Encode;
|
||||
|
||||
@@ -641,7 +676,8 @@ mod tests {
|
||||
weights::Weight,
|
||||
};
|
||||
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};
|
||||
|
||||
type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
|
||||
@@ -716,12 +752,42 @@ mod tests {
|
||||
}
|
||||
|
||||
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(
|
||||
(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
|
||||
)
|
||||
.map(|h| h.into_inner()),
|
||||
Some(head_data(1, 0))
|
||||
Some(stored_head_data(1, 0))
|
||||
);
|
||||
assert_eq!(
|
||||
ImportedParaHeads::<TestRuntime>::get(
|
||||
@@ -836,7 +902,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
ImportedParaHeads::<TestRuntime>::get(ParaId(3), head_hash(3, 10))
|
||||
.map(|h| h.into_inner()),
|
||||
Some(head_data(3, 10))
|
||||
Some(stored_head_data(3, 10))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -886,7 +952,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 5).hash())
|
||||
.map(|h| h.into_inner()),
|
||||
Some(head_data(1, 5))
|
||||
Some(stored_head_data(1, 5))
|
||||
);
|
||||
assert_eq!(
|
||||
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 10).hash())
|
||||
@@ -921,12 +987,12 @@ mod tests {
|
||||
assert_eq!(
|
||||
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 5).hash())
|
||||
.map(|h| h.into_inner()),
|
||||
Some(head_data(1, 5))
|
||||
Some(stored_head_data(1, 5))
|
||||
);
|
||||
assert_eq!(
|
||||
ImportedParaHeads::<TestRuntime>::get(ParaId(1), head_data(1, 10).hash())
|
||||
.map(|h| h.into_inner()),
|
||||
Some(head_data(1, 10))
|
||||
Some(stored_head_data(1, 10))
|
||||
);
|
||||
assert_eq!(
|
||||
System::<TestRuntime>::events(),
|
||||
@@ -1153,10 +1219,9 @@ mod tests {
|
||||
#[test]
|
||||
fn does_nothing_when_parachain_head_is_too_large() {
|
||||
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(|| {
|
||||
// start with relay block #0 and try to import head#5 of parachain#1 and untracked
|
||||
// parachain
|
||||
// start with relay block #0 and try to import head#5 of parachain#1 and big parachain
|
||||
initialize(state_root);
|
||||
let result = Pallet::<TestRuntime>::submit_parachain_heads(
|
||||
RuntimeOrigin::signed(1),
|
||||
@@ -1175,7 +1240,7 @@ mod tests {
|
||||
next_imported_hash_position: 1,
|
||||
})
|
||||
);
|
||||
assert_eq!(ParasInfo::<TestRuntime>::get(ParaId(2)), None);
|
||||
assert_eq!(ParasInfo::<TestRuntime>::get(ParaId(4)), None);
|
||||
assert_eq!(
|
||||
System::<TestRuntime>::events(),
|
||||
vec![
|
||||
@@ -1190,9 +1255,9 @@ mod tests {
|
||||
EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: TestEvent::Parachains(Event::RejectedLargeParachainHead {
|
||||
parachain: ParaId(2),
|
||||
parachain_head_hash: large_head_data(1, 5).hash(),
|
||||
parachain_head_size: large_head_data(1, 5).encoded_size() as u32,
|
||||
parachain: ParaId(4),
|
||||
parachain_head_hash: big_head_data(1, 5).hash(),
|
||||
parachain_head_size: big_stored_head_data(1, 5).encoded_size() as u32,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -1294,7 +1359,7 @@ mod tests {
|
||||
import_parachain_1_head(0, state_root_5, parachains_5, proof_5).expect("ok");
|
||||
assert_eq!(
|
||||
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
|
||||
@@ -1310,7 +1375,7 @@ mod tests {
|
||||
),);
|
||||
assert_eq!(
|
||||
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
|
||||
@@ -1326,7 +1391,7 @@ mod tests {
|
||||
),);
|
||||
assert_eq!(
|
||||
Pallet::<TestRuntime>::best_parachain_head(ParaId(1)),
|
||||
Some(head_data(1, 10))
|
||||
Some(stored_head_data(1, 10))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,16 +15,12 @@
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use bp_polkadot_core::parachains::ParaId;
|
||||
use bp_runtime::Chain;
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types,
|
||||
traits::{ConstU32, IsInVec},
|
||||
weights::Weight,
|
||||
};
|
||||
use bp_runtime::{Chain, Parachain};
|
||||
use frame_support::{construct_runtime, parameter_types, traits::ConstU32, weights::Weight};
|
||||
use sp_runtime::{
|
||||
testing::{Header, H256},
|
||||
traits::{BlakeTwo256, Header as HeaderT, IdentityLookup},
|
||||
Perbill,
|
||||
MultiSignature, Perbill,
|
||||
};
|
||||
|
||||
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 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! {
|
||||
pub enum TestRuntime where
|
||||
@@ -68,7 +166,7 @@ impl frame_system::Config for TestRuntime {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type BlockNumber = TestNumber;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type Hashing = RegularParachainHasher;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
@@ -122,9 +220,9 @@ impl pallet_bridge_parachains::Config for TestRuntime {
|
||||
type WeightInfo = ();
|
||||
type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
|
||||
type ParasPalletName = ParasPalletName;
|
||||
type TrackedParachains = IsInVec<GetTenFirstParachains>;
|
||||
type ParaStoredHeaderDataBuilder = (Parachain1, Parachain2, Parachain3, BigParachain);
|
||||
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)]
|
||||
|
||||
@@ -70,8 +70,12 @@ pub const SESSION_LENGTH: BlockNumber = 4;
|
||||
/// Maximal number of GRANDPA authorities at Rialto.
|
||||
pub const MAX_AUTHORITIES_COUNT: u32 = 5;
|
||||
|
||||
/// Maximal SCALE-encoded size of parachains headers that are stored at Rialto `Paras` pallet.
|
||||
pub const MAX_NESTED_PARACHAIN_HEAD_SIZE: u32 = 1024;
|
||||
/// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Rialto
|
||||
/// 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.
|
||||
pub use time_units::*;
|
||||
|
||||
@@ -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.
|
||||
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
|
||||
/// `MAX_AUTHORITES_COUNT`. Every authority means 32-byte key and 8-byte weight. Let's also have
|
||||
/// some fixed reserve for other things (digest, block hash and number, ...) as well.
|
||||
pub const MAX_NESTED_PARACHAIN_HEAD_SIZE: u32 = 4096 + MAX_AUTHORITIES_COUNT * 40;
|
||||
/// 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;
|
||||
|
||||
/// Maximal number of GRANDPA authorities at Rococo.
|
||||
///
|
||||
|
||||
@@ -15,6 +15,7 @@ bp-runtime = { path = "../runtime", default-features = false }
|
||||
|
||||
# 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 }
|
||||
|
||||
[features]
|
||||
@@ -22,5 +23,6 @@ default = ["std"]
|
||||
std = [
|
||||
"bp-polkadot-core/std",
|
||||
"bp-runtime/std",
|
||||
"frame-support/std",
|
||||
"sp-api/std",
|
||||
]
|
||||
|
||||
@@ -19,11 +19,42 @@
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
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
|
||||
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.
|
||||
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.
|
||||
///
|
||||
/// Let's assume that the largest header is header that enacts new authorities set with
|
||||
/// `MAX_AUTHORITES_COUNT`. Every authority means 32-byte key and 8-byte weight. Let's also have
|
||||
/// some fixed reserve for other things (digest, block hash and number, ...) as well.
|
||||
pub const MAX_NESTED_PARACHAIN_HEAD_SIZE: u32 = 4096 + MAX_AUTHORITIES_COUNT * 40;
|
||||
/// 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;
|
||||
|
||||
/// Identifier of Westmint parachain at the Westend relay chain.
|
||||
pub const WESTMINT_PARACHAIN_ID: u32 = 2000;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
pub use bp_polkadot_core::*;
|
||||
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;
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
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"] }
|
||||
|
||||
# Bridge dependencies
|
||||
|
||||
bp-header-chain = { path = "../header-chain", default-features = false }
|
||||
bp-polkadot-core = { path = "../polkadot-core", 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 }
|
||||
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]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"bp-header-chain/std",
|
||||
"bp-polkadot-core/std",
|
||||
"bp-runtime/std",
|
||||
"codec/std",
|
||||
"frame-support/std",
|
||||
"scale-info/std",
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
]
|
||||
|
||||
@@ -18,15 +18,22 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub use bp_header_chain::StoredHeaderData;
|
||||
|
||||
use bp_polkadot_core::{
|
||||
parachains::{ParaHash, ParaHead, ParaId},
|
||||
BlockNumber as RelayBlockNumber,
|
||||
};
|
||||
use bp_runtime::{StorageDoubleMapKeyProvider, StorageMapKeyProvider};
|
||||
use bp_runtime::{
|
||||
BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider,
|
||||
StorageMapKeyProvider,
|
||||
};
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::storage::StorageKey;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
|
||||
/// Best known parachain head hash.
|
||||
#[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
|
||||
@@ -86,5 +93,60 @@ impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider {
|
||||
type Key1 = ParaId;
|
||||
type Hasher2 = Blake2_128Concat;
|
||||
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 ¶_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`.
|
||||
///
|
||||
/// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header. Keep in mind
|
||||
/// 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.
|
||||
/// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header.
|
||||
#[derive(
|
||||
PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default,
|
||||
)]
|
||||
|
||||
@@ -111,10 +111,7 @@ pub trait Chain: Send + Sync + 'static {
|
||||
+ AsPrimitive<usize>
|
||||
+ Default
|
||||
+ Saturating
|
||||
+ MaxEncodedLen
|
||||
// original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but
|
||||
// `sp_runtime::generic::Era` requires block number -> `u64` conversion.
|
||||
+ Into<u64>;
|
||||
+ MaxEncodedLen;
|
||||
|
||||
/// 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`
|
||||
|
||||
@@ -27,7 +27,7 @@ use frame_system::RawOrigin;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::{hash::H256, storage::StorageKey};
|
||||
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};
|
||||
|
||||
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.
|
||||
pub trait HeaderIdProvider<Header: HeaderT> {
|
||||
// Get the header id.
|
||||
@@ -225,7 +228,9 @@ pub enum TransactionEra<BlockNumber, BlockHash> {
|
||||
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.
|
||||
pub fn new(
|
||||
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 {
|
||||
match *self {
|
||||
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) =>
|
||||
sp_runtime::generic::Era::mortal(period as _, header_id.0.into()),
|
||||
sp_runtime::generic::Era::mortal(period as _, header_id.0.unique_saturated_into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,13 +44,10 @@ pub use crate::{
|
||||
transaction_tracker::TransactionTracker,
|
||||
};
|
||||
pub use bp_runtime::{
|
||||
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderOf,
|
||||
IndexOf, SignatureOf, TransactionEra, TransactionEraOf,
|
||||
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderIdOf,
|
||||
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.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectionParams {
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
//! 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.
|
||||
#[derive(Clone)]
|
||||
@@ -61,13 +64,19 @@ impl SyncLoopMetrics {
|
||||
}
|
||||
|
||||
/// Update best block number at source.
|
||||
pub fn update_best_block_at_source<Number: Into<u64>>(&self, source_best_number: Number) {
|
||||
self.best_source_block_number.set(source_best_number.into());
|
||||
pub fn update_best_block_at_source<Number: UniqueSaturatedInto<u64>>(
|
||||
&self,
|
||||
source_best_number: Number,
|
||||
) {
|
||||
self.best_source_block_number.set(source_best_number.unique_saturated_into());
|
||||
}
|
||||
|
||||
/// Update best block number at target.
|
||||
pub fn update_best_block_at_target<Number: Into<u64>>(&self, target_best_number: Number) {
|
||||
self.best_target_block_number.set(target_best_number.into());
|
||||
pub fn update_best_block_at_target<Number: UniqueSaturatedInto<u64>>(
|
||||
&self,
|
||||
target_best_number: Number,
|
||||
) {
|
||||
self.best_target_block_number.set(target_best_number.unique_saturated_into());
|
||||
}
|
||||
|
||||
/// Update using-same-fork flag.
|
||||
|
||||
@@ -33,12 +33,10 @@ use parachains_relay::{
|
||||
};
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf,
|
||||
HeaderIdOf, HeaderOf, RelayChain, SignParam, TransactionEra, TransactionTracker,
|
||||
UnsignedTransaction,
|
||||
HeaderIdOf, RelayChain, SignParam, TransactionEra, TransactionTracker, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
|
||||
/// Substrate client as parachain heads source.
|
||||
pub struct ParachainsTarget<P: SubstrateParachainsPipeline> {
|
||||
@@ -132,7 +130,7 @@ where
|
||||
.map(|para_info| para_info.best_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
|
||||
.storage_double_map_value::<ImportedParaHeadsKeyProvider>(
|
||||
P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME,
|
||||
@@ -142,8 +140,9 @@ where
|
||||
)
|
||||
.await
|
||||
.and_then(|maybe_encoded_head| match maybe_encoded_head {
|
||||
Some(encoded_head) =>
|
||||
HeaderOf::<P::SourceParachain>::decode(&mut &encoded_head.0[..])
|
||||
Some(encoded_head) => encoded_head
|
||||
.decode_parachain_head_data::<P::SourceParachain>()
|
||||
.map(|head| head.number)
|
||||
.map(Some)
|
||||
.map_err(Self::Error::ResponseParseFailed),
|
||||
None => Ok(None),
|
||||
@@ -159,9 +158,8 @@ where
|
||||
e
|
||||
})
|
||||
.unwrap_or(None);
|
||||
if let Some(imported_para_head) = imported_para_head {
|
||||
metrics
|
||||
.update_best_parachain_block_at_target(para_id, *imported_para_head.number());
|
||||
if let Some(imported_para_head_number) = imported_para_head_number {
|
||||
metrics.update_best_parachain_block_at_target(para_id, imported_para_head_number);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,10 +65,9 @@ impl MessageLaneLoopMetrics {
|
||||
/// Update source client state metrics.
|
||||
pub fn update_source_state<P: MessageLane>(&self, source_client_state: SourceClientState<P>) {
|
||||
self.source_to_target_finality_metrics
|
||||
.update_best_block_at_source(source_client_state.best_self.0.into());
|
||||
self.target_to_source_finality_metrics.update_best_block_at_target(
|
||||
source_client_state.best_finalized_peer_at_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(source_client_state.best_finalized_peer_at_best_self.0);
|
||||
self.target_to_source_finality_metrics.update_using_same_fork(
|
||||
source_client_state.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.
|
||||
pub fn update_target_state<P: MessageLane>(&self, target_client_state: TargetClientState<P>) {
|
||||
self.target_to_source_finality_metrics
|
||||
.update_best_block_at_source(target_client_state.best_self.0.into());
|
||||
self.source_to_target_finality_metrics.update_best_block_at_target(
|
||||
target_client_state.best_finalized_peer_at_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(target_client_state.best_finalized_peer_at_best_self.0);
|
||||
self.source_to_target_finality_metrics.update_using_same_fork(
|
||||
target_client_state.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/>.
|
||||
|
||||
use bp_polkadot_core::parachains::ParaId;
|
||||
use relay_utils::metrics::{
|
||||
metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
|
||||
use relay_utils::{
|
||||
metrics::{metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64},
|
||||
UniqueSaturatedInto,
|
||||
};
|
||||
|
||||
/// Parachains sync metrics.
|
||||
@@ -50,12 +51,12 @@ impl ParachainsLoopMetrics {
|
||||
}
|
||||
|
||||
/// 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,
|
||||
parachain: ParaId,
|
||||
block_number: Number,
|
||||
) {
|
||||
let block_number = block_number.into();
|
||||
let block_number = block_number.unique_saturated_into();
|
||||
let label = parachain_label(¶chain);
|
||||
log::trace!(
|
||||
target: "bridge-metrics",
|
||||
@@ -67,12 +68,12 @@ impl ParachainsLoopMetrics {
|
||||
}
|
||||
|
||||
/// 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,
|
||||
parachain: ParaId,
|
||||
block_number: Number,
|
||||
) {
|
||||
let block_number = block_number.into();
|
||||
let block_number = block_number.unique_saturated_into();
|
||||
let label = parachain_label(¶chain);
|
||||
log::trace!(
|
||||
target: "bridge-metrics",
|
||||
|
||||
@@ -29,4 +29,5 @@ bp-runtime = { path = "../../primitives/runtime" }
|
||||
|
||||
# Substrate dependencies
|
||||
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
pub use bp_runtime::HeaderId;
|
||||
pub use error::Error;
|
||||
pub use relay_loop::{relay_loop, relay_metrics};
|
||||
pub use sp_runtime::traits::UniqueSaturatedInto;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use backoff::{backoff::Backoff, ExponentialBackoff};
|
||||
@@ -51,7 +52,7 @@ pub mod relay_loop;
|
||||
pub trait BlockNumberBase:
|
||||
'static
|
||||
+ From<u32>
|
||||
+ Into<u64>
|
||||
+ UniqueSaturatedInto<u64>
|
||||
+ Ord
|
||||
+ Clone
|
||||
+ Copy
|
||||
@@ -73,7 +74,7 @@ pub trait BlockNumberBase:
|
||||
impl<T> BlockNumberBase for T where
|
||||
T: 'static
|
||||
+ From<u32>
|
||||
+ Into<u64>
|
||||
+ UniqueSaturatedInto<u64>
|
||||
+ Ord
|
||||
+ Clone
|
||||
+ Copy
|
||||
|
||||
Reference in New Issue
Block a user