Repository: paritytech/substrate
File: frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs (Rust)

Code before:
					}
				],
			);

			// after the nominator is slashed and chilled, the nominations remain.
			assert_eq!(Nominators::<Runtime>::get(21).unwrap().targets, vec![81]);

			// validator sets intention to stake again in the same era it was chilled.
			assert_ok!(Staking::validate(RuntimeOrigin::signed(81), Default::default()));

			// progress era and check that the slashed validator is still part of the validator
			// set.
			assert!(start_next_active_era().is_ok());
			assert_eq!(active_era(), 1);
			assert!(Session::validators().contains(&81));
			assert!(<Runtime as pallet_staking::Config>::VoterList::contains(&81));

			// nominations are still active as before the slash.
			assert_eq!(Nominators::<Runtime>::get(21).unwrap().targets, vec![81]);
		})
}

#[test]
/// Active ledger balance may fall below ED if account chills before unbounding.
///
/// Unbonding call fails if the remaining ledger's stash balance falls below the existencial
/// deposit. However, if the stash is chilled before unbonding, the ledger's active balance may
/// be below ED. In that case, only the stash (or root) can kill the ledger entry by calling
/// `withdraw_unbonded` after the bonding period has passed.
///
/// Related to <https://github.com/paritytech/substrate/issues/14246>.
fn ledger_consistency_active_balance_below_ed() {
	use pallet_staking::Error;

	ExtBuilder::default()
		.staking(StakingExtBuilder::default())
		.build_and_execute(|| {
			assert_eq!(Staking::ledger(&11).unwrap().active, 1000);

			// unbonding total of active stake fails because the active ledger balance would fall
			// below the `MinNominatorBond`.
			assert_err!(
				Staking::unbond(RuntimeOrigin::signed(11), 1000),
				Error::<Runtime>::InsufficientBond
			);
			assert_eq!(Staking::ledger(&11).unwrap().active, 1000);

			// however, chilling works as expected.
			assert_ok!(Staking::chill(RuntimeOrigin::signed(11)));

			// now unbonding the full active balance works, since remainer of the active balance is

Review comment (bug):
```suggestion
/// Unbonding call fails if the remaining ledger's stash balance falls below the existential
```

Code after:
/// When validators are slashed, they are chilled and removed from the current `VoterList`. Thus,
/// the slashed validator should not be considered in the next validator set. However, if the
/// slashed validator sets its intention to validate again in the same era when it was slashed and
/// chilled, the validator may not be removed from the active validator set across eras, provided
/// it would selected in the subsequent era if there was no slash. Nominators of the slashed
/// validator will also be slashed and chilled, as expected, but the nomination intentions will
/// remain after the validator re-set the intention to be validating again.
///
/// This behaviour is due to removing implicit chill upon slash
/// <https://github.com/paritytech/substrate/pull/12420>.
///
/// Related to <https://github.com/paritytech/substrate/issues/13714>.
fn set_validation_intention_after_chilled() {
	use frame_election_provider_support::SortedListProvider;
	use pallet_staking::{Event, Forcing, Nominators};

	let (mut ext, pool_state, _) = ExtBuilder::default()
		.epm(EpmExtBuilder::default())
		.staking(StakingExtBuilder::default())
		.build_offchainify();

	ext.execute_with(|| {
		assert_eq!(active_era(), 0);
		// validator is part of the validator set.
		assert!(Session::validators().contains(&41));
		assert!(<Runtime as pallet_staking::Config>::VoterList::contains(&41));

		// nominate validator 81.
		assert_ok!(Staking::nominate(RuntimeOrigin::signed(21), vec![41]));
		assert_eq!(Nominators::<Runtime>::get(21).unwrap().targets, vec![41]);

		// validator is slashed. it is removed from the `VoterList` through chilling but in the
		// current era, the validator is still part of the active validator set.
		add_slash(&41);
		assert!(Session::validators().contains(&41));
		assert!(!<Runtime as pallet_staking::Config>::VoterList::contains(&41));
		assert_eq!(
			staking_events(),
			[
				Event::Chilled { stash: 41 },
				Event::ForceEra { mode: Forcing::ForceNew },
				Event::SlashReported {
					validator: 41,
					slash_era: 0,
					fraction: Perbill::from_percent(10)
				}
			],
		);

		// after the nominator is slashed and chilled, the nominations remain.
		assert_eq!(Nominators::<Runtime>::get(21).unwrap().targets, vec![41]);