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