lib.rs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. //! The Joystream Substrate Node runtime.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
  4. #![recursion_limit = "256"]
  5. // srml_staking_reward_curve::build! - substrate macro produces a warning.
  6. // TODO: remove after post-Rome substrate upgrade
  7. #![allow(array_into_iter)]
  8. // Runtime integration tests
  9. mod test;
  10. // Make the WASM binary available.
  11. // This is required only by the node build.
  12. // A dummy wasm_binary.rs will be built for the IDE.
  13. #[cfg(feature = "std")]
  14. include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
  15. mod integration;
  16. use authority_discovery_primitives::{
  17. AuthorityId as EncodedAuthorityId, Signature as EncodedSignature,
  18. };
  19. use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature};
  20. use codec::{Decode, Encode};
  21. use grandpa::fg_primitives;
  22. use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight};
  23. use im_online::sr25519::AuthorityId as ImOnlineId;
  24. use primitives::OpaqueMetadata;
  25. use rstd::prelude::*;
  26. use sr_primitives::curve::PiecewiseLinear;
  27. use sr_primitives::traits::{
  28. BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, StaticLookup, Verify,
  29. };
  30. use sr_primitives::weights::Weight;
  31. use sr_primitives::{
  32. create_runtime_str, generic, impl_opaque_keys, transaction_validity::TransactionValidity,
  33. ApplyResult, MultiSignature,
  34. };
  35. use substrate_client::{
  36. block_builder::api::{self as block_builder_api, CheckInherentsResult, InherentData},
  37. impl_runtime_apis, runtime_api as client_api,
  38. };
  39. use system::offchain::TransactionSubmitter;
  40. #[cfg(feature = "std")]
  41. use version::NativeVersion;
  42. use version::RuntimeVersion;
  43. // A few exports that help ease life for downstream crates.
  44. pub use balances::Call as BalancesCall;
  45. #[cfg(any(feature = "std", test))]
  46. pub use sr_primitives::BuildStorage;
  47. pub use sr_primitives::{Perbill, Permill};
  48. pub use srml_support::{
  49. construct_runtime, parameter_types, traits::Currency, traits::Imbalance, traits::Randomness,
  50. StorageLinkedMap, StorageMap, StorageValue,
  51. };
  52. pub use staking::StakerStatus;
  53. pub use timestamp::Call as TimestampCall;
  54. use integration::proposals::{CouncilManager, ExtrinsicProposalEncoder, MembershipOriginValidator};
  55. pub use proposals_codex::ProposalsConfigParameters;
  56. /// An index to a block.
  57. pub type BlockNumber = u32;
  58. /// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
  59. pub type Signature = MultiSignature;
  60. /// Some way of identifying an account on the chain. We intentionally make it equivalent
  61. /// to the public key of our transaction signing scheme.
  62. pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
  63. /// The type for looking up accounts. We don't expect more than 4 billion of them, but you
  64. /// never know...
  65. pub type AccountIndex = u32;
  66. /// Balance of an account.
  67. pub type Balance = u128;
  68. /// Index of a transaction in the chain.
  69. pub type Index = u32;
  70. /// A hash of some data used by the chain.
  71. pub type Hash = primitives::H256;
  72. /// Digest item type.
  73. pub type DigestItem = generic::DigestItem<Hash>;
  74. /// Moment type
  75. pub type Moment = u64;
  76. /// Credential type
  77. pub type Credential = u64;
  78. /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
  79. /// the specifics of the runtime. They can then be made to be agnostic over specific formats
  80. /// of data like extrinsics, allowing for them to continue syncing the network through upgrades
  81. /// to even the core datastructures.
  82. pub mod opaque {
  83. use super::*;
  84. pub use sr_primitives::OpaqueExtrinsic as UncheckedExtrinsic;
  85. /// Opaque block header type.
  86. pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
  87. /// Opaque block type.
  88. pub type Block = generic::Block<Header, UncheckedExtrinsic>;
  89. /// Opaque block identifier type.
  90. pub type BlockId = generic::BlockId<Block>;
  91. pub type SessionHandlers = (Grandpa, Babe, ImOnline);
  92. impl_opaque_keys! {
  93. pub struct SessionKeys {
  94. pub grandpa: Grandpa,
  95. pub babe: Babe,
  96. pub im_online: ImOnline,
  97. }
  98. }
  99. }
  100. /// This runtime version.
  101. pub const VERSION: RuntimeVersion = RuntimeVersion {
  102. spec_name: create_runtime_str!("joystream-node"),
  103. impl_name: create_runtime_str!("joystream-node"),
  104. authoring_version: 6,
  105. spec_version: 12,
  106. impl_version: 1,
  107. apis: RUNTIME_API_VERSIONS,
  108. };
  109. /// Constants for Babe.
  110. /// Since BABE is probabilistic this is the average expected block time that
  111. /// we are targetting. Blocks will be produced at a minimum duration defined
  112. /// by `SLOT_DURATION`, but some slots will not be allocated to any
  113. /// authority and hence no block will be produced. We expect to have this
  114. /// block time on average following the defined slot duration and the value
  115. /// of `c` configured for BABE (where `1 - c` represents the probability of
  116. /// a slot being empty).
  117. /// This value is only used indirectly to define the unit constants below
  118. /// that are expressed in blocks. The rest of the code should use
  119. /// `SLOT_DURATION` instead (like the timestamp module for calculating the
  120. /// minimum period).
  121. /// <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
  122. pub const MILLISECS_PER_BLOCK: Moment = 6000;
  123. pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000;
  124. pub const SLOT_DURATION: Moment = 6000;
  125. pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES;
  126. pub const EPOCH_DURATION_IN_SLOTS: u64 = {
  127. const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64;
  128. (EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64
  129. };
  130. // These time units are defined in number of blocks.
  131. pub const MINUTES: BlockNumber = 60 / (SECS_PER_BLOCK as BlockNumber);
  132. pub const HOURS: BlockNumber = MINUTES * 60;
  133. pub const DAYS: BlockNumber = HOURS * 24;
  134. // 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks.
  135. pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
  136. /// The version infromation used to identify this runtime when compiled natively.
  137. #[cfg(feature = "std")]
  138. pub fn native_version() -> NativeVersion {
  139. NativeVersion {
  140. runtime_version: VERSION,
  141. can_author_with: Default::default(),
  142. }
  143. }
  144. parameter_types! {
  145. pub const BlockHashCount: BlockNumber = 250;
  146. pub const MaximumBlockWeight: Weight = 1_000_000;
  147. pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
  148. pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
  149. pub const Version: RuntimeVersion = VERSION;
  150. }
  151. impl system::Trait for Runtime {
  152. /// The identifier used to distinguish between accounts.
  153. type AccountId = AccountId;
  154. /// The aggregated dispatch type that is available for extrinsics.
  155. type Call = Call;
  156. /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
  157. type Lookup = Indices;
  158. /// The index type for storing how many extrinsics an account has signed.
  159. type Index = Index;
  160. /// The index type for blocks.
  161. type BlockNumber = BlockNumber;
  162. /// The type for hashing blocks and tries.
  163. type Hash = Hash;
  164. /// The hashing algorithm used.
  165. type Hashing = BlakeTwo256;
  166. /// The header type.
  167. type Header = generic::Header<BlockNumber, BlakeTwo256>;
  168. /// The ubiquitous event type.
  169. type Event = Event;
  170. /// The ubiquitous origin type.
  171. type Origin = Origin;
  172. /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
  173. type BlockHashCount = BlockHashCount;
  174. /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok.
  175. type MaximumBlockWeight = MaximumBlockWeight;
  176. /// Maximum size of all encoded transactions (in bytes) that are allowed in one block.
  177. type MaximumBlockLength = MaximumBlockLength;
  178. /// Portion of the block weight that is available to all normal transactions.
  179. type AvailableBlockRatio = AvailableBlockRatio;
  180. type Version = Version;
  181. }
  182. parameter_types! {
  183. pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS as u64;
  184. pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
  185. }
  186. impl babe::Trait for Runtime {
  187. type EpochDuration = EpochDuration;
  188. type ExpectedBlockTime = ExpectedBlockTime;
  189. type EpochChangeTrigger = babe::ExternalTrigger;
  190. }
  191. impl grandpa::Trait for Runtime {
  192. type Event = Event;
  193. }
  194. impl indices::Trait for Runtime {
  195. /// The type for recording indexing into the account enumeration. If this ever overflows, there
  196. /// will be problems!
  197. type AccountIndex = u32;
  198. /// Use the standard means of resolving an index hint from an id.
  199. type ResolveHint = indices::SimpleResolveHint<Self::AccountId, Self::AccountIndex>;
  200. /// Determine whether an account is dead.
  201. type IsDeadAccount = Balances;
  202. /// The ubiquitous event type.
  203. type Event = Event;
  204. }
  205. parameter_types! {
  206. pub const MinimumPeriod: Moment = SLOT_DURATION / 2;
  207. }
  208. impl timestamp::Trait for Runtime {
  209. /// A timestamp: milliseconds since the unix epoch.
  210. type Moment = Moment;
  211. type OnTimestampSet = Babe;
  212. type MinimumPeriod = MinimumPeriod;
  213. }
  214. parameter_types! {
  215. pub const ExistentialDeposit: u128 = 0;
  216. pub const TransferFee: u128 = 0;
  217. pub const CreationFee: u128 = 0;
  218. pub const TransactionBaseFee: u128 = 1;
  219. pub const TransactionByteFee: u128 = 0;
  220. pub const InitialMembersBalance: u32 = 2000;
  221. }
  222. impl balances::Trait for Runtime {
  223. /// The type for recording an account's balance.
  224. type Balance = Balance;
  225. /// What to do if an account's free balance gets zeroed.
  226. type OnFreeBalanceZero = (Staking, Session);
  227. /// What to do if a new account is created.
  228. type OnNewAccount = (); // Indices; // disable use of Indices feature
  229. /// The ubiquitous event type.
  230. type Event = Event;
  231. type DustRemoval = ();
  232. type TransferPayment = ();
  233. type ExistentialDeposit = ExistentialDeposit;
  234. type TransferFee = TransferFee;
  235. type CreationFee = CreationFee;
  236. }
  237. impl transaction_payment::Trait for Runtime {
  238. type Currency = Balances;
  239. type OnTransactionPayment = ();
  240. type TransactionBaseFee = TransactionBaseFee;
  241. type TransactionByteFee = TransactionByteFee;
  242. type WeightToFee = ();
  243. type FeeMultiplierUpdate = (); // FeeMultiplierUpdateHandler;
  244. }
  245. impl sudo::Trait for Runtime {
  246. type Event = Event;
  247. type Proposal = Call;
  248. }
  249. parameter_types! {
  250. pub const UncleGenerations: BlockNumber = 5;
  251. }
  252. impl authorship::Trait for Runtime {
  253. type FindAuthor = session::FindAccountFromAuthorIndex<Self, Babe>;
  254. type UncleGenerations = UncleGenerations;
  255. type FilterUncle = ();
  256. type EventHandler = Staking;
  257. }
  258. type SessionHandlers = (Grandpa, Babe, ImOnline);
  259. impl_opaque_keys! {
  260. pub struct SessionKeys {
  261. pub grandpa: Grandpa,
  262. pub babe: Babe,
  263. pub im_online: ImOnline,
  264. }
  265. }
  266. // NOTE: `SessionHandler` and `SessionKeys` are co-dependent: One key will be used for each handler.
  267. // The number and order of items in `SessionHandler` *MUST* be the same number and order of keys in
  268. // `SessionKeys`.
  269. // TODO: Introduce some structure to tie these together to make it a bit less of a footgun. This
  270. // should be easy, since OneSessionHandler trait provides the `Key` as an associated type. #2858
  271. parameter_types! {
  272. pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
  273. }
  274. impl session::Trait for Runtime {
  275. type OnSessionEnding = Staking;
  276. type SessionHandler = SessionHandlers;
  277. type ShouldEndSession = Babe;
  278. type Event = Event;
  279. type Keys = SessionKeys;
  280. type ValidatorId = AccountId;
  281. type ValidatorIdOf = staking::StashOf<Self>;
  282. type SelectInitialValidators = Staking;
  283. type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
  284. }
  285. impl session::historical::Trait for Runtime {
  286. type FullIdentification = staking::Exposure<AccountId, Balance>;
  287. type FullIdentificationOf = staking::ExposureOf<Runtime>;
  288. }
  289. srml_staking_reward_curve::build! {
  290. const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
  291. min_inflation: 0_025_000,
  292. max_inflation: 0_100_000,
  293. ideal_stake: 0_500_000,
  294. falloff: 0_050_000,
  295. max_piece_count: 40,
  296. test_precision: 0_005_000,
  297. );
  298. }
  299. parameter_types! {
  300. pub const SessionsPerEra: sr_staking_primitives::SessionIndex = 6;
  301. pub const BondingDuration: staking::EraIndex = 24 * 28;
  302. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
  303. }
  304. impl staking::Trait for Runtime {
  305. type Currency = Balances;
  306. type Time = Timestamp;
  307. type CurrencyToVote = common::currency::CurrencyToVoteHandler;
  308. type RewardRemainder = ();
  309. type Event = Event;
  310. type Slash = (); // where to send the slashed funds.
  311. type Reward = (); // rewards are minted from the void
  312. type SessionsPerEra = SessionsPerEra;
  313. type BondingDuration = BondingDuration;
  314. type SessionInterface = Self;
  315. type RewardCurve = RewardCurve;
  316. }
  317. type SubmitTransaction = TransactionSubmitter<ImOnlineId, Runtime, UncheckedExtrinsic>;
  318. parameter_types! {
  319. pub const SessionDuration: BlockNumber = EPOCH_DURATION_IN_SLOTS as _;
  320. }
  321. impl im_online::Trait for Runtime {
  322. type AuthorityId = ImOnlineId;
  323. type Call = Call;
  324. type Event = Event;
  325. type SubmitTransaction = SubmitTransaction;
  326. type ReportUnresponsiveness = Offences;
  327. type SessionDuration = SessionDuration;
  328. }
  329. impl offences::Trait for Runtime {
  330. type Event = Event;
  331. type IdentificationTuple = session::historical::IdentificationTuple<Self>;
  332. type OnOffenceHandler = Staking;
  333. }
  334. impl authority_discovery::Trait for Runtime {
  335. type AuthorityId = BabeId;
  336. }
  337. parameter_types! {
  338. pub const WindowSize: BlockNumber = 101;
  339. pub const ReportLatency: BlockNumber = 1000;
  340. }
  341. impl finality_tracker::Trait for Runtime {
  342. type OnFinalizationStalled = Grandpa;
  343. type WindowSize = WindowSize;
  344. type ReportLatency = ReportLatency;
  345. }
  346. pub use forum;
  347. pub use governance::election_params::ElectionParameters;
  348. use governance::{council, election};
  349. use membership::members;
  350. use storage::{data_directory, data_object_storage_registry, data_object_type_registry};
  351. pub use versioned_store;
  352. pub use content_working_group as content_wg;
  353. mod migration;
  354. use roles::actors;
  355. use service_discovery::discovery;
  356. /// Alias for ContentId, used in various places.
  357. pub type ContentId = primitives::H256;
  358. impl versioned_store::Trait for Runtime {
  359. type Event = Event;
  360. }
  361. impl versioned_store_permissions::Trait for Runtime {
  362. type Credential = Credential;
  363. type CredentialChecker = (ContentWorkingGroupCredentials, SudoKeyHasAllCredentials);
  364. type CreateClassPermissionsChecker = ContentLeadOrSudoKeyCanCreateClasses;
  365. }
  366. // Credential Checker that gives the sudo key holder all credentials
  367. pub struct SudoKeyHasAllCredentials {}
  368. impl versioned_store_permissions::CredentialChecker<Runtime> for SudoKeyHasAllCredentials {
  369. fn account_has_credential(
  370. account: &AccountId,
  371. _credential: <Runtime as versioned_store_permissions::Trait>::Credential,
  372. ) -> bool {
  373. <sudo::Module<Runtime>>::key() == *account
  374. }
  375. }
  376. parameter_types! {
  377. pub const CurrentLeadCredential: Credential = 0;
  378. pub const AnyActiveCuratorCredential: Credential = 1;
  379. pub const AnyActiveChannelOwnerCredential: Credential = 2;
  380. pub const PrincipalIdMappingStartsAtCredential: Credential = 1000;
  381. }
  382. pub struct ContentWorkingGroupCredentials {}
  383. impl versioned_store_permissions::CredentialChecker<Runtime> for ContentWorkingGroupCredentials {
  384. fn account_has_credential(
  385. account: &AccountId,
  386. credential: <Runtime as versioned_store_permissions::Trait>::Credential,
  387. ) -> bool {
  388. match credential {
  389. // Credentials from 0..999 represents groups or more complex requirements
  390. // Current Lead if set
  391. credential if credential == CurrentLeadCredential::get() => {
  392. match <content_wg::Module<Runtime>>::ensure_lead_is_set() {
  393. Ok((_, lead)) => lead.role_account == *account,
  394. _ => false,
  395. }
  396. }
  397. // Any Active Curator
  398. credential if credential == AnyActiveCuratorCredential::get() => {
  399. // Look for a Curator with a matching role account
  400. for (_principal_id, principal) in <content_wg::PrincipalById<Runtime>>::enumerate()
  401. {
  402. if let content_wg::Principal::Curator(curator_id) = principal {
  403. let curator = <content_wg::CuratorById<Runtime>>::get(curator_id);
  404. if curator.role_account == *account
  405. && curator.stage == content_wg::CuratorRoleStage::Active
  406. {
  407. return true;
  408. }
  409. }
  410. }
  411. false
  412. }
  413. // Any Active Channel Owner
  414. credential if credential == AnyActiveChannelOwnerCredential::get() => {
  415. // Look for a ChannelOwner with a matching role account
  416. for (_principal_id, principal) in <content_wg::PrincipalById<Runtime>>::enumerate()
  417. {
  418. if let content_wg::Principal::ChannelOwner(channel_id) = principal {
  419. let channel = <content_wg::ChannelById<Runtime>>::get(channel_id);
  420. if channel.role_account == *account {
  421. return true; // should we also take publishing_status/curation_status into account ?
  422. }
  423. }
  424. }
  425. false
  426. }
  427. // mapping to workging group principal id
  428. n if n >= PrincipalIdMappingStartsAtCredential::get() => {
  429. <content_wg::Module<Runtime>>::account_has_credential(
  430. account,
  431. n - PrincipalIdMappingStartsAtCredential::get(),
  432. )
  433. }
  434. _ => false,
  435. }
  436. }
  437. }
  438. // Allow sudo key holder permission to create classes
  439. pub struct SudoKeyCanCreateClasses {}
  440. impl versioned_store_permissions::CreateClassPermissionsChecker<Runtime>
  441. for SudoKeyCanCreateClasses
  442. {
  443. fn account_can_create_class_permissions(account: &AccountId) -> bool {
  444. <sudo::Module<Runtime>>::key() == *account
  445. }
  446. }
  447. // Impl this in the permissions module - can't be done here because
  448. // neither CreateClassPermissionsChecker or (X, Y) are local types?
  449. // impl<
  450. // T: versioned_store_permissions::Trait,
  451. // X: versioned_store_permissions::CreateClassPermissionsChecker<T>,
  452. // Y: versioned_store_permissions::CreateClassPermissionsChecker<T>,
  453. // > versioned_store_permissions::CreateClassPermissionsChecker<T> for (X, Y)
  454. // {
  455. // fn account_can_create_class_permissions(account: &T::AccountId) -> bool {
  456. // X::account_can_create_class_permissions(account)
  457. // || Y::account_can_create_class_permissions(account)
  458. // }
  459. // }
  460. pub struct ContentLeadOrSudoKeyCanCreateClasses {}
  461. impl versioned_store_permissions::CreateClassPermissionsChecker<Runtime>
  462. for ContentLeadOrSudoKeyCanCreateClasses
  463. {
  464. fn account_can_create_class_permissions(account: &AccountId) -> bool {
  465. ContentLeadCanCreateClasses::account_can_create_class_permissions(account)
  466. || SudoKeyCanCreateClasses::account_can_create_class_permissions(account)
  467. }
  468. }
  469. // Allow content working group lead to create classes in content directory
  470. pub struct ContentLeadCanCreateClasses {}
  471. impl versioned_store_permissions::CreateClassPermissionsChecker<Runtime>
  472. for ContentLeadCanCreateClasses
  473. {
  474. fn account_can_create_class_permissions(account: &AccountId) -> bool {
  475. // get current lead id
  476. let maybe_current_lead_id = content_wg::CurrentLeadId::<Runtime>::get();
  477. if let Some(lead_id) = maybe_current_lead_id {
  478. let lead = content_wg::LeadById::<Runtime>::get(lead_id);
  479. lead.role_account == *account
  480. } else {
  481. false
  482. }
  483. }
  484. }
  485. impl hiring::Trait for Runtime {
  486. type OpeningId = u64;
  487. type ApplicationId = u64;
  488. type ApplicationDeactivatedHandler = (); // TODO - what needs to happen?
  489. type StakeHandlerProvider = hiring::Module<Self>;
  490. }
  491. impl minting::Trait for Runtime {
  492. type Currency = <Self as common::currency::GovernanceCurrency>::Currency;
  493. type MintId = u64;
  494. }
  495. impl recurringrewards::Trait for Runtime {
  496. type PayoutStatusHandler = (); // TODO - deal with successful and failed payouts
  497. type RecipientId = u64;
  498. type RewardRelationshipId = u64;
  499. }
  500. parameter_types! {
  501. pub const StakePoolId: [u8; 8] = *b"joystake";
  502. }
  503. impl stake::Trait for Runtime {
  504. type Currency = <Self as common::currency::GovernanceCurrency>::Currency;
  505. type StakePoolId = StakePoolId;
  506. type StakingEventsHandler = (
  507. ContentWorkingGroupStakingEventHandler,
  508. crate::integration::proposals::StakingEventsHandler<Self>,
  509. );
  510. type StakeId = u64;
  511. type SlashId = u64;
  512. }
  513. pub struct ContentWorkingGroupStakingEventHandler {}
  514. impl stake::StakingEventsHandler<Runtime> for ContentWorkingGroupStakingEventHandler {
  515. fn unstaked(
  516. stake_id: &<Runtime as stake::Trait>::StakeId,
  517. _unstaked_amount: stake::BalanceOf<Runtime>,
  518. remaining_imbalance: stake::NegativeImbalance<Runtime>,
  519. ) -> stake::NegativeImbalance<Runtime> {
  520. if !hiring::ApplicationIdByStakingId::<Runtime>::exists(stake_id) {
  521. // Stake not related to a staked role managed by the hiring module
  522. return remaining_imbalance;
  523. }
  524. let application_id = hiring::ApplicationIdByStakingId::<Runtime>::get(stake_id);
  525. if !content_wg::CuratorApplicationById::<Runtime>::exists(application_id) {
  526. // Stake not for a Curator
  527. return remaining_imbalance;
  528. }
  529. // Notify the Hiring module - is there a potential re-entrancy bug if
  530. // instant unstaking is occuring?
  531. hiring::Module::<Runtime>::unstaked(*stake_id);
  532. // Only notify working group module if non instantaneous unstaking occured
  533. if content_wg::UnstakerByStakeId::<Runtime>::exists(stake_id) {
  534. content_wg::Module::<Runtime>::unstaked(*stake_id);
  535. }
  536. // Determine member id of the curator
  537. let curator_application =
  538. content_wg::CuratorApplicationById::<Runtime>::get(application_id);
  539. let member_id = curator_application.member_id;
  540. // get member's profile
  541. let member_profile = membership::members::MemberProfile::<Runtime>::get(member_id).unwrap();
  542. // deposit funds to member's root_account
  543. // The application doesn't recorded the original source_account from which staked funds were
  544. // provided, so we don't really have another option at the moment.
  545. <Runtime as stake::Trait>::Currency::resolve_creating(
  546. &member_profile.root_account,
  547. remaining_imbalance,
  548. );
  549. stake::NegativeImbalance::<Runtime>::zero()
  550. }
  551. // Handler for slashing event
  552. fn slashed(
  553. _id: &<Runtime as stake::Trait>::StakeId,
  554. _slash_id: Option<<Runtime as stake::Trait>::SlashId>,
  555. _slashed_amount: stake::BalanceOf<Runtime>,
  556. _remaining_stake: stake::BalanceOf<Runtime>,
  557. remaining_imbalance: stake::NegativeImbalance<Runtime>,
  558. ) -> stake::NegativeImbalance<Runtime> {
  559. // Check if the stake is associated with a hired curator or applicant
  560. // if their stake goes below minimum required for the role,
  561. // they should get deactivated.
  562. // Since we don't currently implement any slash initiation in working group,
  563. // there is nothing to do for now.
  564. // Not interested in transfering the slashed amount anywhere for now,
  565. // so return it to next handler.
  566. remaining_imbalance
  567. }
  568. }
  569. impl content_wg::Trait for Runtime {
  570. type Event = Event;
  571. }
  572. impl common::currency::GovernanceCurrency for Runtime {
  573. type Currency = balances::Module<Self>;
  574. }
  575. impl governance::election::Trait for Runtime {
  576. type Event = Event;
  577. type CouncilElected = (Council, integration::proposals::CouncilElectedHandler);
  578. }
  579. impl governance::council::Trait for Runtime {
  580. type Event = Event;
  581. type CouncilTermEnded = (CouncilElection,);
  582. }
  583. impl memo::Trait for Runtime {
  584. type Event = Event;
  585. }
  586. impl storage::data_object_type_registry::Trait for Runtime {
  587. type Event = Event;
  588. type DataObjectTypeId = u64;
  589. }
  590. impl storage::data_directory::Trait for Runtime {
  591. type Event = Event;
  592. type ContentId = ContentId;
  593. type SchemaId = u64;
  594. type Roles = LookupRoles;
  595. type IsActiveDataObjectType = DataObjectTypeRegistry;
  596. }
  597. impl storage::data_object_storage_registry::Trait for Runtime {
  598. type Event = Event;
  599. type DataObjectStorageRelationshipId = u64;
  600. type Roles = LookupRoles;
  601. type ContentIdExists = DataDirectory;
  602. }
  603. fn random_index(upper_bound: usize) -> usize {
  604. let seed = RandomnessCollectiveFlip::random_seed();
  605. let mut rand: u64 = 0;
  606. for offset in 0..8 {
  607. rand += (seed.as_ref()[offset] as u64) << offset;
  608. }
  609. (rand as usize) % upper_bound
  610. }
  611. pub struct LookupRoles {}
  612. impl roles::traits::Roles<Runtime> for LookupRoles {
  613. fn is_role_account(account_id: &<Runtime as system::Trait>::AccountId) -> bool {
  614. <actors::Module<Runtime>>::is_role_account(account_id)
  615. }
  616. fn account_has_role(
  617. account_id: &<Runtime as system::Trait>::AccountId,
  618. role: actors::Role,
  619. ) -> bool {
  620. <actors::Module<Runtime>>::account_has_role(account_id, role)
  621. }
  622. fn random_account_for_role(
  623. role: actors::Role,
  624. ) -> Result<<Runtime as system::Trait>::AccountId, &'static str> {
  625. let ids = <actors::AccountIdsByRole<Runtime>>::get(role);
  626. let live_ids: Vec<<Runtime as system::Trait>::AccountId> = ids
  627. .into_iter()
  628. .filter(|id| !<discovery::Module<Runtime>>::is_account_info_expired(id))
  629. .collect();
  630. if live_ids.is_empty() {
  631. Err("no staked account found")
  632. } else {
  633. let index = random_index(live_ids.len());
  634. Ok(live_ids[index].clone())
  635. }
  636. }
  637. }
  638. impl members::Trait for Runtime {
  639. type Event = Event;
  640. type MemberId = u64;
  641. type PaidTermId = u64;
  642. type SubscriptionId = u64;
  643. type ActorId = u64;
  644. type InitialMembersBalance = InitialMembersBalance;
  645. }
  646. /*
  647. * Forum module integration
  648. *
  649. * ForumUserRegistry could have been implemented directly on
  650. * the membership module, and likewise ForumUser on Profile,
  651. * however this approach is more loosley coupled.
  652. *
  653. * Further exploration required to decide what the long
  654. * run convention should be.
  655. */
  656. /// Shim registry which will proxy ForumUserRegistry behaviour to the members module
  657. pub struct ShimMembershipRegistry {}
  658. impl forum::ForumUserRegistry<AccountId> for ShimMembershipRegistry {
  659. fn get_forum_user(id: &AccountId) -> Option<forum::ForumUser<AccountId>> {
  660. if members::Module::<Runtime>::is_member_account(id) {
  661. // For now we don't retreive the members profile since it is not used for anything,
  662. // but in the future we may need it to read out more
  663. // information possibly required to construct a
  664. // ForumUser.
  665. // Now convert member profile to a forum user
  666. Some(forum::ForumUser { id: id.clone() })
  667. } else {
  668. None
  669. }
  670. }
  671. }
  672. impl forum::Trait for Runtime {
  673. type Event = Event;
  674. type MembershipRegistry = ShimMembershipRegistry;
  675. }
  676. impl migration::Trait for Runtime {
  677. type Event = Event;
  678. }
  679. impl actors::Trait for Runtime {
  680. type Event = Event;
  681. type OnActorRemoved = HandleActorRemoved;
  682. }
  683. pub struct HandleActorRemoved {}
  684. impl actors::ActorRemoved<Runtime> for HandleActorRemoved {
  685. fn actor_removed(actor: &<Runtime as system::Trait>::AccountId) {
  686. Discovery::remove_account_info(actor);
  687. }
  688. }
  689. impl discovery::Trait for Runtime {
  690. type Event = Event;
  691. type Roles = LookupRoles;
  692. }
  693. parameter_types! {
  694. pub const ProposalCancellationFee: u64 = 5;
  695. pub const ProposalRejectionFee: u64 = 3;
  696. pub const ProposalTitleMaxLength: u32 = 40;
  697. pub const ProposalDescriptionMaxLength: u32 = 3000;
  698. pub const ProposalMaxActiveProposalLimit: u32 = 5;
  699. }
  700. impl proposals_engine::Trait for Runtime {
  701. type Event = Event;
  702. type ProposerOriginValidator = MembershipOriginValidator<Self>;
  703. type VoterOriginValidator = CouncilManager<Self>;
  704. type TotalVotersCounter = CouncilManager<Self>;
  705. type ProposalId = u32;
  706. type StakeHandlerProvider = proposals_engine::DefaultStakeHandlerProvider;
  707. type CancellationFee = ProposalCancellationFee;
  708. type RejectionFee = ProposalRejectionFee;
  709. type TitleMaxLength = ProposalTitleMaxLength;
  710. type DescriptionMaxLength = ProposalDescriptionMaxLength;
  711. type MaxActiveProposalLimit = ProposalMaxActiveProposalLimit;
  712. type DispatchableCallCode = Call;
  713. }
  714. impl Default for Call {
  715. fn default() -> Self {
  716. panic!("shouldn't call default for Call");
  717. }
  718. }
  719. parameter_types! {
  720. pub const ProposalMaxPostEditionNumber: u32 = 0; // post update is disabled
  721. pub const ProposalMaxThreadInARowNumber: u32 = 100_000; // will not be used
  722. pub const ProposalThreadTitleLengthLimit: u32 = 40;
  723. pub const ProposalPostLengthLimit: u32 = 1000;
  724. }
  725. impl proposals_discussion::Trait for Runtime {
  726. type Event = Event;
  727. type PostAuthorOriginValidator = MembershipOriginValidator<Self>;
  728. type ThreadId = u32;
  729. type PostId = u32;
  730. type MaxPostEditionNumber = ProposalMaxPostEditionNumber;
  731. type ThreadTitleLengthLimit = ProposalThreadTitleLengthLimit;
  732. type PostLengthLimit = ProposalPostLengthLimit;
  733. type MaxThreadInARowNumber = ProposalMaxThreadInARowNumber;
  734. }
  735. parameter_types! {
  736. pub const TextProposalMaxLength: u32 = 5_000;
  737. pub const RuntimeUpgradeWasmProposalMaxLength: u32 = 2_000_000;
  738. }
  739. impl proposals_codex::Trait for Runtime {
  740. type MembershipOriginValidator = MembershipOriginValidator<Self>;
  741. type TextProposalMaxLength = TextProposalMaxLength;
  742. type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength;
  743. type ProposalEncoder = ExtrinsicProposalEncoder;
  744. }
  745. construct_runtime!(
  746. pub enum Runtime where
  747. Block = Block,
  748. NodeBlock = opaque::Block,
  749. UncheckedExtrinsic = UncheckedExtrinsic
  750. {
  751. // Substrate
  752. System: system::{Module, Call, Storage, Config, Event},
  753. Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)},
  754. Timestamp: timestamp::{Module, Call, Storage, Inherent},
  755. Authorship: authorship::{Module, Call, Storage, Inherent},
  756. Indices: indices,
  757. Balances: balances,
  758. TransactionPayment: transaction_payment::{Module, Storage},
  759. Staking: staking::{default, OfflineWorker},
  760. Session: session::{Module, Call, Storage, Event, Config<T>},
  761. FinalityTracker: finality_tracker::{Module, Call, Inherent},
  762. Grandpa: grandpa::{Module, Call, Storage, Config, Event},
  763. ImOnline: im_online::{Module, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
  764. AuthorityDiscovery: authority_discovery::{Module, Call, Config<T>},
  765. Offences: offences::{Module, Call, Storage, Event},
  766. RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
  767. Sudo: sudo,
  768. // Joystream
  769. CouncilElection: election::{Module, Call, Storage, Event<T>, Config<T>},
  770. Council: council::{Module, Call, Storage, Event<T>, Config<T>},
  771. Memo: memo::{Module, Call, Storage, Event<T>},
  772. Members: members::{Module, Call, Storage, Event<T>, Config<T>},
  773. Forum: forum::{Module, Call, Storage, Event<T>, Config<T>},
  774. Migration: migration::{Module, Call, Storage, Event<T>},
  775. Actors: actors::{Module, Call, Storage, Event<T>, Config},
  776. DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
  777. DataDirectory: data_directory::{Module, Call, Storage, Event<T>},
  778. DataObjectStorageRegistry: data_object_storage_registry::{Module, Call, Storage, Event<T>, Config<T>},
  779. Discovery: discovery::{Module, Call, Storage, Event<T>},
  780. VersionedStore: versioned_store::{Module, Call, Storage, Event<T>, Config},
  781. VersionedStorePermissions: versioned_store_permissions::{Module, Call, Storage},
  782. Stake: stake::{Module, Call, Storage},
  783. Minting: minting::{Module, Call, Storage},
  784. RecurringRewards: recurringrewards::{Module, Call, Storage},
  785. Hiring: hiring::{Module, Call, Storage},
  786. ContentWorkingGroup: content_wg::{Module, Call, Storage, Event<T>, Config<T>},
  787. // --- Proposals
  788. ProposalsEngine: proposals_engine::{Module, Call, Storage, Event<T>},
  789. ProposalsDiscussion: proposals_discussion::{Module, Call, Storage, Event<T>},
  790. ProposalsCodex: proposals_codex::{Module, Call, Storage, Error, Config<T>},
  791. // ---
  792. }
  793. );
  794. /// The address format for describing accounts.
  795. pub type Address = <Indices as StaticLookup>::Source;
  796. /// Block header type as expected by this runtime.
  797. pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
  798. /// Block type as expected by this runtime.
  799. pub type Block = generic::Block<Header, UncheckedExtrinsic>;
  800. /// A Block signed with a Justification
  801. pub type SignedBlock = generic::SignedBlock<Block>;
  802. /// BlockId type as expected by this runtime.
  803. pub type BlockId = generic::BlockId<Block>;
  804. /// The SignedExtension to the basic transaction logic.
  805. pub type SignedExtra = (
  806. system::CheckVersion<Runtime>,
  807. system::CheckGenesis<Runtime>,
  808. system::CheckEra<Runtime>,
  809. system::CheckNonce<Runtime>,
  810. system::CheckWeight<Runtime>,
  811. transaction_payment::ChargeTransactionPayment<Runtime>,
  812. );
  813. /// Unchecked extrinsic type as expected by this runtime.
  814. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
  815. /// Extrinsic type that has already been checked.
  816. pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
  817. /// Executive: handles dispatch to the various modules.
  818. pub type Executive =
  819. executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;
  820. impl_runtime_apis! {
  821. impl client_api::Core<Block> for Runtime {
  822. fn version() -> RuntimeVersion {
  823. VERSION
  824. }
  825. fn execute_block(block: Block) {
  826. Executive::execute_block(block)
  827. }
  828. fn initialize_block(header: &<Block as BlockT>::Header) {
  829. Executive::initialize_block(header)
  830. }
  831. }
  832. impl client_api::Metadata<Block> for Runtime {
  833. fn metadata() -> OpaqueMetadata {
  834. Runtime::metadata().into()
  835. }
  836. }
  837. impl block_builder_api::BlockBuilder<Block> for Runtime {
  838. fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult {
  839. Executive::apply_extrinsic(extrinsic)
  840. }
  841. fn finalize_block() -> <Block as BlockT>::Header {
  842. Executive::finalize_block()
  843. }
  844. fn inherent_extrinsics(data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
  845. data.create_extrinsics()
  846. }
  847. fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult {
  848. data.check_extrinsics(&block)
  849. }
  850. fn random_seed() -> <Block as BlockT>::Hash {
  851. RandomnessCollectiveFlip::random_seed()
  852. }
  853. }
  854. impl client_api::TaggedTransactionQueue<Block> for Runtime {
  855. fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
  856. Executive::validate_transaction(tx)
  857. }
  858. }
  859. impl offchain_primitives::OffchainWorkerApi<Block> for Runtime {
  860. fn offchain_worker(number: NumberFor<Block>) {
  861. Executive::offchain_worker(number)
  862. }
  863. }
  864. impl fg_primitives::GrandpaApi<Block> for Runtime {
  865. fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> {
  866. Grandpa::grandpa_authorities()
  867. }
  868. }
  869. impl babe_primitives::BabeApi<Block> for Runtime {
  870. fn configuration() -> babe_primitives::BabeConfiguration {
  871. // The choice of `c` parameter (where `1 - c` represents the
  872. // probability of a slot being empty), is done in accordance to the
  873. // slot duration and expected target block time, for safely
  874. // resisting network delays of maximum two seconds.
  875. // <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
  876. babe_primitives::BabeConfiguration {
  877. slot_duration: Babe::slot_duration(),
  878. epoch_length: EpochDuration::get(),
  879. c: PRIMARY_PROBABILITY,
  880. genesis_authorities: Babe::authorities(),
  881. randomness: Babe::randomness(),
  882. secondary_slots: true,
  883. }
  884. }
  885. }
  886. impl authority_discovery_primitives::AuthorityDiscoveryApi<Block> for Runtime {
  887. fn authorities() -> Vec<EncodedAuthorityId> {
  888. AuthorityDiscovery::authorities().into_iter()
  889. .map(|id| id.encode())
  890. .map(EncodedAuthorityId)
  891. .collect()
  892. }
  893. fn sign(payload: &Vec<u8>) -> Option<(EncodedSignature, EncodedAuthorityId)> {
  894. AuthorityDiscovery::sign(payload).map(|(sig, id)| {
  895. (EncodedSignature(sig.encode()), EncodedAuthorityId(id.encode()))
  896. })
  897. }
  898. fn verify(payload: &Vec<u8>, signature: &EncodedSignature, authority_id: &EncodedAuthorityId) -> bool {
  899. let signature = match BabeSignature::decode(&mut &signature.0[..]) {
  900. Ok(s) => s,
  901. _ => return false,
  902. };
  903. let authority_id = match BabeId::decode(&mut &authority_id.0[..]) {
  904. Ok(id) => id,
  905. _ => return false,
  906. };
  907. AuthorityDiscovery::verify(payload, signature, authority_id)
  908. }
  909. }
  910. impl system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
  911. fn account_nonce(account: AccountId) -> Index {
  912. System::account_nonce(account)
  913. }
  914. }
  915. impl substrate_session::SessionKeys<Block> for Runtime {
  916. fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
  917. let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string"));
  918. opaque::SessionKeys::generate(seed)
  919. }
  920. }
  921. }