lib.rs 35 KB

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