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