partner_chains_demo_runtime/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
3#![recursion_limit = "256"]
4#![allow(deprecated)]
5
6#[cfg(feature = "runtime-benchmarks")]
7#[macro_use]
8extern crate frame_benchmarking;
9
10extern crate alloc;
11
12use alloc::collections::BTreeMap;
13use alloc::string::String;
14use authority_selection_inherents::{
15	AuthoritySelectionInputs, CommitteeMember, PermissionedCandidateDataError,
16	RegistrationDataError, StakeError, select_authorities, validate_permissioned_candidate_data,
17};
18use frame_support::genesis_builder_helper::{build_state, get_preset};
19use frame_support::inherent::ProvideInherent;
20use frame_support::weights::constants::RocksDbWeight as RuntimeDbWeight;
21use frame_support::{
22	BoundedVec, construct_runtime, parameter_types,
23	traits::{ConstBool, ConstU8, ConstU16, ConstU32, ConstU64, ConstU128},
24	weights::{IdentityFee, constants::WEIGHT_REF_TIME_PER_SECOND},
25};
26use frame_system::EnsureRoot;
27use opaque::SessionKeys;
28use pallet_block_producer_metadata;
29use pallet_grandpa::AuthorityId as GrandpaId;
30use pallet_session_validator_management::session_manager::ValidatorManagementSessionManager;
31use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
32use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
33use scale_info::TypeInfo;
34use serde::{Deserialize, Serialize};
35use sidechain_domain::byte_string::{BoundedString, ByteString, SizedByteString};
36use sidechain_domain::{
37	CrossChainPublicKey, DelegatorKey, MainchainKeyHash, PermissionedCandidateData,
38	RegistrationData, ScEpochNumber, ScSlotNumber, StakeDelegation, StakePoolPublicKey, UtxoId,
39};
40use sidechain_slots::Slot;
41use sp_api::impl_runtime_apis;
42use sp_block_participation::AsCardanoSPO;
43use sp_consensus_aura::sr25519::AuthorityId as AuraId;
44#[cfg(feature = "runtime-benchmarks")]
45use sp_core::ByteArray;
46use sp_core::{OpaqueMetadata, crypto::KeyTypeId};
47use sp_governed_map::MainChainScriptsV1;
48use sp_inherents::InherentIdentifier;
49use sp_partner_chains_bridge::{BridgeDataCheckpoint, MainChainScripts as BridgeMainChainScripts};
50use sp_runtime::{
51	ApplyExtrinsicResult, MultiSignature, Perbill, generic, impl_opaque_keys,
52	traits::{
53		AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, OpaqueKeys,
54		Verify,
55	},
56	transaction_validity::{TransactionSource, TransactionValidity},
57};
58use sp_sidechain::SidechainStatus;
59use sp_std::prelude::*;
60use sp_version::RuntimeVersion;
61use sp_weights::Weight;
62
63// Make the WASM binary available.
64#[cfg(feature = "std")]
65include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
66
67pub mod genesis_config_presets;
68
69#[cfg(test)]
70mod mock;
71
72#[cfg(test)]
73mod header_tests;
74
75mod test_helper_pallet;
76
77/// An index to a block.
78pub type BlockNumber = u32;
79
80/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
81pub type Signature = MultiSignature;
82
83/// Some way of identifying an account on the chain. We intentionally make it equivalent
84/// to the public key of our transaction signing scheme.
85pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
86
87/// Balance of an account.
88pub type Balance = u128;
89
90/// Index of a transaction in the chain.
91pub type Nonce = u32;
92
93/// A hash of some data used by the chain.
94pub type Hash = sp_core::H256;
95
96/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
97/// the specifics of the runtime. They can then be made to be agnostic over specific formats
98/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
99/// to even the core data structures.
100pub mod opaque {
101	use super::*;
102	use authority_selection_inherents::MaybeFromCandidateKeys;
103	use parity_scale_codec::MaxEncodedLen;
104	use sp_core::{ed25519, sr25519};
105	pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
106
107	/// Opaque block header type.
108	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
109	/// Opaque block type.
110	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
111	/// Opaque block identifier type.
112	pub type BlockId = generic::BlockId<Block>;
113
114	pub const CROSS_CHAIN: KeyTypeId = KeyTypeId(*b"crch");
115	pub struct CrossChainRuntimeAppPublic;
116
117	pub mod cross_chain_app {
118		use super::CROSS_CHAIN;
119		use parity_scale_codec::MaxEncodedLen;
120		use sidechain_domain::SidechainPublicKey;
121		use sp_core::crypto::AccountId32;
122		use sp_runtime::MultiSigner;
123		use sp_runtime::app_crypto::{app_crypto, ecdsa};
124		use sp_runtime::traits::IdentifyAccount;
125		use sp_std::vec::Vec;
126
127		app_crypto!(ecdsa, CROSS_CHAIN);
128		impl MaxEncodedLen for Signature {
129			fn max_encoded_len() -> usize {
130				ecdsa::Signature::max_encoded_len()
131			}
132		}
133
134		impl From<Signature> for Vec<u8> {
135			fn from(value: Signature) -> Self {
136				value.into_inner().0.to_vec()
137			}
138		}
139
140		impl From<Public> for AccountId32 {
141			fn from(value: Public) -> Self {
142				MultiSigner::from(ecdsa::Public::from(value)).into_account()
143			}
144		}
145
146		impl From<Public> for Vec<u8> {
147			fn from(value: Public) -> Self {
148				value.into_inner().0.to_vec()
149			}
150		}
151
152		impl TryFrom<SidechainPublicKey> for Public {
153			type Error = SidechainPublicKey;
154			fn try_from(pubkey: SidechainPublicKey) -> Result<Self, Self::Error> {
155				let cross_chain_public_key =
156					Public::try_from(pubkey.0.as_slice()).map_err(|_| pubkey)?;
157				Ok(cross_chain_public_key)
158			}
159		}
160	}
161
162	impl_opaque_keys! {
163		#[derive(MaxEncodedLen, PartialOrd, Ord)]
164		pub struct SessionKeys {
165			pub aura: Aura,
166			pub grandpa: Grandpa,
167		}
168	}
169	impl From<(sr25519::Public, ed25519::Public)> for SessionKeys {
170		fn from((aura, grandpa): (sr25519::Public, ed25519::Public)) -> Self {
171			Self { aura: aura.into(), grandpa: grandpa.into() }
172		}
173	}
174
175	impl MaybeFromCandidateKeys for SessionKeys {}
176
177	impl_opaque_keys! {
178		pub struct CrossChainKey {
179			pub account: CrossChainPublic,
180		}
181	}
182}
183
184pub type CrossChainPublic = opaque::cross_chain_app::Public;
185
186// To learn more about runtime versioning, see:
187// https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning
188#[sp_version::runtime_version]
189pub const VERSION: RuntimeVersion = RuntimeVersion {
190	spec_name: alloc::borrow::Cow::Borrowed("cardano-sidechain"),
191	impl_name: alloc::borrow::Cow::Borrowed("cardano-sidechain"),
192	authoring_version: 1,
193	// The version of the runtime specification. A full node will not attempt to use its native
194	//   runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
195	//   `spec_version`, and `authoring_version` are the same between Wasm and native.
196	// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
197	//   the compatible custom types.
198	spec_version: 170,
199	impl_version: 1,
200	apis: RUNTIME_API_VERSIONS,
201	transaction_version: 1,
202	system_version: 1,
203};
204
205/// This determines the average expected block time that we are targeting.
206/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`.
207/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
208/// up by `pallet_aura` to implement `fn slot_duration()`.
209///
210/// Change this to adjust the block time.
211pub const MILLISECS_PER_BLOCK: u64 = 6000;
212
213// NOTE: Currently it is not possible to change the slot duration after the chain has started.
214//       Attempting to do so will brick block production.
215pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
216
217// Time is measured by number of blocks.
218pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
219pub const HOURS: BlockNumber = MINUTES * 60;
220pub const DAYS: BlockNumber = HOURS * 24;
221
222const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
223
224/// We allow for 2 seconds of compute with a 6 second average block time.
225pub const MAXIMUM_BLOCK_WEIGHT: Weight =
226	Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
227pub const MAXIMUM_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;
228
229parameter_types! {
230	pub const BlockHashCount: BlockNumber = 2400;
231	pub const Version: RuntimeVersion = VERSION;
232	pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights
233		::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO);
234	pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength
235		::max_with_normal_ratio(MAXIMUM_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO);
236	pub const SS58Prefix: u8 = 42;
237}
238
239// Configure FRAME pallets to include in runtime.
240
241impl frame_system::Config for Runtime {
242	/// The basic call filter to use in dispatchable.
243	type BaseCallFilter = frame_support::traits::Everything;
244	/// The block type for the runtime.
245	type Block = Block;
246	/// The type for storing how many extrinsics an account has signed.
247	type Nonce = Nonce;
248	/// Block & extrinsics weights: base values and limits.
249	type BlockWeights = BlockWeights;
250	/// The maximum length of a block (in bytes).
251	type BlockLength = BlockLength;
252	/// The identifier used to distinguish between accounts.
253	type AccountId = AccountId;
254	/// The aggregated dispatch type that is available for extrinsics.
255	type RuntimeCall = RuntimeCall;
256	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
257	type Lookup = AccountIdLookup<AccountId, ()>;
258	/// The type for hashing blocks and tries.
259	type Hash = Hash;
260	/// The hashing algorithm used.
261	type Hashing = BlakeTwo256;
262	/// The ubiquitous event type.
263	type RuntimeEvent = RuntimeEvent;
264	/// The ubiquitous origin type.
265	type RuntimeOrigin = RuntimeOrigin;
266	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
267	type BlockHashCount = BlockHashCount;
268	/// The weight of database operations that the runtime can invoke.
269	type DbWeight = RuntimeDbWeight;
270	/// Version of the runtime.
271	type Version = Version;
272	/// Converts a module to the index of the module in `construct_runtime!`.
273	///
274	/// This type is being generated by `construct_runtime!`.
275	type PalletInfo = PalletInfo;
276	/// What to do if a new account is created.
277	type OnNewAccount = ();
278	/// What to do if an account is fully reaped from the system.
279	type OnKilledAccount = ();
280	/// The data to be stored in an account.
281	type AccountData = pallet_balances::AccountData<Balance>;
282	/// Weight information for the extrinsics of this pallet.
283	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Runtime>;
284	// WeightInfo for extensions is present but not accessible in polkadot-stable2412-1, because of that we are using () in our demo runtime
285	type ExtensionsWeightInfo = ();
286	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
287	type SS58Prefix = SS58Prefix;
288	/// The set code logic, just the default since we're not a parachain.
289	type OnSetCode = ();
290	type MaxConsumers = frame_support::traits::ConstU32<16>;
291	type RuntimeTask = RuntimeTask;
292	type SingleBlockMigrations = ();
293	type MultiBlockMigrator = ();
294	type PreInherents = ();
295	type PostInherents = ();
296	type PostTransactions = ();
297}
298
299impl pallet_native_token_management::Config for Runtime {
300	type TokenTransferHandler = TestHelperPallet;
301	type MainChainScriptsOrigin = EnsureRoot<Self::AccountId>;
302	type WeightInfo = pallet_native_token_management::weights::SubstrateWeight<Runtime>;
303}
304
305impl pallet_aura::Config for Runtime {
306	type AuthorityId = AuraId;
307	type DisabledValidators = ();
308	type MaxAuthorities = MaxValidators;
309	type AllowMultipleBlocksPerSlot = ConstBool<false>;
310	type SlotDuration = ConstU64<SLOT_DURATION>;
311}
312
313pallet_partner_chains_session::impl_pallet_session_config!(Runtime);
314
315impl pallet_grandpa::Config for Runtime {
316	type RuntimeEvent = RuntimeEvent;
317
318	type WeightInfo = ();
319	type MaxAuthorities = MaxValidators;
320	type MaxNominators = ConstU32<0>;
321	type MaxSetIdSessionEntries = ConstU64<0>;
322
323	type KeyOwnerProof = sp_core::Void;
324	type EquivocationReportSystem = ();
325}
326
327impl pallet_timestamp::Config for Runtime {
328	/// A timestamp: milliseconds since the unix epoch.
329	type Moment = u64;
330	type OnTimestampSet = Aura;
331	type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
332	type WeightInfo = pallet_timestamp::weights::SubstrateWeight<Runtime>;
333}
334
335/// Existential deposit.
336pub const EXISTENTIAL_DEPOSIT: u128 = 500;
337
338impl pallet_balances::Config for Runtime {
339	type MaxLocks = ConstU32<50>;
340	type MaxReserves = ();
341	type ReserveIdentifier = [u8; 8];
342	/// The type for recording an account's balance.
343	type Balance = Balance;
344	/// The ubiquitous event type.
345	type RuntimeEvent = RuntimeEvent;
346	type DustRemoval = ();
347	type ExistentialDeposit = ConstU128<EXISTENTIAL_DEPOSIT>;
348	type AccountStore = System;
349	type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
350	type FreezeIdentifier = ();
351	type MaxFreezes = ();
352	type RuntimeHoldReason = RuntimeHoldReason;
353	type RuntimeFreezeReason = RuntimeFreezeReason;
354	type DoneSlashHandler = ();
355}
356
357parameter_types! {
358	pub FeeMultiplier: Multiplier = Multiplier::one();
359}
360
361impl pallet_transaction_payment::Config for Runtime {
362	type RuntimeEvent = RuntimeEvent;
363	type OnChargeTransaction = FungibleAdapter<Balances, ()>;
364	type OperationalFeeMultiplier = ConstU8<5>;
365	type WeightToFee = IdentityFee<Balance>;
366	type LengthToFee = IdentityFee<Balance>;
367	type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
368	type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
369}
370
371impl pallet_sudo::Config for Runtime {
372	type RuntimeEvent = RuntimeEvent;
373	type RuntimeCall = RuntimeCall;
374	type WeightInfo = pallet_sudo::weights::SubstrateWeight<Runtime>;
375}
376
377impl pallet_partner_chains_session::Config for Runtime {
378	type ValidatorId = <Self as frame_system::Config>::AccountId;
379	type ShouldEndSession = ValidatorManagementSessionManager<Runtime>;
380	type NextSessionRotation = ();
381	type SessionManager = ValidatorManagementSessionManager<Runtime>;
382	type SessionHandler = <opaque::SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
383	type Keys = opaque::SessionKeys;
384}
385
386parameter_types! {
387	pub const MaxValidators: u32 = 1024;
388}
389
390impl pallet_session_validator_management::Config for Runtime {
391	type MaxValidators = MaxValidators;
392	type AuthorityId = CrossChainPublic;
393	type AuthorityKeys = SessionKeys;
394	type AuthoritySelectionInputs = AuthoritySelectionInputs;
395	type ScEpochNumber = ScEpochNumber;
396	type WeightInfo = pallet_session_validator_management::weights::SubstrateWeight<Runtime>;
397	type CommitteeMember = CommitteeMember<CrossChainPublic, SessionKeys>;
398	type MainChainScriptsOrigin = EnsureRoot<Self::AccountId>;
399
400	fn select_authorities(
401		input: AuthoritySelectionInputs,
402		sidechain_epoch: ScEpochNumber,
403	) -> Option<BoundedVec<Self::CommitteeMember, Self::MaxValidators>> {
404		select_authorities::<opaque::cross_chain_app::Public, SessionKeys, MaxValidators>(
405			Sidechain::genesis_utxo(),
406			input,
407			sidechain_epoch,
408		)
409	}
410
411	fn current_epoch_number() -> ScEpochNumber {
412		Sidechain::current_epoch_number()
413	}
414}
415
416parameter_types! {
417	pub const TokenConversionRate: u128 = 1_000_000_000u128;
418	pub const MaxTransactions: u32 = 256u32;
419}
420
421impl pallet_sidechain::Config for Runtime {
422	fn current_slot_number() -> ScSlotNumber {
423		ScSlotNumber(*pallet_aura::CurrentSlot::<Self>::get())
424	}
425	type OnNewEpoch = TestHelperPallet;
426}
427
428pub type BeneficiaryId = sidechain_domain::byte_string::SizedByteString<32>;
429
430#[derive(
431	MaxEncodedLen,
432	Encode,
433	Decode,
434	DecodeWithMemTracking,
435	Clone,
436	TypeInfo,
437	PartialEq,
438	Eq,
439	Debug,
440	Hash,
441	PartialOrd,
442	Ord,
443)]
444pub enum BlockAuthor {
445	Incentivized(CrossChainPublic, StakePoolPublicKey),
446	ProBono(CrossChainPublic),
447}
448impl BlockAuthor {
449	pub fn id(&self) -> &CrossChainPublic {
450		match self {
451			Self::Incentivized(id, _) => id,
452			Self::ProBono(id) => id,
453		}
454	}
455}
456impl From<CommitteeMember<CrossChainPublic, SessionKeys>> for BlockAuthor {
457	fn from(value: CommitteeMember<CrossChainPublic, SessionKeys>) -> Self {
458		match value {
459			CommitteeMember::Permissioned { id, .. } => BlockAuthor::ProBono(id),
460			CommitteeMember::Registered { id, stake_pool_pub_key, .. } => {
461				BlockAuthor::Incentivized(id, stake_pool_pub_key)
462			},
463		}
464	}
465}
466
467impl AsCardanoSPO for BlockAuthor {
468	fn as_cardano_spo(&self) -> Option<MainchainKeyHash> {
469		match self {
470			BlockAuthor::Incentivized(_, key) => Some(key.hash()),
471			BlockAuthor::ProBono(_) => None,
472		}
473	}
474}
475
476pub const MAX_METADATA_URL_LENGTH: u32 = 512;
477
478#[derive(
479	Clone,
480	Debug,
481	MaxEncodedLen,
482	Encode,
483	Decode,
484	DecodeWithMemTracking,
485	Serialize,
486	Deserialize,
487	PartialEq,
488	Eq,
489	TypeInfo,
490)]
491pub struct BlockProducerMetadataType {
492	pub url: BoundedString<ConstU32<MAX_METADATA_URL_LENGTH>>,
493	pub hash: SizedByteString<32>,
494}
495
496#[cfg(feature = "runtime-benchmarks")]
497pub struct PalletBlockProductionLogBenchmarkHelper;
498
499#[cfg(feature = "runtime-benchmarks")]
500impl pallet_block_production_log::benchmarking::BenchmarkHelper<BlockAuthor>
501	for PalletBlockProductionLogBenchmarkHelper
502{
503	fn producer_id() -> BlockAuthor {
504		let id = sp_core::ecdsa::Public::from_slice(&[0u8; 33]).unwrap().into();
505		BlockAuthor::ProBono(id)
506	}
507}
508
509#[cfg(feature = "runtime-benchmarks")]
510pub struct PalletBlockProducerMetadataBenchmarkHelper;
511
512#[cfg(feature = "runtime-benchmarks")]
513impl
514	pallet_block_producer_metadata::benchmarking::BenchmarkHelper<
515		BlockProducerMetadataType,
516		AccountId,
517	> for PalletBlockProducerMetadataBenchmarkHelper
518{
519	fn genesis_utxo() -> UtxoId {
520		Sidechain::genesis_utxo()
521	}
522
523	fn metadata() -> BlockProducerMetadataType {
524		BlockProducerMetadataType {
525			url: "https://cool.stuff/spo.json".try_into().unwrap(),
526			hash: SizedByteString::from([0; 32]),
527		}
528	}
529
530	fn cross_chain_pub_key() -> sidechain_domain::CrossChainPublicKey {
531		sidechain_domain::CrossChainPublicKey(
532			hex_literal::hex!("020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a1")
533				.to_vec(),
534		)
535	}
536
537	fn cross_chain_sign_key() -> pallet_block_producer_metadata::benchmarking::SecretKey {
538		pallet_block_producer_metadata::benchmarking::SecretKey::from_slice(&hex_literal::hex!(
539			"cb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb4726854"
540		))
541		.unwrap()
542	}
543
544	fn upsert_valid_before() -> u64 {
545		11751276163
546	}
547
548	fn delete_valid_before() -> u64 {
549		11751276230
550	}
551}
552
553impl pallet_block_production_log::Config for Runtime {
554	type BlockProducerId = BlockAuthor;
555	type WeightInfo = pallet_block_production_log::weights::SubstrateWeight<Runtime>;
556
557	fn current_slot() -> sp_consensus_slots::Slot {
558		let slot: u64 = pallet_aura::CurrentSlot::<Runtime>::get().into();
559		sp_consensus_slots::Slot::from(slot)
560	}
561
562	#[cfg(feature = "runtime-benchmarks")]
563	type BenchmarkHelper = PalletBlockProductionLogBenchmarkHelper;
564}
565
566parameter_types! {
567	/// Amount of tokens to burn when making irreversible, forever association
568	pub const AddressAssociationBurnAmount: Balance = 1_000_000;
569}
570
571impl pallet_address_associations::Config for Runtime {
572	type WeightInfo = pallet_address_associations::weights::SubstrateWeight<Runtime>;
573
574	type PartnerChainAddress = AccountId;
575	type Currency = Balances;
576	type BurnAmount = AddressAssociationBurnAmount;
577
578	fn genesis_utxo() -> UtxoId {
579		Sidechain::genesis_utxo()
580	}
581
582	type OnNewAssociation = TestHelperPallet;
583}
584
585#[cfg(feature = "runtime-benchmarks")]
586pub struct PalletBlockProducerFeesBenchmarkHelper;
587
588#[cfg(feature = "runtime-benchmarks")]
589impl pallet_block_producer_fees::benchmarking::BenchmarkHelper<AccountId>
590	for PalletBlockProducerFeesBenchmarkHelper
591{
592	fn account_id(i: u8) -> AccountId {
593		sp_core::sr25519::Public::from_raw([i; 32]).into()
594	}
595}
596
597impl pallet_block_producer_fees::Config for Runtime {
598	type WeightInfo = ();
599
600	type HistoricalChangesPerProducer = ConstU16<5>;
601
602	fn current_slot() -> sp_consensus_slots::Slot {
603		let slot: u64 = pallet_aura::CurrentSlot::<Runtime>::get().into();
604		sp_consensus_slots::Slot::from(slot)
605	}
606
607	#[cfg(feature = "runtime-benchmarks")]
608	type BenchmarkHelper = PalletBlockProducerFeesBenchmarkHelper;
609}
610
611parameter_types! {
612	/// Amount of tokens to hold when upserting block producer metadata.
613	pub const MetadataHoldAmount: Balance = 1_000_000;
614}
615
616impl pallet_block_producer_metadata::Config for Runtime {
617	type WeightInfo = pallet_block_producer_metadata::weights::SubstrateWeight<Runtime>;
618
619	type BlockProducerMetadata = BlockProducerMetadataType;
620
621	fn genesis_utxo() -> UtxoId {
622		Sidechain::genesis_utxo()
623	}
624
625	fn current_time() -> u64 {
626		pallet_timestamp::Now::<Runtime>::get() / 1000
627	}
628
629	type Currency = Balances;
630	type HoldAmount = MetadataHoldAmount;
631	type RuntimeHoldReason = RuntimeHoldReason;
632
633	#[cfg(feature = "runtime-benchmarks")]
634	type BenchmarkHelper = PalletBlockProducerMetadataBenchmarkHelper;
635}
636
637impl pallet_block_participation::Config for Runtime {
638	type WeightInfo = pallet_block_participation::weights::SubstrateWeight<Runtime>;
639	type BlockAuthor = BlockAuthor;
640	type DelegatorId = DelegatorKey;
641
642	fn should_release_data(slot: sidechain_slots::Slot) -> Option<sidechain_slots::Slot> {
643		TestHelperPallet::should_release_participation_data(slot)
644	}
645
646	fn blocks_produced_up_to_slot(slot: Slot) -> impl Iterator<Item = (Slot, BlockAuthor)> {
647		BlockProductionLog::peek_prefix(slot)
648	}
649
650	fn discard_blocks_produced_up_to_slot(slot: Slot) {
651		BlockProductionLog::drop_prefix(&slot)
652	}
653
654	const TARGET_INHERENT_ID: InherentIdentifier = TestHelperPallet::INHERENT_IDENTIFIER;
655}
656
657parameter_types! {
658	pub const MaxChanges: u32 = 16;
659	pub const MaxKeyLength: u32 = 64;
660	pub const MaxValueLength: u32 = 512;
661}
662
663impl pallet_governed_map::Config for Runtime {
664	type MaxChanges = MaxChanges;
665	type MaxKeyLength = MaxKeyLength;
666	type MaxValueLength = MaxValueLength;
667	type WeightInfo = pallet_governed_map::weights::SubstrateWeight<Runtime>;
668
669	type OnGovernedMappingChange = TestHelperPallet;
670	type MainChainScriptsOrigin = EnsureRoot<Self::AccountId>;
671
672	#[cfg(feature = "runtime-benchmarks")]
673	type BenchmarkHelper = ();
674}
675
676impl crate::test_helper_pallet::Config for Runtime {}
677
678parameter_types! {
679pub const MaxTransfersPerBlock: u32 = 256;}
680
681impl pallet_partner_chains_bridge::Config for Runtime {
682	type GovernanceOrigin = EnsureRoot<Runtime>;
683	type Recipient = AccountId;
684	type TransferHandler = TestHelperPallet;
685	type MaxTransfersPerBlock = MaxTransfersPerBlock;
686	type WeightInfo = ();
687
688	#[cfg(feature = "runtime-benchmarks")]
689	type BenchmarkHelper = ();
690}
691
692// Create the runtime by composing the FRAME pallets that were previously configured.
693construct_runtime!(
694	pub struct Runtime {
695		System: frame_system,
696		Timestamp: pallet_timestamp,
697		Aura: pallet_aura,
698		Grandpa: pallet_grandpa,
699		Balances: pallet_balances,
700		TransactionPayment: pallet_transaction_payment,
701		Sudo: pallet_sudo,
702		// Custom Pallets
703		// Sidechain pallet must come after the Aura pallet, since it gets the slot number from it
704		Sidechain: pallet_sidechain,
705		SessionCommitteeManagement: pallet_session_validator_management,
706		AddressAssociations: pallet_address_associations,
707		BlockProducerFees: pallet_block_producer_fees,
708		BlockProducerMetadata: pallet_block_producer_metadata,
709		BlockProductionLog: pallet_block_production_log,
710		BlockParticipation: pallet_block_participation,
711		// pallet_grandpa reads pallet_session::pallet::CurrentIndex storage.
712		// Only stub implementation of pallet_session should be wired.
713		// Partner Chains session_manager ValidatorManagementSessionManager writes to pallet_session::pallet::CurrentIndex.
714		// ValidatorManagementSessionManager is wired in by pallet_partner_chains_session.
715		PalletSession: pallet_session,
716		// The order matters!! pallet_partner_chains_session needs to come last for correct initialization order
717		Session: pallet_partner_chains_session,
718		NativeTokenManagement: pallet_native_token_management,
719		GovernedMap: pallet_governed_map,
720		Bridge: pallet_partner_chains_bridge,
721		TestHelperPallet: crate::test_helper_pallet,
722	}
723);
724
725/// The address format for describing accounts.
726pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
727/// Block header type as expected by this runtime.
728pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
729/// Block type as expected by this runtime.
730pub type Block = generic::Block<Header, UncheckedExtrinsic>;
731/// The SignedExtension to the basic transaction logic.
732pub type SignedExtra = (
733	frame_system::CheckNonZeroSender<Runtime>,
734	frame_system::CheckSpecVersion<Runtime>,
735	frame_system::CheckTxVersion<Runtime>,
736	frame_system::CheckGenesis<Runtime>,
737	frame_system::CheckEra<Runtime>,
738	frame_system::CheckNonce<Runtime>,
739	frame_system::CheckWeight<Runtime>,
740	pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
741);
742
743/// Unchecked extrinsic type as expected by this runtime.
744pub type UncheckedExtrinsic =
745	generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
746/// The payload being signed in transactions.
747pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
748pub type Migrations = (
749	pallet_session_validator_management::migrations::v1::LegacyToV1Migration<Runtime>,
750	// More migrations can be added here
751);
752/// Executive: handles dispatch to the various modules.
753pub type Executive = frame_executive::Executive<
754	Runtime,
755	Block,
756	frame_system::ChainContext<Runtime>,
757	Runtime,
758	AllPalletsWithSystem,
759	Migrations,
760>;
761
762#[cfg(feature = "runtime-benchmarks")]
763mod benches {
764	define_benchmarks!(
765		[frame_benchmarking, BaselineBench::<Runtime>]
766		[frame_system, SystemBench::<Runtime>]
767		[pallet_balances, Balances]
768		[pallet_timestamp, Timestamp]
769		[pallet_sudo, Sudo]
770		[pallet_native_token_management, NativeTokenManagement]
771		[pallet_block_production_log, BlockProductionLog]
772		[pallet_address_associations, AddressAssociations]
773		[pallet_block_producer_fees, BlockProducerFees]
774		[pallet_block_producer_metadata, BlockProducerMetadata]
775		[pallet_block_participation, BlockParticipation]
776		[pallet_governed_map, GovernedMap]
777		[pallet_partner_chains_bridge, Bridge]
778	);
779}
780
781impl_runtime_apis! {
782	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
783		fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
784			build_state::<RuntimeGenesisConfig>(config)
785		}
786
787		fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
788			get_preset::<RuntimeGenesisConfig>(id, crate::genesis_config_presets::get_preset)
789		}
790
791		fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
792			crate::genesis_config_presets::preset_names()
793		}
794	}
795
796	impl sp_api::Core<Block> for Runtime {
797		fn version() -> RuntimeVersion {
798			VERSION
799		}
800
801		fn execute_block(block: Block) {
802			Executive::execute_block(block);
803		}
804
805		fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
806			Executive::initialize_block(header)
807		}
808	}
809
810	impl sp_api::Metadata<Block> for Runtime {
811		fn metadata() -> OpaqueMetadata {
812			OpaqueMetadata::new(Runtime::metadata().into())
813		}
814
815		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
816			Runtime::metadata_at_version(version)
817		}
818
819		fn metadata_versions() -> sp_std::vec::Vec<u32> {
820			Runtime::metadata_versions()
821		}
822	}
823
824	impl sp_block_builder::BlockBuilder<Block> for Runtime {
825		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
826			Executive::apply_extrinsic(extrinsic)
827		}
828
829		fn finalize_block() -> <Block as BlockT>::Header {
830			Executive::finalize_block()
831		}
832
833		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
834			data.create_extrinsics()
835		}
836
837		fn check_inherents(
838			block: Block,
839			data: sp_inherents::InherentData,
840		) -> sp_inherents::CheckInherentsResult {
841			data.check_extrinsics(&block)
842		}
843	}
844
845	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
846		fn validate_transaction(
847			source: TransactionSource,
848			tx: <Block as BlockT>::Extrinsic,
849			block_hash: <Block as BlockT>::Hash,
850		) -> TransactionValidity {
851			Executive::validate_transaction(source, tx, block_hash)
852		}
853	}
854
855	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
856		fn offchain_worker(header: &<Block as BlockT>::Header) {
857			Executive::offchain_worker(header)
858		}
859	}
860
861	impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
862		fn slot_duration() -> sp_consensus_aura::SlotDuration {
863			sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
864		}
865
866		fn authorities() -> Vec<AuraId> {
867			pallet_aura::Authorities::<Runtime>::get().into_inner()
868		}
869	}
870
871	impl sp_session::SessionKeys<Block> for Runtime {
872		fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
873			// despite being named "generate" this function also adds generated keys to local keystore
874			opaque::CrossChainKey::generate(seed.clone());
875			opaque::SessionKeys::generate(seed)
876		}
877
878		fn decode_session_keys(
879			encoded: Vec<u8>,
880		) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
881			opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
882		}
883	}
884
885	impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
886		fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList {
887			Grandpa::grandpa_authorities()
888		}
889
890		fn current_set_id() -> sp_consensus_grandpa::SetId {
891			Grandpa::current_set_id()
892		}
893
894		fn submit_report_equivocation_unsigned_extrinsic(
895			_equivocation_proof: sp_consensus_grandpa::EquivocationProof<
896				<Block as BlockT>::Hash,
897				NumberFor<Block>,
898			>,
899			_key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
900		) -> Option<()> {
901			None
902		}
903
904		fn generate_key_ownership_proof(
905			_set_id: sp_consensus_grandpa::SetId,
906			_authority_id: GrandpaId,
907		) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
908			// NOTE: this is the only implementation possible since we've
909			// defined our key owner proof type as a bottom type (i.e. a type
910			// with no values).
911			None
912		}
913	}
914
915
916	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
917		fn account_nonce(account: AccountId) -> Nonce {
918			System::account_nonce(account)
919		}
920	}
921
922	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
923		fn query_info(
924			uxt: <Block as BlockT>::Extrinsic,
925			len: u32,
926		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
927			TransactionPayment::query_info(uxt, len)
928		}
929		fn query_fee_details(
930			uxt: <Block as BlockT>::Extrinsic,
931			len: u32,
932		) -> pallet_transaction_payment::FeeDetails<Balance> {
933			TransactionPayment::query_fee_details(uxt, len)
934		}
935		fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance {
936			TransactionPayment::weight_to_fee(weight)
937		}
938		fn query_length_to_fee(length: u32) -> Balance {
939			TransactionPayment::length_to_fee(length)
940		}
941	}
942
943	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
944		for Runtime
945	{
946		fn query_call_info(
947			call: RuntimeCall,
948			len: u32,
949		) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
950			TransactionPayment::query_call_info(call, len)
951		}
952		fn query_call_fee_details(
953			call: RuntimeCall,
954			len: u32,
955		) -> pallet_transaction_payment::FeeDetails<Balance> {
956			TransactionPayment::query_call_fee_details(call, len)
957		}
958		fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance {
959			TransactionPayment::weight_to_fee(weight)
960		}
961		fn query_length_to_fee(length: u32) -> Balance {
962			TransactionPayment::length_to_fee(length)
963		}
964	}
965
966	#[cfg(feature = "runtime-benchmarks")]
967	impl frame_benchmarking::Benchmark<Block> for Runtime {
968		fn benchmark_metadata(extra: bool) -> (
969			Vec<frame_benchmarking::BenchmarkList>,
970			Vec<frame_support::traits::StorageInfo>,
971		) {
972			use frame_benchmarking::{baseline, BenchmarkList};
973			use frame_support::traits::StorageInfoTrait;
974			use frame_system_benchmarking::Pallet as SystemBench;
975			use baseline::Pallet as BaselineBench;
976
977			let mut list = Vec::<BenchmarkList>::new();
978			list_benchmarks!(list, extra);
979
980			let storage_info = AllPalletsWithSystem::storage_info();
981
982			(list, storage_info)
983		}
984
985		fn dispatch_benchmark(
986			config: frame_benchmarking::BenchmarkConfig
987		) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
988			use frame_benchmarking::{baseline, BenchmarkBatch};
989			use sp_storage::TrackedStorageKey;
990			use frame_system_benchmarking::Pallet as SystemBench;
991			use baseline::Pallet as BaselineBench;
992			use frame_support::traits::WhitelistedStorageKeys;
993
994			#[allow(non_local_definitions)]
995			impl frame_system_benchmarking::Config for Runtime {}
996			#[allow(non_local_definitions)]
997			impl frame_benchmarking::baseline::Config for Runtime {}
998
999			let whitelist: Vec<TrackedStorageKey> = AllPalletsWithSystem::whitelisted_storage_keys();
1000
1001			let mut batches = Vec::<BenchmarkBatch>::new();
1002			let params = (&config, &whitelist);
1003			add_benchmarks!(params, batches);
1004
1005			Ok(batches)
1006		}
1007	}
1008
1009	#[cfg(feature = "try-runtime")]
1010	impl frame_try_runtime::TryRuntime<Block> for Runtime {
1011		fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
1012			// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
1013			// have a backtrace here. If any of the pre/post migration checks fail, we shall stop
1014			// right here and right now.
1015			let weight = Executive::try_runtime_upgrade(checks).unwrap();
1016			(weight, BlockWeights::get().max_block)
1017		}
1018
1019		fn execute_block(
1020			block: Block,
1021			state_root_check: bool,
1022			signature_check: bool,
1023			select: frame_try_runtime::TryStateSelect
1024		) -> Weight {
1025			// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
1026			// have a backtrace here.
1027			Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed")
1028		}
1029	}
1030
1031	impl sp_sidechain::GetGenesisUtxo<Block> for Runtime {
1032		fn genesis_utxo() -> UtxoId {
1033			Sidechain::genesis_utxo()
1034		}
1035	}
1036
1037	impl sp_sidechain::GetSidechainStatus<Block> for Runtime {
1038		fn get_sidechain_status() -> SidechainStatus {
1039			SidechainStatus {
1040				epoch: Sidechain::current_epoch_number(),
1041				slot: ScSlotNumber(*pallet_aura::CurrentSlot::<Runtime>::get()),
1042				slots_per_epoch: Sidechain::slots_per_epoch().0,
1043			}
1044		}
1045	}
1046
1047	impl sidechain_slots::SlotApi<Block> for Runtime {
1048		fn slot_config() -> sidechain_slots::ScSlotConfig {
1049			sidechain_slots::ScSlotConfig {
1050				slots_per_epoch: Sidechain::slots_per_epoch(),
1051				slot_duration: <Self as sp_consensus_aura::runtime_decl_for_aura_api::AuraApi<Block, AuraId>>::slot_duration()
1052			}
1053		}
1054	}
1055
1056	impl sp_block_producer_metadata::BlockProducerMetadataApi<Block, BlockProducerMetadataType> for Runtime
1057	{
1058		fn get_metadata_for(
1059			cross_chain_pub_key: &CrossChainPublicKey,
1060		) -> Option<BlockProducerMetadataType> {
1061			BlockProducerMetadata::get_metadata_for(&cross_chain_pub_key)
1062		}
1063	}
1064
1065	impl sp_block_producer_fees::BlockProducerFeesApi<Block, AccountId> for Runtime
1066	{
1067		fn get_all_fees() -> Vec<(AccountId, sp_block_producer_fees::PerTenThousands)> {
1068			BlockProducerFees::get_all_latest().map(|(account_id, (_slot, fee))| (account_id, fee)).collect()
1069		}
1070	}
1071
1072	#[api_version(2)]
1073	impl sp_session_validator_management::SessionValidatorManagementApi<
1074		Block,
1075		CommitteeMember<CrossChainPublic, SessionKeys>,
1076		AuthoritySelectionInputs,
1077		sidechain_domain::ScEpochNumber
1078	> for Runtime {
1079		fn get_current_committee() -> (ScEpochNumber, Vec<CommitteeMember<CrossChainPublic, SessionKeys>>) {
1080			SessionCommitteeManagement::current_committee_storage().as_pair()
1081		}
1082		fn get_next_committee() -> Option<(ScEpochNumber, Vec<CommitteeMember<CrossChainPublic, SessionKeys>>)> {
1083			Some(SessionCommitteeManagement::next_committee_storage()?.as_pair())
1084		}
1085		fn get_next_unset_epoch_number() -> sidechain_domain::ScEpochNumber {
1086			SessionCommitteeManagement::get_next_unset_epoch_number()
1087		}
1088		fn calculate_committee(authority_selection_inputs: AuthoritySelectionInputs, sidechain_epoch: ScEpochNumber) -> Option<Vec<CommitteeMember<CrossChainPublic, SessionKeys>>> {
1089			SessionCommitteeManagement::calculate_committee(authority_selection_inputs, sidechain_epoch)
1090		}
1091		fn get_main_chain_scripts() -> sp_session_validator_management::MainChainScripts {
1092			SessionCommitteeManagement::get_main_chain_scripts()
1093		}
1094	}
1095
1096	impl authority_selection_inherents::CandidateValidationApi<Block> for Runtime {
1097		fn validate_registered_candidate_data(stake_pool_public_key: &StakePoolPublicKey, registration_data: &RegistrationData) -> Option<RegistrationDataError> {
1098			authority_selection_inherents::validate_registration_data::<SessionKeys>(stake_pool_public_key, registration_data, Sidechain::genesis_utxo()).err()
1099		}
1100		fn validate_stake(stake: Option<StakeDelegation>) -> Option<StakeError> {
1101			authority_selection_inherents::validate_stake(stake).err()
1102		}
1103		fn validate_permissioned_candidate_data(candidate: PermissionedCandidateData) -> Option<PermissionedCandidateDataError> {
1104			validate_permissioned_candidate_data::<SessionKeys>(candidate).err()
1105		}
1106	}
1107
1108	impl sp_native_token_management::NativeTokenManagementApi<Block> for Runtime {
1109		fn get_main_chain_scripts() -> Option<sp_native_token_management::MainChainScripts> {
1110			NativeTokenManagement::get_main_chain_scripts()
1111		}
1112		fn initialized() -> bool {
1113			NativeTokenManagement::initialized()
1114		}
1115	}
1116
1117	impl sp_block_production_log::BlockProductionLogApi<Block, CommitteeMember<CrossChainPublic, SessionKeys>>  for Runtime {
1118		fn get_author(slot: Slot) -> Option<CommitteeMember<CrossChainPublic, SessionKeys>> {
1119			 SessionCommitteeManagement::get_current_authority_round_robin(*slot as usize)
1120		}
1121	}
1122
1123	impl sp_block_participation::BlockParticipationApi<Block, BlockAuthor> for Runtime {
1124		fn should_release_data(slot: Slot) -> Option<Slot> {
1125			BlockParticipation::should_release_data(slot)
1126		}
1127		fn blocks_produced_up_to_slot(slot: Slot) -> Vec<(Slot, BlockAuthor)> {
1128			<Runtime as pallet_block_participation::Config>::blocks_produced_up_to_slot(slot).collect()
1129		}
1130		fn target_inherent_id() -> InherentIdentifier {
1131			<Runtime as pallet_block_participation::Config>::TARGET_INHERENT_ID
1132		}
1133	}
1134
1135	impl sp_governed_map::GovernedMapIDPApi<Block> for Runtime {
1136		fn is_initialized() -> bool {
1137			GovernedMap::is_initialized()
1138		}
1139		fn get_current_state() -> BTreeMap<String, ByteString> {
1140			GovernedMap::get_all_key_value_pairs_unbounded().collect()
1141		}
1142		fn get_main_chain_scripts() -> Option<MainChainScriptsV1> {
1143			GovernedMap::get_main_chain_scripts()
1144		}
1145		fn get_pallet_version() -> u32 {
1146			GovernedMap::get_version()
1147		}
1148	}
1149
1150	impl sp_partner_chains_bridge::TokenBridgeIDPRuntimeApi<Block> for Runtime {
1151		fn get_pallet_version() -> u32 {
1152			Bridge::get_pallet_version()
1153		}
1154		fn get_main_chain_scripts() -> Option<BridgeMainChainScripts> {
1155			Bridge::get_main_chain_scripts()
1156		}
1157		fn get_max_transfers_per_block() -> u32 {
1158			Bridge::get_max_transfers_per_block()
1159		}
1160		fn get_last_data_checkpoint() -> Option<BridgeDataCheckpoint> {
1161			Bridge::get_data_checkpoint()
1162		}
1163	}
1164}
1165
1166#[cfg(test)]
1167mod tests {
1168	use crate::mock::*;
1169	use frame_support::{
1170		dispatch::PostDispatchInfo,
1171		inherent::ProvideInherent,
1172		traits::{UnfilteredDispatchable, WhitelistedStorageKeys},
1173	};
1174	use sp_core::{Pair, hexdisplay::HexDisplay};
1175	use sp_inherents::InherentData;
1176	use std::collections::HashSet;
1177
1178	#[test]
1179	fn check_whitelist() {
1180		let whitelist: HashSet<String> = super::AllPalletsWithSystem::whitelisted_storage_keys()
1181			.iter()
1182			.map(|e| HexDisplay::from(&e.key).to_string())
1183			.collect();
1184
1185		// Block Number
1186		assert!(
1187			whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")
1188		);
1189		// Total Issuance
1190		assert!(
1191			whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")
1192		);
1193		// Execution Phase
1194		assert!(
1195			whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")
1196		);
1197		// Event Count
1198		assert!(
1199			whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")
1200		);
1201		// System Events
1202		assert!(
1203			whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")
1204		);
1205	}
1206
1207	// The set committee takes effect next session. Committee can be set for 1 session in advance.
1208	#[test]
1209	fn check_grandpa_authorities_rotation() {
1210		new_test_ext().execute_with(|| {
1211			// Needs to be run to initialize first slot and epoch numbers;
1212			advance_block();
1213			set_committee_through_inherent_data(&[alice()]);
1214			until_epoch_after_finalizing(1, &|| {
1215				assert_current_epoch!(0);
1216				assert_grandpa_weights();
1217				assert_grandpa_authorities!([alice(), bob()]);
1218			});
1219
1220			set_committee_through_inherent_data(&[bob()]);
1221			for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH, &|| {
1222				assert_current_epoch!(1);
1223				assert_grandpa_weights();
1224				assert_grandpa_authorities!([alice()]);
1225			});
1226
1227			for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH, &|| {
1228				assert_current_epoch!(2);
1229				assert_grandpa_weights();
1230				assert_grandpa_authorities!([bob()]);
1231			});
1232
1233			// Authorities can be set as late as in the first block of new epoch, but it makes session last 1 block longer
1234			set_committee_through_inherent_data(&[alice()]);
1235			advance_block();
1236			assert_current_epoch!(3);
1237			assert_grandpa_authorities!([bob()]);
1238			set_committee_through_inherent_data(&[alice(), bob()]);
1239			for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH - 1, &|| {
1240				assert_current_epoch!(3);
1241				assert_grandpa_weights();
1242				assert_grandpa_authorities!([alice()]);
1243			});
1244
1245			for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH * 3, &|| {
1246				assert_grandpa_weights();
1247				assert_grandpa_authorities!([alice(), bob()]);
1248			});
1249		});
1250
1251		fn assert_grandpa_weights() {
1252			Grandpa::grandpa_authorities()
1253				.into_iter()
1254				.for_each(|(_, weight)| assert_eq!(weight, 1))
1255		}
1256	}
1257
1258	// The set committee takes effect next session. Committee can be set for 1 session in advance.
1259	#[test]
1260	fn check_aura_authorities_rotation() {
1261		new_test_ext().execute_with(|| {
1262			advance_block();
1263			set_committee_through_inherent_data(&[alice()]);
1264			until_epoch(1, &|| {
1265				assert_current_epoch!(0);
1266				assert_aura_authorities!([alice(), bob()]);
1267			});
1268
1269			for_next_n_blocks(SLOTS_PER_EPOCH, &|| {
1270				assert_current_epoch!(1);
1271				assert_aura_authorities!([alice()]);
1272			});
1273
1274			// Authorities can be set as late as in the first block of new epoch, but it makes session last 1 block longer
1275			set_committee_through_inherent_data(&[bob()]);
1276			assert_current_epoch!(2);
1277			assert_aura_authorities!([alice()]);
1278			advance_block();
1279			set_committee_through_inherent_data(&[alice(), bob()]);
1280			for_next_n_blocks(SLOTS_PER_EPOCH - 1, &|| {
1281				assert_current_epoch!(2);
1282				assert_aura_authorities!([bob()]);
1283			});
1284
1285			set_committee_through_inherent_data(&[alice(), bob()]);
1286			for_next_n_blocks(SLOTS_PER_EPOCH * 3, &|| {
1287				assert_aura_authorities!([alice(), bob()]);
1288			});
1289		});
1290	}
1291
1292	// The set committee takes effect at next session. Committee can be set for 1 session in advance.
1293	#[test]
1294	fn check_cross_chain_committee_rotation() {
1295		new_test_ext().execute_with(|| {
1296			advance_block();
1297			set_committee_through_inherent_data(&[alice()]);
1298			until_epoch(1, &|| {
1299				assert_current_epoch!(0);
1300				assert_next_committee!([alice()]);
1301			});
1302
1303			set_committee_through_inherent_data(&[bob()]);
1304			for_next_n_blocks(SLOTS_PER_EPOCH, &|| {
1305				assert_current_epoch!(1);
1306				assert_next_committee!([bob()]);
1307			});
1308
1309			set_committee_through_inherent_data(&[]);
1310			for_next_n_blocks(SLOTS_PER_EPOCH, &|| {
1311				assert_current_epoch!(2);
1312				assert_next_committee!([bob()]);
1313			});
1314		});
1315	}
1316
1317	pub fn set_committee_through_inherent_data(
1318		expected_authorities: &[TestKeys],
1319	) -> PostDispatchInfo {
1320		let epoch = Sidechain::current_epoch_number();
1321		let slot = *pallet_aura::CurrentSlot::<Test>::get();
1322		println!(
1323			"(slot {slot}, epoch {epoch}) Setting {} authorities for next epoch",
1324			expected_authorities.len()
1325		);
1326		let inherent_data_struct = create_inherent_data_struct(expected_authorities);
1327		let mut inherent_data = InherentData::new();
1328		inherent_data
1329			.put_data(
1330				SessionCommitteeManagement::INHERENT_IDENTIFIER,
1331				&inherent_data_struct.data.unwrap(),
1332			)
1333			.expect("Setting inherent data should not fail");
1334		let call = <SessionCommitteeManagement as ProvideInherent>::create_inherent(&inherent_data)
1335			.expect("Creating test inherent should not fail");
1336		println!("    inherent: {:?}", call);
1337		call.dispatch_bypass_filter(RuntimeOrigin::none())
1338			.expect("dispatching test call should work")
1339	}
1340}