//! The Joystream Substrate Node runtime. #![cfg_attr(not(feature = "std"), no_std)] // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] //Substrate internal issues. #![allow(clippy::large_enum_variant)] #![allow(clippy::unnecessary_mut_passed)] #![allow(non_fmt_panic)] #![allow(clippy::from_over_into)] // Mutually exclusive feature check #[cfg(all(feature = "staging_runtime", feature = "testing_runtime"))] compile_error!("feature \"staging_runtime\" and feature \"testing_runtime\" cannot be enabled at the same time"); // Make the WASM binary available. // This is required only by the node build. // A dummy wasm_binary.rs will be built for the IDE. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); #[cfg(feature = "std")] /// Wasm binary unwrapped. If built with `BUILD_DUMMY_WASM_BINARY`, the function panics. pub fn wasm_binary_unwrap() -> &'static [u8] { WASM_BINARY.expect( "Development wasm binary is not available. This means the client is \ built with `BUILD_DUMMY_WASM_BINARY` flag and it is only usable for \ production chains. Please rebuild with the flag disabled.", ) } pub mod constants; mod integration; pub mod primitives; mod proposals_configuration; mod runtime_api; #[cfg(test)] mod tests; /// Weights for pallets used in the runtime. mod weights; // Runtime integration tests #[macro_use] extern crate lazy_static; // for proposals_configuration module use frame_support::traits::{Currency, KeyOwnerProofSystem, LockIdentifier, OnUnbalanced}; use frame_support::weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}, Weight, }; use frame_support::weights::{WeightToFeeCoefficients, WeightToFeePolynomial}; use frame_support::{construct_runtime, parameter_types}; use frame_system::{EnsureOneOf, EnsureRoot, EnsureSigned}; use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as pallet_session_historical; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_core::crypto::KeyTypeId; use sp_core::Hasher; use sp_runtime::curve::PiecewiseLinear; use sp_runtime::traits::{BlakeTwo256, Block as BlockT, IdentityLookup, OpaqueKeys, Saturating}; use sp_runtime::{create_runtime_str, generic, impl_opaque_keys, ModuleId, Perbill}; use sp_std::boxed::Box; use sp_std::vec::Vec; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; pub use constants::*; pub use primitives::*; pub use proposals_configuration::*; pub use runtime_api::*; use integration::proposals::{CouncilManager, ExtrinsicProposalEncoder}; use common::working_group::{WorkingGroup, WorkingGroupBudgetHandler}; use council::ReferendumConnection; use referendum::{CastVote, OptionResult}; use staking_handler::{LockComparator, StakingManager}; // Node dependencies pub use common; pub use council; pub use forum; pub use membership; #[cfg(any(feature = "std", test))] pub use pallet_balances::Call as BalancesCall; pub use pallet_staking::StakerStatus; pub use proposals_engine::ProposalParameters; pub use referendum; pub use working_group; pub use content; pub use content::MaxNumber; /// This runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { #[cfg(not(any(feature = "staging_runtime", feature = "testing_runtime")))] spec_name: create_runtime_str!("joystream-node"), #[cfg(feature = "staging_runtime")] spec_name: create_runtime_str!("joystream-node-staging"), #[cfg(feature = "testing_runtime")] spec_name: create_runtime_str!("joystream-node-testing"), impl_name: create_runtime_str!("joystream-node"), authoring_version: 10, spec_version: 4, impl_version: 0, apis: crate::runtime_api::EXPORTED_RUNTIME_API_VERSIONS, transaction_version: 1, }; /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default(), } } parameter_types! { pub const BlockHashCount: BlockNumber = 250; /// We allow for 2 seconds of compute with a 6 second average block time. pub const MaximumBlockWeight: Weight = 2 * frame_support::weights::constants::WEIGHT_PER_SECOND; pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; pub const Version: RuntimeVersion = VERSION; /// Assume 10% of weight for average on_initialize calls. pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get().saturating_sub(AVERAGE_ON_INITIALIZE_WEIGHT) * MaximumBlockWeight::get(); } const AVERAGE_ON_INITIALIZE_WEIGHT: Perbill = Perbill::from_percent(10); // TODO: We need to adjust weight of this pallet // once we move to a newer version of substrate where parameters // are not discarded. See the comment in 'scripts/generate-weights.sh' impl frame_system::Trait for Runtime { type BaseCallFilter = (); type Origin = Origin; type Call = Call; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = generic::Header; type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type DbWeight = RocksDbWeight; type BlockExecutionWeight = BlockExecutionWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type MaximumExtrinsicWeight = MaximumExtrinsicWeight; type MaximumBlockLength = MaximumBlockLength; type AvailableBlockRatio = AvailableBlockRatio; type Version = Version; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = weights::frame_system::WeightInfo; } impl substrate_utility::Trait for Runtime { type Event = Event; type Call = Call; type WeightInfo = weights::substrate_utility::WeightInfo; } parameter_types! { pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS as u64; pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; } impl pallet_babe::Trait for Runtime { type EpochDuration = EpochDuration; type ExpectedBlockTime = ExpectedBlockTime; type EpochChangeTrigger = pallet_babe::ExternalTrigger; type KeyOwnerProofSystem = Historical; type KeyOwnerProof = >::Proof; type KeyOwnerIdentification = >::IdentificationTuple; type HandleEquivocation = pallet_babe::EquivocationHandler; type WeightInfo = (); } impl pallet_grandpa::Trait for Runtime { type Event = Event; type Call = Call; type KeyOwnerProof = >::Proof; type KeyOwnerIdentification = >::IdentificationTuple; type KeyOwnerProofSystem = Historical; type HandleEquivocation = pallet_grandpa::EquivocationHandler; type WeightInfo = (); } impl frame_system::offchain::CreateSignedTransaction for Runtime where Call: From, { fn create_transaction>( call: Call, public: ::Signer, account: AccountId, nonce: Index, ) -> Option<( Call, ::SignaturePayload, )> { integration::transactions::create_transaction::(call, public, account, nonce) } } impl frame_system::offchain::SigningTypes for Runtime { type Public = ::Signer; type Signature = Signature; } impl frame_system::offchain::SendTransactionTypes for Runtime where Call: From, { type Extrinsic = UncheckedExtrinsic; type OverarchingCall = Call; } parameter_types! { pub const MinimumPeriod: Moment = SLOT_DURATION / 2; } impl pallet_timestamp::Trait for Runtime { type Moment = Moment; type OnTimestampSet = Babe; type MinimumPeriod = MinimumPeriod; type WeightInfo = weights::pallet_timestamp::WeightInfo; } parameter_types! { pub const MaxLocks: u32 = 50; } impl pallet_balances::Trait for Runtime { type Balance = Balance; type DustRemoval = (); type Event = Event; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = weights::pallet_balances::WeightInfo; type MaxLocks = MaxLocks; } parameter_types! { pub const TransactionByteFee: Balance = 0; } // Temporary commented for Olympia: https://github.com/Joystream/joystream/issues/3237 // TODO: Restore after the Olympia release // parameter_types! { // pub const TransactionByteFee: Balance = 1; // } type NegativeImbalance = >::NegativeImbalance; pub struct Author; impl OnUnbalanced for Author { fn on_nonzero_unbalanced(amount: NegativeImbalance) { Balances::resolve_creating(&Authorship::author(), amount); } } // Temporary commented for Olympia: https://github.com/Joystream/joystream/issues/3237 // TODO: Restore after the Olympia release // pub struct DealWithFees; // impl OnUnbalanced for DealWithFees { // fn on_unbalanceds(mut fees_then_tips: impl Iterator) { // if let Some(fees) = fees_then_tips.next() { // // for fees, 20% to author, for now we don't have treasury so the 80% is ignored // let mut split = fees.ration(80, 20); // if let Some(tips) = fees_then_tips.next() { // // For tips %100 are for the author // tips.ration_merge_into(0, 100, &mut split); // } // Author::on_unbalanced(split.1); // } // } // } /// Stub for zero transaction weights. pub struct NoWeights; impl WeightToFeePolynomial for NoWeights { type Balance = Balance; fn polynomial() -> WeightToFeeCoefficients { Default::default() } fn calc(_weight: &u64) -> Self::Balance { Default::default() } } impl pallet_transaction_payment::Trait for Runtime { type Currency = Balances; type OnTransactionPayment = (); type TransactionByteFee = TransactionByteFee; type WeightToFee = NoWeights; type FeeMultiplierUpdate = (); } // Temporary commented for Olympia: https://github.com/Joystream/joystream/issues/3237 // TODO: Restore after the Olympia release // impl pallet_transaction_payment::Trait for Runtime { // type Currency = Balances; // type OnTransactionPayment = DealWithFees; // type TransactionByteFee = TransactionByteFee; // type WeightToFee = constants::fees::WeightToFee; // type FeeMultiplierUpdate = constants::fees::SlowAdjustingFeeUpdate; // } impl pallet_sudo::Trait for Runtime { type Event = Event; type Call = Call; } parameter_types! { pub const UncleGenerations: BlockNumber = 0; } impl pallet_authorship::Trait for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; type UncleGenerations = UncleGenerations; type FilterUncle = (); type EventHandler = (Staking, ImOnline); } impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, pub babe: Babe, pub im_online: ImOnline, pub authority_discovery: AuthorityDiscovery, } } // NOTE: `SessionHandler` and `SessionKeys` are co-dependent: One key will be used for each handler. // The number and order of items in `SessionHandler` *MUST* be the same number and order of keys in // `SessionKeys`. // TODO: Introduce some structure to tie these together to make it a bit less of a footgun. This // should be easy, since OneSessionHandler trait provides the `Key` as an associated type. #2858 parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); } impl pallet_session::Trait for Runtime { type Event = Event; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; type NextSessionRotation = Babe; type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type WeightInfo = weights::pallet_session::WeightInfo; } impl pallet_session::historical::Trait for Runtime { type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } pallet_staking_reward_curve::build! { const REWARD_CURVE: PiecewiseLinear<'static> = curve!( min_inflation: 0_050_000, max_inflation: 0_750_000, ideal_stake: 0_300_000, falloff: 0_050_000, max_piece_count: 100, test_precision: 0_005_000, ); } parameter_types! { pub const SessionDuration: BlockNumber = EPOCH_DURATION_IN_SLOTS as _; pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; } parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = 6; pub const BondingDuration: pallet_staking::EraIndex = BONDING_DURATION; pub const SlashDeferDuration: pallet_staking::EraIndex = BONDING_DURATION - 1; // 'slightly less' than the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const ElectionLookahead: BlockNumber = EPOCH_DURATION_IN_BLOCKS / 4; pub const MaxIterations: u32 = 10; // 0.05%. The higher the value, the more strict solution acceptance becomes. pub MinSolutionScoreBump: Perbill = Perbill::from_rational_approximation(5u32, 10_000); } impl pallet_staking::Trait for Runtime { type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = CurrencyToVoteHandler; type RewardRemainder = (); // Could be Treasury. type Event = Event; type Slash = (); // Where to send the slashed funds. Could be Treasury. type Reward = (); // Rewards are minted from the void. type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; type SlashCancelOrigin = EnsureRoot; // Requires sudo. Parity recommends: a super-majority of the council can cancel the slash. type SessionInterface = Self; type RewardCurve = RewardCurve; type NextNewSession = Session; type ElectionLookahead = ElectionLookahead; type Call = Call; type MaxIterations = MaxIterations; type MinSolutionScoreBump = MinSolutionScoreBump; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type UnsignedPriority = StakingUnsignedPriority; type WeightInfo = weights::pallet_staking::WeightInfo; } impl pallet_im_online::Trait for Runtime { type AuthorityId = ImOnlineId; type Event = Event; type SessionDuration = SessionDuration; type ReportUnresponsiveness = Offences; // Using the default weights until we check if we can run the benchmarks for this pallet in // the reference machine in an acceptable time. type WeightInfo = (); type UnsignedPriority = ImOnlineUnsignedPriority; } parameter_types! { pub OffencesWeightSoftLimit: Weight = Perbill::from_percent(60) * MaximumBlockWeight::get(); } impl pallet_offences::Trait for Runtime { type Event = Event; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; type WeightSoftLimit = OffencesWeightSoftLimit; } impl pallet_authority_discovery::Trait for Runtime {} parameter_types! { pub const WindowSize: BlockNumber = 101; pub const ReportLatency: BlockNumber = 1000; } impl pallet_finality_tracker::Trait for Runtime { type OnFinalizationStalled = (); type WindowSize = WindowSize; type ReportLatency = ReportLatency; } impl common::currency::GovernanceCurrency for Runtime { type Currency = pallet_balances::Module; } parameter_types! { pub const MaxNumberOfCuratorsPerGroup: MaxNumber = 50; pub const MaxModerators: u64 = 5; // TODO: update pub const CleanupMargin: u32 = 3; // TODO: update pub const CleanupCost: u32 = 1; // TODO: update pub const PricePerByte: u32 = 2; // TODO: update pub const ContentModuleId: ModuleId = ModuleId(*b"mContent"); // module content pub const BloatBondCap: u32 = 1000; // TODO: update } impl content::Trait for Runtime { type Event = Event; type ChannelCategoryId = ChannelCategoryId; type VideoId = VideoId; type VideoCategoryId = VideoCategoryId; type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup; type DataObjectStorage = Storage; type VideoPostId = VideoPostId; type ReactionId = ReactionId; type MaxModerators = MaxModerators; type PricePerByte = PricePerByte; type BloatBondCap = BloatBondCap; type CleanupMargin = CleanupMargin; type CleanupCost = CleanupCost; type ModuleId = ContentModuleId; } // The referendum instance alias. pub type ReferendumInstance = referendum::Instance1; pub type ReferendumModule = referendum::Module; pub type CouncilModule = council::Module; // Production coucil and elections configuration #[cfg(not(any(feature = "staging_runtime", feature = "testing_runtime")))] parameter_types! { // referendum parameters pub const MaxSaltLength: u64 = 32; pub const VoteStageDuration: BlockNumber = 14400; pub const RevealStageDuration: BlockNumber = 14400; pub const MinimumVotingStake: u64 = 10000; // council parameteres pub const MinNumberOfExtraCandidates: u64 = 0; pub const AnnouncingPeriodDuration: BlockNumber = 14400; pub const IdlePeriodDuration: BlockNumber = 57600; pub const CouncilSize: u64 = 12; pub const MinCandidateStake: u64 = 1000; pub const ElectedMemberRewardPeriod: BlockNumber = 14400; pub const DefaultBudgetIncrement: u64 = 5000000; pub const BudgetRefillPeriod: BlockNumber = 14400; pub const MaxWinnerTargetCount: u64 = 15; // should be greater than council size } // Common staging and testing coucil and elections configuration #[cfg(any(feature = "staging_runtime", feature = "testing_runtime"))] parameter_types! { // referendum parameters pub const MaxSaltLength: u64 = 32; pub const VoteStageDuration: BlockNumber = 100; pub const RevealStageDuration: BlockNumber = 50; pub const MinimumVotingStake: u64 = 10000; // council parameteres pub const MinNumberOfExtraCandidates: u64 = 1; pub const AnnouncingPeriodDuration: BlockNumber = 200; pub const IdlePeriodDuration: BlockNumber = 400; pub const MinCandidateStake: u64 = 1000; pub const ElectedMemberRewardPeriod: BlockNumber = 14400; pub const DefaultBudgetIncrement: u64 = 10000000; pub const BudgetRefillPeriod: BlockNumber = 1000; pub const MaxWinnerTargetCount: u64 = 10; } // Staging network council size #[cfg(feature = "staging_runtime")] #[cfg(not(feature = "playground_runtime"))] parameter_types! { pub const CouncilSize: u64 = 5; } // Staging but customized for playground council size #[cfg(feature = "staging_runtime")] #[cfg(feature = "playground_runtime")] parameter_types! { pub const CouncilSize: u64 = 1; } // Testing council size #[cfg(feature = "testing_runtime")] parameter_types! { pub const CouncilSize: u64 = 5; } impl referendum::Trait for Runtime { type Event = Event; type MaxSaltLength = MaxSaltLength; type StakingHandler = VotingStakingManager; type ManagerOrigin = EnsureOneOf, EnsureRoot>; type VotePower = Balance; type VoteStageDuration = VoteStageDuration; type RevealStageDuration = RevealStageDuration; type MinimumStake = MinimumVotingStake; type WeightInfo = weights::referendum::WeightInfo; type MaxWinnerTargetCount = MaxWinnerTargetCount; fn calculate_vote_power( _account_id: &::AccountId, stake: &Balance, ) -> Self::VotePower { *stake } fn can_unlock_vote_stake(vote: &CastVote) -> bool { >::can_unlock_vote_stake(vote).is_ok() } fn process_results(winners: &[OptionResult]) { let tmp_winners: Vec> = winners .iter() .map(|item| OptionResult { option_id: item.option_id, vote_power: item.vote_power, }) .collect(); >::recieve_referendum_results( tmp_winners.as_slice(), ); } fn is_valid_option_id(option_index: &u64) -> bool { >::is_valid_candidate_id(option_index) } fn get_option_power(option_id: &u64) -> Self::VotePower { >::get_option_power(option_id) } fn increase_option_power(option_id: &u64, amount: &Self::VotePower) { >::increase_option_power(option_id, amount); } } impl council::Trait for Runtime { type Event = Event; type Referendum = ReferendumModule; type MinNumberOfExtraCandidates = MinNumberOfExtraCandidates; type CouncilSize = CouncilSize; type AnnouncingPeriodDuration = AnnouncingPeriodDuration; type IdlePeriodDuration = IdlePeriodDuration; type MinCandidateStake = MinCandidateStake; type CandidacyLock = StakingManager; type CouncilorLock = StakingManager; type StakingAccountValidator = Members; type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod; type BudgetRefillPeriod = BudgetRefillPeriod; type MemberOriginValidator = Members; type WeightInfo = weights::council::WeightInfo; fn new_council_elected(_elected_members: &[council::CouncilMemberOf]) { >::reject_active_proposals(); >::reactivate_pending_constitutionality_proposals(); } } impl common::StorageOwnership for Runtime { type ChannelId = ChannelId; type ContentId = ContentId; type DataObjectTypeId = DataObjectTypeId; } parameter_types! { pub const MaxDistributionBucketFamilyNumber: u64 = 200; pub const DataObjectDeletionPrize: Balance = 0; //TODO: Change during Olympia release pub const BlacklistSizeLimit: u64 = 10000; //TODO: adjust value pub const MaxRandomIterationNumber: u64 = 10; //TODO: adjust value pub const MaxNumberOfPendingInvitationsPerDistributionBucket: u64 = 20; //TODO: adjust value pub const StorageModuleId: ModuleId = ModuleId(*b"mstorage"); // module storage pub const StorageBucketsPerBagValueConstraint: storage::StorageBucketsPerBagValueConstraint = storage::StorageBucketsPerBagValueConstraint {min: 5, max_min_diff: 15}; //TODO: adjust value pub const DefaultMemberDynamicBagNumberOfStorageBuckets: u64 = 5; //TODO: adjust value pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 5; //TODO: adjust value pub const DistributionBucketsPerBagValueConstraint: storage::DistributionBucketsPerBagValueConstraint = storage::DistributionBucketsPerBagValueConstraint {min: 1, max_min_diff: 100}; //TODO: adjust value pub const MaxDataObjectSize: u64 = 10 * 1024 * 1024 * 1024; // 10 GB } impl storage::Trait for Runtime { type Event = Event; type DataObjectId = DataObjectId; type StorageBucketId = StorageBucketId; type DistributionBucketIndex = DistributionBucketIndex; type DistributionBucketFamilyId = DistributionBucketFamilyId; type ChannelId = ChannelId; type DataObjectDeletionPrize = DataObjectDeletionPrize; type BlacklistSizeLimit = BlacklistSizeLimit; type ModuleId = StorageModuleId; type StorageBucketsPerBagValueConstraint = StorageBucketsPerBagValueConstraint; type DefaultMemberDynamicBagNumberOfStorageBuckets = DefaultMemberDynamicBagNumberOfStorageBuckets; type DefaultChannelDynamicBagNumberOfStorageBuckets = DefaultChannelDynamicBagNumberOfStorageBuckets; type Randomness = RandomnessCollectiveFlip; type MaxRandomIterationNumber = MaxRandomIterationNumber; type MaxDistributionBucketFamilyNumber = MaxDistributionBucketFamilyNumber; type DistributionBucketsPerBagValueConstraint = DistributionBucketsPerBagValueConstraint; type DistributionBucketOperatorId = DistributionBucketOperatorId; type MaxNumberOfPendingInvitationsPerDistributionBucket = MaxNumberOfPendingInvitationsPerDistributionBucket; type MaxDataObjectSize = MaxDataObjectSize; type ContentId = ContentId; type StorageWorkingGroup = StorageWorkingGroup; type DistributionWorkingGroup = DistributionWorkingGroup; } impl common::membership::MembershipTypes for Runtime { type MemberId = MemberId; type ActorId = ActorId; } parameter_types! { pub const DefaultMembershipPrice: Balance = 100; pub const ReferralCutMaximumPercent: u8 = 50; pub const DefaultInitialInvitationBalance: Balance = 100; // The candidate stake should be more than the transaction fee which currently is 53 pub const CandidateStake: Balance = 200; } impl membership::Trait for Runtime { type Event = Event; type DefaultMembershipPrice = DefaultMembershipPrice; type DefaultInitialInvitationBalance = DefaultInitialInvitationBalance; type InvitedMemberStakingHandler = InvitedMemberStakingManager; type StakingCandidateStakingHandler = BoundStakingAccountStakingManager; type WorkingGroup = MembershipWorkingGroup; type WeightInfo = weights::membership::WeightInfo; type ReferralCutMaximumPercent = ReferralCutMaximumPercent; type CandidateStake = CandidateStake; } parameter_types! { pub const MaxCategoryDepth: u64 = 6; pub const MaxSubcategories: u64 = 20; pub const MaxThreadsInCategory: u64 = 20; pub const MaxPostsInThread: u64 = 20; pub const MaxModeratorsForCategory: u64 = 20; pub const MaxCategories: u64 = 20; pub const MaxPollAlternativesNumber: u64 = 20; pub const ThreadDeposit: u64 = 30; pub const PostDeposit: u64 = 10; pub const ForumModuleId: ModuleId = ModuleId(*b"mo:forum"); // module : forum pub const PostLifeTime: BlockNumber = 3600; } pub struct MapLimits; impl forum::StorageLimits for MapLimits { type MaxSubcategories = MaxSubcategories; type MaxModeratorsForCategory = MaxModeratorsForCategory; type MaxCategories = MaxCategories; type MaxPollAlternativesNumber = MaxPollAlternativesNumber; } impl forum::Trait for Runtime { type Event = Event; type ThreadId = ThreadId; type PostId = PostId; type CategoryId = u64; type PostReactionId = u64; type MaxCategoryDepth = MaxCategoryDepth; type ThreadDeposit = ThreadDeposit; type PostDeposit = PostDeposit; type ModuleId = ForumModuleId; type MapLimits = MapLimits; type WeightInfo = weights::forum::WeightInfo; type WorkingGroup = ForumWorkingGroup; type MemberOriginValidator = Members; type PostLifeTime = PostLifeTime; fn calculate_hash(text: &[u8]) -> Self::Hash { Self::Hashing::hash(text) } } impl LockComparator<::Balance> for Runtime { fn are_locks_conflicting(new_lock: &LockIdentifier, existing_locks: &[LockIdentifier]) -> bool { let other_locks_present = !existing_locks.is_empty(); let new_lock_is_rivalrous = !NON_RIVALROUS_LOCKS.contains(new_lock); let existing_locks_contain_rivalrous_lock = existing_locks .iter() .any(|lock_id| !NON_RIVALROUS_LOCKS.contains(lock_id)); other_locks_present && new_lock_is_rivalrous && existing_locks_contain_rivalrous_lock } } parameter_types! { pub const MaxWorkerNumberLimit: u32 = 100; pub const MinUnstakingPeriodLimit: u32 = 43200; pub const ForumWorkingGroupRewardPeriod: u32 = 14400 + 10; pub const StorageWorkingGroupRewardPeriod: u32 = 14400 + 20; pub const ContentWorkingGroupRewardPeriod: u32 = 14400 + 30; pub const MembershipRewardPeriod: u32 = 14400 + 40; pub const GatewayRewardPeriod: u32 = 14400 + 50; pub const OperationsAlphaRewardPeriod: u32 = 14400 + 60; pub const OperationsBetaRewardPeriod: u32 = 14400 + 70; pub const OperationsGammaRewardPeriod: u32 = 14400 + 80; pub const DistributionRewardPeriod: u32 = 14400 + 90; // This should be more costly than `apply_on_opening` fee with the current configuration // the base cost of `apply_on_opening` in tokens is 193. And has a very slight slope // with the lenght with the length of rationale, with 2000 stake we are probably safe. pub const MinimumApplicationStake: Balance = 2000; // This should be more costly than `add_opening` fee with the current configuration // the base cost of `add_opening` in tokens is 81. And has a very slight slope // with the lenght with the length of rationale, with 2000 stake we are probably safe. pub const LeaderOpeningStake: Balance = 2000; } // Staking managers type aliases. pub type ForumWorkingGroupStakingManager = staking_handler::StakingManager; pub type VotingStakingManager = staking_handler::StakingManager; pub type ContentWorkingGroupStakingManager = staking_handler::StakingManager; pub type StorageWorkingGroupStakingManager = staking_handler::StakingManager; pub type MembershipWorkingGroupStakingManager = staking_handler::StakingManager; pub type InvitedMemberStakingManager = staking_handler::StakingManager; pub type BoundStakingAccountStakingManager = staking_handler::StakingManager; pub type GatewayWorkingGroupStakingManager = staking_handler::StakingManager; pub type OperationsWorkingGroupAlphaStakingManager = staking_handler::StakingManager; pub type OperationsWorkingGroupBetaStakingManager = staking_handler::StakingManager; pub type OperationsWorkingGroupGammaStakingManager = staking_handler::StakingManager; pub type DistributionWorkingGroupStakingManager = staking_handler::StakingManager; // The forum working group instance alias. pub type ForumWorkingGroupInstance = working_group::Instance1; // The storage working group instance alias. pub type StorageWorkingGroupInstance = working_group::Instance2; // The content directory working group instance alias. pub type ContentWorkingGroupInstance = working_group::Instance3; // The builder working group instance alias. pub type OperationsWorkingGroupInstanceAlpha = working_group::Instance4; // The gateway working group instance alias. pub type GatewayWorkingGroupInstance = working_group::Instance5; // The membership working group instance alias. pub type MembershipWorkingGroupInstance = working_group::Instance6; // The builder working group instance alias. pub type OperationsWorkingGroupInstanceBeta = working_group::Instance7; // The builder working group instance alias. pub type OperationsWorkingGroupInstanceGamma = working_group::Instance8; // The distribution working group instance alias. pub type DistributionWorkingGroupInstance = working_group::Instance9; impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = ForumWorkingGroupStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = ForumWorkingGroupRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = StorageWorkingGroupStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = StorageWorkingGroupRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = ContentWorkingGroupStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = ContentWorkingGroupRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = MembershipWorkingGroupStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = MembershipRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = OperationsWorkingGroupAlphaStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = OperationsAlphaRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = GatewayWorkingGroupStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = GatewayRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = OperationsWorkingGroupBetaStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = OperationsBetaRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = OperationsWorkingGroupGammaStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = OperationsGammaRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; type StakingHandler = DistributionWorkingGroupStakingManager; type StakingAccountValidator = Members; type MemberOriginValidator = Members; type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit; type RewardPeriod = DistributionRewardPeriod; type WeightInfo = weights::working_group::WeightInfo; type MinimumApplicationStake = MinimumApplicationStake; type LeaderOpeningStake = LeaderOpeningStake; } parameter_types! { pub const ProposalCancellationFee: u64 = 10000; pub const ProposalRejectionFee: u64 = 5000; pub const ProposalTitleMaxLength: u32 = 40; pub const ProposalDescriptionMaxLength: u32 = 3000; pub const ProposalMaxActiveProposalLimit: u32 = 20; } impl proposals_engine::Trait for Runtime { type Event = Event; type ProposerOriginValidator = Members; type CouncilOriginValidator = Council; type TotalVotersCounter = CouncilManager; type ProposalId = u32; type StakingHandler = staking_handler::StakingManager; type CancellationFee = ProposalCancellationFee; type RejectionFee = ProposalRejectionFee; type TitleMaxLength = ProposalTitleMaxLength; type DescriptionMaxLength = ProposalDescriptionMaxLength; type MaxActiveProposalLimit = ProposalMaxActiveProposalLimit; type DispatchableCallCode = Call; type ProposalObserver = ProposalsCodex; type WeightInfo = weights::proposals_engine::WeightInfo; type StakingAccountValidator = Members; } impl Default for Call { fn default() -> Self { panic!("shouldn't call default for Call"); } } parameter_types! { pub const MaxWhiteListSize: u32 = 20; pub const ProposalsPostDeposit: Balance = 2000; // module : proposals_discussion pub const ProposalsDiscussionModuleId: ModuleId = ModuleId(*b"mo:prdis"); pub const ForumPostLifeTime: BlockNumber = 3600; } macro_rules! call_wg { ($working_group:ident, $function:ident $(,$x:expr)*) => {{ match $working_group { WorkingGroup::Content => >::$function($($x,)*), WorkingGroup::Storage => >::$function($($x,)*), WorkingGroup::Forum => >::$function($($x,)*), WorkingGroup::Membership => >::$function($($x,)*), WorkingGroup::Gateway => >::$function($($x,)*), WorkingGroup::Distribution => >::$function($($x,)*), WorkingGroup::OperationsAlpha => >::$function($($x,)*), WorkingGroup::OperationsBeta => >::$function($($x,)*), WorkingGroup::OperationsGamma => >::$function($($x,)*), } }}; } impl proposals_discussion::Trait for Runtime { type Event = Event; type AuthorOriginValidator = Members; type CouncilOriginValidator = Council; type ThreadId = ThreadId; type PostId = PostId; type MaxWhiteListSize = MaxWhiteListSize; type WeightInfo = weights::proposals_discussion::WeightInfo; type PostDeposit = ProposalsPostDeposit; type ModuleId = ProposalsDiscussionModuleId; type PostLifeTime = ForumPostLifeTime; } impl joystream_utility::Trait for Runtime { type Event = Event; type WeightInfo = weights::joystream_utility::WeightInfo; fn get_working_group_budget(working_group: WorkingGroup) -> Balance { call_wg!(working_group, get_budget) } fn set_working_group_budget(working_group: WorkingGroup, budget: Balance) { call_wg!(working_group, set_budget, budget) } } parameter_types! { // Make sure to stay below MAX_BLOCK_SIZE of substrate consensus of ~4MB pub const RuntimeUpgradeWasmProposalMaxLength: u32 = 3_500_000; } impl proposals_codex::Trait for Runtime { type Event = Event; type MembershipOriginValidator = Members; type ProposalEncoder = ExtrinsicProposalEncoder; type SetMaxValidatorCountProposalParameters = SetMaxValidatorCountProposalParameters; type RuntimeUpgradeProposalParameters = RuntimeUpgradeProposalParameters; type SignalProposalParameters = SignalProposalParameters; type FundingRequestProposalParameters = FundingRequestProposalParameters; type CreateWorkingGroupLeadOpeningProposalParameters = CreateWorkingGroupLeadOpeningProposalParameters; type FillWorkingGroupLeadOpeningProposalParameters = FillWorkingGroupLeadOpeningProposalParameters; type UpdateWorkingGroupBudgetProposalParameters = UpdateWorkingGroupBudgetProposalParameters; type DecreaseWorkingGroupLeadStakeProposalParameters = DecreaseWorkingGroupLeadStakeProposalParameters; type SlashWorkingGroupLeadProposalParameters = SlashWorkingGroupLeadProposalParameters; type SetWorkingGroupLeadRewardProposalParameters = SetWorkingGroupLeadRewardProposalParameters; type TerminateWorkingGroupLeadProposalParameters = TerminateWorkingGroupLeadProposalParameters; type AmendConstitutionProposalParameters = AmendConstitutionProposalParameters; type CancelWorkingGroupLeadOpeningProposalParameters = CancelWorkingGroupLeadOpeningProposalParameters; type SetMembershipPriceProposalParameters = SetMembershipPriceProposalParameters; type SetCouncilBudgetIncrementProposalParameters = SetCouncilBudgetIncrementProposalParameters; type SetCouncilorRewardProposalParameters = SetCouncilorRewardProposalParameters; type SetInitialInvitationBalanceProposalParameters = SetInitialInvitationBalanceProposalParameters; type SetInvitationCountProposalParameters = SetInvitationCountProposalParameters; type SetMembershipLeadInvitationQuotaProposalParameters = SetMembershipLeadInvitationQuotaProposalParameters; type SetReferralCutProposalParameters = SetReferralCutProposalParameters; type CreateBlogPostProposalParameters = CreateBlogPostProposalParameters; type EditBlogPostProoposalParamters = EditBlogPostProoposalParamters; type LockBlogPostProposalParameters = LockBlogPostProposalParameters; type UnlockBlogPostProposalParameters = UnlockBlogPostProposalParameters; type VetoProposalProposalParameters = VetoProposalProposalParameters; type WeightInfo = weights::proposals_codex::WeightInfo; } impl pallet_constitution::Trait for Runtime { type Event = Event; type WeightInfo = weights::pallet_constitution::WeightInfo; } parameter_types! { pub const BountyModuleId: ModuleId = ModuleId(*b"m:bounty"); // module : bounty pub const ClosedContractSizeLimit: u32 = 50; pub const MinCherryLimit: Balance = 1000; pub const MinFundingLimit: Balance = 1000; pub const MinWorkEntrantStake: Balance = 1000; } impl bounty::Trait for Runtime { type Event = Event; type ModuleId = BountyModuleId; type BountyId = u64; type Membership = Members; type WeightInfo = weights::bounty::WeightInfo; type CouncilBudgetManager = Council; type StakingHandler = staking_handler::StakingManager; type EntryId = u64; type ClosedContractSizeLimit = ClosedContractSizeLimit; type MinCherryLimit = MinCherryLimit; type MinFundingLimit = MinFundingLimit; type MinWorkEntrantStake = MinWorkEntrantStake; } parameter_types! { pub const PostsMaxNumber: u64 = 20; pub const RepliesMaxNumber: u64 = 100; pub const ReplyDeposit: Balance = 2000; pub const BlogModuleId: ModuleId = ModuleId(*b"mod:blog"); // module : forum pub const ReplyLifetime: BlockNumber = 43_200; } pub type BlogInstance = blog::Instance1; impl blog::Trait for Runtime { type Event = Event; type PostsMaxNumber = PostsMaxNumber; type ParticipantEnsureOrigin = Members; type WeightInfo = weights::blog::WeightInfo; type ReplyId = u64; type ReplyDeposit = ReplyDeposit; type ModuleId = BlogModuleId; type ReplyLifetime = ReplyLifetime; } /// Forum identifier for category pub type CategoryId = u64; /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know /// the specifics of the runtime. They can then be made to be agnostic over specific formats /// of data like extrinsics, allowing for them to continue syncing the network through upgrades /// to even the core datastructures. pub mod opaque { use super::*; pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; /// Opaque block header type. pub type Header = generic::Header; /// Opaque block type. pub type Block = generic::Block; /// Opaque block identifier type. pub type BlockId = generic::BlockId; } construct_runtime!( pub enum Runtime where Block = Block, NodeBlock = opaque::Block, UncheckedExtrinsic = UncheckedExtrinsic { // Substrate System: frame_system::{Module, Call, Storage, Config, Event}, Utility: substrate_utility::{Module, Call, Event}, Babe: pallet_babe::{Module, Call, Storage, Config, Inherent, ValidateUnsigned}, Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, Authorship: pallet_authorship::{Module, Call, Storage, Inherent}, Balances: pallet_balances::{Module, Call, Storage, Config, Event}, TransactionPayment: pallet_transaction_payment::{Module, Storage}, Staking: pallet_staking::{Module, Call, Config, Storage, Event, ValidateUnsigned}, Session: pallet_session::{Module, Call, Storage, Event, Config}, Historical: pallet_session_historical::{Module}, FinalityTracker: pallet_finality_tracker::{Module, Call, Inherent}, Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event}, ImOnline: pallet_im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, AuthorityDiscovery: pallet_authority_discovery::{Module, Call, Config}, Offences: pallet_offences::{Module, Call, Storage, Event}, RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, Sudo: pallet_sudo::{Module, Call, Config, Storage, Event}, // Joystream Council: council::{Module, Call, Storage, Event, Config}, Referendum: referendum::::{Module, Call, Storage, Event, Config}, Members: membership::{Module, Call, Storage, Event, Config}, Forum: forum::{Module, Call, Storage, Event, Config}, Constitution: pallet_constitution::{Module, Call, Storage, Event}, Bounty: bounty::{Module, Call, Storage, Event}, Blog: blog::::{Module, Call, Storage, Event}, JoystreamUtility: joystream_utility::{Module, Call, Event}, Content: content::{Module, Call, Storage, Event, Config}, Storage: storage::{Module, Call, Storage, Event}, // --- Proposals ProposalsEngine: proposals_engine::{Module, Call, Storage, Event}, ProposalsDiscussion: proposals_discussion::{Module, Call, Storage, Event}, ProposalsCodex: proposals_codex::{Module, Call, Storage, Event}, // --- Working groups ForumWorkingGroup: working_group::::{Module, Call, Storage, Event}, StorageWorkingGroup: working_group::::{Module, Call, Storage, Event}, ContentWorkingGroup: working_group::::{Module, Call, Storage, Event}, OperationsWorkingGroupAlpha: working_group::::{Module, Call, Storage, Event}, GatewayWorkingGroup: working_group::::{Module, Call, Storage, Event}, MembershipWorkingGroup: working_group::::{Module, Call, Storage, Event}, OperationsWorkingGroupBeta: working_group::::{Module, Call, Storage, Event}, OperationsWorkingGroupGamma: working_group::::{Module, Call, Storage, Event}, DistributionWorkingGroup: working_group::::{Module, Call, Storage, Event}, } );