partner_chains_demo_runtime/
lib.rs

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