diff --git a/Cargo.lock b/Cargo.lock index e16083e55..29de2b0ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -723,6 +723,8 @@ name = "darwinia-kton" version = "0.1.0" dependencies = [ "darwinia-support 0.1.0", + "node-primitives 2.0.0", + "node-runtime 0.1.0", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", @@ -743,6 +745,7 @@ dependencies = [ "darwinia-balances 2.0.0", "darwinia-kton 0.1.0", "darwinia-support 0.1.0", + "node-primitives 2.0.0", "node-runtime 0.1.0", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index bb9a82001..1d59faccd 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -15,26 +15,23 @@ // along with Substrate. If not, see . //! Substrate chain configurations. +pub use node_runtime::GenesisConfig; + use babe_primitives::AuthorityId as BabeId; use chain_spec::ChainSpecExtension; use grandpa_primitives::AuthorityId as GrandpaId; use hex_literal::hex; use im_online::sr25519::AuthorityId as ImOnlineId; use node_primitives::{AccountId, Balance}; -use node_runtime::constants::currency::*; -use node_runtime::Block; -pub use node_runtime::GenesisConfig; use node_runtime::{ - AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, ContractsConfig, GrandpaConfig, ImOnlineConfig, - IndicesConfig, KtonConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, SudoConfig, SystemConfig, COIN, - WASM_BINARY, + constants::currency::*, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, ContractsConfig, + GrandpaConfig, ImOnlineConfig, IndicesConfig, KtonConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, + SudoConfig, SystemConfig, WASM_BINARY, }; use primitives::{crypto::UncheckedInto, Pair, Public}; use serde::{Deserialize, Serialize}; -use serde_json::de::ParserNumber; -use serde_json::Number; +use serde_json::{de::ParserNumber, Number}; use sr_primitives::Perbill; -use substrate_service; use substrate_service::Properties; use substrate_telemetry::TelemetryEndpoints; @@ -195,8 +192,8 @@ pub fn testnet_genesis( ] }); - const ENDOWMENT: Balance = 10_000_000 * DOLLARS; - const STASH: Balance = 100 * DOLLARS; + const ENDOWMENT: Balance = 10_000_000 * COIN; + const STASH: Balance = 100 * COIN; GenesisConfig { system: Some(SystemConfig { @@ -230,7 +227,7 @@ pub fn testnet_genesis( enable_println, // this should only be enabled on development chains ..Default::default() }, - gas_price: 1 * MILLICENTS, + gas_price: 1 * MICRO, }), sudo: Some(SudoConfig { key: root_key }), babe: Some(BabeConfig { authorities: vec![] }), @@ -385,7 +382,7 @@ pub fn darwinia_genesis_verbose( enable_println, // this should only be enabled on development chains ..Default::default() }, - gas_price: 1 * MILLICENTS, + gas_price: 1 * MICRO, }), sudo: Some(SudoConfig { key: root_key }), babe: Some(BabeConfig { authorities: vec![] }), diff --git a/node/runtime/src/constants.rs b/node/runtime/src/constants.rs index 489934045..c6271bc12 100644 --- a/node/runtime/src/constants.rs +++ b/node/runtime/src/constants.rs @@ -20,9 +20,10 @@ pub mod currency { use node_primitives::Balance; - pub const MILLICENTS: Balance = 1_000_000_000; - pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. - pub const DOLLARS: Balance = 100 * CENTS; + 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; } /// Time. diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 29eda15b1..9eaf3f9a7 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -19,60 +19,51 @@ #![cfg_attr(not(feature = "std"), no_std)] #![recursion_limit = "256"] -use authority_discovery_primitives::{AuthorityId as EncodedAuthorityId, Signature as EncodedSignature}; -use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature}; -pub use balances::Call as BalancesCall; -use codec::{Decode, Encode}; +/// Constant values used within the runtime. +pub mod constants; +/// Implementations of some helper traits passed into runtime modules as associated types. +pub mod impls; + pub use contracts::Gas; -use sr_api::impl_runtime_apis; +pub use timestamp::Call as TimestampCall; -//use grandpa::fg_primitives; -//use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; -//use im_online::sr25519::AuthorityId as ImOnlineId; +pub use balances::Call as BalancesCall; +pub use staking::StakerStatus; +use authority_discovery_primitives::{AuthorityId as EncodedAuthorityId, Signature as EncodedSignature}; +use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature}; +use codec::{Decode, Encode}; +use grandpa::{fg_primitives, AuthorityList as GrandpaAuthorityList}; +use im_online::sr25519::AuthorityId as ImOnlineId; use node_primitives::{AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature}; use rstd::prelude::*; -use sr_primitives::traits::{ - self, BlakeTwo256, Block as BlockT, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, +use sr_api::impl_runtime_apis; +use sr_primitives::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{self, BlakeTwo256, Block as BlockT, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup}, + transaction_validity::TransactionValidity, + weights::Weight, + ApplyResult, Perbill, }; -use sr_primitives::transaction_validity::TransactionValidity; -use sr_primitives::weights::Weight; -#[cfg(any(feature = "std", test))] -pub use sr_primitives::BuildStorage; - -use sr_primitives::{create_runtime_str, generic, impl_opaque_keys, ApplyResult, Perbill}; use substrate_primitives::u32_trait::{_1, _4}; - -use support::traits::OnUnbalanced; -pub use support::StorageValue; +use substrate_primitives::OpaqueMetadata; use support::{ construct_runtime, parameter_types, - traits::{Currency, Randomness, SplitTwoWays}, + traits::{Currency, OnUnbalanced, Randomness, SplitTwoWays}, }; - -pub use timestamp::Call as TimestampCall; +use system::offchain::TransactionSubmitter; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; #[cfg(any(feature = "std", test))] use version::NativeVersion; use version::RuntimeVersion; +//use grandpa::fg_primitives; +//use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +//use im_online::sr25519::AuthorityId as ImOnlineId; -use grandpa::fg_primitives; -use grandpa::AuthorityList as GrandpaAuthorityList; -use im_online::sr25519::AuthorityId as ImOnlineId; -use substrate_primitives::OpaqueMetadata; -use system::offchain::TransactionSubmitter; -use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; - +use constants::{currency::*, time::*}; use darwinia_support::TimeStamp; -use staking::EraIndex; -pub use staking::StakerStatus; - -/// Implementations of some helper traits passed into runtime modules as associated types. -pub mod impls; use impls::{Author, CurrencyToVoteHandler, LinearWeightToFee, TargetedFeeAdjustment}; - -/// Constant values used within the runtime. -pub mod constants; -use constants::time::*; +use staking::EraIndex; // Make the WASM binary available. #[cfg(feature = "std")] @@ -96,12 +87,15 @@ pub fn native_version() -> NativeVersion { } } -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; - type NegativeImbalance = >::NegativeImbalance; +type DealWithFees = SplitTwoWays< + Balance, + NegativeImbalance, + _4, + MockTreasury, // 4 parts (80%) goes to the treasury. + _1, + Author, // 1 part (20%) goes to the block author. +>; //pub struct Author; // @@ -118,20 +112,6 @@ impl OnUnbalanced for MockTreasury { } } -pub type DealWithFees = SplitTwoWays< - Balance, - NegativeImbalance, - _4, - MockTreasury, // 4 parts (80%) goes to the treasury. - _1, - Author, // 1 part (20%) goes to the block author. ->; - -pub const SECS_PER_BLOCK: BlockNumber = 6; -pub const MINUTES: BlockNumber = 60 / SECS_PER_BLOCK; -pub const HOURS: BlockNumber = MINUTES * 60; -pub const DAYS: BlockNumber = HOURS * 24; - parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const MaximumBlockWeight: Weight = 1_000_000_000; @@ -171,8 +151,8 @@ impl indices::Trait for Runtime { parameter_types! { pub const ExistentialDeposit: Balance = 1 * COIN; - pub const TransferFee: Balance = 1 * MILLI; - pub const CreationFee: Balance = 1 * MILLI; + pub const TransferFee: Balance = 1 * MICRO; + pub const CreationFee: Balance = 1 * MICRO; } impl balances::Trait for Runtime { type Balance = Balance; @@ -187,7 +167,7 @@ impl balances::Trait for Runtime { } parameter_types! { - pub const TransactionBaseFee: Balance = 1 * MILLI; + pub const TransactionBaseFee: Balance = 1 * MICRO; pub const TransactionByteFee: Balance = 10 * MICRO; // setting this to zero will disable the weight fee. pub const WeightFeeCoefficient: Balance = 1_000; @@ -309,11 +289,11 @@ impl finality_tracker::Trait for Runtime { } parameter_types! { - pub const ContractTransferFee: Balance = 1 * MILLI; - pub const ContractCreationFee: Balance = 1 * MILLI; - pub const ContractTransactionBaseFee: Balance = 1 * MILLI; + pub const ContractTransferFee: Balance = 1 * MICRO; + pub const ContractCreationFee: Balance = 1 * MICRO; + pub const ContractTransactionBaseFee: Balance = 1 * MICRO; pub const ContractTransactionByteFee: Balance = 10 * MICRO; - pub const ContractFee: Balance = 1 * MILLI; + pub const ContractFee: Balance = 1 * MICRO; pub const TombstoneDeposit: Balance = 1 * COIN; pub const RentByteFee: Balance = 1 * COIN; pub const RentDepositOffset: Balance = 1000 * COIN; diff --git a/srml/kton/Cargo.toml b/srml/kton/Cargo.toml index cd07c220d..12721233c 100644 --- a/srml/kton/Cargo.toml +++ b/srml/kton/Cargo.toml @@ -22,6 +22,9 @@ darwinia-support = { path = "../support", default-features = false } runtime_io = { package = "sr-io", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop" } substrate-primitives = { git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop" } +node-runtime = { path = "../../node/runtime" } +node-primitives = { path = "../../node/primitives" } + [features] default = ["std"] std = [ diff --git a/srml/kton/src/lib.rs b/srml/kton/src/lib.rs index 485e636f1..2e96f497a 100644 --- a/srml/kton/src/lib.rs +++ b/srml/kton/src/lib.rs @@ -1,8 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Codec, Decode, Encode}; -#[cfg(not(feature = "std"))] -use rstd::borrow::ToOwned; use rstd::{cmp, fmt::Debug, prelude::*, result}; #[cfg(feature = "std")] use sr_primitives::traits::One; diff --git a/srml/kton/src/mock.rs b/srml/kton/src/mock.rs index 60aed4901..b51141bef 100644 --- a/srml/kton/src/mock.rs +++ b/srml/kton/src/mock.rs @@ -1,8 +1,11 @@ +pub use node_runtime::constants::currency::COIN; + use std::{cell::RefCell, collections::HashSet}; use sr_primitives::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, + weights::Weight, Perbill, }; use srml_support::{impl_outer_origin, parameter_types}; @@ -10,18 +13,21 @@ use substrate_primitives::H256; use super::*; use crate::{GenesisConfig, Module}; - -pub const COIN: u64 = 1_000_000_000; +use node_primitives::Balance; 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); } /// The AccountId alias in this test module. pub type AccountId = u64; +// FIXME: +// replace +// testing::Header.number: u64 +// with +// node_primitives::BlockNumber pub type BlockNumber = u64; -pub type Balance = u64; impl_outer_origin! { pub enum Origin for Test {} @@ -31,8 +37,8 @@ impl_outer_origin! { #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: u32 = 1024; + pub const BlockHashCount: BlockNumber = 250; + pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } @@ -71,7 +77,7 @@ impl Trait for Test { } pub struct ExtBuilder { - existential_deposit: u64, + existential_deposit: Balance, } impl Default for ExtBuilder { @@ -81,7 +87,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 } diff --git a/srml/staking/Cargo.toml b/srml/staking/Cargo.toml index dc2abaf8e..b6976270a 100644 --- a/srml/staking/Cargo.toml +++ b/srml/staking/Cargo.toml @@ -29,9 +29,10 @@ substrate-primitives = { git = "https://github.com/darwinia-network/substrate.gi timestamp = { package = "srml-timestamp", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop" } rand = "0.7.2" -balances = { package = "darwinia-balances", path = '../balances', default-features = false } +balances = { package = "darwinia-balances", path = '../balances' } kton = { package = "darwinia-kton", path = "../kton" } node-runtime = { path = "../../node/runtime" } +node-primitives = { path = "../../node/primitives" } [features] equalize = [] diff --git a/srml/staking/src/inflation.rs b/srml/staking/src/inflation.rs index 92e0be19b..ef378aae6 100644 --- a/srml/staking/src/inflation.rs +++ b/srml/staking/src/inflation.rs @@ -9,7 +9,7 @@ use substrate_primitives::U256; // 1 - (99 /100)^sqrt(year) // () -> RingBalanceOf -pub fn compute_total_payout( +pub fn compute_total_payout( era_duration: u64, living_time: u64, total_left: u128, @@ -48,7 +48,7 @@ pub fn compute_total_payout( // consistent with the formula in smart contract in evolution land which can be found in // https://github.com/evolutionlandorg/bank/blob/master/contracts/GringottsBank.sol#L280 -pub fn compute_kton_return(value: RingBalanceOf, months: u32) -> KtonBalanceOf { +pub fn compute_kton_return(value: RingBalanceOf, months: u32) -> KtonBalanceOf { let value = value.saturated_into::(); let no = U256::from(67).pow(U256::from(months)); let de = U256::from(66).pow(U256::from(months)); diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 6a78bc79a..661a04600 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -24,7 +24,7 @@ extern crate test; pub mod inflation; use codec::{Decode, Encode, HasCompact}; -use rstd::{prelude::*, result}; +use rstd::{borrow::ToOwned, prelude::*, result}; use session::{historical::OnSessionEnding, SelectInitialValidators}; use sr_primitives::{ traits::{CheckedSub, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, @@ -47,8 +47,6 @@ use darwinia_support::{ }; use phragmen::{build_support_map, elect, equalize, ExtendedBalance, PhragmenStakedAssignment}; -use core::convert::TryInto; - #[allow(unused)] #[cfg(any(feature = "bench", test))] mod mock; @@ -109,19 +107,22 @@ pub enum StakerStatus { #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct ValidatorPrefs { + pub node_name: Vec, /// Validator should ensure this many more slashes than is necessary before being unstaked. #[codec(compact)] pub unstake_threshold: u32, /// percent of Reward that validator takes up-front; only the rest is split between themselves and /// nominators. - pub validator_payment_ratio: Perbill, + #[codec(compact)] + pub validator_payment_ratio: u32, } impl Default for ValidatorPrefs { fn default() -> Self { ValidatorPrefs { + node_name: vec![], unstake_threshold: 3, - validator_payment_ratio: Default::default(), + validator_payment_ratio: 0, } } } @@ -382,19 +383,15 @@ decl_storage! { /// The rest of the slashed value is handled by the `Slash`. pub SlashRewardFraction get(fn slash_reward_fraction) config(): Perbill; - /// A mapping from still-bonded eras to the first session index of that era. - BondedEras: Vec<(EraIndex, SessionIndex)>; - - /// All slashes that have occurred in a given era. - EraSlashJournal get(fn era_slash_journal): - map EraIndex => Vec>; - - pub NodeName get(node_name): map T::AccountId => Vec; - pub RingPool get(ring_pool): RingBalanceOf; pub KtonPool get(kton_pool): KtonBalanceOf; + /// A mapping from still-bonded eras to the first session index of that era. + BondedEras: Vec<(EraIndex, SessionIndex)>; + + /// All slashes that have occurred in a given era. + EraSlashJournal get(fn era_slash_journal): map EraIndex => Vec>; } add_extra_genesis { config(stakers): @@ -407,21 +404,22 @@ decl_storage! { T::Lookup::unlookup(controller.clone()), StakingBalance::Ring(balance), RewardDestination::Stash, - 12 + 12, ); let _ = match status { StakerStatus::Validator => { >::validate( T::Origin::from(Some(controller.clone()).into()), - [0;8].to_vec(), - 0, - 3 + ValidatorPrefs { + node_name: vec![0; 8], + ..Default::default() + }, ) }, StakerStatus::Nominator(votes) => { >::nominate( T::Origin::from(Some(controller.clone()).into()), - votes.iter().map(|l| {T::Lookup::unlookup(l.clone())}).collect() + votes.iter().map(|l| {T::Lookup::unlookup(l.clone())}).collect(), ) }, _ => Ok(()) }; @@ -454,25 +452,25 @@ decl_module! { fn deposit_event() = default; - fn bond(origin, + fn bond( + origin, controller: ::Source, value: StakingBalance, KtonBalanceOf>, payee: RewardDestination, promise_month: u32 ) { let stash = ensure_signed(origin)?; - ensure!(promise_month <= 36, "months at most is 36."); - if >::exists(&stash) { return Err("stash already bonded") } let controller = T::Lookup::lookup(controller)?; - if >::exists(&controller) { return Err("controller already paired") } + ensure!(promise_month <= 36, "months at most is 36."); + >::insert(&stash, &controller); >::insert(&stash, payee); @@ -495,14 +493,17 @@ decl_module! { } } - fn bond_extra(origin, + fn bond_extra( + origin, value: StakingBalance, KtonBalanceOf>, promise_month: u32 ) { let stash = ensure_signed(origin)?; - ensure!(promise_month <= 36, "months at most is 36."); let controller = Self::bonded(&stash).ok_or("not a stash")?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; + + ensure!(promise_month <= 36, "months at most is 36."); + match value { StakingBalance::Ring(r) => { let stash_balance = T::Ring::free_balance(&stash); @@ -528,12 +529,8 @@ decl_module! { /// modify time_deposit_items and time_deposit_ring amount fn unbond(origin, value: StakingBalance, KtonBalanceOf>) { let controller = ensure_signed(origin)?; - - Self::clear_mature_deposits(&controller); - - let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; + let mut ledger = Self::clear_mature_deposits(Self::ledger(&controller).ok_or("not a controller")?); let StakingLedger { - stash: _, active_ring, active_deposit_ring, active_kton, @@ -542,9 +539,17 @@ decl_module! { .. } = &mut ledger; + // due to the macro parser, we've to add a bracket + // actually, this's totally wrong: + // `a as u32 + b as u32 < c` + // workaround: + // 1. `(a as u32 + b as u32) < c` + // 2. `let c_ = a as u32 + b as u32; c_ < c` ensure!( - ring_staking_lock.unbondings.len() + kton_staking_lock.unbondings.len() < MAX_UNLOCKING_CHUNKS.try_into().unwrap(), - "can not schedule more unlock chunks" + (ring_staking_lock.unbondings.len() as u32 + kton_staking_lock.unbondings.len() as u32) + < + MAX_UNLOCKING_CHUNKS, + "can not schedule more unlock chunks", ); let at = >::now().saturated_into::() + T::BondingDuration::get(); @@ -585,14 +590,12 @@ decl_module! { /// called by controller fn deposit_extra(origin, value: RingBalanceOf, promise_month: u32) { let controller = ensure_signed(origin)?; - if Self::ledger(&controller).is_none() { return Err("not a controller"); } + let ledger = Self::ledger(&controller).ok_or("not a controller")?; ensure!(promise_month >= 3 && promise_month <= 36, "months at least is 3 and at most is 36."); - Self::clear_mature_deposits(&controller); - let now = >::now(); - let mut ledger = Self::ledger(&controller).unwrap(); + let mut ledger = Self::clear_mature_deposits(ledger); let StakingLedger { stash, active_ring, @@ -619,7 +622,8 @@ decl_module! { fn claim_mature_deposits(origin) { let controller = ensure_signed(origin)?; - Self::clear_mature_deposits(&controller); + let ledger = Self::clear_mature_deposits(Self::ledger(&controller).ok_or("not a controller")?); + >::insert(controller, ledger); } fn claim_deposits_with_punish(origin, expire_time: T::Moment) { @@ -679,24 +683,32 @@ decl_module! { >::insert(&controller, ledger); } - fn validate(origin, name: Vec, ratio: u32, unstake_threshold: u32) { + fn validate(origin, prefs: ValidatorPrefs) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; - let stash = &ledger.stash; + ensure!( - unstake_threshold <= MAX_UNSTAKE_THRESHOLD, - "unstake threshold too large" + !prefs.node_name.is_empty(), + "node name can not be empty", ); + ensure!( + prefs.unstake_threshold <= MAX_UNSTAKE_THRESHOLD, + "unstake threshold too large", + ); + + let stash = &ledger.stash; + let mut prefs = prefs; // at most 100% - let ratio = Perbill::from_percent(ratio.min(100)); - let prefs = ValidatorPrefs {unstake_threshold: unstake_threshold, validator_payment_ratio: ratio }; + prefs.validator_payment_ratio = prefs.validator_payment_ratio.min(100); >::remove(stash); - >::insert(stash, prefs); - if !>::exists(&controller) { - >::insert(controller, name); - Self::deposit_event(RawEvent::NodeNameUpdated); - } + >::mutate(stash, |prefs_| { + let exists = !prefs_.node_name.is_empty(); + *prefs_ = prefs; + if exists { + Self::deposit_event(RawEvent::NodeNameUpdated); + } + }); } fn nominate(origin, targets: Vec<::Source>) { @@ -765,26 +777,26 @@ decl_module! { } impl Module { - pub fn clear_mature_deposits(controller: &T::AccountId) { - if let Some(mut ledger) = Self::ledger(&controller) { - let now = >::now(); - let StakingLedger { - active_deposit_ring, - deposit_items, - .. - } = &mut ledger; - - deposit_items.retain(|item| { - if item.expire_time > now { - true - } else { - *active_deposit_ring = active_deposit_ring.saturating_sub(item.value); - false - } - }); + pub fn clear_mature_deposits( + mut ledger: StakingLedger, KtonBalanceOf, T::Moment>, + ) -> StakingLedger, KtonBalanceOf, T::Moment> { + let now = >::now(); + let StakingLedger { + active_deposit_ring, + deposit_items, + .. + } = &mut ledger; + + deposit_items.retain(|item| { + if item.expire_time > now { + true + } else { + *active_deposit_ring = active_deposit_ring.saturating_sub(item.value); + false + } + }); - >::insert(controller, ledger); - }; + ledger } fn bond_helper_in_ring( @@ -858,6 +870,13 @@ impl Module { >::insert(controller, ledger); } + /// Slash a given validator by a specific amount with given (historical) exposure. + /// + /// Removes the slash from the validator's balance by preference, + /// and reduces the nominators' balance if needed. + /// + /// Returns the resulting `NegativeImbalance` to allow distributing the slashed amount and + /// pushes an entry onto the slash journal. fn slash_validator( stash: &T::AccountId, slash: ExtendedBalance, @@ -884,7 +903,7 @@ impl Module { // The amount we'll slash from the validator's stash directly. let own_slash = own_remaining.min(slash); - let (mut ring_imbalance, mut kton_imblance, missing) = + let (mut ring_imbalance, mut kton_imbalance, missing) = Self::slash_individual(stash, Perbill::from_rational_approximation(own_slash, exposure.own)); // T::Currency::slash(stash, own_slash); let own_slash = own_slash - missing; // The amount remaining that we can't slash from the validator, @@ -904,21 +923,21 @@ impl Module { ); ring_imbalance.subsume(r); - kton_imblance.subsume(k); + kton_imbalance.subsume(k); } } } journal.push(SlashJournalEntry { - who: stash.clone(), - own_slash: own_slash.clone(), + who: stash.to_owned(), + own_slash, amount: slash, }); // trigger the event - Self::deposit_event(RawEvent::Slash(stash.clone(), slash)); + Self::deposit_event(RawEvent::Slash(stash.to_owned(), slash)); - (ring_imbalance, kton_imblance) + (ring_imbalance, kton_imbalance) } // TODO: there is reserve balance in Balance.Slash, we assuming it is zero for now. @@ -937,7 +956,6 @@ impl Module { } else { (>::zero(), Zero::zero()) }; - let (kton_imbalance, _) = if !ledger.active_kton.is_zero() { let slashable_kton = slash_ratio * ledger.active_kton; let value_slashed = Self::slash_helper(&controller, &mut ledger, StakingBalance::Kton(slashable_kton)); @@ -1129,8 +1147,11 @@ impl Module { maybe_new_validators } + /// Reward a given validator by a specific amount. Add the reward to the validator's, and its + /// nominators' balance, pro-rata based on their exposure, after having removed the validator's + /// pre-payout cut. fn reward_validator(stash: &T::AccountId, reward: RingBalanceOf) -> RingPositiveImbalanceOf { - let off_the_table = Self::validators(stash).validator_payment_ratio * reward; + let off_the_table = Perbill::from_percent(Self::validators(stash).validator_payment_ratio) * reward; let reward = reward - off_the_table; let mut imbalance = >::zero(); let validator_cut = if reward.is_zero() { diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 019e4f16f..730c13b4c 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -1,8 +1,12 @@ +pub use node_primitives::Balance; +pub use node_runtime::constants::currency::COIN; + use std::{cell::RefCell, collections::HashSet}; use sr_primitives::{ testing::{Header, UintAuthorityId}, traits::{BlakeTwo256, Convert, IdentityLookup, OnInitialize, OpaqueKeys}, + weights::Weight, KeyTypeId, Perbill, }; use sr_staking_primitives::SessionIndex; @@ -13,14 +17,18 @@ use srml_support::{ }; use substrate_primitives::{crypto::key_types, H256}; -use crate::{EraIndex, GenesisConfig, Module, Nominators, RewardDestination, StakerStatus, StakingBalance, Trait}; +use crate::*; use darwinia_support::TimeStamp; use phragmen::ExtendedBalance; /// The AccountId alias in this test module. pub type AccountId = u64; +// FIXME: +// replace +// testing::Header.number: u64 +// with +// node_primitives::BlockNumber pub type BlockNumber = u64; -pub type Balance = u64; /// Module alias pub type System = system::Module; @@ -50,7 +58,7 @@ impl Convert for CurrencyToVoteHandler { 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); } pub struct TestSessionHandler; @@ -81,8 +89,8 @@ pub fn is_disabled(validator: 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()) } } @@ -95,8 +103,8 @@ impl_outer_origin! { #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: u32 = 1024; + pub const BlockHashCount: BlockNumber = 250; + pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } @@ -177,7 +185,6 @@ parameter_types! { pub const BondingDuration: TimeStamp = 60; pub const ErasPerEpoch: EraIndex = 10; } -pub const COIN: u64 = 1_000_000_000; parameter_types! { // decimal 9 pub const CAP: Balance = 10_000_000_000 * COIN; @@ -202,9 +209,9 @@ impl Trait for Test { } pub struct ExtBuilder { - existential_deposit: u64, + existential_deposit: Balance, current_era: EraIndex, - reward: u64, + reward: Balance, validator_pool: bool, nominate: bool, validator_count: u32, @@ -228,7 +235,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 } @@ -393,7 +400,7 @@ pub fn check_nominator_exposure(stash: u64) { ); } -pub fn assert_total_expo(stash: u64, val: u128) { +pub fn assert_total_expo(stash: u64, val: Balance) { let expo = Staking::stakers(&stash); assert_eq!(expo.total, val); } @@ -402,7 +409,7 @@ pub fn assert_is_stash(acc: u64) { assert!(Staking::bonded(&acc).is_some(), "Not a stash."); } -pub fn bond_validator(acc: u64, val: u64) { +pub fn bond_validator(acc: u64, val: Balance) { // a = controller // a + 1 = stash let _ = Ring::make_free_balance_be(&(acc + 1), val); @@ -411,17 +418,19 @@ pub fn bond_validator(acc: u64, val: u64) { acc, StakingBalance::Ring(val), RewardDestination::Controller, - 0 + 0, )); assert_ok!(Staking::validate( Origin::signed(acc), - "test".as_bytes().to_owned(), - 0, - 0 + ValidatorPrefs { + node_name: "test".as_bytes().to_vec(), + unstake_threshold: 0, + validator_payment_ratio: 0, + } )); } -pub fn bond_nominator(acc: u64, val: u64, target: Vec) { +pub fn bond_nominator(acc: u64, val: Balance, target: Vec) { // a = controller // a + 1 = stash let _ = Ring::make_free_balance_be(&(acc + 1), val); @@ -430,7 +439,7 @@ pub fn bond_nominator(acc: u64, val: u64, target: Vec) { acc, StakingBalance::Ring(val), RewardDestination::Controller, - 0 + 0, )); assert_ok!(Staking::nominate(Origin::signed(acc), target)); } diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 3c93a2b09..1361b9a8a 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -8,107 +8,106 @@ use darwinia_support::{BalanceLock, NormalLock, StakingLock, WithdrawLock, Withd // will create stash `a` and controller `b` // `a` has 100 Ring and 100 Kton // promise for `m` month with 50 Ring and 50 Kton -// `m` can be ignore, and it wont perfrom `bond` action +// `m` can be ignore, and it wont perform `bond` action // gen_paired_account!(a(1), b(2)); -//macro_rules! gen_paired_account { -// ($stash:ident($stash_id:expr), $controller:ident($controller_id:expr), $promise_month:ident($how_long:expr)) => { -// #[allow(non_snake_case, unused)] -// let $stash = $stash_id; -// let _ = Ring::deposit_creating(&$stash, 100 * COIN); -// Kton::deposit_creating(&$stash, 100 * COIN); -// #[allow(non_snake_case, unused)] -// let $controller = $controller_id; -// let _ = Ring::deposit_creating(&$controller, COIN); -// #[allow(non_snake_case, unused)] -// let $promise_month = $how_long; -// assert_ok!(Staking::bond( -// Origin::signed($stash), -// $controller, -// StakingBalance::Ring(50 * COIN), -// RewardDestination::Stash, -// $how_long -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed($stash), -// StakingBalance::Kton(50 * COIN), -// $how_long -// )); -// }; -// ($stash:ident($stash_id:expr), $controller:ident($controller_id:expr), $how_long:expr) => { -// #[allow(non_snake_case, unused)] -// let $stash = $stash_id; -// let _ = Ring::deposit_creating(&$stash, 100 * COIN); -// Kton::deposit_creating(&$stash, 100 * COIN); -// #[allow(non_snake_case, unused)] -// let $controller = $controller_id; -// let _ = Ring::deposit_creating(&$controller, COIN); -// assert_ok!(Staking::bond( -// Origin::signed($stash), -// $controller, -// StakingBalance::Ring(50 * COIN), -// RewardDestination::Stash, -// $how_long -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed($stash), -// StakingBalance::Kton(50 * COIN), -// $how_long -// )); -// }; -// ($stash:ident($stash_id:expr), $controller:ident($controller_id:expr)) => { -// #[allow(non_snake_case, unused)] -// let $stash = $stash_id; -// let _ = Ring::deposit_creating(&$stash, 100 * COIN); -// Kton::deposit_creating(&$stash, 100 * COIN); -// #[allow(non_snake_case, unused)] -// let $controller = $controller_id; -// let _ = Ring::deposit_creating(&$controller, COIN); -// }; -//} +macro_rules! gen_paired_account { + ($stash:ident($stash_id:expr), $controller:ident($controller_id:expr), $promise_month:ident($how_long:expr)) => { + #[allow(non_snake_case, unused)] + let $stash = $stash_id; + let _ = Ring::deposit_creating(&$stash, 100 * COIN); + Kton::deposit_creating(&$stash, 100 * COIN); + #[allow(non_snake_case, unused)] + let $controller = $controller_id; + let _ = Ring::deposit_creating(&$controller, COIN); + #[allow(non_snake_case, unused)] + let $promise_month = $how_long; + assert_ok!(Staking::bond( + Origin::signed($stash), + $controller, + StakingBalance::Ring(50 * COIN), + RewardDestination::Stash, + $how_long, + )); + assert_ok!(Staking::bond_extra( + Origin::signed($stash), + StakingBalance::Kton(50 * COIN), + $how_long + )); + }; + ($stash:ident($stash_id:expr), $controller:ident($controller_id:expr), $how_long:expr) => { + #[allow(non_snake_case, unused)] + let $stash = $stash_id; + let _ = Ring::deposit_creating(&$stash, 100 * COIN); + Kton::deposit_creating(&$stash, 100 * COIN); + #[allow(non_snake_case, unused)] + let $controller = $controller_id; + let _ = Ring::deposit_creating(&$controller, COIN); + assert_ok!(Staking::bond( + Origin::signed($stash), + $controller, + StakingBalance::Ring(50 * COIN), + RewardDestination::Stash, + $how_long, + )); + assert_ok!(Staking::bond_extra( + Origin::signed($stash), + StakingBalance::Kton(50 * COIN), + $how_long, + )); + }; + ($stash:ident($stash_id:expr), $controller:ident($controller_id:expr)) => { + #[allow(non_snake_case, unused)] + let $stash = $stash_id; + let _ = Ring::deposit_creating(&$stash, 100 * COIN); + Kton::deposit_creating(&$stash, 100 * COIN); + #[allow(non_snake_case, unused)] + let $controller = $controller_id; + let _ = Ring::deposit_creating(&$controller, COIN); + }; +} #[test] fn test_env_build() { ExtBuilder::default().existential_deposit(0).build().execute_with(|| { check_exposure_all(); - assert_eq!(Staking::bonded(&11), Some(10)); + let (stash, controller) = (11, 10); + + assert_eq!(Staking::bonded(&stash), Some(controller)); assert_eq!( - Staking::ledger(&10).unwrap(), + Staking::ledger(&controller).unwrap(), StakingLedger { - stash: 11, + stash, active_ring: 100 * COIN, active_deposit_ring: 100 * COIN, active_kton: 0, deposit_items: vec![TimeDepositItem { value: 100 * COIN, start_time: 0, - expire_time: 12 * MONTH_IN_SECONDS as u64 + expire_time: (12 * MONTH_IN_SECONDS) as _, }], ring_staking_lock: StakingLock { staking_amount: 100 * COIN, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] + unbondings: vec![], }, + kton_staking_lock: Default::default(), } ); assert_eq!(Kton::free_balance(&11), COIN / 100); assert_eq!(Kton::total_issuance(), 16 * COIN / 100); - let origin_ledger = Staking::ledger(&10).unwrap(); - let _ = Ring::deposit_creating(&11, 100 * COIN); + let origin_ledger = Staking::ledger(&controller).unwrap(); + let _ = Ring::deposit_creating(&stash, 100 * COIN); assert_ok!(Staking::bond_extra( - Origin::signed(11), + Origin::signed(stash), StakingBalance::Ring(20 * COIN), - 13 + 13, )); assert_eq!( - Staking::ledger(&10).unwrap(), + Staking::ledger(&controller).unwrap(), StakingLedger { - stash: 11, + stash, active_ring: origin_ledger.active_ring + 20 * COIN, active_deposit_ring: origin_ledger.active_deposit_ring + 20 * COIN, active_kton: 0, @@ -116,22 +115,19 @@ fn test_env_build() { TimeDepositItem { value: 100 * COIN, start_time: 0, - expire_time: 12 * MONTH_IN_SECONDS as u64 + expire_time: (12 * MONTH_IN_SECONDS) as _, }, TimeDepositItem { value: 20 * COIN, start_time: 0, - expire_time: 13 * MONTH_IN_SECONDS as u64 - } + expire_time: (13 * MONTH_IN_SECONDS) as _, + }, ], ring_staking_lock: StakingLock { staking_amount: origin_ledger.active_ring + 20 * COIN, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] + unbondings: vec![], }, + kton_staking_lock: Default::default(), } ); }); @@ -140,1086 +136,800 @@ fn test_env_build() { #[test] fn normal_kton_should_work() { ExtBuilder::default().existential_deposit(0).build().execute_with(|| { - Kton::deposit_creating(&1001, 10 * COIN); - assert_ok!(Staking::bond( - Origin::signed(1001), - 1000, - StakingBalance::Kton(10 * COIN), - RewardDestination::Stash, - 0 - )); - assert_eq!( - Staking::ledger(&1000).unwrap(), - StakingLedger { - stash: 1001, - active_ring: 0, - active_deposit_ring: 0, - active_kton: 10 * COIN, - deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 10 * COIN, - unbondings: vec![] - }, - } - ); - assert_eq!( - Kton::locks(&1001), - vec![BalanceLock { - id: STAKING_ID, - withdraw_lock: WithdrawLock::WithStaking(StakingLock { - staking_amount: 10 * COIN, - unbondings: vec![], - }), - reasons: WithdrawReasons::all() - }] - ); + { + let (stash, controller) = (1001, 1000); - // promise_month should not work for kton - Kton::deposit_creating(&2001, 10 * COIN); - assert_ok!(Staking::bond( - Origin::signed(2001), - 2000, - StakingBalance::Kton(10 * COIN), - RewardDestination::Stash, - 12 - )); - assert_eq!( - Staking::ledger(&2000).unwrap(), - StakingLedger { - stash: 2001, - active_ring: 0, - active_deposit_ring: 0, - active_kton: 10 * COIN, - deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 10 * COIN, - unbondings: vec![] - }, - } - ); + Kton::deposit_creating(&stash, 10 * COIN); + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Kton(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 + Kton::deposit_creating(&stash, 10 * COIN); + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Kton(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_should_work() { +fn time_deposit_ring_unbond_and_withdraw_automatically_should_work() { ExtBuilder::default().existential_deposit(0).build().execute_with(|| { - Timestamp::set_timestamp(13 * MONTH_IN_SECONDS as u64); + let (stash, controller) = (11, 10); - let ledger = Staking::ledger(&10).unwrap(); - assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Ring(10 * COIN))); - // Only active normal ring can be unbond - assert_eq!(&Staking::ledger(&10).unwrap(), &ledger,); - assert_eq!( - Ring::locks(11), - vec![BalanceLock { + { + let locks = vec![BalanceLock { id: STAKING_ID, withdraw_lock: WithdrawLock::WithStaking(StakingLock { staking_amount: 100 * COIN, unbondings: vec![], }), - reasons: WithdrawReasons::all() - }] - ); - - assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Ring(20 * COIN))); - assert_eq!( - Staking::ledger(&10).unwrap(), - StakingLedger { - stash: 11, + reasons: WithdrawReasons::all(), + }]; + let ledger = StakingLedger { + stash, active_ring: 100 * COIN, - active_deposit_ring: 70 * COIN, + active_deposit_ring: 100 * COIN, active_kton: 0, deposit_items: vec![TimeDepositItem { - value: 70 * COIN, + value: 100 * COIN, start_time: 0, - expire_time: 12 * MONTH_IN_SECONDS as u64 + expire_time: (12 * MONTH_IN_SECONDS) as _, }], ring_staking_lock: StakingLock { staking_amount: 100 * COIN, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] + unbondings: vec![], }, - } + kton_staking_lock: Default::default(), + }; + + assert_ok!(Staking::unbond( + Origin::signed(controller), + StakingBalance::Ring(10 * COIN) + )); + assert_eq!(Ring::locks(stash), locks); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger,); + + assert_ok!(Staking::unbond( + Origin::signed(controller), + StakingBalance::Ring(120 * COIN) + )); + assert_eq!(Ring::locks(stash), locks); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger); + } + + { + let (unbond_start, unbond_value) = ((13 * MONTH_IN_SECONDS) as _, 10 * COIN); + Timestamp::set_timestamp(unbond_start); + + assert_ok!(Staking::unbond( + Origin::signed(controller), + StakingBalance::Ring(unbond_value) + )); + assert_eq!( + Ring::locks(stash), + vec![BalanceLock { + id: STAKING_ID, + withdraw_lock: WithdrawLock::WithStaking(StakingLock { + staking_amount: 100 * COIN - unbond_value, + unbondings: vec![NormalLock { + amount: unbond_value, + until: unbond_start + BondingDuration::get(), + }], + }), + reasons: WithdrawReasons::all(), + }] + ); + assert_eq!( + Staking::ledger(&controller).unwrap(), + StakingLedger { + stash, + active_ring: 100 * COIN - unbond_value, + active_deposit_ring: 0, + active_kton: 0, + deposit_items: vec![], + ring_staking_lock: StakingLock { + staking_amount: 100 * COIN - unbond_value, + unbondings: vec![NormalLock { + amount: unbond_value, + until: unbond_start + BondingDuration::get(), + }], + }, + kton_staking_lock: Default::default(), + } + ); + + Timestamp::set_timestamp(unbond_start + BondingDuration::get()); + assert_err!( + Ring::ensure_can_withdraw( + &stash, + unbond_value, + WithdrawReason::Transfer.into(), + 100 * COIN - unbond_value - 1, + ), + "account liquidity restrictions prevent withdrawal" + ); + assert_ok!(Ring::ensure_can_withdraw( + &stash, + unbond_value, + WithdrawReason::Transfer.into(), + 100 * COIN - unbond_value, + )); + } + }); +} + +#[test] +fn normal_unbond_should_work() { + ExtBuilder::default().existential_deposit(0).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), + StakingBalance::Ring(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_SECONDS) as _, + }); + 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.03 Kton + // extra = 1.min(0.03) + // bond += 0.03 + assert_ok!(Staking::bond_extra( + Origin::signed(stash), + StakingBalance::Kton(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), + StakingBalance::Kton(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().existential_deposit(0).build().execute_with(|| { + let (stash, controller) = (1001, 1000); + let promise_month = 36; + let _ = Ring::deposit_creating(&stash, 100 * COIN); + Kton::deposit_creating(&stash, COIN / 100000); + let mut ledger = StakingLedger { + stash, + active_ring: 10 * COIN, + active_deposit_ring: 10 * COIN, + active_kton: 0, + deposit_items: vec![TimeDepositItem { + value: 10 * COIN, + start_time: 0, + expire_time: (promise_month * MONTH_IN_SECONDS) as _, + }], + ring_staking_lock: StakingLock { + staking_amount: 10 * COIN, + unbondings: vec![], + }, + kton_staking_lock: Default::default(), + }; + + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Ring(10 * COIN), + RewardDestination::Stash, + promise_month, + )); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger); + // kton is 0, skip unbond_with_punish + assert_ok!(Staking::claim_deposits_with_punish( + Origin::signed(controller), + (promise_month * MONTH_IN_SECONDS) as _, + )); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger); + + // set more kton balance to make it work + Kton::deposit_creating(&stash, 10 * COIN); + let kton_free_balance = Kton::free_balance(&stash); + let kton_punishment = inflation::compute_kton_return::(10 * COIN, promise_month); + assert_ok!(Staking::claim_deposits_with_punish( + Origin::signed(controller), + (promise_month * MONTH_IN_SECONDS) as _, + )); + ledger.active_deposit_ring -= 10 * COIN; + ledger.deposit_items.clear(); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger); + assert_eq!(Kton::free_balance(&stash), kton_free_balance - 3 * kton_punishment); + }); +} + +#[test] +fn transform_to_deposited_ring_should_work() { + ExtBuilder::default().existential_deposit(0).build().execute_with(|| { + let (stash, controller) = (1001, 1000); + let _ = Ring::deposit_creating(&stash, 100 * COIN); + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Ring(10 * 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), 5 * COIN, 12)); + ledger.active_deposit_ring += 5 * COIN; + ledger.deposit_items.push(TimeDepositItem { + value: 5 * COIN, + start_time: 0, + expire_time: (12 * MONTH_IN_SECONDS) as u64, + }); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger); + assert_eq!(Kton::free_balance(&stash), kton_free_balance + (5 * COIN / 10000)); + }); +} + +#[test] +fn expired_ring_should_capable_to_promise_again() { + ExtBuilder::default().existential_deposit(0).build().execute_with(|| { + let (stash, controller) = (1001, 1000); + let _ = Ring::deposit_creating(&stash, 100 * COIN); + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Ring(10 * COIN), + RewardDestination::Stash, + 12, + )); + let mut ledger = Staking::ledger(&controller).unwrap(); + let ts = (13 * MONTH_IN_SECONDS) as u64; + let promise_extra_value = 5 * COIN; + + 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().existential_deposit(0).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); + // TODO + // assert_eq!(Staking::current_era_total_reward(), 80000000 * COIN / 10); + // start_era(11); + // // ErasPerEpoch = 10 + // assert_eq!(Staking::current_era_total_reward(), 88000000 * COIN / 10); + }); +} + +#[test] +fn reward_and_slash_should_work() { + ExtBuilder::default().build().execute_with(|| { + gen_paired_account!(stash_1(123), _c(456), 12); + gen_paired_account!(stash_2(234), _c(567), 12); + + >::insert( + &stash_1, + Exposure { + total: 1, + own: 1, + others: vec![], + }, ); - // unbondings: vec![ - // NormalLock { - // value: StakingBalance::Ring(10 * COIN), - // era: 3, - // is_time_deposit: true + assert_eq!(Ring::free_balance(&stash_1), 100 * COIN); + let _ = Staking::reward_validator(&stash_1, 20 * COIN); + assert_eq!(Ring::free_balance(&stash_1), 120 * COIN); + + // FIXME: slash strategy + // >::insert( + // &stash_1, + // Exposure { + // total: 100 * COIN, + // own: 1, + // others: vec![IndividualExposure { + // who: stash_2, + // value: 100 * COIN - 1, + // }], // }, - // NormalLock { - // value: StakingBalance::Ring(20 * COIN), - // era: 3, - // is_time_deposit: true - // } - // ] - - // more than active ring - assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Ring(120 * COIN))); + // ); + // let _ = Staking::slash_validator(&stash_1, 1, &Staking::stakers(&stash_1), &mut Vec::new()); + // assert_eq!(Ring::free_balance(&stash_1), 120 * COIN - 1); + // assert_eq!(Ring::free_balance(&stash_2), 1); + }); +} + +#[test] +fn set_controller_should_work() { + ExtBuilder::default().existential_deposit(0).build().execute_with(|| { + let (stash, old_controller, new_controller) = (11, 10, 12); + let ledger = Staking::ledger(&old_controller).unwrap(); + + assert_ok!(Staking::set_controller(Origin::signed(stash), new_controller)); + assert_eq!(Staking::ledger(&old_controller), None); + assert_eq!(Staking::ledger(&new_controller).unwrap(), ledger); + }); +} + +#[test] +fn slash_should_not_touch_unbondings() { + ExtBuilder::default().existential_deposit(0).build().execute_with(|| { + let (stash, controller) = (11, 10); + let ledger = Staking::ledger(&controller).unwrap(); + + // only deposit_ring, no normal_ring assert_eq!( - Staking::ledger(&10).unwrap(), - StakingLedger { - stash: 11, - active_ring: 100 * COIN, - active_deposit_ring: 0, - active_kton: 0, - deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, - } + (ledger.active_ring, ledger.active_deposit_ring), + (100 * COIN, 100 * COIN), ); - // unbondings: vec![ - // NormalLock { - // value: StakingBalance::Ring(10 * COIN), - // era: 3, - // is_time_deposit: true - // }, - // NormalLock { - // value: StakingBalance::Ring(20 * COIN), - // era: 3, - // is_time_deposit: true - // }, - // NormalLock { - // value: StakingBalance::Ring(70 * COIN), - // era: 3, - // is_time_deposit: true - // }, - // ] - Timestamp::set_timestamp(BondingDuration::get()); + assert_ok!(Staking::bond_extra( + Origin::signed(stash), + StakingBalance::Ring(100 * COIN), + 0, + )); + Kton::deposit_creating(&stash, 10 * COIN); + assert_ok!(Staking::bond_extra( + Origin::signed(stash), + StakingBalance::Kton(10 * COIN), + 0, + )); + + assert_ok!(Staking::unbond( + Origin::signed(controller), + StakingBalance::Ring(10 * COIN), + )); + 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), + (190 * COIN, 100 * COIN), + ); + >::insert( + &stash, + Exposure { + total: 1, + own: 1, + others: vec![], + }, + ); + // FIXME: slash strategy + let _ = Staking::slash_validator( + &stash, + ExtendedBalance::max_value(), + &Staking::stakers(&stash), + &mut vec![], + ); + let ledger = Staking::ledger(&controller).unwrap(); assert_eq!( - Staking::ledger(&10).unwrap(), - StakingLedger { - stash: 11, - active_ring: 0, - active_deposit_ring: 0, - active_kton: 0, - deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, - } + ( + 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 bond_over_max_promise_month_should_fail() { + ExtBuilder::default().existential_deposit(0).build().execute_with(|| { + gen_paired_account!(stash(123), controller(456)); + assert_err!( + Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Ring(COIN), + RewardDestination::Stash, + 37, + ), + "months at most is 36.", ); - // unbondings: vec![] - let free_balance = Ring::free_balance(&11); + gen_paired_account!(stash(123), controller(456), promise_month(12)); + assert_err!( + Staking::bond_extra(Origin::signed(stash), StakingBalance::Ring(COIN), 37), + "months at most is 36.", + ); + }); +} + +#[test] +fn check_stash_already_bonded_and_controller_already_paired() { + ExtBuilder::default().existential_deposit(0).build().execute_with(|| { + gen_paired_account!(unpaired_stash(123), unpaired_controller(456)); + assert_err!( + Staking::bond( + Origin::signed(11), + unpaired_controller, + StakingBalance::Ring(COIN), + RewardDestination::Stash, + 0, + ), + "stash already bonded", + ); + assert_err!( + Staking::bond( + Origin::signed(unpaired_stash), + 10, + StakingBalance::Ring(COIN), + RewardDestination::Stash, + 0, + ), + "controller already paired", + ); + }); +} + +#[test] +fn pool_should_be_increased_and_decreased_correctly() { + ExtBuilder::default().existential_deposit(0).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), + StakingBalance::Ring(50 * COIN) + )); + assert_ok!(Staking::unbond( + Origin::signed(controller_1), + StakingBalance::Kton(25 * COIN) + )); + // not yet expired: promise for 12 months + assert_ok!(Staking::unbond( + Origin::signed(controller_2), + StakingBalance::Ring(50 * COIN) + )); + assert_ok!(Staking::unbond( + Origin::signed(controller_2), + StakingBalance::Kton(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::claim_deposits_with_punish( + Origin::signed(controller_2), + (promise_month * MONTH_IN_SECONDS) as u64, + )); + // unbond deposit items: 12.5Ring + Timestamp::set_timestamp((promise_month * MONTH_IN_SECONDS) as u64); + assert_ok!(Staking::unbond( + Origin::signed(controller_2), + StakingBalance::Ring(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, + ExtendedBalance::max_value(), + &Staking::stakers(&stash_1), + &mut vec![], + ); + // FIXME: slash strategy + let _ = Staking::slash_validator( + &stash_2, + ExtendedBalance::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().existential_deposit(0).build().execute_with(|| { + gen_paired_account!(stash(123), controller(456)); + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Ring(COIN), + RewardDestination::Stash, + 0, + )); + + for ts in 0..MAX_UNLOCKING_CHUNKS { + Timestamp::set_timestamp(ts as u64); + assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Ring(1))); + } + + assert_err!( + Staking::unbond(Origin::signed(controller), StakingBalance::Ring(1)), + "can not schedule more unlock chunks", + ); + }); +} + +#[test] +fn promise_extra_should_not_remove_unexpired_items() { + ExtBuilder::default().existential_deposit(0).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_SECONDS) as u64; + + assert_ok!(Staking::bond_extra( + Origin::signed(stash), + StakingBalance::Ring(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!( - Ring::locks(&11), - vec![BalanceLock { - id: STAKING_ID, - withdraw_lock: WithdrawLock::WithStaking(StakingLock { - staking_amount: 0, - unbondings: vec![], - }), - reasons: WithdrawReasons::all() - }] + Staking::ledger(&controller).unwrap().deposit_items.len(), + 2 + expired_items_len, ); - assert_ok!(Ring::ensure_can_withdraw( - &11, - free_balance, - WithdrawReason::Transfer.into(), - 0 + + 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().existential_deposit(0).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_SECONDS) as u64); + assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Ring(0))); + assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Kton(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().existential_deposit(0).build().execute_with(|| { + let (stash, controller) = (777, 888); + let _ = Ring::deposit_creating(&stash, 20_000); + + assert_ok!(Staking::bond( + Origin::signed(stash), + controller, + StakingBalance::Ring(10_000), + RewardDestination::Stash, + 12, + )); + assert_ok!(Staking::bond_extra( + Origin::signed(stash), + StakingBalance::Ring(10_000), + 36, + )); + assert_eq!(Kton::free_balance(&stash), 4); + + assert_ok!(Staking::bond_extra(Origin::signed(stash), StakingBalance::Kton(1), 36)); + assert_eq!(Staking::ledger(&controller).unwrap().active_kton, 1); + + assert_ok!(Staking::nominate(Origin::signed(controller), vec![controller])); + + assert_ok!(Staking::claim_deposits_with_punish( + Origin::signed(controller), + (12 * MONTH_IN_SECONDS) as u64, + )); + assert_eq!(Kton::free_balance(&stash), 1); + + let ledger = Staking::ledger(&controller).unwrap(); + // not enough Kton to unbond + assert_ok!(Staking::claim_deposits_with_punish( + Origin::signed(controller), + (36 * MONTH_IN_SECONDS) as u64, )); + assert_eq!(Staking::ledger(&controller).unwrap(), ledger); }); } -//#[test] -//fn normal_unbond_should_work() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let stash = 11; -// let controller = 10; -// let value = 200 * COIN; -// let promise_month = 12; -// // unbond normal ring -// 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), -// StakingBalance::Ring(value), -// promise_month, -// )); -// assert_eq!( -// Kton::free_balance(&stash), -// kton_free_balance + inflation::compute_kton_return::(value, promise_month) -// ); -// ledger.total_deposit_ring += value; -// ledger.active_ring += value; -// ledger.active_deposit_ring += value; -// ledger.deposit_items.push(TimeDepositItem { -// value: value, -// start_time: 0, -// expire_time: promise_month as u64 * MONTH_IN_SECONDS as u64, -// }); -// 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.03 Kton -// // extra = 1.min(0.03) -// // bond += 0.03 -// assert_ok!(Staking::bond_extra( -// Origin::signed(stash), -// StakingBalance::Kton(COIN), -// 0 -// )); -// ledger.active_kton += kton_free_balance; -// assert_eq!(&Staking::ledger(&controller).unwrap(), &ledger); -// -// assert_ok!(Staking::unbond( -// Origin::signed(controller), -// StakingBalance::Kton(kton_free_balance) -// )); -// ledger.active_kton = 0; -// ledger.unbondings = vec![NormalLock { -// value: StakingBalance::Kton(kton_free_balance), -// era: 3, -// is_time_deposit: false, -// }]; -// assert_eq!(&Staking::ledger(&controller).unwrap(), &ledger); -// } -// }); -//} -// -//#[test] -//fn punished_unbond_should_work() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let stash = 1001; -// let controller = 1000; -// let promise_month = 36; -// -// let _ = Ring::deposit_creating(&stash, 100 * COIN); -// Kton::deposit_creating(&stash, COIN / 100000); -// -// // timestamp now is 0. -// // free balance of kton is too low to work -// assert_ok!(Staking::bond( -// Origin::signed(stash), -// controller, -// StakingBalance::Ring(10 * COIN), -// RewardDestination::Stash, -// promise_month -// )); -// assert_eq!( -// Staking::ledger(&controller), -// Some(StakingLedger { -// stash, -// total_deposit_ring: 10 * COIN, -// active_deposit_ring: 10 * COIN, -// active_ring: 10 * COIN, -// active_kton: 0, -// deposit_items: vec![TimeDepositItem { -// value: 10 * COIN, -// start_time: 0, -// expire_time: promise_month as u64 * MONTH_IN_SECONDS as u64 -// }], // should be cleared -// unbondings: vec![] -// }) -// ); -// let mut ledger = Staking::ledger(&controller).unwrap(); -// let kton_free_balance = Kton::free_balance(&stash); -// // kton is 0, skip unbond_with_punish -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 10 * COIN, -// promise_month as u64 * MONTH_IN_SECONDS as u64 -// )); -// assert_eq!(&Staking::ledger(&controller).unwrap(), &ledger); -// assert_eq!(Kton::free_balance(&stash), kton_free_balance); -// -// // set more kton balance to make it work -// Kton::deposit_creating(&stash, 10 * COIN); -// let kton_free_balance = Kton::free_balance(&stash); -// let unbond_value = 5 * COIN; -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// unbond_value, -// promise_month as u64 * MONTH_IN_SECONDS as u64 -// )); -// ledger.active_ring -= unbond_value; -// ledger.active_deposit_ring -= unbond_value; -// ledger.deposit_items[0].value -= unbond_value; -// ledger.unbondings = vec![NormalLock { -// value: StakingBalance::Ring(unbond_value), -// era: 3, -// is_time_deposit: true, -// }]; -// assert_eq!(&Staking::ledger(&controller).unwrap(), &ledger); -// -// let kton_punishment = inflation::compute_kton_return::(unbond_value, promise_month); -// assert_eq!(Kton::free_balance(&stash), kton_free_balance - 3 * kton_punishment); -// -// // if deposit_item.value == 0 -// // the whole item should be be dropped -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 5 * COIN, -// promise_month as u64 * MONTH_IN_SECONDS as u64 -// )); -// assert!(Staking::ledger(&controller).unwrap().deposit_items.is_empty()); -// }); -//} -// -//#[test] -//fn transform_to_promised_ring_should_work() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let _ = Ring::deposit_creating(&1001, 100 * COIN); -// assert_ok!(Staking::bond( -// Origin::signed(1001), -// 1000, -// StakingBalance::Ring(10 * COIN), -// RewardDestination::Stash, -// 0 -// )); -// let origin_ledger = Staking::ledger(&1000).unwrap(); -// let kton_free_balance = Kton::free_balance(&1001); -// -// assert_ok!(Staking::promise_extra(Origin::signed(1000), 5 * COIN, 12)); -// -// assert_eq!( -// Staking::ledger(&1000), -// Some(StakingLedger { -// stash: 1001, -// total_deposit_ring: origin_ledger.total_deposit_ring + 5 * COIN, -// active_deposit_ring: origin_ledger.active_deposit_ring + 5 * COIN, -// active_ring: origin_ledger.active_ring, -// active_kton: origin_ledger.active_kton, -// deposit_items: vec![TimeDepositItem { -// value: 5 * COIN, -// start_time: 0, -// expire_time: 12 * MONTH_IN_SECONDS as u64 -// }], -// unbondings: vec![] -// }) -// ); -// -// assert_eq!(Kton::free_balance(&1001), kton_free_balance + (5 * COIN / 10000)); -// }); -//} -// -//#[test] -//fn expired_ring_should_capable_to_promise_again() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let _ = Ring::deposit_creating(&1001, 100 * COIN); -// assert_ok!(Staking::bond( -// Origin::signed(1001), -// 1000, -// StakingBalance::Ring(10 * COIN), -// RewardDestination::Stash, -// 12 -// )); -// let mut ledger = Staking::ledger(&1000).unwrap(); -// let ts = 13 * MONTH_IN_SECONDS as u64; -// let promise_extra_value = 5 * COIN; -// Timestamp::set_timestamp(ts); -// assert_ok!(Staking::promise_extra(Origin::signed(1000), promise_extra_value, 13)); -// ledger.total_deposit_ring = promise_extra_value; -// 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(&1000).unwrap(), &ledger); -// }); -//} -// -////#[test] -////fn inflation_should_be_correct() { -//// ExtBuilder::default().existential_deposit(0).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); -//// // assert_eq!(Staking::current_era_total_reward(), 80000000 * COIN / 10); -//// start_era(11); -//// // ErasPerEpoch = 10 -//// // assert_eq!(Staking::current_era_total_reward(), 88000000 * COIN / 10); -//// }); -////} -// -//#[test] -//fn reward_should_work_correctly() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// // create controller account -// let _ = Ring::deposit_creating(&2000, COIN); -// let _ = Ring::deposit_creating(&1000, COIN); -// let _ = Ring::deposit_creating(&200, COIN); -// // new validator -// let _ = Ring::deposit_creating(&2001, 2000 * COIN); -// Kton::deposit_creating(&2001, 10 * COIN); -// // new validator -// let _ = Ring::deposit_creating(&1001, 300 * COIN); -// Kton::deposit_creating(&1001, 1 * COIN); -// // handle some dirty work -// let _ = Ring::deposit_creating(&201, 2000 * COIN); -// Kton::deposit_creating(&201, 10 * COIN); -// assert_eq!(Kton::free_balance(&201), 10 * COIN); -// -// // 2001-2000 -// assert_ok!(Staking::bond( -// Origin::signed(2001), -// 2000, -// StakingBalance::Ring(300 * COIN), -// RewardDestination::Controller, -// 12, -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed(2001), -// StakingBalance::Kton(1 * COIN), -// 0 -// )); -// // 1001-1000 -// assert_ok!(Staking::bond( -// Origin::signed(1001), -// 1000, -// StakingBalance::Ring(300 * COIN), -// RewardDestination::Controller, -// 12, -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed(1001), -// StakingBalance::Kton(1 * COIN), -// 0 -// )); -// let ring_pool = Staking::ring_pool(); -// let kton_pool = Staking::kton_pool(); -// // 201-200 -// assert_ok!(Staking::bond( -// Origin::signed(201), -// 200, -// StakingBalance::Ring(3000 * COIN - ring_pool), -// RewardDestination::Stash, -// 12, -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed(201), -// StakingBalance::Kton(10 * COIN - kton_pool), -// 0, -// )); -// // ring_pool and kton_pool -// assert_eq!(Staking::ring_pool(), 3000 * COIN); -// assert_eq!(Staking::kton_pool(), 10 * COIN); -// // 1/5 ring_pool and 1/5 kton_pool -// assert_ok!(Staking::validate(Origin::signed(2000), [0; 8].to_vec(), 0, 3)); -// assert_ok!(Staking::nominate(Origin::signed(1000), vec![2001])); -// -// assert_eq!(Staking::ledger(&2000).unwrap().active_kton, 1 * COIN); -// assert_eq!(Staking::ledger(&2000).unwrap().active_ring, 300 * COIN); -// assert_eq!(Staking::power_of(&2001), 1_000_000_000 / 10 as u128); -// // 600COIN for rewarding ring bond-er -// // 600COIN for rewarding kton bond-er -// Staking::select_validators(); -// Staking::reward_validator(&2001, 1200 * COIN); -// -// assert_eq!( -// Staking::stakers(2001), -// Exposure { -// total: 1200000000000, -// own: 600000000000, -// others: vec![IndividualExposure { -// who: 1001, -// value: 600000000000 -// }] -// } -// ); -// assert_eq!(Ring::free_balance(&2000), 601 * COIN); -// assert_eq!(Ring::free_balance(&1000), 601 * COIN); -// }); -//} -// -//#[test] -//fn slash_should_work() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let _ = Ring::deposit_creating(&1001, 100 * COIN); -// Kton::deposit_creating(&1001, 100 * COIN); -// -// assert_ok!(Staking::bond( -// Origin::signed(1001), -// 1000, -// StakingBalance::Ring(50 * COIN), -// RewardDestination::Controller, -// 0, -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed(1001), -// StakingBalance::Kton(50 * COIN), -// 0 -// )); -// assert_ok!(Staking::validate(Origin::signed(1000), [0; 8].to_vec(), 0, 3)); -// -// // slash 1% -// let slash_value = 5 * COIN / 10; -// let mut ledger = Staking::ledger(&1000).unwrap(); -// let ring_free_balance = Ring::free_balance(&1001); -// let kton_free_balance = Kton::free_balance(&1001); -// Staking::slash_validator(&1001, 10_000_000); -// ledger.active_ring -= slash_value; -// ledger.active_kton -= slash_value; -// assert_eq!(&Staking::ledger(&1000).unwrap(), &ledger); -// assert_eq!(Ring::free_balance(&1001), ring_free_balance - slash_value); -// assert_eq!(Kton::free_balance(&1001), kton_free_balance - slash_value); -// }); -//} -// -//#[test] -////fn test_inflation() { -//// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -//// assert_eq!(Staking::current_era_total_reward(), 80_000_000 * COIN / 10); -//// start_era(20); -//// assert_eq!(Staking::epoch_index(), 2); -//// assert_eq!(Staking::current_era_total_reward(), 9_999_988_266 * COIN / 1000); -//// }); -////} -//#[test] -//fn set_controller_should_remove_old_ledger() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let stash = 11; -// let old_controller = 10; -// let new_controller = 12; -// -// assert!(Staking::ledger(&old_controller).is_some()); -// assert_eq!(Staking::bonded(&stash), Some(old_controller)); -// -// assert_ok!(Staking::set_controller(Origin::signed(stash), new_controller)); -// assert!(Staking::ledger(&old_controller).is_none()); -// }); -//} -// -//#[test] -//fn set_controller_should_not_change_ledger() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// assert_eq!(Staking::ledger(&10).unwrap().active_ring, 100 * COIN); -// assert_ok!(Staking::set_controller(Origin::signed(11), 12)); -// assert_eq!(Staking::ledger(&12).unwrap().active_ring, 100 * COIN); -// }); -//} -// -//#[test] -//fn slash_should_not_touch_unbondingss() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let old_ledger = Staking::ledger(&10).unwrap(); -// // only deposit_ring, no normal_ring -// assert_eq!( -// ( -// old_ledger.active_ring, -// old_ledger.active_deposit_ring -// ), -// (100 * COIN, 100 * COIN) -// ); -// -// assert_ok!(Staking::bond_extra( -// Origin::signed(11), -// StakingBalance::Ring(100 * COIN), -// 0 -// )); -// Kton::deposit_creating(&11, 10 * COIN); -// assert_ok!(Staking::bond_extra( -// Origin::signed(11), -// StakingBalance::Kton(10 * COIN), -// 0 -// )); -// -// assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Ring(10 * COIN))); -// let new_ledger = Staking::ledger(&10).unwrap(); -// assert_eq!( -// ( -// new_ledger.active_ring, -// new_ledger.active_deposit_ring -// ), -// (190 * COIN, 100 * COIN) -// ); -// -// // slash 100% -// Staking::slash_validator(&11, 1_000_000_000); -// -// let ledger = Staking::ledger(&10).unwrap(); -// assert_eq!( -// (ledger.active_ring, ledger.active_deposit_ring), -// // 10Ring in unbondings -// (0, 0) -// ); -// assert_eq!(ledger.unbondings[0].value, StakingBalance::Ring(10 * COIN)); -// }); -//} -// -//#[test] -//fn bond_over_max_promise_month_should_fail() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// gen_paired_account!(stash(123), controller(456)); -// assert_err!( -// Staking::bond( -// Origin::signed(stash), -// controller, -// StakingBalance::Ring(COIN), -// RewardDestination::Stash, -// 37 -// ), -// "months at most is 36." -// ); -// -// gen_paired_account!(stash(123), controller(456), promise_month(12)); -// assert_err!( -// Staking::bond_extra(Origin::signed(stash), StakingBalance::Ring(COIN), 37), -// "months at most is 36." -// ); -// }); -//} -// -//#[test] -//fn stash_already_bonded_and_controller_already_paired_should_fail() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// gen_paired_account!(unpaired_stash(123), unpaired_controller(456)); -// assert_err!( -// Staking::bond( -// Origin::signed(11), -// unpaired_controller, -// StakingBalance::Ring(COIN), -// RewardDestination::Stash, -// 0 -// ), -// "stash already bonded" -// ); -// assert_err!( -// Staking::bond( -// Origin::signed(unpaired_stash), -// 10, -// StakingBalance::Ring(COIN), -// RewardDestination::Stash, -// 0 -// ), -// "controller already paired" -// ); -// }); -//} -// -//#[test] -//fn pool_should_be_increased_and_decreased_correctly() { -// ExtBuilder::default().existential_deposit(0).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), -// StakingBalance::Ring(50 * COIN) -// )); -// assert_ok!(Staking::unbond( -// Origin::signed(controller_1), -// StakingBalance::Kton(25 * COIN) -// )); -// // not yet expired: promise for 12 months -// assert_ok!(Staking::unbond( -// Origin::signed(controller_2), -// StakingBalance::Ring(50 * COIN) -// )); -// assert_ok!(Staking::unbond( -// Origin::signed(controller_2), -// StakingBalance::Kton(25 * COIN) -// )); -// ring_pool -= 50 * COIN; -// kton_pool -= 50 * COIN; -// assert_eq!(Staking::ring_pool(), ring_pool); -// assert_eq!(Staking::kton_pool(), kton_pool); -// -// // unbond with punish: 12.5Ring -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller_2), -// 125 * COIN / 10, -// promise_month * MONTH_IN_SECONDS as u64 -// )); -// // unbond deposit items: 12.5Ring -// Timestamp::set_timestamp(promise_month * MONTH_IN_SECONDS as u64); -// assert_ok!(Staking::unbond( -// Origin::signed(controller_2), -// StakingBalance::Ring(125 * COIN / 10) -// )); -// ring_pool -= 25 * COIN; -// assert_eq!(Staking::ring_pool(), ring_pool); -// -// // slash: 25Ring 50Kton -// Staking::slash_validator(&stash_1, 1_000_000_000); -// Staking::slash_validator(&stash_2, 1_000_000_000); -// ring_pool -= 25 * COIN; -// 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().existential_deposit(0).build().execute_with(|| { -// gen_paired_account!(stash(123), controller(456), promise_month(12)); -// let deposit_items_len = MAX_UNLOCKING_CHUNKS + 1; -// -// for _ in 1..deposit_items_len { -// assert_ok!(Staking::bond_extra( -// Origin::signed(stash), -// StakingBalance::Ring(COIN), -// promise_month -// )); -// } -// { -// let ledger = Staking::ledger(&controller).unwrap(); -// assert_eq!(ledger.deposit_items.len(), deposit_items_len); -// assert_eq!(ledger.unbondings.len(), 0); -// } -// -// Timestamp::set_timestamp(promise_month as u64 * MONTH_IN_SECONDS as u64); -// -// for _ in 1..deposit_items_len { -// assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Ring(COIN))); -// } -// { -// let ledger = Staking::ledger(&controller).unwrap(); -// assert_eq!(ledger.deposit_items.len(), 1); -// assert_eq!(ledger.unbondings.len(), deposit_items_len - 1); -// } -// assert_err!( -// Staking::unbond( -// Origin::signed(controller), -// StakingBalance::Ring((deposit_items_len - 1) as u64 * COIN) -// ), -// "can not schedule more unlock chunks" -// ); -// }); -//} -// -//#[test] -//fn unlock_value_should_be_increased_and_decreased_correctly() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// // normal Ring/Kton -// { -// let stash = 444; -// let controller = 555; -// let _ = Ring::deposit_creating(&stash, 100 * COIN); -// Kton::deposit_creating(&stash, 100 * COIN); -// -// assert_ok!(Staking::bond( -// Origin::signed(stash), -// controller, -// StakingBalance::Ring(50 * COIN), -// RewardDestination::Stash, -// 0 -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed(stash), -// StakingBalance::Kton(50 * COIN), -// 0 -// )); -// -// let mut unbondings = Staking::ledger(&controller).unwrap().unbondings; -// -// assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Ring(COIN))); -// unbondings.push(NormalLock { -// value: StakingBalance::Ring(COIN), -// era: 3, -// is_time_deposit: false, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Kton(COIN))); -// unbondings.push(NormalLock { -// value: StakingBalance::Kton(COIN), -// era: 3, -// is_time_deposit: false, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// -// assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Ring(0))); -// unbondings.push(NormalLock { -// value: StakingBalance::Ring(0), -// era: 3, -// is_time_deposit: true, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Kton(0))); -// unbondings.push(NormalLock { -// value: StakingBalance::Kton(0), -// era: 3, -// is_time_deposit: false, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// } -// -// // promise Ring -// { -// gen_paired_account!(stash(666), controller(777), promise_month(12)); -// -// assert_ok!(Staking::bond_extra( -// Origin::signed(stash), -// StakingBalance::Ring(50 * COIN), -// 36 -// )); -// -// let mut unbondings = Staking::ledger(&controller).unwrap().unbondings; -// -// assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Ring(COIN))); -// unbondings.push(NormalLock { -// value: StakingBalance::Ring(0), -// era: 3, -// is_time_deposit: true, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// -// for month in [12, 36].iter() { -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 20 * COIN, -// month * MONTH_IN_SECONDS as u64 -// )); -// unbondings.push(NormalLock { -// value: StakingBalance::Ring(20 * COIN), -// era: 3, -// is_time_deposit: true, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 29 * COIN, -// month * MONTH_IN_SECONDS as u64 -// )); -// unbondings.push(NormalLock { -// value: StakingBalance::Ring(29 * COIN), -// era: 3, -// is_time_deposit: true, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 50 * COIN, -// month * MONTH_IN_SECONDS as u64 -// )); -// unbondings.push(NormalLock { -// value: StakingBalance::Ring(1 * COIN), -// era: 3, -// is_time_deposit: true, -// }); -// assert_eq!(&Staking::ledger(&controller).unwrap().unbondings, &unbondings); -// } -// } -// }); -//} -// -//// #[test] -//// fn total_deposit_should_be_increased_and_decreased_correctly() { -//// with_externalities( -//// &mut ExtBuilder::default().existential_deposit(0).build(), -//// || body, -//// ); -//// } -// -//#[test] -//fn promise_extra_should_not_remove_unexpired_items() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// gen_paired_account!(stash(123), controller(456), promise_month(12)); -// -// let expired_item_len = 3; -// let expiry_date = promise_month as u64 * MONTH_IN_SECONDS as u64; -// -// assert_ok!(Staking::bond_extra( -// Origin::signed(stash), -// StakingBalance::Ring(5 * COIN), -// 0 -// )); -// for _ in 0..expired_item_len { -// assert_ok!(Staking::promise_extra(Origin::signed(controller), COIN, promise_month)); -// } -// -// Timestamp::set_timestamp(expiry_date - 1); -// assert_ok!(Staking::promise_extra( -// Origin::signed(controller), -// 2 * COIN, -// promise_month -// )); -// assert_eq!( -// Staking::ledger(&controller).unwrap().deposit_items.len(), -// 2 + expired_item_len -// ); -// -// Timestamp::set_timestamp(expiry_date); -// assert_ok!(Staking::promise_extra( -// Origin::signed(controller), -// 2 * COIN, -// promise_month -// )); -// assert_eq!(Staking::ledger(&controller).unwrap().deposit_items.len(), 2); -// }); -//} -// -//#[test] -//fn unbond_zero_before_expiry() { -// ExtBuilder::default().existential_deposit(0).build().execute_with(|| { -// let expiry_date = 12 * MONTH_IN_SECONDS as u64; -// let unbond_value = StakingBalance::Ring(COIN); -// -// Timestamp::set_timestamp(expiry_date - 1); -// assert_ok!(Staking::unbond(Origin::signed(10), unbond_value.clone())); -// assert_eq!( -// Staking::ledger(&10).unwrap().unbondings[0].value, -// StakingBalance::Ring(0) -// ); -// -// Timestamp::set_timestamp(expiry_date); -// assert_ok!(Staking::unbond(Origin::signed(10), unbond_value.clone())); -// assert_eq!(Staking::ledger(&10).unwrap().unbondings[1].value, unbond_value); -// }); -//} -// -//// 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().existential_deposit(0).build().execute_with(|| { -// let stash = 777; -// let controller = 888; -// let _ = Ring::deposit_creating(&stash, 20_000); -// -// assert_ok!(Staking::bond( -// Origin::signed(stash), -// controller, -// StakingBalance::Ring(10_000), -// RewardDestination::Stash, -// 12 -// )); -// assert_ok!(Staking::bond_extra( -// Origin::signed(stash), -// StakingBalance::Ring(10_000), -// 36 -// )); -// assert_eq!(Kton::free_balance(&stash), 4); -// -// assert_ok!(Staking::bond_extra(Origin::signed(stash), StakingBalance::Kton(1), 36)); -// assert_eq!(Staking::ledger(&controller).unwrap().active_kton, 1); -// -// assert_ok!(Staking::nominate(Origin::signed(controller), vec![controller])); -// -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 10_000 * COIN, -// 12 * MONTH_IN_SECONDS as u64 -// )); -// assert_eq!(Kton::free_balance(&stash), 1); -// -// let ledger = StakingLedger { -// stash: 777, -// total_deposit_ring: 10_000, -// active_ring: 10_000, -// active_deposit_ring: 10_000, -// active_kton: 1, -// deposit_items: vec![TimeDepositItem { -// value: 10_000, -// start_time: 0, -// expire_time: 36 * MONTH_IN_SECONDS as u64, -// }], -// unbondings: vec![], -// }; -// start_era(3); -// assert_ok!(Staking::withdraw_unbonded(Origin::signed(controller))); -// assert_eq!(&Staking::ledger(&controller).unwrap(), &ledger); -// // not enough Kton to unbond -// assert_ok!(Staking::unbond_with_punish( -// Origin::signed(controller), -// 10_000 * COIN, -// 36 * MONTH_IN_SECONDS as u64 -// )); -// 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) -> u64 { -// let mut balance = 0; -// ExtBuilder::default().existential_deposit(0).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), -// vec![0; 8], -// 0, -// 3 -// )); -// assert_ok!(Staking::validate( -// Origin::signed(validator_2_controller), -// vec![1; 8], -// 0, -// 3 -// )); -// 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); -// } -// Staking::reward_validator(&validator_1_stash, 1000 * COIN); -// 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); -//} +// 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().existential_deposit(0).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() { @@ -1265,7 +975,7 @@ fn xavier_q1() { staking_amount: 10, unbondings: vec![], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Bond Extra - Kton Balance: {:?}", Kton::free_balance(stash)); @@ -1288,7 +998,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Unbond - Kton Balance: {:?}", Kton::free_balance(stash)); @@ -1325,7 +1035,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); @@ -1343,7 +1053,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); assert_eq!( @@ -1354,10 +1064,7 @@ fn xavier_q1() { active_deposit_ring: 0, active_kton: 20, deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, + ring_staking_lock: Default::default(), kton_staking_lock: StakingLock { staking_amount: 20, unbondings: vec![NormalLock { @@ -1399,7 +1106,7 @@ fn xavier_q1() { staking_amount: 5, unbondings: vec![], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Init - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1418,7 +1125,7 @@ fn xavier_q1() { staking_amount: 10, unbondings: vec![], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Bond Extra - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1441,7 +1148,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Unbond - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1450,7 +1157,7 @@ fn xavier_q1() { assert_err!( Ring::transfer(Origin::signed(stash), controller, 1), - "account liquidity restrictions prevent withdrawal" + "account liquidity restrictions prevent withdrawal", ); // println!("Locking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); // println!("Locking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); @@ -1478,7 +1185,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); @@ -1496,7 +1203,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); assert_eq!( @@ -1514,10 +1221,7 @@ fn xavier_q1() { until: BondingDuration::get() + unbond_start, }] }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, + kton_staking_lock: Default::default(), } ); // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1554,7 +1258,7 @@ fn xavier_q2() { staking_amount: 5, unbondings: vec![], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Init - Kton Balance: {:?}", Kton::free_balance(stash)); @@ -1573,18 +1277,18 @@ fn xavier_q2() { staking_amount: 9, unbondings: vec![], }), - reasons: WithdrawReasons::all() + 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_value_1, unbond_start_1) = (2, 2); + let (unbond_start_1, unbond_value_1) = (2, 2); Timestamp::set_timestamp(unbond_start_1); assert_ok!(Staking::unbond( Origin::signed(controller), - StakingBalance::Kton(unbond_value_1) + StakingBalance::Kton(unbond_value_1), )); assert_eq!(Timestamp::get(), unbond_start_1); assert_eq!(Kton::free_balance(stash), 10); @@ -1599,14 +1303,14 @@ fn xavier_q2() { until: BondingDuration::get() + unbond_start_1, }], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Unbond - Kton Balance: {:?}", Kton::free_balance(stash)); // println!("Ok Unbond - Kton Locks: {:#?}", Kton::locks(stash)); // println!(); - let (unbond_value_2, unbond_start_2) = (6, 3); + let (unbond_start_2, unbond_value_2) = (3, 6); Timestamp::set_timestamp(unbond_start_2); assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Kton(6))); assert_eq!(Timestamp::get(), unbond_start_2); @@ -1628,7 +1332,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Unbond - Kton Balance: {:?}", Kton::free_balance(stash)); @@ -1637,7 +1341,7 @@ fn xavier_q2() { assert_err!( Kton::transfer(Origin::signed(stash), controller, unbond_value_1), - "account liquidity restrictions prevent withdrawal" + "account liquidity restrictions prevent withdrawal", ); // println!("Locking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); // println!("Locking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); @@ -1651,7 +1355,7 @@ fn xavier_q2() { 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" + "account liquidity restrictions prevent withdrawal", ); // println!("Locking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); // println!("Locking Transfer - Kton Locks: {:#?}", Kton::locks(stash)); @@ -1676,7 +1380,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Unlocking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); @@ -1703,7 +1407,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Unlocking Transfer - Kton Balance: {:?}", Kton::free_balance(stash)); @@ -1730,7 +1434,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); }); @@ -1757,7 +1461,7 @@ fn xavier_q2() { staking_amount: 5, unbondings: vec![], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Init - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1776,14 +1480,14 @@ fn xavier_q2() { staking_amount: 9, unbondings: vec![], }), - reasons: WithdrawReasons::all() + 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_value_1, unbond_start_1) = (2, 2); + let (unbond_start_1, unbond_value_1) = (2, 2); Timestamp::set_timestamp(unbond_start_1); assert_ok!(Staking::unbond( Origin::signed(controller), @@ -1802,14 +1506,14 @@ fn xavier_q2() { until: BondingDuration::get() + unbond_start_1, },], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Unbond - Ring Balance: {:?}", Ring::free_balance(stash)); // println!("Ok Unbond - Ring Locks: {:#?}", Ring::locks(stash)); // println!(); - let (unbond_value_2, unbond_start_2) = (6, 3); + let (unbond_start_2, unbond_value_2) = (3, 6); Timestamp::set_timestamp(unbond_start_2); assert_ok!(Staking::unbond(Origin::signed(controller), StakingBalance::Ring(6))); assert_eq!(Timestamp::get(), unbond_start_2); @@ -1831,7 +1535,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Ok Unbond - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1840,7 +1544,7 @@ fn xavier_q2() { assert_err!( Ring::transfer(Origin::signed(stash), controller, unbond_value_1), - "account liquidity restrictions prevent withdrawal" + "account liquidity restrictions prevent withdrawal", ); // println!("Locking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); // println!("Locking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); @@ -1854,7 +1558,7 @@ fn xavier_q2() { 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" + "account liquidity restrictions prevent withdrawal", ); // println!("Locking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); // println!("Locking Transfer - Ring Locks: {:#?}", Ring::locks(stash)); @@ -1879,7 +1583,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1906,7 +1610,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); // println!("Unlocking Transfer - Ring Balance: {:?}", Ring::free_balance(stash)); @@ -1933,7 +1637,7 @@ fn xavier_q2() { } ], }), - reasons: WithdrawReasons::all() + reasons: WithdrawReasons::all(), }] ); }); @@ -1963,13 +1667,10 @@ fn xavier_q3() { active_deposit_ring: 0, active_kton: 5, deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, + ring_staking_lock: Default::default(), kton_staking_lock: StakingLock { staking_amount: 5, - unbondings: vec![] + unbondings: vec![], }, } ); @@ -1986,13 +1687,10 @@ fn xavier_q3() { active_deposit_ring: 0, active_kton: 0, deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, + ring_staking_lock: Default::default(), kton_staking_lock: StakingLock { staking_amount: 0, - unbondings: vec![NormalLock { amount: 5, until: 61 }] + unbondings: vec![NormalLock { amount: 5, until: 61 }], }, } ); @@ -2011,13 +1709,10 @@ fn xavier_q3() { active_deposit_ring: 0, active_kton: 1, deposit_items: vec![], - ring_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] - }, + ring_staking_lock: Default::default(), kton_staking_lock: StakingLock { staking_amount: 1, - unbondings: vec![NormalLock { amount: 5, until: 61 }] + unbondings: vec![NormalLock { amount: 5, until: 61 }], }, } ); @@ -2050,12 +1745,9 @@ fn xavier_q3() { deposit_items: vec![], ring_staking_lock: StakingLock { staking_amount: 5, - unbondings: vec![] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] + unbondings: vec![], }, + kton_staking_lock: Default::default(), } ); // println!("Locks: {:#?}", Ring::locks(stash)); @@ -2073,12 +1765,9 @@ fn xavier_q3() { deposit_items: vec![], ring_staking_lock: StakingLock { staking_amount: 0, - unbondings: vec![NormalLock { amount: 5, until: 61 }] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] + unbondings: vec![NormalLock { amount: 5, until: 61 }], }, + kton_staking_lock: Default::default(), } ); // println!("Locks: {:#?}", Ring::locks(stash)); @@ -2098,12 +1787,9 @@ fn xavier_q3() { deposit_items: vec![], ring_staking_lock: StakingLock { staking_amount: 1, - unbondings: vec![NormalLock { amount: 5, until: 61 }] - }, - kton_staking_lock: StakingLock { - staking_amount: 0, - unbondings: vec![] + unbondings: vec![NormalLock { amount: 5, until: 61 }], }, + kton_staking_lock: Default::default(), } ); // println!("Locks: {:#?}", Ring::locks(stash)); diff --git a/types.json b/types.json index f59e2e99b..79a6b8957 100644 --- a/types.json +++ b/types.json @@ -23,8 +23,9 @@ }, "ValidatorPrefs": { + "node_name": "Vec", "unstake_threshold": "Compact", - "validator_payment_ratio": "Perbill" + "validator_payment_ratio": "Compact" }, "StakingLedger": {