1#![cfg_attr(not(feature = "std"), no_std)]
2#![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::CommitteeMember;
15use authority_selection_inherents::authority_selection_inputs::AuthoritySelectionInputs;
16use authority_selection_inherents::filter_invalid_candidates::{
17 PermissionedCandidateDataError, RegistrationDataError, StakeError,
18 validate_permissioned_candidate_data,
19};
20use authority_selection_inherents::select_authorities::select_authorities;
21use frame_support::genesis_builder_helper::{build_state, get_preset};
22use frame_support::inherent::ProvideInherent;
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::session_manager::ValidatorManagementSessionManager;
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_runtime::{
53 ApplyExtrinsicResult, MultiSignature, Perbill, generic, impl_opaque_keys,
54 traits::{
55 AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, OpaqueKeys,
56 Verify,
57 },
58 transaction_validity::{TransactionSource, TransactionValidity},
59};
60use sp_sidechain::SidechainStatus;
61use sp_std::prelude::*;
62use sp_version::RuntimeVersion;
63use sp_weights::Weight;
64
65#[cfg(feature = "std")]
67include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
68
69pub mod genesis_config_presets;
70
71#[cfg(test)]
72mod mock;
73
74#[cfg(test)]
75mod header_tests;
76
77mod test_helper_pallet;
78
79pub type BlockNumber = u32;
81
82pub type Signature = MultiSignature;
84
85pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
88
89pub type Balance = u128;
91
92pub type Nonce = u32;
94
95pub type Hash = sp_core::H256;
97
98pub mod opaque {
103 use super::*;
104 use parity_scale_codec::MaxEncodedLen;
105 use sp_core::{ed25519, sr25519};
106 pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
107
108 pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
110 pub type Block = generic::Block<Header, UncheckedExtrinsic>;
112 pub type BlockId = generic::BlockId<Block>;
114
115 pub const CROSS_CHAIN: KeyTypeId = KeyTypeId(*b"crch");
116 pub struct CrossChainRuntimeAppPublic;
117
118 pub mod cross_chain_app {
119 use super::CROSS_CHAIN;
120 use parity_scale_codec::MaxEncodedLen;
121 use sidechain_domain::SidechainPublicKey;
122 use sp_core::crypto::AccountId32;
123 use sp_runtime::MultiSigner;
124 use sp_runtime::app_crypto::{app_crypto, ecdsa};
125 use sp_runtime::traits::IdentifyAccount;
126 use sp_std::vec::Vec;
127
128 app_crypto!(ecdsa, CROSS_CHAIN);
129 impl MaxEncodedLen for Signature {
130 fn max_encoded_len() -> usize {
131 ecdsa::Signature::max_encoded_len()
132 }
133 }
134
135 impl From<Signature> for Vec<u8> {
136 fn from(value: Signature) -> Self {
137 value.into_inner().0.to_vec()
138 }
139 }
140
141 impl From<Public> for AccountId32 {
142 fn from(value: Public) -> Self {
143 MultiSigner::from(ecdsa::Public::from(value)).into_account()
144 }
145 }
146
147 impl From<Public> for Vec<u8> {
148 fn from(value: Public) -> Self {
149 value.into_inner().0.to_vec()
150 }
151 }
152
153 impl TryFrom<SidechainPublicKey> for Public {
154 type Error = SidechainPublicKey;
155 fn try_from(pubkey: SidechainPublicKey) -> Result<Self, Self::Error> {
156 let cross_chain_public_key =
157 Public::try_from(pubkey.0.as_slice()).map_err(|_| pubkey)?;
158 Ok(cross_chain_public_key)
159 }
160 }
161 }
162
163 impl_opaque_keys! {
164 #[derive(MaxEncodedLen, PartialOrd, Ord)]
165 pub struct SessionKeys {
166 pub aura: Aura,
167 pub grandpa: Grandpa,
168 }
169 }
170 impl From<(sr25519::Public, ed25519::Public)> for SessionKeys {
171 fn from((aura, grandpa): (sr25519::Public, ed25519::Public)) -> Self {
172 Self { aura: aura.into(), grandpa: grandpa.into() }
173 }
174 }
175
176 impl_opaque_keys! {
177 pub struct CrossChainKey {
178 pub account: CrossChainPublic,
179 }
180 }
181}
182
183pub type CrossChainPublic = opaque::cross_chain_app::Public;
184
185#[sp_version::runtime_version]
188pub const VERSION: RuntimeVersion = RuntimeVersion {
189 spec_name: alloc::borrow::Cow::Borrowed("cardano-sidechain"),
190 impl_name: alloc::borrow::Cow::Borrowed("cardano-sidechain"),
191 authoring_version: 1,
192 spec_version: 170,
198 impl_version: 1,
199 apis: RUNTIME_API_VERSIONS,
200 transaction_version: 1,
201 system_version: 1,
202};
203
204pub const MILLISECS_PER_BLOCK: u64 = 6000;
211
212pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
215
216pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
218pub const HOURS: BlockNumber = MINUTES * 60;
219pub const DAYS: BlockNumber = HOURS * 24;
220
221const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
222
223pub const MAXIMUM_BLOCK_WEIGHT: Weight =
225 Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
226pub const MAXIMUM_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;
227
228parameter_types! {
229 pub const BlockHashCount: BlockNumber = 2400;
230 pub const Version: RuntimeVersion = VERSION;
231 pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights
232 ::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO);
233 pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength
234 ::max_with_normal_ratio(MAXIMUM_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO);
235 pub const SS58Prefix: u8 = 42;
236}
237
238impl frame_system::Config for Runtime {
241 type BaseCallFilter = frame_support::traits::Everything;
243 type Block = Block;
245 type Nonce = Nonce;
247 type BlockWeights = BlockWeights;
249 type BlockLength = BlockLength;
251 type AccountId = AccountId;
253 type RuntimeCall = RuntimeCall;
255 type Lookup = AccountIdLookup<AccountId, ()>;
257 type Hash = Hash;
259 type Hashing = BlakeTwo256;
261 type RuntimeEvent = RuntimeEvent;
263 type RuntimeOrigin = RuntimeOrigin;
265 type BlockHashCount = BlockHashCount;
267 type DbWeight = RuntimeDbWeight;
269 type Version = Version;
271 type PalletInfo = PalletInfo;
275 type OnNewAccount = ();
277 type OnKilledAccount = ();
279 type AccountData = pallet_balances::AccountData<Balance>;
281 type SystemWeightInfo = frame_system::weights::SubstrateWeight<Runtime>;
283 type ExtensionsWeightInfo = ();
285 type SS58Prefix = SS58Prefix;
287 type OnSetCode = ();
289 type MaxConsumers = frame_support::traits::ConstU32<16>;
290 type RuntimeTask = RuntimeTask;
291 type SingleBlockMigrations = ();
292 type MultiBlockMigrator = ();
293 type PreInherents = ();
294 type PostInherents = ();
295 type PostTransactions = ();
296}
297
298impl pallet_native_token_management::Config for Runtime {
299 type RuntimeEvent = RuntimeEvent;
300 type TokenTransferHandler = TestHelperPallet;
301 type MainChainScriptsOrigin = EnsureRoot<Self::AccountId>;
302 type WeightInfo = pallet_native_token_management::weights::SubstrateWeight<Runtime>;
303}
304
305impl pallet_aura::Config for Runtime {
306 type AuthorityId = AuraId;
307 type DisabledValidators = ();
308 type MaxAuthorities = MaxValidators;
309 type AllowMultipleBlocksPerSlot = ConstBool<false>;
310 type SlotDuration = ConstU64<SLOT_DURATION>;
311}
312
313pallet_partner_chains_session::impl_pallet_session_config!(Runtime);
314
315impl pallet_grandpa::Config for Runtime {
316 type RuntimeEvent = RuntimeEvent;
317
318 type WeightInfo = ();
319 type MaxAuthorities = MaxValidators;
320 type MaxNominators = ConstU32<0>;
321 type MaxSetIdSessionEntries = ConstU64<0>;
322
323 type KeyOwnerProof = sp_core::Void;
324 type EquivocationReportSystem = ();
325}
326
327impl pallet_timestamp::Config for Runtime {
328 type Moment = u64;
330 type OnTimestampSet = Aura;
331 type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
332 type WeightInfo = pallet_timestamp::weights::SubstrateWeight<Runtime>;
333}
334
335pub const EXISTENTIAL_DEPOSIT: u128 = 500;
337
338impl pallet_balances::Config for Runtime {
339 type MaxLocks = ConstU32<50>;
340 type MaxReserves = ();
341 type ReserveIdentifier = [u8; 8];
342 type Balance = Balance;
344 type RuntimeEvent = RuntimeEvent;
346 type DustRemoval = ();
347 type ExistentialDeposit = ConstU128<EXISTENTIAL_DEPOSIT>;
348 type AccountStore = System;
349 type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
350 type FreezeIdentifier = ();
351 type MaxFreezes = ();
352 type RuntimeHoldReason = ();
353 type RuntimeFreezeReason = RuntimeFreezeReason;
354 type DoneSlashHandler = ();
355}
356
357parameter_types! {
358 pub FeeMultiplier: Multiplier = Multiplier::one();
359}
360
361impl pallet_transaction_payment::Config for Runtime {
362 type RuntimeEvent = RuntimeEvent;
363 type OnChargeTransaction = FungibleAdapter<Balances, ()>;
364 type OperationalFeeMultiplier = ConstU8<5>;
365 type WeightToFee = IdentityFee<Balance>;
366 type LengthToFee = IdentityFee<Balance>;
367 type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
368 type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
369}
370
371impl pallet_sudo::Config for Runtime {
372 type RuntimeEvent = RuntimeEvent;
373 type RuntimeCall = RuntimeCall;
374 type WeightInfo = pallet_sudo::weights::SubstrateWeight<Runtime>;
375}
376
377impl pallet_partner_chains_session::Config for Runtime {
378 type RuntimeEvent = RuntimeEvent;
379 type ValidatorId = <Self as frame_system::Config>::AccountId;
380 type ShouldEndSession = ValidatorManagementSessionManager<Runtime>;
381 type NextSessionRotation = ();
382 type SessionManager = ValidatorManagementSessionManager<Runtime>;
383 type SessionHandler = <opaque::SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
384 type Keys = opaque::SessionKeys;
385}
386
387parameter_types! {
388 pub const MaxValidators: u32 = 32;
389}
390
391impl pallet_session_validator_management::Config for Runtime {
392 type RuntimeEvent = RuntimeEvent;
393 type MaxValidators = MaxValidators;
394 type AuthorityId = CrossChainPublic;
395 type AuthorityKeys = SessionKeys;
396 type AuthoritySelectionInputs = AuthoritySelectionInputs;
397 type ScEpochNumber = ScEpochNumber;
398 type WeightInfo = pallet_session_validator_management::weights::SubstrateWeight<Runtime>;
399 type CommitteeMember = CommitteeMember<CrossChainPublic, SessionKeys>;
400 type MainChainScriptsOrigin = EnsureRoot<Self::AccountId>;
401
402 fn select_authorities(
403 input: AuthoritySelectionInputs,
404 sidechain_epoch: ScEpochNumber,
405 ) -> Option<BoundedVec<Self::CommitteeMember, Self::MaxValidators>> {
406 Some(BoundedVec::truncate_from(
407 select_authorities(Sidechain::genesis_utxo(), input, sidechain_epoch)?
408 .into_iter()
409 .map(|member| member.into())
410 .collect(),
411 ))
412 }
413
414 fn current_epoch_number() -> ScEpochNumber {
415 Sidechain::current_epoch_number()
416 }
417}
418
419parameter_types! {
420 pub const TokenConversionRate: u128 = 1_000_000_000u128;
421 pub const MaxTransactions: u32 = 256u32;
422}
423
424impl pallet_sidechain::Config for Runtime {
425 fn current_slot_number() -> ScSlotNumber {
426 ScSlotNumber(*pallet_aura::CurrentSlot::<Self>::get())
427 }
428 type OnNewEpoch = TestHelperPallet;
429}
430
431pub type BeneficiaryId = sidechain_domain::byte_string::SizedByteString<32>;
432
433#[derive(
434 MaxEncodedLen,
435 Encode,
436 Decode,
437 DecodeWithMemTracking,
438 Clone,
439 TypeInfo,
440 PartialEq,
441 Eq,
442 Debug,
443 Hash,
444 PartialOrd,
445 Ord,
446)]
447pub enum BlockAuthor {
448 Incentivized(CrossChainPublic, StakePoolPublicKey),
449 ProBono(CrossChainPublic),
450}
451impl BlockAuthor {
452 pub fn id(&self) -> &CrossChainPublic {
453 match self {
454 Self::Incentivized(id, _) => id,
455 Self::ProBono(id) => id,
456 }
457 }
458}
459impl From<CommitteeMember<CrossChainPublic, SessionKeys>> for BlockAuthor {
460 fn from(value: CommitteeMember<CrossChainPublic, SessionKeys>) -> Self {
461 match value {
462 CommitteeMember::Permissioned { id, .. } => BlockAuthor::ProBono(id),
463 CommitteeMember::Registered { id, stake_pool_pub_key, .. } => {
464 BlockAuthor::Incentivized(id, stake_pool_pub_key)
465 },
466 }
467 }
468}
469
470impl AsCardanoSPO for BlockAuthor {
471 fn as_cardano_spo(&self) -> Option<MainchainKeyHash> {
472 match self {
473 BlockAuthor::Incentivized(_, key) => Some(key.hash()),
474 BlockAuthor::ProBono(_) => None,
475 }
476 }
477}
478
479pub const MAX_METADATA_URL_LENGTH: u32 = 512;
480
481#[derive(
482 Clone,
483 Debug,
484 MaxEncodedLen,
485 Encode,
486 Decode,
487 DecodeWithMemTracking,
488 Serialize,
489 Deserialize,
490 PartialEq,
491 Eq,
492 TypeInfo,
493)]
494pub struct BlockProducerMetadataType {
495 pub url: BoundedString<ConstU32<MAX_METADATA_URL_LENGTH>>,
496 pub hash: SizedByteString<32>,
497}
498
499#[cfg(feature = "runtime-benchmarks")]
500pub struct PalletBlockProductionLogBenchmarkHelper;
501
502#[cfg(feature = "runtime-benchmarks")]
503impl pallet_block_production_log::benchmarking::BenchmarkHelper<BlockAuthor>
504 for PalletBlockProductionLogBenchmarkHelper
505{
506 fn producer_id() -> BlockAuthor {
507 let id = sp_core::ecdsa::Public::from_slice(&[0u8; 33]).unwrap().into();
508 BlockAuthor::ProBono(id)
509 }
510}
511
512#[cfg(feature = "runtime-benchmarks")]
513pub struct PalletBlockProducerMetadataBenchmarkHelper;
514
515#[cfg(feature = "runtime-benchmarks")]
516impl pallet_block_producer_metadata::benchmarking::BenchmarkHelper<BlockProducerMetadataType>
517 for PalletBlockProducerMetadataBenchmarkHelper
518{
519 fn metadata() -> BlockProducerMetadataType {
520 BlockProducerMetadataType {
521 url: "https://cool.stuff/spo.json".try_into().unwrap(),
522 hash: SizedByteString::from([0; 32]),
523 }
524 }
525 fn cross_chain_pub_key() -> sidechain_domain::CrossChainPublicKey {
526 sidechain_domain::CrossChainPublicKey(
527 hex_literal::hex!("020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a1")
528 .to_vec(),
529 )
530 }
531 fn cross_chain_signature() -> sidechain_domain::CrossChainSignature {
532 sidechain_domain::CrossChainSignature(hex_literal::hex!("d1e02e4a5484c3b7202ce6b844577048e7578dc62901cf8f51e6d74bbd3adb091688feacedd8343d0b04a0f5862b2e06148934a75e678e42051fde5431eca33d").to_vec())
533 }
534}
535
536impl pallet_block_production_log::Config for Runtime {
537 type BlockProducerId = BlockAuthor;
538 type WeightInfo = pallet_block_production_log::weights::SubstrateWeight<Runtime>;
539
540 fn current_slot() -> sp_consensus_slots::Slot {
541 let slot: u64 = pallet_aura::CurrentSlot::<Runtime>::get().into();
542 sp_consensus_slots::Slot::from(slot)
543 }
544
545 #[cfg(feature = "runtime-benchmarks")]
546 type BenchmarkHelper = PalletBlockProductionLogBenchmarkHelper;
547}
548
549impl pallet_address_associations::Config for Runtime {
550 type WeightInfo = pallet_address_associations::weights::SubstrateWeight<Runtime>;
551
552 type PartnerChainAddress = AccountId;
553
554 fn genesis_utxo() -> UtxoId {
555 Sidechain::genesis_utxo()
556 }
557
558 type OnNewAssociation = TestHelperPallet;
559}
560
561#[cfg(feature = "runtime-benchmarks")]
562pub struct PalletBlockProducerFeesBenchmarkHelper;
563
564#[cfg(feature = "runtime-benchmarks")]
565impl pallet_block_producer_fees::benchmarking::BenchmarkHelper<AccountId>
566 for PalletBlockProducerFeesBenchmarkHelper
567{
568 fn account_id(i: u8) -> AccountId {
569 sp_core::sr25519::Public::from_raw([i; 32]).into()
570 }
571}
572
573impl pallet_block_producer_fees::Config for Runtime {
574 type WeightInfo = ();
575
576 type HistoricalChangesPerProducer = ConstU16<5>;
577
578 fn current_slot() -> sp_consensus_slots::Slot {
579 let slot: u64 = pallet_aura::CurrentSlot::<Runtime>::get().into();
580 sp_consensus_slots::Slot::from(slot)
581 }
582
583 #[cfg(feature = "runtime-benchmarks")]
584 type BenchmarkHelper = PalletBlockProducerFeesBenchmarkHelper;
585}
586
587impl pallet_block_producer_metadata::Config for Runtime {
588 type WeightInfo = pallet_block_producer_metadata::weights::SubstrateWeight<Runtime>;
589
590 type BlockProducerMetadata = BlockProducerMetadataType;
591
592 fn genesis_utxo() -> UtxoId {
593 Sidechain::genesis_utxo()
594 }
595
596 #[cfg(feature = "runtime-benchmarks")]
597 type BenchmarkHelper = PalletBlockProducerMetadataBenchmarkHelper;
598}
599
600impl pallet_block_participation::Config for Runtime {
601 type WeightInfo = pallet_block_participation::weights::SubstrateWeight<Runtime>;
602 type BlockAuthor = BlockAuthor;
603 type DelegatorId = DelegatorKey;
604
605 fn should_release_data(slot: sidechain_slots::Slot) -> Option<sidechain_slots::Slot> {
606 TestHelperPallet::should_release_participation_data(slot)
607 }
608
609 fn blocks_produced_up_to_slot(slot: Slot) -> impl Iterator<Item = (Slot, BlockAuthor)> {
610 BlockProductionLog::peek_prefix(slot)
611 }
612
613 fn discard_blocks_produced_up_to_slot(slot: Slot) {
614 BlockProductionLog::drop_prefix(&slot)
615 }
616
617 const TARGET_INHERENT_ID: InherentIdentifier = TestHelperPallet::INHERENT_IDENTIFIER;
618}
619
620parameter_types! {
621 pub const MaxChanges: u32 = 16;
622 pub const MaxKeyLength: u32 = 64;
623 pub const MaxValueLength: u32 = 512;
624}
625
626impl pallet_governed_map::Config for Runtime {
627 type MaxChanges = MaxChanges;
628 type MaxKeyLength = MaxKeyLength;
629 type MaxValueLength = MaxValueLength;
630 type WeightInfo = pallet_governed_map::weights::SubstrateWeight<Runtime>;
631
632 type OnGovernedMappingChange = TestHelperPallet;
633 type MainChainScriptsOrigin = EnsureRoot<Self::AccountId>;
634
635 #[cfg(feature = "runtime-benchmarks")]
636 type BenchmarkHelper = ();
637}
638
639impl crate::test_helper_pallet::Config for Runtime {}
640
641construct_runtime!(
643 pub struct Runtime {
644 System: frame_system,
645 Timestamp: pallet_timestamp,
646 Aura: pallet_aura,
647 Grandpa: pallet_grandpa,
648 Balances: pallet_balances,
649 TransactionPayment: pallet_transaction_payment,
650 Sudo: pallet_sudo,
651 Sidechain: pallet_sidechain,
654 SessionCommitteeManagement: pallet_session_validator_management,
655 AddressAssociations: pallet_address_associations,
656 BlockProducerFees: pallet_block_producer_fees,
657 BlockProducerMetadata: pallet_block_producer_metadata,
658 BlockProductionLog: pallet_block_production_log,
659 BlockParticipation: pallet_block_participation,
660 PalletSession: pallet_session,
665 Session: pallet_partner_chains_session,
667 NativeTokenManagement: pallet_native_token_management,
668 GovernedMap: pallet_governed_map,
669 TestHelperPallet: crate::test_helper_pallet,
670 }
671);
672
673pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
675pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
677pub type Block = generic::Block<Header, UncheckedExtrinsic>;
679pub type SignedExtra = (
681 frame_system::CheckNonZeroSender<Runtime>,
682 frame_system::CheckSpecVersion<Runtime>,
683 frame_system::CheckTxVersion<Runtime>,
684 frame_system::CheckGenesis<Runtime>,
685 frame_system::CheckEra<Runtime>,
686 frame_system::CheckNonce<Runtime>,
687 frame_system::CheckWeight<Runtime>,
688 pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
689);
690
691pub type UncheckedExtrinsic =
693 generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
694pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
696pub type Migrations = (
697 pallet_session_validator_management::migrations::v1::LegacyToV1Migration<Runtime>,
698 );
700pub type Executive = frame_executive::Executive<
702 Runtime,
703 Block,
704 frame_system::ChainContext<Runtime>,
705 Runtime,
706 AllPalletsWithSystem,
707 Migrations,
708>;
709
710#[cfg(feature = "runtime-benchmarks")]
711mod benches {
712 define_benchmarks!(
713 [frame_benchmarking, BaselineBench::<Runtime>]
714 [frame_system, SystemBench::<Runtime>]
715 [pallet_balances, Balances]
716 [pallet_timestamp, Timestamp]
717 [pallet_sudo, Sudo]
718 [pallet_native_token_management, NativeTokenManagement]
719 [pallet_block_production_log, BlockProductionLog]
720 [pallet_address_associations, AddressAssociations]
721 [pallet_block_producer_fees, BlockProducerFees]
722 [pallet_block_producer_metadata, BlockProducerMetadata]
723 [pallet_block_participation, BlockParticipation]
724 [pallet_governed_map, GovernedMap]
725 );
726}
727
728impl_runtime_apis! {
729 impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
730 fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
731 build_state::<RuntimeGenesisConfig>(config)
732 }
733
734 fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
735 get_preset::<RuntimeGenesisConfig>(id, crate::genesis_config_presets::get_preset)
736 }
737
738 fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
739 crate::genesis_config_presets::preset_names()
740 }
741 }
742
743 impl sp_api::Core<Block> for Runtime {
744 fn version() -> RuntimeVersion {
745 VERSION
746 }
747
748 fn execute_block(block: Block) {
749 Executive::execute_block(block);
750 }
751
752 fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
753 Executive::initialize_block(header)
754 }
755 }
756
757 impl sp_api::Metadata<Block> for Runtime {
758 fn metadata() -> OpaqueMetadata {
759 OpaqueMetadata::new(Runtime::metadata().into())
760 }
761
762 fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
763 Runtime::metadata_at_version(version)
764 }
765
766 fn metadata_versions() -> sp_std::vec::Vec<u32> {
767 Runtime::metadata_versions()
768 }
769 }
770
771 impl sp_block_builder::BlockBuilder<Block> for Runtime {
772 fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
773 Executive::apply_extrinsic(extrinsic)
774 }
775
776 fn finalize_block() -> <Block as BlockT>::Header {
777 Executive::finalize_block()
778 }
779
780 fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
781 data.create_extrinsics()
782 }
783
784 fn check_inherents(
785 block: Block,
786 data: sp_inherents::InherentData,
787 ) -> sp_inherents::CheckInherentsResult {
788 data.check_extrinsics(&block)
789 }
790 }
791
792 impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
793 fn validate_transaction(
794 source: TransactionSource,
795 tx: <Block as BlockT>::Extrinsic,
796 block_hash: <Block as BlockT>::Hash,
797 ) -> TransactionValidity {
798 Executive::validate_transaction(source, tx, block_hash)
799 }
800 }
801
802 impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
803 fn offchain_worker(header: &<Block as BlockT>::Header) {
804 Executive::offchain_worker(header)
805 }
806 }
807
808 impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
809 fn slot_duration() -> sp_consensus_aura::SlotDuration {
810 sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
811 }
812
813 fn authorities() -> Vec<AuraId> {
814 pallet_aura::Authorities::<Runtime>::get().into_inner()
815 }
816 }
817
818 impl sp_session::SessionKeys<Block> for Runtime {
819 fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
820 opaque::CrossChainKey::generate(seed.clone());
822 opaque::SessionKeys::generate(seed)
823 }
824
825 fn decode_session_keys(
826 encoded: Vec<u8>,
827 ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
828 opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
829 }
830 }
831
832 impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
833 fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList {
834 Grandpa::grandpa_authorities()
835 }
836
837 fn current_set_id() -> sp_consensus_grandpa::SetId {
838 Grandpa::current_set_id()
839 }
840
841 fn submit_report_equivocation_unsigned_extrinsic(
842 _equivocation_proof: sp_consensus_grandpa::EquivocationProof<
843 <Block as BlockT>::Hash,
844 NumberFor<Block>,
845 >,
846 _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
847 ) -> Option<()> {
848 None
849 }
850
851 fn generate_key_ownership_proof(
852 _set_id: sp_consensus_grandpa::SetId,
853 _authority_id: GrandpaId,
854 ) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
855 None
859 }
860 }
861
862
863 impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
864 fn account_nonce(account: AccountId) -> Nonce {
865 System::account_nonce(account)
866 }
867 }
868
869 impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
870 fn query_info(
871 uxt: <Block as BlockT>::Extrinsic,
872 len: u32,
873 ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
874 TransactionPayment::query_info(uxt, len)
875 }
876 fn query_fee_details(
877 uxt: <Block as BlockT>::Extrinsic,
878 len: u32,
879 ) -> pallet_transaction_payment::FeeDetails<Balance> {
880 TransactionPayment::query_fee_details(uxt, len)
881 }
882 fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance {
883 TransactionPayment::weight_to_fee(weight)
884 }
885 fn query_length_to_fee(length: u32) -> Balance {
886 TransactionPayment::length_to_fee(length)
887 }
888 }
889
890 impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
891 for Runtime
892 {
893 fn query_call_info(
894 call: RuntimeCall,
895 len: u32,
896 ) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
897 TransactionPayment::query_call_info(call, len)
898 }
899 fn query_call_fee_details(
900 call: RuntimeCall,
901 len: u32,
902 ) -> pallet_transaction_payment::FeeDetails<Balance> {
903 TransactionPayment::query_call_fee_details(call, len)
904 }
905 fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance {
906 TransactionPayment::weight_to_fee(weight)
907 }
908 fn query_length_to_fee(length: u32) -> Balance {
909 TransactionPayment::length_to_fee(length)
910 }
911 }
912
913 #[cfg(feature = "runtime-benchmarks")]
914 impl frame_benchmarking::Benchmark<Block> for Runtime {
915 fn benchmark_metadata(extra: bool) -> (
916 Vec<frame_benchmarking::BenchmarkList>,
917 Vec<frame_support::traits::StorageInfo>,
918 ) {
919 use frame_benchmarking::{baseline, BenchmarkList};
920 use frame_support::traits::StorageInfoTrait;
921 use frame_system_benchmarking::Pallet as SystemBench;
922 use baseline::Pallet as BaselineBench;
923
924 let mut list = Vec::<BenchmarkList>::new();
925 list_benchmarks!(list, extra);
926
927 let storage_info = AllPalletsWithSystem::storage_info();
928
929 (list, storage_info)
930 }
931
932 fn dispatch_benchmark(
933 config: frame_benchmarking::BenchmarkConfig
934 ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
935 use frame_benchmarking::{baseline, BenchmarkBatch};
936 use sp_storage::TrackedStorageKey;
937 use frame_system_benchmarking::Pallet as SystemBench;
938 use baseline::Pallet as BaselineBench;
939 use frame_support::traits::WhitelistedStorageKeys;
940
941 #[allow(non_local_definitions)]
942 impl frame_system_benchmarking::Config for Runtime {}
943 #[allow(non_local_definitions)]
944 impl frame_benchmarking::baseline::Config for Runtime {}
945
946 let whitelist: Vec<TrackedStorageKey> = AllPalletsWithSystem::whitelisted_storage_keys();
947
948 let mut batches = Vec::<BenchmarkBatch>::new();
949 let params = (&config, &whitelist);
950 add_benchmarks!(params, batches);
951
952 Ok(batches)
953 }
954 }
955
956 #[cfg(feature = "try-runtime")]
957 impl frame_try_runtime::TryRuntime<Block> for Runtime {
958 fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
959 let weight = Executive::try_runtime_upgrade(checks).unwrap();
963 (weight, BlockWeights::get().max_block)
964 }
965
966 fn execute_block(
967 block: Block,
968 state_root_check: bool,
969 signature_check: bool,
970 select: frame_try_runtime::TryStateSelect
971 ) -> Weight {
972 Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed")
975 }
976 }
977
978 impl sp_sidechain::GetGenesisUtxo<Block> for Runtime {
979 fn genesis_utxo() -> UtxoId {
980 Sidechain::genesis_utxo()
981 }
982 }
983
984 impl sp_sidechain::GetSidechainStatus<Block> for Runtime {
985 fn get_sidechain_status() -> SidechainStatus {
986 SidechainStatus {
987 epoch: Sidechain::current_epoch_number(),
988 slot: ScSlotNumber(*pallet_aura::CurrentSlot::<Runtime>::get()),
989 slots_per_epoch: Sidechain::slots_per_epoch().0,
990 }
991 }
992 }
993
994 impl sidechain_slots::SlotApi<Block> for Runtime {
995 fn slot_config() -> sidechain_slots::ScSlotConfig {
996 sidechain_slots::ScSlotConfig {
997 slots_per_epoch: Sidechain::slots_per_epoch(),
998 slot_duration: <Self as sp_consensus_aura::runtime_decl_for_aura_api::AuraApi<Block, AuraId>>::slot_duration()
999 }
1000 }
1001 }
1002
1003 impl sp_block_producer_metadata::BlockProducerMetadataApi<Block, BlockProducerMetadataType> for Runtime
1004 {
1005 fn get_metadata_for(
1006 cross_chain_pub_key: &CrossChainPublicKey,
1007 ) -> Option<BlockProducerMetadataType> {
1008 BlockProducerMetadata::get_metadata_for(&cross_chain_pub_key)
1009 }
1010 }
1011
1012 impl sp_block_producer_fees::BlockProducerFeesApi<Block, AccountId> for Runtime
1013 {
1014 fn get_all_fees() -> Vec<(AccountId, sp_block_producer_fees::PerTenThousands)> {
1015 BlockProducerFees::get_all_latest().map(|(account_id, (_slot, fee))| (account_id, fee)).collect()
1016 }
1017 }
1018
1019 #[api_version(2)]
1020 impl sp_session_validator_management::SessionValidatorManagementApi<
1021 Block,
1022 CommitteeMember<CrossChainPublic, SessionKeys>,
1023 AuthoritySelectionInputs,
1024 sidechain_domain::ScEpochNumber
1025 > for Runtime {
1026 fn get_current_committee() -> (ScEpochNumber, Vec<CommitteeMember<CrossChainPublic, SessionKeys>>) {
1027 SessionCommitteeManagement::current_committee_storage().as_pair()
1028 }
1029 fn get_next_committee() -> Option<(ScEpochNumber, Vec<CommitteeMember<CrossChainPublic, SessionKeys>>)> {
1030 Some(SessionCommitteeManagement::next_committee_storage()?.as_pair())
1031 }
1032 fn get_next_unset_epoch_number() -> sidechain_domain::ScEpochNumber {
1033 SessionCommitteeManagement::get_next_unset_epoch_number()
1034 }
1035 fn calculate_committee(authority_selection_inputs: AuthoritySelectionInputs, sidechain_epoch: ScEpochNumber) -> Option<Vec<CommitteeMember<CrossChainPublic, SessionKeys>>> {
1036 SessionCommitteeManagement::calculate_committee(authority_selection_inputs, sidechain_epoch)
1037 }
1038 fn get_main_chain_scripts() -> sp_session_validator_management::MainChainScripts {
1039 SessionCommitteeManagement::get_main_chain_scripts()
1040 }
1041 }
1042
1043 impl authority_selection_inherents::filter_invalid_candidates::CandidateValidationApi<Block> for Runtime {
1044 fn validate_registered_candidate_data(stake_pool_public_key: &StakePoolPublicKey, registration_data: &RegistrationData) -> Option<RegistrationDataError> {
1045 authority_selection_inherents::filter_invalid_candidates::validate_registration_data(stake_pool_public_key, registration_data, Sidechain::genesis_utxo()).err()
1046 }
1047 fn validate_stake(stake: Option<StakeDelegation>) -> Option<StakeError> {
1048 authority_selection_inherents::filter_invalid_candidates::validate_stake(stake).err()
1049 }
1050 fn validate_permissioned_candidate_data(candidate: PermissionedCandidateData) -> Option<PermissionedCandidateDataError> {
1051 validate_permissioned_candidate_data::<CrossChainPublic>(candidate).err()
1052 }
1053 }
1054
1055 impl sp_native_token_management::NativeTokenManagementApi<Block> for Runtime {
1056 fn get_main_chain_scripts() -> Option<sp_native_token_management::MainChainScripts> {
1057 NativeTokenManagement::get_main_chain_scripts()
1058 }
1059 fn initialized() -> bool {
1060 NativeTokenManagement::initialized()
1061 }
1062 }
1063
1064 impl sp_block_production_log::BlockProductionLogApi<Block, CommitteeMember<CrossChainPublic, SessionKeys>> for Runtime {
1065 fn get_author(slot: Slot) -> Option<CommitteeMember<CrossChainPublic, SessionKeys>> {
1066 SessionCommitteeManagement::get_current_authority_round_robin(*slot as usize)
1067 }
1068 }
1069
1070 impl sp_block_participation::BlockParticipationApi<Block, BlockAuthor> for Runtime {
1071 fn should_release_data(slot: Slot) -> Option<Slot> {
1072 BlockParticipation::should_release_data(slot)
1073 }
1074 fn blocks_produced_up_to_slot(slot: Slot) -> Vec<(Slot, BlockAuthor)> {
1075 <Runtime as pallet_block_participation::Config>::blocks_produced_up_to_slot(slot).collect()
1076 }
1077 fn target_inherent_id() -> InherentIdentifier {
1078 <Runtime as pallet_block_participation::Config>::TARGET_INHERENT_ID
1079 }
1080 }
1081
1082 impl sp_governed_map::GovernedMapIDPApi<Block> for Runtime {
1083 fn is_initialized() -> bool {
1084 GovernedMap::is_initialized()
1085 }
1086 fn get_current_state() -> BTreeMap<String, ByteString> {
1087 GovernedMap::get_all_key_value_pairs_unbounded().collect()
1088 }
1089 fn get_main_chain_scripts() -> Option<MainChainScriptsV1> {
1090 GovernedMap::get_main_chain_scripts()
1091 }
1092 fn get_pallet_version() -> u32 {
1093 GovernedMap::get_version()
1094 }
1095 }
1096}
1097
1098#[cfg(test)]
1099mod tests {
1100 use crate::mock::*;
1101 use frame_support::{
1102 dispatch::PostDispatchInfo,
1103 inherent::ProvideInherent,
1104 traits::{UnfilteredDispatchable, WhitelistedStorageKeys},
1105 };
1106 use sp_core::{Pair, hexdisplay::HexDisplay};
1107 use sp_inherents::InherentData;
1108 use std::collections::HashSet;
1109
1110 #[test]
1111 fn check_whitelist() {
1112 let whitelist: HashSet<String> = super::AllPalletsWithSystem::whitelisted_storage_keys()
1113 .iter()
1114 .map(|e| HexDisplay::from(&e.key).to_string())
1115 .collect();
1116
1117 assert!(
1119 whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")
1120 );
1121 assert!(
1123 whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")
1124 );
1125 assert!(
1127 whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")
1128 );
1129 assert!(
1131 whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")
1132 );
1133 assert!(
1135 whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")
1136 );
1137 }
1138
1139 #[test]
1141 fn check_grandpa_authorities_rotation() {
1142 new_test_ext().execute_with(|| {
1143 advance_block();
1145 set_committee_through_inherent_data(&[alice()]);
1146 until_epoch_after_finalizing(1, &|| {
1147 assert_current_epoch!(0);
1148 assert_grandpa_weights();
1149 assert_grandpa_authorities!([alice(), bob()]);
1150 });
1151
1152 set_committee_through_inherent_data(&[bob()]);
1153 for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH, &|| {
1154 assert_current_epoch!(1);
1155 assert_grandpa_weights();
1156 assert_grandpa_authorities!([alice()]);
1157 });
1158
1159 for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH, &|| {
1160 assert_current_epoch!(2);
1161 assert_grandpa_weights();
1162 assert_grandpa_authorities!([bob()]);
1163 });
1164
1165 set_committee_through_inherent_data(&[alice()]);
1167 advance_block();
1168 assert_current_epoch!(3);
1169 assert_grandpa_authorities!([bob()]);
1170 set_committee_through_inherent_data(&[alice(), bob()]);
1171 for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH - 1, &|| {
1172 assert_current_epoch!(3);
1173 assert_grandpa_weights();
1174 assert_grandpa_authorities!([alice()]);
1175 });
1176
1177 for_next_n_blocks_after_finalizing(SLOTS_PER_EPOCH * 3, &|| {
1178 assert_grandpa_weights();
1179 assert_grandpa_authorities!([alice(), bob()]);
1180 });
1181 });
1182
1183 fn assert_grandpa_weights() {
1184 Grandpa::grandpa_authorities()
1185 .into_iter()
1186 .for_each(|(_, weight)| assert_eq!(weight, 1))
1187 }
1188 }
1189
1190 #[test]
1192 fn check_aura_authorities_rotation() {
1193 new_test_ext().execute_with(|| {
1194 advance_block();
1195 set_committee_through_inherent_data(&[alice()]);
1196 until_epoch(1, &|| {
1197 assert_current_epoch!(0);
1198 assert_aura_authorities!([alice(), bob()]);
1199 });
1200
1201 for_next_n_blocks(SLOTS_PER_EPOCH, &|| {
1202 assert_current_epoch!(1);
1203 assert_aura_authorities!([alice()]);
1204 });
1205
1206 set_committee_through_inherent_data(&[bob()]);
1208 assert_current_epoch!(2);
1209 assert_aura_authorities!([alice()]);
1210 advance_block();
1211 set_committee_through_inherent_data(&[alice(), bob()]);
1212 for_next_n_blocks(SLOTS_PER_EPOCH - 1, &|| {
1213 assert_current_epoch!(2);
1214 assert_aura_authorities!([bob()]);
1215 });
1216
1217 set_committee_through_inherent_data(&[alice(), bob()]);
1218 for_next_n_blocks(SLOTS_PER_EPOCH * 3, &|| {
1219 assert_aura_authorities!([alice(), bob()]);
1220 });
1221 });
1222 }
1223
1224 #[test]
1226 fn check_cross_chain_committee_rotation() {
1227 new_test_ext().execute_with(|| {
1228 advance_block();
1229 set_committee_through_inherent_data(&[alice()]);
1230 until_epoch(1, &|| {
1231 assert_current_epoch!(0);
1232 assert_next_committee!([alice()]);
1233 });
1234
1235 set_committee_through_inherent_data(&[bob()]);
1236 for_next_n_blocks(SLOTS_PER_EPOCH, &|| {
1237 assert_current_epoch!(1);
1238 assert_next_committee!([bob()]);
1239 });
1240
1241 set_committee_through_inherent_data(&[]);
1242 for_next_n_blocks(SLOTS_PER_EPOCH, &|| {
1243 assert_current_epoch!(2);
1244 assert_next_committee!([bob()]);
1245 });
1246 });
1247 }
1248
1249 pub fn set_committee_through_inherent_data(
1250 expected_authorities: &[TestKeys],
1251 ) -> PostDispatchInfo {
1252 let epoch = Sidechain::current_epoch_number();
1253 let slot = *pallet_aura::CurrentSlot::<Test>::get();
1254 println!(
1255 "(slot {slot}, epoch {epoch}) Setting {} authorities for next epoch",
1256 expected_authorities.len()
1257 );
1258 let inherent_data_struct = create_inherent_data_struct(expected_authorities);
1259 let mut inherent_data = InherentData::new();
1260 inherent_data
1261 .put_data(
1262 SessionCommitteeManagement::INHERENT_IDENTIFIER,
1263 &inherent_data_struct.data.unwrap(),
1264 )
1265 .expect("Setting inherent data should not fail");
1266 let call = <SessionCommitteeManagement as ProvideInherent>::create_inherent(&inherent_data)
1267 .expect("Creating test inherent should not fail");
1268 println!(" inherent: {:?}", call);
1269 call.dispatch_bypass_filter(RuntimeOrigin::none())
1270 .expect("dispatching test call should work")
1271 }
1272}