diff --git a/substrate/core/test-runtime/wasm/Cargo.lock b/substrate/core/test-runtime/wasm/Cargo.lock index 8791d2c1ff..8721c4d21b 100644 --- a/substrate/core/test-runtime/wasm/Cargo.lock +++ b/substrate/core/test-runtime/wasm/Cargo.lock @@ -1112,8 +1112,10 @@ version = "0.1.0" dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-primitives 0.1.0", diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 440d0288d7..e7d060ff3b 100644 Binary files a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/node/cli/src/chain_spec.rs b/substrate/node/cli/src/chain_spec.rs index 345b98418e..26e86f596b 100644 --- a/substrate/node/cli/src/chain_spec.rs +++ b/substrate/node/cli/src/chain_spec.rs @@ -86,6 +86,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { bonding_duration: 60 * MINUTES, offline_slash_grace: 4, minimum_validator_count: 4, + invulnerables: initial_authorities.iter().cloned().map(Into::into).collect(), }), democracy: Some(DemocracyConfig { launch_period: 10 * MINUTES, // 1 day per public referendum @@ -211,6 +212,7 @@ pub fn testnet_genesis( current_offline_slash: 0, current_session_reward: 0, offline_slash_grace: 0, + invulnerables: initial_authorities.iter().cloned().map(Into::into).collect(), }), democracy: Some(DemocracyConfig { launch_period: 9, diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index 1c711f90c1..8ab8a6ceab 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -252,6 +252,7 @@ mod tests { current_offline_slash: 0, current_session_reward: 0, offline_slash_grace: 0, + invulnerables: vec![alice(), bob(), Charlie.to_raw_public().into()], }), democracy: Some(Default::default()), council_seats: Some(Default::default()), @@ -312,9 +313,9 @@ mod tests { 1, GENESIS_HASH.into(), if support_changes_trie { - hex!("bc4bdc45ba03402f9b4c7ec09834065c57205b1742bf2469ab9fc54544d8d002").into() + hex!("0bc6c118c326c65da9d0f93199f471aab4f636cfe87ab9a56c823024ca83995a").into() } else { - hex!("6bfbf71fa08d99f2488e295807059269cbc43ea21af3316a92406974593a1fc2").into() + hex!("58e1f1493e311d9b1fef3660426ee289736c38eb6f7d98911551c51765163056").into() }, if support_changes_trie { vec![changes_trie_log( @@ -340,7 +341,7 @@ mod tests { construct_block( 2, block1(false).1, - hex!("24f8ac99a6d98e9b53f4f6ef6ffdd12ba53ea3f247200a8126fa69c4b5047fbc").into(), + hex!("ced5607b16774cdbf750f8f7f0a99cd4afd7eb14db376a44bb8656f2ce02b18e").into(), vec![ // session changes here, so we add a grandpa change signal log. Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![ (Keyring::One.to_raw_public().into(), 1), @@ -369,7 +370,7 @@ mod tests { construct_block( 1, GENESIS_HASH.into(), - hex!("7b7d3b509a444cdf214825d3354507823a4c91eafa493f0956448881a81ab797").into(), + hex!("8a506a6f72c7efb75fd069a8c4f57c8e0b6b5adbea9646522bda64d4c78f5412").into(), vec![], vec![ CheckedExtrinsic { @@ -659,7 +660,7 @@ mod tests { let b = construct_block( 1, GENESIS_HASH.into(), - hex!("bfc8051f91071149cca8b8dca6290fdb82eda6868d48cfed25f8ca38ed3a1049").into(), + hex!("ce21753c3f806443c2758c982850861708054b65097fed82689e7b16cd5d6e24").into(), vec![], vec![ CheckedExtrinsic { diff --git a/substrate/node/runtime/wasm/Cargo.lock b/substrate/node/runtime/wasm/Cargo.lock index 0a44e0b021..ab578ac885 100644 --- a/substrate/node/runtime/wasm/Cargo.lock +++ b/substrate/node/runtime/wasm/Cargo.lock @@ -1472,8 +1472,10 @@ version = "0.1.0" dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-primitives 0.1.0", diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index fcb764ca1f..b7c15d3bfc 100644 Binary files a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs index c5ae4982f3..527c916008 100644 --- a/substrate/srml/staking/src/lib.rs +++ b/substrate/srml/staking/src/lib.rs @@ -224,6 +224,11 @@ decl_module! { let new: u32 = new.into(); >::put(new); } + + /// Set the validators who cannot be slashed (if any). + fn set_invulnerables(validators: Vec) { + >::put(validators); + } } } @@ -260,6 +265,10 @@ decl_storage! { /// The length of the bonding duration in blocks. pub BondingDuration get(bonding_duration) config(): T::BlockNumber = T::BlockNumber::sa(1000); + /// Any validators that may never be slashed or forcible kicked. It's a Vec since they're easy to initialise + /// and the performance hit is minimal (we expect no more than four invulnerables) and restricted to testnets. + pub Invulerables get(invulnerables) config(): Vec; + /// The current era index. pub CurrentEra get(current_era) config(): T::BlockNumber; /// Preferences that a validator has. @@ -501,6 +510,11 @@ impl Module { pub fn on_offline_validator(v: T::AccountId, count: usize) { use primitives::traits::CheckedShl; + // Early exit if validator is invulnerable. + if Self::invulnerables().contains(&v) { + return + } + for _ in 0..count { let slash_count = Self::slash_count(&v); >::insert(v.clone(), slash_count + 1); diff --git a/substrate/srml/staking/src/mock.rs b/substrate/srml/staking/src/mock.rs index a434b4510b..cf5976f88a 100644 --- a/substrate/srml/staking/src/mock.rs +++ b/substrate/srml/staking/src/mock.rs @@ -123,6 +123,7 @@ pub fn new_test_ext( current_session_reward: reward, current_offline_slash: 20, offline_slash_grace: 0, + invulnerables: vec![], }.build_storage().unwrap().0); t.extend(timestamp::GenesisConfig::{ period: 5, diff --git a/substrate/srml/staking/src/tests.rs b/substrate/srml/staking/src/tests.rs index 88ce66c8d7..801c15d3e1 100644 --- a/substrate/srml/staking/src/tests.rs +++ b/substrate/srml/staking/src/tests.rs @@ -35,6 +35,22 @@ fn note_null_offline_should_work() { }); } +#[test] +fn invulnerability_should_work() { + with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { + Staking::set_invulnerables(vec![10]); + Balances::set_free_balance(&10, 70); + assert_eq!(Staking::offline_slash_grace(), 0); + assert_eq!(Staking::slash_count(&10), 0); + assert_eq!(Balances::free_balance(&10), 70); + System::set_extrinsic_index(1); + Staking::on_offline_validator(10, 1); + assert_eq!(Staking::slash_count(&10), 0); + assert_eq!(Balances::free_balance(&10), 70); + assert!(Staking::forcing_new_era().is_none()); + }); +} + #[test] fn note_offline_should_work() { with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || {