mock.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. #![cfg(test)]
  2. /////////////////// Configuration //////////////////////////////////////////////
  3. use crate::{
  4. BalanceReferendum, CandidateOf, CouncilMemberOf, CouncilMembers, CouncilStage,
  5. CouncilStageAnnouncing, CouncilStageElection, CouncilStageUpdate, CouncilStageUpdateOf,
  6. CurrentAnnouncementCycleId, Error, GenesisConfig, Module, ReferendumConnection, Stage, Trait,
  7. };
  8. use frame_support::traits::{Currency, Get, LockIdentifier, OnFinalize};
  9. use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, StorageValue};
  10. use balances;
  11. use rand::Rng;
  12. use referendum::{
  13. Balance, CastVote, CurrentCycleId, OptionResult, ReferendumManager, ReferendumStage,
  14. ReferendumStageRevealing,
  15. };
  16. use sp_core::H256;
  17. use sp_io;
  18. use sp_runtime::{
  19. testing::Header,
  20. traits::{BlakeTwo256, IdentityLookup},
  21. Perbill,
  22. };
  23. use std::cell::RefCell;
  24. use std::collections::BTreeMap;
  25. use std::marker::PhantomData;
  26. use system::{EnsureOneOf, EnsureRoot, EnsureSigned, RawOrigin};
  27. use crate::staking_handler::mocks::{Lock1, Lock2};
  28. pub const USER_REGULAR_POWER_VOTES: u64 = 0;
  29. pub const POWER_VOTE_STRENGTH: u64 = 10;
  30. pub const VOTER_BASE_ID: u64 = 4000;
  31. pub const CANDIDATE_BASE_ID: u64 = VOTER_BASE_ID + VOTER_CANDIDATE_OFFSET;
  32. pub const VOTER_CANDIDATE_OFFSET: u64 = 1000;
  33. pub const INVALID_USER_MEMBER: u64 = 9999;
  34. /////////////////// Runtime and Instances //////////////////////////////////////
  35. // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
  36. #[derive(Clone, PartialEq, Eq, Debug)]
  37. pub struct Runtime;
  38. parameter_types! {
  39. pub const MinNumberOfExtraCandidates: u64 = 1;
  40. pub const AnnouncingPeriodDuration: u64 = 15;
  41. pub const IdlePeriodDuration: u64 = 17;
  42. pub const CouncilSize: u64 = 3;
  43. pub const MinCandidateStake: u64 = 10;
  44. pub const CandidacyLockId: LockIdentifier = *b"council1";
  45. pub const ElectedMemberLockId: LockIdentifier = *b"council2";
  46. }
  47. impl Trait for Runtime {
  48. type Event = TestEvent;
  49. type Referendum = referendum::Module<RuntimeReferendum, ReferendumInstance>;
  50. type CouncilUserId = <Lock1 as membership::Trait>::MemberId;
  51. type MinNumberOfExtraCandidates = MinNumberOfExtraCandidates;
  52. type CouncilSize = CouncilSize;
  53. type AnnouncingPeriodDuration = AnnouncingPeriodDuration;
  54. type IdlePeriodDuration = IdlePeriodDuration;
  55. type MinCandidateStake = MinCandidateStake;
  56. type CandidacyLock = Lock1;
  57. type ElectedMemberLock = Lock2;
  58. fn is_council_user(
  59. account_id: &<Self as system::Trait>::AccountId,
  60. council_user_id: &Self::CouncilUserId,
  61. ) -> bool {
  62. // all possible generated candidates
  63. account_id == council_user_id
  64. && account_id >= &CANDIDATE_BASE_ID
  65. && account_id < &(CANDIDATE_BASE_ID + VOTER_CANDIDATE_OFFSET)
  66. }
  67. }
  68. /////////////////// Module implementation //////////////////////////////////////
  69. impl_outer_origin! {
  70. pub enum Origin for Runtime {}
  71. }
  72. mod event_mod {
  73. pub use crate::Event;
  74. }
  75. mod referendum_mod {
  76. pub use referendum::Event;
  77. pub use referendum::Instance0;
  78. }
  79. impl_outer_event! {
  80. pub enum TestEvent for Runtime {
  81. event_mod<T>,
  82. system<T>,
  83. }
  84. }
  85. parameter_types! {
  86. pub const BlockHashCount: u64 = 250;
  87. pub const MaximumBlockWeight: u32 = 1024;
  88. pub const MaximumBlockLength: u32 = 2 * 1024;
  89. pub const AvailableBlockRatio: Perbill = Perbill::one();
  90. }
  91. impl system::Trait for Runtime {
  92. type BaseCallFilter = ();
  93. type Origin = Origin;
  94. type Index = u64;
  95. type BlockNumber = u64;
  96. type Call = ();
  97. type Hash = H256;
  98. type Hashing = BlakeTwo256;
  99. type AccountId = u64;
  100. type Lookup = IdentityLookup<Self::AccountId>;
  101. type Header = Header;
  102. type Event = TestEvent;
  103. type BlockHashCount = BlockHashCount;
  104. type MaximumBlockWeight = MaximumBlockWeight;
  105. type DbWeight = ();
  106. type BlockExecutionWeight = ();
  107. type ExtrinsicBaseWeight = ();
  108. type MaximumExtrinsicWeight = ();
  109. type MaximumBlockLength = MaximumBlockLength;
  110. type AvailableBlockRatio = AvailableBlockRatio;
  111. type Version = ();
  112. type ModuleToIndex = ();
  113. type AccountData = balances::AccountData<u64>;
  114. type OnNewAccount = ();
  115. type OnKilledAccount = ();
  116. }
  117. /////////////////// Election module ////////////////////////////////////////////
  118. pub type ReferendumInstance = referendum::Instance0;
  119. thread_local! {
  120. pub static IS_UNSTAKE_ENABLED: RefCell<(bool, )> = RefCell::new((true, )); // global switch for stake locking features; use it to simulate lock fails
  121. pub static IS_OPTION_ID_VALID: RefCell<(bool, )> = RefCell::new((true, )); // global switch used to test is_valid_option_id()
  122. pub static INTERMEDIATE_RESULTS: RefCell<BTreeMap<u64, <<Runtime as Trait>::Referendum as ReferendumManager<<RuntimeReferendum as system::Trait>::Origin, <RuntimeReferendum as system::Trait>::AccountId, <RuntimeReferendum as system::Trait>::Hash>>::VotePower>> = RefCell::new(BTreeMap::<u64,
  123. <<Runtime as Trait>::Referendum as ReferendumManager<<RuntimeReferendum as system::Trait>::Origin, <RuntimeReferendum as system::Trait>::AccountId, <RuntimeReferendum as system::Trait>::Hash>>::VotePower>::new());
  124. }
  125. parameter_types! {
  126. pub const VoteStageDuration: u64 = 19;
  127. pub const RevealStageDuration: u64 = 23;
  128. pub const MinimumStake: u64 = 10000;
  129. pub const MaxSaltLength: u64 = 32; // use some multiple of 8 for ez testing
  130. pub const ReferendumLockId: LockIdentifier = *b"referend";
  131. }
  132. mod balances_mod {
  133. pub use balances::Event;
  134. }
  135. impl_outer_event! {
  136. pub enum TestReferendumEvent for RuntimeReferendum {
  137. referendum_mod Instance0 <T>,
  138. balances_mod<T>,
  139. system<T>,
  140. }
  141. }
  142. #[derive(Clone, PartialEq, Eq, Debug)]
  143. pub struct RuntimeReferendum;
  144. impl referendum::Trait<ReferendumInstance> for RuntimeReferendum {
  145. type Event = TestReferendumEvent;
  146. type MaxSaltLength = MaxSaltLength;
  147. type Currency = balances::Module<Self>;
  148. type LockId = ReferendumLockId;
  149. type ManagerOrigin =
  150. EnsureOneOf<Self::AccountId, EnsureSigned<Self::AccountId>, EnsureRoot<Self::AccountId>>;
  151. type VotePower = u64;
  152. type VoteStageDuration = VoteStageDuration;
  153. type RevealStageDuration = RevealStageDuration;
  154. type MinimumStake = MinimumStake;
  155. fn caclulate_vote_power(
  156. account_id: &<Self as system::Trait>::AccountId,
  157. stake: &Balance<Self, ReferendumInstance>,
  158. ) -> Self::VotePower {
  159. let stake: u64 = u64::from(*stake);
  160. if *account_id == USER_REGULAR_POWER_VOTES {
  161. return stake * POWER_VOTE_STRENGTH;
  162. }
  163. stake
  164. }
  165. fn can_release_voting_stake(
  166. _vote: &CastVote<Self::Hash, Balance<Self, ReferendumInstance>>,
  167. ) -> bool {
  168. // trigger fail when requested to do so
  169. if !IS_UNSTAKE_ENABLED.with(|value| value.borrow().0) {
  170. return false;
  171. }
  172. <Module<Runtime> as ReferendumConnection<Runtime>>::can_release_vote_stake().is_ok()
  173. }
  174. fn process_results(winners: &[OptionResult<Self::VotePower>]) {
  175. let tmp_winners: Vec<OptionResult<Self::VotePower>> = winners
  176. .iter()
  177. .map(|item| OptionResult {
  178. option_id: item.option_id,
  179. vote_power: item.vote_power.into(),
  180. })
  181. .collect();
  182. <Module<Runtime> as ReferendumConnection<Runtime>>::recieve_referendum_results(
  183. tmp_winners.as_slice(),
  184. )
  185. .unwrap();
  186. INTERMEDIATE_RESULTS.with(|value| value.replace(BTreeMap::new()));
  187. }
  188. fn is_valid_option_id(_option_index: &u64) -> bool {
  189. if !IS_OPTION_ID_VALID.with(|value| value.borrow().0) {
  190. return false;
  191. }
  192. true
  193. }
  194. fn get_option_power(option_id: &u64) -> Self::VotePower {
  195. INTERMEDIATE_RESULTS.with(|value| match value.borrow().get(option_id) {
  196. Some(vote_power) => *vote_power,
  197. None => 0,
  198. })
  199. }
  200. fn increase_option_power(option_id: &u64, amount: &Self::VotePower) {
  201. INTERMEDIATE_RESULTS.with(|value| {
  202. let current = Self::get_option_power(option_id);
  203. value.borrow_mut().insert(*option_id, amount + current);
  204. });
  205. }
  206. }
  207. impl system::Trait for RuntimeReferendum {
  208. type BaseCallFilter = ();
  209. type Origin = Origin;
  210. type Index = u64;
  211. type BlockNumber = u64;
  212. type Call = ();
  213. type Hash = H256;
  214. type Hashing = BlakeTwo256;
  215. type AccountId = u64;
  216. type Lookup = IdentityLookup<Self::AccountId>;
  217. type Header = Header;
  218. type Event = TestReferendumEvent;
  219. type BlockHashCount = BlockHashCount;
  220. type MaximumBlockWeight = MaximumBlockWeight;
  221. type DbWeight = ();
  222. type BlockExecutionWeight = ();
  223. type ExtrinsicBaseWeight = ();
  224. type MaximumExtrinsicWeight = ();
  225. type MaximumBlockLength = MaximumBlockLength;
  226. type AvailableBlockRatio = AvailableBlockRatio;
  227. type Version = ();
  228. type ModuleToIndex = ();
  229. type AccountData = balances::AccountData<u64>;
  230. type OnNewAccount = ();
  231. type OnKilledAccount = ();
  232. }
  233. impl balances::Trait for RuntimeReferendum {
  234. type Balance = u64;
  235. type Event = TestReferendumEvent;
  236. type DustRemoval = ();
  237. type ExistentialDeposit = ExistentialDeposit;
  238. type AccountStore = system::Module<Self>;
  239. }
  240. impl Runtime {
  241. pub fn _feature_option_id_valid(is_valid: bool) -> () {
  242. IS_OPTION_ID_VALID.with(|value| {
  243. *value.borrow_mut() = (is_valid,);
  244. });
  245. }
  246. }
  247. parameter_types! {
  248. pub const ExistentialDeposit: u64 = 0;
  249. }
  250. /////////////////// Data structures ////////////////////////////////////////////
  251. #[allow(dead_code)]
  252. #[derive(Clone)]
  253. pub enum OriginType<AccountId> {
  254. Signed(AccountId),
  255. //Inherent, <== did not find how to make such an origin yet
  256. Root,
  257. }
  258. #[derive(Clone)]
  259. pub struct CandidateInfo<T: Trait> {
  260. pub origin: OriginType<T::AccountId>,
  261. pub account_id: T::CouncilUserId,
  262. pub council_user_id: T::CouncilUserId,
  263. pub candidate: CandidateOf<T>,
  264. }
  265. #[derive(Clone)]
  266. pub struct VoterInfo<T: Trait> {
  267. pub origin: OriginType<T::AccountId>,
  268. pub commitment: T::Hash,
  269. pub salt: Vec<u8>,
  270. pub vote_for: u64,
  271. pub stake: BalanceReferendum<T>,
  272. }
  273. #[derive(Clone)]
  274. pub struct CouncilSettings<T: Trait> {
  275. pub council_size: u64,
  276. pub min_candidate_count: u64,
  277. pub min_candidate_stake: BalanceReferendum<T>,
  278. pub announcing_stage_duration: T::BlockNumber,
  279. pub voting_stage_duration: T::BlockNumber,
  280. pub reveal_stage_duration: T::BlockNumber,
  281. pub idle_stage_duration: T::BlockNumber,
  282. }
  283. impl<T: Trait> CouncilSettings<T>
  284. where
  285. T::BlockNumber: From<u64>,
  286. {
  287. pub fn extract_settings() -> CouncilSettings<T> {
  288. let council_size = T::CouncilSize::get();
  289. CouncilSettings {
  290. council_size,
  291. min_candidate_count: council_size + <T as Trait>::MinNumberOfExtraCandidates::get(),
  292. min_candidate_stake: T::MinCandidateStake::get(),
  293. announcing_stage_duration: <T as Trait>::AnnouncingPeriodDuration::get(),
  294. voting_stage_duration:
  295. <RuntimeReferendum as referendum::Trait<ReferendumInstance>>::VoteStageDuration::get().into(),
  296. reveal_stage_duration:
  297. <RuntimeReferendum as referendum::Trait<ReferendumInstance>>::RevealStageDuration::get().into(),
  298. idle_stage_duration: <T as Trait>::IdlePeriodDuration::get(),
  299. }
  300. }
  301. }
  302. #[derive(Clone, PartialEq, Debug)]
  303. pub enum CouncilCycleInterrupt {
  304. BeforeCandidatesAnnounce,
  305. AfterCandidatesAnnounce,
  306. BeforeVoting,
  307. AfterVoting,
  308. BeforeRevealing,
  309. AfterRevealing,
  310. }
  311. #[derive(Clone)]
  312. pub struct CouncilCycleParams<T: Trait> {
  313. pub council_settings: CouncilSettings<T>,
  314. pub cycle_start_block_number: T::BlockNumber,
  315. pub expected_initial_council_members: Vec<CouncilMemberOf<T>>, // council members
  316. pub expected_final_council_members: Vec<CouncilMemberOf<T>>, // council members after cycle finishes
  317. pub candidates_announcing: Vec<CandidateInfo<T>>, // candidates announcing their candidacy
  318. pub expected_candidates: Vec<CandidateOf<T>>, // expected list of candidates after announcement period is over
  319. pub voters: Vec<VoterInfo<T>>, // voters that will participate in council voting
  320. pub interrupt_point: Option<CouncilCycleInterrupt>, // info about when should be cycle interrupted (used to customize the test)
  321. }
  322. /////////////////// Util macros ////////////////////////////////////////////////
  323. macro_rules! escape_checkpoint {
  324. ($item:expr, $expected_value:expr) => {
  325. if $item == $expected_value {
  326. return;
  327. }
  328. };
  329. ($item:expr, $expected_value:expr, $return_value:expr) => {
  330. if $item == $expected_value {
  331. return $c;
  332. }
  333. };
  334. }
  335. /////////////////// Utility mocks //////////////////////////////////////////////
  336. pub fn default_genesis_config() -> GenesisConfig<Runtime> {
  337. GenesisConfig::<Runtime> {
  338. stage: CouncilStageUpdate::default(),
  339. council_members: vec![],
  340. candidates: vec![],
  341. current_cycle_candidates_order: vec![],
  342. current_announcement_cycle_id: 0,
  343. }
  344. }
  345. pub fn build_test_externalities(config: GenesisConfig<Runtime>) -> sp_io::TestExternalities {
  346. let mut t = system::GenesisConfig::default()
  347. .build_storage::<Runtime>()
  348. .unwrap();
  349. config.assimilate_storage(&mut t).unwrap();
  350. let mut result = Into::<sp_io::TestExternalities>::into(t.clone());
  351. // Make sure we are not in block 1 where no events are emitted - see https://substrate.dev/recipes/2-appetizers/4-events.html#emitting-events
  352. result.execute_with(|| InstanceMockUtils::<Runtime>::increase_block_number(1));
  353. result
  354. }
  355. pub struct InstanceMockUtils<T: Trait> {
  356. _dummy: PhantomData<T>, // 0-sized data meant only to bound generic parameters
  357. }
  358. impl<T: Trait> InstanceMockUtils<T>
  359. where
  360. T::AccountId: From<u64>,
  361. T::CouncilUserId: From<u64>,
  362. T::BlockNumber: From<u64> + Into<u64>,
  363. BalanceReferendum<T>: From<u64> + Into<u64>,
  364. {
  365. pub fn mock_origin(origin: OriginType<T::AccountId>) -> T::Origin {
  366. match origin {
  367. OriginType::Signed(account_id) => T::Origin::from(RawOrigin::Signed(account_id)),
  368. OriginType::Root => RawOrigin::Root.into(),
  369. //_ => panic!("not implemented"),
  370. }
  371. }
  372. pub fn increase_block_number(increase: u64) -> () {
  373. let block_number = system::Module::<T>::block_number();
  374. for i in 0..increase {
  375. let tmp_index: T::BlockNumber = block_number + i.into();
  376. <Module<T> as OnFinalize<T::BlockNumber>>::on_finalize(tmp_index);
  377. <referendum::Module<RuntimeReferendum, ReferendumInstance> as OnFinalize<
  378. <RuntimeReferendum as system::Trait>::BlockNumber,
  379. >>::on_finalize(tmp_index.into());
  380. system::Module::<T>::set_block_number(tmp_index + 1.into());
  381. }
  382. }
  383. // topup currency to the account
  384. fn topup_account(account_id: u64, amount: BalanceReferendum<T>) {
  385. let _ = balances::Module::<RuntimeReferendum>::deposit_creating(
  386. &account_id,
  387. amount.into(),
  388. );
  389. }
  390. pub fn generate_candidate(
  391. index: u64,
  392. stake: BalanceReferendum<T>,
  393. order_index: u64,
  394. ) -> CandidateInfo<T> {
  395. let account_id = CANDIDATE_BASE_ID + index;
  396. let origin = OriginType::Signed(account_id.into());
  397. let candidate = CandidateOf::<T> {
  398. account_id: account_id.into(),
  399. cycle_id: CurrentAnnouncementCycleId::get(),
  400. order_index,
  401. stake,
  402. };
  403. Self::topup_account(account_id.into(), stake);
  404. CandidateInfo {
  405. origin,
  406. candidate,
  407. council_user_id: account_id.into(),
  408. account_id: account_id.into(),
  409. }
  410. }
  411. pub fn generate_voter(
  412. index: u64,
  413. stake: BalanceReferendum<T>,
  414. vote_for_index: u64,
  415. ) -> VoterInfo<T> {
  416. let account_id = VOTER_BASE_ID + index;
  417. let origin = OriginType::Signed(account_id.into());
  418. let (commitment, salt) = Self::vote_commitment(&account_id.into(), &vote_for_index.into());
  419. Self::topup_account(account_id.into(), stake);
  420. VoterInfo {
  421. origin,
  422. commitment,
  423. salt,
  424. vote_for: vote_for_index,
  425. stake,
  426. }
  427. }
  428. pub fn generate_salt() -> Vec<u8> {
  429. let mut rng = rand::thread_rng();
  430. rng.gen::<u64>().to_be_bytes().to_vec()
  431. }
  432. pub fn vote_commitment(
  433. account_id: &<T as system::Trait>::AccountId,
  434. vote_option_index: &u64,
  435. ) -> (T::Hash, Vec<u8>) {
  436. let cycle_id = CurrentCycleId::<ReferendumInstance>::get();
  437. let salt = Self::generate_salt();
  438. (
  439. T::Referendum::calculate_commitment(account_id, &salt, &cycle_id, vote_option_index),
  440. salt.to_vec(),
  441. )
  442. }
  443. }
  444. /////////////////// Mocks of Module's actions //////////////////////////////////
  445. pub struct InstanceMocks<T: Trait> {
  446. _dummy: PhantomData<T>, // 0-sized data meant only to bound generic parameters
  447. }
  448. impl<T: Trait> InstanceMocks<T>
  449. where
  450. T::AccountId: From<u64>,
  451. T::CouncilUserId: From<u64>,
  452. T::BlockNumber: From<u64> + Into<u64>,
  453. BalanceReferendum<T>: From<u64> + Into<u64>,
  454. T::Hash: From<<RuntimeReferendum as system::Trait>::Hash>
  455. + Into<<RuntimeReferendum as system::Trait>::Hash>,
  456. T::Origin: From<<RuntimeReferendum as system::Trait>::Origin>
  457. + Into<<RuntimeReferendum as system::Trait>::Origin>,
  458. <T::Referendum as ReferendumManager<T::Origin, T::AccountId, T::Hash>>::VotePower:
  459. From<u64> + Into<u64>,
  460. {
  461. pub fn check_announcing_period(
  462. expected_update_block_number: T::BlockNumber,
  463. expected_state: CouncilStageAnnouncing,
  464. ) -> () {
  465. // check stage is in proper state
  466. assert_eq!(
  467. Stage::<T>::get(),
  468. CouncilStageUpdateOf::<T> {
  469. stage: CouncilStage::Announcing(expected_state),
  470. changed_at: expected_update_block_number,
  471. },
  472. );
  473. }
  474. pub fn check_election_period(
  475. expected_update_block_number: T::BlockNumber,
  476. expected_state: CouncilStageElection,
  477. ) -> () {
  478. // check stage is in proper state
  479. assert_eq!(
  480. Stage::<T>::get(),
  481. CouncilStageUpdateOf::<T> {
  482. stage: CouncilStage::Election(expected_state),
  483. changed_at: expected_update_block_number,
  484. },
  485. );
  486. }
  487. pub fn check_idle_period(expected_update_block_number: T::BlockNumber) -> () {
  488. // check stage is in proper state
  489. assert_eq!(
  490. Stage::<T>::get(),
  491. CouncilStageUpdateOf::<T> {
  492. stage: CouncilStage::Idle,
  493. changed_at: expected_update_block_number,
  494. },
  495. );
  496. }
  497. pub fn check_council_members(expect_members: Vec<CouncilMemberOf<T>>) -> () {
  498. // check stage is in proper state
  499. assert_eq!(CouncilMembers::<T>::get(), expect_members,);
  500. }
  501. pub fn check_referendum_revealing(
  502. // candidate_count: u64,
  503. winning_target_count: u64,
  504. intermediate_winners: Vec<
  505. OptionResult<
  506. <T::Referendum as ReferendumManager<T::Origin, T::AccountId, T::Hash>>::VotePower,
  507. >,
  508. >,
  509. intermediate_results: BTreeMap<
  510. u64,
  511. <T::Referendum as ReferendumManager<T::Origin, T::AccountId, T::Hash>>::VotePower,
  512. >,
  513. expected_update_block_number: T::BlockNumber,
  514. ) {
  515. // check stage is in proper state
  516. assert_eq!(
  517. referendum::Stage::<RuntimeReferendum, ReferendumInstance>::get(),
  518. ReferendumStage::Revealing(ReferendumStageRevealing {
  519. winning_target_count,
  520. started: expected_update_block_number.into(),
  521. intermediate_winners: intermediate_winners
  522. .iter()
  523. .map(|item| OptionResult {
  524. option_id: item.option_id,
  525. vote_power: item.vote_power.into(),
  526. })
  527. .collect(),
  528. }),
  529. );
  530. INTERMEDIATE_RESULTS.with(|value| {
  531. assert_eq!(
  532. *value.borrow(),
  533. intermediate_results
  534. .iter()
  535. .map(|(key, value)| (*key, value.clone().into()))
  536. .collect(),
  537. )
  538. });
  539. }
  540. pub fn announce_candidacy(
  541. origin: OriginType<T::AccountId>,
  542. member_id: T::CouncilUserId,
  543. stake: BalanceReferendum<T>,
  544. expected_result: Result<(), Error<T>>,
  545. ) {
  546. // check method returns expected result
  547. assert_eq!(
  548. Module::<T>::announce_candidacy(
  549. InstanceMockUtils::<T>::mock_origin(origin),
  550. member_id,
  551. stake
  552. ),
  553. expected_result,
  554. );
  555. }
  556. pub fn vote_for_candidate(
  557. origin: OriginType<T::AccountId>,
  558. commitment: T::Hash,
  559. stake: BalanceReferendum<T>,
  560. expected_result: Result<(), ()>,
  561. ) -> () {
  562. // check method returns expected result
  563. assert_eq!(
  564. referendum::Module::<RuntimeReferendum, ReferendumInstance>::vote(
  565. InstanceMockUtils::<T>::mock_origin(origin).into(),
  566. commitment.into(),
  567. stake.into(),
  568. )
  569. .is_ok(),
  570. expected_result.is_ok(),
  571. );
  572. }
  573. pub fn reveal_vote(
  574. origin: OriginType<T::AccountId>,
  575. salt: Vec<u8>,
  576. vote_option: u64,
  577. //expected_result: Result<(), referendum::Error<T, ReferendumInstance>>,
  578. expected_result: Result<(), ()>,
  579. ) -> () {
  580. // check method returns expected result
  581. assert_eq!(
  582. referendum::Module::<RuntimeReferendum, ReferendumInstance>::reveal_vote(
  583. InstanceMockUtils::<T>::mock_origin(origin).into(),
  584. salt,
  585. vote_option,
  586. )
  587. .is_ok(),
  588. expected_result.is_ok(),
  589. );
  590. }
  591. /// simulate one council's election cycle
  592. pub fn simulate_council_cycle(params: CouncilCycleParams<T>) {
  593. let settings = params.council_settings;
  594. // check initial council members
  595. Self::check_council_members(params.expected_initial_council_members.clone());
  596. // start announcing
  597. Self::check_announcing_period(
  598. params.cycle_start_block_number,
  599. CouncilStageAnnouncing {
  600. candidates_count: 0,
  601. },
  602. );
  603. escape_checkpoint!(
  604. params.interrupt_point.clone(),
  605. Some(CouncilCycleInterrupt::BeforeCandidatesAnnounce)
  606. );
  607. // announce candidacy for each candidate
  608. params.candidates_announcing.iter().for_each(|candidate| {
  609. Self::announce_candidacy(
  610. candidate.origin.clone(),
  611. candidate.account_id.clone(),
  612. settings.min_candidate_stake,
  613. Ok(()),
  614. );
  615. });
  616. escape_checkpoint!(
  617. params.interrupt_point.clone(),
  618. Some(CouncilCycleInterrupt::AfterCandidatesAnnounce)
  619. );
  620. // forward to election-voting period
  621. InstanceMockUtils::<T>::increase_block_number(
  622. settings.announcing_stage_duration.into() + 1,
  623. );
  624. // finish announcing period / start referendum -> will cause period prolongement
  625. Self::check_election_period(
  626. params.cycle_start_block_number + settings.announcing_stage_duration,
  627. CouncilStageElection {
  628. candidates_count: params.expected_candidates.len() as u64,
  629. },
  630. );
  631. escape_checkpoint!(
  632. params.interrupt_point.clone(),
  633. Some(CouncilCycleInterrupt::BeforeVoting)
  634. );
  635. // vote with all voters
  636. params.voters.iter().for_each(|voter| {
  637. Self::vote_for_candidate(
  638. voter.origin.clone(),
  639. voter.commitment.clone(),
  640. voter.stake.clone(),
  641. Ok(()),
  642. )
  643. });
  644. escape_checkpoint!(
  645. params.interrupt_point.clone(),
  646. Some(CouncilCycleInterrupt::AfterVoting)
  647. );
  648. // forward to election-revealing period
  649. InstanceMockUtils::<T>::increase_block_number(settings.voting_stage_duration.into() + 1);
  650. // referendum - start revealing period
  651. Self::check_referendum_revealing(
  652. settings.council_size,
  653. vec![],
  654. BTreeMap::new(), //<u64, T::VotePower>,
  655. params.cycle_start_block_number
  656. + settings.announcing_stage_duration
  657. + settings.voting_stage_duration,
  658. );
  659. escape_checkpoint!(
  660. params.interrupt_point.clone(),
  661. Some(CouncilCycleInterrupt::BeforeRevealing)
  662. );
  663. // reveal vote for all voters
  664. params.voters.iter().for_each(|voter| {
  665. Self::reveal_vote(
  666. voter.origin.clone(),
  667. voter.salt.clone(),
  668. voter.vote_for,
  669. Ok(()),
  670. );
  671. });
  672. escape_checkpoint!(
  673. params.interrupt_point.clone(),
  674. Some(CouncilCycleInterrupt::AfterRevealing)
  675. );
  676. // finish election / start idle period
  677. InstanceMockUtils::<T>::increase_block_number(settings.reveal_stage_duration.into() + 1);
  678. Self::check_idle_period(
  679. params.cycle_start_block_number
  680. + settings.reveal_stage_duration
  681. + settings.announcing_stage_duration
  682. + settings.voting_stage_duration,
  683. );
  684. Self::check_council_members(params.expected_final_council_members.clone());
  685. }
  686. }