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