Skip to content

Commit af6c435

Browse files
authored
Cache the treasury account when applying the slash. (paritytech#151)
1 parent d40999d commit af6c435

File tree

5 files changed

+70
-94
lines changed

5 files changed

+70
-94
lines changed

cli/src/chain_spec.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ fn testnet_genesis(
271271
minimum_validator_count: 4,
272272
sessions_per_era: 12,
273273
vesting_account: get_account_id_from_seed::<sr25519::Public>("vesting"),
274-
glob_dist_ratio: (12, 88),
275-
mining_ratio: (10, 90),
274+
glob_dist_ratio: (12, 88), // (Treasury, X-type Asset and Staking) = (12, 88)
275+
mining_ratio: (10, 90), // (Asset Mining, Staking) = (10, 90)
276276
..Default::default()
277277
}),
278278
xpallet_dex_spot: Some(XSpotConfig {

xpallets/mining/asset/src/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Error, Trait};
1+
use crate::Trait;
22
use chainx_primitives::AssetId;
33
use codec::{Decode, Encode};
44
use sp_runtime::RuntimeDebug;

xpallets/mining/staking/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ use xp_mining_staking::{AssetMining, SessionIndex, TreasuryAccount, UnbondedInde
2929
use xpallet_assets::{AssetErr, AssetType};
3030
use xpallet_support::debug;
3131

32-
use types::*;
33-
3432
pub use impls::{IdentificationTuple, SimpleValidatorRewardPotAccountDeterminer};
33+
pub use types::*;
3534

3635
/// Session reward of the first 210_000 sessions.
3736
const INITIAL_REWARD: u64 = 5_000_000_000;

xpallets/mining/staking/src/slashing.rs

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
use super::*;
22

33
impl<T: Trait> Module<T> {
4-
/// Actually slash the account being punished, all slashed balance will go to the treasury.
5-
fn apply_slash(reward_pot: &T::AccountId, value: T::Balance) {
6-
// FIXME: cache the treasury_account?
7-
let treasury_account = T::TreasuryAccount::treasury_account();
8-
let _ = <xpallet_assets::Module<T>>::pcx_move_free_balance(
9-
reward_pot,
10-
&treasury_account,
11-
value,
12-
);
13-
}
14-
154
/// Average reward for validator per block.
165
fn reward_per_block(staking_reward: T::Balance, validator_count: usize) -> u128 {
176
let session_length = T::SessionDuration::get();
@@ -21,21 +10,6 @@ impl<T: Trait> Module<T> {
2110
per_reward
2211
}
2312

24-
/// Returns Ok(_) if the reward pot of offender has enough balance to cover the slashing,
25-
/// otherwise slash the reward pot as much as possible and returns the value actually slashed.
26-
fn try_slash(offender: &T::AccountId, expected_slash: T::Balance) -> Result<(), T::Balance> {
27-
let reward_pot = Self::reward_pot_for(offender);
28-
let reward_pot_balance = <xpallet_assets::Module<T>>::pcx_free_balance(&reward_pot);
29-
30-
if expected_slash <= reward_pot_balance {
31-
Self::apply_slash(&reward_pot, expected_slash);
32-
Ok(())
33-
} else {
34-
Self::apply_slash(&reward_pot, reward_pot_balance);
35-
Err(reward_pot_balance)
36-
}
37-
}
38-
3913
/// TODO: flexiable slash according to slash fraction?
4014
fn expected_slash_of(reward_per_block: u128) -> T::Balance {
4115
let ideal_slash = reward_per_block * u128::from(Self::offence_severity());
@@ -49,11 +23,14 @@ impl<T: Trait> Module<T> {
4923
let validators = T::SessionInterface::validators();
5024
let valid_offenders = Self::offenders_in_session()
5125
.into_iter()
52-
.filter(|o| validators.contains(o))
26+
.filter(|offender| validators.contains(offender))
5327
.collect::<Vec<_>>();
5428

5529
let reward_per_block = Self::reward_per_block(staking_reward, validators.len());
5630

31+
let treasury_account = T::TreasuryAccount::treasury_account();
32+
let slasher = Slasher::<T>::new(treasury_account);
33+
5734
let minimum_validator_count = Self::minimum_validator_count() as usize;
5835

5936
let active_validators = Self::active_validator_set().collect::<Vec<_>>();
@@ -63,8 +40,8 @@ impl<T: Trait> Module<T> {
6340
.into_iter()
6441
.flat_map(|offender| {
6542
let expected_slash = Self::expected_slash_of(reward_per_block);
66-
match Self::try_slash(&offender, expected_slash) {
67-
Ok(_) => None,
43+
match slasher.try_slash(&offender, expected_slash) {
44+
Ok(_) => None, // Slash the offender successfully.
6845
Err(actual_slashed) => {
6946
debug!(
7047
"[slash_offenders_in_session]expected_slash:{:?}, actual_slashed:{:?}",
@@ -73,7 +50,7 @@ impl<T: Trait> Module<T> {
7350
if active_count > minimum_validator_count {
7451
Self::apply_force_chilled(&offender);
7552
active_count -= 1;
76-
Some(offender)
53+
Some(offender) // The offender does not have enough balance for the slashing.
7754
} else {
7855
None
7956
}

xpallets/mining/staking/src/types.rs

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use sp_runtime::RuntimeDebug;
55
#[cfg(feature = "std")]
66
use sp_runtime::{Deserialize, Serialize};
77
use xp_mining_common::WeightType;
8+
use xp_mining_staking::MiningPower;
89

910
/// Destination for minted fresh PCX on each new session.
1011
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
@@ -17,7 +18,7 @@ pub enum MintedDestination<AccountId> {
1718
///
1819
/// If the (potential) validator failed to meet this requirement, force it to be chilled on new election round.
1920
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
20-
pub struct BondRequirement<Balance: Default> {
21+
pub struct BondRequirement<Balance> {
2122
/// The minimal amount of self-bonded balance to be a qualified validator candidate.
2223
pub self_bonded: Balance,
2324
/// The minimal amount of total-bonded balance to be a qualified validator candidate.
@@ -30,7 +31,7 @@ pub struct BondRequirement<Balance: Default> {
3031
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
3132
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
3233
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
33-
pub struct Unbonded<Balance: Default, BlockNumber: Default> {
34+
pub struct Unbonded<Balance, BlockNumber> {
3435
/// Amount of funds to be unlocked.
3536
pub value: Balance,
3637
/// Block number at which point it'll be unlocked.
@@ -55,9 +56,9 @@ pub struct ValidatorLedger<Balance, BlockNumber> {
5556
pub struct NominatorLedger<Balance, BlockNumber> {
5657
/// The amount of
5758
pub nomination: Balance,
58-
///
59+
/// Last calculated total vote weight of current nominator.
5960
pub last_vote_weight: WeightType,
60-
///
61+
/// Block number at which point `last_vote_weight` just updated.
6162
pub last_vote_weight_update: BlockNumber,
6263
}
6364

@@ -67,10 +68,12 @@ pub struct NominatorLedger<Balance, BlockNumber> {
6768
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
6869
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
6970
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
70-
pub struct ValidatorProfile<BlockNumber: Default> {
71+
pub struct ValidatorProfile<BlockNumber> {
7172
/// Block number at which point it's registered on chain.
7273
pub registered_at: BlockNumber,
7374
/// Validator is chilled right now.
75+
///
76+
/// Declared no desire to be a validator or forced to be chilled due to `MinimumCandidateThreshold`.
7477
pub is_chilled: bool,
7578
/// Block number of last performed `chill` operation.
7679
pub last_chilled: Option<BlockNumber>,
@@ -80,46 +83,30 @@ pub struct ValidatorProfile<BlockNumber: Default> {
8083
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
8184
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
8285
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
83-
pub struct NominatorProfile<Balance: Default, BlockNumber: Default> {
86+
pub struct NominatorProfile<Balance, BlockNumber> {
8487
/// Block number of last `rebond` operation.
8588
pub last_rebond: Option<BlockNumber>,
86-
///
89+
/// Total unbonded entries.
8790
pub unbonded_chunks: Vec<Unbonded<Balance, BlockNumber>>,
8891
}
8992

90-
/// Status of (potential) validator in staking module.
91-
///
92-
/// For RPC usage.
93-
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
94-
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
95-
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
96-
pub enum ValidatorStatus {
97-
/// Declared no desire to be a validator or forced to be chilled due to `MinimumCandidateThreshold`.
98-
Chilled,
99-
/// Declared desire to be a validator but haven't won one place.
100-
Candidate,
101-
/// Being a validator, responsible for authoring the new blocks.
102-
Validating,
103-
}
104-
105-
impl Default for ValidatorStatus {
106-
fn default() -> Self {
107-
Self::Candidate
108-
}
109-
}
110-
11193
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
11294
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
11395
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
114-
pub struct ValidatorInfo<AccountId: Default, Balance: Default, BlockNumber: Default> {
96+
pub struct ValidatorInfo<AccountId, Balance, BlockNumber> {
97+
/// AccountId of this (potential) validator.
11598
pub account: AccountId,
11699
#[cfg_attr(feature = "std", serde(flatten))]
117100
pub profile: ValidatorProfile<BlockNumber>,
118101
#[cfg_attr(feature = "std", serde(flatten))]
119102
pub ledger: ValidatorLedger<Balance, BlockNumber>,
120-
pub status: ValidatorStatus,
103+
/// Being a validator, reponsible for authoring the new blocks.
104+
pub is_validating: bool,
105+
/// How much balances the validator has bonded itself.
121106
pub self_bonded: Balance,
107+
/// AccountId of the reward pot of this validator.
122108
pub reward_pot_account: AccountId,
109+
/// Balance of the reward pot account.
123110
pub reward_pot_balance: Balance,
124111
}
125112

@@ -155,54 +142,30 @@ impl Default for Forcing {
155142
}
156143
}
157144

158-
// Shares of various reward destinations.
159-
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
145+
// Top level shares of various reward destinations.
146+
#[derive(Copy, Clone, PartialEq, Eq, Default, Encode, Decode, RuntimeDebug)]
160147
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
161148
pub struct GlobalDistribution {
162149
pub treasury: u32,
163150
pub mining: u32,
164151
}
165152

166-
impl Default for GlobalDistribution {
167-
/// According to the ChainX 1.0 referendum proposal09:
168-
/// (Treasury, Airdrop Asset, X-type Asset and Staking) = (12, 8, 80)
169-
///
170-
/// Airdrop Assets have been retired in ChainX 2.0, now only treasury and mining destinations.
171-
/// (Treasury, X-type Asset and Staking) = (12, 88)
172-
fn default() -> Self {
173-
Self {
174-
treasury: 12u32,
175-
mining: 88u32,
176-
}
177-
}
178-
}
179-
180153
impl GlobalDistribution {
154+
/// Calculates the rewards for treasury and mining accordingly.
181155
pub fn calc_rewards<T: Trait>(&self, reward: T::Balance) -> (T::Balance, T::Balance) {
182156
let treasury_reward = reward * self.treasury.saturated_into()
183157
/ (self.treasury + self.mining).saturated_into();
184158
(treasury_reward, reward - treasury_reward)
185159
}
186160
}
187161

188-
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
162+
#[derive(Copy, Clone, PartialEq, Eq, Default, Encode, Decode, RuntimeDebug)]
189163
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
190164
pub struct MiningDistribution {
191165
pub asset: u32,
192166
pub staking: u32,
193167
}
194168

195-
impl Default for MiningDistribution {
196-
/// According to the ChainX 1.0 referendum proposal09,
197-
/// (Asset Mining, Staking) = (10, 90)
198-
fn default() -> Self {
199-
Self {
200-
asset: 10u32,
201-
staking: 90u32,
202-
}
203-
}
204-
}
205-
206169
impl MiningDistribution {
207170
/// Returns the reward for Staking given the total reward according to the Staking proportion.
208171
pub fn calc_staking_reward<T: Trait>(&self, reward: T::Balance) -> T::Balance {
@@ -216,7 +179,7 @@ impl MiningDistribution {
216179
/// the mining assets, but its unit mining power starts to decrease compared to the inital FixedPower.
217180
fn asset_mining_vs_staking<T: Trait>(&self) -> (u128, u128) {
218181
let total_staking_power =
219-
crate::Module::<T>::total_staked().saturated_into::<xp_mining_staking::MiningPower>();
182+
crate::Module::<T>::total_staked().saturated_into::<MiningPower>();
220183
let total_asset_mining_power = T::AssetMining::total_asset_mining_power();
221184

222185
// When:
@@ -257,3 +220,40 @@ impl MiningDistribution {
257220
}
258221
}
259222
}
223+
224+
/// Struct for performing the slash.
225+
///
226+
/// Abstracted for caching the treasury account.
227+
#[derive(Copy, Clone, PartialEq, Eq, Default, Encode, Decode, RuntimeDebug)]
228+
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
229+
pub struct Slasher<T: Trait>(T::AccountId);
230+
231+
impl<T: Trait> Slasher<T> {
232+
pub fn new(treasury_account: T::AccountId) -> Self {
233+
Self(treasury_account)
234+
}
235+
236+
/// Returns Ok(_) if the reward pot of offender has enough balance to cover the slashing,
237+
/// otherwise slash the reward pot as much as possible and returns the value actually slashed.
238+
pub fn try_slash(
239+
&self,
240+
offender: &T::AccountId,
241+
expected_slash: T::Balance,
242+
) -> Result<(), T::Balance> {
243+
let reward_pot = T::DetermineRewardPotAccount::reward_pot_account_for(offender);
244+
let reward_pot_balance = <xpallet_assets::Module<T>>::pcx_free_balance(&reward_pot);
245+
246+
if expected_slash <= reward_pot_balance {
247+
self.apply_slash(&reward_pot, expected_slash);
248+
Ok(())
249+
} else {
250+
self.apply_slash(&reward_pot, reward_pot_balance);
251+
Err(reward_pot_balance)
252+
}
253+
}
254+
255+
/// Actually slash the account being punished, all slashed balance will go to the treasury.
256+
fn apply_slash(&self, reward_pot: &T::AccountId, value: T::Balance) {
257+
let _ = <xpallet_assets::Module<T>>::pcx_move_free_balance(reward_pot, &self.0, value);
258+
}
259+
}

0 commit comments

Comments
 (0)