lib.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. //! # Proposals codex module
  2. //! Proposals `codex` module for the Joystream platform. Version 2.
  3. //! Component of the proposals system. It contains preset proposal types.
  4. //!
  5. //! ## Overview
  6. //!
  7. //! The proposals codex module serves as a facade and entry point of the proposals system. It uses
  8. //! proposals `engine` module to maintain a lifecycle of the proposal and to execute proposals.
  9. //! During the proposal creation, `codex` also create a discussion thread using the `discussion`
  10. //! proposals module. `Codex` uses predefined parameters (eg.:`voting_period`) for each proposal and
  11. //! encodes extrinsic calls from dependency modules in order to create proposals inside the `engine`
  12. //! module. For each proposal, [its crucial details](./enum.ProposalDetails.html) are saved to the
  13. //! `ProposalDetailsByProposalId` map.
  14. //!
  15. //! ### Supported extrinsics (proposal types)
  16. //! - [create_text_proposal](./struct.Module.html#method.create_text_proposal)
  17. //! - [create_runtime_upgrade_proposal](./struct.Module.html#method.create_runtime_upgrade_proposal)
  18. //! - [create_set_election_parameters_proposal](./struct.Module.html#method.create_set_election_parameters_proposal)
  19. //! - [create_set_content_working_group_mint_capacity_proposal](./struct.Module.html#method.create_set_content_working_group_mint_capacity_proposal)
  20. //! - [create_spending_proposal](./struct.Module.html#method.create_spending_proposal)
  21. //! - [create_set_lead_proposal](./struct.Module.html#method.create_set_lead_proposal)
  22. //! - [create_set_validator_count_proposal](./struct.Module.html#method.create_set_validator_count_proposal)
  23. //!
  24. //! ### Proposal implementations of this module
  25. //! - execute_text_proposal - prints the proposal to the log
  26. //! - execute_runtime_upgrade_proposal - sets the runtime code
  27. //!
  28. //! ### Dependencies:
  29. //! - [proposals engine](../substrate_proposals_engine_module/index.html)
  30. //! - [proposals discussion](../substrate_proposals_discussion_module/index.html)
  31. //! - [membership](../substrate_membership_module/index.html)
  32. //! - [governance](../substrate_governance_module/index.html)
  33. //! - [content_working_group](../substrate_content_working_group_module/index.html)
  34. //!
  35. //! ### Notes
  36. //! The module uses [ProposalEncoder](./trait.ProposalEncoder.html) to encode the proposal using
  37. //! its details. Encoded byte vector is passed to the _proposals engine_ as serialized executable code.
  38. // Clippy linter warning. TODO: remove after the Constaninople release
  39. #![allow(clippy::type_complexity)]
  40. // disable it because of possible frontend API break
  41. // Clippy linter warning. TODO: refactor "this function has too many argument"
  42. #![allow(clippy::too_many_arguments)] // disable it because of possible API break
  43. // Ensure we're `no_std` when compiling for Wasm.
  44. #![cfg_attr(not(feature = "std"), no_std)]
  45. // Do not delete! Cannot be uncommented by default, because of Parity decl_module! issue.
  46. // #![warn(missing_docs)]
  47. mod proposal_types;
  48. #[cfg(test)]
  49. mod tests;
  50. use common::origin::ActorOriginValidator;
  51. use governance::election_params::ElectionParameters;
  52. use proposal_engine::ProposalParameters;
  53. use rstd::clone::Clone;
  54. use rstd::prelude::*;
  55. use rstd::str::from_utf8;
  56. use rstd::vec::Vec;
  57. use sr_primitives::traits::Zero;
  58. use srml_support::dispatch::DispatchResult;
  59. use srml_support::traits::{Currency, Get};
  60. use srml_support::{decl_error, decl_module, decl_storage, ensure, print};
  61. use system::ensure_root;
  62. pub use crate::proposal_types::ProposalsConfigParameters;
  63. pub use proposal_types::{ProposalDetails, ProposalDetailsOf, ProposalEncoder};
  64. // 'Set working group mint capacity' proposal limit
  65. const CONTENT_WORKING_GROUP_MINT_CAPACITY_MAX_VALUE: u32 = 1_000_000;
  66. // Max allowed value for 'spending' proposal
  67. const MAX_SPENDING_PROPOSAL_VALUE: u32 = 2_000_000_u32;
  68. // Max validator count for the 'set validator count' proposal
  69. const MAX_VALIDATOR_COUNT: u32 = 100;
  70. // council_size min value for the 'set election parameters' proposal
  71. const ELECTION_PARAMETERS_COUNCIL_SIZE_MIN_VALUE: u32 = 4;
  72. // council_size max value for the 'set election parameters' proposal
  73. const ELECTION_PARAMETERS_COUNCIL_SIZE_MAX_VALUE: u32 = 20;
  74. // candidacy_limit min value for the 'set election parameters' proposal
  75. const ELECTION_PARAMETERS_CANDIDACY_LIMIT_MIN_VALUE: u32 = 25;
  76. // candidacy_limit max value for the 'set election parameters' proposal
  77. const ELECTION_PARAMETERS_CANDIDACY_LIMIT_MAX_VALUE: u32 = 100;
  78. // min_voting_stake min value for the 'set election parameters' proposal
  79. const ELECTION_PARAMETERS_MIN_STAKE_MIN_VALUE: u32 = 1;
  80. // min_voting_stake max value for the 'set election parameters' proposal
  81. const ELECTION_PARAMETERS_MIN_STAKE_MAX_VALUE: u32 = 100_000_u32;
  82. // new_term_duration min value for the 'set election parameters' proposal
  83. const ELECTION_PARAMETERS_NEW_TERM_DURATION_MIN_VALUE: u32 = 14400;
  84. // new_term_duration max value for the 'set election parameters' proposal
  85. const ELECTION_PARAMETERS_NEW_TERM_DURATION_MAX_VALUE: u32 = 432_000;
  86. // revealing_period min value for the 'set election parameters' proposal
  87. const ELECTION_PARAMETERS_REVEALING_PERIOD_MIN_VALUE: u32 = 14400;
  88. // revealing_period max value for the 'set election parameters' proposal
  89. const ELECTION_PARAMETERS_REVEALING_PERIOD_MAX_VALUE: u32 = 28800;
  90. // voting_period min value for the 'set election parameters' proposal
  91. const ELECTION_PARAMETERS_VOTING_PERIOD_MIN_VALUE: u32 = 14400;
  92. // voting_period max value for the 'set election parameters' proposal
  93. const ELECTION_PARAMETERS_VOTING_PERIOD_MAX_VALUE: u32 = 28800;
  94. // announcing_period min value for the 'set election parameters' proposal
  95. const ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MIN_VALUE: u32 = 14400;
  96. // announcing_period max value for the 'set election parameters' proposal
  97. const ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MAX_VALUE: u32 = 43200;
  98. // min_council_stake min value for the 'set election parameters' proposal
  99. const ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MIN_VALUE: u32 = 1;
  100. // min_council_stake max value for the 'set election parameters' proposal
  101. const ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MAX_VALUE: u32 = 100_000_u32;
  102. /// 'Proposals codex' substrate module Trait
  103. pub trait Trait:
  104. system::Trait
  105. + proposal_engine::Trait
  106. + proposal_discussion::Trait
  107. + membership::members::Trait
  108. + governance::election::Trait
  109. + content_working_group::Trait
  110. + staking::Trait
  111. {
  112. /// Defines max allowed text proposal length.
  113. type TextProposalMaxLength: Get<u32>;
  114. /// Defines max wasm code length of the runtime upgrade proposal.
  115. type RuntimeUpgradeWasmProposalMaxLength: Get<u32>;
  116. /// Validates member id and origin combination
  117. type MembershipOriginValidator: ActorOriginValidator<
  118. Self::Origin,
  119. MemberId<Self>,
  120. Self::AccountId,
  121. >;
  122. /// Encodes the proposal usint its details
  123. type ProposalEncoder: ProposalEncoder<Self>;
  124. }
  125. /// Balance alias for `stake` module
  126. pub type BalanceOf<T> =
  127. <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
  128. /// Currency alias for `stake` module
  129. pub type CurrencyOf<T> = <T as stake::Trait>::Currency;
  130. /// Balance alias for GovernanceCurrency from `common` module. TODO: replace with BalanceOf
  131. pub type BalanceOfGovernanceCurrency<T> =
  132. <<T as common::currency::GovernanceCurrency>::Currency as Currency<
  133. <T as system::Trait>::AccountId,
  134. >>::Balance;
  135. /// Balance alias for token mint balance from `token mint` module. TODO: replace with BalanceOf
  136. pub type BalanceOfMint<T> =
  137. <<T as mint::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
  138. /// Negative imbalance alias for staking
  139. pub type NegativeImbalance<T> =
  140. <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
  141. type MemberId<T> = <T as membership::members::Trait>::MemberId;
  142. decl_error! {
  143. /// Codex module predefined errors
  144. pub enum Error {
  145. /// The size of the provided text for text proposal exceeded the limit
  146. TextProposalSizeExceeded,
  147. /// Provided text for text proposal is empty
  148. TextProposalIsEmpty,
  149. /// The size of the provided WASM code for the runtime upgrade proposal exceeded the limit
  150. RuntimeProposalSizeExceeded,
  151. /// Provided WASM code for the runtime upgrade proposal is empty
  152. RuntimeProposalIsEmpty,
  153. /// Invalid balance value for the spending proposal
  154. InvalidSpendingProposalBalance,
  155. /// Invalid validator count for the 'set validator count' proposal
  156. InvalidValidatorCount,
  157. /// Require root origin in extrinsics
  158. RequireRootOrigin,
  159. /// Invalid council election parameter - council_size
  160. InvalidCouncilElectionParameterCouncilSize,
  161. /// Invalid council election parameter - candidacy-limit
  162. InvalidCouncilElectionParameterCandidacyLimit,
  163. /// Invalid council election parameter - min-voting_stake
  164. InvalidCouncilElectionParameterMinVotingStake,
  165. /// Invalid council election parameter - new_term_duration
  166. InvalidCouncilElectionParameterNewTermDuration,
  167. /// Invalid council election parameter - min_council_stake
  168. InvalidCouncilElectionParameterMinCouncilStake,
  169. /// Invalid council election parameter - revealing_period
  170. InvalidCouncilElectionParameterRevealingPeriod,
  171. /// Invalid council election parameter - voting_period
  172. InvalidCouncilElectionParameterVotingPeriod,
  173. /// Invalid council election parameter - announcing_period
  174. InvalidCouncilElectionParameterAnnouncingPeriod,
  175. /// Invalid working group mint capacity parameter
  176. InvalidStorageWorkingGroupMintCapacity,
  177. /// Invalid 'set lead proposal' parameter - proposed lead cannot be a councilor
  178. InvalidSetLeadParameterCannotBeCouncilor
  179. }
  180. }
  181. impl From<system::Error> for Error {
  182. fn from(error: system::Error) -> Self {
  183. match error {
  184. system::Error::Other(msg) => Error::Other(msg),
  185. system::Error::RequireRootOrigin => Error::RequireRootOrigin,
  186. _ => Error::Other(error.into()),
  187. }
  188. }
  189. }
  190. impl From<proposal_engine::Error> for Error {
  191. fn from(error: proposal_engine::Error) -> Self {
  192. match error {
  193. proposal_engine::Error::Other(msg) => Error::Other(msg),
  194. proposal_engine::Error::RequireRootOrigin => Error::RequireRootOrigin,
  195. _ => Error::Other(error.into()),
  196. }
  197. }
  198. }
  199. impl From<proposal_discussion::Error> for Error {
  200. fn from(error: proposal_discussion::Error) -> Self {
  201. match error {
  202. proposal_discussion::Error::Other(msg) => Error::Other(msg),
  203. proposal_discussion::Error::RequireRootOrigin => Error::RequireRootOrigin,
  204. _ => Error::Other(error.into()),
  205. }
  206. }
  207. }
  208. // Storage for the proposals codex module
  209. decl_storage! {
  210. pub trait Store for Module<T: Trait> as ProposalCodex{
  211. /// Map proposal id to its discussion thread id
  212. pub ThreadIdByProposalId get(fn thread_id_by_proposal_id):
  213. map T::ProposalId => T::ThreadId;
  214. /// Map proposal id to proposal details
  215. pub ProposalDetailsByProposalId get(fn proposal_details_by_proposal_id):
  216. map T::ProposalId => ProposalDetails<
  217. BalanceOfMint<T>,
  218. BalanceOfGovernanceCurrency<T>,
  219. T::BlockNumber,
  220. T::AccountId,
  221. T::MemberId
  222. >;
  223. /// Voting period for the 'set validator count' proposal
  224. pub SetValidatorCountProposalVotingPeriod get(set_validator_count_proposal_voting_period)
  225. config(): T::BlockNumber;
  226. /// Grace period for the 'set validator count' proposal
  227. pub SetValidatorCountProposalGracePeriod get(set_validator_count_proposal_grace_period)
  228. config(): T::BlockNumber;
  229. /// Voting period for the 'runtime upgrade' proposal
  230. pub RuntimeUpgradeProposalVotingPeriod get(runtime_upgrade_proposal_voting_period)
  231. config(): T::BlockNumber;
  232. /// Grace period for the 'runtime upgrade' proposal
  233. pub RuntimeUpgradeProposalGracePeriod get(runtime_upgrade_proposal_grace_period)
  234. config(): T::BlockNumber;
  235. /// Voting period for the 'set election parameters' proposal
  236. pub SetElectionParametersProposalVotingPeriod get(set_election_parameters_proposal_voting_period)
  237. config(): T::BlockNumber;
  238. /// Grace period for the 'set election parameters' proposal
  239. pub SetElectionParametersProposalGracePeriod get(set_election_parameters_proposal_grace_period)
  240. config(): T::BlockNumber;
  241. /// Voting period for the 'text' proposal
  242. pub TextProposalVotingPeriod get(text_proposal_voting_period) config(): T::BlockNumber;
  243. /// Grace period for the 'text' proposal
  244. pub TextProposalGracePeriod get(text_proposal_grace_period) config(): T::BlockNumber;
  245. /// Voting period for the 'set content working group mint capacity' proposal
  246. pub SetContentWorkingGroupMintCapacityProposalVotingPeriod get(set_content_working_group_mint_capacity_proposal_voting_period)
  247. config(): T::BlockNumber;
  248. /// Grace period for the 'set content working group mint capacity' proposal
  249. pub SetContentWorkingGroupMintCapacityProposalGracePeriod get(set_content_working_group_mint_capacity_proposal_grace_period)
  250. config(): T::BlockNumber;
  251. /// Voting period for the 'set lead' proposal
  252. pub SetLeadProposalVotingPeriod get(set_lead_proposal_voting_period)
  253. config(): T::BlockNumber;
  254. /// Grace period for the 'set lead' proposal
  255. pub SetLeadProposalGracePeriod get(set_lead_proposal_grace_period)
  256. config(): T::BlockNumber;
  257. /// Voting period for the 'spending' proposal
  258. pub SpendingProposalVotingPeriod get(spending_proposal_voting_period) config(): T::BlockNumber;
  259. /// Grace period for the 'spending' proposal
  260. pub SpendingProposalGracePeriod get(spending_proposal_grace_period) config(): T::BlockNumber;
  261. }
  262. }
  263. decl_module! {
  264. /// Proposal codex substrate module Call
  265. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  266. /// Predefined errors
  267. type Error = Error;
  268. /// Exports max allowed text proposal length const.
  269. const TextProposalMaxLength: u32 = T::TextProposalMaxLength::get();
  270. /// Exports max wasm code length of the runtime upgrade proposal const.
  271. const RuntimeUpgradeWasmProposalMaxLength: u32 = T::RuntimeUpgradeWasmProposalMaxLength::get();
  272. /// Create 'Text (signal)' proposal type.
  273. pub fn create_text_proposal(
  274. origin,
  275. member_id: MemberId<T>,
  276. title: Vec<u8>,
  277. description: Vec<u8>,
  278. stake_balance: Option<BalanceOf<T>>,
  279. text: Vec<u8>,
  280. ) {
  281. ensure!(!text.is_empty(), Error::TextProposalIsEmpty);
  282. ensure!(text.len() as u32 <= T::TextProposalMaxLength::get(),
  283. Error::TextProposalSizeExceeded);
  284. let proposal_parameters = proposal_types::parameters::text_proposal::<T>();
  285. let proposal_details = ProposalDetails::<BalanceOfMint<T>, BalanceOfGovernanceCurrency<T>, T::BlockNumber, T::AccountId, MemberId<T>>::Text(text);
  286. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  287. Self::create_proposal(
  288. origin,
  289. member_id,
  290. title,
  291. description,
  292. stake_balance,
  293. proposal_code,
  294. proposal_parameters,
  295. proposal_details,
  296. )?;
  297. }
  298. /// Create 'Runtime upgrade' proposal type. Runtime upgrade can be initiated only by
  299. /// members from the hardcoded list `RuntimeUpgradeProposalAllowedProposers`
  300. pub fn create_runtime_upgrade_proposal(
  301. origin,
  302. member_id: MemberId<T>,
  303. title: Vec<u8>,
  304. description: Vec<u8>,
  305. stake_balance: Option<BalanceOf<T>>,
  306. wasm: Vec<u8>,
  307. ) {
  308. ensure!(!wasm.is_empty(), Error::RuntimeProposalIsEmpty);
  309. ensure!(wasm.len() as u32 <= T::RuntimeUpgradeWasmProposalMaxLength::get(),
  310. Error::RuntimeProposalSizeExceeded);
  311. let proposal_parameters = proposal_types::parameters::runtime_upgrade_proposal::<T>();
  312. let proposal_details = ProposalDetails::RuntimeUpgrade(wasm);
  313. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  314. Self::create_proposal(
  315. origin,
  316. member_id,
  317. title,
  318. description,
  319. stake_balance,
  320. proposal_code,
  321. proposal_parameters,
  322. proposal_details,
  323. )?;
  324. }
  325. /// Create 'Set election parameters' proposal type. This proposal uses `set_election_parameters()`
  326. /// extrinsic from the `governance::election module`.
  327. pub fn create_set_election_parameters_proposal(
  328. origin,
  329. member_id: MemberId<T>,
  330. title: Vec<u8>,
  331. description: Vec<u8>,
  332. stake_balance: Option<BalanceOf<T>>,
  333. election_parameters: ElectionParameters<BalanceOfGovernanceCurrency<T>, T::BlockNumber>,
  334. ) {
  335. election_parameters.ensure_valid()?;
  336. Self::ensure_council_election_parameters_valid(&election_parameters)?;
  337. let proposal_details = ProposalDetails::SetElectionParameters(election_parameters);
  338. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  339. let proposal_parameters =
  340. proposal_types::parameters::set_election_parameters_proposal::<T>();
  341. Self::create_proposal(
  342. origin,
  343. member_id,
  344. title,
  345. description,
  346. stake_balance,
  347. proposal_code,
  348. proposal_parameters,
  349. proposal_details,
  350. )?;
  351. }
  352. /// Create 'Set content working group mint capacity' proposal type.
  353. /// This proposal uses `set_mint_capacity()` extrinsic from the `content-working-group` module.
  354. pub fn create_set_content_working_group_mint_capacity_proposal(
  355. origin,
  356. member_id: MemberId<T>,
  357. title: Vec<u8>,
  358. description: Vec<u8>,
  359. stake_balance: Option<BalanceOf<T>>,
  360. mint_balance: BalanceOfMint<T>,
  361. ) {
  362. ensure!(
  363. mint_balance <= <BalanceOfMint<T>>::from(CONTENT_WORKING_GROUP_MINT_CAPACITY_MAX_VALUE),
  364. Error::InvalidStorageWorkingGroupMintCapacity
  365. );
  366. let proposal_parameters =
  367. proposal_types::parameters::set_content_working_group_mint_capacity_proposal::<T>();
  368. let proposal_details = ProposalDetails::SetContentWorkingGroupMintCapacity(mint_balance);
  369. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  370. Self::create_proposal(
  371. origin,
  372. member_id,
  373. title,
  374. description,
  375. stake_balance,
  376. proposal_code,
  377. proposal_parameters,
  378. proposal_details,
  379. )?;
  380. }
  381. /// Create 'Spending' proposal type.
  382. /// This proposal uses `spend_from_council_mint()` extrinsic from the `governance::council` module.
  383. pub fn create_spending_proposal(
  384. origin,
  385. member_id: MemberId<T>,
  386. title: Vec<u8>,
  387. description: Vec<u8>,
  388. stake_balance: Option<BalanceOf<T>>,
  389. balance: BalanceOfMint<T>,
  390. destination: T::AccountId,
  391. ) {
  392. ensure!(balance != BalanceOfMint::<T>::zero(), Error::InvalidSpendingProposalBalance);
  393. ensure!(
  394. balance <= <BalanceOfMint<T>>::from(MAX_SPENDING_PROPOSAL_VALUE),
  395. Error::InvalidSpendingProposalBalance
  396. );
  397. let proposal_parameters =
  398. proposal_types::parameters::spending_proposal::<T>();
  399. let proposal_details = ProposalDetails::Spending(balance, destination);
  400. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  401. Self::create_proposal(
  402. origin,
  403. member_id,
  404. title,
  405. description,
  406. stake_balance,
  407. proposal_code,
  408. proposal_parameters,
  409. proposal_details,
  410. )?;
  411. }
  412. /// Create 'Set lead' proposal type.
  413. /// This proposal uses `replace_lead()` extrinsic from the `content_working_group` module.
  414. pub fn create_set_lead_proposal(
  415. origin,
  416. member_id: MemberId<T>,
  417. title: Vec<u8>,
  418. description: Vec<u8>,
  419. stake_balance: Option<BalanceOf<T>>,
  420. new_lead: Option<(T::MemberId, T::AccountId)>
  421. ) {
  422. if let Some(lead) = new_lead.clone() {
  423. let account_id = lead.1;
  424. ensure!(
  425. !<governance::council::Module<T>>::is_councilor(&account_id),
  426. Error::InvalidSetLeadParameterCannotBeCouncilor
  427. );
  428. }
  429. let proposal_parameters =
  430. proposal_types::parameters::set_lead_proposal::<T>();
  431. let proposal_details = ProposalDetails::SetLead(new_lead);
  432. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  433. Self::create_proposal(
  434. origin,
  435. member_id,
  436. title,
  437. description,
  438. stake_balance,
  439. proposal_code,
  440. proposal_parameters,
  441. proposal_details,
  442. )?;
  443. }
  444. /// Create 'Evict storage provider' proposal type.
  445. /// This proposal uses `set_validator_count()` extrinsic from the Substrate `staking` module.
  446. pub fn create_set_validator_count_proposal(
  447. origin,
  448. member_id: MemberId<T>,
  449. title: Vec<u8>,
  450. description: Vec<u8>,
  451. stake_balance: Option<BalanceOf<T>>,
  452. new_validator_count: u32,
  453. ) {
  454. ensure!(
  455. new_validator_count >= <staking::Module<T>>::minimum_validator_count(),
  456. Error::InvalidValidatorCount
  457. );
  458. ensure!(
  459. new_validator_count <= MAX_VALIDATOR_COUNT,
  460. Error::InvalidValidatorCount
  461. );
  462. let proposal_parameters =
  463. proposal_types::parameters::set_validator_count_proposal::<T>();
  464. let proposal_details = ProposalDetails::SetValidatorCount(new_validator_count);
  465. let proposal_code = T::ProposalEncoder::encode_proposal(proposal_details.clone());
  466. Self::create_proposal(
  467. origin,
  468. member_id,
  469. title,
  470. description,
  471. stake_balance,
  472. proposal_code,
  473. proposal_parameters,
  474. proposal_details,
  475. )?;
  476. }
  477. // *************** Extrinsic to execute
  478. /// Text proposal extrinsic. Should be used as callable object to pass to the `engine` module.
  479. pub fn execute_text_proposal(
  480. origin,
  481. text: Vec<u8>,
  482. ) {
  483. ensure_root(origin)?;
  484. print("Text proposal: ");
  485. let text_string_result = from_utf8(text.as_slice());
  486. if let Ok(text_string) = text_string_result{
  487. print(text_string);
  488. }
  489. }
  490. /// Runtime upgrade proposal extrinsic.
  491. /// Should be used as callable object to pass to the `engine` module.
  492. pub fn execute_runtime_upgrade_proposal(
  493. origin,
  494. wasm: Vec<u8>,
  495. ) {
  496. let (cloned_origin1, cloned_origin2) = common::origin::double_origin::<T>(origin);
  497. ensure_root(cloned_origin1)?;
  498. print("Runtime upgrade proposal execution started.");
  499. <system::Module<T>>::set_code(cloned_origin2, wasm)?;
  500. print("Runtime upgrade proposal execution finished.");
  501. }
  502. }
  503. }
  504. impl<T: Trait> Module<T> {
  505. // Generic template proposal builder
  506. fn create_proposal(
  507. origin: T::Origin,
  508. member_id: MemberId<T>,
  509. title: Vec<u8>,
  510. description: Vec<u8>,
  511. stake_balance: Option<BalanceOf<T>>,
  512. proposal_code: Vec<u8>,
  513. proposal_parameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>,
  514. proposal_details: ProposalDetails<
  515. BalanceOfMint<T>,
  516. BalanceOfGovernanceCurrency<T>,
  517. T::BlockNumber,
  518. T::AccountId,
  519. T::MemberId,
  520. >,
  521. ) -> DispatchResult<Error> {
  522. let account_id = T::MembershipOriginValidator::ensure_actor_origin(origin, member_id)?;
  523. <proposal_engine::Module<T>>::ensure_create_proposal_parameters_are_valid(
  524. &proposal_parameters,
  525. &title,
  526. &description,
  527. stake_balance,
  528. )?;
  529. <proposal_discussion::Module<T>>::ensure_can_create_thread(member_id, &title)?;
  530. let discussion_thread_id =
  531. <proposal_discussion::Module<T>>::create_thread(member_id, title.clone())?;
  532. let proposal_id = <proposal_engine::Module<T>>::create_proposal(
  533. account_id,
  534. member_id,
  535. proposal_parameters,
  536. title,
  537. description,
  538. stake_balance,
  539. proposal_code,
  540. )?;
  541. <ThreadIdByProposalId<T>>::insert(proposal_id, discussion_thread_id);
  542. <ProposalDetailsByProposalId<T>>::insert(proposal_id, proposal_details);
  543. Ok(())
  544. }
  545. // validates council election parameters for the 'Set election parameters' proposal
  546. pub(crate) fn ensure_council_election_parameters_valid(
  547. election_parameters: &ElectionParameters<BalanceOfGovernanceCurrency<T>, T::BlockNumber>,
  548. ) -> Result<(), Error> {
  549. ensure!(
  550. election_parameters.council_size >= ELECTION_PARAMETERS_COUNCIL_SIZE_MIN_VALUE,
  551. Error::InvalidCouncilElectionParameterCouncilSize
  552. );
  553. ensure!(
  554. election_parameters.council_size <= ELECTION_PARAMETERS_COUNCIL_SIZE_MAX_VALUE,
  555. Error::InvalidCouncilElectionParameterCouncilSize
  556. );
  557. ensure!(
  558. election_parameters.candidacy_limit >= ELECTION_PARAMETERS_CANDIDACY_LIMIT_MIN_VALUE,
  559. Error::InvalidCouncilElectionParameterCandidacyLimit
  560. );
  561. ensure!(
  562. election_parameters.candidacy_limit <= ELECTION_PARAMETERS_CANDIDACY_LIMIT_MAX_VALUE,
  563. Error::InvalidCouncilElectionParameterCandidacyLimit
  564. );
  565. ensure!(
  566. election_parameters.min_voting_stake
  567. >= <BalanceOfGovernanceCurrency<T>>::from(ELECTION_PARAMETERS_MIN_STAKE_MIN_VALUE),
  568. Error::InvalidCouncilElectionParameterMinVotingStake
  569. );
  570. ensure!(
  571. election_parameters.min_voting_stake
  572. <= <BalanceOfGovernanceCurrency<T>>::from(ELECTION_PARAMETERS_MIN_STAKE_MAX_VALUE),
  573. Error::InvalidCouncilElectionParameterMinVotingStake
  574. );
  575. ensure!(
  576. election_parameters.new_term_duration
  577. >= T::BlockNumber::from(ELECTION_PARAMETERS_NEW_TERM_DURATION_MIN_VALUE),
  578. Error::InvalidCouncilElectionParameterNewTermDuration
  579. );
  580. ensure!(
  581. election_parameters.new_term_duration
  582. <= T::BlockNumber::from(ELECTION_PARAMETERS_NEW_TERM_DURATION_MAX_VALUE),
  583. Error::InvalidCouncilElectionParameterNewTermDuration
  584. );
  585. ensure!(
  586. election_parameters.revealing_period
  587. >= T::BlockNumber::from(ELECTION_PARAMETERS_REVEALING_PERIOD_MIN_VALUE),
  588. Error::InvalidCouncilElectionParameterRevealingPeriod
  589. );
  590. ensure!(
  591. election_parameters.revealing_period
  592. <= T::BlockNumber::from(ELECTION_PARAMETERS_REVEALING_PERIOD_MAX_VALUE),
  593. Error::InvalidCouncilElectionParameterRevealingPeriod
  594. );
  595. ensure!(
  596. election_parameters.voting_period
  597. >= T::BlockNumber::from(ELECTION_PARAMETERS_VOTING_PERIOD_MIN_VALUE),
  598. Error::InvalidCouncilElectionParameterVotingPeriod
  599. );
  600. ensure!(
  601. election_parameters.voting_period
  602. <= T::BlockNumber::from(ELECTION_PARAMETERS_VOTING_PERIOD_MAX_VALUE),
  603. Error::InvalidCouncilElectionParameterVotingPeriod
  604. );
  605. ensure!(
  606. election_parameters.announcing_period
  607. >= T::BlockNumber::from(ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MIN_VALUE),
  608. Error::InvalidCouncilElectionParameterAnnouncingPeriod
  609. );
  610. ensure!(
  611. election_parameters.announcing_period
  612. <= T::BlockNumber::from(ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MAX_VALUE),
  613. Error::InvalidCouncilElectionParameterAnnouncingPeriod
  614. );
  615. ensure!(
  616. election_parameters.min_council_stake
  617. >= <BalanceOfGovernanceCurrency<T>>::from(
  618. ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MIN_VALUE
  619. ),
  620. Error::InvalidCouncilElectionParameterMinCouncilStake
  621. );
  622. ensure!(
  623. election_parameters.min_council_stake
  624. <= <BalanceOfGovernanceCurrency<T>>::from(
  625. ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MAX_VALUE
  626. ),
  627. Error::InvalidCouncilElectionParameterMinCouncilStake
  628. );
  629. Ok(())
  630. }
  631. /// Sets default config values for the proposals.
  632. /// Should be called on the migration to the new runtime version.
  633. pub fn set_default_config_values() {
  634. let p = ProposalsConfigParameters::default();
  635. <SetValidatorCountProposalVotingPeriod<T>>::put(T::BlockNumber::from(
  636. p.set_validator_count_proposal_voting_period,
  637. ));
  638. <SetValidatorCountProposalGracePeriod<T>>::put(T::BlockNumber::from(
  639. p.set_validator_count_proposal_grace_period,
  640. ));
  641. <RuntimeUpgradeProposalVotingPeriod<T>>::put(T::BlockNumber::from(
  642. p.runtime_upgrade_proposal_voting_period,
  643. ));
  644. <RuntimeUpgradeProposalGracePeriod<T>>::put(T::BlockNumber::from(
  645. p.runtime_upgrade_proposal_grace_period,
  646. ));
  647. <TextProposalVotingPeriod<T>>::put(T::BlockNumber::from(p.text_proposal_voting_period));
  648. <TextProposalGracePeriod<T>>::put(T::BlockNumber::from(p.text_proposal_grace_period));
  649. <SetElectionParametersProposalVotingPeriod<T>>::put(T::BlockNumber::from(
  650. p.set_election_parameters_proposal_voting_period,
  651. ));
  652. <SetElectionParametersProposalGracePeriod<T>>::put(T::BlockNumber::from(
  653. p.set_election_parameters_proposal_grace_period,
  654. ));
  655. <SetContentWorkingGroupMintCapacityProposalVotingPeriod<T>>::put(T::BlockNumber::from(
  656. p.set_content_working_group_mint_capacity_proposal_voting_period,
  657. ));
  658. <SetContentWorkingGroupMintCapacityProposalGracePeriod<T>>::put(T::BlockNumber::from(
  659. p.set_content_working_group_mint_capacity_proposal_grace_period,
  660. ));
  661. <SetLeadProposalVotingPeriod<T>>::put(T::BlockNumber::from(
  662. p.set_lead_proposal_voting_period,
  663. ));
  664. <SetLeadProposalGracePeriod<T>>::put(T::BlockNumber::from(
  665. p.set_lead_proposal_grace_period,
  666. ));
  667. <SpendingProposalVotingPeriod<T>>::put(T::BlockNumber::from(
  668. p.spending_proposal_voting_period,
  669. ));
  670. <SpendingProposalGracePeriod<T>>::put(T::BlockNumber::from(
  671. p.spending_proposal_grace_period,
  672. ));
  673. }
  674. }