Skip to content
tests.rs 69.4 KiB
Newer Older
		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.
		assert_eq!(Staking::stakers(&11).total, 1250);

		Staking::on_offence(
			&[OffenceDetails {
				offender: (
					11,
					Staking::stakers(&11),
				),
				reporters: vec![1, 2],
			}],
			&[Perbill::from_percent(50)],
		);

		// 1250 x 50% (slash fraction) x 10% (rewards slice)
		assert_eq!(Balances::free_balance(&1), 10 + 31);
		assert_eq!(Balances::free_balance(&2), 20 + 31);
	});
}

#[test]
fn invulnerables_are_not_slashed() {
	// For invulnerable validators no slashing is performed.
	with_externalities(
		&mut ExtBuilder::default().invulnerables(vec![11]).build(),
		|| {
			assert_eq!(Balances::free_balance(&11), 1000);
			assert_eq!(Balances::free_balance(&21), 2000);
			assert_eq!(Staking::stakers(&21).total, 1250);

			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);
			assert_eq!(Balances::free_balance(&21), 1750); // 2000 - (0.2 * 1250)
		},
	);
}

#[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);
	});
}