diff --git a/README.adoc b/README.adoc index 1f19815a3..c855a8573 100644 --- a/README.adoc +++ b/README.adoc @@ -160,7 +160,7 @@ Detailed logs may be shown by running the node with the following environment va If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain specification that have been endowed with a testnet Ring. -We'll start Alice's Darwinia node first with her chain database stored locally at `/tmp/darwinia-develop/alice`. +We'll start Alice's Darwinia node first with her chain database stored locally at `/tmp/darwinia-develop/alice`: [source, shell] cargo run --release \-- \ @@ -178,7 +178,7 @@ Or just: [source, shell] cargo run --release -- --alice --conf=boot-conf/develop/alice.json -In the second terminal, we'll run the following to start Bob's Darwinia node on a different TCP port of 30334, and with his chain database stored locally at `/tmp/darwinia-develop/bob`. We'll specify a value for the `--bootnodes` option that will connect his node to Alice's Bootnode ID on TCP port 30333: +In the second terminal, we'll run the following to start Bob's Darwinia node on a different TCP port, and with his chain database stored locally at `/tmp/darwinia-develop/bob`: [source, shell] cargo run --release \-- \ diff --git a/srml/staking/src/inflation.rs b/srml/staking/src/inflation.rs index 2237f643e..cf29b6a19 100644 --- a/srml/staking/src/inflation.rs +++ b/srml/staking/src/inflation.rs @@ -5,7 +5,7 @@ use sr_primitives::{ }; use substrate_primitives::U256; -use crate::{KtonBalanceOf, Moment, RingBalanceOf, Trait}; +use crate::{Kton, Moment, Ring, Trait}; // 1 - (99 / 100) ^ sqrt(year) // () -> RingBalanceOf @@ -13,7 +13,7 @@ pub fn compute_total_payout( era_duration: Moment, living_time: Moment, total_left: u128, -) -> (RingBalanceOf, RingBalanceOf) { +) -> (Ring, Ring) { // Milliseconds per year for the Julian year (365.25 days). const MILLISECONDS_PER_YEAR: Moment = ((36525 * 24 * 60 * 60) / 100) * 1000; @@ -27,16 +27,16 @@ pub fn compute_total_payout( let payout = maximum * 1; // TODO: add treasury ratio: Perbill::from_rational_approximation(npos_token_staked, total_tokens); - let payout: RingBalanceOf = >::saturated_from::(payout); + let payout: Ring = >::saturated_from::(payout); - let maximum: RingBalanceOf = >::saturated_from::(maximum); + let maximum: Ring = >::saturated_from::(maximum); (payout, maximum) } // 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: u64) -> KtonBalanceOf { +pub fn compute_kton_return(value: Ring, months: u64) -> Kton { 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 76a7c8645..7d0e6db2e 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -42,6 +42,7 @@ mod mock; mod tests; use codec::{Decode, Encode, HasCompact}; +use phragmen::{build_support_map, elect, equalize, ExtendedBalance as Power, PhragmenStakedAssignment}; use rstd::{borrow::ToOwned, prelude::*, result}; use session::{historical::OnSessionEnding, SelectInitialValidators}; use sr_primitives::{ @@ -64,13 +65,6 @@ use system::{ensure_root, ensure_signed}; use darwinia_support::{ LockIdentifier, LockableCurrency, NormalLock, StakingLock, WithdrawLock, WithdrawReason, WithdrawReasons, }; -use phragmen::{build_support_map, elect, equalize, ExtendedBalance, PhragmenStakedAssignment}; - -const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; -const MAX_NOMINATIONS: usize = 16; -const MAX_UNLOCKING_CHUNKS: u32 = 32; -const MONTH_IN_MILLISECONDS: u64 = 30 * 24 * 60 * 60 * 1000; -const STAKING_ID: LockIdentifier = *b"staking "; pub type Balance = u128; pub type Moment = u64; @@ -81,6 +75,22 @@ pub type EraIndex = u32; /// Counter for the number of "reward" points earned by a given validator. pub type Points = u32; +type Ring = <::Ring as Currency<::AccountId>>::Balance; +type PositiveImbalanceRing = <::Ring as Currency<::AccountId>>::PositiveImbalance; +type NegativeImbalanceRing = <::Ring as Currency<::AccountId>>::NegativeImbalance; + +type Kton = <::Kton as Currency<::AccountId>>::Balance; +type PositiveImbalanceKton = <::Kton as Currency<::AccountId>>::PositiveImbalance; +type NegativeImbalanceKton = <::Kton as Currency<::AccountId>>::NegativeImbalance; + +type MomentOf = <::Time as Time>::Moment; + +const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; +const MAX_NOMINATIONS: usize = 16; +const MAX_UNLOCKING_CHUNKS: u32 = 32; +const MONTH_IN_MILLISECONDS: Moment = 30 * 24 * 60 * 60 * 1000; +const STAKING_ID: LockIdentifier = *b"staking "; + /// Reward points of an era. Used to split era total payout between validators. #[derive(Encode, Decode, Default)] pub struct EraPoints { @@ -259,16 +269,6 @@ pub struct SlashJournalEntry { own_slash: Power, } -type RingBalanceOf = <::Ring as Currency<::AccountId>>::Balance; -type RingPositiveImbalanceOf = <::Ring as Currency<::AccountId>>::PositiveImbalance; -type RingNegativeImbalanceOf = <::Ring as Currency<::AccountId>>::NegativeImbalance; - -type KtonBalanceOf = <::Kton as Currency<::AccountId>>::Balance; -type KtonPositiveImbalanceOf = <::Kton as Currency<::AccountId>>::PositiveImbalance; -type KtonNegativeImbalanceOf = <::Kton as Currency<::AccountId>>::NegativeImbalance; - -type MomentOf = <::Time as Time>::Moment; - /// Means for interacting with a specialized version of the `session` trait. /// /// This is needed because `Staking` sets the `ValidatorIdOf` of the `session::Trait` @@ -289,7 +289,7 @@ impl SessionInterface<::AccountId> for T where T: session::Trait::AccountId>, T: session::historical::Trait< - FullIdentification = Exposure<::AccountId, ExtendedBalance>, + FullIdentification = Exposure<::AccountId, Power>, FullIdentificationOf = ExposureOf, >, T::SessionHandler: session::SessionHandler<::AccountId>, @@ -324,23 +324,23 @@ pub trait Trait: timestamp::Trait + session::Trait { /// TODO: #1377 /// The backward convert should be removed as the new Phragmen API returns ratio. /// The post-processing needs it but will be moved to off-chain. TODO: #2908 - type CurrencyToVote: Convert + Convert; + type CurrencyToVote: Convert + Convert; /// Tokens have been minted and are unused for validator-reward. - type RingRewardRemainder: OnUnbalanced>; + type RingRewardRemainder: OnUnbalanced>; /// The overarching event type. type Event: From> + Into<::Event>; /// Handler for the unbalanced increment when rewarding a staker. - type RingReward: OnUnbalanced>; + type RingReward: OnUnbalanced>; /// Handler for the unbalanced increment when rewarding a staker. - type KtonReward: OnUnbalanced>; + type KtonReward: OnUnbalanced>; /// Handler for the unbalanced reduction when slashing a staker. - type RingSlash: OnUnbalanced>; + type RingSlash: OnUnbalanced>; /// Handler for the unbalanced reduction when slashing a staker. - type KtonSlash: OnUnbalanced>; + type KtonSlash: OnUnbalanced>; /// Number of sessions per era. type SessionsPerEra: Get; @@ -393,7 +393,7 @@ decl_storage! { pub Bonded get(fn bonded): map T::AccountId => Option; /// Map from all (unlocked) "controller" accounts to the info regarding the staking. - pub Ledger get(fn ledger): map T::AccountId => Option, KtonBalanceOf, T::Moment>>; + pub Ledger get(fn ledger): map T::AccountId => Option, Kton, T::Moment>>; /// Where the reward payment should be made. Keyed by stash. pub Payee get(fn payee): map T::AccountId => RewardDestination; @@ -408,7 +408,7 @@ decl_storage! { /// through validators here, but you can find them in the Session module. /// /// This is keyed by the stash account. - pub Stakers get(fn stakers): map T::AccountId => Exposure; + pub Stakers get(fn stakers): map T::AccountId => Exposure; /// The currently elected validator set keyed by stash account ID. pub CurrentElected get(fn current_elected): Vec; @@ -430,7 +430,7 @@ decl_storage! { /// This is used to derive rewards and punishments. pub SlotStake get(fn slot_stake) build(|config: &GenesisConfig| { config.stakers.iter().map(|&(_, _, value, _)| value.saturated_into()).min().unwrap_or_default() - }): ExtendedBalance; + }): Power; /// True if the next session change will be a new era regardless of index. pub ForceEra get(fn force_era) config(): Forcing; @@ -441,19 +441,19 @@ decl_storage! { pub SlashRewardFraction get(fn slash_reward_fraction) config(): Perbill; /// Total *Ring* in pool. - pub RingPool get(fn ring_pool): RingBalanceOf; + pub RingPool get(fn ring_pool): Ring; /// Total *Kton* in pool. - pub KtonPool get(fn kton_pool): KtonBalanceOf; + pub KtonPool get(fn kton_pool): Kton; /// 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>; + EraSlashJournal get(fn era_slash_journal): map EraIndex => Vec>; } add_extra_genesis { - config(stakers): Vec<(T::AccountId, T::AccountId, RingBalanceOf, StakerStatus)>; + config(stakers): Vec<(T::AccountId, T::AccountId, Ring, StakerStatus)>; build(|config: &GenesisConfig| { for &(ref stash, ref controller, ring, ref status) in &config.stakers { assert!(T::Ring::free_balance(&stash) >= ring); @@ -488,14 +488,17 @@ decl_storage! { } decl_event!( - pub enum Event where Balance = RingBalanceOf, ::AccountId { + pub enum Event + where + ::AccountId + { /// All validators have been rewarded by the first balance; the second is the remainder /// from the maximum amount of reward. Reward(Balance, Balance), // TODO: refactor to Balance later? /// One validator (and its nominators) has been slashed by the given amount. - Slash(AccountId, ExtendedBalance), + Slash(AccountId, Power), /// An old slashing report from a prior era was discarded because it could /// not be processed. OldSlashingReportDiscarded(SessionIndex), @@ -503,6 +506,14 @@ decl_event!( /// NodeName changed. NodeNameUpdated, + /// Bond succeed. + /// `amount`, `now`, `duration` in month + Bond(Balance, Moment, Moment), + + /// Unbond succeed. + /// `amount`, `now` + Unbond(Balance, Moment), + // Develop // Print(u128), } @@ -544,9 +555,9 @@ decl_module! { fn bond( origin, controller: ::Source, - value: StakingBalance, KtonBalanceOf>, + value: StakingBalance, Kton>, payee: RewardDestination, - promise_month: u64 + promise_month: Moment ) { let stash = ensure_signed(origin)?; ensure!(!>::exists(&stash), err::STASH_ALREADY_BONDED); @@ -563,22 +574,32 @@ decl_module! { stash: stash.clone(), ..Default::default() }; + let bond_amount; + let now = >::now().saturated_into::(); + let promise_month = promise_month.min(36); + match value { StakingBalance::Ring(r) => { let stash_balance = T::Ring::free_balance(&stash); let value = r.min(stash_balance); - // increase ring pool - >::mutate(|r| *r += value); + bond_amount = value.saturated_into(); + Self::bond_helper_in_ring(&stash, &controller, value, promise_month, ledger); + + >::mutate(|r| *r += value); }, StakingBalance::Kton(k) => { let stash_balance = T::Kton::free_balance(&stash); - let value: KtonBalanceOf = k.min(stash_balance); - // increase kton pool - >::mutate(|k| *k += value); + let value = k.min(stash_balance); + bond_amount = value.saturated_into(); + Self::bond_helper_in_kton(&controller, value, ledger); + + >::mutate(|k| *k += value); }, } + + >::deposit_event(RawEvent::Bond(bond_amount, now, promise_month)); } /// Add some extra amount that have appeared in the stash `free_balance` into the balance up @@ -598,33 +619,74 @@ decl_module! { #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn bond_extra( origin, - value: StakingBalance, KtonBalanceOf>, - promise_month: u64 + value: StakingBalance, Kton>, + promise_month: Moment ) { let stash = ensure_signed(origin)?; let controller = Self::bonded(&stash).ok_or(err::STASH_INVALID)?; let ledger = Self::ledger(&controller).ok_or(err::CONTROLLER_INVALID)?; + let now = >::now().saturated_into::(); + let promise_month = promise_month.min(36); match value { StakingBalance::Ring(r) => { let stash_balance = T::Ring::free_balance(&stash); if let Some(extra) = stash_balance.checked_sub(&ledger.active_ring) { let extra = extra.min(r); - >::mutate(|r| *r += extra); + Self::bond_helper_in_ring(&stash, &controller, extra, promise_month, ledger); + + >::mutate(|r| *r += extra); + >::deposit_event(RawEvent::Bond(extra.saturated_into(), now, promise_month)); } }, StakingBalance::Kton(k) => { let stash_balance = T::Kton::free_balance(&stash); if let Some(extra) = stash_balance.checked_sub(&ledger.active_kton) { let extra = extra.min(k); - >::mutate(|k| *k += extra); + Self::bond_helper_in_kton(&controller, extra, ledger); + + >::mutate(|k| *k += extra); + >::deposit_event(RawEvent::Bond(extra.saturated_into(), now, promise_month)); } }, } } + // TODO: doc + fn deposit_extra(origin, value: Ring, promise_month: Moment) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or(err::CONTROLLER_INVALID)?; + let promise_month = promise_month.max(3).min(36); + + let now = >::now(); + let mut ledger = Self::clear_mature_deposits(ledger); + let StakingLedger { + stash, + active_ring, + active_deposit_ring, + deposit_items, + .. + } = &mut ledger; + let value = value.min(*active_ring - *active_deposit_ring); + // for now, kton_return is free + // mint kton + let kton_return = inflation::compute_kton_return::(value, promise_month); + let kton_positive_imbalance = T::Kton::deposit_creating(stash, kton_return); + + T::KtonReward::on_unbalanced(kton_positive_imbalance); + *active_deposit_ring += value; + deposit_items.push(TimeDepositItem { + value, + start_time: now, + expire_time: now + T::Moment::saturated_from((promise_month * MONTH_IN_MILLISECONDS).into()), + }); + + >::insert(&controller, ledger); + >::deposit_event(RawEvent::Bond(value.saturated_into(), now.saturated_into::(), promise_month)); + } + /// for normal_ring or normal_kton, follow the original substrate pattern /// for time_deposit_ring, transform it into normal_ring first /// modify time_deposit_items and time_deposit_ring amount @@ -645,11 +707,11 @@ decl_module! { /// - Independent of the arguments. Limited but potentially exploitable complexity. /// - Contains a limited number of reads. /// - Each call (requires the remainder of the bonded balance to be above `minimum_balance`) - /// will cause a new entry to be inserted into a vector (`StakingLock.unlockings`) kept in storage. + /// will cause a new entry to be inserted into a vector (`StakingLock.unbondings`) kept in storage. /// - One DB entry. /// #[weight = SimpleDispatchInfo::FixedNormal(400_000)] - fn unbond(origin, value: StakingBalance, KtonBalanceOf>) { + fn unbond(origin, value: StakingBalance, Kton>) { let controller = ensure_signed(origin)?; let mut ledger = Self::clear_mature_deposits(Self::ledger(&controller).ok_or(err::CONTROLLER_INVALID)?); let StakingLedger { @@ -690,8 +752,10 @@ decl_module! { until: now + T::BondingDuration::get(), }); - >::mutate(|r| *r -= available_unbond_ring); Self::update_ledger(&controller, &mut ledger, value); + + >::mutate(|r| *r -= available_unbond_ring); + >::deposit_event(RawEvent::Unbond(available_unbond_ring.saturated_into(), now.saturated_into::())); } }, StakingBalance::Kton(k) => { @@ -704,45 +768,15 @@ decl_module! { until: now + T::BondingDuration::get(), }); - >::mutate(|k| *k -= unbond_kton); Self::update_ledger(&controller, &mut ledger, value); + + >::mutate(|k| *k -= unbond_kton); + >::deposit_event(RawEvent::Unbond(unbond_kton.saturated_into(), now.saturated_into::())); } }, } } - // TODO: doc - fn deposit_extra(origin, value: RingBalanceOf, promise_month: u64) { - let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(err::CONTROLLER_INVALID)?; - let promise_month = promise_month.max(3).min(36); - - let now = >::now(); - let mut ledger = Self::clear_mature_deposits(ledger); - let StakingLedger { - stash, - active_ring, - active_deposit_ring, - deposit_items, - .. - } = &mut ledger; - let value = value.min(*active_ring - *active_deposit_ring); - // for now, kton_return is free - // mint kton - let kton_return = inflation::compute_kton_return::(value, promise_month); - let kton_positive_imbalance = T::Kton::deposit_creating(stash, kton_return); - - T::KtonReward::on_unbalanced(kton_positive_imbalance); - *active_deposit_ring += value; - deposit_items.push(TimeDepositItem { - value, - start_time: now, - expire_time: now + T::Moment::saturated_from((promise_month * MONTH_IN_MILLISECONDS).into()), - }); - - >::insert(&controller, ledger); - } - // TODO: doc fn claim_mature_deposits(origin) { let controller = ensure_signed(origin)?; @@ -1006,8 +1040,8 @@ impl Module { // TODO: doc pub fn clear_mature_deposits( - mut ledger: StakingLedger, KtonBalanceOf, T::Moment>, - ) -> StakingLedger, KtonBalanceOf, T::Moment> { + mut ledger: StakingLedger, Kton, T::Moment>, + ) -> StakingLedger, Kton, T::Moment> { let now = >::now(); let StakingLedger { active_deposit_ring, @@ -1031,12 +1065,10 @@ impl Module { fn bond_helper_in_ring( stash: &T::AccountId, controller: &T::AccountId, - value: RingBalanceOf, - promise_month: u64, - mut ledger: StakingLedger, KtonBalanceOf, T::Moment>, + value: Ring, + promise_month: Moment, + mut ledger: StakingLedger, Kton, T::Moment>, ) { - let promise_month = promise_month.min(36); - // if stash promise to a extra-lock // there will be extra reward, kton, which // can also be use to stake. @@ -1062,8 +1094,8 @@ impl Module { // TODO: doc fn bond_helper_in_kton( controller: &T::AccountId, - value: KtonBalanceOf, - mut ledger: StakingLedger, KtonBalanceOf, T::Moment>, + value: Kton, + mut ledger: StakingLedger, Kton, T::Moment>, ) { ledger.active_kton += value; @@ -1074,7 +1106,7 @@ impl Module { fn slash_individual( stash: &T::AccountId, slash_ratio: Perbill, - ) -> (RingNegativeImbalanceOf, KtonNegativeImbalanceOf, ExtendedBalance) { + ) -> (NegativeImbalanceRing, NegativeImbalanceKton, Power) { let controller = Self::bonded(stash).unwrap(); let mut ledger = Self::ledger(&controller).unwrap(); @@ -1083,29 +1115,29 @@ impl Module { let value_slashed = Self::slash_helper(&controller, &mut ledger, StakingBalance::Ring(slashable_ring)); T::Ring::slash(stash, value_slashed.0) } else { - (>::zero(), Zero::zero()) + (>::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)); T::Kton::slash(stash, value_slashed.1) } else { - (>::zero(), Zero::zero()) + (>::zero(), Zero::zero()) }; (ring_imbalance, kton_imbalance, 0) } // TODO: doc - fn power_of(stash: &T::AccountId) -> ExtendedBalance { + fn power_of(stash: &T::AccountId) -> Power { // power is a mixture of ring and kton // power = ring_ratio * POWER_COUNT / 2 + kton_ratio * POWER_COUNT / 2 - fn calc_power>(active: S, pool: S) -> ExtendedBalance { + fn calc_power>(active: S, pool: S) -> Power { const HALF_POWER_COUNT: u128 = 1_000_000_000 / 2; Perquintill::from_rational_approximation( - active.saturated_into::(), - pool.saturated_into::().max(1), + active.saturated_into::(), + pool.saturated_into::().max(1), ) * HALF_POWER_COUNT } @@ -1121,8 +1153,8 @@ impl Module { /// will lock the entire funds except paying for further transactions. fn update_ledger( controller: &T::AccountId, - ledger: &mut StakingLedger, KtonBalanceOf, T::Moment>, - staking_balance: StakingBalance, KtonBalanceOf>, + ledger: &mut StakingLedger, Kton, T::Moment>, + staking_balance: StakingBalance, Kton>, ) { match staking_balance { StakingBalance::Ring(_r) => { @@ -1159,10 +1191,10 @@ impl Module { /// pushes an entry onto the slash journal. fn slash_validator( stash: &T::AccountId, - slash: ExtendedBalance, - exposure: &Exposure, - journal: &mut Vec>, - ) -> (RingNegativeImbalanceOf, KtonNegativeImbalanceOf) { + slash: Power, + exposure: &Exposure, + journal: &mut Vec>, + ) -> (NegativeImbalanceRing, NegativeImbalanceKton) { // The amount we are actually going to slash (can't be bigger than the validator's total // exposure) let slash = slash.min(exposure.total); @@ -1177,7 +1209,7 @@ impl Module { .iter() .filter(|entry| &entry.who == stash) .map(|entry| entry.own_slash) - .fold(ExtendedBalance::zero(), |a, c| a.saturating_add(c)); + .fold(Power::zero(), |a, c| a.saturating_add(c)); let own_remaining = exposure.own.saturating_sub(already_slashed_own); @@ -1223,9 +1255,9 @@ impl Module { // TODO: doc fn slash_helper( controller: &T::AccountId, - ledger: &mut StakingLedger, KtonBalanceOf, T::Moment>, - value: StakingBalance, KtonBalanceOf>, - ) -> (RingBalanceOf, KtonBalanceOf) { + ledger: &mut StakingLedger, Kton, T::Moment>, + value: StakingBalance, Kton>, + ) -> (Ring, Kton) { match value { StakingBalance::Ring(r) => { let StakingLedger { @@ -1293,7 +1325,7 @@ impl Module { /// Actually make a payment to a staker. This uses the currency's reward function /// to pay the right payee for the given staker account. - fn make_payout(stash: &T::AccountId, amount: RingBalanceOf) -> Option> { + fn make_payout(stash: &T::AccountId, amount: Ring) -> Option> { let dest = Self::payee(stash); match dest { RewardDestination::Controller => { @@ -1306,10 +1338,10 @@ impl Module { /// 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 { + fn reward_validator(stash: &T::AccountId, reward: Ring) -> PositiveImbalanceRing { 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 mut imbalance = >::zero(); let validator_cut = if reward.is_zero() { Zero::zero() } else { @@ -1333,10 +1365,7 @@ impl Module { /// with the exposure of the prior validator set. fn new_session( session_index: SessionIndex, - ) -> Option<( - Vec, - Vec<(T::AccountId, Exposure)>, - )> { + ) -> Option<(Vec, Vec<(T::AccountId, Exposure)>)> { let era_length = session_index .checked_sub(Self::current_era_start_session_index()) .unwrap_or(0); @@ -1385,7 +1414,7 @@ impl Module { (T::Cap::get() - T::Ring::total_issuance()).saturated_into::(), ); - let mut total_imbalance = >::zero(); + let mut total_imbalance = >::zero(); for (v, p) in validators.iter().zip(points.individual.into_iter()) { if p != 0 { let reward = Perbill::from_rational_approximation(p, points.total) * total_payout; @@ -1397,7 +1426,7 @@ impl Module { let total_payout = total_imbalance.peek(); let rest = max_payout.saturating_sub(total_payout); - Self::deposit_event(RawEvent::Reward(total_payout, rest)); + Self::deposit_event(RawEvent::Reward(total_payout.saturated_into(), rest.saturated_into())); T::RingReward::on_unbalanced(total_imbalance); T::RingRewardRemainder::on_unbalanced(T::Ring::issue(rest)); @@ -1445,7 +1474,7 @@ impl Module { /// Select a new validator set from the assembled stakers and their role preferences. /// /// Returns the new `SlotStake` value. - fn select_validators() -> (ExtendedBalance, Option>) { + fn select_validators() -> (Power, Option>) { let mut all_nominators: Vec<(T::AccountId, Vec)> = Vec::new(); let all_validator_candidates_iter = >::enumerate(); let all_validators = all_validator_candidates_iter @@ -1473,11 +1502,8 @@ impl Module { .collect::>(); let assignments = phragmen_result.assignments; - let to_votes = |b: ExtendedBalance| { - >::convert(b) as ExtendedBalance - }; - let to_balance = - |e: ExtendedBalance| >::convert(e); + let to_votes = |b: Power| >::convert(b) as Power; + let to_balance = |e: Power| >::convert(e); let mut supports = build_support_map::<_, _, _, T::CurrencyToVote>(&elected_stashes, &assignments, Self::power_of); @@ -1520,7 +1546,7 @@ impl Module { } // Populate Stakers and figure out the minimum stake behind a slot. - let mut slot_stake = ExtendedBalance::max_value(); + let mut slot_stake = Power::max_value(); for (c, s) in supports.into_iter() { // build `struct exposure` from `support` let exposure = Exposure { @@ -1635,14 +1661,11 @@ impl session::OnSessionEnding for Module { } } -impl OnSessionEnding> for Module { +impl OnSessionEnding> for Module { fn on_session_ending( _ending: SessionIndex, start_session: SessionIndex, - ) -> Option<( - Vec, - Vec<(T::AccountId, Exposure)>, - )> { + ) -> Option<(Vec, Vec<(T::AccountId, Exposure)>)> { Self::new_session(start_session - 1) } } @@ -1678,8 +1701,8 @@ impl Convert> for StashOf { /// on that account. pub struct ExposureOf(rstd::marker::PhantomData); -impl Convert>> for ExposureOf { - fn convert(validator: T::AccountId) -> Option> { +impl Convert>> for ExposureOf { + fn convert(validator: T::AccountId) -> Option> { Some(>::stakers(&validator)) } } @@ -1695,7 +1718,7 @@ impl OnOffenceHandler::AccountId>, T: session::historical::Trait< - FullIdentification = Exposure<::AccountId, ExtendedBalance>, + FullIdentification = Exposure<::AccountId, Power>, FullIdentificationOf = ExposureOf, >, T::SessionHandler: session::SessionHandler<::AccountId>, @@ -1707,8 +1730,8 @@ where offenders: &[OffenceDetails>], slash_fraction: &[Perbill], ) { - let mut ring_remaining_imbalance = >::zero(); - let mut kton_remaining_imbalance = >::zero(); + let mut ring_remaining_imbalance = >::zero(); + let mut kton_remaining_imbalance = >::zero(); let slash_reward_fraction = SlashRewardFraction::get(); let era_now = Self::current_era(); diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 77fb98c3a..f575085a0 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -1,5 +1,6 @@ use std::{cell::RefCell, collections::HashSet}; +use phragmen::ExtendedBalance as Power; use sr_primitives::{ testing::{Header, UintAuthorityId}, traits::{BlakeTwo256, Convert, IdentityLookup, OnInitialize, OpaqueKeys}, @@ -15,7 +16,6 @@ use srml_support::{ use substrate_primitives::{crypto::key_types, H256}; use crate::*; -use phragmen::ExtendedBalance; /// The AccountId alias in this test module. pub type AccountId = u64; @@ -171,7 +171,7 @@ impl session::Trait for Test { } impl session::historical::Trait for Test { - type FullIdentification = crate::Exposure; + type FullIdentification = crate::Exposure; type FullIdentificationOf = crate::ExposureOf; } diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 70567f022..35bc07bde 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -2758,12 +2758,7 @@ fn slash_should_not_touch_unbondings() { }, ); // FIXME: slash strategy - let _ = Staking::slash_validator( - &stash, - ExtendedBalance::max_value(), - &Staking::stakers(&stash), - &mut vec![], - ); + let _ = Staking::slash_validator(&stash, Power::max_value(), &Staking::stakers(&stash), &mut vec![]); let ledger = Staking::ledger(controller).unwrap(); assert_eq!( ( @@ -2872,19 +2867,9 @@ fn pool_should_be_increased_and_decreased_correctly() { }, ); // FIXME: slash strategy - let _ = Staking::slash_validator( - &stash_1, - ExtendedBalance::max_value(), - &Staking::stakers(&stash_1), - &mut vec![], - ); + let _ = Staking::slash_validator(&stash_1, Power::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![], - ); + let _ = Staking::slash_validator(&stash_2, Power::max_value(), &Staking::stakers(&stash_2), &mut vec![]); ring_pool -= 375 * COIN / 10; kton_pool -= 50 * COIN; assert_eq!(Staking::ring_pool(), ring_pool); diff --git a/types/Cargo.lock b/types/Cargo.lock new file mode 100644 index 000000000..3f54406c3 --- /dev/null +++ b/types/Cargo.lock @@ -0,0 +1,58 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+/~https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+/~https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "1.3.1" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+/~https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+/~https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+/~https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+/~https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.12" +source = "registry+/~https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+/~https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "types" +version = "0.1.0" +dependencies = [ + "regex 1.3.1 (registry+/~https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.6 (registry+/~https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum lazy_static 1.4.0 (registry+/~https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum memchr 2.2.1 (registry+/~https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum regex 1.3.1 (registry+/~https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+/~https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum thread_local 0.3.6 (registry+/~https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" diff --git a/types/Cargo.toml b/types/Cargo.toml new file mode 100644 index 000000000..8432743f8 --- /dev/null +++ b/types/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "types" +version = "0.1.0" +authors = ["Xavier Lau "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "*" + +[workspace] \ No newline at end of file diff --git a/types/currency_types.json b/types/currency_types.json new file mode 100644 index 000000000..b5cd94bb2 --- /dev/null +++ b/types/currency_types.json @@ -0,0 +1,21 @@ +{ + "BalanceLock": { + "id": "LockIdentifier", + "withdraw_lock": "WithdrawLock", + "reasons": "WithdrawReasons" + }, + "NormalLock": { + "amount": "u128", + "until": "Moment" + }, + "StakingLock": { + "staking_amount": "u128", + "unbondings": "Vec" + }, + "WithdrawLock": { + "_enum": { + "Normal": "NormalLock", + "WithStaking": "StakingLock" + } + } +} \ No newline at end of file diff --git a/types/eth_relay_types.json b/types/eth_relay_types.json new file mode 100644 index 000000000..53efc5d76 --- /dev/null +++ b/types/eth_relay_types.json @@ -0,0 +1,60 @@ +{ + "ActionRecord": { + "index": "u64", + "proof": "Vec", + "header_hash": "H256" + }, + "Address": "H160", + "BestBlock": { + "height": "EthBlockNumber", + "hash": "H256", + "total_difficulty": "U256" + }, + "BlockDetails": { + "height": "EthBlockNumber", + "hash": "H256", + "total_difficulty": "U256" + }, + "Bloom": { + "_struct": "[u8; 256]" + }, + "EthBlockNumber": "u64", + "EthHeader": { + "parent_hash": "H256", + "timestamp": "u64", + "number": "EthBlockNumber", + "auth": "Address", + "transaction_root": "H256", + "uncles_hash": "H256", + "extra_data": "Bytes", + "state_root": "H256", + "receipts_root": "H256", + "log_bloom": "Bloom", + "gas_used": "U256", + "gas_limit": "U256", + "difficulty": "U256", + "seal": "Vec", + "hash": "Option" + }, + "H64": { + "_struct": "[u8; 8]" + }, + "LogEntry": { + "address": "Address", + "topics": "Vec", + "data": "Bytes" + }, + "Receipt": { + "gas_used": "U256", + "log_bloom": "Bloom", + "logs": "Vec", + "outcome": "TransactionOutcome" + }, + "TransactionOutcome": { + "_enum": { + "Unknown": null, + "StateRoot": "H256", + "StatusCode": "u8" + } + } +} \ No newline at end of file diff --git a/types/runtime_types.json b/types/runtime_types.json new file mode 100644 index 000000000..80a9fa093 --- /dev/null +++ b/types/runtime_types.json @@ -0,0 +1,4 @@ +{ + "EpochDuration": "u64", + "TimeStamp": "u64" +} \ No newline at end of file diff --git a/types/src/main.rs b/types/src/main.rs new file mode 100644 index 000000000..5b7f8a303 --- /dev/null +++ b/types/src/main.rs @@ -0,0 +1,117 @@ +use std::{ + env, + fs::{self, File}, + io::{self, Read}, + path::Path, +}; + +use regex::Regex; + +mod native_types { + const ARRAY: &[&str] = &["Bytes", "H160", "H256", "U128", "U256", "U512"]; + + const NUMERIC: &[&str] = &[ + "i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", "i128", "u128", "i268", "u256", + ]; + + const SUBSTRATE: &[&str] = &["Address", "LockIdentifier"]; + + const WRAPPER: &[&str] = &[r"Compact<.+?>", r"Option<.+?>", r"Vec<.+?>", r"[.+?;.+?]"]; +} + +fn main() -> io::Result<()> { + let srml_path = env::args() + .skip(1) + .next() + .ok_or(io::Error::new( + io::ErrorKind::NotFound, + "please specify the `srml` path", + ))? + .to_string(); + let srml_path = Path::new(&srml_path); + + if !srml_path.is_dir() { + return Ok(()); + } + + let modules = srml_path + .read_dir()? + .into_iter() + .filter_map(|entry| { + if let Ok(entry) = entry { + if entry.path().is_dir() { + return Some(Module::new(entry.path().to_str().unwrap())); + } + } + + None + }) + .collect::>(); + + println!("{:?}", modules); + + Ok(()) +} + +#[derive(Debug, Default)] +struct Module { + path: String, + storage: Storage, +} + +impl Module { + fn new>(path: S) -> Self { + Module { + path: path.as_ref().to_string(), + ..Default::default() + } + } + + fn read(&mut self) -> io::Result<()> { + self.storage = Path::new(&self.path) + .read_dir()? + .into_iter() + .filter_map(|entry| { + if let Ok(entry) = entry { + if let Some(path) = entry.path().to_str() { + if path.ends_with(".rs") { + return Storage::from_file(path).ok(); + } + } + } + + None + }) + .fold(Storage::default(), |acc, storage| acc.merge(storage)); + + Ok(()) + } +} + +#[derive(Debug, Default)] +struct Storage { + structs: Vec, +} + +impl Storage { + fn from_file>(path: S) -> io::Result { + let mut file = File::open(path)?; + let mut text = String::new(); + file.read_to_string(&mut text)?; + + Ok(Self { + structs: Storage::parse_structs(text), + }) + } + + fn merge(mut self, mut storage: Self) -> Self { + self.structs.append(&mut storage.structs); + self + } + + fn parse_structs(text: String) -> Vec { + let mut structs = vec![]; + + structs + } +} diff --git a/types/staking_types.json b/types/staking_types.json new file mode 100644 index 000000000..b00e81f26 --- /dev/null +++ b/types/staking_types.json @@ -0,0 +1,40 @@ +{ + "EraIndex": "u32", + "Exposure": { + "total": "ExtendedBalance", + "own": "ExtendedBalance", + "others": "Vec" + }, + "ExtendedBalance": "u128", + "IndividualExposure": { + "who": "AccountId", + "value": "ExtendedBalance" + }, + "KtonBalanceOf": "u128", + "RingBalanceOf": "u128", + "StakingBalance": { + "_enum": { + "Ring": "RingBalanceOf", + "Kton": "KtonBalanceOf" + } + }, + "StakingLedger": { + "stash": "AccountId", + "active_ring": "Compact", + "active_deposit_ring": "Compact", + "active_kton": "Compact", + "deposit_items": "Vec", + "ring_staking_lock": "StakingLock", + "kton_staking_lock": "StakingLock" + }, + "TimeDepositItem": { + "value": "Compact", + "start_time": "Compact", + "expire_time": "Compact" + }, + "ValidatorPrefs": { + "node_name": "Vec", + "unstake_threshold": "Compact", + "validator_payment_ratio": "Compact" + } +} \ No newline at end of file diff --git a/types.json b/types/types.json similarity index 76% rename from types.json rename to types/types.json index c3bd5c00c..01e4f9c27 100644 --- a/types.json +++ b/types/types.json @@ -6,11 +6,11 @@ "reasons": "WithdrawReasons" }, "NormalLock": { - "amount": "u128", + "amount": "Balance", "until": "Moment" }, "StakingLock": { - "staking_amount": "u128", + "staking_amount": "Balance", "unbondings": "Vec" }, "WithdrawLock": { @@ -21,7 +21,7 @@ }, "ActionRecord": { "index": "u64", - "proof": "Vec", + "proof": "Bytes", "header_hash": "H256" }, "BestBlock": { @@ -79,44 +79,44 @@ }, "EraIndex": "u32", "Exposure": { - "total": "Compact", - "own": "Compact", + "total": "Compact", + "own": "Compact", "others": "Vec" }, - "ExtendedBalance": "u128", "IndividualExposure": { "who": "AccountId", - "value": "Compact" + "value": "Compact" }, - "KtonBalanceOf": "u128", - "RingBalanceOf": "u128", + "Ring": "Balance", + "Power": "Balance", + "Kton": "Balance", "SlashJournalEntry": { "who": "AccountId", - "amount": "Compact", - "own_slash": "Compact" + "amount": "Compact", + "own_slash": "Compact" }, "StakingBalance": { "_enum": { - "Ring": "RingBalanceOf", - "Kton": "KtonBalanceOf" + "Ring": "Balance", + "Kton": "Balance" } }, "StakingLedger": { "stash": "AccountId", - "active_ring": "Compact", - "active_deposit_ring": "Compact", - "active_kton": "Compact", + "active_ring": "Compact", + "active_deposit_ring": "Compact", + "active_kton": "Compact", "deposit_items": "Vec", "ring_staking_lock": "StakingLock", "kton_staking_lock": "StakingLock" }, "TimeDepositItem": { - "value": "Compact", + "value": "Compact", "start_time": "Compact", "expire_time": "Compact" }, "ValidatorPrefs": { - "node_name": "Vec", + "node_name": "Bytes", "validator_payment_ratio": "Compact" } } \ No newline at end of file