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-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",
+13 -21
View File
@@ -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)
}
}
+1
View File
@@ -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]
+131 -66
View File
@@ -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(&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) {
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, &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 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))
);
});
}
+109 -11
View File
@@ -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)]
+6 -2
View File
@@ -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::*;
+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.
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",
]
+35 -5
View File
@@ -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;
+1 -1
View File
@@ -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;
+7
View File
@@ -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",
]
+64 -2
View File
@@ -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 &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`.
///
/// 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,
)]
+1 -4
View File
@@ -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`
+10 -3
View File
@@ -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()),
}
}
+2 -5
View File
@@ -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);
}
}
+6 -8
View File
@@ -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(&parachain);
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(&parachain);
log::trace!(
target: "bridge-metrics",
+1
View File
@@ -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" }
+3 -2
View File
@@ -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