Skip to content

Commit

Permalink
0.9.5 fixes (paritytech#366)
Browse files Browse the repository at this point in the history
* Ensure minimal validator count

Fixes paritytech#362

* Remove needless retain

* Slash validators on new session insteead of every block

Closes paritytech#369

* Trigger OnAssetChanged

Fixes paritytech#363

* Update acceleration of setup_trustee to 1000

- Closes paritytech#371

* Slash maximum between 1% of jackpot and minimum penalty

Closes paritytech#374

* Update wasm

* 1% instead of 1/10!!!
  • Loading branch information
liuchengxu authored Mar 4, 2019
1 parent 809dfbe commit 46a4810
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 49 deletions.
Binary file modified cli/src/chainx_runtime_wasm.compact.wasm
Binary file not shown.
9 changes: 1 addition & 8 deletions cli/src/genesis_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,15 +222,8 @@ pub fn testnet_genesis(genesis_spec: GenesisSpec) -> GenesisConfig {
bonding_duration: bonding_duration,
intention_bonding_duration: intention_bonding_duration,
current_era: 0,
penalty: 50 * 100_000_000 / 150, // 1 per block reward
minimum_penalty: 10_000_000, // 0.1 PCX by default
validator_stake_threshold: 1,
// council_address: funding,
// team_address: Public::from_ss58check(
// "5CSff76SK7qcWYq5MpvoHDVRrjWFwpxurwUu6Bqw25hKPQiy",
// )
// .unwrap()
// .0
// .into(),
}),
xtokens: Some(XTokensConfig {
token_discount: 50,
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl CheckFee for Call {
XStakingCall::unnominate(_, _, _) => Some(3),
XStakingCall::unfreeze(_, _) => Some(2),
XStakingCall::claim(_) => Some(3),
XStakingCall::setup_trustee(_, _, _, _) => Some(5),
XStakingCall::setup_trustee(_, _, _, _) => Some(1000),
_ => None,
},
Call::XTokens(call) => match call {
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl fee_manager::Trait for Runtime {
// assets
impl xassets::Trait for Runtime {
type Event = Event;
type OnAssetChanged = ();
type OnAssetChanged = (XTokens);
type OnAssetRegisterOrRevoke = (XTokens, XSpot);
}

Expand Down
Binary file not shown.
12 changes: 8 additions & 4 deletions xrml/xmining/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ decl_module! {
}

/// Set the offline slash grace period.
fn set_penalty(new: T::Balance) {
<Penalty<T>>::put(new);
fn set_minimum_penalty(new: T::Balance) {
<MinimumPenalty<T>>::put(new);
}

}
Expand Down Expand Up @@ -369,8 +369,12 @@ decl_storage! {

pub TeamAddress get(team_address): T::AccountId;
pub CouncilAddress get(council_address): T::AccountId;
pub Penalty get(penalty) config(): T::Balance;
pub PunishList get(punish_list): Vec<T::AccountId>;
/// Minimum penalty for each slash.
pub MinimumPenalty get(minimum_penalty) config(): T::Balance;
/// The validators should be slashed per session.
pub SlashedPerSession get(slashed): Vec<T::AccountId>;
/// The accumulative fine that each slashed validator should pay per session.
pub TotalSlashOfPerSession get(total_slash_of_per_session): map T::AccountId => T::Balance;
}
}

Expand Down
110 changes: 75 additions & 35 deletions xrml/xmining/staking/src/shifter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! Coordidate session and era rotation.

use super::*;
use rstd::cmp;
use runtime_primitives::traits::{As, One, Zero};
use session::OnSessionChange;
use xaccounts::IntentionJackpotAccountIdFor;
Expand Down Expand Up @@ -82,55 +83,87 @@ impl<T: Trait> Module<T> {
let _ = <xassets::Module<T>>::pcx_issue(&jackpot_addr, to_jackpot);
}

/// Slash a given (potential) validator by a specific amount.
fn slash_validator(who: &T::AccountId, slash: T::Balance) {
/// Actually slash a given (potential) validator by a specific amount.
/// If the jackpot of the validator can't afford the penalty, then he
/// should be enforced to be inactive.
fn slash_validator(who: &T::AccountId) -> bool {
let jackpot_addr = T::DetermineIntentionJackpotAccountId::accountid_for(who);
let fund_id = Self::council_address();
let council = Self::council_address();

if slash <= <xassets::Module<T>>::pcx_free_balance(&jackpot_addr) {
let _ = <xassets::Module<T>>::pcx_move_free_balance(&jackpot_addr, &fund_id, slash);
let total_slash = <TotalSlashOfPerSession<T>>::take(who);
let jackpot_balance = <xassets::Module<T>>::pcx_free_balance(&jackpot_addr);

let (slashed, should_be_enforced) = if total_slash <= jackpot_balance {
(total_slash, false)
} else {
// Put the slashed validator into the punished list when its jackpot is not enough to be slashed.
// These on the punish list will be enforced inactive on new session when possible.
if !<PunishList<T>>::get().into_iter().any(|x| x == *who) {
<PunishList<T>>::mutate(|i| i.push(who.clone()));
}
(jackpot_balance, true)
};

let _ = <xassets::Module<T>>::pcx_move_free_balance(&jackpot_addr, &council, slashed);
Self::deposit_event(RawEvent::OfflineSlash(who.clone(), slashed));

should_be_enforced
}

fn note_offline_slashed(who: &T::AccountId, slash: T::Balance) {
if !<SlashedPerSession<T>>::get().into_iter().any(|x| x == *who) {
<SlashedPerSession<T>>::mutate(|i| i.push(who.clone()));
}
let total_slash = Self::total_slash_of_per_session(who);
<TotalSlashOfPerSession<T>>::insert(who, total_slash + slash);
}

/// Enforce these punished to be inactive, so that they won't become validators and be rewarded.
fn enforce_inactive(is_new_era: bool) {
let punished = <PunishList<T>>::take();
let slashed = <SlashedPerSession<T>>::take();

if punished.is_empty() {
if slashed.is_empty() {
return;
}

if Self::gather_candidates().len() <= Self::minimum_validator_count() as usize {
for s in slashed {
<TotalSlashOfPerSession<T>>::remove(s);
}
return;
}

for v in punished.iter() {
// Force those punished to be inactive
<xaccounts::IntentionPropertiesOf<T>>::mutate(v, |props| {
props.is_active = false;
info!("validator enforced to be inactive: {:?}", v);
});
let mut validators = <session::Module<T>>::validators()
.into_iter()
.map(|(v, _)| v)
.collect::<Vec<_>>();

for v in slashed.iter() {
let should_be_enforced = Self::slash_validator(v);

if should_be_enforced {
// Force those slashed yet can't afford the penalty to be inactive
<xaccounts::IntentionPropertiesOf<T>>::mutate(v, |props| {
props.is_active = false;
info!("validator enforced to be inactive: {:?}", v);
});

if validators.len() > Self::minimum_validator_count() as usize {
validators.retain(|x| *x != *v);
}
}
}

// The validator set will be set on new era, so we don't have to update here.
if !is_new_era {
let mut validators = <session::Module<T>>::validators();
validators.retain(|(v, _)| !punished.contains(&v));
let validators = validators
.into_iter()
.map(|(v, _)| (Self::intention_profiles(&v).total_nomination.as_(), v))
.map(|(a, b)| (b, a))
.collect::<Vec<_>>();
<session::Module<T>>::set_validators(validators.as_slice());
Self::deposit_event(RawEvent::EnforceValidatorsInactive(slashed.clone()));

// The validator set will be updated on new era, so we don't have to update here.
if is_new_era {
return;
}

Self::deposit_event(RawEvent::EnforceValidatorsInactive(punished));
// Update to the latest total nomination
let validators = validators
.into_iter()
.map(|v| (Self::intention_profiles(&v).total_nomination.as_(), v))
.map(|(a, b)| (b, a))
.collect::<Vec<_>>();
info!("new validators due to enforce inactive: {:?}", validators);
<session::Module<T>>::set_validators(validators.as_slice());
}

/// Session has just changed. We need to determine whether we pay a reward, slash and/or
Expand All @@ -140,6 +173,7 @@ impl<T: Trait> Module<T> {
let is_new_era = <ForcingNewEra<T>>::take().is_some()
|| ((session_index - Self::last_era_length_change()) % Self::sessions_per_era())
.is_zero();

Self::enforce_inactive(is_new_era);

if should_reward {
Expand Down Expand Up @@ -249,12 +283,6 @@ impl<T: Trait> Module<T> {
Self::deposit_event(RawEvent::Rotation(validators));
}

pub fn on_offline_validator(v: &T::AccountId) {
let slash = Self::penalty();
Self::slash_validator(v, slash);
Self::deposit_event(RawEvent::OfflineSlash(v.clone(), slash));
}

fn new_trustees() {
let candidates = Self::gather_candidates()
.into_iter()
Expand All @@ -280,6 +308,18 @@ impl<T: Trait> Module<T> {

Self::deposit_event(RawEvent::NewTrustees(trustees));
}

fn jackpot_balance_of(who: &T::AccountId) -> T::Balance {
let jackpot_addr = T::DetermineIntentionJackpotAccountId::accountid_for(who);
<xassets::Module<T>>::pcx_free_balance(&jackpot_addr)
}

pub fn on_offline_validator(v: &T::AccountId) {
let jackpot_balance = Self::jackpot_balance_of(v);
let penalty = cmp::max(jackpot_balance.as_() / 100, Self::minimum_penalty().as_());

Self::note_offline_slashed(v, T::Balance::sa(penalty));
}
}

impl<T: Trait> OnSessionChange<T::Moment> for Module<T> {
Expand Down

0 comments on commit 46a4810

Please sign in to comment.