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