mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-24 07:45:49 +00:00
Era change can be forced on and forced off (#3374)
* Forcing can be on or off. * Add a testcase.
This commit is contained in:
@@ -141,6 +141,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
(x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)
|
(x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)
|
||||||
}).collect(),
|
}).collect(),
|
||||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
||||||
|
.. Default::default()
|
||||||
}),
|
}),
|
||||||
democracy: Some(DemocracyConfig::default()),
|
democracy: Some(DemocracyConfig::default()),
|
||||||
collective_Instance1: Some(CouncilConfig {
|
collective_Instance1: Some(CouncilConfig {
|
||||||
@@ -268,6 +269,7 @@ pub fn testnet_genesis(
|
|||||||
(x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)
|
(x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)
|
||||||
}).collect(),
|
}).collect(),
|
||||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
||||||
|
.. Default::default()
|
||||||
}),
|
}),
|
||||||
democracy: Some(DemocracyConfig::default()),
|
democracy: Some(DemocracyConfig::default()),
|
||||||
collective_Instance1: Some(CouncilConfig {
|
collective_Instance1: Some(CouncilConfig {
|
||||||
|
|||||||
@@ -378,6 +378,7 @@ mod tests {
|
|||||||
offline_slash: Perbill::zero(),
|
offline_slash: Perbill::zero(),
|
||||||
offline_slash_grace: 0,
|
offline_slash_grace: 0,
|
||||||
invulnerables: vec![alice(), bob(), charlie()],
|
invulnerables: vec![alice(), bob(), charlie()],
|
||||||
|
.. Default::default()
|
||||||
}),
|
}),
|
||||||
contracts: Some(ContractsConfig {
|
contracts: Some(ContractsConfig {
|
||||||
current_schedule: Default::default(),
|
current_schedule: Default::default(),
|
||||||
|
|||||||
@@ -80,8 +80,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
// and set impl_version to equal spec_version. If only runtime
|
// and set impl_version to equal spec_version. If only runtime
|
||||||
// implementation changes and behavior does not, then leave spec_version as
|
// implementation changes and behavior does not, then leave spec_version as
|
||||||
// is and increment impl_version.
|
// is and increment impl_version.
|
||||||
spec_version: 139,
|
spec_version: 140,
|
||||||
impl_version: 139,
|
impl_version: 140,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -555,6 +555,22 @@ pub trait Trait: system::Trait {
|
|||||||
type SessionInterface: self::SessionInterface<Self::AccountId>;
|
type SessionInterface: self::SessionInterface<Self::AccountId>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mode of era-forcing.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
|
||||||
|
pub enum Forcing {
|
||||||
|
/// Not forcing anything - just let whatever happen.
|
||||||
|
NotForcing,
|
||||||
|
/// Force a new era, then reset to `NotForcing` as soon as it is done.
|
||||||
|
ForceNew,
|
||||||
|
/// Avoid a new era indefinitely.
|
||||||
|
ForceNone,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Forcing {
|
||||||
|
fn default() -> Self { Forcing::NotForcing }
|
||||||
|
}
|
||||||
|
|
||||||
decl_storage! {
|
decl_storage! {
|
||||||
trait Store for Module<T: Trait> as Staking {
|
trait Store for Module<T: Trait> as Staking {
|
||||||
|
|
||||||
@@ -625,7 +641,7 @@ decl_storage! {
|
|||||||
pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>;
|
pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>;
|
||||||
|
|
||||||
/// True if the next session change will be a new era regardless of index.
|
/// True if the next session change will be a new era regardless of index.
|
||||||
pub ForceNewEra get(forcing_new_era): bool;
|
pub ForceEra get(force_era) config(): Forcing;
|
||||||
|
|
||||||
/// A mapping from still-bonded eras to the first session index of that era.
|
/// A mapping from still-bonded eras to the first session index of that era.
|
||||||
BondedEras: Vec<(EraIndex, SessionIndex)>;
|
BondedEras: Vec<(EraIndex, SessionIndex)>;
|
||||||
@@ -988,18 +1004,27 @@ decl_module! {
|
|||||||
|
|
||||||
// ----- Root calls.
|
// ----- Root calls.
|
||||||
|
|
||||||
/// Force there to be a new era. This also forces a new session immediately after.
|
/// Force there to be no new eras indefinitely.
|
||||||
/// `apply_rewards` should be true for validators to get the session reward.
|
|
||||||
///
|
///
|
||||||
/// # <weight>
|
/// # <weight>
|
||||||
/// - Independent of the arguments.
|
/// - No arguments.
|
||||||
/// - Triggers the Phragmen election. Expensive but not user-controlled.
|
/// # </weight>
|
||||||
/// - Depends on state: `O(|edges| * |validators|)`.
|
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
||||||
|
fn force_no_eras(origin) {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
ForceEra::put(Forcing::ForceNone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Force there to be a new era at the end of the next session. After this, it will be
|
||||||
|
/// reset to normal (non-forced) behaviour.
|
||||||
|
///
|
||||||
|
/// # <weight>
|
||||||
|
/// - No arguments.
|
||||||
/// # </weight>
|
/// # </weight>
|
||||||
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
||||||
fn force_new_era(origin) {
|
fn force_new_era(origin) {
|
||||||
ensure_root(origin)?;
|
ensure_root(origin)?;
|
||||||
Self::apply_force_new_era()
|
ForceEra::put(Forcing::ForceNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the offline slash grace period.
|
/// Set the offline slash grace period.
|
||||||
@@ -1129,16 +1154,17 @@ impl<T: Trait> Module<T> {
|
|||||||
fn new_session(session_index: SessionIndex)
|
fn new_session(session_index: SessionIndex)
|
||||||
-> Option<(Vec<T::AccountId>, Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>)>
|
-> Option<(Vec<T::AccountId>, Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>)>
|
||||||
{
|
{
|
||||||
if ForceNewEra::take() || session_index % T::SessionsPerEra::get() == 0 {
|
match ForceEra::get() {
|
||||||
let validators = T::SessionInterface::validators();
|
Forcing::ForceNew => ForceEra::kill(),
|
||||||
let prior = validators.into_iter()
|
Forcing::NotForcing if session_index % T::SessionsPerEra::get() == 0 => (),
|
||||||
.map(|v| { let e = Self::stakers(&v); (v, e) })
|
_ => return None,
|
||||||
.collect();
|
|
||||||
|
|
||||||
Self::new_era(session_index).map(move |new| (new, prior))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
let validators = T::SessionInterface::validators();
|
||||||
|
let prior = validators.into_iter()
|
||||||
|
.map(|v| { let e = Self::stakers(&v); (v, e) })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self::new_era(session_index).map(move |new| (new, prior))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The era has changed - enact new staking set.
|
/// The era has changed - enact new staking set.
|
||||||
@@ -1335,10 +1361,6 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_force_new_era() {
|
|
||||||
ForceNewEra::put(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove all associated data of a stash account from the staking system.
|
/// Remove all associated data of a stash account from the staking system.
|
||||||
///
|
///
|
||||||
/// This is called :
|
/// This is called :
|
||||||
|
|||||||
@@ -310,6 +310,7 @@ impl ExtBuilder {
|
|||||||
offline_slash: Perbill::from_percent(5),
|
offline_slash: Perbill::from_percent(5),
|
||||||
offline_slash_grace: 0,
|
offline_slash_grace: 0,
|
||||||
invulnerables: vec![],
|
invulnerables: vec![],
|
||||||
|
.. Default::default()
|
||||||
}.assimilate_storage(&mut storage);
|
}.assimilate_storage(&mut storage);
|
||||||
|
|
||||||
let _ = session::GenesisConfig::<Test> {
|
let _ = session::GenesisConfig::<Test> {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ fn no_offline_should_work() {
|
|||||||
assert_eq!(Staking::slash_count(&10), 0);
|
assert_eq!(Staking::slash_count(&10), 0);
|
||||||
assert_eq!(Balances::free_balance(&10), 1);
|
assert_eq!(Balances::free_balance(&10), 1);
|
||||||
// New era is not being forced
|
// New era is not being forced
|
||||||
assert!(!Staking::forcing_new_era());
|
assert_eq!(Staking::force_era(), Forcing::NotForcing);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ fn invulnerability_should_work() {
|
|||||||
assert!(<Validators<Test>>::exists(&11));
|
assert!(<Validators<Test>>::exists(&11));
|
||||||
// New era not being forced
|
// New era not being forced
|
||||||
// NOTE: new era is always forced once slashing happens -> new validators need to be chosen.
|
// NOTE: new era is always forced once slashing happens -> new validators need to be chosen.
|
||||||
assert!(!Staking::forcing_new_era());
|
assert_eq!(Staking::force_era(), Forcing::NotForcing);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -884,6 +884,43 @@ fn session_and_eras_work() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn forcing_new_era_works() {
|
||||||
|
with_externalities(&mut ExtBuilder::default().build(),|| {
|
||||||
|
// normal flow of session.
|
||||||
|
assert_eq!(Staking::current_era(), 0);
|
||||||
|
start_session(0);
|
||||||
|
assert_eq!(Staking::current_era(), 0);
|
||||||
|
start_session(1);
|
||||||
|
assert_eq!(Staking::current_era(), 0);
|
||||||
|
start_session(2);
|
||||||
|
assert_eq!(Staking::current_era(), 1);
|
||||||
|
|
||||||
|
// no era change.
|
||||||
|
ForceEra::put(Forcing::ForceNone);
|
||||||
|
start_session(3);
|
||||||
|
assert_eq!(Staking::current_era(), 1);
|
||||||
|
start_session(4);
|
||||||
|
assert_eq!(Staking::current_era(), 1);
|
||||||
|
start_session(5);
|
||||||
|
assert_eq!(Staking::current_era(), 1);
|
||||||
|
start_session(6);
|
||||||
|
assert_eq!(Staking::current_era(), 1);
|
||||||
|
|
||||||
|
// back to normal
|
||||||
|
ForceEra::put(Forcing::NotForcing);
|
||||||
|
start_session(7);
|
||||||
|
assert_eq!(Staking::current_era(), 1);
|
||||||
|
start_session(8);
|
||||||
|
assert_eq!(Staking::current_era(), 2);
|
||||||
|
|
||||||
|
// forceful change
|
||||||
|
ForceEra::put(Forcing::ForceNew);
|
||||||
|
start_session(9);
|
||||||
|
assert_eq!(Staking::current_era(), 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cannot_transfer_staked_balance() {
|
fn cannot_transfer_staked_balance() {
|
||||||
// Tests that a stash account cannot transfer funds
|
// Tests that a stash account cannot transfer funds
|
||||||
|
|||||||
Reference in New Issue
Block a user