lib.rs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. // TODO: adjust all extrinsic weights
  2. //! # Referendum module
  3. //! General voting engine module for the the Joystream platform. Component of the council system.
  4. //!
  5. //! ## Overview
  6. //!
  7. //! Referendum is an abstract module that enables priviliged network participants to vote on the given topic.
  8. //! The module has no notion on the topic that is actually voted on focuses and rather focuses on enabling
  9. //! users to cast their votes and selecting the winning option after voting concludes.
  10. //!
  11. //! The voting itself is divided into three phases. In the default Idle phase, the module waits
  12. //! for the new voting round initiation by the runtime. In the Voting phase, users can submit sealed commitment
  13. //! of their vote that they can later reveal in the Revealing phase. After the Revealing phase ends,
  14. //! the Referendum becomes Idle again and waits for the new cycle start.
  15. //!
  16. //! The module supports an unlimited number of options for voting and one or multiple winners of the referendum.
  17. //! Depending on the runtime implementation, users can be required to stake at least a minimum amount of currency,
  18. //! and the winning options can be decided by the total number of votes received or the total amount staked
  19. //! behind them.
  20. //!
  21. //! ## Supported extrinsics
  22. //!
  23. //! - [vote](./struct.Module.html#method.vote)
  24. //! - [reveal_vote](./struct.Module.html#method.reveal_vote)
  25. //! - [release_vote_stake](./struct.Module.html#method.release_vote_stake)
  26. //!
  27. //! ## Notes
  28. //! This module is instantiable pallet as described here https://substrate.dev/recipes/3-entrees/instantiable.html
  29. //! No default instance is provided.
  30. /////////////////// Configuration //////////////////////////////////////////////
  31. #![cfg_attr(not(feature = "std"), no_std)]
  32. // used dependencies
  33. use codec::{Codec, Decode, Encode};
  34. use frame_support::traits::{
  35. Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, WithdrawReason,
  36. };
  37. use frame_support::{
  38. decl_error, decl_event, decl_module, decl_storage, error::BadOrigin, Parameter, StorageValue,
  39. };
  40. use sp_arithmetic::traits::BaseArithmetic;
  41. use sp_runtime::traits::{MaybeSerialize, Member};
  42. use std::marker::PhantomData;
  43. use system::ensure_signed;
  44. // declared modules
  45. mod mock;
  46. mod tests;
  47. /////////////////// Data Structures ////////////////////////////////////////////
  48. /// Possible referendum states.
  49. #[derive(Encode, Decode, PartialEq, Eq, Debug)]
  50. pub enum ReferendumStage<BlockNumber, VotePower> {
  51. /// The referendum is dormant and waiting to be started by external source.
  52. Inactive,
  53. /// In the voting stage, users can cast their sealed votes.
  54. Voting(ReferendumStageVoting<BlockNumber>),
  55. /// In the revealing stage, users can reveal votes they cast in the voting stage.
  56. Revealing(ReferendumStageRevealing<BlockNumber, VotePower>),
  57. }
  58. impl<BlockNumber, VotePower: Encode + Decode> Default for ReferendumStage<BlockNumber, VotePower> {
  59. fn default() -> ReferendumStage<BlockNumber, VotePower> {
  60. ReferendumStage::Inactive
  61. }
  62. }
  63. /// Representation for voting stage state.
  64. #[derive(Encode, Decode, PartialEq, Eq, Debug, Default)]
  65. pub struct ReferendumStageVoting<BlockNumber> {
  66. pub started: BlockNumber, // block in which referendum started
  67. pub winning_target_count: u64, // target number of winners
  68. }
  69. /// Representation for revealing stage state.
  70. #[derive(Encode, Decode, PartialEq, Eq, Debug, Default)]
  71. pub struct ReferendumStageRevealing<BlockNumber, VotePower> {
  72. pub started: BlockNumber, // block in which referendum started
  73. pub winning_target_count: u64, // target number of winners
  74. pub intermediate_winners: Vec<OptionResult<VotePower>>, // intermediate winning options
  75. }
  76. #[derive(Encode, Decode, PartialEq, Eq, Debug, Default, Clone)]
  77. pub struct OptionResult<VotePower> {
  78. pub option_id: u64,
  79. pub vote_power: VotePower,
  80. }
  81. /// Vote cast in referendum. Vote target is concealed until user reveals commitment's proof.
  82. #[derive(Encode, Decode, PartialEq, Eq, Debug, Default)]
  83. pub struct CastVote<Hash, Currency> {
  84. pub commitment: Hash, // a commitment that a user submits in the voting stage before revealing what this vote is actually for
  85. pub cycle_id: u64, // current referendum cycle number
  86. pub stake: Currency, // stake locked for vote
  87. pub vote_for: Option<u64>, // target option this vote favors; is `None` before the vote is revealed
  88. }
  89. /////////////////// Type aliases ///////////////////////////////////////////////
  90. // `Ez` prefix in some of the following type aliases means *easy* and is meant to create unique short names
  91. // aliasing existing structs and enums
  92. // types simplifying access to common structs and enums
  93. pub type Balance<T, I> =
  94. <<T as Trait<I>>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
  95. pub type CastVoteOf<T, I> = CastVote<<T as system::Trait>::Hash, Balance<T, I>>;
  96. pub type ReferendumStageVotingOf<T> = ReferendumStageVoting<<T as system::Trait>::BlockNumber>;
  97. pub type ReferendumStageRevealingOf<T, I> =
  98. ReferendumStageRevealing<<T as system::Trait>::BlockNumber, <T as Trait<I>>::VotePower>;
  99. // types aliases for check functions return values
  100. pub type CanRevealResult<T, I> = (
  101. ReferendumStageRevealingOf<T, I>,
  102. <T as system::Trait>::AccountId,
  103. CastVoteOf<T, I>,
  104. );
  105. /////////////////// Trait, Storage, Errors, and Events /////////////////////////
  106. /// Trait that should be used by other modules to start the referendum, etc.
  107. pub trait ReferendumManager<Origin, AccountId, Hash> {
  108. /// Power of vote(s) used to determine the referendum winner(s).
  109. type VotePower: Parameter
  110. + Member
  111. + BaseArithmetic
  112. + Codec
  113. + Default
  114. + Copy
  115. + MaybeSerialize
  116. + PartialEq;
  117. /// Currency for referendum staking.
  118. type Currency: LockableCurrency<AccountId>;
  119. /// Start a new referendum.
  120. fn start_referendum(origin: Origin, extra_winning_target_count: u64) -> Result<(), ()>;
  121. /// Start referendum independent of the current state.
  122. /// If an election is running before calling this function, it will be discontinued without any winners selected.
  123. fn force_start(extra_winning_target_count: u64);
  124. /// Calculate commitment for a vote.
  125. fn calculate_commitment(
  126. account_id: &AccountId,
  127. salt: &[u8],
  128. cycle_id: &u64,
  129. vote_option_id: &u64,
  130. ) -> Hash;
  131. }
  132. /// The main Referendum module's trait.
  133. pub trait Trait<I: Instance>: system::Trait {
  134. /// The overarching event type.
  135. type Event: From<Event<Self, I>> + Into<<Self as system::Trait>::Event>;
  136. /// Maximum length of vote commitment salt. Use length that ensures uniqueness for hashing e.g. std::u64::MAX.
  137. type MaxSaltLength: Get<u64>;
  138. /// Currency for referendum staking.
  139. type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>;
  140. /// Identifier for currency locks used for staking.
  141. type LockId: Get<LockIdentifier>;
  142. /// Origin from which the referendum can be started.
  143. type ManagerOrigin: EnsureOrigin<Self::Origin>;
  144. /// Power of vote(s) used to determine the referendum winner(s).
  145. type VotePower: Parameter
  146. + Member
  147. + BaseArithmetic
  148. + Codec
  149. + Default
  150. + Copy
  151. + MaybeSerialize
  152. + PartialEq;
  153. /// Duration of voting stage (number of blocks)
  154. type VoteStageDuration: Get<Self::BlockNumber>;
  155. /// Duration of revealing stage (number of blocks)
  156. type RevealStageDuration: Get<Self::BlockNumber>;
  157. /// Minimum stake needed for voting
  158. type MinimumStake: Get<Balance<Self, I>>;
  159. /// Calculate the vote's power for user and his stake.
  160. fn calculate_vote_power(
  161. account_id: &<Self as system::Trait>::AccountId,
  162. stake: &Balance<Self, I>,
  163. ) -> <Self as Trait<I>>::VotePower;
  164. /// Checks if user can unlock his stake from the given vote.
  165. /// Gives runtime an ability to penalize user for not revealing stake, etc.
  166. fn can_release_vote_stake(
  167. vote: &CastVote<Self::Hash, Balance<Self, I>>,
  168. current_voting_cycle_id: &u64,
  169. ) -> bool;
  170. /// Gives runtime an ability to react on referendum result.
  171. fn process_results(winners: &[OptionResult<Self::VotePower>]);
  172. /// Check if an option a user is voting for actually exists.
  173. fn is_valid_option_id(option_id: &u64) -> bool;
  174. // If the id is a valid alternative, the current total voting mass backing it is returned, otherwise nothing.
  175. fn get_option_power(option_id: &u64) -> Self::VotePower;
  176. // Increases voting mass behind given alternative by given amount, if present and return true, otherwise return false.
  177. fn increase_option_power(option_id: &u64, amount: &Self::VotePower);
  178. }
  179. decl_storage! {
  180. trait Store for Module<T: Trait<I>, I: Instance> as Referendum {
  181. /// Current referendum stage.
  182. pub Stage get(fn stage) config(): ReferendumStage<T::BlockNumber, T::VotePower>;
  183. /// Votes cast in the referendum. A new record is added to this map when a user casts a sealed vote.
  184. /// It is modified when a user reveals the vote's commitment proof.
  185. /// A record is finally removed when the user unstakes, which can happen during a voting stage or after the current cycle ends.
  186. /// A stake for a vote can be reused in future referendum cycles.
  187. pub Votes get(fn votes) config(): map hasher(blake2_128_concat) T::AccountId => CastVoteOf<T, I>;
  188. /// Index of the current referendum cycle. It is incremented everytime referendum ends.
  189. pub CurrentCycleId get(fn current_cycle_id) config(): u64;
  190. }
  191. }
  192. decl_event! {
  193. pub enum Event<T, I>
  194. where
  195. Balance = Balance<T, I>,
  196. <T as system::Trait>::Hash,
  197. <T as system::Trait>::AccountId,
  198. <T as Trait<I>>::VotePower,
  199. {
  200. /// Referendum started
  201. ReferendumStarted(u64),
  202. /// Referendum started
  203. ReferendumStartedForcefully(u64),
  204. /// Revealing phase has begun
  205. RevealingStageStarted(),
  206. /// Referendum ended and winning option was selected
  207. ReferendumFinished(Vec<OptionResult<VotePower>>),
  208. /// User cast a vote in referendum
  209. VoteCast(AccountId, Hash, Balance),
  210. /// User revealed his vote
  211. VoteRevealed(AccountId, u64),
  212. /// User released his stake
  213. StakeReleased(AccountId),
  214. }
  215. }
  216. decl_error! {
  217. /// Referendum errors
  218. pub enum Error for Module<T: Trait<I>, I: Instance> {
  219. /// Origin is invalid
  220. BadOrigin,
  221. /// Referendum is not running when expected to
  222. ReferendumNotRunning,
  223. /// Revealing stage is not in progress right now
  224. RevealingNotInProgress,
  225. /// Account can't stake enough currency (now)
  226. InsufficientBalanceToStakeCurrency,
  227. /// Insufficient stake provided to cast a vote
  228. InsufficientStake,
  229. /// Salt and referendum option provided don't correspond to the commitment
  230. InvalidReveal,
  231. /// Vote for not existing option was revealed
  232. InvalidVote,
  233. /// Trying to reveal vote that was not cast
  234. VoteNotExisting,
  235. /// Trying to vote multiple time in the same cycle
  236. AlreadyVotedThisCycle,
  237. /// Invalid time to release the locked stake
  238. UnstakingVoteInSameCycle,
  239. /// Salt is too long
  240. SaltTooLong,
  241. /// Unstaking has been forbidden for the user (at least for now)
  242. UnstakingForbidden,
  243. }
  244. }
  245. impl<T: Trait<I>, I: Instance> PartialEq for Error<T, I> {
  246. fn eq(&self, other: &Self) -> bool {
  247. self.as_u8() == other.as_u8()
  248. }
  249. }
  250. impl<T: Trait<I>, I: Instance> From<BadOrigin> for Error<T, I> {
  251. fn from(_error: BadOrigin) -> Self {
  252. Error::<T, I>::BadOrigin
  253. }
  254. }
  255. /////////////////// Module definition and implementation ///////////////////////
  256. decl_module! {
  257. pub struct Module<T: Trait<I>, I: Instance> for enum Call where origin: T::Origin {
  258. /// Predefined errors
  259. type Error = Error<T, I>;
  260. /// Setup events
  261. fn deposit_event() = default;
  262. /////////////////// Lifetime ///////////////////////////////////////////
  263. // No origin so this is a priviledged call
  264. fn on_finalize(now: T::BlockNumber) {
  265. Self::try_progress_stage(now);
  266. }
  267. /////////////////// User actions ///////////////////////////////////////
  268. /// Cast a sealed vote in the referendum.
  269. #[weight = 10_000_000]
  270. pub fn vote(origin, commitment: T::Hash, stake: Balance<T, I>) -> Result<(), Error<T, I>> {
  271. // ensure action can be started
  272. let account_id = EnsureChecks::<T, I>::can_vote(origin, &stake)?;
  273. //
  274. // == MUTATION SAFE ==
  275. //
  276. // start revealing phase - it can return error when stake fails to lock
  277. Mutations::<T, I>::vote(&account_id, &commitment, &stake)?;
  278. // emit event
  279. Self::deposit_event(RawEvent::VoteCast(account_id, commitment, stake));
  280. Ok(())
  281. }
  282. /// Reveal a sealed vote in the referendum.
  283. #[weight = 10_000_000]
  284. pub fn reveal_vote(origin, salt: Vec<u8>, vote_option_id: u64) -> Result<(), Error<T, I>> {
  285. let (stage_data, account_id, cast_vote) = EnsureChecks::<T, I>::can_reveal_vote::<Self>(origin, &salt, &vote_option_id)?;
  286. //
  287. // == MUTATION SAFE ==
  288. //
  289. // reveal the vote - it can return error when stake fails to unlock
  290. Mutations::<T, I>::reveal_vote(stage_data, &account_id, &vote_option_id, cast_vote)?;
  291. // emit event
  292. Self::deposit_event(RawEvent::VoteRevealed(account_id, vote_option_id));
  293. Ok(())
  294. }
  295. /// Release a locked stake.
  296. #[weight = 10_000_000]
  297. pub fn release_vote_stake(origin) -> Result<(), Error<T, I>> {
  298. let account_id = EnsureChecks::<T, I>::can_release_vote_stake(origin)?;
  299. //
  300. // == MUTATION SAFE ==
  301. //
  302. // reveal the vote - it can return error when stake fails to unlock
  303. Mutations::<T, I>::release_vote_stake(&account_id);
  304. // emit event
  305. Self::deposit_event(RawEvent::StakeReleased(account_id));
  306. Ok(())
  307. }
  308. }
  309. }
  310. /////////////////// Inner logic ////////////////////////////////////////////////
  311. impl<T: Trait<I>, I: Instance> Module<T, I> {
  312. /// Checkout expire of referendum stage.
  313. fn try_progress_stage(now: T::BlockNumber) {
  314. match Stage::<T, I>::get() {
  315. ReferendumStage::Inactive => (),
  316. ReferendumStage::Voting(stage_data) => {
  317. if now == stage_data.started + T::VoteStageDuration::get() - 1.into() {
  318. Self::end_voting_period(stage_data);
  319. }
  320. }
  321. ReferendumStage::Revealing(stage_data) => {
  322. if now == stage_data.started + T::RevealStageDuration::get() - 1.into() {
  323. Self::end_reveal_period(stage_data);
  324. }
  325. }
  326. }
  327. }
  328. /// Finish voting and start ravealing.
  329. fn end_voting_period(stage_data: ReferendumStageVotingOf<T>) {
  330. // start revealing phase
  331. Mutations::<T, I>::start_revealing_period(stage_data);
  332. // emit event
  333. Self::deposit_event(RawEvent::RevealingStageStarted());
  334. }
  335. /// Conclude the referendum.
  336. fn end_reveal_period(stage_data: ReferendumStageRevealingOf<T, I>) {
  337. // conclude referendum
  338. let winners = Mutations::<T, I>::conclude_referendum(stage_data);
  339. // let runtime know about referendum results
  340. T::process_results(&winners);
  341. // emit event
  342. Self::deposit_event(RawEvent::ReferendumFinished(winners));
  343. }
  344. }
  345. /////////////////// ReferendumManager //////////////////////////////////////////
  346. impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Hash>
  347. for Module<T, I>
  348. {
  349. type VotePower = T::VotePower;
  350. type Currency = T::Currency;
  351. /// Start new referendum run.
  352. fn start_referendum(origin: T::Origin, extra_winning_target_count: u64) -> Result<(), ()> {
  353. let winning_target_count = extra_winning_target_count + 1;
  354. // ensure action can be started
  355. EnsureChecks::<T, I>::can_start_referendum(origin)?;
  356. //
  357. // == MUTATION SAFE ==
  358. //
  359. // update state
  360. Mutations::<T, I>::start_voting_period(&winning_target_count);
  361. // emit event
  362. Self::deposit_event(RawEvent::ReferendumStarted(winning_target_count));
  363. Ok(())
  364. }
  365. /// Start referendum independent of the current state.
  366. /// If an election is running before calling this function, it will be discontinued without any winners selected.
  367. fn force_start(extra_winning_target_count: u64) {
  368. let winning_target_count = extra_winning_target_count + 1;
  369. // remember if referendum is running
  370. let referendum_running = !matches!(Stage::<T, I>::get(), ReferendumStage::Inactive);
  371. // update state
  372. Mutations::<T, I>::start_voting_period(&winning_target_count);
  373. // emit event
  374. if referendum_running {
  375. Self::deposit_event(RawEvent::ReferendumStartedForcefully(winning_target_count));
  376. } else {
  377. Self::deposit_event(RawEvent::ReferendumStarted(winning_target_count));
  378. }
  379. }
  380. /// Calculate commitment for a vote.
  381. fn calculate_commitment(
  382. account_id: &<T as system::Trait>::AccountId,
  383. salt: &[u8],
  384. cycle_id: &u64,
  385. vote_option_id: &u64,
  386. ) -> T::Hash {
  387. let mut payload = account_id.encode();
  388. let mut mut_option_id = vote_option_id.encode();
  389. let mut mut_salt = salt.encode(); //.to_vec();
  390. let mut mut_cycle_id = cycle_id.encode(); //.to_vec();
  391. payload.append(&mut mut_option_id);
  392. payload.append(&mut mut_salt);
  393. payload.append(&mut mut_cycle_id);
  394. <T::Hashing as sp_runtime::traits::Hash>::hash(&payload)
  395. }
  396. }
  397. /////////////////// Mutations //////////////////////////////////////////////////
  398. struct Mutations<T: Trait<I>, I: Instance> {
  399. _dummy: PhantomData<(T, I)>, // 0-sized data meant only to bound generic parameters
  400. }
  401. impl<T: Trait<I>, I: Instance> Mutations<T, I> {
  402. /// Change the referendum stage from inactive to voting stage.
  403. fn start_voting_period(winning_target_count: &u64) {
  404. // change referendum state
  405. Stage::<T, I>::put(ReferendumStage::Voting(ReferendumStageVoting::<
  406. T::BlockNumber,
  407. > {
  408. started: <system::Module<T>>::block_number() + 1.into(),
  409. winning_target_count: *winning_target_count,
  410. }));
  411. }
  412. /// Change the referendum stage from inactive to the voting stage.
  413. fn start_revealing_period(old_stage: ReferendumStageVotingOf<T>) {
  414. // change referendum state
  415. Stage::<T, I>::put(ReferendumStage::Revealing(ReferendumStageRevealingOf::<
  416. T,
  417. I,
  418. > {
  419. started: <system::Module<T>>::block_number() + 1.into(),
  420. winning_target_count: old_stage.winning_target_count,
  421. intermediate_winners: vec![],
  422. }));
  423. }
  424. /// Conclude referendum, count votes, and select the winners.
  425. fn conclude_referendum(
  426. revealing_stage: ReferendumStageRevealingOf<T, I>,
  427. ) -> Vec<OptionResult<<T as Trait<I>>::VotePower>> {
  428. // reset referendum state
  429. Self::reset_referendum();
  430. // return winning option
  431. revealing_stage.intermediate_winners
  432. }
  433. /// Change the referendum stage from revealing to the inactive stage.
  434. fn reset_referendum() {
  435. Stage::<T, I>::put(ReferendumStage::Inactive);
  436. CurrentCycleId::<I>::put(CurrentCycleId::<I>::get() + 1);
  437. }
  438. /// Cast a user's sealed vote for the current referendum cycle.
  439. fn vote(
  440. account_id: &<T as system::Trait>::AccountId,
  441. commitment: &T::Hash,
  442. stake: &Balance<T, I>,
  443. ) -> Result<(), Error<T, I>> {
  444. // lock stake amount
  445. T::Currency::set_lock(
  446. T::LockId::get(),
  447. account_id,
  448. *stake,
  449. WithdrawReason::Transfer.into(),
  450. );
  451. // store vote
  452. Votes::<T, I>::insert(
  453. account_id,
  454. CastVote {
  455. commitment: *commitment,
  456. stake: *stake,
  457. cycle_id: CurrentCycleId::<I>::get(),
  458. vote_for: None,
  459. },
  460. );
  461. Ok(())
  462. }
  463. /// Reveal user's vote target and check the commitment proof.
  464. fn reveal_vote(
  465. stage_data: ReferendumStageRevealingOf<T, I>,
  466. account_id: &<T as system::Trait>::AccountId,
  467. option_id: &u64,
  468. cast_vote: CastVoteOf<T, I>,
  469. ) -> Result<(), Error<T, I>> {
  470. // prepare new values
  471. let vote_power = T::calculate_vote_power(&account_id, &cast_vote.stake);
  472. let option_result = OptionResult {
  473. option_id: *option_id,
  474. vote_power,
  475. };
  476. // try to insert option to winner list or update it's value when already present
  477. let new_winners = Self::try_winner_insert(
  478. option_result,
  479. &stage_data.intermediate_winners,
  480. stage_data.winning_target_count,
  481. );
  482. let new_stage_data = ReferendumStageRevealing {
  483. intermediate_winners: new_winners,
  484. ..stage_data
  485. };
  486. // let runtime update option's vote power
  487. T::increase_option_power(option_id, &vote_power);
  488. // store revealed vote
  489. Stage::<T, I>::mutate(|stage| *stage = ReferendumStage::Revealing(new_stage_data));
  490. // remove user commitment to prevent repeated revealing
  491. Votes::<T, I>::mutate(account_id, |vote| (*vote).vote_for = Some(*option_id));
  492. Ok(())
  493. }
  494. /// Release stake associated to the user's last vote.
  495. fn release_vote_stake(account_id: &<T as system::Trait>::AccountId) {
  496. // lock stake amount
  497. T::Currency::remove_lock(T::LockId::get(), account_id);
  498. // remove vote record
  499. Votes::<T, I>::remove(account_id);
  500. }
  501. /// Tries to insert option to the proper place in the winners list. Utility for reaveal_vote() function.
  502. fn try_winner_insert(
  503. option_result: OptionResult<T::VotePower>,
  504. current_winners: &[OptionResult<T::VotePower>],
  505. winning_target_count: u64,
  506. ) -> Vec<OptionResult<T::VotePower>> {
  507. /// Tries to place record to temporary place in the winning list.
  508. fn place_record_to_winner_list<T: Trait<I>, I: Instance>(
  509. option_result: OptionResult<T::VotePower>,
  510. current_winners: &[OptionResult<T::VotePower>],
  511. winning_target_count: u64,
  512. ) -> (Vec<OptionResult<T::VotePower>>, Option<usize>) {
  513. let current_winners_count = current_winners.len();
  514. // check if option is already somewhere in list
  515. let current_winners_index_of_vote_recipient: Option<usize> = current_winners
  516. .iter()
  517. .enumerate()
  518. .find(|(_, value)| option_result.option_id == value.option_id)
  519. .map(|(index, _)| index);
  520. // espace when item is currently not in winning list and still has not enough vote power to make it to already full list
  521. if current_winners_index_of_vote_recipient.is_none()
  522. && current_winners_count as u64 == winning_target_count
  523. && option_result.vote_power <= current_winners[current_winners_count - 1].vote_power
  524. {
  525. return (current_winners.to_vec(), None);
  526. }
  527. let mut new_winners = current_winners.to_vec();
  528. // update record in list when it is already present
  529. if let Some(index) = current_winners_index_of_vote_recipient {
  530. let old_option_total = T::get_option_power(&option_result.option_id);
  531. let new_option_total = old_option_total + option_result.vote_power;
  532. new_winners[index] = OptionResult {
  533. option_id: option_result.option_id,
  534. vote_power: new_option_total,
  535. };
  536. return (new_winners, Some(index));
  537. }
  538. // at this point record needs to be added to list
  539. // replace last winner if list is already full
  540. if current_winners_count as u64 == winning_target_count {
  541. let last_index = current_winners_count - 1;
  542. new_winners[last_index] = option_result;
  543. return (new_winners, Some(last_index));
  544. }
  545. // append winner to incomplete list
  546. new_winners.push(option_result);
  547. (new_winners, Some(current_winners_count))
  548. }
  549. // if there are no winners right now return list with only current option
  550. if current_winners.is_empty() {
  551. return vec![option_result];
  552. }
  553. // get new possibly updated list and record's position in it
  554. let (mut new_winners, current_record_index) = place_record_to_winner_list::<T, I>(
  555. option_result,
  556. current_winners,
  557. winning_target_count,
  558. );
  559. // resort list in case it was updated
  560. if let Some(index) = current_record_index {
  561. for i in (1..=index).rev() {
  562. if new_winners[i].vote_power <= new_winners[i - 1].vote_power {
  563. break;
  564. }
  565. new_winners.swap(i, i - 1);
  566. }
  567. }
  568. new_winners.to_vec()
  569. }
  570. }
  571. /////////////////// Ensure checks //////////////////////////////////////////////
  572. struct EnsureChecks<T: Trait<I>, I: Instance> {
  573. _dummy: PhantomData<(T, I)>, // 0-sized data meant only to bound generic parameters
  574. }
  575. impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
  576. /////////////////// Common checks //////////////////////////////////////////
  577. fn ensure_regular_user(origin: T::Origin) -> Result<T::AccountId, Error<T, I>> {
  578. let account_id = ensure_signed(origin)?;
  579. Ok(account_id)
  580. }
  581. /////////////////// Action checks //////////////////////////////////////////
  582. fn can_start_referendum(origin: T::Origin) -> Result<(), ()> {
  583. T::ManagerOrigin::ensure_origin(origin).map_err(|_| ())?;
  584. // ensure referendum is not already running
  585. match Stage::<T, I>::get() {
  586. ReferendumStage::Inactive => Ok(()),
  587. _ => Err(()),
  588. }?;
  589. Ok(())
  590. }
  591. fn can_vote(origin: T::Origin, stake: &Balance<T, I>) -> Result<T::AccountId, Error<T, I>> {
  592. fn prevent_repeated_vote<T: Trait<I>, I: Instance>(
  593. account_id: &T::AccountId,
  594. ) -> Result<(), Error<T, I>> {
  595. if !Votes::<T, I>::contains_key(&account_id) {
  596. return Ok(());
  597. }
  598. let existing_vote = Votes::<T, I>::get(&account_id);
  599. // don't allow repeated vote
  600. if existing_vote.cycle_id == CurrentCycleId::<I>::get() {
  601. return Err(Error::<T, I>::AlreadyVotedThisCycle);
  602. }
  603. Ok(())
  604. }
  605. // ensure superuser requested action
  606. let account_id = Self::ensure_regular_user(origin)?;
  607. let stage = Stage::<T, I>::get();
  608. // ensure referendum is running
  609. match stage {
  610. ReferendumStage::Voting(_) => (),
  611. _ => return Err(Error::ReferendumNotRunning),
  612. };
  613. // prevent repeated vote
  614. prevent_repeated_vote::<T, I>(&account_id)?;
  615. // ensure stake is enough for voting
  616. if stake < &T::MinimumStake::get() {
  617. return Err(Error::InsufficientStake);
  618. }
  619. // ensure account can lock the stake
  620. if T::Currency::total_balance(&account_id) < *stake {
  621. return Err(Error::InsufficientBalanceToStakeCurrency);
  622. }
  623. Ok(account_id)
  624. }
  625. fn can_reveal_vote<R: ReferendumManager<T::Origin, T::AccountId, T::Hash>>(
  626. origin: T::Origin,
  627. salt: &[u8],
  628. vote_option_id: &u64,
  629. ) -> Result<CanRevealResult<T, I>, Error<T, I>> {
  630. let cycle_id = CurrentCycleId::<I>::get();
  631. // ensure superuser requested action
  632. let account_id = Self::ensure_regular_user(origin)?;
  633. let stage = Stage::<T, I>::get();
  634. // ensure referendum is running
  635. let stage_data = match stage {
  636. ReferendumStage::Revealing(tmp_stage_data) => tmp_stage_data,
  637. _ => return Err(Error::RevealingNotInProgress),
  638. };
  639. let cast_vote = Self::ensure_vote_exists(&account_id)?;
  640. // ask runtime if option is valid
  641. if !T::is_valid_option_id(vote_option_id) {
  642. return Err(Error::InvalidVote);
  643. }
  644. // ensure vote was cast for the running referendum
  645. if cycle_id != cast_vote.cycle_id {
  646. return Err(Error::InvalidVote);
  647. }
  648. // ensure salt is not too long
  649. if salt.len() as u64 > T::MaxSaltLength::get() {
  650. return Err(Error::SaltTooLong);
  651. }
  652. // ensure commitment corresponds to salt and vote option
  653. let commitment = R::calculate_commitment(&account_id, salt, &cycle_id, vote_option_id);
  654. if commitment != cast_vote.commitment {
  655. return Err(Error::InvalidReveal);
  656. }
  657. Ok((stage_data, account_id, cast_vote))
  658. }
  659. fn can_release_vote_stake(origin: T::Origin) -> Result<T::AccountId, Error<T, I>> {
  660. let cycle_id = CurrentCycleId::<I>::get();
  661. // ensure superuser requested action
  662. let account_id = Self::ensure_regular_user(origin)?;
  663. let cast_vote = Self::ensure_vote_exists(&account_id)?;
  664. // allow release only for past cycles
  665. if cycle_id == cast_vote.cycle_id {
  666. return Err(Error::UnstakingVoteInSameCycle);
  667. }
  668. // ask runtime if stake can be released
  669. if !T::can_release_vote_stake(&cast_vote, &cycle_id) {
  670. return Err(Error::UnstakingForbidden);
  671. }
  672. Ok(account_id)
  673. }
  674. fn ensure_vote_exists(account_id: &T::AccountId) -> Result<CastVoteOf<T, I>, Error<T, I>> {
  675. // ensure there is some vote with locked stake
  676. if !Votes::<T, I>::contains_key(account_id) {
  677. return Err(Error::VoteNotExisting);
  678. }
  679. let cast_vote = Votes::<T, I>::get(account_id);
  680. Ok(cast_vote)
  681. }
  682. }