lib.rs 38 KB

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