Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
assert_eq!(Staking::current_era(), 3);
assert_eq!(Staking::current_era_start_session_index(), session + 1);
start_era(4);
assert_eq!(Staking::current_era_start_session_index(), session + SessionsPerEra::get() + 1);
});
}
#[test]
fn offence_forces_new_era() {
with_externalities(&mut ExtBuilder::default().build(), || {
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![],
}],
&[Perbill::from_percent(5)],
);
assert_eq!(Staking::force_era(), Forcing::ForceNew);
});
}
#[test]
fn slashing_performed_according_exposure() {
// This test checks that slashing is performed according the exposure (or more precisely,
// historical exposure), not the current balance.
with_externalities(&mut ExtBuilder::default().build(), || {
assert_eq!(Staking::stakers(&11).own, 1000);
// Handle an offence with a historical exposure.
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Exposure {
total: 500,
own: 500,
others: vec![],
},
),
reporters: vec![],
}],
&[Perbill::from_percent(50)],
);
// The stash account should be slashed for 250 (50% of 500).
assert_eq!(Balances::free_balance(&11), 1000 - 250);
});
}
#[test]
fn reporters_receive_their_slice() {
// This test verifies that the reporters of the offence receive their slice from the slashed
// amount.
with_externalities(&mut ExtBuilder::default().build(), || {
// The reporters' reward is calculated from the total exposure.
#[cfg(feature = "equalize")]
let initial_balance = 1250;
#[cfg(not(feature = "equalize"))]
let initial_balance = 1125;
assert_eq!(Staking::stakers(&11).total, initial_balance);
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![1, 2],
}],
&[Perbill::from_percent(50)],
);
// initial_balance x 50% (slash fraction) x 10% (rewards slice)
let reward = initial_balance / 20 / 2;
assert_eq!(Balances::free_balance(&1), 10 + reward);
assert_eq!(Balances::free_balance(&2), 20 + reward);
});
}
#[test]
fn invulnerables_are_not_slashed() {
// For invulnerable validators no slashing is performed.
with_externalities(
&mut ExtBuilder::default().invulnerables(vec![11]).build(),
|| {
#[cfg(feature = "equalize")]
let initial_balance = 1250;
#[cfg(not(feature = "equalize"))]
let initial_balance = 1375;
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&21), 2000);
assert_eq!(Staking::stakers(&21).total, initial_balance);
Staking::on_offence(
&[
OffenceDetails {
offender: (11, Staking::stakers(&11)),
reporters: vec![],
},
OffenceDetails {
offender: (21, Staking::stakers(&21)),
reporters: vec![],
},
],
&[Perbill::from_percent(50), Perbill::from_percent(20)],
);
// The validator 11 hasn't been slashed, but 21 has been.
assert_eq!(Balances::free_balance(&11), 1000);
// 2000 - (0.2 * initial_balance)
assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10));
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
},
);
}
#[test]
fn dont_slash_if_fraction_is_zero() {
// Don't slash if the fraction is zero.
with_externalities(&mut ExtBuilder::default().build(), || {
assert_eq!(Balances::free_balance(&11), 1000);
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![],
}],
&[Perbill::from_percent(0)],
);
// The validator hasn't been slashed. The new era is not forced.
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Staking::force_era(), Forcing::NotForcing);
});
}