From 53838aa4a2375982528bd15c01e11977e928dfdf Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Mon, 24 Feb 2020 17:03:46 +0800 Subject: [PATCH 1/2] update: ready for staking tests --- Cargo.lock | 2 + bin/node/runtime/src/constants.rs | 1 + frame/staking/Cargo.toml | 4 +- frame/staking/src/lib.rs | 2 +- frame/staking/src/mock.rs | 242 +- frame/staking/src/tests.rs | 5390 ++++++++++++++--------------- frame/support/src/lib.rs | 9 +- 7 files changed, 2838 insertions(+), 2812 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e36800b8..7e108dd5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1057,6 +1057,7 @@ dependencies = [ name = "darwinia-staking" version = "0.4.0" dependencies = [ + "darwinia-kton", "darwinia-phragmen", "darwinia-ring", "darwinia-support", @@ -1064,6 +1065,7 @@ dependencies = [ "frame-system", "pallet-authorship", "pallet-session", + "pallet-timestamp", "parity-scale-codec", "safe-mix", "serde", diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs index 9fa653816..10726cbdb 100644 --- a/bin/node/runtime/src/constants.rs +++ b/bin/node/runtime/src/constants.rs @@ -31,6 +31,7 @@ pub mod time { use node_primitives::{BlockNumber, Moment}; use sp_staking::SessionIndex; + // TODO doc include!(concat!(env!("OUT_DIR"), "/timestamp_now.rs")); pub const GENESIS_TIME: Moment = NOW; diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 5cf0ac10c..93ab2e2c3 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -28,8 +28,10 @@ darwinia-support = { default-features = false, path = "../support" } [dev-dependencies] substrate-test-utils = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git", tag = "pre-v2.0-3e65111" } +pallet-timestamp = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git", tag = "pre-v2.0-3e65111" } -darwinia-ring = { path = "../../frame/balances/ring" } +pallet-ring = { package = "darwinia-ring", path = "../../frame/balances/ring" } +pallet-kton = { package = "darwinia-kton", path = "../../frame/balances/kton" } [features] equalize = [] diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 99155f5f6..9d607cdd3 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -124,7 +124,7 @@ //! ``` //! use frame_support::{decl_module, dispatch}; //! use frame_system::{self as system, ensure_signed}; -//! use pallet_staking::{self as staking}; +//! use darwinia_staking::{self as staking}; //! //! pub trait Trait: staking::Trait {} //! diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b4560e054..94a56d2d9 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -1,6 +1,10 @@ //! Test utilities -use std::{cell::RefCell, collections::HashSet}; +use std::{ + cell::RefCell, + collections::HashSet, + time::{SystemTime, UNIX_EPOCH}, +}; use frame_support::{ assert_ok, impl_outer_origin, parameter_types, @@ -11,9 +15,8 @@ use frame_support::{ use sp_core::{crypto::key_types, H256}; use sp_io; use sp_runtime::{ - curve::PiecewiseLinear, testing::{Header, UintAuthorityId}, - traits::{Convert, IdentityLookup, OnInitialize, OpaqueKeys, SaturatedConversion}, + traits::{IdentityLookup, OnInitialize, OpaqueKeys, SaturatedConversion}, {KeyTypeId, Perbill}, }; use sp_staking::{ @@ -23,27 +26,29 @@ use sp_staking::{ use crate::*; -/// The AccountId alias in this test module. pub type AccountId = u64; pub type BlockNumber = u64; pub type Balance = u64; -/// Simple structure that exposes how u64 currency can be represented as... u64. -pub struct CurrencyToVoteHandler; -impl Convert for CurrencyToVoteHandler { - fn convert(x: u64) -> u64 { - x - } -} -impl Convert for CurrencyToVoteHandler { - fn convert(x: u128) -> u64 { - x.saturated_into() - } -} +pub type System = system::Module; +pub type Session = pallet_session::Module; +pub type Timestamp = pallet_timestamp::Module; + +pub type Ring = pallet_ring::Module; +pub type Kton = pallet_kton::Module; +pub type Staking = Module; + +pub const NANO: Balance = 1; +pub const MICRO: Balance = 1_000 * NANO; +pub const MILLI: Balance = 1_000 * MICRO; +pub const COIN: Balance = 1_000 * MILLI; + +pub const CAP: Balance = 1_000_000_000 * COIN; +pub const TOTAL_POWER: Power = 1_000_000_000; thread_local! { static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); - static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); static SLASH_DEFER_DURATION: RefCell = RefCell::new(0); } @@ -76,8 +81,8 @@ pub fn is_disabled(controller: AccountId) -> bool { } pub struct ExistentialDeposit; -impl Get for ExistentialDeposit { - fn get() -> u64 { +impl Get for ExistentialDeposit { + fn get() -> Balance { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) } } @@ -115,9 +120,9 @@ parameter_types! { } impl system::Trait for Test { type Origin = Origin; + type Call = (); type Index = u64; type BlockNumber = BlockNumber; - type Call = (); type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; @@ -126,8 +131,8 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; - type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; type Version = (); type ModuleToIndex = (); } @@ -135,17 +140,25 @@ parameter_types! { pub const TransferFee: Balance = 0; pub const CreationFee: Balance = 0; } -impl pallet_balances::Trait for Test { +impl pallet_ring::Trait for Test { type Balance = Balance; type OnFreeBalanceZero = Staking; type OnNewAccount = (); - type Event = (); type TransferPayment = (); type DustRemoval = (); + type Event = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; } +impl pallet_kton::Trait for Test { + type Balance = Balance; + type Event = (); + type RingCurrency = Ring; + type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; +} parameter_types! { pub const Period: BlockNumber = 1; pub const Offset: BlockNumber = 0; @@ -153,20 +166,20 @@ parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(25); } impl pallet_session::Trait for Test { - type OnSessionEnding = pallet_session::historical::NoteHistoricalRoot; - type Keys = UintAuthorityId; - type ShouldEndSession = pallet_session::PeriodicSessions; - type SessionHandler = TestSessionHandler; type Event = (); type ValidatorId = AccountId; - type ValidatorIdOf = crate::StashOf; - type SelectInitialValidators = Staking; + type ValidatorIdOf = StashOf; + type ShouldEndSession = pallet_session::PeriodicSessions; + type OnSessionEnding = pallet_session::historical::NoteHistoricalRoot; + type SessionHandler = TestSessionHandler; + type Keys = UintAuthorityId; type DisabledValidatorsThreshold = DisabledValidatorsThreshold; + type SelectInitialValidators = Staking; } impl pallet_session::historical::Trait for Test { - type FullIdentification = crate::Exposure; - type FullIdentificationOf = crate::ExposureOf; + type FullIdentification = Exposure; + type FullIdentificationOf = ExposureOf; } impl pallet_authorship::Trait for Test { type FindAuthor = Author11; @@ -182,39 +195,39 @@ impl pallet_timestamp::Trait for Test { type OnTimestampSet = (); type MinimumPeriod = MinimumPeriod; } -pallet_staking_reward_curve::build! { - const I_NPOS: PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} parameter_types! { pub const SessionsPerEra: SessionIndex = 3; - pub const BondingDuration: EraIndex = 3; - pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; + pub const BondingDurationInEra: EraIndex = 3; + // assume 60 blocks per session + pub const BondingDurationInBlockNumber: BlockNumber = 3 * 3 * 60; + + pub const Cap: Balance = CAP; + pub const TotalPower: Power = TOTAL_POWER; + pub const GenesisTime: Moment = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as _; } impl Trait for Test { - type Currency = pallet_balances::Module; type Time = pallet_timestamp::Module; - type CurrencyToVote = CurrencyToVoteHandler; - type RewardRemainder = (); type Event = (); - type Slash = (); - type Reward = (); type SessionsPerEra = SessionsPerEra; + type BondingDurationInEra = (); + type BondingDurationInBlockNumber = (); type SlashDeferDuration = SlashDeferDuration; type SlashCancelOrigin = system::EnsureRoot; - type BondingDuration = BondingDuration; type SessionInterface = Self; - type RewardCurve = RewardCurve; + type RingCurrency = Ring; + type RingRewardRemainder = (); + type RingSlash = (); + type RingReward = (); + type KtonCurrency = Kton; + type KtonSlash = (); + type KtonReward = (); + type Cap = Cap; + type TotalPower = TotalPower; + type GenesisTime = GenesisTime; } pub struct ExtBuilder { - existential_deposit: u64, + existential_deposit: Balance, validator_pool: bool, nominate: bool, validator_count: u32, @@ -222,7 +235,7 @@ pub struct ExtBuilder { slash_defer_duration: EraIndex, fair: bool, num_validators: Option, - invulnerables: Vec, + invulnerables: Vec, } impl Default for ExtBuilder { @@ -242,7 +255,7 @@ impl Default for ExtBuilder { } impl ExtBuilder { - pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { + pub fn existential_deposit(mut self, existential_deposit: Balance) -> Self { self.existential_deposit = existential_deposit; self } @@ -274,7 +287,7 @@ impl ExtBuilder { self.num_validators = Some(num_validators); self } - pub fn invulnerables(mut self, invulnerables: Vec) -> Self { + pub fn invulnerables(mut self, invulnerables: Vec) -> Self { self.invulnerables = invulnerables; self } @@ -292,7 +305,29 @@ impl ExtBuilder { .map(|x| ((x + 1) * 10 + 1) as u64) .collect::>(); - let _ = pallet_balances::GenesisConfig:: { + let _ = pallet_ring::GenesisConfig:: { + balances: vec![ + (1, 10 * balance_factor), + (2, 20 * balance_factor), + (3, 300 * balance_factor), + (4, 400 * balance_factor), + (10, balance_factor), + (11, balance_factor * 1000), + (20, balance_factor), + (21, balance_factor * 2000), + (30, balance_factor), + (31, balance_factor * 2000), + (40, balance_factor), + (41, balance_factor * 2000), + (100, 2000 * balance_factor), + (101, 2000 * balance_factor), + // This allow us to have a total_payout different from 0. + (999, 1_000_000_000_000), + ], + vesting: vec![], + } + .assimilate_storage(&mut storage); + let _ = pallet_kton::GenesisConfig:: { balances: vec![ (1, 10 * balance_factor), (2, 20 * balance_factor), @@ -361,12 +396,6 @@ impl ExtBuilder { } } -pub type System = system::Module; -pub type Balances = pallet_balances::Module; -pub type Session = pallet_session::Module; -pub type Timestamp = pallet_timestamp::Module; -pub type Staking = Module; - pub fn check_exposure_all() { Staking::current_elected() .into_iter() @@ -378,73 +407,70 @@ pub fn check_nominator_all() { } /// Check for each selected validator: expo.total = Sum(expo.other) + expo.own -pub fn check_exposure(stash: u64) { +pub fn check_exposure(stash: AccountId) { assert_is_stash(stash); let expo = Staking::stakers(&stash); - assert_eq!( - expo.total as u128, - expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), - "wrong total exposure for {:?}: {:?}", - stash, - expo, - ); + // assert_eq!( + // expo.total as u128, + // expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), + // "wrong total exposure for {:?}: {:?}", + // stash, + // expo, + // ); } /// Check that for each nominator: slashable_balance > sum(used_balance) /// Note: we might not consume all of a nominator's balance, but we MUST NOT over spend it. -pub fn check_nominator_exposure(stash: u64) { +pub fn check_nominator_exposure(stash: AccountId) { assert_is_stash(stash); let mut sum = 0; - Staking::current_elected() - .iter() - .map(|v| Staking::stakers(v)) - .for_each(|e| e.others.iter().filter(|i| i.who == stash).for_each(|i| sum += i.value)); - let nominator_stake = Staking::slashable_balance_of(&stash); - // a nominator cannot over-spend. - assert!( - nominator_stake >= sum, - "failed: Nominator({}) stake({}) >= sum divided({})", - stash, - nominator_stake, - sum, - ); -} - -pub fn assert_is_stash(acc: u64) { + // Staking::current_elected() + // .iter() + // .map(|v| Staking::stakers(v)) + // .for_each(|e| e.others.iter().filter(|i| i.who == stash).for_each(|i| sum += i.value)); + // let nominator_stake = Staking::slashable_balance_of(&stash); + // // a nominator cannot over-spend. + // assert!( + // nominator_stake >= sum, + // "failed: Nominator({}) stake({}) >= sum divided({})", + // stash, + // nominator_stake, + // sum, + // ); +} + +pub fn assert_is_stash(acc: AccountId) { assert!(Staking::bonded(&acc).is_some(), "Not a stash."); } -pub fn assert_ledger_consistent(stash: u64) { - assert_is_stash(stash); - let ledger = Staking::ledger(stash - 1).unwrap(); - - let real_total: Balance = ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value); - assert_eq!(real_total, ledger.total); -} - -pub fn bond_validator(acc: u64, val: u64) { +pub fn bond(acc: AccountId, val: StakingBalanceT) { // a = controller // a + 1 = stash - let _ = Balances::make_free_balance_be(&(acc + 1), val); + match val { + StakingBalance::RingBalance(r) => { + let _ = Ring::make_free_balance_be(&(acc + 1), r); + } + StakingBalance::KtonBalance(k) => { + let _ = Kton::make_free_balance_be(&(acc + 1), k); + } + _ => return, + } assert_ok!(Staking::bond( Origin::signed(acc + 1), acc, val, - RewardDestination::Controller + RewardDestination::Controller, + 0, )); +} + +pub fn bond_validator(acc: AccountId, val: StakingBalanceT) { + bond(acc, val); assert_ok!(Staking::validate(Origin::signed(acc), ValidatorPrefs::default())); } -pub fn bond_nominator(acc: u64, val: u64, target: Vec) { - // a = controller - // a + 1 = stash - let _ = Balances::make_free_balance_be(&(acc + 1), val); - assert_ok!(Staking::bond( - Origin::signed(acc + 1), - acc, - val, - RewardDestination::Controller - )); +pub fn bond_nominator(acc: AccountId, val: StakingBalanceT, target: Vec) { + bond(acc, val); assert_ok!(Staking::nominate(Origin::signed(acc), target)); } @@ -501,7 +527,7 @@ pub fn on_offence_in_era( slash_fraction: &[Perbill], era: EraIndex, ) { - let bonded_eras = crate::BondedEras::get(); + let bonded_eras = BondedEras::get(); for &(bonded_era, start_session) in bonded_eras.iter() { if bonded_era == era { Staking::on_offence(offenders, slash_fraction, start_session); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 2425e57bd..9b49d4fc3 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1,2703 +1,2691 @@ //! Tests for the module. -use super::*; -use frame_support::{ - assert_noop, assert_ok, - dispatch::DispatchError, - traits::{Currency, ReservableCurrency}, -}; -use mock::*; -use sp_runtime::{ - assert_eq_error_rate, - traits::{BadOrigin, OnInitialize}, -}; -use sp_staking::offence::OffenceDetails; -use substrate_test_utils::assert_eq_uvec; - -#[test] -fn force_unstake_works() { - // Verifies initial conditions of mock - ExtBuilder::default().build().execute_with(|| { - // Account 11 is stashed and locked, and account 10 is the controller - assert_eq!(Staking::bonded(&11), Some(10)); - // Cant transfer - assert_noop!( - Balances::transfer(Origin::signed(11), 1, 10), - DispatchError::Module { - index: 0, - error: 1, - message: Some("LiquidityRestrictions"), - } - ); - // Force unstake requires root. - assert_noop!(Staking::force_unstake(Origin::signed(11), 11), BadOrigin); - // We now force them to unstake - assert_ok!(Staking::force_unstake(Origin::ROOT, 11)); - // No longer bonded. - assert_eq!(Staking::bonded(&11), None); - // Transfer works. - assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); - }); -} - -#[test] -fn basic_setup_works() { - // Verifies initial conditions of mock - ExtBuilder::default().build().execute_with(|| { - // Account 11 is stashed and locked, and account 10 is the controller - assert_eq!(Staking::bonded(&11), Some(10)); - // Account 21 is stashed and locked, and account 20 is the controller - assert_eq!(Staking::bonded(&21), Some(20)); - // Account 1 is not a stashed - assert_eq!(Staking::bonded(&1), None); - - // Account 10 controls the stash from account 11, which is 100 * balance_factor units - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: vec![] - }) - ); - // Account 20 controls the stash from account 21, which is 200 * balance_factor units - assert_eq!( - Staking::ledger(&20), - Some(StakingLedger { - stash: 21, - total: 1000, - active: 1000, - unlocking: vec![] - }) - ); - // Account 1 does not control any stash - assert_eq!(Staking::ledger(&1), None); - - // ValidatorPrefs are default - assert_eq!( - >::enumerate().collect::>(), - vec![ - (31, ValidatorPrefs::default()), - (21, ValidatorPrefs::default()), - (11, ValidatorPrefs::default()) - ] - ); - - assert_eq!( - Staking::ledger(100), - Some(StakingLedger { - stash: 101, - total: 500, - active: 500, - unlocking: vec![] - }) - ); - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - - if cfg!(feature = "equalize") { - assert_eq!( - Staking::stakers(11), - Exposure { - total: 1250, - own: 1000, - others: vec![IndividualExposure { who: 101, value: 250 }] - } - ); - assert_eq!( - Staking::stakers(21), - Exposure { - total: 1250, - own: 1000, - others: vec![IndividualExposure { who: 101, value: 250 }] - } - ); - // initial slot_stake - assert_eq!(Staking::slot_stake(), 1250); - } else { - assert_eq!( - Staking::stakers(11), - Exposure { - total: 1125, - own: 1000, - others: vec![IndividualExposure { who: 101, value: 125 }] - } - ); - assert_eq!( - Staking::stakers(21), - Exposure { - total: 1375, - own: 1000, - others: vec![IndividualExposure { who: 101, value: 375 }] - } - ); - // initial slot_stake - assert_eq!(Staking::slot_stake(), 1125); - } - - // The number of validators required. - assert_eq!(Staking::validator_count(), 2); - - // Initial Era and session - assert_eq!(Staking::current_era(), 0); - - // Account 10 has `balance_factor` free balance - assert_eq!(Balances::free_balance(&10), 1); - assert_eq!(Balances::free_balance(&10), 1); - - // New era is not being forced - assert_eq!(Staking::force_era(), Forcing::NotForcing); - - // All exposures must be correct. - check_exposure_all(); - check_nominator_all(); - }); -} - -#[test] -fn change_controller_works() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Staking::bonded(&11), Some(10)); - - assert!(>::enumerate() - .map(|(c, _)| c) - .collect::>() - .contains(&11)); - // 10 can control 11 who is initially a validator. - assert_ok!(Staking::chill(Origin::signed(10))); - assert!(!>::enumerate() - .map(|(c, _)| c) - .collect::>() - .contains(&11)); - - assert_ok!(Staking::set_controller(Origin::signed(11), 5)); - - start_era(1); - - assert_noop!( - Staking::validate(Origin::signed(10), ValidatorPrefs::default()), - Error::::NotController, - ); - assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default())); - }) -} - -#[test] -fn rewards_should_work() { - // should check that: - // * rewards get recorded per session - // * rewards get paid per Era - // * Check that nominators are also rewarded - ExtBuilder::default().nominate(false).build().execute_with(|| { - // Init some balances - let _ = Balances::make_free_balance_be(&2, 500); - - let delay = 1000; - let init_balance_2 = Balances::total_balance(&2); - let init_balance_10 = Balances::total_balance(&10); - let init_balance_11 = Balances::total_balance(&11); - - // Set payee to controller - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - - // Initial config should be correct - assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::current_index(), 0); - - // Add a dummy nominator. - // - // Equal division indicates that the reward will be equally divided among validator and - // nominator. - >::insert( - &11, - Exposure { - own: 500, - total: 1000, - others: vec![IndividualExposure { who: 2, value: 500 }], - }, - ); - - >::insert(&2, RewardDestination::Stash); - assert_eq!(Staking::payee(2), RewardDestination::Stash); - assert_eq!(Staking::payee(11), RewardDestination::Controller); - - let mut block = 3; // Block 3 => Session 1 => Era 0 - System::set_block_number(block); - Timestamp::set_timestamp(block * 5000); // on time. - Session::on_initialize(System::block_number()); - assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::current_index(), 1); - >::reward_by_ids(vec![(11, 50)]); - >::reward_by_ids(vec![(11, 50)]); - // This is the second validator of the current elected set. - >::reward_by_ids(vec![(21, 50)]); - // This must be no-op as it is not an elected validator. - >::reward_by_ids(vec![(1001, 10_000)]); - - // Compute total payout now for whole duration as other parameter won't change - let total_payout = current_total_payout_for_duration(9 * 5 * 1000); - assert!(total_payout > 10); // Test is meaningful if reward something - - // No reward yet - assert_eq!(Balances::total_balance(&2), init_balance_2); - assert_eq!(Balances::total_balance(&10), init_balance_10); - assert_eq!(Balances::total_balance(&11), init_balance_11); - - block = 6; // Block 6 => Session 2 => Era 0 - System::set_block_number(block); - Timestamp::set_timestamp(block * 5000 + delay); // a little late. - Session::on_initialize(System::block_number()); - assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::current_index(), 2); - - block = 9; // Block 9 => Session 3 => Era 1 - System::set_block_number(block); - Timestamp::set_timestamp(block * 5000); // back to being on time. no delays - Session::on_initialize(System::block_number()); - assert_eq!(Staking::current_era(), 1); - assert_eq!(Session::current_index(), 3); - - // 11 validator has 2/3 of the total rewards and half half for it and its nominator - assert_eq_error_rate!(Balances::total_balance(&2), init_balance_2 + total_payout / 3, 1); - assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + total_payout / 3, 1); - assert_eq!(Balances::total_balance(&11), init_balance_11); - }); -} - -#[test] -fn multi_era_reward_should_work() { - // Should check that: - // The value of current_session_reward is set at the end of each era, based on - // slot_stake and session_reward. - ExtBuilder::default().nominate(false).build().execute_with(|| { - let init_balance_10 = Balances::total_balance(&10); - - // Set payee to controller - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - - // Compute now as other parameter won't change - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 10); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - - start_session(0); - start_session(1); - start_session(2); - start_session(3); - - assert_eq!(Staking::current_era(), 1); - assert_eq!(Balances::total_balance(&10), init_balance_10 + total_payout_0); - - start_session(4); - - let total_payout_1 = current_total_payout_for_duration(3000); - assert!(total_payout_1 > 10); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 101)]); - - // new era is triggered here. - start_session(5); - - // pay time - assert_eq!( - Balances::total_balance(&10), - init_balance_10 + total_payout_0 + total_payout_1 - ); - }); -} - -#[test] -fn staking_should_work() { - // should test: - // * new validators can be added to the default set - // * new ones will be chosen per era - // * either one can unlock the stash and back-down from being a validator via `chill`ing. - ExtBuilder::default() - .nominate(false) - .fair(false) // to give 20 more staked value - .build() - .execute_with(|| { - Timestamp::set_timestamp(1); // Initialize time. - - // remember + compare this along with the test. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // put some money in account that we'll use. - for i in 1..5 { - let _ = Balances::make_free_balance_be(&i, 2000); - } - - // --- Block 1: - start_session(1); - // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); - - // No effects will be seen so far. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // --- Block 2: - start_session(2); - - // No effects will be seen so far. Era has not been yet triggered. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // --- Block 3: the validators will now be queued. - start_session(3); - assert_eq!(Staking::current_era(), 1); - - // --- Block 4: the validators will now be changed. - start_session(4); - - assert_eq_uvec!(validator_controllers(), vec![20, 4]); - // --- Block 4: Unstake 4 as a validator, freeing up the balance stashed in 3 - // 4 will chill - Staking::chill(Origin::signed(4)).unwrap(); - - // --- Block 5: nothing. 4 is still there. - start_session(5); - assert_eq_uvec!(validator_controllers(), vec![20, 4]); - - // --- Block 6: 4 will not be a validator. - start_session(7); - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // Note: the stashed value of 4 is still lock - assert_eq!( - Staking::ledger(&4), - Some(StakingLedger { - stash: 3, - total: 1500, - active: 1500, - unlocking: vec![] - }) - ); - // e.g. it cannot spend more than 500 that it has free from the total 2000 - assert_noop!( - Balances::reserve(&3, 501), - DispatchError::Module { - index: 0, - error: 1, - message: Some("LiquidityRestrictions"), - } - ); - assert_ok!(Balances::reserve(&3, 409)); - }); -} - -#[test] -fn less_than_needed_candidates_works() { - ExtBuilder::default() - .minimum_validator_count(1) - .validator_count(4) - .nominate(false) - .num_validators(3) - .build() - .execute_with(|| { - assert_eq!(Staking::validator_count(), 4); - assert_eq!(Staking::minimum_validator_count(), 1); - assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); - - start_era(1); - - // Previous set is selected. NO election algorithm is even executed. - assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); - - // But the exposure is updated in a simple way. No external votes exists. - // This is purely self-vote. - assert_eq!(Staking::stakers(10).others.len(), 0); - assert_eq!(Staking::stakers(20).others.len(), 0); - assert_eq!(Staking::stakers(30).others.len(), 0); - check_exposure_all(); - check_nominator_all(); - }); -} - -#[test] -fn no_candidate_emergency_condition() { - ExtBuilder::default() - .minimum_validator_count(10) - .validator_count(15) - .num_validators(4) - .validator_pool(true) - .nominate(false) - .build() - .execute_with(|| { - // initial validators - assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); - - // set the minimum validator count. - ::MinimumValidatorCount::put(10); - ::ValidatorCount::put(15); - assert_eq!(Staking::validator_count(), 15); - - let _ = Staking::chill(Origin::signed(10)); - - // trigger era - System::set_block_number(1); - Session::on_initialize(System::block_number()); - - // Previous ones are elected. chill is invalidates. TODO: #2494 - assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); - assert_eq!(Staking::current_elected().len(), 0); - }); -} - -#[test] -fn nominating_and_rewards_should_work() { - // PHRAGMEN OUTPUT: running this test with the reference impl gives: - // - // Sequential Phragmén gives - // 10 is elected with stake 2200.0 and score 0.0003333333333333333 - // 20 is elected with stake 1800.0 and score 0.0005555555555555556 - - // 10 has load 0.0003333333333333333 and supported - // 10 with stake 1000.0 - // 20 has load 0.0005555555555555556 and supported - // 20 with stake 1000.0 - // 30 has load 0 and supported - // 30 with stake 0 - // 40 has load 0 and supported - // 40 with stake 0 - // 2 has load 0.0005555555555555556 and supported - // 10 with stake 600.0 20 with stake 400.0 30 with stake 0.0 - // 4 has load 0.0005555555555555556 and supported - // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 - - // Sequential Phragmén with post processing gives - // 10 is elected with stake 2000.0 and score 0.0003333333333333333 - // 20 is elected with stake 2000.0 and score 0.0005555555555555556 - - // 10 has load 0.0003333333333333333 and supported - // 10 with stake 1000.0 - // 20 has load 0.0005555555555555556 and supported - // 20 with stake 1000.0 - // 30 has load 0 and supported - // 30 with stake 0 - // 40 has load 0 and supported - // 40 with stake 0 - // 2 has load 0.0005555555555555556 and supported - // 10 with stake 400.0 20 with stake 600.0 30 with stake 0 - // 4 has load 0.0005555555555555556 and supported - // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 - ExtBuilder::default() - .nominate(false) - .validator_pool(true) - .build() - .execute_with(|| { - // initial validators -- everyone is actually even. - assert_eq_uvec!(validator_controllers(), vec![40, 30]); - - // Set payee to controller - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); - - // give the man some money - let initial_balance = 1000; - for i in [1, 2, 3, 4, 5, 10, 11, 20, 21].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); - } - - // bond two account pairs and state interest in nomination. - // 2 will nominate for 10, 20, 30 - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); - // 4 will nominate for 10, 20, 40 - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); - - // the total reward for era 0 - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(41, 1)]); - >::reward_by_ids(vec![(31, 1)]); - >::reward_by_ids(vec![(21, 10)]); // must be no-op - >::reward_by_ids(vec![(11, 10)]); // must be no-op - - start_era(1); - - // 10 and 20 have more votes, they will be chosen by phragmen. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // OLD validators must have already received some rewards. - assert_eq!(Balances::total_balance(&40), 1 + total_payout_0 / 2); - assert_eq!(Balances::total_balance(&30), 1 + total_payout_0 / 2); - - // ------ check the staked value of all parties. - - if cfg!(feature = "equalize") { - // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(11).own, 1000); - assert_eq_error_rate!(Staking::stakers(11).total, 1000 + 1000, 2); - // 2 and 4 supported 10, each with stake 600, according to phragmen. - assert_eq!( - Staking::stakers(11) - .others - .iter() - .map(|e| e.value) - .collect::>>(), - vec![600, 400] - ); - assert_eq!( - Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - // total expo of 20, with 500 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(21).own, 1000); - assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1000, 2); - // 2 and 4 supported 20, each with stake 250, according to phragmen. - assert_eq!( - Staking::stakers(21) - .others - .iter() - .map(|e| e.value) - .collect::>>(), - vec![400, 600] - ); - assert_eq!( - Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - } else { - // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(11).own, 1000); - assert_eq!(Staking::stakers(11).total, 1000 + 800); - // 2 and 4 supported 10, each with stake 600, according to phragmen. - assert_eq!( - Staking::stakers(11) - .others - .iter() - .map(|e| e.value) - .collect::>>(), - vec![400, 400] - ); - assert_eq!( - Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - // total expo of 20, with 500 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(21).own, 1000); - assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1200, 2); - // 2 and 4 supported 20, each with stake 250, according to phragmen. - assert_eq!( - Staking::stakers(21) - .others - .iter() - .map(|e| e.value) - .collect::>>(), - vec![600, 600] - ); - assert_eq!( - Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - } - - // They are not chosen anymore - assert_eq!(Staking::stakers(31).total, 0); - assert_eq!(Staking::stakers(41).total, 0); - - // the total reward for era 1 - let total_payout_1 = current_total_payout_for_duration(3000); - assert!(total_payout_1 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(41, 10)]); // must be no-op - >::reward_by_ids(vec![(31, 10)]); // must be no-op - >::reward_by_ids(vec![(21, 2)]); - >::reward_by_ids(vec![(11, 1)]); - - start_era(2); - - // nothing else will happen, era ends and rewards are paid again, - // it is expected that nominators will also be paid. See below - - let payout_for_10 = total_payout_1 / 3; - let payout_for_20 = 2 * total_payout_1 / 3; - if cfg!(feature = "equalize") { - // Nominator 2: has [400 / 2000 ~ 1 / 5 from 10] + [600 / 2000 ~ 3 / 10 from 20]'s reward. - assert_eq_error_rate!( - Balances::total_balance(&2), - initial_balance + payout_for_10 / 5 + payout_for_20 * 3 / 10, - 2, - ); - // Nominator 4: has [400 / 2000 ~ 1 / 5 from 20] + [600 / 2000 ~ 3 / 10 from 10]'s reward. - assert_eq_error_rate!( - Balances::total_balance(&4), - initial_balance + payout_for_20 / 5 + payout_for_10 * 3 / 10, - 2, - ); - - // Validator 10: got 1000 / 2000 external stake. - assert_eq_error_rate!(Balances::total_balance(&10), initial_balance + payout_for_10 / 2, 1,); - // Validator 20: got 1000 / 2000 external stake. - assert_eq_error_rate!(Balances::total_balance(&20), initial_balance + payout_for_20 / 2, 1,); - } else { - // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 - assert_eq_error_rate!( - Balances::total_balance(&2), - initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), - 1, - ); - // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 - assert_eq_error_rate!( - Balances::total_balance(&4), - initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), - 1, - ); - - // Validator 10: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 - assert_eq_error_rate!(Balances::total_balance(&10), initial_balance + 5 * payout_for_10 / 9, 1,); - // Validator 20: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 - assert_eq_error_rate!( - Balances::total_balance(&20), - initial_balance + 5 * payout_for_20 / 11, - 1, - ); - } - - check_exposure_all(); - check_nominator_all(); - }); -} - -#[test] -fn nominators_also_get_slashed() { - // A nominator should be slashed if the validator they nominated is slashed - // Here is the breakdown of roles: - // 10 - is the controller of 11 - // 11 - is the stash. - // 2 - is the nominator of 20, 10 - ExtBuilder::default().nominate(false).build().execute_with(|| { - assert_eq!(Staking::validator_count(), 2); - - // Set payee to controller - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - - // give the man some money. - let initial_balance = 1000; - for i in [1, 2, 3, 10].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); - } - - // 2 will nominate for 10, 20 - let nominator_stake = 500; - assert_ok!(Staking::bond( - Origin::signed(1), - 2, - nominator_stake, - RewardDestination::default() - )); - assert_ok!(Staking::nominate(Origin::signed(2), vec![20, 10])); - - let total_payout = current_total_payout_for_duration(3000); - assert!(total_payout > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - - // new era, pay rewards, - start_era(1); - - // Nominator stash didn't collect any. - assert_eq!(Balances::total_balance(&2), initial_balance); - - // 10 goes offline - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(5)], - ); - let expo = Staking::stakers(11); - let slash_value = 50; - let total_slash = expo.total.min(slash_value); - let validator_slash = expo.own.min(total_slash); - let nominator_slash = nominator_stake.min(total_slash - validator_slash); - - // initial + first era reward + slash - assert_eq!(Balances::total_balance(&11), initial_balance - validator_slash); - assert_eq!(Balances::total_balance(&2), initial_balance - nominator_slash); - check_exposure_all(); - check_nominator_all(); - // Because slashing happened. - assert!(is_disabled(10)); - }); -} - -#[test] -fn double_staking_should_fail() { - // should test (in the same order): - // * an account already bonded as stash cannot be be stashed again. - // * an account already bonded as stash cannot nominate. - // * an account already bonded as controller can nominate. - ExtBuilder::default().build().execute_with(|| { - let arbitrary_value = 5; - // 2 = controller, 1 stashed => ok - assert_ok!(Staking::bond( - Origin::signed(1), - 2, - arbitrary_value, - RewardDestination::default() - )); - // 4 = not used so far, 1 stashed => not allowed. - assert_noop!( - Staking::bond(Origin::signed(1), 4, arbitrary_value, RewardDestination::default()), - Error::::AlreadyBonded, - ); - // 1 = stashed => attempting to nominate should fail. - assert_noop!( - Staking::nominate(Origin::signed(1), vec![1]), - Error::::NotController - ); - // 2 = controller => nominating should work. - assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); - }); -} - -#[test] -fn double_controlling_should_fail() { - // should test (in the same order): - // * an account already bonded as controller CANNOT be reused as the controller of another account. - ExtBuilder::default().build().execute_with(|| { - let arbitrary_value = 5; - // 2 = controller, 1 stashed => ok - assert_ok!(Staking::bond( - Origin::signed(1), - 2, - arbitrary_value, - RewardDestination::default(), - )); - // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op - assert_noop!( - Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), - Error::::AlreadyPaired, - ); - }); -} - -#[test] -fn session_and_eras_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Staking::current_era(), 0); - - // Block 1: No change. - start_session(0); - assert_eq!(Session::current_index(), 1); - assert_eq!(Staking::current_era(), 0); - - // Block 2: Simple era change. - start_session(2); - assert_eq!(Session::current_index(), 3); - assert_eq!(Staking::current_era(), 1); - - // Block 3: Schedule an era length change; no visible changes. - start_session(3); - assert_eq!(Session::current_index(), 4); - assert_eq!(Staking::current_era(), 1); - - // Block 4: Era change kicks in. - start_session(5); - assert_eq!(Session::current_index(), 6); - assert_eq!(Staking::current_era(), 2); - - // Block 5: No change. - start_session(6); - assert_eq!(Session::current_index(), 7); - assert_eq!(Staking::current_era(), 2); - - // Block 6: No change. - start_session(7); - assert_eq!(Session::current_index(), 8); - assert_eq!(Staking::current_era(), 2); - - // Block 7: Era increment. - start_session(8); - assert_eq!(Session::current_index(), 9); - assert_eq!(Staking::current_era(), 3); - }); -} - -#[test] -fn forcing_new_era_works() { - ExtBuilder::default().build().execute_with(|| { - // normal flow of session. - assert_eq!(Staking::current_era(), 0); - start_session(0); - assert_eq!(Staking::current_era(), 0); - start_session(1); - assert_eq!(Staking::current_era(), 0); - start_session(2); - assert_eq!(Staking::current_era(), 1); - - // no era change. - ForceEra::put(Forcing::ForceNone); - start_session(3); - assert_eq!(Staking::current_era(), 1); - start_session(4); - assert_eq!(Staking::current_era(), 1); - start_session(5); - assert_eq!(Staking::current_era(), 1); - start_session(6); - assert_eq!(Staking::current_era(), 1); - - // back to normal. - // this immediately starts a new session. - ForceEra::put(Forcing::NotForcing); - start_session(7); - assert_eq!(Staking::current_era(), 2); - start_session(8); - assert_eq!(Staking::current_era(), 2); - - // forceful change - ForceEra::put(Forcing::ForceAlways); - start_session(9); - assert_eq!(Staking::current_era(), 3); - start_session(10); - assert_eq!(Staking::current_era(), 4); - start_session(11); - assert_eq!(Staking::current_era(), 5); - - // just one forceful change - ForceEra::put(Forcing::ForceNew); - start_session(12); - assert_eq!(Staking::current_era(), 6); - - assert_eq!(ForceEra::get(), Forcing::NotForcing); - start_session(13); - assert_eq!(Staking::current_era(), 6); - }); -} - -#[test] -fn cannot_transfer_staked_balance() { - // Tests that a stash account cannot transfer funds - ExtBuilder::default().nominate(false).build().execute_with(|| { - // Confirm account 11 is stashed - assert_eq!(Staking::bonded(&11), Some(10)); - // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(&11), 1000); - // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::stakers(&11).total, 1000); - // Confirm account 11 cannot transfer as a result - assert_noop!( - Balances::transfer(Origin::signed(11), 20, 1), - DispatchError::Module { - index: 0, - error: 1, - message: Some("LiquidityRestrictions"), - } - ); - - // Give account 11 extra free balance - let _ = Balances::make_free_balance_be(&11, 10000); - // Confirm that account 11 can now transfer some balance - assert_ok!(Balances::transfer(Origin::signed(11), 20, 1)); - }); -} - -#[test] -fn cannot_transfer_staked_balance_2() { - // Tests that a stash account cannot transfer funds - // Same test as above but with 20, and more accurate. - // 21 has 2000 free balance but 1000 at stake - ExtBuilder::default() - .nominate(false) - .fair(true) - .build() - .execute_with(|| { - // Confirm account 21 is stashed - assert_eq!(Staking::bonded(&21), Some(20)); - // Confirm account 21 has some free balance - assert_eq!(Balances::free_balance(&21), 2000); - // Confirm account 21 (via controller 20) is totally staked - assert_eq!(Staking::stakers(&21).total, 1000); - // Confirm account 21 can transfer at most 1000 - assert_noop!( - Balances::transfer(Origin::signed(21), 20, 1001), - DispatchError::Module { - index: 0, - error: 1, - message: Some("LiquidityRestrictions"), - } - ); - assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000)); - }); -} - -#[test] -fn cannot_reserve_staked_balance() { - // Checks that a bonded account cannot reserve balance from free balance - ExtBuilder::default().build().execute_with(|| { - // Confirm account 11 is stashed - assert_eq!(Staking::bonded(&11), Some(10)); - // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(&11), 1000); - // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::stakers(&11).own, 1000); - // Confirm account 11 cannot transfer as a result - assert_noop!( - Balances::reserve(&11, 1), - DispatchError::Module { - index: 0, - error: 1, - message: Some("LiquidityRestrictions"), - } - ); - - // Give account 11 extra free balance - let _ = Balances::make_free_balance_be(&11, 10000); - // Confirm account 11 can now reserve balance - assert_ok!(Balances::reserve(&11, 1)); - }); -} - -#[test] -fn reward_destination_works() { - // Rewards go to the correct destination as determined in Payee - ExtBuilder::default().nominate(false).build().execute_with(|| { - // Check that account 11 is a validator - assert!(Staking::current_elected().contains(&11)); - // Check the balance of the validator account - assert_eq!(Balances::free_balance(&10), 1); - // Check the balance of the stash account - assert_eq!(Balances::free_balance(&11), 1000); - // Check how much is at stake - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: vec![], - }) - ); - - // Compute total payout now for whole duration as other parameter won't change - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - - start_era(1); - - // Check that RewardDestination is Staked (default) - assert_eq!(Staking::payee(&11), RewardDestination::Staked); - // Check that reward went to the stash account of validator - assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0); - // Check that amount at stake increased accordingly - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + total_payout_0, - active: 1000 + total_payout_0, - unlocking: vec![], - }) - ); - - //Change RewardDestination to Stash - >::insert(&11, RewardDestination::Stash); - - // Compute total payout now for whole duration as other parameter won't change - let total_payout_1 = current_total_payout_for_duration(3000); - assert!(total_payout_1 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - - start_era(2); - - // Check that RewardDestination is Stash - assert_eq!(Staking::payee(&11), RewardDestination::Stash); - // Check that reward went to the stash account - assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0 + total_payout_1); - // Record this value - let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; - // Check that amount at stake is NOT increased - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + total_payout_0, - active: 1000 + total_payout_0, - unlocking: vec![], - }) - ); - - // Change RewardDestination to Controller - >::insert(&11, RewardDestination::Controller); - - // Check controller balance - assert_eq!(Balances::free_balance(&10), 1); - - // Compute total payout now for whole duration as other parameter won't change - let total_payout_2 = current_total_payout_for_duration(3000); - assert!(total_payout_2 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - - start_era(3); - - // Check that RewardDestination is Controller - assert_eq!(Staking::payee(&11), RewardDestination::Controller); - // Check that reward went to the controller account - assert_eq!(Balances::free_balance(&10), 1 + total_payout_2); - // Check that amount at stake is NOT increased - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + total_payout_0, - active: 1000 + total_payout_0, - unlocking: vec![], - }) - ); - // Check that amount in staked account is NOT increased. - assert_eq!(Balances::free_balance(&11), recorded_stash_balance); - }); -} - -#[test] -fn validator_payment_prefs_work() { - // Test that validator preferences are correctly honored - // Note: unstake threshold is being directly tested in slashing tests. - // This test will focus on validator payment. - ExtBuilder::default().build().execute_with(|| { - // Initial config - let stash_initial_balance = Balances::total_balance(&11); - - // check the balance of a validator accounts. - assert_eq!(Balances::total_balance(&10), 1); - // check the balance of a validator's stash accounts. - assert_eq!(Balances::total_balance(&11), stash_initial_balance); - // and the nominator (to-be) - let _ = Balances::make_free_balance_be(&2, 500); - - // add a dummy nominator. - >::insert( - &11, - Exposure { - own: 500, // equal division indicates that the reward will be equally divided among validator and nominator. - total: 1000, - others: vec![IndividualExposure { who: 2, value: 500 }], - }, - ); - >::insert(&2, RewardDestination::Stash); - >::insert( - &11, - ValidatorPrefs { - commission: Perbill::from_percent(50), - }, - ); - - // Compute total payout now for whole duration as other parameter won't change - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - - start_era(1); - - // whats left to be shared is the sum of 3 rounds minus the validator's cut. - let shared_cut = total_payout_0 / 2; - // Validator's payee is Staked account, 11, reward will be paid here. - assert_eq!( - Balances::total_balance(&11), - stash_initial_balance + shared_cut / 2 + shared_cut - ); - // Controller account will not get any reward. - assert_eq!(Balances::total_balance(&10), 1); - // Rest of the reward will be shared and paid to the nominator in stake. - assert_eq!(Balances::total_balance(&2), 500 + shared_cut / 2); - - check_exposure_all(); - check_nominator_all(); - }); -} - -#[test] -fn bond_extra_works() { - // Tests that extra `free_balance` in the stash can be added to stake - // NOTE: this tests only verifies `StakingLedger` for correct updates - // See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`. - ExtBuilder::default().build().execute_with(|| { - // Check that account 10 is a validator - assert!(>::exists(11)); - // Check that account 10 is bonded to account 11 - assert_eq!(Staking::bonded(&11), Some(10)); - // Check how much is at stake - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: vec![], - }) - ); - - // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); - - // Call the bond_extra function from controller, add only 100 - assert_ok!(Staking::bond_extra(Origin::signed(11), 100)); - // There should be 100 more `total` and `active` in the ledger - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + 100, - active: 1000 + 100, - unlocking: vec![], - }) - ); - - // Call the bond_extra function with a large number, should handle it - assert_ok!(Staking::bond_extra(Origin::signed(11), u64::max_value())); - // The full amount of the funds should now be in the total and active - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000000, - active: 1000000, - unlocking: vec![], - }) - ); - }); -} - -#[test] -fn bond_extra_and_withdraw_unbonded_works() { - // * Should test - // * Given an account being bonded [and chosen as a validator](not mandatory) - // * It can add extra funds to the bonded account. - // * it can unbond a portion of its funds from the stash account. - // * Once the unbonding period is done, it can actually take the funds out of the stash. - ExtBuilder::default().nominate(false).build().execute_with(|| { - // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - - // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); - - // Initial config should be correct - assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::current_index(), 0); - - // check the balance of a validator accounts. - assert_eq!(Balances::total_balance(&10), 1); - - // confirm that 10 is a normal validator and gets paid at the end of the era. - start_era(1); - - // Initial state of 10 - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: vec![], - }) - ); - assert_eq!( - Staking::stakers(&11), - Exposure { - total: 1000, - own: 1000, - others: vec![] - } - ); - - // deposit the extra 100 units - Staking::bond_extra(Origin::signed(11), 100).unwrap(); - - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + 100, - active: 1000 + 100, - unlocking: vec![], - }) - ); - // Exposure is a snapshot! only updated after the next era update. - assert_ne!( - Staking::stakers(&11), - Exposure { - total: 1000 + 100, - own: 1000 + 100, - others: vec![] - } - ); - - // trigger next era. - Timestamp::set_timestamp(10); - start_era(2); - assert_eq!(Staking::current_era(), 2); - - // ledger should be the same. - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + 100, - active: 1000 + 100, - unlocking: vec![], - }) - ); - // Exposure is now updated. - assert_eq!( - Staking::stakers(&11), - Exposure { - total: 1000 + 100, - own: 1000 + 100, - others: vec![] - } - ); - - // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 1000).unwrap(); - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + 100, - active: 100, - unlocking: vec![UnlockChunk { - value: 1000, - era: 2 + 3 - }] - }) - ); - - // Attempting to free the balances now will fail. 2 eras need to pass. - Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + 100, - active: 100, - unlocking: vec![UnlockChunk { - value: 1000, - era: 2 + 3 - }] - }) - ); - - // trigger next era. - start_era(3); - - // nothing yet - Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000 + 100, - active: 100, - unlocking: vec![UnlockChunk { - value: 1000, - era: 2 + 3 - }] - }) - ); - - // trigger next era. - start_era(5); - - Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); - // Now the value is free and the staking ledger is updated. - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 100, - active: 100, - unlocking: vec![] - }) - ); - }) -} - -#[test] -fn too_many_unbond_calls_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - // locked at era 0 until 3 - for _ in 0..MAX_UNLOCKING_CHUNKS - 1 { - assert_ok!(Staking::unbond(Origin::signed(10), 1)); - } - - start_era(1); - - // locked at era 1 until 4 - assert_ok!(Staking::unbond(Origin::signed(10), 1)); - // can't do more. - assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); - - start_era(3); - - assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); - // free up. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10))); - - // Can add again. - assert_ok!(Staking::unbond(Origin::signed(10), 1)); - assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2); - }) -} - -#[test] -fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() { - // Test that slot_stake is determined by the least staked validator - // Test that slot_stake is the maximum punishment that can happen to a validator - ExtBuilder::default() - .nominate(false) - .fair(false) - .build() - .execute_with(|| { - // Confirm validator count is 2 - assert_eq!(Staking::validator_count(), 2); - // Confirm account 10 and 20 are validators - assert!(>::exists(&11) && >::exists(&21)); - - assert_eq!(Staking::stakers(&11).total, 1000); - assert_eq!(Staking::stakers(&21).total, 2000); - - // Give the man some money. - let _ = Balances::make_free_balance_be(&10, 1000); - let _ = Balances::make_free_balance_be(&20, 1000); - - // We confirm initialized slot_stake is this value - assert_eq!(Staking::slot_stake(), Staking::stakers(&11).total); - - // Now lets lower account 20 stake - >::insert( - &21, - Exposure { - total: 69, - own: 69, - others: vec![], - }, - ); - assert_eq!(Staking::stakers(&21).total, 69); - >::insert( - &20, - StakingLedger { - stash: 22, - total: 69, - active: 69, - unlocking: vec![], - }, - ); - - // Compute total payout now for whole duration as other parameter won't change - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(11, 1)]); - >::reward_by_ids(vec![(21, 1)]); - - // New era --> rewards are paid --> stakes are changed - start_era(1); - - // -- new balances + reward - assert_eq!(Staking::stakers(&11).total, 1000 + total_payout_0 / 2); - assert_eq!(Staking::stakers(&21).total, 69 + total_payout_0 / 2); - - let _11_balance = Balances::free_balance(&11); - assert_eq!(_11_balance, 1000 + total_payout_0 / 2); - - // -- slot stake should also be updated. - assert_eq!(Staking::slot_stake(), 69 + total_payout_0 / 2); - - check_exposure_all(); - check_nominator_all(); - }); -} - -#[test] -fn on_free_balance_zero_stash_removes_validator() { - // Tests that validator storage items are cleaned up when stash is empty - // Tests that storage items are untouched when controller is empty - ExtBuilder::default().existential_deposit(10).build().execute_with(|| { - // Check the balance of the validator account - assert_eq!(Balances::free_balance(&10), 256); - // Check the balance of the stash account - assert_eq!(Balances::free_balance(&11), 256000); - // Check these two accounts are bonded - assert_eq!(Staking::bonded(&11), Some(10)); - - // Set some storage items which we expect to be cleaned up - // Set payee information - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); - - // Check storage items that should be cleaned up - assert!(>::exists(&10)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - - // Reduce free_balance of controller to 0 - let _ = Balances::slash(&10, u64::max_value()); - - // Check the balance of the stash account has not been touched - assert_eq!(Balances::free_balance(&11), 256000); - // Check these two accounts are still bonded - assert_eq!(Staking::bonded(&11), Some(10)); - - // Check storage items have not changed - assert!(>::exists(&10)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - - // Reduce free_balance of stash to 0 - let _ = Balances::slash(&11, u64::max_value()); - // Check total balance of stash - assert_eq!(Balances::total_balance(&11), 0); - - // Check storage items do not exist - assert!(!>::exists(&10)); - assert!(!>::exists(&11)); - assert!(!>::exists(&11)); - assert!(!>::exists(&11)); - assert!(!>::exists(&11)); - }); -} - -#[test] -fn on_free_balance_zero_stash_removes_nominator() { - // Tests that nominator storage items are cleaned up when stash is empty - // Tests that storage items are untouched when controller is empty - ExtBuilder::default().existential_deposit(10).build().execute_with(|| { - // Make 10 a nominator - assert_ok!(Staking::nominate(Origin::signed(10), vec![20])); - // Check that account 10 is a nominator - assert!(>::exists(11)); - // Check the balance of the nominator account - assert_eq!(Balances::free_balance(&10), 256); - // Check the balance of the stash account - assert_eq!(Balances::free_balance(&11), 256000); - - // Set payee information - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); - - // Check storage items that should be cleaned up - assert!(>::exists(&10)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - - // Reduce free_balance of controller to 0 - let _ = Balances::slash(&10, u64::max_value()); - // Check total balance of account 10 - assert_eq!(Balances::total_balance(&10), 0); - - // Check the balance of the stash account has not been touched - assert_eq!(Balances::free_balance(&11), 256000); - // Check these two accounts are still bonded - assert_eq!(Staking::bonded(&11), Some(10)); - - // Check storage items have not changed - assert!(>::exists(&10)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - assert!(>::exists(&11)); - - // Reduce free_balance of stash to 0 - let _ = Balances::slash(&11, u64::max_value()); - // Check total balance of stash - assert_eq!(Balances::total_balance(&11), 0); - - // Check storage items do not exist - assert!(!>::exists(&10)); - assert!(!>::exists(&11)); - assert!(!>::exists(&11)); - assert!(!>::exists(&11)); - assert!(!>::exists(&11)); - }); -} - -#[test] -fn switching_roles() { - // Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead. - ExtBuilder::default().nominate(false).build().execute_with(|| { - Timestamp::set_timestamp(1); // Initialize time. - - // Reset reward destination - for i in &[10, 20] { - assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); - } - - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // put some money in account that we'll use. - for i in 1..7 { - let _ = Balances::deposit_creating(&i, 5000); - } - - // add 2 nominators - assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5])); - - assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1])); - - // add a new validator candidate - assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); - - // new block - start_session(1); - - // no change - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // new block - start_session(2); - - // no change - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // new block --> ne era --> new validators - start_session(3); - - // with current nominators 10 and 5 have the most stake - assert_eq_uvec!(validator_controllers(), vec![6, 10]); - - // 2 decides to be a validator. Consequences: - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); - // new stakes: - // 10: 1000 self vote - // 20: 1000 self vote + 250 vote - // 6 : 1000 self vote - // 2 : 2000 self vote + 250 vote. - // Winners: 20 and 2 - - start_session(4); - assert_eq_uvec!(validator_controllers(), vec![6, 10]); - - start_session(5); - assert_eq_uvec!(validator_controllers(), vec![6, 10]); - - // ne era - start_session(6); - assert_eq_uvec!(validator_controllers(), vec![2, 20]); - - check_exposure_all(); - check_nominator_all(); - }); -} - -#[test] -fn wrong_vote_is_null() { - ExtBuilder::default() - .nominate(false) - .validator_pool(true) - .build() - .execute_with(|| { - assert_eq_uvec!(validator_controllers(), vec![40, 30]); - - // put some money in account that we'll use. - for i in 1..3 { - let _ = Balances::deposit_creating(&i, 5000); - } - - // add 1 nominators - assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::default())); - assert_ok!(Staking::nominate( - Origin::signed(2), - vec![ - 11, 21, // good votes - 1, 2, 15, 1000, 25 // crap votes. No effect. - ] - )); - - // new block - start_era(1); - - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - }); -} - -#[test] -fn bond_with_no_staked_value() { - // Behavior when someone bonds with no staked value. - // Particularly when she votes and the candidate is elected. - ExtBuilder::default() - .validator_count(3) - .existential_deposit(5) - .nominate(false) - .minimum_validator_count(1) - .build() - .execute_with(|| { - // Can't bond with 1 - assert_noop!( - Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), - Error::::InsufficientValue, - ); - // bonded with absolute minimum value possible. - assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); - assert_eq!(Balances::locks(&1)[0].amount, 5); - - // unbonding even 1 will cause all to be unbonded. - assert_ok!(Staking::unbond(Origin::signed(2), 1)); - assert_eq!( - Staking::ledger(2), - Some(StakingLedger { - stash: 1, - active: 0, - total: 5, - unlocking: vec![UnlockChunk { value: 5, era: 3 }] - }) - ); - - start_era(1); - start_era(2); - - // not yet removed. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); - assert!(Staking::ledger(2).is_some()); - assert_eq!(Balances::locks(&1)[0].amount, 5); - - start_era(3); - - // poof. Account 1 is removed from the staking system. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); - assert!(Staking::ledger(2).is_none()); - assert_eq!(Balances::locks(&1).len(), 0); - }); -} - -#[test] -fn bond_with_little_staked_value_bounded_by_slot_stake() { - // Behavior when someone bonds with little staked value. - // Particularly when she votes and the candidate is elected. - ExtBuilder::default() - .validator_count(3) - .nominate(false) - .minimum_validator_count(1) - .build() - .execute_with(|| { - // setup - assert_ok!(Staking::chill(Origin::signed(30))); - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - let init_balance_2 = Balances::free_balance(&2); - let init_balance_10 = Balances::free_balance(&10); - - // Stingy validator. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); - - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - reward_all_elected(); - start_era(1); - - // 2 is elected. - // and fucks up the slot stake. - assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); - assert_eq!(Staking::slot_stake(), 1); - - // Old ones are rewarded. - assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3); - // no rewards paid to 2. This was initial election. - assert_eq!(Balances::free_balance(&2), init_balance_2); - - let total_payout_1 = current_total_payout_for_duration(3000); - assert!(total_payout_1 > 100); // Test is meaningfull if reward something - reward_all_elected(); - start_era(2); - - assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); - assert_eq!(Staking::slot_stake(), 1); - - assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1 / 3); - assert_eq!( - Balances::free_balance(&10), - init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3, - ); - check_exposure_all(); - check_nominator_all(); - }); -} - -#[cfg(feature = "equalize")] -#[test] -fn phragmen_linear_worse_case_equalize() { - ExtBuilder::default() - .nominate(false) - .validator_pool(true) - .fair(true) - .build() - .execute_with(|| { - bond_validator(50, 1000); - bond_validator(60, 1000); - bond_validator(70, 1000); - - bond_nominator(2, 2000, vec![11]); - bond_nominator(4, 1000, vec![11, 21]); - bond_nominator(6, 1000, vec![21, 31]); - bond_nominator(8, 1000, vec![31, 41]); - bond_nominator(110, 1000, vec![41, 51]); - bond_nominator(120, 1000, vec![51, 61]); - bond_nominator(130, 1000, vec![61, 71]); - - for i in &[10, 20, 30, 40, 50, 60, 70] { - assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); - } - - assert_eq_uvec!(validator_controllers(), vec![40, 30]); - assert_ok!(Staking::set_validator_count(Origin::ROOT, 7)); - - start_era(1); - - assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]); - - assert_eq_error_rate!(Staking::stakers(11).total, 3000, 2); - assert_eq_error_rate!(Staking::stakers(21).total, 2255, 2); - assert_eq_error_rate!(Staking::stakers(31).total, 2255, 2); - assert_eq_error_rate!(Staking::stakers(41).total, 1925, 2); - assert_eq_error_rate!(Staking::stakers(51).total, 1870, 2); - assert_eq_error_rate!(Staking::stakers(61).total, 1890, 2); - assert_eq_error_rate!(Staking::stakers(71).total, 1800, 2); - - check_exposure_all(); - check_nominator_all(); - }) -} - -#[test] -fn new_era_elects_correct_number_of_validators() { - ExtBuilder::default() - .nominate(true) - .validator_pool(true) - .fair(true) - .validator_count(1) - .build() - .execute_with(|| { - assert_eq!(Staking::validator_count(), 1); - assert_eq!(validator_controllers().len(), 1); - - System::set_block_number(1); - Session::on_initialize(System::block_number()); - - assert_eq!(validator_controllers().len(), 1); - check_exposure_all(); - check_nominator_all(); - }) -} - -#[test] -fn phragmen_should_not_overflow_validators() { - ExtBuilder::default().nominate(false).build().execute_with(|| { - let _ = Staking::chill(Origin::signed(10)); - let _ = Staking::chill(Origin::signed(20)); - - bond_validator(2, u64::max_value()); - bond_validator(4, u64::max_value()); - - bond_nominator(6, u64::max_value() / 2, vec![3, 5]); - bond_nominator(8, u64::max_value() / 2, vec![3, 5]); - - start_era(1); - - assert_eq_uvec!(validator_controllers(), vec![4, 2]); - - // This test will fail this. Will saturate. - // check_exposure_all(); - assert_eq!(Staking::stakers(3).total, u64::max_value()); - assert_eq!(Staking::stakers(5).total, u64::max_value()); - }) -} - -#[test] -fn phragmen_should_not_overflow_nominators() { - ExtBuilder::default().nominate(false).build().execute_with(|| { - let _ = Staking::chill(Origin::signed(10)); - let _ = Staking::chill(Origin::signed(20)); - - bond_validator(2, u64::max_value() / 2); - bond_validator(4, u64::max_value() / 2); - - bond_nominator(6, u64::max_value(), vec![3, 5]); - bond_nominator(8, u64::max_value(), vec![3, 5]); - - start_era(1); - - assert_eq_uvec!(validator_controllers(), vec![4, 2]); - - // Saturate. - assert_eq!(Staking::stakers(3).total, u64::max_value()); - assert_eq!(Staking::stakers(5).total, u64::max_value()); - }) -} - -#[test] -fn phragmen_should_not_overflow_ultimate() { - ExtBuilder::default().nominate(false).build().execute_with(|| { - bond_validator(2, u64::max_value()); - bond_validator(4, u64::max_value()); - - bond_nominator(6, u64::max_value(), vec![3, 5]); - bond_nominator(8, u64::max_value(), vec![3, 5]); - - start_era(1); - - assert_eq_uvec!(validator_controllers(), vec![4, 2]); - - // Saturate. - assert_eq!(Staking::stakers(3).total, u64::max_value()); - assert_eq!(Staking::stakers(5).total, u64::max_value()); - }) -} - -#[test] -fn reward_validator_slashing_validator_doesnt_overflow() { - ExtBuilder::default().build().execute_with(|| { - let stake = u32::max_value() as u64 * 2; - let reward_slash = u32::max_value() as u64 * 2; - - // Assert multiplication overflows in balance arithmetic. - assert!(stake.checked_mul(reward_slash).is_none()); - - // Set staker - let _ = Balances::make_free_balance_be(&11, stake); - >::insert( - &11, - Exposure { - total: stake, - own: stake, - others: vec![], - }, - ); - - // Check reward - let _ = Staking::reward_validator(&11, reward_slash); - assert_eq!(Balances::total_balance(&11), stake * 2); - - // Set staker - let _ = Balances::make_free_balance_be(&11, stake); - let _ = Balances::make_free_balance_be(&2, stake); - - // only slashes out of bonded stake are applied. without this line, - // it is 0. - Staking::bond(Origin::signed(2), 20000, stake - 1, RewardDestination::default()).unwrap(); - >::insert( - &11, - Exposure { - total: stake, - own: 1, - others: vec![IndividualExposure { - who: 2, - value: stake - 1, - }], - }, - ); - - // Check slashing - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(100)], - ); - - assert_eq!(Balances::total_balance(&11), stake - 1); - assert_eq!(Balances::total_balance(&2), 1); - }) -} - -#[test] -fn reward_from_authorship_event_handler_works() { - ExtBuilder::default().build().execute_with(|| { - use pallet_authorship::EventHandler; - - assert_eq!(>::author(), 11); - - >::note_author(11); - >::note_uncle(21, 1); - // An uncle author that is not currently elected doesn't get rewards, - // but the block producer does get reward for referencing it. - >::note_uncle(31, 1); - // Rewarding the same two times works. - >::note_uncle(11, 1); - - // Not mandatory but must be coherent with rewards - assert_eq!(>::get(), vec![21, 11]); - - // 21 is rewarded as an uncle producer - // 11 is rewarded as a block producer and uncle referencer and uncle producer - assert_eq!(CurrentEraPointsEarned::get().individual, vec![1, 20 + 2 * 3 + 1]); - assert_eq!(CurrentEraPointsEarned::get().total, 28); - }) -} - -#[test] -fn add_reward_points_fns_works() { - ExtBuilder::default().build().execute_with(|| { - let validators = >::current_elected(); - // Not mandatory but must be coherent with rewards - assert_eq!(validators, vec![21, 11]); - - >::reward_by_indices(vec![(0, 1), (1, 1), (2, 1), (1, 1)]); - - >::reward_by_ids(vec![(21, 1), (11, 1), (31, 1), (11, 1)]); - - assert_eq!(CurrentEraPointsEarned::get().individual, vec![2, 4]); - assert_eq!(CurrentEraPointsEarned::get().total, 6); - }) -} - -#[test] -fn unbonded_balance_is_not_slashable() { - ExtBuilder::default().build().execute_with(|| { - // total amount staked is slashable. - assert_eq!(Staking::slashable_balance_of(&11), 1000); - - assert_ok!(Staking::unbond(Origin::signed(10), 800)); - - // only the active portion. - assert_eq!(Staking::slashable_balance_of(&11), 200); - }) -} - -#[test] -fn era_is_always_same_length() { - // This ensures that the sessions is always of the same length if there is no forcing no - // session changes. - ExtBuilder::default().build().execute_with(|| { - start_era(1); - assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get()); - - start_era(2); - assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get() * 2); - - let session = Session::current_index(); - ForceEra::put(Forcing::ForceNew); - advance_session(); - assert_eq!(Staking::current_era(), 3); - assert_eq!(Staking::current_era_start_session_index(), session + 1); - - start_era(4); - assert_eq!( - Staking::current_era_start_session_index(), - session + SessionsPerEra::get() + 1 - ); - }); -} - -#[test] -fn offence_forces_new_era() { - ExtBuilder::default().build().execute_with(|| { - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(5)], - ); - - assert_eq!(Staking::force_era(), Forcing::ForceNew); - }); -} - -#[test] -fn offence_ensures_new_era_without_clobbering() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Staking::force_new_era_always(Origin::ROOT)); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(5)], - ); - - assert_eq!(Staking::force_era(), Forcing::ForceAlways); - }); -} - -#[test] -fn offence_deselects_validator_when_slash_is_zero() { - ExtBuilder::default().build().execute_with(|| { - assert!(>::exists(11)); - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - ); - assert_eq!(Staking::force_era(), Forcing::ForceNew); - assert!(!>::exists(11)); - }); -} - -#[test] -fn slashing_performed_according_exposure() { - // This test checks that slashing is performed according the exposure (or more precisely, - // historical exposure), not the current balance. - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Staking::stakers(&11).own, 1000); - - // Handle an offence with a historical exposure. - on_offence_now( - &[OffenceDetails { - offender: ( - 11, - Exposure { - total: 500, - own: 500, - others: vec![], - }, - ), - reporters: vec![], - }], - &[Perbill::from_percent(50)], - ); - - // The stash account should be slashed for 250 (50% of 500). - assert_eq!(Balances::free_balance(&11), 1000 - 250); - }); -} - -#[test] -fn slash_in_old_span_does_not_deselect() { - ExtBuilder::default().build().execute_with(|| { - start_era(1); - - assert!(>::exists(11)); - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - ); - assert_eq!(Staking::force_era(), Forcing::ForceNew); - assert!(!>::exists(11)); - - start_era(2); - - Staking::validate(Origin::signed(10), Default::default()).unwrap(); - assert_eq!(Staking::force_era(), Forcing::NotForcing); - assert!(>::exists(11)); - - start_era(3); - - // this staker is in a new slashing span now, having re-registered after - // their prior slash. - - on_offence_in_era( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - 1, - ); - - // not for zero-slash. - assert_eq!(Staking::force_era(), Forcing::NotForcing); - assert!(>::exists(11)); - - on_offence_in_era( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(100)], - 1, - ); - - // or non-zero. - assert_eq!(Staking::force_era(), Forcing::NotForcing); - assert!(>::exists(11)); - assert_ledger_consistent(11); - }); -} - -#[test] -fn reporters_receive_their_slice() { - // This test verifies that the reporters of the offence receive their slice from the slashed - // amount. - ExtBuilder::default().build().execute_with(|| { - // The reporters' reward is calculated from the total exposure. - #[cfg(feature = "equalize")] - let initial_balance = 1250; - #[cfg(not(feature = "equalize"))] - let initial_balance = 1125; - - assert_eq!(Staking::stakers(&11).total, initial_balance); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![1, 2], - }], - &[Perbill::from_percent(50)], - ); - - // F1 * (reward_proportion * slash - 0) - // 50% * (10% * initial_balance / 2) - let reward = (initial_balance / 20) / 2; - let reward_each = reward / 2; // split into two pieces. - assert_eq!(Balances::free_balance(&1), 10 + reward_each); - assert_eq!(Balances::free_balance(&2), 20 + reward_each); - assert_ledger_consistent(11); - }); -} - -#[test] -fn subsequent_reports_in_same_span_pay_out_less() { - // This test verifies that the reporters of the offence receive their slice from the slashed - // amount. - ExtBuilder::default().build().execute_with(|| { - // The reporters' reward is calculated from the total exposure. - #[cfg(feature = "equalize")] - let initial_balance = 1250; - #[cfg(not(feature = "equalize"))] - let initial_balance = 1125; - - assert_eq!(Staking::stakers(&11).total, initial_balance); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![1], - }], - &[Perbill::from_percent(20)], - ); - - // F1 * (reward_proportion * slash - 0) - // 50% * (10% * initial_balance * 20%) - let reward = (initial_balance / 5) / 20; - assert_eq!(Balances::free_balance(&1), 10 + reward); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![1], - }], - &[Perbill::from_percent(50)], - ); - - let prior_payout = reward; - - // F1 * (reward_proportion * slash - prior_payout) - // 50% * (10% * (initial_balance / 2) - prior_payout) - let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(Balances::free_balance(&1), 10 + prior_payout + reward); - assert_ledger_consistent(11); - }); -} - -#[test] -fn invulnerables_are_not_slashed() { - // For invulnerable validators no slashing is performed. - ExtBuilder::default().invulnerables(vec![11]).build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&21), 2000); - - let exposure = Staking::stakers(&21); - let initial_balance = Staking::slashable_balance_of(&21); - - let nominator_balances: Vec<_> = exposure.others.iter().map(|o| Balances::free_balance(&o.who)).collect(); - - on_offence_now( - &[ - OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }, - OffenceDetails { - offender: (21, Staking::stakers(&21)), - reporters: vec![], - }, - ], - &[Perbill::from_percent(50), Perbill::from_percent(20)], - ); - - // The validator 11 hasn't been slashed, but 21 has been. - assert_eq!(Balances::free_balance(&11), 1000); - // 2000 - (0.2 * initial_balance) - assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10)); - - // ensure that nominators were slashed as well. - for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) { - assert_eq!( - Balances::free_balance(&other.who), - initial_balance - (2 * other.value / 10), - ); - } - assert_ledger_consistent(11); - assert_ledger_consistent(21); - }); -} - -#[test] -fn dont_slash_if_fraction_is_zero() { - // Don't slash if the fraction is zero. - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 1000); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - ); - - // The validator hasn't been slashed. The new era is not forced. - assert_eq!(Balances::free_balance(&11), 1000); - assert_ledger_consistent(11); - }); -} - -#[test] -fn only_slash_for_max_in_era() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 1000); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(50)], - ); - - // The validator has been slashed and has been force-chilled. - assert_eq!(Balances::free_balance(&11), 500); - assert_eq!(Staking::force_era(), Forcing::ForceNew); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(25)], - ); - - // The validator has not been slashed additionally. - assert_eq!(Balances::free_balance(&11), 500); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(60)], - ); - - // The validator got slashed 10% more. - assert_eq!(Balances::free_balance(&11), 400); - assert_ledger_consistent(11); - }) -} - -#[test] -fn garbage_collection_after_slashing() { - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 256_000); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - assert_eq!(Balances::free_balance(&11), 256_000 - 25_600); - assert!(::SlashingSpans::get(&11).is_some()); - assert_eq!( - ::SpanSlash::get(&(11, 0)).amount_slashed(), - &25_600 - ); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(100)], - ); - - // validator and nominator slash in era are garbage-collected by era change, - // so we don't test those here. - - assert_eq!(Balances::free_balance(&11), 0); - assert!(::SlashingSpans::get(&11).is_none()); - assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &0); - }) -} - -#[test] -fn garbage_collection_on_window_pruning() { - ExtBuilder::default().build().execute_with(|| { - start_era(1); - - assert_eq!(Balances::free_balance(&11), 1000); - - let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); - let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - let now = Staking::current_era(); - - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); - - assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); - assert!(::NominatorSlashInEra::get(&now, &101).is_some()); - - // + 1 because we have to exit the bonding window. - for era in (0..(BondingDuration::get() + 1)).map(|offset| offset + now + 1) { - assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); - assert!(::NominatorSlashInEra::get(&now, &101).is_some()); - - start_era(era); - } - - assert!(::ValidatorSlashInEra::get(&now, &11).is_none()); - assert!(::NominatorSlashInEra::get(&now, &101).is_none()); - }) -} - -#[test] -fn slashing_nominators_by_span_max() { - ExtBuilder::default().build().execute_with(|| { - start_era(1); - start_era(2); - start_era(3); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&21), 2000); - assert_eq!(Balances::free_balance(&101), 2000); - assert_eq!(Staking::slashable_balance_of(&21), 1000); - - let exposure_11 = Staking::stakers(&11); - let exposure_21 = Staking::stakers(&21); - assert_eq!(Balances::free_balance(&101), 2000); - let nominated_value_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; - let nominated_value_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; - - on_offence_in_era( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - 2, - ); - - assert_eq!(Balances::free_balance(&11), 900); - - let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; - assert_eq!(Balances::free_balance(&101), 2000 - slash_1_amount); - - let expected_spans = vec![ - slashing::SlashingSpan { - index: 1, - start: 4, - length: None, - }, - slashing::SlashingSpan { - index: 0, - start: 0, - length: Some(4), - }, - ]; - - let get_span = |account| ::SlashingSpans::get(&account).unwrap(); - - assert_eq!(get_span(11).iter().collect::>(), expected_spans,); - - assert_eq!(get_span(101).iter().collect::>(), expected_spans,); - - // second slash: higher era, higher value, same span. - on_offence_in_era( - &[OffenceDetails { - offender: (21, Staking::stakers(&21)), - reporters: vec![], - }], - &[Perbill::from_percent(30)], - 3, - ); - - // 11 was not further slashed, but 21 and 101 were. - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&21), 1700); - - let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; - assert!(slash_2_amount > slash_1_amount); - - // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount); - - // third slash: in same era and on same validator as first, higher - // in-era value, but lower slash value than slash 2. - on_offence_in_era( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(20)], - 2, - ); - - // 11 was further slashed, but 21 and 101 were not. - assert_eq!(Balances::free_balance(&11), 800); - assert_eq!(Balances::free_balance(&21), 1700); - - let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; - assert!(slash_3_amount < slash_2_amount); - assert!(slash_3_amount > slash_1_amount); - - // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount); - }); -} - -#[test] -fn slashes_are_summed_across_spans() { - ExtBuilder::default().build().execute_with(|| { - start_era(1); - start_era(2); - start_era(3); - - assert_eq!(Balances::free_balance(&21), 2000); - assert_eq!(Staking::slashable_balance_of(&21), 1000); - - let get_span = |account| ::SlashingSpans::get(&account).unwrap(); - - on_offence_now( - &[OffenceDetails { - offender: (21, Staking::stakers(&21)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - let expected_spans = vec![ - slashing::SlashingSpan { - index: 1, - start: 4, - length: None, - }, - slashing::SlashingSpan { - index: 0, - start: 0, - length: Some(4), - }, - ]; - - assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(&21), 1900); - - // 21 has been force-chilled. re-signal intent to validate. - Staking::validate(Origin::signed(20), Default::default()).unwrap(); - - start_era(4); - - assert_eq!(Staking::slashable_balance_of(&21), 900); - - on_offence_now( - &[OffenceDetails { - offender: (21, Staking::stakers(&21)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - let expected_spans = vec![ - slashing::SlashingSpan { - index: 2, - start: 5, - length: None, - }, - slashing::SlashingSpan { - index: 1, - start: 4, - length: Some(1), - }, - slashing::SlashingSpan { - index: 0, - start: 0, - length: Some(4), - }, - ]; - - assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(&21), 1810); - }); -} - -#[test] -fn deferred_slashes_are_deferred() { - ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { - start_era(1); - - assert_eq!(Balances::free_balance(&11), 1000); - - let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); - let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - start_era(2); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - start_era(3); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - // at the start of era 4, slashes from era 1 are processed, - // after being deferred for at least 2 full eras. - start_era(4); - - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); - }) -} - -#[test] -fn remove_deferred() { - ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { - start_era(1); - - assert_eq!(Balances::free_balance(&11), 1000); - - let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); - let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; - - on_offence_now( - &[OffenceDetails { - offender: (11, exposure.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - start_era(2); - - on_offence_in_era( - &[OffenceDetails { - offender: (11, exposure.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(15)], - 1, - ); - - Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0]).unwrap(); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - start_era(3); - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - // at the start of era 4, slashes from era 1 are processed, - // after being deferred for at least 2 full eras. - start_era(4); - - // the first slash for 10% was cancelled, so no effect. - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); - - start_era(5); - - let slash_10 = Perbill::from_percent(10); - let slash_15 = Perbill::from_percent(15); - let initial_slash = slash_10 * nominated_value; - - let total_slash = slash_15 * nominated_value; - let actual_slash = total_slash - initial_slash; - - // 5% slash (15 - 10) processed now. - assert_eq!(Balances::free_balance(&11), 950); - assert_eq!(Balances::free_balance(&101), 2000 - actual_slash); - }) -} - -#[test] -fn remove_multi_deferred() { - ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { - start_era(1); - - assert_eq!(Balances::free_balance(&11), 1000); - - let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); - - on_offence_now( - &[OffenceDetails { - offender: (11, exposure.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - on_offence_now( - &[OffenceDetails { - offender: (21, Staking::stakers(&21)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - - on_offence_now( - &[OffenceDetails { - offender: (11, exposure.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(25)], - ); - - assert_eq!(::UnappliedSlashes::get(&1).len(), 3); - Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0, 2]).unwrap(); - - let slashes = ::UnappliedSlashes::get(&1); - assert_eq!(slashes.len(), 1); - assert_eq!(slashes[0].validator, 21); - }) -} - -#[test] -fn version_initialized() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!( - ::StorageVersion::get(), - crate::migration::CURRENT_VERSION - ); - }); -} +use crate::{mock::*, *}; + +// #[test] +// fn force_unstake_works() { +// // Verifies initial conditions of mock +// ExtBuilder::default().build().execute_with(|| { +// // Account 11 is stashed and locked, and account 10 is the controller +// assert_eq!(Staking::bonded(&11), Some(10)); +// // Cant transfer +// assert_noop!( +// Balances::transfer(Origin::signed(11), 1, 10), +// DispatchError::Module { +// index: 0, +// error: 1, +// message: Some("LiquidityRestrictions"), +// } +// ); +// // Force unstake requires root. +// assert_noop!(Staking::force_unstake(Origin::signed(11), 11), BadOrigin); +// // We now force them to unstake +// assert_ok!(Staking::force_unstake(Origin::ROOT, 11)); +// // No longer bonded. +// assert_eq!(Staking::bonded(&11), None); +// // Transfer works. +// assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); +// }); +// } +// +// #[test] +// fn basic_setup_works() { +// // Verifies initial conditions of mock +// ExtBuilder::default().build().execute_with(|| { +// // Account 11 is stashed and locked, and account 10 is the controller +// assert_eq!(Staking::bonded(&11), Some(10)); +// // Account 21 is stashed and locked, and account 20 is the controller +// assert_eq!(Staking::bonded(&21), Some(20)); +// // Account 1 is not a stashed +// assert_eq!(Staking::bonded(&1), None); +// +// // Account 10 controls the stash from account 11, which is 100 * balance_factor units +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000, +// active: 1000, +// unlocking: vec![] +// }) +// ); +// // Account 20 controls the stash from account 21, which is 200 * balance_factor units +// assert_eq!( +// Staking::ledger(&20), +// Some(StakingLedger { +// stash: 21, +// total: 1000, +// active: 1000, +// unlocking: vec![] +// }) +// ); +// // Account 1 does not control any stash +// assert_eq!(Staking::ledger(&1), None); +// +// // ValidatorPrefs are default +// assert_eq!( +// >::enumerate().collect::>(), +// vec![ +// (31, ValidatorPrefs::default()), +// (21, ValidatorPrefs::default()), +// (11, ValidatorPrefs::default()) +// ] +// ); +// +// assert_eq!( +// Staking::ledger(100), +// Some(StakingLedger { +// stash: 101, +// total: 500, +// active: 500, +// unlocking: vec![] +// }) +// ); +// assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); +// +// if cfg!(feature = "equalize") { +// assert_eq!( +// Staking::stakers(11), +// Exposure { +// total: 1250, +// own: 1000, +// others: vec![IndividualExposure { who: 101, value: 250 }] +// } +// ); +// assert_eq!( +// Staking::stakers(21), +// Exposure { +// total: 1250, +// own: 1000, +// others: vec![IndividualExposure { who: 101, value: 250 }] +// } +// ); +// // initial slot_stake +// assert_eq!(Staking::slot_stake(), 1250); +// } else { +// assert_eq!( +// Staking::stakers(11), +// Exposure { +// total: 1125, +// own: 1000, +// others: vec![IndividualExposure { who: 101, value: 125 }] +// } +// ); +// assert_eq!( +// Staking::stakers(21), +// Exposure { +// total: 1375, +// own: 1000, +// others: vec![IndividualExposure { who: 101, value: 375 }] +// } +// ); +// // initial slot_stake +// assert_eq!(Staking::slot_stake(), 1125); +// } +// +// // The number of validators required. +// assert_eq!(Staking::validator_count(), 2); +// +// // Initial Era and session +// assert_eq!(Staking::current_era(), 0); +// +// // Account 10 has `balance_factor` free balance +// assert_eq!(Balances::free_balance(&10), 1); +// assert_eq!(Balances::free_balance(&10), 1); +// +// // New era is not being forced +// assert_eq!(Staking::force_era(), Forcing::NotForcing); +// +// // All exposures must be correct. +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[test] +// fn change_controller_works() { +// ExtBuilder::default().build().execute_with(|| { +// assert_eq!(Staking::bonded(&11), Some(10)); +// +// assert!(>::enumerate() +// .map(|(c, _)| c) +// .collect::>() +// .contains(&11)); +// // 10 can control 11 who is initially a validator. +// assert_ok!(Staking::chill(Origin::signed(10))); +// assert!(!>::enumerate() +// .map(|(c, _)| c) +// .collect::>() +// .contains(&11)); +// +// assert_ok!(Staking::set_controller(Origin::signed(11), 5)); +// +// start_era(1); +// +// assert_noop!( +// Staking::validate(Origin::signed(10), ValidatorPrefs::default()), +// Error::::NotController, +// ); +// assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default())); +// }) +// } +// +// #[test] +// fn rewards_should_work() { +// // should check that: +// // * rewards get recorded per session +// // * rewards get paid per Era +// // * Check that nominators are also rewarded +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// // Init some balances +// let _ = Balances::make_free_balance_be(&2, 500); +// +// let delay = 1000; +// let init_balance_2 = Balances::total_balance(&2); +// let init_balance_10 = Balances::total_balance(&10); +// let init_balance_11 = Balances::total_balance(&11); +// +// // Set payee to controller +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// +// // Initial config should be correct +// assert_eq!(Staking::current_era(), 0); +// assert_eq!(Session::current_index(), 0); +// +// // Add a dummy nominator. +// // +// // Equal division indicates that the reward will be equally divided among validator and +// // nominator. +// >::insert( +// &11, +// Exposure { +// own: 500, +// total: 1000, +// others: vec![IndividualExposure { who: 2, value: 500 }], +// }, +// ); +// +// >::insert(&2, RewardDestination::Stash); +// assert_eq!(Staking::payee(2), RewardDestination::Stash); +// assert_eq!(Staking::payee(11), RewardDestination::Controller); +// +// let mut block = 3; // Block 3 => Session 1 => Era 0 +// System::set_block_number(block); +// Timestamp::set_timestamp(block * 5000); // on time. +// Session::on_initialize(System::block_number()); +// assert_eq!(Staking::current_era(), 0); +// assert_eq!(Session::current_index(), 1); +// >::reward_by_ids(vec![(11, 50)]); +// >::reward_by_ids(vec![(11, 50)]); +// // This is the second validator of the current elected set. +// >::reward_by_ids(vec![(21, 50)]); +// // This must be no-op as it is not an elected validator. +// >::reward_by_ids(vec![(1001, 10_000)]); +// +// // Compute total payout now for whole duration as other parameter won't change +// let total_payout = current_total_payout_for_duration(9 * 5 * 1000); +// assert!(total_payout > 10); // Test is meaningful if reward something +// +// // No reward yet +// assert_eq!(Balances::total_balance(&2), init_balance_2); +// assert_eq!(Balances::total_balance(&10), init_balance_10); +// assert_eq!(Balances::total_balance(&11), init_balance_11); +// +// block = 6; // Block 6 => Session 2 => Era 0 +// System::set_block_number(block); +// Timestamp::set_timestamp(block * 5000 + delay); // a little late. +// Session::on_initialize(System::block_number()); +// assert_eq!(Staking::current_era(), 0); +// assert_eq!(Session::current_index(), 2); +// +// block = 9; // Block 9 => Session 3 => Era 1 +// System::set_block_number(block); +// Timestamp::set_timestamp(block * 5000); // back to being on time. no delays +// Session::on_initialize(System::block_number()); +// assert_eq!(Staking::current_era(), 1); +// assert_eq!(Session::current_index(), 3); +// +// // 11 validator has 2/3 of the total rewards and half half for it and its nominator +// assert_eq_error_rate!(Balances::total_balance(&2), init_balance_2 + total_payout / 3, 1); +// assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + total_payout / 3, 1); +// assert_eq!(Balances::total_balance(&11), init_balance_11); +// }); +// } +// +// #[test] +// fn multi_era_reward_should_work() { +// // Should check that: +// // The value of current_session_reward is set at the end of each era, based on +// // slot_stake and session_reward. +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// let init_balance_10 = Balances::total_balance(&10); +// +// // Set payee to controller +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// +// // Compute now as other parameter won't change +// let total_payout_0 = current_total_payout_for_duration(3000); +// assert!(total_payout_0 > 10); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// +// start_session(0); +// start_session(1); +// start_session(2); +// start_session(3); +// +// assert_eq!(Staking::current_era(), 1); +// assert_eq!(Balances::total_balance(&10), init_balance_10 + total_payout_0); +// +// start_session(4); +// +// let total_payout_1 = current_total_payout_for_duration(3000); +// assert!(total_payout_1 > 10); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 101)]); +// +// // new era is triggered here. +// start_session(5); +// +// // pay time +// assert_eq!( +// Balances::total_balance(&10), +// init_balance_10 + total_payout_0 + total_payout_1 +// ); +// }); +// } +// +// #[test] +// fn staking_should_work() { +// // should test: +// // * new validators can be added to the default set +// // * new ones will be chosen per era +// // * either one can unlock the stash and back-down from being a validator via `chill`ing. +// ExtBuilder::default() +// .nominate(false) +// .fair(false) // to give 20 more staked value +// .build() +// .execute_with(|| { +// Timestamp::set_timestamp(1); // Initialize time. +// +// // remember + compare this along with the test. +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // put some money in account that we'll use. +// for i in 1..5 { +// let _ = Balances::make_free_balance_be(&i, 2000); +// } +// +// // --- Block 1: +// start_session(1); +// // add a new candidate for being a validator. account 3 controlled by 4. +// assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); +// assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); +// +// // No effects will be seen so far. +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // --- Block 2: +// start_session(2); +// +// // No effects will be seen so far. Era has not been yet triggered. +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // --- Block 3: the validators will now be queued. +// start_session(3); +// assert_eq!(Staking::current_era(), 1); +// +// // --- Block 4: the validators will now be changed. +// start_session(4); +// +// assert_eq_uvec!(validator_controllers(), vec![20, 4]); +// // --- Block 4: Unstake 4 as a validator, freeing up the balance stashed in 3 +// // 4 will chill +// Staking::chill(Origin::signed(4)).unwrap(); +// +// // --- Block 5: nothing. 4 is still there. +// start_session(5); +// assert_eq_uvec!(validator_controllers(), vec![20, 4]); +// +// // --- Block 6: 4 will not be a validator. +// start_session(7); +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // Note: the stashed value of 4 is still lock +// assert_eq!( +// Staking::ledger(&4), +// Some(StakingLedger { +// stash: 3, +// total: 1500, +// active: 1500, +// unlocking: vec![] +// }) +// ); +// // e.g. it cannot spend more than 500 that it has free from the total 2000 +// assert_noop!( +// Balances::reserve(&3, 501), +// DispatchError::Module { +// index: 0, +// error: 1, +// message: Some("LiquidityRestrictions"), +// } +// ); +// assert_ok!(Balances::reserve(&3, 409)); +// }); +// } +// +// #[test] +// fn less_than_needed_candidates_works() { +// ExtBuilder::default() +// .minimum_validator_count(1) +// .validator_count(4) +// .nominate(false) +// .num_validators(3) +// .build() +// .execute_with(|| { +// assert_eq!(Staking::validator_count(), 4); +// assert_eq!(Staking::minimum_validator_count(), 1); +// assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); +// +// start_era(1); +// +// // Previous set is selected. NO election algorithm is even executed. +// assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); +// +// // But the exposure is updated in a simple way. No external votes exists. +// // This is purely self-vote. +// assert_eq!(Staking::stakers(10).others.len(), 0); +// assert_eq!(Staking::stakers(20).others.len(), 0); +// assert_eq!(Staking::stakers(30).others.len(), 0); +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[test] +// fn no_candidate_emergency_condition() { +// ExtBuilder::default() +// .minimum_validator_count(10) +// .validator_count(15) +// .num_validators(4) +// .validator_pool(true) +// .nominate(false) +// .build() +// .execute_with(|| { +// // initial validators +// assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); +// +// // set the minimum validator count. +// ::MinimumValidatorCount::put(10); +// ::ValidatorCount::put(15); +// assert_eq!(Staking::validator_count(), 15); +// +// let _ = Staking::chill(Origin::signed(10)); +// +// // trigger era +// System::set_block_number(1); +// Session::on_initialize(System::block_number()); +// +// // Previous ones are elected. chill is invalidates. TODO: #2494 +// assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); +// assert_eq!(Staking::current_elected().len(), 0); +// }); +// } +// +// #[test] +// fn nominating_and_rewards_should_work() { +// // PHRAGMEN OUTPUT: running this test with the reference impl gives: +// // +// // Sequential Phragmén gives +// // 10 is elected with stake 2200.0 and score 0.0003333333333333333 +// // 20 is elected with stake 1800.0 and score 0.0005555555555555556 +// +// // 10 has load 0.0003333333333333333 and supported +// // 10 with stake 1000.0 +// // 20 has load 0.0005555555555555556 and supported +// // 20 with stake 1000.0 +// // 30 has load 0 and supported +// // 30 with stake 0 +// // 40 has load 0 and supported +// // 40 with stake 0 +// // 2 has load 0.0005555555555555556 and supported +// // 10 with stake 600.0 20 with stake 400.0 30 with stake 0.0 +// // 4 has load 0.0005555555555555556 and supported +// // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 +// +// // Sequential Phragmén with post processing gives +// // 10 is elected with stake 2000.0 and score 0.0003333333333333333 +// // 20 is elected with stake 2000.0 and score 0.0005555555555555556 +// +// // 10 has load 0.0003333333333333333 and supported +// // 10 with stake 1000.0 +// // 20 has load 0.0005555555555555556 and supported +// // 20 with stake 1000.0 +// // 30 has load 0 and supported +// // 30 with stake 0 +// // 40 has load 0 and supported +// // 40 with stake 0 +// // 2 has load 0.0005555555555555556 and supported +// // 10 with stake 400.0 20 with stake 600.0 30 with stake 0 +// // 4 has load 0.0005555555555555556 and supported +// // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 +// ExtBuilder::default() +// .nominate(false) +// .validator_pool(true) +// .build() +// .execute_with(|| { +// // initial validators -- everyone is actually even. +// assert_eq_uvec!(validator_controllers(), vec![40, 30]); +// +// // Set payee to controller +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); +// assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); +// assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); +// +// // give the man some money +// let initial_balance = 1000; +// for i in [1, 2, 3, 4, 5, 10, 11, 20, 21].iter() { +// let _ = Balances::make_free_balance_be(i, initial_balance); +// } +// +// // bond two account pairs and state interest in nomination. +// // 2 will nominate for 10, 20, 30 +// assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); +// assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); +// // 4 will nominate for 10, 20, 40 +// assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); +// assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); +// +// // the total reward for era 0 +// let total_payout_0 = current_total_payout_for_duration(3000); +// assert!(total_payout_0 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(41, 1)]); +// >::reward_by_ids(vec![(31, 1)]); +// >::reward_by_ids(vec![(21, 10)]); // must be no-op +// >::reward_by_ids(vec![(11, 10)]); // must be no-op +// +// start_era(1); +// +// // 10 and 20 have more votes, they will be chosen by phragmen. +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // OLD validators must have already received some rewards. +// assert_eq!(Balances::total_balance(&40), 1 + total_payout_0 / 2); +// assert_eq!(Balances::total_balance(&30), 1 + total_payout_0 / 2); +// +// // ------ check the staked value of all parties. +// +// if cfg!(feature = "equalize") { +// // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. +// assert_eq!(Staking::stakers(11).own, 1000); +// assert_eq_error_rate!(Staking::stakers(11).total, 1000 + 1000, 2); +// // 2 and 4 supported 10, each with stake 600, according to phragmen. +// assert_eq!( +// Staking::stakers(11) +// .others +// .iter() +// .map(|e| e.value) +// .collect::>>(), +// vec![600, 400] +// ); +// assert_eq!( +// Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), +// vec![3, 1] +// ); +// // total expo of 20, with 500 coming from nominators (externals), according to phragmen. +// assert_eq!(Staking::stakers(21).own, 1000); +// assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1000, 2); +// // 2 and 4 supported 20, each with stake 250, according to phragmen. +// assert_eq!( +// Staking::stakers(21) +// .others +// .iter() +// .map(|e| e.value) +// .collect::>>(), +// vec![400, 600] +// ); +// assert_eq!( +// Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), +// vec![3, 1] +// ); +// } else { +// // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. +// assert_eq!(Staking::stakers(11).own, 1000); +// assert_eq!(Staking::stakers(11).total, 1000 + 800); +// // 2 and 4 supported 10, each with stake 600, according to phragmen. +// assert_eq!( +// Staking::stakers(11) +// .others +// .iter() +// .map(|e| e.value) +// .collect::>>(), +// vec![400, 400] +// ); +// assert_eq!( +// Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), +// vec![3, 1] +// ); +// // total expo of 20, with 500 coming from nominators (externals), according to phragmen. +// assert_eq!(Staking::stakers(21).own, 1000); +// assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1200, 2); +// // 2 and 4 supported 20, each with stake 250, according to phragmen. +// assert_eq!( +// Staking::stakers(21) +// .others +// .iter() +// .map(|e| e.value) +// .collect::>>(), +// vec![600, 600] +// ); +// assert_eq!( +// Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), +// vec![3, 1] +// ); +// } +// +// // They are not chosen anymore +// assert_eq!(Staking::stakers(31).total, 0); +// assert_eq!(Staking::stakers(41).total, 0); +// +// // the total reward for era 1 +// let total_payout_1 = current_total_payout_for_duration(3000); +// assert!(total_payout_1 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(41, 10)]); // must be no-op +// >::reward_by_ids(vec![(31, 10)]); // must be no-op +// >::reward_by_ids(vec![(21, 2)]); +// >::reward_by_ids(vec![(11, 1)]); +// +// start_era(2); +// +// // nothing else will happen, era ends and rewards are paid again, +// // it is expected that nominators will also be paid. See below +// +// let payout_for_10 = total_payout_1 / 3; +// let payout_for_20 = 2 * total_payout_1 / 3; +// if cfg!(feature = "equalize") { +// // Nominator 2: has [400 / 2000 ~ 1 / 5 from 10] + [600 / 2000 ~ 3 / 10 from 20]'s reward. +// assert_eq_error_rate!( +// Balances::total_balance(&2), +// initial_balance + payout_for_10 / 5 + payout_for_20 * 3 / 10, +// 2, +// ); +// // Nominator 4: has [400 / 2000 ~ 1 / 5 from 20] + [600 / 2000 ~ 3 / 10 from 10]'s reward. +// assert_eq_error_rate!( +// Balances::total_balance(&4), +// initial_balance + payout_for_20 / 5 + payout_for_10 * 3 / 10, +// 2, +// ); +// +// // Validator 10: got 1000 / 2000 external stake. +// assert_eq_error_rate!(Balances::total_balance(&10), initial_balance + payout_for_10 / 2, 1,); +// // Validator 20: got 1000 / 2000 external stake. +// assert_eq_error_rate!(Balances::total_balance(&20), initial_balance + payout_for_20 / 2, 1,); +// } else { +// // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 +// assert_eq_error_rate!( +// Balances::total_balance(&2), +// initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), +// 1, +// ); +// // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 +// assert_eq_error_rate!( +// Balances::total_balance(&4), +// initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), +// 1, +// ); +// +// // Validator 10: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 +// assert_eq_error_rate!(Balances::total_balance(&10), initial_balance + 5 * payout_for_10 / 9, 1,); +// // Validator 20: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 +// assert_eq_error_rate!( +// Balances::total_balance(&20), +// initial_balance + 5 * payout_for_20 / 11, +// 1, +// ); +// } +// +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[test] +// fn nominators_also_get_slashed() { +// // A nominator should be slashed if the validator they nominated is slashed +// // Here is the breakdown of roles: +// // 10 - is the controller of 11 +// // 11 - is the stash. +// // 2 - is the nominator of 20, 10 +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// assert_eq!(Staking::validator_count(), 2); +// +// // Set payee to controller +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// +// // give the man some money. +// let initial_balance = 1000; +// for i in [1, 2, 3, 10].iter() { +// let _ = Balances::make_free_balance_be(i, initial_balance); +// } +// +// // 2 will nominate for 10, 20 +// let nominator_stake = 500; +// assert_ok!(Staking::bond( +// Origin::signed(1), +// 2, +// nominator_stake, +// RewardDestination::default() +// )); +// assert_ok!(Staking::nominate(Origin::signed(2), vec![20, 10])); +// +// let total_payout = current_total_payout_for_duration(3000); +// assert!(total_payout > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// +// // new era, pay rewards, +// start_era(1); +// +// // Nominator stash didn't collect any. +// assert_eq!(Balances::total_balance(&2), initial_balance); +// +// // 10 goes offline +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(5)], +// ); +// let expo = Staking::stakers(11); +// let slash_value = 50; +// let total_slash = expo.total.min(slash_value); +// let validator_slash = expo.own.min(total_slash); +// let nominator_slash = nominator_stake.min(total_slash - validator_slash); +// +// // initial + first era reward + slash +// assert_eq!(Balances::total_balance(&11), initial_balance - validator_slash); +// assert_eq!(Balances::total_balance(&2), initial_balance - nominator_slash); +// check_exposure_all(); +// check_nominator_all(); +// // Because slashing happened. +// assert!(is_disabled(10)); +// }); +// } +// +// #[test] +// fn double_staking_should_fail() { +// // should test (in the same order): +// // * an account already bonded as stash cannot be be stashed again. +// // * an account already bonded as stash cannot nominate. +// // * an account already bonded as controller can nominate. +// ExtBuilder::default().build().execute_with(|| { +// let arbitrary_value = 5; +// // 2 = controller, 1 stashed => ok +// assert_ok!(Staking::bond( +// Origin::signed(1), +// 2, +// arbitrary_value, +// RewardDestination::default() +// )); +// // 4 = not used so far, 1 stashed => not allowed. +// assert_noop!( +// Staking::bond(Origin::signed(1), 4, arbitrary_value, RewardDestination::default()), +// Error::::AlreadyBonded, +// ); +// // 1 = stashed => attempting to nominate should fail. +// assert_noop!( +// Staking::nominate(Origin::signed(1), vec![1]), +// Error::::NotController +// ); +// // 2 = controller => nominating should work. +// assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); +// }); +// } +// +// #[test] +// fn double_controlling_should_fail() { +// // should test (in the same order): +// // * an account already bonded as controller CANNOT be reused as the controller of another account. +// ExtBuilder::default().build().execute_with(|| { +// let arbitrary_value = 5; +// // 2 = controller, 1 stashed => ok +// assert_ok!(Staking::bond( +// Origin::signed(1), +// 2, +// arbitrary_value, +// RewardDestination::default(), +// )); +// // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op +// assert_noop!( +// Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), +// Error::::AlreadyPaired, +// ); +// }); +// } +// +// #[test] +// fn session_and_eras_work() { +// ExtBuilder::default().build().execute_with(|| { +// assert_eq!(Staking::current_era(), 0); +// +// // Block 1: No change. +// start_session(0); +// assert_eq!(Session::current_index(), 1); +// assert_eq!(Staking::current_era(), 0); +// +// // Block 2: Simple era change. +// start_session(2); +// assert_eq!(Session::current_index(), 3); +// assert_eq!(Staking::current_era(), 1); +// +// // Block 3: Schedule an era length change; no visible changes. +// start_session(3); +// assert_eq!(Session::current_index(), 4); +// assert_eq!(Staking::current_era(), 1); +// +// // Block 4: Era change kicks in. +// start_session(5); +// assert_eq!(Session::current_index(), 6); +// assert_eq!(Staking::current_era(), 2); +// +// // Block 5: No change. +// start_session(6); +// assert_eq!(Session::current_index(), 7); +// assert_eq!(Staking::current_era(), 2); +// +// // Block 6: No change. +// start_session(7); +// assert_eq!(Session::current_index(), 8); +// assert_eq!(Staking::current_era(), 2); +// +// // Block 7: Era increment. +// start_session(8); +// assert_eq!(Session::current_index(), 9); +// assert_eq!(Staking::current_era(), 3); +// }); +// } +// +// #[test] +// fn forcing_new_era_works() { +// ExtBuilder::default().build().execute_with(|| { +// // normal flow of session. +// assert_eq!(Staking::current_era(), 0); +// start_session(0); +// assert_eq!(Staking::current_era(), 0); +// start_session(1); +// assert_eq!(Staking::current_era(), 0); +// start_session(2); +// assert_eq!(Staking::current_era(), 1); +// +// // no era change. +// ForceEra::put(Forcing::ForceNone); +// start_session(3); +// assert_eq!(Staking::current_era(), 1); +// start_session(4); +// assert_eq!(Staking::current_era(), 1); +// start_session(5); +// assert_eq!(Staking::current_era(), 1); +// start_session(6); +// assert_eq!(Staking::current_era(), 1); +// +// // back to normal. +// // this immediately starts a new session. +// ForceEra::put(Forcing::NotForcing); +// start_session(7); +// assert_eq!(Staking::current_era(), 2); +// start_session(8); +// assert_eq!(Staking::current_era(), 2); +// +// // forceful change +// ForceEra::put(Forcing::ForceAlways); +// start_session(9); +// assert_eq!(Staking::current_era(), 3); +// start_session(10); +// assert_eq!(Staking::current_era(), 4); +// start_session(11); +// assert_eq!(Staking::current_era(), 5); +// +// // just one forceful change +// ForceEra::put(Forcing::ForceNew); +// start_session(12); +// assert_eq!(Staking::current_era(), 6); +// +// assert_eq!(ForceEra::get(), Forcing::NotForcing); +// start_session(13); +// assert_eq!(Staking::current_era(), 6); +// }); +// } +// +// #[test] +// fn cannot_transfer_staked_balance() { +// // Tests that a stash account cannot transfer funds +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// // Confirm account 11 is stashed +// assert_eq!(Staking::bonded(&11), Some(10)); +// // Confirm account 11 has some free balance +// assert_eq!(Balances::free_balance(&11), 1000); +// // Confirm account 11 (via controller 10) is totally staked +// assert_eq!(Staking::stakers(&11).total, 1000); +// // Confirm account 11 cannot transfer as a result +// assert_noop!( +// Balances::transfer(Origin::signed(11), 20, 1), +// DispatchError::Module { +// index: 0, +// error: 1, +// message: Some("LiquidityRestrictions"), +// } +// ); +// +// // Give account 11 extra free balance +// let _ = Balances::make_free_balance_be(&11, 10000); +// // Confirm that account 11 can now transfer some balance +// assert_ok!(Balances::transfer(Origin::signed(11), 20, 1)); +// }); +// } +// +// #[test] +// fn cannot_transfer_staked_balance_2() { +// // Tests that a stash account cannot transfer funds +// // Same test as above but with 20, and more accurate. +// // 21 has 2000 free balance but 1000 at stake +// ExtBuilder::default() +// .nominate(false) +// .fair(true) +// .build() +// .execute_with(|| { +// // Confirm account 21 is stashed +// assert_eq!(Staking::bonded(&21), Some(20)); +// // Confirm account 21 has some free balance +// assert_eq!(Balances::free_balance(&21), 2000); +// // Confirm account 21 (via controller 20) is totally staked +// assert_eq!(Staking::stakers(&21).total, 1000); +// // Confirm account 21 can transfer at most 1000 +// assert_noop!( +// Balances::transfer(Origin::signed(21), 20, 1001), +// DispatchError::Module { +// index: 0, +// error: 1, +// message: Some("LiquidityRestrictions"), +// } +// ); +// assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000)); +// }); +// } +// +// #[test] +// fn cannot_reserve_staked_balance() { +// // Checks that a bonded account cannot reserve balance from free balance +// ExtBuilder::default().build().execute_with(|| { +// // Confirm account 11 is stashed +// assert_eq!(Staking::bonded(&11), Some(10)); +// // Confirm account 11 has some free balance +// assert_eq!(Balances::free_balance(&11), 1000); +// // Confirm account 11 (via controller 10) is totally staked +// assert_eq!(Staking::stakers(&11).own, 1000); +// // Confirm account 11 cannot transfer as a result +// assert_noop!( +// Balances::reserve(&11, 1), +// DispatchError::Module { +// index: 0, +// error: 1, +// message: Some("LiquidityRestrictions"), +// } +// ); +// +// // Give account 11 extra free balance +// let _ = Balances::make_free_balance_be(&11, 10000); +// // Confirm account 11 can now reserve balance +// assert_ok!(Balances::reserve(&11, 1)); +// }); +// } +// +// #[test] +// fn reward_destination_works() { +// // Rewards go to the correct destination as determined in Payee +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// // Check that account 11 is a validator +// assert!(Staking::current_elected().contains(&11)); +// // Check the balance of the validator account +// assert_eq!(Balances::free_balance(&10), 1); +// // Check the balance of the stash account +// assert_eq!(Balances::free_balance(&11), 1000); +// // Check how much is at stake +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000, +// active: 1000, +// unlocking: vec![], +// }) +// ); +// +// // Compute total payout now for whole duration as other parameter won't change +// let total_payout_0 = current_total_payout_for_duration(3000); +// assert!(total_payout_0 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// +// start_era(1); +// +// // Check that RewardDestination is Staked (default) +// assert_eq!(Staking::payee(&11), RewardDestination::Staked); +// // Check that reward went to the stash account of validator +// assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0); +// // Check that amount at stake increased accordingly +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + total_payout_0, +// active: 1000 + total_payout_0, +// unlocking: vec![], +// }) +// ); +// +// //Change RewardDestination to Stash +// >::insert(&11, RewardDestination::Stash); +// +// // Compute total payout now for whole duration as other parameter won't change +// let total_payout_1 = current_total_payout_for_duration(3000); +// assert!(total_payout_1 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// +// start_era(2); +// +// // Check that RewardDestination is Stash +// assert_eq!(Staking::payee(&11), RewardDestination::Stash); +// // Check that reward went to the stash account +// assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0 + total_payout_1); +// // Record this value +// let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; +// // Check that amount at stake is NOT increased +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + total_payout_0, +// active: 1000 + total_payout_0, +// unlocking: vec![], +// }) +// ); +// +// // Change RewardDestination to Controller +// >::insert(&11, RewardDestination::Controller); +// +// // Check controller balance +// assert_eq!(Balances::free_balance(&10), 1); +// +// // Compute total payout now for whole duration as other parameter won't change +// let total_payout_2 = current_total_payout_for_duration(3000); +// assert!(total_payout_2 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// +// start_era(3); +// +// // Check that RewardDestination is Controller +// assert_eq!(Staking::payee(&11), RewardDestination::Controller); +// // Check that reward went to the controller account +// assert_eq!(Balances::free_balance(&10), 1 + total_payout_2); +// // Check that amount at stake is NOT increased +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + total_payout_0, +// active: 1000 + total_payout_0, +// unlocking: vec![], +// }) +// ); +// // Check that amount in staked account is NOT increased. +// assert_eq!(Balances::free_balance(&11), recorded_stash_balance); +// }); +// } +// +// #[test] +// fn validator_payment_prefs_work() { +// // Test that validator preferences are correctly honored +// // Note: unstake threshold is being directly tested in slashing tests. +// // This test will focus on validator payment. +// ExtBuilder::default().build().execute_with(|| { +// // Initial config +// let stash_initial_balance = Balances::total_balance(&11); +// +// // check the balance of a validator accounts. +// assert_eq!(Balances::total_balance(&10), 1); +// // check the balance of a validator's stash accounts. +// assert_eq!(Balances::total_balance(&11), stash_initial_balance); +// // and the nominator (to-be) +// let _ = Balances::make_free_balance_be(&2, 500); +// +// // add a dummy nominator. +// >::insert( +// &11, +// Exposure { +// own: 500, // equal division indicates that the reward will be equally divided among validator and nominator. +// total: 1000, +// others: vec![IndividualExposure { who: 2, value: 500 }], +// }, +// ); +// >::insert(&2, RewardDestination::Stash); +// >::insert( +// &11, +// ValidatorPrefs { +// commission: Perbill::from_percent(50), +// }, +// ); +// +// // Compute total payout now for whole duration as other parameter won't change +// let total_payout_0 = current_total_payout_for_duration(3000); +// assert!(total_payout_0 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// +// start_era(1); +// +// // whats left to be shared is the sum of 3 rounds minus the validator's cut. +// let shared_cut = total_payout_0 / 2; +// // Validator's payee is Staked account, 11, reward will be paid here. +// assert_eq!( +// Balances::total_balance(&11), +// stash_initial_balance + shared_cut / 2 + shared_cut +// ); +// // Controller account will not get any reward. +// assert_eq!(Balances::total_balance(&10), 1); +// // Rest of the reward will be shared and paid to the nominator in stake. +// assert_eq!(Balances::total_balance(&2), 500 + shared_cut / 2); +// +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[test] +// fn bond_extra_works() { +// // Tests that extra `free_balance` in the stash can be added to stake +// // NOTE: this tests only verifies `StakingLedger` for correct updates +// // See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`. +// ExtBuilder::default().build().execute_with(|| { +// // Check that account 10 is a validator +// assert!(>::exists(11)); +// // Check that account 10 is bonded to account 11 +// assert_eq!(Staking::bonded(&11), Some(10)); +// // Check how much is at stake +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000, +// active: 1000, +// unlocking: vec![], +// }) +// ); +// +// // Give account 11 some large free balance greater than total +// let _ = Balances::make_free_balance_be(&11, 1000000); +// +// // Call the bond_extra function from controller, add only 100 +// assert_ok!(Staking::bond_extra(Origin::signed(11), 100)); +// // There should be 100 more `total` and `active` in the ledger +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + 100, +// active: 1000 + 100, +// unlocking: vec![], +// }) +// ); +// +// // Call the bond_extra function with a large number, should handle it +// assert_ok!(Staking::bond_extra(Origin::signed(11), u64::max_value())); +// // The full amount of the funds should now be in the total and active +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000000, +// active: 1000000, +// unlocking: vec![], +// }) +// ); +// }); +// } +// +// #[test] +// fn bond_extra_and_withdraw_unbonded_works() { +// // * Should test +// // * Given an account being bonded [and chosen as a validator](not mandatory) +// // * It can add extra funds to the bonded account. +// // * it can unbond a portion of its funds from the stash account. +// // * Once the unbonding period is done, it can actually take the funds out of the stash. +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// // Set payee to controller. avoids confusion +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// +// // Give account 11 some large free balance greater than total +// let _ = Balances::make_free_balance_be(&11, 1000000); +// +// // Initial config should be correct +// assert_eq!(Staking::current_era(), 0); +// assert_eq!(Session::current_index(), 0); +// +// // check the balance of a validator accounts. +// assert_eq!(Balances::total_balance(&10), 1); +// +// // confirm that 10 is a normal validator and gets paid at the end of the era. +// start_era(1); +// +// // Initial state of 10 +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000, +// active: 1000, +// unlocking: vec![], +// }) +// ); +// assert_eq!( +// Staking::stakers(&11), +// Exposure { +// total: 1000, +// own: 1000, +// others: vec![] +// } +// ); +// +// // deposit the extra 100 units +// Staking::bond_extra(Origin::signed(11), 100).unwrap(); +// +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + 100, +// active: 1000 + 100, +// unlocking: vec![], +// }) +// ); +// // Exposure is a snapshot! only updated after the next era update. +// assert_ne!( +// Staking::stakers(&11), +// Exposure { +// total: 1000 + 100, +// own: 1000 + 100, +// others: vec![] +// } +// ); +// +// // trigger next era. +// Timestamp::set_timestamp(10); +// start_era(2); +// assert_eq!(Staking::current_era(), 2); +// +// // ledger should be the same. +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + 100, +// active: 1000 + 100, +// unlocking: vec![], +// }) +// ); +// // Exposure is now updated. +// assert_eq!( +// Staking::stakers(&11), +// Exposure { +// total: 1000 + 100, +// own: 1000 + 100, +// others: vec![] +// } +// ); +// +// // Unbond almost all of the funds in stash. +// Staking::unbond(Origin::signed(10), 1000).unwrap(); +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + 100, +// active: 100, +// unlocking: vec![UnlockChunk { +// value: 1000, +// era: 2 + 3 +// }] +// }) +// ); +// +// // Attempting to free the balances now will fail. 2 eras need to pass. +// Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + 100, +// active: 100, +// unlocking: vec![UnlockChunk { +// value: 1000, +// era: 2 + 3 +// }] +// }) +// ); +// +// // trigger next era. +// start_era(3); +// +// // nothing yet +// Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 1000 + 100, +// active: 100, +// unlocking: vec![UnlockChunk { +// value: 1000, +// era: 2 + 3 +// }] +// }) +// ); +// +// // trigger next era. +// start_era(5); +// +// Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); +// // Now the value is free and the staking ledger is updated. +// assert_eq!( +// Staking::ledger(&10), +// Some(StakingLedger { +// stash: 11, +// total: 100, +// active: 100, +// unlocking: vec![] +// }) +// ); +// }) +// } +// +// #[test] +// fn too_many_unbond_calls_should_not_work() { +// ExtBuilder::default().build().execute_with(|| { +// // locked at era 0 until 3 +// for _ in 0..MAX_UNLOCKING_CHUNKS - 1 { +// assert_ok!(Staking::unbond(Origin::signed(10), 1)); +// } +// +// start_era(1); +// +// // locked at era 1 until 4 +// assert_ok!(Staking::unbond(Origin::signed(10), 1)); +// // can't do more. +// assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); +// +// start_era(3); +// +// assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); +// // free up. +// assert_ok!(Staking::withdraw_unbonded(Origin::signed(10))); +// +// // Can add again. +// assert_ok!(Staking::unbond(Origin::signed(10), 1)); +// assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2); +// }) +// } +// +// #[test] +// fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() { +// // Test that slot_stake is determined by the least staked validator +// // Test that slot_stake is the maximum punishment that can happen to a validator +// ExtBuilder::default() +// .nominate(false) +// .fair(false) +// .build() +// .execute_with(|| { +// // Confirm validator count is 2 +// assert_eq!(Staking::validator_count(), 2); +// // Confirm account 10 and 20 are validators +// assert!(>::exists(&11) && >::exists(&21)); +// +// assert_eq!(Staking::stakers(&11).total, 1000); +// assert_eq!(Staking::stakers(&21).total, 2000); +// +// // Give the man some money. +// let _ = Balances::make_free_balance_be(&10, 1000); +// let _ = Balances::make_free_balance_be(&20, 1000); +// +// // We confirm initialized slot_stake is this value +// assert_eq!(Staking::slot_stake(), Staking::stakers(&11).total); +// +// // Now lets lower account 20 stake +// >::insert( +// &21, +// Exposure { +// total: 69, +// own: 69, +// others: vec![], +// }, +// ); +// assert_eq!(Staking::stakers(&21).total, 69); +// >::insert( +// &20, +// StakingLedger { +// stash: 22, +// total: 69, +// active: 69, +// unlocking: vec![], +// }, +// ); +// +// // Compute total payout now for whole duration as other parameter won't change +// let total_payout_0 = current_total_payout_for_duration(3000); +// assert!(total_payout_0 > 100); // Test is meaningfull if reward something +// >::reward_by_ids(vec![(11, 1)]); +// >::reward_by_ids(vec![(21, 1)]); +// +// // New era --> rewards are paid --> stakes are changed +// start_era(1); +// +// // -- new balances + reward +// assert_eq!(Staking::stakers(&11).total, 1000 + total_payout_0 / 2); +// assert_eq!(Staking::stakers(&21).total, 69 + total_payout_0 / 2); +// +// let _11_balance = Balances::free_balance(&11); +// assert_eq!(_11_balance, 1000 + total_payout_0 / 2); +// +// // -- slot stake should also be updated. +// assert_eq!(Staking::slot_stake(), 69 + total_payout_0 / 2); +// +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[test] +// fn on_free_balance_zero_stash_removes_validator() { +// // Tests that validator storage items are cleaned up when stash is empty +// // Tests that storage items are untouched when controller is empty +// ExtBuilder::default().existential_deposit(10).build().execute_with(|| { +// // Check the balance of the validator account +// assert_eq!(Balances::free_balance(&10), 256); +// // Check the balance of the stash account +// assert_eq!(Balances::free_balance(&11), 256000); +// // Check these two accounts are bonded +// assert_eq!(Staking::bonded(&11), Some(10)); +// +// // Set some storage items which we expect to be cleaned up +// // Set payee information +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); +// +// // Check storage items that should be cleaned up +// assert!(>::exists(&10)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// +// // Reduce free_balance of controller to 0 +// let _ = Balances::slash(&10, u64::max_value()); +// +// // Check the balance of the stash account has not been touched +// assert_eq!(Balances::free_balance(&11), 256000); +// // Check these two accounts are still bonded +// assert_eq!(Staking::bonded(&11), Some(10)); +// +// // Check storage items have not changed +// assert!(>::exists(&10)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// +// // Reduce free_balance of stash to 0 +// let _ = Balances::slash(&11, u64::max_value()); +// // Check total balance of stash +// assert_eq!(Balances::total_balance(&11), 0); +// +// // Check storage items do not exist +// assert!(!>::exists(&10)); +// assert!(!>::exists(&11)); +// assert!(!>::exists(&11)); +// assert!(!>::exists(&11)); +// assert!(!>::exists(&11)); +// }); +// } +// +// #[test] +// fn on_free_balance_zero_stash_removes_nominator() { +// // Tests that nominator storage items are cleaned up when stash is empty +// // Tests that storage items are untouched when controller is empty +// ExtBuilder::default().existential_deposit(10).build().execute_with(|| { +// // Make 10 a nominator +// assert_ok!(Staking::nominate(Origin::signed(10), vec![20])); +// // Check that account 10 is a nominator +// assert!(>::exists(11)); +// // Check the balance of the nominator account +// assert_eq!(Balances::free_balance(&10), 256); +// // Check the balance of the stash account +// assert_eq!(Balances::free_balance(&11), 256000); +// +// // Set payee information +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); +// +// // Check storage items that should be cleaned up +// assert!(>::exists(&10)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// +// // Reduce free_balance of controller to 0 +// let _ = Balances::slash(&10, u64::max_value()); +// // Check total balance of account 10 +// assert_eq!(Balances::total_balance(&10), 0); +// +// // Check the balance of the stash account has not been touched +// assert_eq!(Balances::free_balance(&11), 256000); +// // Check these two accounts are still bonded +// assert_eq!(Staking::bonded(&11), Some(10)); +// +// // Check storage items have not changed +// assert!(>::exists(&10)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// assert!(>::exists(&11)); +// +// // Reduce free_balance of stash to 0 +// let _ = Balances::slash(&11, u64::max_value()); +// // Check total balance of stash +// assert_eq!(Balances::total_balance(&11), 0); +// +// // Check storage items do not exist +// assert!(!>::exists(&10)); +// assert!(!>::exists(&11)); +// assert!(!>::exists(&11)); +// assert!(!>::exists(&11)); +// assert!(!>::exists(&11)); +// }); +// } +// +// #[test] +// fn switching_roles() { +// // Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead. +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// Timestamp::set_timestamp(1); // Initialize time. +// +// // Reset reward destination +// for i in &[10, 20] { +// assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); +// } +// +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // put some money in account that we'll use. +// for i in 1..7 { +// let _ = Balances::deposit_creating(&i, 5000); +// } +// +// // add 2 nominators +// assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller)); +// assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5])); +// +// assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); +// assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1])); +// +// // add a new validator candidate +// assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller)); +// assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); +// +// // new block +// start_session(1); +// +// // no change +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // new block +// start_session(2); +// +// // no change +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// +// // new block --> ne era --> new validators +// start_session(3); +// +// // with current nominators 10 and 5 have the most stake +// assert_eq_uvec!(validator_controllers(), vec![6, 10]); +// +// // 2 decides to be a validator. Consequences: +// assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); +// // new stakes: +// // 10: 1000 self vote +// // 20: 1000 self vote + 250 vote +// // 6 : 1000 self vote +// // 2 : 2000 self vote + 250 vote. +// // Winners: 20 and 2 +// +// start_session(4); +// assert_eq_uvec!(validator_controllers(), vec![6, 10]); +// +// start_session(5); +// assert_eq_uvec!(validator_controllers(), vec![6, 10]); +// +// // ne era +// start_session(6); +// assert_eq_uvec!(validator_controllers(), vec![2, 20]); +// +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[test] +// fn wrong_vote_is_null() { +// ExtBuilder::default() +// .nominate(false) +// .validator_pool(true) +// .build() +// .execute_with(|| { +// assert_eq_uvec!(validator_controllers(), vec![40, 30]); +// +// // put some money in account that we'll use. +// for i in 1..3 { +// let _ = Balances::deposit_creating(&i, 5000); +// } +// +// // add 1 nominators +// assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::default())); +// assert_ok!(Staking::nominate( +// Origin::signed(2), +// vec![ +// 11, 21, // good votes +// 1, 2, 15, 1000, 25 // crap votes. No effect. +// ] +// )); +// +// // new block +// start_era(1); +// +// assert_eq_uvec!(validator_controllers(), vec![20, 10]); +// }); +// } +// +// #[test] +// fn bond_with_no_staked_value() { +// // Behavior when someone bonds with no staked value. +// // Particularly when she votes and the candidate is elected. +// ExtBuilder::default() +// .validator_count(3) +// .existential_deposit(5) +// .nominate(false) +// .minimum_validator_count(1) +// .build() +// .execute_with(|| { +// // Can't bond with 1 +// assert_noop!( +// Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), +// Error::::InsufficientValue, +// ); +// // bonded with absolute minimum value possible. +// assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); +// assert_eq!(Balances::locks(&1)[0].amount, 5); +// +// // unbonding even 1 will cause all to be unbonded. +// assert_ok!(Staking::unbond(Origin::signed(2), 1)); +// assert_eq!( +// Staking::ledger(2), +// Some(StakingLedger { +// stash: 1, +// active: 0, +// total: 5, +// unlocking: vec![UnlockChunk { value: 5, era: 3 }] +// }) +// ); +// +// start_era(1); +// start_era(2); +// +// // not yet removed. +// assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); +// assert!(Staking::ledger(2).is_some()); +// assert_eq!(Balances::locks(&1)[0].amount, 5); +// +// start_era(3); +// +// // poof. Account 1 is removed from the staking system. +// assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); +// assert!(Staking::ledger(2).is_none()); +// assert_eq!(Balances::locks(&1).len(), 0); +// }); +// } +// +// #[test] +// fn bond_with_little_staked_value_bounded_by_slot_stake() { +// // Behavior when someone bonds with little staked value. +// // Particularly when she votes and the candidate is elected. +// ExtBuilder::default() +// .validator_count(3) +// .nominate(false) +// .minimum_validator_count(1) +// .build() +// .execute_with(|| { +// // setup +// assert_ok!(Staking::chill(Origin::signed(30))); +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// let init_balance_2 = Balances::free_balance(&2); +// let init_balance_10 = Balances::free_balance(&10); +// +// // Stingy validator. +// assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); +// assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); +// +// let total_payout_0 = current_total_payout_for_duration(3000); +// assert!(total_payout_0 > 100); // Test is meaningfull if reward something +// reward_all_elected(); +// start_era(1); +// +// // 2 is elected. +// // and fucks up the slot stake. +// assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); +// assert_eq!(Staking::slot_stake(), 1); +// +// // Old ones are rewarded. +// assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3); +// // no rewards paid to 2. This was initial election. +// assert_eq!(Balances::free_balance(&2), init_balance_2); +// +// let total_payout_1 = current_total_payout_for_duration(3000); +// assert!(total_payout_1 > 100); // Test is meaningfull if reward something +// reward_all_elected(); +// start_era(2); +// +// assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); +// assert_eq!(Staking::slot_stake(), 1); +// +// assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1 / 3); +// assert_eq!( +// Balances::free_balance(&10), +// init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3, +// ); +// check_exposure_all(); +// check_nominator_all(); +// }); +// } +// +// #[cfg(feature = "equalize")] +// #[test] +// fn phragmen_linear_worse_case_equalize() { +// ExtBuilder::default() +// .nominate(false) +// .validator_pool(true) +// .fair(true) +// .build() +// .execute_with(|| { +// bond_validator(50, 1000); +// bond_validator(60, 1000); +// bond_validator(70, 1000); +// +// bond_nominator(2, 2000, vec![11]); +// bond_nominator(4, 1000, vec![11, 21]); +// bond_nominator(6, 1000, vec![21, 31]); +// bond_nominator(8, 1000, vec![31, 41]); +// bond_nominator(110, 1000, vec![41, 51]); +// bond_nominator(120, 1000, vec![51, 61]); +// bond_nominator(130, 1000, vec![61, 71]); +// +// for i in &[10, 20, 30, 40, 50, 60, 70] { +// assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); +// } +// +// assert_eq_uvec!(validator_controllers(), vec![40, 30]); +// assert_ok!(Staking::set_validator_count(Origin::ROOT, 7)); +// +// start_era(1); +// +// assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]); +// +// assert_eq_error_rate!(Staking::stakers(11).total, 3000, 2); +// assert_eq_error_rate!(Staking::stakers(21).total, 2255, 2); +// assert_eq_error_rate!(Staking::stakers(31).total, 2255, 2); +// assert_eq_error_rate!(Staking::stakers(41).total, 1925, 2); +// assert_eq_error_rate!(Staking::stakers(51).total, 1870, 2); +// assert_eq_error_rate!(Staking::stakers(61).total, 1890, 2); +// assert_eq_error_rate!(Staking::stakers(71).total, 1800, 2); +// +// check_exposure_all(); +// check_nominator_all(); +// }) +// } +// +// #[test] +// fn new_era_elects_correct_number_of_validators() { +// ExtBuilder::default() +// .nominate(true) +// .validator_pool(true) +// .fair(true) +// .validator_count(1) +// .build() +// .execute_with(|| { +// assert_eq!(Staking::validator_count(), 1); +// assert_eq!(validator_controllers().len(), 1); +// +// System::set_block_number(1); +// Session::on_initialize(System::block_number()); +// +// assert_eq!(validator_controllers().len(), 1); +// check_exposure_all(); +// check_nominator_all(); +// }) +// } +// +// #[test] +// fn phragmen_should_not_overflow_validators() { +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// let _ = Staking::chill(Origin::signed(10)); +// let _ = Staking::chill(Origin::signed(20)); +// +// bond_validator(2, u64::max_value()); +// bond_validator(4, u64::max_value()); +// +// bond_nominator(6, u64::max_value() / 2, vec![3, 5]); +// bond_nominator(8, u64::max_value() / 2, vec![3, 5]); +// +// start_era(1); +// +// assert_eq_uvec!(validator_controllers(), vec![4, 2]); +// +// // This test will fail this. Will saturate. +// // check_exposure_all(); +// assert_eq!(Staking::stakers(3).total, u64::max_value()); +// assert_eq!(Staking::stakers(5).total, u64::max_value()); +// }) +// } +// +// #[test] +// fn phragmen_should_not_overflow_nominators() { +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// let _ = Staking::chill(Origin::signed(10)); +// let _ = Staking::chill(Origin::signed(20)); +// +// bond_validator(2, u64::max_value() / 2); +// bond_validator(4, u64::max_value() / 2); +// +// bond_nominator(6, u64::max_value(), vec![3, 5]); +// bond_nominator(8, u64::max_value(), vec![3, 5]); +// +// start_era(1); +// +// assert_eq_uvec!(validator_controllers(), vec![4, 2]); +// +// // Saturate. +// assert_eq!(Staking::stakers(3).total, u64::max_value()); +// assert_eq!(Staking::stakers(5).total, u64::max_value()); +// }) +// } +// +// #[test] +// fn phragmen_should_not_overflow_ultimate() { +// ExtBuilder::default().nominate(false).build().execute_with(|| { +// bond_validator(2, u64::max_value()); +// bond_validator(4, u64::max_value()); +// +// bond_nominator(6, u64::max_value(), vec![3, 5]); +// bond_nominator(8, u64::max_value(), vec![3, 5]); +// +// start_era(1); +// +// assert_eq_uvec!(validator_controllers(), vec![4, 2]); +// +// // Saturate. +// assert_eq!(Staking::stakers(3).total, u64::max_value()); +// assert_eq!(Staking::stakers(5).total, u64::max_value()); +// }) +// } +// +// #[test] +// fn reward_validator_slashing_validator_doesnt_overflow() { +// ExtBuilder::default().build().execute_with(|| { +// let stake = u32::max_value() as u64 * 2; +// let reward_slash = u32::max_value() as u64 * 2; +// +// // Assert multiplication overflows in balance arithmetic. +// assert!(stake.checked_mul(reward_slash).is_none()); +// +// // Set staker +// let _ = Balances::make_free_balance_be(&11, stake); +// >::insert( +// &11, +// Exposure { +// total: stake, +// own: stake, +// others: vec![], +// }, +// ); +// +// // Check reward +// let _ = Staking::reward_validator(&11, reward_slash); +// assert_eq!(Balances::total_balance(&11), stake * 2); +// +// // Set staker +// let _ = Balances::make_free_balance_be(&11, stake); +// let _ = Balances::make_free_balance_be(&2, stake); +// +// // only slashes out of bonded stake are applied. without this line, +// // it is 0. +// Staking::bond(Origin::signed(2), 20000, stake - 1, RewardDestination::default()).unwrap(); +// >::insert( +// &11, +// Exposure { +// total: stake, +// own: 1, +// others: vec![IndividualExposure { +// who: 2, +// value: stake - 1, +// }], +// }, +// ); +// +// // Check slashing +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(100)], +// ); +// +// assert_eq!(Balances::total_balance(&11), stake - 1); +// assert_eq!(Balances::total_balance(&2), 1); +// }) +// } +// +// #[test] +// fn reward_from_authorship_event_handler_works() { +// ExtBuilder::default().build().execute_with(|| { +// use pallet_authorship::EventHandler; +// +// assert_eq!(>::author(), 11); +// +// >::note_author(11); +// >::note_uncle(21, 1); +// // An uncle author that is not currently elected doesn't get rewards, +// // but the block producer does get reward for referencing it. +// >::note_uncle(31, 1); +// // Rewarding the same two times works. +// >::note_uncle(11, 1); +// +// // Not mandatory but must be coherent with rewards +// assert_eq!(>::get(), vec![21, 11]); +// +// // 21 is rewarded as an uncle producer +// // 11 is rewarded as a block producer and uncle referencer and uncle producer +// assert_eq!(CurrentEraPointsEarned::get().individual, vec![1, 20 + 2 * 3 + 1]); +// assert_eq!(CurrentEraPointsEarned::get().total, 28); +// }) +// } +// +// #[test] +// fn add_reward_points_fns_works() { +// ExtBuilder::default().build().execute_with(|| { +// let validators = >::current_elected(); +// // Not mandatory but must be coherent with rewards +// assert_eq!(validators, vec![21, 11]); +// +// >::reward_by_indices(vec![(0, 1), (1, 1), (2, 1), (1, 1)]); +// +// >::reward_by_ids(vec![(21, 1), (11, 1), (31, 1), (11, 1)]); +// +// assert_eq!(CurrentEraPointsEarned::get().individual, vec![2, 4]); +// assert_eq!(CurrentEraPointsEarned::get().total, 6); +// }) +// } +// +// #[test] +// fn unbonded_balance_is_not_slashable() { +// ExtBuilder::default().build().execute_with(|| { +// // total amount staked is slashable. +// assert_eq!(Staking::slashable_balance_of(&11), 1000); +// +// assert_ok!(Staking::unbond(Origin::signed(10), 800)); +// +// // only the active portion. +// assert_eq!(Staking::slashable_balance_of(&11), 200); +// }) +// } +// +// #[test] +// fn era_is_always_same_length() { +// // This ensures that the sessions is always of the same length if there is no forcing no +// // session changes. +// ExtBuilder::default().build().execute_with(|| { +// start_era(1); +// assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get()); +// +// start_era(2); +// assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get() * 2); +// +// let session = Session::current_index(); +// ForceEra::put(Forcing::ForceNew); +// advance_session(); +// assert_eq!(Staking::current_era(), 3); +// assert_eq!(Staking::current_era_start_session_index(), session + 1); +// +// start_era(4); +// assert_eq!( +// Staking::current_era_start_session_index(), +// session + SessionsPerEra::get() + 1 +// ); +// }); +// } +// +// #[test] +// fn offence_forces_new_era() { +// ExtBuilder::default().build().execute_with(|| { +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(5)], +// ); +// +// assert_eq!(Staking::force_era(), Forcing::ForceNew); +// }); +// } +// +// #[test] +// fn offence_ensures_new_era_without_clobbering() { +// ExtBuilder::default().build().execute_with(|| { +// assert_ok!(Staking::force_new_era_always(Origin::ROOT)); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(5)], +// ); +// +// assert_eq!(Staking::force_era(), Forcing::ForceAlways); +// }); +// } +// +// #[test] +// fn offence_deselects_validator_when_slash_is_zero() { +// ExtBuilder::default().build().execute_with(|| { +// assert!(>::exists(11)); +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(0)], +// ); +// assert_eq!(Staking::force_era(), Forcing::ForceNew); +// assert!(!>::exists(11)); +// }); +// } +// +// #[test] +// fn slashing_performed_according_exposure() { +// // This test checks that slashing is performed according the exposure (or more precisely, +// // historical exposure), not the current balance. +// ExtBuilder::default().build().execute_with(|| { +// assert_eq!(Staking::stakers(&11).own, 1000); +// +// // Handle an offence with a historical exposure. +// on_offence_now( +// &[OffenceDetails { +// offender: ( +// 11, +// Exposure { +// total: 500, +// own: 500, +// others: vec![], +// }, +// ), +// reporters: vec![], +// }], +// &[Perbill::from_percent(50)], +// ); +// +// // The stash account should be slashed for 250 (50% of 500). +// assert_eq!(Balances::free_balance(&11), 1000 - 250); +// }); +// } +// +// #[test] +// fn slash_in_old_span_does_not_deselect() { +// ExtBuilder::default().build().execute_with(|| { +// start_era(1); +// +// assert!(>::exists(11)); +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(0)], +// ); +// assert_eq!(Staking::force_era(), Forcing::ForceNew); +// assert!(!>::exists(11)); +// +// start_era(2); +// +// Staking::validate(Origin::signed(10), Default::default()).unwrap(); +// assert_eq!(Staking::force_era(), Forcing::NotForcing); +// assert!(>::exists(11)); +// +// start_era(3); +// +// // this staker is in a new slashing span now, having re-registered after +// // their prior slash. +// +// on_offence_in_era( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(0)], +// 1, +// ); +// +// // not for zero-slash. +// assert_eq!(Staking::force_era(), Forcing::NotForcing); +// assert!(>::exists(11)); +// +// on_offence_in_era( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(100)], +// 1, +// ); +// +// // or non-zero. +// assert_eq!(Staking::force_era(), Forcing::NotForcing); +// assert!(>::exists(11)); +// assert_ledger_consistent(11); +// }); +// } +// +// #[test] +// fn reporters_receive_their_slice() { +// // This test verifies that the reporters of the offence receive their slice from the slashed +// // amount. +// ExtBuilder::default().build().execute_with(|| { +// // The reporters' reward is calculated from the total exposure. +// #[cfg(feature = "equalize")] +// let initial_balance = 1250; +// #[cfg(not(feature = "equalize"))] +// let initial_balance = 1125; +// +// assert_eq!(Staking::stakers(&11).total, initial_balance); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![1, 2], +// }], +// &[Perbill::from_percent(50)], +// ); +// +// // F1 * (reward_proportion * slash - 0) +// // 50% * (10% * initial_balance / 2) +// let reward = (initial_balance / 20) / 2; +// let reward_each = reward / 2; // split into two pieces. +// assert_eq!(Balances::free_balance(&1), 10 + reward_each); +// assert_eq!(Balances::free_balance(&2), 20 + reward_each); +// assert_ledger_consistent(11); +// }); +// } +// +// #[test] +// fn subsequent_reports_in_same_span_pay_out_less() { +// // This test verifies that the reporters of the offence receive their slice from the slashed +// // amount. +// ExtBuilder::default().build().execute_with(|| { +// // The reporters' reward is calculated from the total exposure. +// #[cfg(feature = "equalize")] +// let initial_balance = 1250; +// #[cfg(not(feature = "equalize"))] +// let initial_balance = 1125; +// +// assert_eq!(Staking::stakers(&11).total, initial_balance); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![1], +// }], +// &[Perbill::from_percent(20)], +// ); +// +// // F1 * (reward_proportion * slash - 0) +// // 50% * (10% * initial_balance * 20%) +// let reward = (initial_balance / 5) / 20; +// assert_eq!(Balances::free_balance(&1), 10 + reward); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![1], +// }], +// &[Perbill::from_percent(50)], +// ); +// +// let prior_payout = reward; +// +// // F1 * (reward_proportion * slash - prior_payout) +// // 50% * (10% * (initial_balance / 2) - prior_payout) +// let reward = ((initial_balance / 20) - prior_payout) / 2; +// assert_eq!(Balances::free_balance(&1), 10 + prior_payout + reward); +// assert_ledger_consistent(11); +// }); +// } +// +// #[test] +// fn invulnerables_are_not_slashed() { +// // For invulnerable validators no slashing is performed. +// ExtBuilder::default().invulnerables(vec![11]).build().execute_with(|| { +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&21), 2000); +// +// let exposure = Staking::stakers(&21); +// let initial_balance = Staking::slashable_balance_of(&21); +// +// let nominator_balances: Vec<_> = exposure.others.iter().map(|o| Balances::free_balance(&o.who)).collect(); +// +// on_offence_now( +// &[ +// OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }, +// OffenceDetails { +// offender: (21, Staking::stakers(&21)), +// reporters: vec![], +// }, +// ], +// &[Perbill::from_percent(50), Perbill::from_percent(20)], +// ); +// +// // The validator 11 hasn't been slashed, but 21 has been. +// assert_eq!(Balances::free_balance(&11), 1000); +// // 2000 - (0.2 * initial_balance) +// assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10)); +// +// // ensure that nominators were slashed as well. +// for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) { +// assert_eq!( +// Balances::free_balance(&other.who), +// initial_balance - (2 * other.value / 10), +// ); +// } +// assert_ledger_consistent(11); +// assert_ledger_consistent(21); +// }); +// } +// +// #[test] +// fn dont_slash_if_fraction_is_zero() { +// // Don't slash if the fraction is zero. +// ExtBuilder::default().build().execute_with(|| { +// assert_eq!(Balances::free_balance(&11), 1000); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(0)], +// ); +// +// // The validator hasn't been slashed. The new era is not forced. +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_ledger_consistent(11); +// }); +// } +// +// #[test] +// fn only_slash_for_max_in_era() { +// ExtBuilder::default().build().execute_with(|| { +// assert_eq!(Balances::free_balance(&11), 1000); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(50)], +// ); +// +// // The validator has been slashed and has been force-chilled. +// assert_eq!(Balances::free_balance(&11), 500); +// assert_eq!(Staking::force_era(), Forcing::ForceNew); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(25)], +// ); +// +// // The validator has not been slashed additionally. +// assert_eq!(Balances::free_balance(&11), 500); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(60)], +// ); +// +// // The validator got slashed 10% more. +// assert_eq!(Balances::free_balance(&11), 400); +// assert_ledger_consistent(11); +// }) +// } +// +// #[test] +// fn garbage_collection_after_slashing() { +// ExtBuilder::default().existential_deposit(1).build().execute_with(|| { +// assert_eq!(Balances::free_balance(&11), 256_000); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// assert_eq!(Balances::free_balance(&11), 256_000 - 25_600); +// assert!(::SlashingSpans::get(&11).is_some()); +// assert_eq!( +// ::SpanSlash::get(&(11, 0)).amount_slashed(), +// &25_600 +// ); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(100)], +// ); +// +// // validator and nominator slash in era are garbage-collected by era change, +// // so we don't test those here. +// +// assert_eq!(Balances::free_balance(&11), 0); +// assert!(::SlashingSpans::get(&11).is_none()); +// assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &0); +// }) +// } +// +// #[test] +// fn garbage_collection_on_window_pruning() { +// ExtBuilder::default().build().execute_with(|| { +// start_era(1); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// +// let exposure = Staking::stakers(&11); +// assert_eq!(Balances::free_balance(&101), 2000); +// let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// let now = Staking::current_era(); +// +// assert_eq!(Balances::free_balance(&11), 900); +// assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); +// +// assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); +// assert!(::NominatorSlashInEra::get(&now, &101).is_some()); +// +// // + 1 because we have to exit the bonding window. +// for era in (0..(BondingDuration::get() + 1)).map(|offset| offset + now + 1) { +// assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); +// assert!(::NominatorSlashInEra::get(&now, &101).is_some()); +// +// start_era(era); +// } +// +// assert!(::ValidatorSlashInEra::get(&now, &11).is_none()); +// assert!(::NominatorSlashInEra::get(&now, &101).is_none()); +// }) +// } +// +// #[test] +// fn slashing_nominators_by_span_max() { +// ExtBuilder::default().build().execute_with(|| { +// start_era(1); +// start_era(2); +// start_era(3); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&21), 2000); +// assert_eq!(Balances::free_balance(&101), 2000); +// assert_eq!(Staking::slashable_balance_of(&21), 1000); +// +// let exposure_11 = Staking::stakers(&11); +// let exposure_21 = Staking::stakers(&21); +// assert_eq!(Balances::free_balance(&101), 2000); +// let nominated_value_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; +// let nominated_value_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; +// +// on_offence_in_era( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// 2, +// ); +// +// assert_eq!(Balances::free_balance(&11), 900); +// +// let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; +// assert_eq!(Balances::free_balance(&101), 2000 - slash_1_amount); +// +// let expected_spans = vec![ +// slashing::SlashingSpan { +// index: 1, +// start: 4, +// length: None, +// }, +// slashing::SlashingSpan { +// index: 0, +// start: 0, +// length: Some(4), +// }, +// ]; +// +// let get_span = |account| ::SlashingSpans::get(&account).unwrap(); +// +// assert_eq!(get_span(11).iter().collect::>(), expected_spans,); +// +// assert_eq!(get_span(101).iter().collect::>(), expected_spans,); +// +// // second slash: higher era, higher value, same span. +// on_offence_in_era( +// &[OffenceDetails { +// offender: (21, Staking::stakers(&21)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(30)], +// 3, +// ); +// +// // 11 was not further slashed, but 21 and 101 were. +// assert_eq!(Balances::free_balance(&11), 900); +// assert_eq!(Balances::free_balance(&21), 1700); +// +// let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; +// assert!(slash_2_amount > slash_1_amount); +// +// // only the maximum slash in a single span is taken. +// assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount); +// +// // third slash: in same era and on same validator as first, higher +// // in-era value, but lower slash value than slash 2. +// on_offence_in_era( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(20)], +// 2, +// ); +// +// // 11 was further slashed, but 21 and 101 were not. +// assert_eq!(Balances::free_balance(&11), 800); +// assert_eq!(Balances::free_balance(&21), 1700); +// +// let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; +// assert!(slash_3_amount < slash_2_amount); +// assert!(slash_3_amount > slash_1_amount); +// +// // only the maximum slash in a single span is taken. +// assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount); +// }); +// } +// +// #[test] +// fn slashes_are_summed_across_spans() { +// ExtBuilder::default().build().execute_with(|| { +// start_era(1); +// start_era(2); +// start_era(3); +// +// assert_eq!(Balances::free_balance(&21), 2000); +// assert_eq!(Staking::slashable_balance_of(&21), 1000); +// +// let get_span = |account| ::SlashingSpans::get(&account).unwrap(); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (21, Staking::stakers(&21)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// let expected_spans = vec![ +// slashing::SlashingSpan { +// index: 1, +// start: 4, +// length: None, +// }, +// slashing::SlashingSpan { +// index: 0, +// start: 0, +// length: Some(4), +// }, +// ]; +// +// assert_eq!(get_span(21).iter().collect::>(), expected_spans); +// assert_eq!(Balances::free_balance(&21), 1900); +// +// // 21 has been force-chilled. re-signal intent to validate. +// Staking::validate(Origin::signed(20), Default::default()).unwrap(); +// +// start_era(4); +// +// assert_eq!(Staking::slashable_balance_of(&21), 900); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (21, Staking::stakers(&21)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// let expected_spans = vec![ +// slashing::SlashingSpan { +// index: 2, +// start: 5, +// length: None, +// }, +// slashing::SlashingSpan { +// index: 1, +// start: 4, +// length: Some(1), +// }, +// slashing::SlashingSpan { +// index: 0, +// start: 0, +// length: Some(4), +// }, +// ]; +// +// assert_eq!(get_span(21).iter().collect::>(), expected_spans); +// assert_eq!(Balances::free_balance(&21), 1810); +// }); +// } +// +// #[test] +// fn deferred_slashes_are_deferred() { +// ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { +// start_era(1); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// +// let exposure = Staking::stakers(&11); +// assert_eq!(Balances::free_balance(&101), 2000); +// let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, Staking::stakers(&11)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// start_era(2); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// start_era(3); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// // at the start of era 4, slashes from era 1 are processed, +// // after being deferred for at least 2 full eras. +// start_era(4); +// +// assert_eq!(Balances::free_balance(&11), 900); +// assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); +// }) +// } +// +// #[test] +// fn remove_deferred() { +// ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { +// start_era(1); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// +// let exposure = Staking::stakers(&11); +// assert_eq!(Balances::free_balance(&101), 2000); +// let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, exposure.clone()), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// start_era(2); +// +// on_offence_in_era( +// &[OffenceDetails { +// offender: (11, exposure.clone()), +// reporters: vec![], +// }], +// &[Perbill::from_percent(15)], +// 1, +// ); +// +// Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0]).unwrap(); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// start_era(3); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// // at the start of era 4, slashes from era 1 are processed, +// // after being deferred for at least 2 full eras. +// start_era(4); +// +// // the first slash for 10% was cancelled, so no effect. +// assert_eq!(Balances::free_balance(&11), 1000); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// start_era(5); +// +// let slash_10 = Perbill::from_percent(10); +// let slash_15 = Perbill::from_percent(15); +// let initial_slash = slash_10 * nominated_value; +// +// let total_slash = slash_15 * nominated_value; +// let actual_slash = total_slash - initial_slash; +// +// // 5% slash (15 - 10) processed now. +// assert_eq!(Balances::free_balance(&11), 950); +// assert_eq!(Balances::free_balance(&101), 2000 - actual_slash); +// }) +// } +// +// #[test] +// fn remove_multi_deferred() { +// ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { +// start_era(1); +// +// assert_eq!(Balances::free_balance(&11), 1000); +// +// let exposure = Staking::stakers(&11); +// assert_eq!(Balances::free_balance(&101), 2000); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, exposure.clone()), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (21, Staking::stakers(&21)), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// +// on_offence_now( +// &[OffenceDetails { +// offender: (11, exposure.clone()), +// reporters: vec![], +// }], +// &[Perbill::from_percent(25)], +// ); +// +// assert_eq!(::UnappliedSlashes::get(&1).len(), 3); +// Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0, 2]).unwrap(); +// +// let slashes = ::UnappliedSlashes::get(&1); +// assert_eq!(slashes.len(), 1); +// assert_eq!(slashes[0].validator, 21); +// }) +// } +// +// #[test] +// fn version_initialized() { +// ExtBuilder::default().build().execute_with(|| { +// assert_eq!( +// ::StorageVersion::get(), +// crate::migration::CURRENT_VERSION +// ); +// }); +// } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index eacfc51df..0e1ca2200 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -242,6 +242,7 @@ mod traits { fn remove_lock(id: LockIdentifier, who: &AccountId); } + // TODO doc pub trait Fee { fn pay_transfer_fee( transactor: &AccountId, @@ -250,7 +251,13 @@ mod traits { ) -> DispatchResult; } - // callback on eth-backing module + impl Fee for () { + fn pay_transfer_fee(_: &AccountId, _: Balance, _: ExistenceRequirement) -> DispatchResult { + Ok(()) + } + } + + /// Callback on eth-backing module pub trait OnDepositRedeem { type Balance; type Moment; From 7a24f1f5e5720deac5fa938130d685365a2f5d1d Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Mon, 24 Feb 2020 17:17:18 +0800 Subject: [PATCH 2/2] add: old tests template --- frame/staking/src/tests.rs | 1864 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1864 insertions(+) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9b49d4fc3..8c3c380a8 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2689,3 +2689,1867 @@ use crate::{mock::*, *}; // ); // }); // } + +// custom tests + +// #[test] +// fn bond_zero_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (123, 456); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(0), +// RewardDestination::Stash, +// 0, +// )); +// +// let (stash, controller) = (234, 567); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::KtonBalance(0), +// RewardDestination::Stash, +// 0, +// )); +// }); +// } +// +// #[test] +// fn normal_kton_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// { +// let (stash, controller) = (1001, 1000); +// +// let _ = Kton::deposit_creating(&stash, 10 * COIN); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::KtonBalance(10 * COIN), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 10 * COIN, +// deposit_items: vec![], +// ring_staking_lock: Default::default(), +// kton_staking_lock: StakingLock { +// staking_amount: 10 * COIN, +// unbondings: vec![], +// }, +// } +// ); +// assert_eq!( +// Kton::locks(&stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 10 * COIN, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// } +// +// { +// let (stash, controller) = (2001, 2000); +// +// // promise_month should not work for kton +// let _ = Kton::deposit_creating(&stash, 10 * COIN); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::KtonBalance(10 * COIN), +// RewardDestination::Stash, +// 12, +// )); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 10 * COIN, +// deposit_items: vec![], +// ring_staking_lock: Default::default(), +// kton_staking_lock: StakingLock { +// staking_amount: 10 * COIN, +// unbondings: vec![], +// }, +// } +// ); +// } +// }); +// } +// +// #[test] +// fn time_deposit_ring_unbond_and_withdraw_automatically_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (11, 10); +// +// let unbond_value = 10; +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(unbond_value), +// )); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1000 - unbond_value, +// unbondings: vec![NormalLock { +// amount: unbond_value, +// until: BondingDuration::get(), +// }], +// }), +// reasons: WithdrawReasons::all(), +// }], +// ); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash, +// active_ring: 1000 - unbond_value, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: StakingLock { +// staking_amount: 1000 - unbond_value, +// unbondings: vec![NormalLock { +// amount: unbond_value, +// until: BondingDuration::get(), +// }], +// }, +// kton_staking_lock: Default::default(), +// }, +// ); +// +// let unbond_start = 30; +// Timestamp::set_timestamp(unbond_start); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(COIN) +// )); +// +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 0, +// unbondings: vec![ +// NormalLock { +// amount: unbond_value, +// until: BondingDuration::get(), +// }, +// NormalLock { +// amount: 1000 - unbond_value, +// until: unbond_start + BondingDuration::get(), +// }, +// ], +// }), +// reasons: WithdrawReasons::all(), +// }], +// ); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: StakingLock { +// staking_amount: 0, +// unbondings: vec![ +// NormalLock { +// amount: unbond_value, +// until: BondingDuration::get(), +// }, +// NormalLock { +// amount: 1000 - unbond_value, +// until: unbond_start + BondingDuration::get(), +// }, +// ], +// }, +// kton_staking_lock: Default::default(), +// }, +// ); +// +// assert_err!( +// Ring::transfer(Origin::signed(stash), controller, 1), +// "account liquidity restrictions prevent withdrawal", +// ); +// +// Timestamp::set_timestamp(BondingDuration::get()); +// assert_ok!(Ring::transfer(Origin::signed(stash), controller, 1)); +// }); +// } +// +// #[test] +// fn normal_unbond_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (11, 10); +// let value = 200 * COIN; +// let promise_month = 12; +// let _ = Ring::deposit_creating(&stash, 1000 * COIN); +// +// { +// let kton_free_balance = Kton::free_balance(&stash); +// let mut ledger = Staking::ledger(controller).unwrap(); +// +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(value), +// promise_month, +// )); +// assert_eq!( +// Kton::free_balance(&stash), +// kton_free_balance + inflation::compute_kton_return::(value, promise_month) +// ); +// ledger.active_ring += value; +// ledger.active_deposit_ring += value; +// ledger.deposit_items.push(TimeDepositItem { +// value, +// start_time: 0, +// expire_time: promise_month * MONTH_IN_MILLISECONDS, +// }); +// ledger.ring_staking_lock.staking_amount += value; +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// } +// +// { +// let kton_free_balance = Kton::free_balance(&stash); +// let mut ledger = Staking::ledger(controller).unwrap(); +// +// // We try to bond 1 kton, but stash only has 0.2 Kton. +// // extra = COIN.min(20_000_000) +// // bond += 20_000_000 +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(COIN), +// 0, +// )); +// ledger.active_kton += kton_free_balance; +// ledger.kton_staking_lock.staking_amount += kton_free_balance; +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::KtonBalance(kton_free_balance) +// )); +// ledger.active_kton = 0; +// ledger.kton_staking_lock.staking_amount = 0; +// ledger.kton_staking_lock.unbondings.push(NormalLock { +// amount: kton_free_balance, +// until: BondingDuration::get(), +// }); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// } +// }); +// } +// +// #[test] +// fn punished_claim_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (1001, 1000); +// let promise_month = 36; +// let bond_value = 10; +// let _ = Ring::deposit_creating(&stash, 1000); +// let mut ledger = StakingLedger { +// stash, +// active_ring: bond_value, +// active_deposit_ring: bond_value, +// active_kton: 0, +// deposit_items: vec![TimeDepositItem { +// value: bond_value, +// start_time: 0, +// expire_time: promise_month * MONTH_IN_MILLISECONDS, +// }], +// ring_staking_lock: StakingLock { +// staking_amount: bond_value, +// unbondings: vec![], +// }, +// kton_staking_lock: Default::default(), +// }; +// +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(bond_value), +// RewardDestination::Stash, +// promise_month, +// )); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// // Kton is 0, skip `unbond_with_punish`. +// assert_ok!(Staking::try_claim_deposits_with_punish( +// Origin::signed(controller), +// promise_month * MONTH_IN_MILLISECONDS, +// )); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// +// // Set more kton balance to make it work. +// let _ = Kton::deposit_creating(&stash, COIN); +// assert_ok!(Staking::try_claim_deposits_with_punish( +// Origin::signed(controller), +// promise_month * MONTH_IN_MILLISECONDS, +// )); +// ledger.active_deposit_ring -= bond_value; +// ledger.deposit_items.clear(); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// assert_eq!(Kton::free_balance(&stash), COIN - 3); +// }); +// } +// +// #[test] +// fn transform_to_deposited_ring_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (1001, 1000); +// let _ = Ring::deposit_creating(&stash, COIN); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(COIN), +// RewardDestination::Stash, +// 0, +// )); +// let kton_free_balance = Kton::free_balance(&stash); +// let mut ledger = Staking::ledger(controller).unwrap(); +// +// assert_ok!(Staking::deposit_extra(Origin::signed(controller), COIN, 12)); +// ledger.active_deposit_ring += COIN; +// ledger.deposit_items.push(TimeDepositItem { +// value: COIN, +// start_time: 0, +// expire_time: 12 * MONTH_IN_MILLISECONDS, +// }); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// assert_eq!(Kton::free_balance(&stash), kton_free_balance + (COIN / 10000)); +// }); +// } +// +// #[test] +// fn expired_ring_should_capable_to_promise_again() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (1001, 1000); +// let _ = Ring::deposit_creating(&stash, 10); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(10), +// RewardDestination::Stash, +// 12, +// )); +// let mut ledger = Staking::ledger(controller).unwrap(); +// let ts = 13 * MONTH_IN_MILLISECONDS; +// let promise_extra_value = 5; +// +// Timestamp::set_timestamp(ts); +// assert_ok!(Staking::deposit_extra( +// Origin::signed(controller), +// promise_extra_value, +// 13, +// )); +// ledger.active_deposit_ring = promise_extra_value; +// // old deposit_item with 12 months promised removed +// ledger.deposit_items = vec![TimeDepositItem { +// value: promise_extra_value, +// start_time: ts, +// expire_time: 2 * ts, +// }]; +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// }); +// } +// +// #[test] +// fn inflation_should_be_correct() { +// ExtBuilder::default().build().execute_with(|| { +// let initial_issuance = 1_200_000_000 * COIN; +// let surplus_needed = initial_issuance - Ring::total_issuance(); +// let _ = Ring::deposit_into_existing(&11, surplus_needed); +// +// assert_eq!(Ring::total_issuance(), initial_issuance); +// }); +// +// // // breakpoint test +// // ExtBuilder::default().build().execute_with(|| { +// // gen_paired_account!(validator_1_stash(123), validator_1_controller(456), 0); +// // gen_paired_account!(validator_2_stash(234), validator_2_controller(567), 0); +// // gen_paired_account!(nominator_stash(345), nominator_controller(678), 0); +// // +// // assert_ok!(Staking::validate( +// // Origin::signed(validator_1_controller), +// // ValidatorPrefs { +// // node_name: vec![0; 8], +// // ..Default::default() +// // }, +// // )); +// // assert_ok!(Staking::validate( +// // Origin::signed(validator_2_controller), +// // ValidatorPrefs { +// // node_name: vec![1; 8], +// // ..Default::default() +// // }, +// // )); +// // assert_ok!(Staking::nominate( +// // Origin::signed(nominator_controller), +// // vec![validator_1_stash, validator_2_stash], +// // )); +// // +// // Timestamp::set_timestamp(1_575_448_345_000 - 12_000); +// // // breakpoint here +// // Staking::new_era(1); +// // +// // Timestamp::set_timestamp(1_575_448_345_000); +// // // breakpoint here +// // Staking::new_era(2); +// // +// // // breakpoint here +// // inflation::compute_total_payout::(11_999, 1_295_225_000, 9_987_999_900_000_000_000); +// // +// // loop {} +// // }); +// } +// +// #[test] +// fn validator_payment_ratio_should_work() { +// ExtBuilder::default().build().execute_with(|| { +// gen_paired_account!(validator_stash(123), validator_controller(456), 0); +// gen_paired_account!(nominator_stash(345), nominator_controller(678), 0); +// +// assert_ok!(Staking::validate( +// Origin::signed(validator_controller), +// ValidatorPrefs { +// node_name: vec![0; 8], +// validator_payment_ratio: 0, +// }, +// )); +// assert_ok!(Staking::nominate( +// Origin::signed(nominator_controller), +// vec![validator_stash], +// )); +// +// assert_eq!(Staking::reward_validator(&validator_stash, COIN).0.peek(), 0); +// +// assert_ok!(Staking::chill(Origin::signed(validator_controller))); +// assert_ok!(Staking::chill(Origin::signed(nominator_controller))); +// +// assert_ok!(Staking::validate( +// Origin::signed(validator_controller), +// ValidatorPrefs { +// node_name: vec![0; 8], +// validator_payment_ratio: 100, +// }, +// )); +// assert_ok!(Staking::nominate( +// Origin::signed(nominator_controller), +// vec![validator_stash], +// )); +// +// assert_eq!(Staking::reward_validator(&validator_stash, COIN).0.peek(), COIN); +// }); +// } +// +// #[test] +// fn check_node_name_should_work() { +// for node_name in [[0; 33].as_ref(), &[1; 34], &[2; 35]].iter() { +// let validator_prefs = ValidatorPrefs { +// node_name: (*node_name).to_vec(), +// ..Default::default() +// }; +// assert_err!(validator_prefs.check_node_name(), err::NODE_NAME_REACH_MAX); +// } +// +// for node_name in ["hello@darwinia.network"].iter() { +// let validator_prefs = ValidatorPrefs { +// node_name: (*node_name).into(), +// ..Default::default() +// }; +// assert_err!(validator_prefs.check_node_name(), err::NODE_NAME_CONTAINS_INVALID_CHARS); +// } +// +// for node_name in [ +// "com", +// "http", +// "https", +// "itering com", +// "http darwinia", +// "https darwinia", +// "http darwinia network", +// "https darwinia network", +// ] +// .iter() +// { +// let validator_prefs = ValidatorPrefs { +// node_name: (*node_name).into(), +// ..Default::default() +// }; +// assert_err!(validator_prefs.check_node_name(), err::NODE_NAME_CONTAINS_URLS); +// } +// +// for node_name in ["Darwinia Node"].iter() { +// let validator_prefs = ValidatorPrefs { +// node_name: (*node_name).into(), +// ..Default::default() +// }; +// assert_ok!(validator_prefs.check_node_name()); +// } +// } +// +// #[test] +// fn slash_should_not_touch_unbondings() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (11, 10); +// +// assert_ok!(Staking::deposit_extra(Origin::signed(controller), 1000, 12)); +// let ledger = Staking::ledger(controller).unwrap(); +// // Only deposit_ring, no normal_ring. +// assert_eq!((ledger.active_ring, ledger.active_deposit_ring), (1000, 1000)); +// +// let _ = Ring::deposit_creating(&stash, 1000); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(1000), +// 0, +// )); +// let _ = Kton::deposit_creating(&stash, 1000); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(1000), +// 0, +// )); +// +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(10) +// )); +// let ledger = Staking::ledger(controller).unwrap(); +// let unbondings = ( +// ledger.ring_staking_lock.unbondings.clone(), +// ledger.kton_staking_lock.unbondings.clone(), +// ); +// assert_eq!( +// (ledger.active_ring, ledger.active_deposit_ring), +// (1000 + 1000 - 10, 1000), +// ); +// +// >::insert( +// &stash, +// Exposure { +// total: 1, +// own: 1, +// others: vec![], +// }, +// ); +// // FIXME: slash strategy +// let _ = Staking::slash_validator(&stash, Power::max_value(), &Staking::stakers(&stash), &mut vec![]); +// let ledger = Staking::ledger(controller).unwrap(); +// assert_eq!( +// ( +// ledger.ring_staking_lock.unbondings.clone(), +// ledger.kton_staking_lock.unbondings.clone(), +// ), +// unbondings, +// ); +// assert_eq!((ledger.active_ring, ledger.active_deposit_ring), (0, 0)); +// }); +// } +// +// #[test] +// fn check_stash_already_bonded_and_controller_already_paired() { +// ExtBuilder::default().build().execute_with(|| { +// gen_paired_account!(unpaired_stash(123), unpaired_controller(456)); +// assert_err!( +// Staking::bond( +// Origin::signed(11), +// unpaired_controller, +// StakingBalances::RingBalance(COIN), +// RewardDestination::Stash, +// 0, +// ), +// err::STASH_ALREADY_BONDED, +// ); +// assert_err!( +// Staking::bond( +// Origin::signed(unpaired_stash), +// 10, +// StakingBalances::RingBalance(COIN), +// RewardDestination::Stash, +// 0, +// ), +// err::CONTROLLER_ALREADY_PAIRED, +// ); +// }); +// } +// +// #[test] +// fn pool_should_be_increased_and_decreased_correctly() { +// ExtBuilder::default().build().execute_with(|| { +// let mut ring_pool = Staking::ring_pool(); +// let mut kton_pool = Staking::kton_pool(); +// +// // bond: 100COIN +// gen_paired_account!(stash_1(111), controller_1(222), 0); +// gen_paired_account!(stash_2(333), controller_2(444), promise_month(12)); +// ring_pool += 100 * COIN; +// kton_pool += 100 * COIN; +// assert_eq!(Staking::ring_pool(), ring_pool); +// assert_eq!(Staking::kton_pool(), kton_pool); +// +// // unbond: 50Ring 50Kton +// assert_ok!(Staking::unbond( +// Origin::signed(controller_1), +// StakingBalances::RingBalance(50 * COIN) +// )); +// assert_ok!(Staking::unbond( +// Origin::signed(controller_1), +// StakingBalances::KtonBalance(25 * COIN) +// )); +// // not yet expired: promise for 12 months +// assert_ok!(Staking::unbond( +// Origin::signed(controller_2), +// StakingBalances::RingBalance(50 * COIN) +// )); +// assert_ok!(Staking::unbond( +// Origin::signed(controller_2), +// StakingBalances::KtonBalance(25 * COIN) +// )); +// ring_pool -= 50 * COIN; +// kton_pool -= 50 * COIN; +// assert_eq!(Staking::ring_pool(), ring_pool); +// assert_eq!(Staking::kton_pool(), kton_pool); +// +// // claim: 50Ring +// assert_ok!(Staking::try_claim_deposits_with_punish( +// Origin::signed(controller_2), +// promise_month * MONTH_IN_MILLISECONDS, +// )); +// // unbond deposit items: 12.5Ring +// Timestamp::set_timestamp(promise_month * MONTH_IN_MILLISECONDS); +// assert_ok!(Staking::unbond( +// Origin::signed(controller_2), +// StakingBalances::RingBalance(125 * COIN / 10), +// )); +// ring_pool -= 125 * COIN / 10; +// assert_eq!(Staking::ring_pool(), ring_pool); +// +// // slash: 37.5Ring 50Kton +// >::insert( +// &stash_1, +// Exposure { +// total: 1, +// own: 1, +// others: vec![], +// }, +// ); +// >::insert( +// &stash_2, +// Exposure { +// total: 1, +// own: 1, +// others: vec![], +// }, +// ); +// // FIXME: slash strategy +// let _ = Staking::slash_validator(&stash_1, Power::max_value(), &Staking::stakers(&stash_1), &mut vec![]); +// // FIXME: slash strategy +// let _ = Staking::slash_validator(&stash_2, Power::max_value(), &Staking::stakers(&stash_2), &mut vec![]); +// ring_pool -= 375 * COIN / 10; +// kton_pool -= 50 * COIN; +// assert_eq!(Staking::ring_pool(), ring_pool); +// assert_eq!(Staking::kton_pool(), kton_pool); +// }); +// } +// +// #[test] +// fn unbond_over_max_unbondings_chunks_should_fail() { +// ExtBuilder::default().build().execute_with(|| { +// gen_paired_account!(stash(123), controller(456)); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(COIN), +// RewardDestination::Stash, +// 0, +// )); +// +// for ts in 0..MAX_UNLOCKING_CHUNKS { +// Timestamp::set_timestamp(ts as u64); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(1) +// )); +// } +// +// assert_err!( +// Staking::unbond(Origin::signed(controller), StakingBalances::RingBalance(1)), +// err::UNLOCK_CHUNKS_REACH_MAX, +// ); +// }); +// } +// +// #[test] +// fn promise_extra_should_not_remove_unexpired_items() { +// ExtBuilder::default().build().execute_with(|| { +// gen_paired_account!(stash(123), controller(456), promise_month(12)); +// let expired_items_len = 3; +// let expiry_date = promise_month * MONTH_IN_MILLISECONDS; +// +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(5 * COIN), +// 0, +// )); +// for _ in 0..expired_items_len { +// assert_ok!(Staking::deposit_extra(Origin::signed(controller), COIN, promise_month)); +// } +// +// Timestamp::set_timestamp(expiry_date - 1); +// assert_ok!(Staking::deposit_extra( +// Origin::signed(controller), +// 2 * COIN, +// promise_month, +// )); +// assert_eq!( +// Staking::ledger(controller).unwrap().deposit_items.len(), +// 2 + expired_items_len, +// ); +// +// Timestamp::set_timestamp(expiry_date); +// assert_ok!(Staking::deposit_extra( +// Origin::signed(controller), +// 2 * COIN, +// promise_month, +// )); +// assert_eq!(Staking::ledger(controller).unwrap().deposit_items.len(), 2); +// }); +// } +// +// #[test] +// fn unbond_zero() { +// ExtBuilder::default().build().execute_with(|| { +// gen_paired_account!(stash(123), controller(456), promise_month(12)); +// let ledger = Staking::ledger(controller).unwrap(); +// +// Timestamp::set_timestamp(promise_month * MONTH_IN_MILLISECONDS); +// assert_ok!(Staking::unbond(Origin::signed(10), StakingBalances::RingBalance(0))); +// assert_ok!(Staking::unbond(Origin::signed(10), StakingBalances::KtonBalance(0))); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// }); +// } +// +// // bond 10_000 Ring for 12 months, gain 1 Kton +// // bond extra 10_000 Ring for 36 months, gain 3 Kton +// // bond extra 1 Kton +// // nominate +// // unlock the 12 months deposit item with punish +// // lost 3 Kton and 10_000 Ring's power for nominate +// #[test] +// fn yakio_q1() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, controller) = (777, 888); +// let _ = Ring::deposit_creating(&stash, 20_000); +// +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(10_000), +// RewardDestination::Stash, +// 12, +// )); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(10_000), +// 36, +// )); +// assert_eq!(Kton::free_balance(&stash), 4); +// +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(1), +// 36 +// )); +// assert_eq!(Staking::ledger(controller).unwrap().active_kton, 1); +// +// assert_ok!(Staking::nominate(Origin::signed(controller), vec![controller])); +// +// assert_ok!(Staking::try_claim_deposits_with_punish( +// Origin::signed(controller), +// 12 * MONTH_IN_MILLISECONDS, +// )); +// assert_eq!(Kton::free_balance(&stash), 1); +// +// let ledger = Staking::ledger(controller).unwrap(); +// // not enough Kton to unbond +// assert_ok!(Staking::try_claim_deposits_with_punish( +// Origin::signed(controller), +// 36 * MONTH_IN_MILLISECONDS, +// )); +// assert_eq!(Staking::ledger(controller).unwrap(), ledger); +// }); +// } +// +// // how to balance the power and calculate the reward if some validators have been chilled +// #[test] +// fn yakio_q2() { +// fn run(with_new_era: bool) -> Balance { +// let mut balance = 0; +// ExtBuilder::default().build().execute_with(|| { +// gen_paired_account!(validator_1_stash(123), validator_1_controller(456), 0); +// gen_paired_account!(validator_2_stash(234), validator_2_controller(567), 0); +// gen_paired_account!(nominator_stash(345), nominator_controller(678), 0); +// +// assert_ok!(Staking::validate( +// Origin::signed(validator_1_controller), +// ValidatorPrefs { +// node_name: vec![0; 8], +// ..Default::default() +// }, +// )); +// assert_ok!(Staking::validate( +// Origin::signed(validator_2_controller), +// ValidatorPrefs { +// node_name: vec![1; 8], +// ..Default::default() +// }, +// )); +// assert_ok!(Staking::nominate( +// Origin::signed(nominator_controller), +// vec![validator_1_stash, validator_2_stash], +// )); +// +// start_era(1); +// assert_ok!(Staking::chill(Origin::signed(validator_1_controller))); +// // assert_ok!(Staking::chill(Origin::signed(validator_2_controller))); +// if with_new_era { +// start_era(2); +// } +// let _ = Staking::reward_validator(&validator_1_stash, 1000 * COIN); +// let _ = Staking::reward_validator(&validator_2_stash, 1000 * COIN); +// +// balance = Ring::free_balance(&nominator_stash); +// }); +// +// balance +// } +// +// let free_balance = run(false); +// let free_balance_with_new_era = run(true); +// +// assert_ne!(free_balance, 0); +// assert_ne!(free_balance_with_new_era, 0); +// assert!(free_balance > free_balance_with_new_era); +// } +// +// #[test] +// fn xavier_q1() { +// ExtBuilder::default().build().execute_with(|| { +// let stash = 123; +// let controller = 456; +// let _ = Kton::deposit_creating(&stash, 10); +// +// Timestamp::set_timestamp(0); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::KtonBalance(5), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!(Timestamp::get(), 0); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 5, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Init - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Init - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(5), +// 0 +// )); +// assert_eq!(Timestamp::get(), 1); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 10, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Bond Extra - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Bond Extra - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// let unbond_start = 2; +// Timestamp::set_timestamp(unbond_start); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::KtonBalance(9) +// )); +// assert_eq!(Timestamp::get(), 2); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Unbond - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Unbond - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// assert_err!( +// Kton::transfer(Origin::signed(stash), controller, 1), +// "account liquidity restrictions prevent withdrawal", +// ); +// // println!("Locking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Locking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// Timestamp::set_timestamp(BondingDuration::get() + unbond_start); +// assert_ok!(Kton::transfer(Origin::signed(stash), controller, 1)); +// // println!("Unlocking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Unlocking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!( +// // "Unlocking Transfer - Kton StakingLedger: {:#?}", +// // Staking::ledger(controller) +// // ); +// // println!(); +// assert_eq!(Timestamp::get(), BondingDuration::get() + unbond_start); +// assert_eq!(Kton::free_balance(stash), 9); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// +// let _ = Kton::deposit_creating(&stash, 20); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(19), +// 0 +// )); +// assert_eq!(Kton::free_balance(stash), 29); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 20, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 20, +// deposit_items: vec![], +// ring_staking_lock: Default::default(), +// kton_staking_lock: StakingLock { +// staking_amount: 20, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }, +// } +// ); +// // println!("Unlocking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Unlocking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!( +// // "Unlocking Transfer - Kton StakingLedger: {:#?}", +// // Staking::ledger(controller) +// // ); +// // println!(); +// }); +// +// ExtBuilder::default().build().execute_with(|| { +// let stash = 123; +// let controller = 456; +// let _ = Ring::deposit_creating(&stash, 10); +// +// Timestamp::set_timestamp(0); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(5), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!(Timestamp::get(), 0); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 5, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Init - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Init - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(5), +// 0 +// )); +// assert_eq!(Timestamp::get(), 1); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 10, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Bond Extra - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Bond Extra - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// let unbond_start = 2; +// Timestamp::set_timestamp(unbond_start); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(9) +// )); +// assert_eq!(Timestamp::get(), 2); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Unbond - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Unbond - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// assert_err!( +// Ring::transfer(Origin::signed(stash), controller, 1), +// "account liquidity restrictions prevent withdrawal", +// ); +// // println!("Locking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Locking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// Timestamp::set_timestamp(BondingDuration::get() + unbond_start); +// assert_ok!(Ring::transfer(Origin::signed(stash), controller, 1)); +// // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Unlocking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!( +// // "Unlocking Transfer - Ring StakingLedger: {:#?}", +// // Staking::ledger(controller) +// // ); +// // println!(); +// assert_eq!(Timestamp::get(), BondingDuration::get() + unbond_start); +// assert_eq!(Ring::free_balance(stash), 9); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// +// let _ = Ring::deposit_creating(&stash, 20); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(19), +// 0 +// )); +// assert_eq!(Ring::free_balance(stash), 29); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 20, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 20, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: StakingLock { +// staking_amount: 20, +// unbondings: vec![NormalLock { +// amount: 9, +// until: BondingDuration::get() + unbond_start, +// }], +// }, +// kton_staking_lock: Default::default(), +// } +// ); +// // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Unlocking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!( +// // "Unlocking Transfer - Ring StakingLedger: {:#?}", +// // Staking::ledger(controller) +// // ); +// // println!(); +// }); +// } +// +// #[test] +// fn xavier_q2() { +// ExtBuilder::default().build().execute_with(|| { +// let stash = 123; +// let controller = 456; +// let _ = Kton::deposit_creating(&stash, 10); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::KtonBalance(5), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 5, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Init - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Init - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(4), +// 0 +// )); +// assert_eq!(Timestamp::get(), 1); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 9, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Bond Extra - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Bond Extra - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// let (unbond_start_1, unbond_value_1) = (2, 2); +// Timestamp::set_timestamp(unbond_start_1); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::KtonBalance(unbond_value_1), +// )); +// assert_eq!(Timestamp::get(), unbond_start_1); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 7, +// unbondings: vec![NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Unbond - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Unbond - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// let (unbond_start_2, unbond_value_2) = (3, 6); +// Timestamp::set_timestamp(unbond_start_2); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::KtonBalance(6) +// )); +// assert_eq!(Timestamp::get(), unbond_start_2); +// assert_eq!(Kton::free_balance(stash), 10); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Unbond - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Ok Unbond - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// assert_err!( +// Kton::transfer(Origin::signed(stash), controller, unbond_value_1), +// "account liquidity restrictions prevent withdrawal", +// ); +// // println!("Locking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Locking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// +// assert_ok!(Kton::transfer(Origin::signed(stash), controller, unbond_value_1 - 1)); +// assert_eq!(Kton::free_balance(stash), 9); +// // println!("Normal Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Normal Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// +// Timestamp::set_timestamp(BondingDuration::get() + unbond_start_1); +// assert_err!( +// Kton::transfer(Origin::signed(stash), controller, unbond_value_1 + 1), +// "account liquidity restrictions prevent withdrawal", +// ); +// // println!("Locking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Locking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// // println!(); +// assert_ok!(Kton::transfer(Origin::signed(stash), controller, unbond_value_1)); +// assert_eq!(Timestamp::get(), BondingDuration::get() + unbond_start_1); +// assert_eq!(Kton::free_balance(stash), 7); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Unlocking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Unlocking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// +// Timestamp::set_timestamp(BondingDuration::get() + unbond_start_2); +// assert_ok!(Kton::transfer(Origin::signed(stash), controller, unbond_value_2)); +// assert_eq!(Timestamp::get(), BondingDuration::get() + unbond_start_2); +// assert_eq!(Kton::free_balance(stash), 1); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Unlocking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); +// // println!("Unlocking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); +// +// let _ = Kton::deposit_creating(&stash, 1); +// // println!("Staking Ledger: {:#?}", Staking::ledger(controller).unwrap()); +// assert_eq!(Kton::free_balance(stash), 2); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(1), +// 0 +// )); +// assert_eq!( +// Kton::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 2, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// }); +// +// ExtBuilder::default().build().execute_with(|| { +// let stash = 123; +// let controller = 456; +// let _ = Ring::deposit_creating(&stash, 10); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(5), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 5, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Init - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Init - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(4), +// 0 +// )); +// assert_eq!(Timestamp::get(), 1); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 9, +// unbondings: vec![], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Bond Extra - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Bond Extra - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// let (unbond_start_1, unbond_value_1) = (2, 2); +// Timestamp::set_timestamp(unbond_start_1); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(unbond_value_1) +// )); +// assert_eq!(Timestamp::get(), unbond_start_1); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 7, +// unbondings: vec![NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Unbond - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Unbond - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// let (unbond_start_2, unbond_value_2) = (3, 6); +// Timestamp::set_timestamp(unbond_start_2); +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(6) +// )); +// assert_eq!(Timestamp::get(), unbond_start_2); +// assert_eq!(Ring::free_balance(stash), 10); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Ok Unbond - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Ok Unbond - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// assert_err!( +// Ring::transfer(Origin::signed(stash), controller, unbond_value_1), +// "account liquidity restrictions prevent withdrawal", +// ); +// // println!("Locking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Locking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// +// assert_ok!(Ring::transfer(Origin::signed(stash), controller, unbond_value_1 - 1)); +// assert_eq!(Ring::free_balance(stash), 9); +// // println!("Normal Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Normal Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// +// Timestamp::set_timestamp(BondingDuration::get() + unbond_start_1); +// assert_err!( +// Ring::transfer(Origin::signed(stash), controller, unbond_value_1 + 1), +// "account liquidity restrictions prevent withdrawal", +// ); +// // println!("Locking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Locking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// // println!(); +// assert_ok!(Ring::transfer(Origin::signed(stash), controller, unbond_value_1)); +// assert_eq!(Timestamp::get(), BondingDuration::get() + unbond_start_1); +// assert_eq!(Ring::free_balance(stash), 7); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Unlocking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// +// Timestamp::set_timestamp(BondingDuration::get() + unbond_start_2); +// assert_ok!(Ring::transfer(Origin::signed(stash), controller, unbond_value_2)); +// assert_eq!(Timestamp::get(), BondingDuration::get() + unbond_start_2); +// assert_eq!(Ring::free_balance(stash), 1); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 1, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); +// // println!("Unlocking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); +// +// let _ = Ring::deposit_creating(&stash, 1); +// // println!("Staking Ledger: {:#?}", Staking::ledger(controller).unwrap()); +// assert_eq!(Ring::free_balance(stash), 2); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(1), +// 0 +// )); +// assert_eq!( +// Ring::locks(stash), +// vec![BalanceLock { +// id: STAKING_ID, +// withdraw_lock: WithdrawLock::WithStaking(StakingLock { +// staking_amount: 2, +// unbondings: vec![ +// NormalLock { +// amount: 2, +// until: BondingDuration::get() + unbond_start_1, +// }, +// NormalLock { +// amount: 6, +// until: BondingDuration::get() + unbond_start_2, +// } +// ], +// }), +// reasons: WithdrawReasons::all(), +// }] +// ); +// }); +// } +// +// #[test] +// fn xavier_q3() { +// ExtBuilder::default().build().execute_with(|| { +// let stash = 123; +// let controller = 456; +// let _ = Kton::deposit_creating(&stash, 10); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::KtonBalance(5), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!(Timestamp::get(), 1); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 5, +// deposit_items: vec![], +// ring_staking_lock: Default::default(), +// kton_staking_lock: StakingLock { +// staking_amount: 5, +// unbondings: vec![], +// }, +// } +// ); +// // println!("Locks: {:#?}", Kton::locks(stash)); +// // println!("StakingLedger: {:#?}", Staking::ledger(controller)); +// // println!(); +// +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::KtonBalance(5) +// )); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: Default::default(), +// kton_staking_lock: StakingLock { +// staking_amount: 0, +// unbondings: vec![NormalLock { amount: 5, until: 61 }], +// }, +// } +// ); +// // println!("Locks: {:#?}", Kton::locks(stash)); +// // println!("StakingLedger: {:#?}", Staking::ledger(controller)); +// // println!(); +// +// Timestamp::set_timestamp(61); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(1), +// 0 +// )); +// assert_eq!(Timestamp::get(), 61); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 1, +// deposit_items: vec![], +// ring_staking_lock: Default::default(), +// kton_staking_lock: StakingLock { +// staking_amount: 1, +// unbondings: vec![NormalLock { amount: 5, until: 61 }], +// }, +// } +// ); +// // println!("Locks: {:#?}", Kton::locks(stash)); +// // println!("StakingLedger: {:#?}", Staking::ledger(controller)); +// // println!(); +// }); +// +// ExtBuilder::default().build().execute_with(|| { +// let stash = 123; +// let controller = 456; +// let _ = Ring::deposit_creating(&stash, 10); +// +// Timestamp::set_timestamp(1); +// assert_ok!(Staking::bond( +// Origin::signed(stash), +// controller, +// StakingBalances::RingBalance(5), +// RewardDestination::Stash, +// 0, +// )); +// assert_eq!(Timestamp::get(), 1); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 5, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: StakingLock { +// staking_amount: 5, +// unbondings: vec![], +// }, +// kton_staking_lock: Default::default(), +// } +// ); +// // println!("Locks: {:#?}", Ring::locks(stash)); +// // println!("StakingLedger: {:#?}", Staking::ledger(controller)); +// // println!(); +// +// assert_ok!(Staking::unbond( +// Origin::signed(controller), +// StakingBalances::RingBalance(5), +// )); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 0, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: StakingLock { +// staking_amount: 0, +// unbondings: vec![NormalLock { amount: 5, until: 61 }], +// }, +// kton_staking_lock: Default::default(), +// } +// ); +// // println!("Locks: {:#?}", Ring::locks(stash)); +// // println!("StakingLedger: {:#?}", Staking::ledger(controller)); +// // println!(); +// +// Timestamp::set_timestamp(61); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::RingBalance(1), +// 0 +// )); +// assert_eq!(Timestamp::get(), 61); +// assert_eq!( +// Staking::ledger(controller).unwrap(), +// StakingLedger { +// stash: 123, +// active_ring: 1, +// active_deposit_ring: 0, +// active_kton: 0, +// deposit_items: vec![], +// ring_staking_lock: StakingLock { +// staking_amount: 1, +// unbondings: vec![NormalLock { amount: 5, until: 61 }], +// }, +// kton_staking_lock: Default::default(), +// } +// ); +// // println!("Locks: {:#?}", Ring::locks(stash)); +// // println!("StakingLedger: {:#?}", Staking::ledger(controller)); +// // println!(); +// }); +// } +// +// #[test] +// fn test_payout() { +// ExtBuilder::default().build().execute_with(|| { +// // Set payee to controller +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// +// assert_eq!( +// Ring::total_issuance(), +// Ring::total_balance(&1) +// + Ring::total_balance(&2) +// + Ring::total_balance(&3) +// + Ring::total_balance(&4) +// + Ring::total_balance(&10) +// + Ring::total_balance(&11) +// + Ring::total_balance(&20) +// + Ring::total_balance(&21) +// + Ring::total_balance(&30) +// + Ring::total_balance(&31) +// + Ring::total_balance(&40) +// + Ring::total_balance(&41) +// + Ring::total_balance(&100) +// + Ring::total_balance(&101) +// + Ring::total_balance(&999) +// ); +// let left = 2000_000_000 * COIN +// - (Ring::total_balance(&1) +// + Ring::total_balance(&2) +// + Ring::total_balance(&3) +// + Ring::total_balance(&4) +// + Ring::total_balance(&10) +// + Ring::total_balance(&11) +// + Ring::total_balance(&20) +// + Ring::total_balance(&21) +// + Ring::total_balance(&30) +// + Ring::total_balance(&31) +// + Ring::total_balance(&40) +// + Ring::total_balance(&41) +// + Ring::total_balance(&100) +// + Ring::total_balance(&101) +// + Ring::total_balance(&999)); +// let _ = Ring::deposit_creating(&9999, left); +// assert_eq!(Ring::total_issuance(), 2000_000_000 * COIN); +// +// assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); +// +// let total_pay_out_now = current_total_payout_for_duration(180 * 1000); +// assert_eq!(total_pay_out_now, 456308464522 / 2); +// // // for one year, Note: this test will take over 60s +// // for i in 0..175319 { +// // start_session(i); +// // >::reward_by_ids(vec![(11, 101)]); +// // } +// // assert_eq!(current_total_payout_for_duration(1000 * 3600 * 24 * 36525 / 100), 79601332265494830 / 2); +// }); +// } + +// breakpoint test +//#[test] +//fn xavier_q4() { +// ExtBuilder::default().build().execute_with(|| { +// let (stash, _controller) = (11, 10); +// let _ = Kton::deposit_creating(&stash, 1000); +// assert_ok!(Staking::bond_extra( +// Origin::signed(stash), +// StakingBalances::KtonBalance(1000), +// 0, +// )); +// +// let power = Staking::power_of(&11); +// >::insert( +// &stash, +// Exposure { +// total: power, +// own: power, +// others: vec![], +// }, +// ); +// let _ = Staking::slash_validator(&stash, power / 2, &Staking::stakers(&stash), &mut vec![]); +// }); +//}