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