//! 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)] // 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.", ) } mod constants; mod integration; pub mod primitives; mod runtime_api; #[cfg(test)] mod tests; // Runtime integration tests mod weights; use frame_support::dispatch::DispatchResult; use frame_support::traits::{Currency, KeyOwnerProofSystem, 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::EnsureRoot; 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_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 runtime_api::*; use integration::proposals::{CouncilManager, ExtrinsicProposalEncoder, MembershipOriginValidator}; use governance::{council, election}; // Node dependencies pub use common; pub use forum; pub use governance::election_params::ElectionParameters; pub use membership; #[cfg(any(feature = "std", test))] pub use pallet_balances::Call as BalancesCall; pub use pallet_staking::StakerStatus; pub use proposals_codex::ProposalsConfigParameters; pub use working_group; pub use content; pub use content::MaxNumber; /// This runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("joystream-node"), impl_name: create_runtime_str!("joystream-node"), authoring_version: 9, spec_version: 11, 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: adjust weight 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 ExistentialDeposit: u128 = 0; pub const TransferFee: u128 = 0; pub const CreationFee: u128 = 0; pub const MaxLocks: u32 = 50; pub const InitialMembersBalance: u32 = 2000; } 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; } type NegativeImbalance = >::NegativeImbalance; pub struct Author; impl OnUnbalanced for Author { fn on_nonzero_unbalanced(amount: NegativeImbalance) { Balances::resolve_creating(&Authorship::author(), amount); } } /// 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 = (); } 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 = common::currency::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; } parameter_types! { pub const MaxNumberOfCuratorsPerGroup: MaxNumber = 50; pub const ChannelOwnershipPaymentEscrowId: [u8; 8] = *b"chescrow"; pub const VideosMigrationsEachBlock: u64 = 100; pub const ChannelsMigrationsEachBlock: u64 = 25; } impl content::Trait for Runtime { type Event = Event; type ChannelOwnershipPaymentEscrowId = ChannelOwnershipPaymentEscrowId; type ChannelCategoryId = ChannelCategoryId; type VideoId = VideoId; type VideoCategoryId = VideoCategoryId; type PlaylistId = PlaylistId; type PersonId = PersonId; type SeriesId = SeriesId; type ChannelOwnershipTransferRequestId = ChannelOwnershipTransferRequestId; type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup; type DataObjectStorage = Storage; type VideosMigrationsEachBlock = VideosMigrationsEachBlock; type ChannelsMigrationsEachBlock = ChannelsMigrationsEachBlock; } impl hiring::Trait for Runtime { type OpeningId = u64; type ApplicationId = u64; type ApplicationDeactivatedHandler = (); // TODO - what needs to happen? type StakeHandlerProvider = hiring::Module; } impl minting::Trait for Runtime { type Currency = ::Currency; type MintId = u64; } impl recurring_rewards::Trait for Runtime { type PayoutStatusHandler = (); // TODO - deal with successful and failed payouts type RecipientId = u64; type RewardRelationshipId = u64; } parameter_types! { pub const StakePoolId: [u8; 8] = *b"joystake"; } #[allow(clippy::type_complexity)] impl stake::Trait for Runtime { type Currency = ::Currency; type StakePoolId = StakePoolId; type StakingEventsHandler = ( ( ( crate::integration::proposals::StakingEventsHandler, crate::integration::working_group::ContentDirectoryWgStakingEventsHandler, ), ( crate::integration::working_group::StorageWgStakingEventsHandler, crate::integration::working_group::OperationsWgStakingEventsHandlerAlpha, ), ), ( ( crate::integration::working_group::OperationsWgStakingEventsHandlerBeta, crate::integration::working_group::OperationsWgStakingEventsHandlerGamma, ), ( crate::integration::working_group::GatewayWgStakingEventsHandler, crate::integration::working_group::DistributionWgStakingEventsHandler, ), ), ); type StakeId = u64; type SlashId = u64; } impl common::currency::GovernanceCurrency for Runtime { type Currency = pallet_balances::Module; } impl common::MembershipTypes for Runtime { type MemberId = MemberId; type ActorId = ActorId; } impl common::StorageOwnership for Runtime { type ChannelId = ChannelId; type ContentId = ContentId; type DataObjectTypeId = DataObjectTypeId; } impl governance::election::Trait for Runtime { type Event = Event; type CouncilElected = (Council, integration::proposals::CouncilElectedHandler); } impl governance::council::Trait for Runtime { type Event = Event; type CouncilTermEnded = (CouncilElection,); } impl memo::Trait for Runtime { type Event = Event; } parameter_types! { pub const ScreenedMemberMaxInitialBalance: u128 = 5000; } impl membership::Trait for Runtime { type Event = Event; type PaidTermId = u64; type SubscriptionId = u64; type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance; } impl forum::Trait for Runtime { type Event = Event; type MembershipRegistry = integration::forum::ShimMembershipRegistry; type ThreadId = ThreadId; type PostId = PostId; } // The storage working group instance alias. pub type StorageWorkingGroupInstance = working_group::Instance2; // The content working group instance alias. pub type ContentWorkingGroupInstance = working_group::Instance3; // The distribution working group instance alias. pub type DistributionWorkingGroupInstance = working_group::Instance6; // The gateway working group instance alias. pub type GatewayWorkingGroupInstance = working_group::Instance5; // The operation working group alpha instance alias. pub type OperationsWorkingGroupInstanceAlpha = working_group::Instance4; // The operation working group beta instance alias . pub type OperationsWorkingGroupInstanceBeta = working_group::Instance7; // The operation working group gamma instance alias . pub type OperationsWorkingGroupInstanceGamma = working_group::Instance8; parameter_types! { pub const MaxWorkerNumberLimit: u32 = 100; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } impl working_group::Trait for Runtime { type Event = Event; type MaxWorkerNumberLimit = MaxWorkerNumberLimit; } 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 = MembershipOriginValidator; type VoterOriginValidator = CouncilManager; type TotalVotersCounter = CouncilManager; type ProposalId = u32; type StakeHandlerProvider = proposals_engine::DefaultStakeHandlerProvider; type CancellationFee = ProposalCancellationFee; type RejectionFee = ProposalRejectionFee; type TitleMaxLength = ProposalTitleMaxLength; type DescriptionMaxLength = ProposalDescriptionMaxLength; type MaxActiveProposalLimit = ProposalMaxActiveProposalLimit; type DispatchableCallCode = Call; } impl Default for Call { fn default() -> Self { panic!("shouldn't call default for Call"); } } parameter_types! { pub const ProposalMaxPostEditionNumber: u32 = 0; // post update is disabled pub const ProposalMaxThreadInARowNumber: u32 = 100_000; // will not be used pub const ProposalThreadTitleLengthLimit: u32 = 40; pub const ProposalPostLengthLimit: u32 = 1000; } impl proposals_discussion::Trait for Runtime { type Event = Event; type PostAuthorOriginValidator = MembershipOriginValidator; type ThreadId = ThreadId; type PostId = PostId; type MaxPostEditionNumber = ProposalMaxPostEditionNumber; type ThreadTitleLengthLimit = ProposalThreadTitleLengthLimit; type PostLengthLimit = ProposalPostLengthLimit; type MaxThreadInARowNumber = ProposalMaxThreadInARowNumber; } parameter_types! { pub const TextProposalMaxLength: u32 = 5_000; pub const RuntimeUpgradeWasmProposalMaxLength: u32 = 3_000_000; } impl proposals_codex::Trait for Runtime { type MembershipOriginValidator = MembershipOriginValidator; type TextProposalMaxLength = TextProposalMaxLength; type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength; type ProposalEncoder = ExtrinsicProposalEncoder; } parameter_types! { pub const TombstoneDeposit: Balance = 1; // TODO: adjust fee pub const RentByteFee: Balance = 1; // TODO: adjust fee pub const RentDepositOffset: Balance = 0; // no rent deposit pub const SurchargeReward: Balance = 0; // no reward } parameter_types! { pub const MaxDistributionBucketNumberPerFamily: u64 = 500; pub const MaxDistributionBucketFamilyNumber: u64 = 200; pub const DataObjectDeletionPrize: Balance = 1; //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 DistributionBucketId = DistributionBucketId; type DistributionBucketFamilyId = DistributionBucketFamilyId; type ChannelId = ChannelId; type DataObjectDeletionPrize = DataObjectDeletionPrize; type BlacklistSizeLimit = BlacklistSizeLimit; type ModuleId = StorageModuleId; type MemberOriginValidator = MembershipOriginValidator; type StorageBucketsPerBagValueConstraint = StorageBucketsPerBagValueConstraint; type DefaultMemberDynamicBagNumberOfStorageBuckets = DefaultMemberDynamicBagNumberOfStorageBuckets; type DefaultChannelDynamicBagNumberOfStorageBuckets = DefaultChannelDynamicBagNumberOfStorageBuckets; type Randomness = RandomnessCollectiveFlip; type MaxRandomIterationNumber = MaxRandomIterationNumber; type MaxDistributionBucketFamilyNumber = MaxDistributionBucketFamilyNumber; type MaxDistributionBucketNumberPerFamily = MaxDistributionBucketNumberPerFamily; type DistributionBucketsPerBagValueConstraint = DistributionBucketsPerBagValueConstraint; type DistributionBucketOperatorId = DistributionBucketOperatorId; type MaxNumberOfPendingInvitationsPerDistributionBucket = MaxNumberOfPendingInvitationsPerDistributionBucket; type MaxDataObjectSize = MaxDataObjectSize; type ContentId = ContentId; fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult { StorageWorkingGroup::ensure_origin_is_active_leader(origin) } fn ensure_storage_worker_origin(origin: Self::Origin, worker_id: ActorId) -> DispatchResult { StorageWorkingGroup::ensure_worker_signed(origin, &worker_id).map(|_| ()) } fn ensure_storage_worker_exists(worker_id: &ActorId) -> DispatchResult { StorageWorkingGroup::ensure_worker_exists(&worker_id) .map(|_| ()) .map_err(|err| err.into()) } fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult { DistributionWorkingGroup::ensure_origin_is_active_leader(origin) } fn ensure_distribution_worker_origin( origin: Self::Origin, worker_id: ActorId, ) -> DispatchResult { DistributionWorkingGroup::ensure_worker_signed(origin, &worker_id).map(|_| ()) } fn ensure_distribution_worker_exists(worker_id: &ActorId) -> DispatchResult { DistributionWorkingGroup::ensure_worker_exists(&worker_id) .map(|_| ()) .map_err(|err| err.into()) } } /// 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 CouncilElection: election::{Module, Call, Storage, Event, Config}, Council: council::{Module, Call, Storage, Event, Config}, Memo: memo::{Module, Call, Storage, Event}, Members: membership::{Module, Call, Storage, Event, Config}, Forum: forum::{Module, Call, Storage, Event, Config}, Stake: stake::{Module, Call, Storage}, Minting: minting::{Module, Call, Storage}, RecurringRewards: recurring_rewards::{Module, Call, Storage}, Hiring: hiring::{Module, Call, Storage}, Content: content::{Module, Call, Storage, Event, Config}, // --- Proposals ProposalsEngine: proposals_engine::{Module, Call, Storage, Event}, ProposalsDiscussion: proposals_discussion::{Module, Call, Storage, Event}, ProposalsCodex: proposals_codex::{Module, Call, Storage, Config}, Storage: storage::{Module, Call, Storage, Event}, // --- Working groups // reserved for the future use: ForumWorkingGroup: working_group::::{Module, Call, Storage, Config, Event}, StorageWorkingGroup: working_group::::{Module, Call, Storage, Config, Event}, ContentWorkingGroup: working_group::::{Module, Call, Storage, Config, Event}, OperationsWorkingGroupAlpha: working_group::::{Module, Call, Storage, Config, Event}, GatewayWorkingGroup: working_group::::{Module, Call, Storage, Config, Event}, DistributionWorkingGroup: working_group::::{Module, Call, Storage, Config, Event}, OperationsWorkingGroupBeta: working_group::::{Module, Call, Storage, Config, Event}, OperationsWorkingGroupGamma: working_group::::{Module, Call, Storage, Config, Event}, } );