mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 12:11:09 +00:00
Remove pallet::without_storage_info from bridge GRANDPA pallet (#1478)
* remove pallet::without_storage_info from bridge GRANDPA pallet * StoredBridgedHeader * spelling * fix benchmarks * MAX_BRIDGED_AUTHORITIES: 256 -> 2048 * Update modules/grandpa/src/storage_types.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> * Update modules/grandpa/src/storage_types.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> * moved max authorities + header size to chain primitives * removed unused code * new -> try_new * fix benchmarks compilation Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
committed by
Bastian Köcher
parent
6f9bda5db0
commit
f38852f661
@@ -426,11 +426,25 @@ parameter_types! {
|
|||||||
pub const HeadersToKeep: u32 = 7 * bp_rialto::DAYS as u32;
|
pub const HeadersToKeep: u32 = 7 * bp_rialto::DAYS as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
/// Maximal number of authorities at Rialto.
|
||||||
|
pub const MaxAuthoritiesAtRialto: u32 = bp_rialto::MAX_AUTHORITIES_COUNT;
|
||||||
|
/// Maximal size of SCALE-encoded Rialto header.
|
||||||
|
pub const MaxRialtoHeaderSize: u32 = bp_rialto::MAX_HEADER_SIZE;
|
||||||
|
|
||||||
|
/// Maximal number of authorities at Westend.
|
||||||
|
pub const MaxAuthoritiesAtWestend: u32 = bp_westend::MAX_AUTHORITIES_COUNT;
|
||||||
|
/// Maximal size of SCALE-encoded Westend header.
|
||||||
|
pub const MaxWestendHeaderSize: u32 = bp_westend::MAX_HEADER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
pub type RialtoGrandpaInstance = ();
|
pub type RialtoGrandpaInstance = ();
|
||||||
impl pallet_bridge_grandpa::Config for Runtime {
|
impl pallet_bridge_grandpa::Config for Runtime {
|
||||||
type BridgedChain = bp_rialto::Rialto;
|
type BridgedChain = bp_rialto::Rialto;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = MaxAuthoritiesAtRialto;
|
||||||
|
type MaxBridgedHeaderSize = MaxRialtoHeaderSize;
|
||||||
|
|
||||||
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
||||||
}
|
}
|
||||||
@@ -440,6 +454,8 @@ impl pallet_bridge_grandpa::Config<WestendGrandpaInstance> for Runtime {
|
|||||||
type BridgedChain = bp_westend::Westend;
|
type BridgedChain = bp_westend::Westend;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = MaxAuthoritiesAtWestend;
|
||||||
|
type MaxBridgedHeaderSize = MaxWestendHeaderSize;
|
||||||
|
|
||||||
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -531,6 +531,11 @@ parameter_types! {
|
|||||||
/// Assuming the worst case of every header being finalized, we will keep headers at least for a
|
/// Assuming the worst case of every header being finalized, we will keep headers at least for a
|
||||||
/// week.
|
/// week.
|
||||||
pub const HeadersToKeep: u32 = 7 * bp_millau::DAYS as u32;
|
pub const HeadersToKeep: u32 = 7 * bp_millau::DAYS as u32;
|
||||||
|
|
||||||
|
/// Maximal number of authorities at Millau.
|
||||||
|
pub const MaxAuthoritiesAtMillau: u32 = bp_millau::MAX_AUTHORITIES_COUNT;
|
||||||
|
/// Maximal size of SCALE-encoded Millau header.
|
||||||
|
pub const MaxMillauHeaderSize: u32 = bp_millau::MAX_HEADER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MillauGrandpaInstance = ();
|
pub type MillauGrandpaInstance = ();
|
||||||
@@ -538,6 +543,8 @@ impl pallet_bridge_grandpa::Config for Runtime {
|
|||||||
type BridgedChain = bp_millau::Millau;
|
type BridgedChain = bp_millau::Millau;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = MaxAuthoritiesAtMillau;
|
||||||
|
type MaxBridgedHeaderSize = MaxMillauHeaderSize;
|
||||||
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -417,6 +417,11 @@ parameter_types! {
|
|||||||
/// Assuming the worst case of every header being finalized, we will keep headers at least for a
|
/// Assuming the worst case of every header being finalized, we will keep headers at least for a
|
||||||
/// week.
|
/// week.
|
||||||
pub const HeadersToKeep: u32 = 7 * bp_rialto::DAYS as u32;
|
pub const HeadersToKeep: u32 = 7 * bp_rialto::DAYS as u32;
|
||||||
|
|
||||||
|
/// Maximal number of authorities at Millau.
|
||||||
|
pub const MaxAuthoritiesAtMillau: u32 = bp_millau::MAX_AUTHORITIES_COUNT;
|
||||||
|
/// Maximal size of SCALE-encoded Millau header.
|
||||||
|
pub const MaxMillauHeaderSize: u32 = bp_millau::MAX_HEADER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MillauGrandpaInstance = ();
|
pub type MillauGrandpaInstance = ();
|
||||||
@@ -424,6 +429,8 @@ impl pallet_bridge_grandpa::Config for Runtime {
|
|||||||
type BridgedChain = bp_millau::Millau;
|
type BridgedChain = bp_millau::Millau;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = MaxAuthoritiesAtMillau;
|
||||||
|
type MaxBridgedHeaderSize = MaxMillauHeaderSize;
|
||||||
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight<Runtime>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
// Runtime-generated enums
|
// Runtime-generated enums
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
|
||||||
|
use storage_types::{StoredAuthoritySet, StoredBridgedHeader};
|
||||||
|
|
||||||
use bp_header_chain::{justification::GrandpaJustification, InitializationData};
|
use bp_header_chain::{justification::GrandpaJustification, InitializationData};
|
||||||
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, OwnedBridgeModule};
|
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, OwnedBridgeModule};
|
||||||
use finality_grandpa::voter_set::VoterSet;
|
use finality_grandpa::voter_set::VoterSet;
|
||||||
@@ -48,6 +50,7 @@ use sp_std::{boxed::Box, convert::TryInto};
|
|||||||
mod extension;
|
mod extension;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock;
|
mod mock;
|
||||||
|
mod storage_types;
|
||||||
|
|
||||||
/// Module, containing weights for this pallet.
|
/// Module, containing weights for this pallet.
|
||||||
pub mod weights;
|
pub mod weights;
|
||||||
@@ -102,12 +105,24 @@ pub mod pallet {
|
|||||||
#[pallet::constant]
|
#[pallet::constant]
|
||||||
type HeadersToKeep: Get<u32>;
|
type HeadersToKeep: Get<u32>;
|
||||||
|
|
||||||
|
/// Max number of authorities at the bridged chain.
|
||||||
|
#[pallet::constant]
|
||||||
|
type MaxBridgedAuthorities: Get<u32>;
|
||||||
|
/// Maximal size (in bytes) of the SCALE-encoded bridged chain header.
|
||||||
|
///
|
||||||
|
/// This constant must be selected with care. The pallet requires mandatory headers to be
|
||||||
|
/// submitted to be able to proceed. Mandatory headers contain public keys of all GRANDPA
|
||||||
|
/// authorities. E.g. for 1024 authorities, the size of encoded keys will be at least 32 KB.
|
||||||
|
/// The same header may also contain other digest items as well, so some reserve here
|
||||||
|
/// is required.
|
||||||
|
#[pallet::constant]
|
||||||
|
type MaxBridgedHeaderSize: Get<u32>;
|
||||||
|
|
||||||
/// Weights gathered through benchmarking.
|
/// Weights gathered through benchmarking.
|
||||||
type WeightInfo: WeightInfo;
|
type WeightInfo: WeightInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
#[pallet::without_storage_info]
|
|
||||||
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
|
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
|
||||||
|
|
||||||
#[pallet::hooks]
|
#[pallet::hooks]
|
||||||
@@ -180,12 +195,14 @@ pub mod pallet {
|
|||||||
|
|
||||||
let authority_set = <CurrentAuthoritySet<T, I>>::get();
|
let authority_set = <CurrentAuthoritySet<T, I>>::get();
|
||||||
let set_id = authority_set.set_id;
|
let set_id = authority_set.set_id;
|
||||||
verify_justification::<T, I>(&justification, hash, *number, authority_set)?;
|
verify_justification::<T, I>(&justification, hash, *number, authority_set.into())?;
|
||||||
|
|
||||||
let is_authorities_change_enacted =
|
let is_authorities_change_enacted =
|
||||||
try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
||||||
|
let finality_target =
|
||||||
|
StoredBridgedHeader::<T, I>::try_from_bridged_header(*finality_target)?;
|
||||||
<RequestCount<T, I>>::mutate(|count| *count += 1);
|
<RequestCount<T, I>>::mutate(|count| *count += 1);
|
||||||
insert_header::<T, I>(*finality_target, hash);
|
insert_header::<T, I>(finality_target, hash);
|
||||||
log::info!(
|
log::info!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"Successfully imported finalized header with hash {:?}!",
|
"Successfully imported finalized header with hash {:?}!",
|
||||||
@@ -221,7 +238,7 @@ pub mod pallet {
|
|||||||
|
|
||||||
let init_allowed = !<BestFinalized<T, I>>::exists();
|
let init_allowed = !<BestFinalized<T, I>>::exists();
|
||||||
ensure!(init_allowed, <Error<T, I>>::AlreadyInitialized);
|
ensure!(init_allowed, <Error<T, I>>::AlreadyInitialized);
|
||||||
initialize_bridge::<T, I>(init_data.clone());
|
initialize_bridge::<T, I>(init_data.clone())?;
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
@@ -286,12 +303,12 @@ pub mod pallet {
|
|||||||
/// Headers which have been imported into the pallet.
|
/// Headers which have been imported into the pallet.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
pub type ImportedHeaders<T: Config<I>, I: 'static = ()> =
|
pub type ImportedHeaders<T: Config<I>, I: 'static = ()> =
|
||||||
StorageMap<_, Identity, BridgedBlockHash<T, I>, BridgedHeader<T, I>>;
|
StorageMap<_, Identity, BridgedBlockHash<T, I>, StoredBridgedHeader<T, I>>;
|
||||||
|
|
||||||
/// The current GRANDPA Authority set.
|
/// The current GRANDPA Authority set.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
pub(super) type CurrentAuthoritySet<T: Config<I>, I: 'static = ()> =
|
pub(super) type CurrentAuthoritySet<T: Config<I>, I: 'static = ()> =
|
||||||
StorageValue<_, bp_header_chain::AuthoritySet, ValueQuery>;
|
StorageValue<_, StoredAuthoritySet<T, I>, ValueQuery>;
|
||||||
|
|
||||||
/// Optional pallet owner.
|
/// Optional pallet owner.
|
||||||
///
|
///
|
||||||
@@ -333,7 +350,7 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(init_data) = self.init_data.clone() {
|
if let Some(init_data) = self.init_data.clone() {
|
||||||
initialize_bridge::<T, I>(init_data);
|
initialize_bridge::<T, I>(init_data).expect("genesis config is correct; qed");
|
||||||
} else {
|
} else {
|
||||||
// Since the bridge hasn't been initialized we shouldn't allow anyone to perform
|
// Since the bridge hasn't been initialized we shouldn't allow anyone to perform
|
||||||
// transactions.
|
// transactions.
|
||||||
@@ -364,6 +381,10 @@ pub mod pallet {
|
|||||||
AlreadyInitialized,
|
AlreadyInitialized,
|
||||||
/// The storage proof doesn't contains storage root. So it is invalid for given header.
|
/// The storage proof doesn't contains storage root. So it is invalid for given header.
|
||||||
StorageRootMismatch,
|
StorageRootMismatch,
|
||||||
|
/// Too many authorities in the set.
|
||||||
|
TooManyAuthoritiesInSet,
|
||||||
|
/// Too large header.
|
||||||
|
TooLargeHeader,
|
||||||
/// Error generated by the `OwnedBridgeModule` trait.
|
/// Error generated by the `OwnedBridgeModule` trait.
|
||||||
BridgeModule(bp_runtime::OwnedBridgeModuleError),
|
BridgeModule(bp_runtime::OwnedBridgeModuleError),
|
||||||
}
|
}
|
||||||
@@ -392,8 +413,11 @@ pub mod pallet {
|
|||||||
ensure!(change.delay == Zero::zero(), <Error<T, I>>::UnsupportedScheduledChange);
|
ensure!(change.delay == Zero::zero(), <Error<T, I>>::UnsupportedScheduledChange);
|
||||||
|
|
||||||
// TODO [#788]: Stop manually increasing the `set_id` here.
|
// TODO [#788]: Stop manually increasing the `set_id` here.
|
||||||
let next_authorities = bp_header_chain::AuthoritySet {
|
let next_authorities = StoredAuthoritySet::<T, I> {
|
||||||
authorities: change.next_authorities,
|
authorities: change
|
||||||
|
.next_authorities
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| Error::<T, I>::TooManyAuthoritiesInSet)?,
|
||||||
set_id: current_set_id + 1,
|
set_id: current_set_id + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -454,7 +478,7 @@ pub mod pallet {
|
|||||||
/// Note this function solely takes care of updating the storage and pruning old entries,
|
/// Note this function solely takes care of updating the storage and pruning old entries,
|
||||||
/// but does not verify the validity of such import.
|
/// but does not verify the validity of such import.
|
||||||
pub(crate) fn insert_header<T: Config<I>, I: 'static>(
|
pub(crate) fn insert_header<T: Config<I>, I: 'static>(
|
||||||
header: BridgedHeader<T, I>,
|
header: StoredBridgedHeader<T, I>,
|
||||||
hash: BridgedBlockHash<T, I>,
|
hash: BridgedBlockHash<T, I>,
|
||||||
) {
|
) {
|
||||||
let index = <ImportedHashesPointer<T, I>>::get();
|
let index = <ImportedHashesPointer<T, I>>::get();
|
||||||
@@ -475,19 +499,23 @@ pub mod pallet {
|
|||||||
/// were called by a trusted origin.
|
/// were called by a trusted origin.
|
||||||
pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>(
|
pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>(
|
||||||
init_params: super::InitializationData<BridgedHeader<T, I>>,
|
init_params: super::InitializationData<BridgedHeader<T, I>>,
|
||||||
) {
|
) -> Result<(), Error<T, I>> {
|
||||||
let super::InitializationData { header, authority_list, set_id, operating_mode } =
|
let super::InitializationData { header, authority_list, set_id, operating_mode } =
|
||||||
init_params;
|
init_params;
|
||||||
|
let authority_set = StoredAuthoritySet::<T, I>::try_new(authority_list, set_id)
|
||||||
|
.map_err(|_| Error::TooManyAuthoritiesInSet)?;
|
||||||
|
let header = StoredBridgedHeader::<T, I>::try_from_bridged_header(*header)?;
|
||||||
|
|
||||||
let initial_hash = header.hash();
|
let initial_hash = header.hash();
|
||||||
<InitialHash<T, I>>::put(initial_hash);
|
<InitialHash<T, I>>::put(initial_hash);
|
||||||
<ImportedHashesPointer<T, I>>::put(0);
|
<ImportedHashesPointer<T, I>>::put(0);
|
||||||
insert_header::<T, I>(*header, initial_hash);
|
insert_header::<T, I>(header, initial_hash);
|
||||||
|
|
||||||
let authority_set = bp_header_chain::AuthoritySet::new(authority_list, set_id);
|
|
||||||
<CurrentAuthoritySet<T, I>>::put(authority_set);
|
<CurrentAuthoritySet<T, I>>::put(authority_set);
|
||||||
|
|
||||||
<PalletOperatingMode<T, I>>::put(operating_mode);
|
<PalletOperatingMode<T, I>>::put(operating_mode);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
@@ -496,7 +524,7 @@ pub mod pallet {
|
|||||||
) {
|
) {
|
||||||
let start_number = *init_params.header.number();
|
let start_number = *init_params.header.number();
|
||||||
let end_number = start_number + T::HeadersToKeep::get().into();
|
let end_number = start_number + T::HeadersToKeep::get().into();
|
||||||
initialize_bridge::<T, I>(init_params);
|
initialize_bridge::<T, I>(init_params).expect("benchmarks are correct");
|
||||||
|
|
||||||
let mut number = start_number;
|
let mut number = start_number;
|
||||||
while number < end_number {
|
while number < end_number {
|
||||||
@@ -509,7 +537,11 @@ pub mod pallet {
|
|||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let hash = header.hash();
|
let hash = header.hash();
|
||||||
insert_header::<T, I>(header, hash);
|
insert_header::<T, I>(
|
||||||
|
StoredBridgedHeader::try_from_bridged_header(header)
|
||||||
|
.expect("only used from benchmarks; benchmarks are correct; qed"),
|
||||||
|
hash,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,7 +553,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
|||||||
/// if the pallet has not been initialized yet.
|
/// if the pallet has not been initialized yet.
|
||||||
pub fn best_finalized() -> Option<BridgedHeader<T, I>> {
|
pub fn best_finalized() -> Option<BridgedHeader<T, I>> {
|
||||||
let (_, hash) = <BestFinalized<T, I>>::get()?;
|
let (_, hash) = <BestFinalized<T, I>>::get()?;
|
||||||
<ImportedHeaders<T, I>>::get(hash)
|
<ImportedHeaders<T, I>>::get(hash).map(|h| h.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a particular header is known to the bridge pallet.
|
/// Check if a particular header is known to the bridge pallet.
|
||||||
@@ -591,13 +623,17 @@ pub fn initialize_for_benchmarks<T: Config<I>, I: 'static>(header: BridgedHeader
|
|||||||
* benchmarks */
|
* benchmarks */
|
||||||
set_id: 0,
|
set_id: 0,
|
||||||
operating_mode: bp_runtime::BasicOperatingMode::Normal,
|
operating_mode: bp_runtime::BasicOperatingMode::Normal,
|
||||||
});
|
})
|
||||||
|
.expect("only used from benchmarks; benchmarks are correct; qed");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mock::{run_test, test_header, Origin, TestHeader, TestNumber, TestRuntime};
|
use crate::mock::{
|
||||||
|
run_test, test_header, Origin, TestHeader, TestNumber, TestRuntime,
|
||||||
|
MAX_BRIDGED_AUTHORITIES, MAX_HEADER_SIZE,
|
||||||
|
};
|
||||||
use bp_runtime::BasicOperatingMode;
|
use bp_runtime::BasicOperatingMode;
|
||||||
use bp_test_utils::{
|
use bp_test_utils::{
|
||||||
authority_list, generate_owned_bridge_module_tests, make_default_justification,
|
authority_list, generate_owned_bridge_module_tests, make_default_justification,
|
||||||
@@ -673,6 +709,22 @@ mod tests {
|
|||||||
Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] }
|
Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn many_authorities_log() -> Digest {
|
||||||
|
let consensus_log =
|
||||||
|
ConsensusLog::<TestNumber>::ScheduledChange(sp_finality_grandpa::ScheduledChange {
|
||||||
|
next_authorities: std::iter::repeat((ALICE.into(), 1))
|
||||||
|
.take(MAX_BRIDGED_AUTHORITIES as usize + 1)
|
||||||
|
.collect(),
|
||||||
|
delay: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn large_digest() -> Digest {
|
||||||
|
Digest { logs: vec![DigestItem::Other(vec![42; MAX_HEADER_SIZE as _])] }
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn init_root_or_owner_origin_can_initialize_pallet() {
|
fn init_root_or_owner_origin_can_initialize_pallet() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
@@ -715,6 +767,45 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_fails_if_there_are_too_many_authorities_in_the_set() {
|
||||||
|
run_test(|| {
|
||||||
|
let genesis = test_header(0);
|
||||||
|
let init_data = InitializationData {
|
||||||
|
header: Box::new(genesis),
|
||||||
|
authority_list: std::iter::repeat(authority_list().remove(0))
|
||||||
|
.take(MAX_BRIDGED_AUTHORITIES as usize + 1)
|
||||||
|
.collect(),
|
||||||
|
set_id: 1,
|
||||||
|
operating_mode: BasicOperatingMode::Normal,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_noop!(
|
||||||
|
Pallet::<TestRuntime>::initialize(Origin::root(), init_data),
|
||||||
|
Error::<TestRuntime>::TooManyAuthoritiesInSet,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_fails_if_header_is_too_large() {
|
||||||
|
run_test(|| {
|
||||||
|
let mut genesis = test_header(0);
|
||||||
|
genesis.digest = large_digest();
|
||||||
|
let init_data = InitializationData {
|
||||||
|
header: Box::new(genesis),
|
||||||
|
authority_list: authority_list(),
|
||||||
|
set_id: 1,
|
||||||
|
operating_mode: BasicOperatingMode::Normal,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_noop!(
|
||||||
|
Pallet::<TestRuntime>::initialize(Origin::root(), init_data),
|
||||||
|
Error::<TestRuntime>::TooLargeHeader,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pallet_rejects_transactions_if_halted() {
|
fn pallet_rejects_transactions_if_halted() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
@@ -880,7 +971,8 @@ mod tests {
|
|||||||
// Make sure that the authority set actually changed upon importing our header
|
// Make sure that the authority set actually changed upon importing our header
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
<CurrentAuthoritySet<TestRuntime>>::get(),
|
<CurrentAuthoritySet<TestRuntime>>::get(),
|
||||||
bp_header_chain::AuthoritySet::new(next_authorities, next_set_id),
|
StoredAuthoritySet::<TestRuntime, ()>::try_new(next_authorities, next_set_id)
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -935,6 +1027,56 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn importing_header_rejects_header_with_too_many_authorities() {
|
||||||
|
run_test(|| {
|
||||||
|
initialize_substrate_bridge();
|
||||||
|
|
||||||
|
// Need to update the header digest to indicate that our header signals an authority set
|
||||||
|
// change. However, the change doesn't happen until the next block.
|
||||||
|
let mut header = test_header(2);
|
||||||
|
header.digest = many_authorities_log();
|
||||||
|
|
||||||
|
// Create a valid justification for the header
|
||||||
|
let justification = make_default_justification(&header);
|
||||||
|
|
||||||
|
// Should not be allowed to import this header
|
||||||
|
assert_err!(
|
||||||
|
Pallet::<TestRuntime>::submit_finality_proof(
|
||||||
|
Origin::signed(1),
|
||||||
|
Box::new(header),
|
||||||
|
justification
|
||||||
|
),
|
||||||
|
<Error<TestRuntime>>::TooManyAuthoritiesInSet
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn importing_header_rejects_header_if_it_is_too_large() {
|
||||||
|
run_test(|| {
|
||||||
|
initialize_substrate_bridge();
|
||||||
|
|
||||||
|
// Need to update the header digest to indicate that our header signals an authority set
|
||||||
|
// change. However, the change doesn't happen until the next block.
|
||||||
|
let mut header = test_header(2);
|
||||||
|
header.digest = large_digest();
|
||||||
|
|
||||||
|
// Create a valid justification for the header
|
||||||
|
let justification = make_default_justification(&header);
|
||||||
|
|
||||||
|
// Should not be allowed to import this header
|
||||||
|
assert_err!(
|
||||||
|
Pallet::<TestRuntime>::submit_finality_proof(
|
||||||
|
Origin::signed(1),
|
||||||
|
Box::new(header),
|
||||||
|
justification
|
||||||
|
),
|
||||||
|
<Error<TestRuntime>>::TooLargeHeader
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() {
|
fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
@@ -959,7 +1101,10 @@ mod tests {
|
|||||||
|
|
||||||
let hash = header.hash();
|
let hash = header.hash();
|
||||||
<BestFinalized<TestRuntime>>::put((2, hash));
|
<BestFinalized<TestRuntime>>::put((2, hash));
|
||||||
<ImportedHeaders<TestRuntime>>::insert(hash, header);
|
<ImportedHeaders<TestRuntime>>::insert(
|
||||||
|
hash,
|
||||||
|
StoredBridgedHeader::try_from_bridged_header(header).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_ok!(
|
assert_ok!(
|
||||||
Pallet::<TestRuntime>::parse_finalized_storage_proof(hash, storage_proof, |_| (),),
|
Pallet::<TestRuntime>::parse_finalized_storage_proof(hash, storage_proof, |_| (),),
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ pub type TestNumber = crate::BridgedBlockNumber<TestRuntime, ()>;
|
|||||||
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
||||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
|
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
|
||||||
|
|
||||||
|
pub const MAX_BRIDGED_AUTHORITIES: u32 = 2048;
|
||||||
|
pub const MAX_HEADER_SIZE: u32 = 65536;
|
||||||
|
|
||||||
use crate as grandpa;
|
use crate as grandpa;
|
||||||
|
|
||||||
construct_runtime! {
|
construct_runtime! {
|
||||||
@@ -91,6 +94,8 @@ impl grandpa::Config for TestRuntime {
|
|||||||
type BridgedChain = TestBridgedChain;
|
type BridgedChain = TestBridgedChain;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = frame_support::traits::ConstU32<MAX_BRIDGED_AUTHORITIES>;
|
||||||
|
type MaxBridgedHeaderSize = frame_support::traits::ConstU32<MAX_HEADER_SIZE>;
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
// Copyright 2022 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Bridges Common.
|
||||||
|
|
||||||
|
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Wrappers for public types that are implementing `MaxEncodedLen`
|
||||||
|
|
||||||
|
use crate::{BridgedHeader, Config, Error};
|
||||||
|
|
||||||
|
use bp_header_chain::AuthoritySet;
|
||||||
|
use codec::{Decode, Encode, MaxEncodedLen};
|
||||||
|
use frame_support::{traits::Get, BoundedVec, RuntimeDebugNoBound};
|
||||||
|
use scale_info::{Type, TypeInfo};
|
||||||
|
use sp_finality_grandpa::{AuthorityId, AuthorityList, AuthorityWeight, SetId};
|
||||||
|
|
||||||
|
/// A bounded list of Grandpa authorities with associated weights.
|
||||||
|
pub type StoredAuthorityList<MaxBridgedAuthorities> =
|
||||||
|
BoundedVec<(AuthorityId, AuthorityWeight), MaxBridgedAuthorities>;
|
||||||
|
|
||||||
|
/// A bounded GRANDPA Authority List and ID.
|
||||||
|
#[derive(Clone, Decode, Encode, Eq, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound)]
|
||||||
|
#[scale_info(skip_type_params(T, I))]
|
||||||
|
pub struct StoredAuthoritySet<T: Config<I>, I: 'static> {
|
||||||
|
/// List of GRANDPA authorities for the current round.
|
||||||
|
pub authorities: StoredAuthorityList<<T as Config<I>>::MaxBridgedAuthorities>,
|
||||||
|
/// Monotonic identifier of the current GRANDPA authority set.
|
||||||
|
pub set_id: SetId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> StoredAuthoritySet<T, I> {
|
||||||
|
/// Try to create a new bounded GRANDPA Authority Set from unbounded list.
|
||||||
|
///
|
||||||
|
/// Returns error if number of authorities in the provided list is too large.
|
||||||
|
pub fn try_new(authorities: AuthorityList, set_id: SetId) -> Result<Self, ()> {
|
||||||
|
Ok(Self { authorities: TryFrom::try_from(authorities)?, set_id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> PartialEq for StoredAuthoritySet<T, I> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.set_id == other.set_id && self.authorities == other.authorities
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> Default for StoredAuthoritySet<T, I> {
|
||||||
|
fn default() -> Self {
|
||||||
|
StoredAuthoritySet { authorities: BoundedVec::default(), set_id: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> From<StoredAuthoritySet<T, I>> for AuthoritySet {
|
||||||
|
fn from(t: StoredAuthoritySet<T, I>) -> Self {
|
||||||
|
AuthoritySet { authorities: t.authorities.into(), set_id: t.set_id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A bounded chain header.
|
||||||
|
#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebugNoBound)]
|
||||||
|
pub struct StoredBridgedHeader<T: Config<I>, I: 'static>(pub BridgedHeader<T, I>);
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> StoredBridgedHeader<T, I> {
|
||||||
|
/// Construct `StoredBridgedHeader` from the `BridgedHeader` with all required checks.
|
||||||
|
pub fn try_from_bridged_header(header: BridgedHeader<T, I>) -> Result<Self, Error<T, I>> {
|
||||||
|
// this conversion is heavy (since we do encoding here), so we may want to optimize it later
|
||||||
|
// (e.g. by introducing custom Encode implementation, and turning `StoredBridgedHeader` into
|
||||||
|
// `enum StoredBridgedHeader { Decoded(BridgedHeader), Encoded(Vec<u8>) }`)
|
||||||
|
if header.encoded_size() > T::MaxBridgedHeaderSize::get() as usize {
|
||||||
|
Err(Error::TooLargeHeader)
|
||||||
|
} else {
|
||||||
|
Ok(StoredBridgedHeader(header))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> sp_std::ops::Deref for StoredBridgedHeader<T, I> {
|
||||||
|
type Target = BridgedHeader<T, I>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> TypeInfo for StoredBridgedHeader<T, I> {
|
||||||
|
type Identity = Self;
|
||||||
|
|
||||||
|
fn type_info() -> Type {
|
||||||
|
BridgedHeader::<T, I>::type_info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> MaxEncodedLen for StoredBridgedHeader<T, I> {
|
||||||
|
fn max_encoded_len() -> usize {
|
||||||
|
T::MaxBridgedHeaderSize::get() as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -95,6 +95,8 @@ impl pallet_bridge_grandpa::Config<pallet_bridge_grandpa::Instance1> for TestRun
|
|||||||
type BridgedChain = TestBridgedChain;
|
type BridgedChain = TestBridgedChain;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = frame_support::traits::ConstU32<5>;
|
||||||
|
type MaxBridgedHeaderSize = frame_support::traits::ConstU32<512>;
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +104,8 @@ impl pallet_bridge_grandpa::Config<pallet_bridge_grandpa::Instance2> for TestRun
|
|||||||
type BridgedChain = TestBridgedChain;
|
type BridgedChain = TestBridgedChain;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
type HeadersToKeep = HeadersToKeep;
|
type HeadersToKeep = HeadersToKeep;
|
||||||
|
type MaxBridgedAuthorities = frame_support::traits::ConstU32<5>;
|
||||||
|
type MaxBridgedHeaderSize = frame_support::traits::ConstU32<512>;
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,12 @@ pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 700_000_000;
|
|||||||
/// conditions.
|
/// conditions.
|
||||||
pub const SESSION_LENGTH: BlockNumber = 5 * time_units::MINUTES;
|
pub const SESSION_LENGTH: BlockNumber = 5 * time_units::MINUTES;
|
||||||
|
|
||||||
|
/// Maximal number of GRANDPA authorities at Millau.
|
||||||
|
pub const MAX_AUTHORITIES_COUNT: u32 = 5;
|
||||||
|
|
||||||
|
/// Maximal SCALE-encoded header size (in bytes) at Millau.
|
||||||
|
pub const MAX_HEADER_SIZE: u32 = 512;
|
||||||
|
|
||||||
/// Re-export `time_units` to make usage easier.
|
/// Re-export `time_units` to make usage easier.
|
||||||
pub use time_units::*;
|
pub use time_units::*;
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 700_000_000;
|
|||||||
/// conditions.
|
/// conditions.
|
||||||
pub const SESSION_LENGTH: BlockNumber = 4;
|
pub const SESSION_LENGTH: BlockNumber = 4;
|
||||||
|
|
||||||
|
/// Maximal number of GRANDPA authorities at Rialto.
|
||||||
|
pub const MAX_AUTHORITIES_COUNT: u32 = 5;
|
||||||
|
|
||||||
|
/// Maximal SCALE-encoded header size (in bytes) at Rialto.
|
||||||
|
pub const MAX_HEADER_SIZE: u32 = 512;
|
||||||
|
|
||||||
/// Re-export `time_units` to make usage easier.
|
/// Re-export `time_units` to make usage easier.
|
||||||
pub use time_units::*;
|
pub use time_units::*;
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,18 @@ pub const WITH_WESTEND_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeWestendParachains
|
|||||||
/// conditions.
|
/// conditions.
|
||||||
pub const SESSION_LENGTH: BlockNumber = 10 * time_units::MINUTES;
|
pub const SESSION_LENGTH: BlockNumber = 10 * time_units::MINUTES;
|
||||||
|
|
||||||
|
/// Maximal number of GRANDPA authorities at Westend.
|
||||||
|
///
|
||||||
|
/// Corresponds to the `MaxAuthorities` constant value from the Westend runtime configuration.
|
||||||
|
pub const MAX_AUTHORITIES_COUNT: u32 = 100_000;
|
||||||
|
|
||||||
|
/// Maximal SCALE-encoded header size (in bytes) at Westend.
|
||||||
|
///
|
||||||
|
/// 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_HEADER_SIZE: u32 = 4096 + MAX_AUTHORITIES_COUNT * 40;
|
||||||
|
|
||||||
/// Identifier of Westmint parachain at the Westend relay chain.
|
/// Identifier of Westmint parachain at the Westend relay chain.
|
||||||
pub const WESTMINT_PARACHAIN_ID: u32 = 2000;
|
pub const WESTMINT_PARACHAIN_ID: u32 = 2000;
|
||||||
|
|
||||||
|
|||||||
@@ -71,47 +71,6 @@ pub struct InitializationData<H: HeaderT> {
|
|||||||
pub operating_mode: BasicOperatingMode,
|
pub operating_mode: BasicOperatingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// base trait for verifying transaction inclusion proofs.
|
|
||||||
pub trait InclusionProofVerifier {
|
|
||||||
/// Transaction type.
|
|
||||||
type Transaction: Parameter;
|
|
||||||
/// Transaction inclusion proof type.
|
|
||||||
type TransactionInclusionProof: Parameter;
|
|
||||||
|
|
||||||
/// Verify that transaction is a part of given block.
|
|
||||||
///
|
|
||||||
/// Returns Some(transaction) if proof is valid and None otherwise.
|
|
||||||
fn verify_transaction_inclusion_proof(
|
|
||||||
proof: &Self::TransactionInclusionProof,
|
|
||||||
) -> Option<Self::Transaction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for pallets which want to keep track of finalized headers from a bridged chain.
|
|
||||||
pub trait HeaderChain<H, E> {
|
|
||||||
/// Get the best finalized header known to the header chain.
|
|
||||||
fn best_finalized() -> Option<H>;
|
|
||||||
|
|
||||||
/// Get the best authority set known to the header chain.
|
|
||||||
fn authority_set() -> AuthoritySet;
|
|
||||||
|
|
||||||
/// Write a header finalized by GRANDPA to the underlying pallet storage.
|
|
||||||
fn append_header(header: H) -> Result<(), E>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: Default, E> HeaderChain<H, E> for () {
|
|
||||||
fn best_finalized() -> Option<H> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn authority_set() -> AuthoritySet {
|
|
||||||
AuthoritySet::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append_header(_header: H) -> Result<(), E> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Abstract finality proof that is justifying block finality.
|
/// Abstract finality proof that is justifying block finality.
|
||||||
pub trait FinalityProof<Number>: Clone + Send + Sync + Debug {
|
pub trait FinalityProof<Number>: Clone + Send + Sync + Debug {
|
||||||
/// Return number of header that this proof is generated for.
|
/// Return number of header that this proof is generated for.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::HeaderIdProvider;
|
use crate::HeaderIdProvider;
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode, MaxEncodedLen};
|
||||||
use frame_support::{weights::Weight, Parameter};
|
use frame_support::{weights::Weight, Parameter};
|
||||||
use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero};
|
use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
@@ -111,6 +111,7 @@ pub trait Chain: Send + Sync + 'static {
|
|||||||
+ AsPrimitive<usize>
|
+ AsPrimitive<usize>
|
||||||
+ Default
|
+ Default
|
||||||
+ Saturating
|
+ Saturating
|
||||||
|
+ MaxEncodedLen
|
||||||
// original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but
|
// original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but
|
||||||
// `sp_runtime::generic::Era` requires block number -> `u64` conversion.
|
// `sp_runtime::generic::Era` requires block number -> `u64` conversion.
|
||||||
+ Into<u64>;
|
+ Into<u64>;
|
||||||
@@ -130,7 +131,8 @@ pub trait Chain: Send + Sync + 'static {
|
|||||||
+ SimpleBitOps
|
+ SimpleBitOps
|
||||||
+ AsRef<[u8]>
|
+ AsRef<[u8]>
|
||||||
+ AsMut<[u8]>
|
+ AsMut<[u8]>
|
||||||
+ MaybeMallocSizeOf;
|
+ MaybeMallocSizeOf
|
||||||
|
+ MaxEncodedLen;
|
||||||
|
|
||||||
/// A type that fulfills the abstract idea of what a Substrate hasher (a type
|
/// A type that fulfills the abstract idea of what a Substrate hasher (a type
|
||||||
/// that produces hashes) is.
|
/// that produces hashes) is.
|
||||||
@@ -148,7 +150,13 @@ pub trait Chain: Send + Sync + 'static {
|
|||||||
+ MaybeSerializeDeserialize;
|
+ MaybeSerializeDeserialize;
|
||||||
|
|
||||||
/// The user account identifier type for the runtime.
|
/// The user account identifier type for the runtime.
|
||||||
type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord;
|
type AccountId: Parameter
|
||||||
|
+ Member
|
||||||
|
+ MaybeSerializeDeserialize
|
||||||
|
+ Debug
|
||||||
|
+ MaybeDisplay
|
||||||
|
+ Ord
|
||||||
|
+ MaxEncodedLen;
|
||||||
/// Balance of an account in native tokens.
|
/// Balance of an account in native tokens.
|
||||||
///
|
///
|
||||||
/// The chain may support multiple tokens, but this particular type is for token that is used
|
/// The chain may support multiple tokens, but this particular type is for token that is used
|
||||||
@@ -165,7 +173,8 @@ pub trait Chain: Send + Sync + 'static {
|
|||||||
+ PartialOrd
|
+ PartialOrd
|
||||||
+ SaturatingAdd
|
+ SaturatingAdd
|
||||||
+ Zero
|
+ Zero
|
||||||
+ TryFrom<sp_core::U256>;
|
+ TryFrom<sp_core::U256>
|
||||||
|
+ MaxEncodedLen;
|
||||||
/// Index of a transaction used by the chain.
|
/// Index of a transaction used by the chain.
|
||||||
type Index: Parameter
|
type Index: Parameter
|
||||||
+ Member
|
+ Member
|
||||||
@@ -175,7 +184,8 @@ pub trait Chain: Send + Sync + 'static {
|
|||||||
+ MaybeDisplay
|
+ MaybeDisplay
|
||||||
+ MaybeSerializeDeserialize
|
+ MaybeSerializeDeserialize
|
||||||
+ AtLeast32Bit
|
+ AtLeast32Bit
|
||||||
+ Copy;
|
+ Copy
|
||||||
|
+ MaxEncodedLen;
|
||||||
/// Signature type, used on this chain.
|
/// Signature type, used on this chain.
|
||||||
type Signature: Parameter + Verify;
|
type Signature: Parameter + Verify;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user