diff --git a/runtime/src/curated_grandpa.rs b/runtime/src/curated_grandpa.rs
new file mode 100644
index 000000000000..ee7279eda456
--- /dev/null
+++ b/runtime/src/curated_grandpa.rs
@@ -0,0 +1,79 @@
+// Copyright 2017 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot. If not, see .
+
+//! A module for manually curated GRANDPA set.
+
+use {grandpa, system};
+use codec::Decode;
+use sr_primitives::traits::{As, Hash as HashT, BlakeTwo256, Zero};
+use rstd::prelude::*;
+
+
+pub trait Trait: grandpa::Trait {}
+
+decl_storage! {
+ trait Store for Module as CuratedGrandpa {
+ /// How often to shuffle the GRANDPA sets.
+ pub ShufflePeriod get(shuffle_period) build(|_| T::BlockNumber::sa(1024u64)): T::BlockNumber;
+ }
+}
+
+decl_module! {
+ /// curated GRANDPA set.
+ pub struct Module for enum Call where origin: T::Origin {
+ /// Changes the GRANDPA voter set.
+ fn set_voters(origin, voters: Vec<(T::SessionKey, u64)>) {
+ system::ensure_root(origin)?;
+ grandpa::Module::::schedule_change(voters, T::BlockNumber::zero())?;
+ }
+
+ fn on_finalise(block_number: T::BlockNumber) {
+ // every so often shuffle the voters and issue a change.
+ let shuffle_period: u64 = Self::shuffle_period().as_();
+ if block_number.as_() % shuffle_period == 0 {
+ let mut seed = system::Module::::random_seed().as_ref().to_vec();
+ seed.extend(b"grandpa_shuffling");
+ let mut seed = BlakeTwo256::hash(&seed);
+
+ let mut voters = grandpa::Module::::grandpa_authorities();
+ let voter_count = voters.len();
+
+ if voter_count == 0 { return }
+
+ for i in 0..(voter_count - 1) {
+ // 4 bytes of entropy used per cycle, 32 bytes entropy per hash
+ let offset = (i * 4 % 32) as usize;
+
+ // number of roles remaining to select from.
+ let remaining = (voter_count - i) as usize;
+
+ // 8 32-bit ints per 256-bit seed.
+ let voter_index = u32::decode(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
+
+ if offset == 28 {
+ // into the last 4 bytes - rehash to gather new entropy
+ seed = BlakeTwo256::hash(seed.as_ref());
+ }
+
+ // exchange last item with randomly chosen first.
+ voters.swap(remaining - 1, voter_index);
+ }
+
+ let _ = grandpa::Module::::schedule_change(voters, T::BlockNumber::zero());
+ }
+ }
+ }
+}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 5fa066749a02..a61b782611bf 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -63,6 +63,7 @@ extern crate polkadot_primitives as primitives;
#[cfg(test)]
extern crate substrate_keyring as keyring;
+mod curated_grandpa;
mod parachains;
use rstd::prelude::*;
@@ -108,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("polkadot"),
impl_name: create_runtime_str!("parity-polkadot"),
authoring_version: 1,
- spec_version: 103,
+ spec_version: 104,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
};
@@ -181,7 +182,7 @@ impl Convert for SessionKeyConversion {
impl session::Trait for Runtime {
type ConvertAccountIdToSessionKey = SessionKeyConversion;
- type OnSessionChange = (Staking, grandpa::SyncedAuthorities);
+ type OnSessionChange = Staking;
type Event = Event;
}
@@ -221,6 +222,8 @@ impl grandpa::Trait for Runtime {
type Event = Event;
}
+impl curated_grandpa::Trait for Runtime { }
+
impl parachains::Trait for Runtime {
const SET_POSITION: u32 = PARACHAINS_SET_POSITION;
}
@@ -251,6 +254,7 @@ construct_runtime!(
Staking: staking,
Democracy: democracy,
Grandpa: grandpa::{Module, Call, Storage, Config, Log(), Event},
+ CuratedGrandpa: curated_grandpa::{Module, Call, Storage},
Council: council::{Module, Call, Storage, Event},
CouncilVoting: council_voting,
CouncilMotions: council_motions::{Module, Call, Storage, Event, Origin},
diff --git a/runtime/wasm/Cargo.lock b/runtime/wasm/Cargo.lock
index a220368da7b1..b3d897680c7c 100644
--- a/runtime/wasm/Cargo.lock
+++ b/runtime/wasm/Cargo.lock
@@ -1,3 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
[[package]]
name = "arrayvec"
version = "0.4.7"
diff --git a/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm
index 5aeb3cb314e8..70dca42f0151 100644
Binary files a/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ
diff --git a/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm
index 62dfed3d54da..045ecf0e42f4 100755
Binary files a/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ