From 2789bc2b8fb5b22b6cfc8ed96c99290eb2337fc5 Mon Sep 17 00:00:00 2001
From: Gav <gavin@parity.io>
Date: Sun, 21 Jan 2018 22:35:25 +0100
Subject: [PATCH] Simple governance subsytem.

---
 substrate/executor/src/wasm_executor.rs       |   5 +-
 substrate/native-runtime/support/src/lib.rs   |  13 ++-
 .../polkadot/src/codec/endiansensitive.rs     |   5 +
 .../polkadot/src/codec/slicable.rs            |  24 ++--
 substrate/wasm-runtime/polkadot/src/lib.rs    |   2 +-
 .../polkadot/src/runtime/governance.rs        |  97 ++++++++++++++++
 .../wasm-runtime/polkadot/src/runtime/mod.rs  |   4 +-
 .../polkadot/src/runtime/staking.rs           | 108 ++++++++++--------
 .../polkadot/src/support/function.rs          |  16 ++-
 .../wasm-runtime/polkadot/src/support/mod.rs  |   1 +
 .../polkadot/src/support/primitives.rs        |  20 +++-
 .../polkadot/src/support/proposal.rs          | 108 ++++++++++++++++++
 .../polkadot/src/support/statichex.rs         |  11 +-
 .../polkadot/src/support/storable.rs          |  23 ++--
 substrate/wasm-runtime/support/src/lib.rs     |   6 +-
 15 files changed, 360 insertions(+), 83 deletions(-)
 create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/governance.rs
 create mode 100644 substrate/wasm-runtime/polkadot/src/support/proposal.rs

diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs
index 7fc9a741f83..d0bc9081360 100644
--- a/substrate/executor/src/wasm_executor.rs
+++ b/substrate/executor/src/wasm_executor.rs
@@ -128,11 +128,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
 		this.memory.write_primitive(written_out, written);
 		offset as u32
 	},
-	ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32 => {
+	ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32 => {
 		if let Ok(key) = this.memory.get(key_data, key_len as usize) {
 			if let Ok(value) = this.ext.storage(&key) {
+				let value = &value[value_offset as usize..];
 				let written = ::std::cmp::min(value_len as usize, value.len());
-				let _ = this.memory.set(value_data, &value[0..written]);
+				let _ = this.memory.set(value_data, &value[..written]);
 				written as u32
 			} else { 0 }
 		} else { 0 }
diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs
index 348c0b17a9c..7adf9a904b8 100644
--- a/substrate/native-runtime/support/src/lib.rs
+++ b/substrate/native-runtime/support/src/lib.rs
@@ -47,24 +47,29 @@ environmental!(ext : Externalities<Error=NoError> + 'static);
 /// Get `key` from storage and return a `Vec`, empty if there's a problem.
 pub fn storage(key: &[u8]) -> Vec<u8> {
 	ext::with(|ext| ext.storage(key).ok().map(|s| s.to_vec()))
-		.unwrap_or(None)
-		.unwrap_or_else(|| vec![])
+		.expect("read_storage cannot be called outside of an Externalities-provided environment.")
+		.unwrap_or_else(Vec::new)
 }
 
 /// Get `key` from storage, placing the value into `value_out` (as much as possible) and return
 /// the number of bytes that the key in storage was.
-pub fn read_storage(key: &[u8], value_out: &mut [u8]) -> usize {
+pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> usize {
 	ext::with(|ext| {
 		if let Ok(value) = ext.storage(key) {
+			let value = &value[value_offset..];
 			let written = ::std::cmp::min(value.len(), value_out.len());
 			value_out[0..written].copy_from_slice(&value[0..written]);
 			value.len()
 		} else {
+			// no-entry is treated as an empty vector of bytes.
+			// TODO: consider allowing empty-vector to exist separately to no-entry (i.e. return
+			// Option<usize>)
 			0
 		}
-	}).unwrap_or(0)
+	}).expect("read_storage cannot be called outside of an Externalities-provided environment.")
 }
 
+/// Set the storage to some particular key.
 pub fn set_storage(key: &[u8], value: &[u8]) {
 	ext::with(|ext|
 		ext.set_storage(key.to_vec(), value.to_vec())
diff --git a/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs
index a1576284228..734067d2342 100644
--- a/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs
+++ b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs
@@ -44,6 +44,11 @@ macro_rules! impl_non_endians {
 	)* }
 }
 
+// TODO: this is fine as long as bool is one byte. it'll break if llvm tries to use more. happily,
+// this isn't an issue for the forseeable future. if it ever happens, then it should be implemented
+// as endian sensitive.
+impl EndianSensitive for bool {}
+
 impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize);
 impl_non_endians!(u8, i8, [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8],
 	[u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40],
diff --git a/substrate/wasm-runtime/polkadot/src/codec/slicable.rs b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs
index 5ec042ec9bf..1c783e39dfd 100644
--- a/substrate/wasm-runtime/polkadot/src/codec/slicable.rs
+++ b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs
@@ -23,8 +23,10 @@ use endiansensitive::EndianSensitive;
 /// Trait that allows zero-copy read/write of value-references to/from slices in LE format.
 pub trait Slicable: Sized {
 	fn from_slice(value: &[u8]) -> Option<Self> {
-		Self::set_as_slice(|out| if value.len() == out.len() {
-			out.copy_from_slice(&value);
+		Self::set_as_slice(&|out, offset| if value.len() >= out.len() + offset {
+			let value = &value[offset..];
+			let len = out.len();
+			out.copy_from_slice(&value[0..len]);
 			true
 		} else {
 			false
@@ -33,7 +35,7 @@ pub trait Slicable: Sized {
 	fn to_vec(&self) -> Vec<u8> {
 		self.as_slice_then(|s| s.to_vec())
 	}
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(set_slice: F) -> Option<Self>;
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(set_slice: &F) -> Option<Self>;
 	fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
 		f(&self.to_vec())
 	}
@@ -44,13 +46,13 @@ pub trait Slicable: Sized {
 pub trait NonTrivialSlicable: Slicable {}
 
 impl<T: EndianSensitive> Slicable for T {
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(fill_slice: F) -> Option<Self> {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(fill_slice: &F) -> Option<Self> {
 		let size = size_of::<T>();
 		let mut result: T = unsafe { uninitialized() };
 		let result_slice = unsafe {
 			slice::from_raw_parts_mut(transmute::<*mut T, *mut u8>(&mut result), size)
 		};
-		if fill_slice(result_slice) {
+		if fill_slice(result_slice, 0) {
 			Some(result.from_le())
 		} else {
 			None
@@ -74,8 +76,16 @@ impl Slicable for Vec<u8> {
 	fn from_slice(value: &[u8]) -> Option<Self> {
 		Some(value[4..].to_vec())
 	}
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
-		unimplemented!();
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(fill_slice: &F) -> Option<Self> {
+		u32::set_as_slice(fill_slice).and_then(|len| {
+			let mut v = Vec::with_capacity(len as usize);
+			unsafe { v.set_len(len as usize); }
+			if fill_slice(&mut v, 4) {
+				Some(v)
+			} else {
+				None
+			}
+		})
 	}
 	fn to_vec(&self) -> Vec<u8> {
 		let mut r: Vec<u8> = Vec::new().join(&(self.len() as u32));
diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs
index 7a96b6cee44..713d8eb0919 100644
--- a/substrate/wasm-runtime/polkadot/src/lib.rs
+++ b/substrate/wasm-runtime/polkadot/src/lib.rs
@@ -30,7 +30,7 @@ mod codec;
 mod support;
 mod runtime;
 pub use codec::{endiansensitive, streamreader, joiner, slicable, keyedvec};
-pub use support::{primitives, function, environment, storable};
+pub use support::{primitives, function, proposal, environment, storable};
 #[cfg(test)]
 pub use support::{testing, statichex};
 
diff --git a/substrate/wasm-runtime/polkadot/src/runtime/governance.rs b/substrate/wasm-runtime/polkadot/src/runtime/governance.rs
new file mode 100644
index 00000000000..783522ffdf8
--- /dev/null
+++ b/substrate/wasm-runtime/polkadot/src/runtime/governance.rs
@@ -0,0 +1,97 @@
+// 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 <http://www.gnu.org/licenses/>.
+
+//! Governance system: Handles administration and dispatch of sensitive operations including
+//! setting new code, minting new tokens and changing parameters.
+
+use runtime_support::Vec;
+use keyedvec::KeyedVec;
+use storable::{Storable, StorageVec, kill};
+use primitives::{AccountID, Hash, BlockNumber};
+use proposal::Proposal;
+use runtime::{staking, system, session};
+
+// TRANSACTION API
+
+pub fn propose(transactor: &AccountID, proposal: &Proposal) {
+	if Proposal::lookup(b"gov:pro").is_some() {
+		panic!("there may only be one proposal per era.");
+	}
+	proposal.store(b"gov:pro");
+	approve(transactor, staking::current_era());
+}
+
+pub fn approve(transactor: &AccountID, era_index: BlockNumber) {
+	if era_index != staking::current_era() {
+		panic!("approval vote applied on non-current era.")
+	}
+	if Proposal::lookup(b"gov:pro").is_none() {
+		panic!("there must be a proposal in order to approve.");
+	}
+	let key = transactor.to_keyed_vec(b"gov:app:");
+	if bool::lookup(&key).is_some() {
+		panic!("transactor may not approve a proposal twice in one era.");
+	}
+	true.store(&key);
+	(approval_count() + 1).store(b"gov:app");
+}
+
+// INSPECTION API
+
+pub fn approval_count() -> u32 {
+	Storable::lookup_default(b"gov:app")
+}
+
+pub fn approval_ppm_required() -> u32 {
+	Storable::lookup(b"gov:apr").unwrap_or(1000)
+}
+
+pub fn approvals_required() -> u32 {
+	approval_ppm_required() * staking::validator_count() as u32 / 1000
+}
+
+// PUBLIC API
+
+/// Current era is ending; we should finish up any proposals.
+pub fn end_of_an_era() {
+	// TODO: tally up votes for the current proposal, if any. enact if there are sufficient
+	// approvals.
+	if let Some(proposal) = Proposal::lookup(b"gov:pro") {
+		let enact = approval_count() >= approvals_required();
+
+		// clear proposal
+		reset_proposal();
+
+		if enact {
+			proposal.enact();
+		}
+	}
+}
+
+// PRIVATE API
+
+fn reset_proposal() {
+	session::validators().into_iter().for_each(|v| {
+		kill(&v.to_keyed_vec(b"gov:app:"));
+	});
+	kill(b"gov:pro");
+	kill(b"gov:app");
+}
+
+#[cfg(test)]
+mod tests {
+	// TODO
+}
diff --git a/substrate/wasm-runtime/polkadot/src/runtime/mod.rs b/substrate/wasm-runtime/polkadot/src/runtime/mod.rs
index f83922c42fe..6af33d6a657 100644
--- a/substrate/wasm-runtime/polkadot/src/runtime/mod.rs
+++ b/substrate/wasm-runtime/polkadot/src/runtime/mod.rs
@@ -26,5 +26,7 @@ pub mod staking;
 pub mod timestamp;
 #[allow(unused)]
 pub mod session;
+#[allow(unused)]
+pub mod governance;
 
-// TODO: governance, polkadao
+// TODO: polkadao
diff --git a/substrate/wasm-runtime/polkadot/src/runtime/staking.rs b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs
index fc7c12798e3..96843290a2b 100644
--- a/substrate/wasm-runtime/polkadot/src/runtime/staking.rs
+++ b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs
@@ -16,11 +16,11 @@
 
 //! Staking manager: Handles balances and periodically determines the best set of validators.
 
-use runtime_support::Vec;
+use runtime_support::{Vec, RefCell};
 use keyedvec::KeyedVec;
 use storable::{Storable, StorageVec};
 use primitives::{BlockNumber, AccountID};
-use runtime::{system, session};
+use runtime::{system, session, governance};
 
 /// The balance of an account.
 pub type Balance = u64;
@@ -31,7 +31,7 @@ pub type Bondage = u64;
 struct IntentionStorageVec {}
 impl StorageVec for IntentionStorageVec {
 	type Item = AccountID;
-	const PREFIX: &'static[u8] = b"ses:wil:";
+	const PREFIX: &'static[u8] = b"sta:wil:";
 }
 
 // Each identity's stake may be in one of three bondage states, given by an integer:
@@ -40,45 +40,7 @@ impl StorageVec for IntentionStorageVec {
 // - n | n > current_era(): deactivating: recently representing a validator and not yet
 //   ready for transfer.
 
-/// The length of the bonding duration in eras.
-pub fn bonding_duration() -> BlockNumber {
-	Storable::lookup_default(b"sta:loc")
-}
-
-/// The length of a staking era in sessions.
-pub fn validator_count() -> usize {
-	u32::lookup_default(b"sta:vac") as usize
-}
-
-/// The length of a staking era in blocks.
-pub fn era_length() -> BlockNumber {
-	sessions_per_era() * session::length()
-}
-
-/// The length of a staking era in sessions.
-pub fn sessions_per_era() -> BlockNumber {
-	Storable::lookup_default(b"sta:spe")
-}
-
-/// The current era index.
-pub fn current_era() -> BlockNumber {
-	Storable::lookup_default(b"sta:era")
-}
-
-/// The block number at which the era length last changed.
-pub fn last_era_length_change() -> BlockNumber {
-	Storable::lookup_default(b"sta:lec")
-}
-
-/// The balance of a given account.
-pub fn balance(who: &AccountID) -> Balance {
-	Storable::lookup_default(&who.to_keyed_vec(b"sta:bal:"))
-}
-
-/// The liquidity-state of a given account.
-pub fn bondage(who: &AccountID) -> Bondage {
-	Storable::lookup_default(&who.to_keyed_vec(b"sta:bon:"))
-}
+// TRANSACTION API
 
 /// Transfer some unlocked staking balance to another staker.
 pub fn transfer(transactor: &AccountID, dest: &AccountID, value: Balance) {
@@ -119,6 +81,54 @@ pub fn unstake(transactor: &AccountID) {
 	(current_era() + bonding_duration()).store(&transactor.to_keyed_vec(b"sta:bon:"));
 }
 
+// PUBLIC API
+
+pub fn set_sessions_per_era(new: BlockNumber) {
+	new.store(b"sta:nse");
+}
+
+// INSPECTION API
+
+/// The length of the bonding duration in eras.
+pub fn bonding_duration() -> BlockNumber {
+	Storable::lookup_default(b"sta:loc")
+}
+
+/// The length of a staking era in sessions.
+pub fn validator_count() -> usize {
+	u32::lookup_default(b"sta:vac") as usize
+}
+
+/// The length of a staking era in blocks.
+pub fn era_length() -> BlockNumber {
+	sessions_per_era() * session::length()
+}
+
+/// The length of a staking era in sessions.
+pub fn sessions_per_era() -> BlockNumber {
+	Storable::lookup_default(b"sta:spe")
+}
+
+/// The current era index.
+pub fn current_era() -> BlockNumber {
+	Storable::lookup_default(b"sta:era")
+}
+
+/// The block number at which the era length last changed.
+pub fn last_era_length_change() -> BlockNumber {
+	Storable::lookup_default(b"sta:lec")
+}
+
+/// The balance of a given account.
+pub fn balance(who: &AccountID) -> Balance {
+	Storable::lookup_default(&who.to_keyed_vec(b"sta:bal:"))
+}
+
+/// The liquidity-state of a given account.
+pub fn bondage(who: &AccountID) -> Bondage {
+	Storable::lookup_default(&who.to_keyed_vec(b"sta:bon:"))
+}
+
 /// Hook to be called after to transaction processing.
 pub fn check_new_era() {
 	// check block number and call new_era if necessary.
@@ -131,8 +141,12 @@ pub fn check_new_era() {
 
 /// The era has changed - enact new staking set.
 ///
-/// NOTE: This always happens on a session change.
+/// NOTE: This always happens immediately before a session change to ensure that new validators
+/// get a chance to set their session keys.
 fn new_era() {
+	// Inform governance module that it's the end of an era
+	governance::end_of_an_era();
+
 	// Increment current era.
 	(current_era() + 1).store(b"sta:era");
 
@@ -143,9 +157,8 @@ fn new_era() {
 		system::block_number().store(b"sta:lec");
 	}
 
-	// TODO: evaluate desired staking amounts and nominations and optimise to find the best
+	// evaluate desired staking amounts and nominations and optimise to find the best
 	// combination of validators, then use session::set_validators().
-
 	// for now, this just orders would-be stakers by their balances and chooses the top-most
 	// validator_count() of them.
 	let mut intentions = IntentionStorageVec::items()
@@ -161,11 +174,6 @@ fn new_era() {
 	);
 }
 
-/// Set a new era length. Won't kick in until the next era change (at current length).
-fn set_sessions_per_era(new: BlockNumber) {
-	new.store(b"sta:nse");
-}
-
 #[cfg(test)]
 mod tests {
 	use runtime_support::{with_externalities, twox_128};
diff --git a/substrate/wasm-runtime/polkadot/src/support/function.rs b/substrate/wasm-runtime/polkadot/src/support/function.rs
index f4ee9c79e6e..dd54ba10806 100644
--- a/substrate/wasm-runtime/polkadot/src/support/function.rs
+++ b/substrate/wasm-runtime/polkadot/src/support/function.rs
@@ -18,9 +18,9 @@
 
 use primitives::AccountID;
 use streamreader::StreamReader;
-use runtime::{staking, session, timestamp};
+use runtime::{staking, session, timestamp, governance};
 
-/// The functions that a transaction can call (and be dispatched to).
+/// Public functions that can be dispatched to.
 #[cfg_attr(test, derive(PartialEq, Debug))]
 #[derive(Clone, Copy)]
 pub enum Function {
@@ -29,6 +29,8 @@ pub enum Function {
 	StakingTransfer,
 	SessionSetKey,
 	TimestampSet,
+	GovernancePropose,
+	GovernanceApprove,
 }
 
 impl Function {
@@ -40,6 +42,8 @@ impl Function {
 			x if x == Function::StakingTransfer as u8 => Some(Function::StakingTransfer),
 			x if x == Function::SessionSetKey as u8 => Some(Function::SessionSetKey),
 			x if x == Function::TimestampSet as u8 => Some(Function::TimestampSet),
+			x if x == Function::GovernancePropose as u8 => Some(Function::GovernancePropose),
+			x if x == Function::GovernanceApprove as u8 => Some(Function::GovernanceApprove),
 			_ => None,
 		}
 	}
@@ -69,6 +73,14 @@ impl Function {
 				let t = params.read().unwrap();
 				timestamp::set(t);
 			}
+			Function::GovernancePropose => {
+				let proposal = params.read().unwrap();
+				governance::propose(transactor, &proposal);
+			}
+			Function::GovernanceApprove => {
+				let era_index = params.read().unwrap();
+				governance::approve(transactor, era_index);
+			}
 		}
 	}
 }
diff --git a/substrate/wasm-runtime/polkadot/src/support/mod.rs b/substrate/wasm-runtime/polkadot/src/support/mod.rs
index 56ad3a355c5..384909d019b 100644
--- a/substrate/wasm-runtime/polkadot/src/support/mod.rs
+++ b/substrate/wasm-runtime/polkadot/src/support/mod.rs
@@ -18,6 +18,7 @@
 
 pub mod primitives;
 pub mod function;
+pub mod proposal;
 pub mod environment;
 pub mod storable;
 
diff --git a/substrate/wasm-runtime/polkadot/src/support/primitives.rs b/substrate/wasm-runtime/polkadot/src/support/primitives.rs
index 3ab385d4889..c59e7c5dcd4 100644
--- a/substrate/wasm-runtime/polkadot/src/support/primitives.rs
+++ b/substrate/wasm-runtime/polkadot/src/support/primitives.rs
@@ -28,15 +28,25 @@ use std::fmt;
 
 /// The Ed25519 pubkey that identifies an account.
 pub type AccountID = [u8; 32];
+
+/// Virtual account ID that represents the idea of a dispatch/statement being signed by everybody
+/// (who matters). Essentially this means that a majority of validators have decided it is
+/// "correct".
+pub const EVERYBODY: AccountID = [255u8; 32];
+
 /// The Ed25519 pub key of an session that belongs to an authority. This is used as what the
 /// external environment/consensus algorithm calls an "authority".
 pub type SessionKey = AccountID;
+
 /// Indentifier for a chain.
 pub type ChainID = u64;
+
 /// Index of a block in the chain.
 pub type BlockNumber = u64;
+
 /// Index of a transaction.
 pub type TxOrder = u64;
+
 /// A hash of some data.
 pub type Hash = [u8; 32];
 
@@ -76,7 +86,7 @@ impl Slicable for Header {
 		})
 	}
 
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(_fill_slice: &F) -> Option<Self> {
 		unimplemented!();
 	}
 
@@ -122,7 +132,7 @@ impl Slicable for Transaction {
 		})
 	}
 
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(_fill_slice: &F) -> Option<Self> {
 		unimplemented!();
 	}
 
@@ -200,7 +210,7 @@ impl Slicable for UncheckedTransaction {
 		})
 	}
 
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(_fill_slice: &F) -> Option<Self> {
 		unimplemented!();
 	}
 
@@ -237,7 +247,7 @@ impl Slicable for Block {
 		})
 	}
 
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(_fill_slice: &F) -> Option<Self> {
 		unimplemented!();
 	}
 
@@ -271,7 +281,7 @@ impl<T: NonTrivialSlicable> Slicable for Vec<T> {
 		Some(r)
 	}
 
-	fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(_fill_slice: &F) -> Option<Self> {
 		unimplemented!();
 	}
 
diff --git a/substrate/wasm-runtime/polkadot/src/support/proposal.rs b/substrate/wasm-runtime/polkadot/src/support/proposal.rs
new file mode 100644
index 00000000000..bffd7aa76ce
--- /dev/null
+++ b/substrate/wasm-runtime/polkadot/src/support/proposal.rs
@@ -0,0 +1,108 @@
+// 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 <http://www.gnu.org/licenses/>.
+
+//! Proposal: This describes a combination of a function ID and data that can be used to call into
+//! an internal function.
+
+use runtime_support::size_of;
+use slicable::Slicable;
+use joiner::Joiner;
+use streamreader::StreamReader;
+use runtime::staking;
+
+/// Internal functions that can be dispatched to.
+#[cfg_attr(test, derive(PartialEq, Debug))]
+#[derive(Clone, Copy)]
+pub enum InternalFunction {
+	SystemSetCode,
+	StakingSetSessionsPerEra,
+}
+
+impl InternalFunction {
+	/// Derive `Some` value from a `u8`, or `None` if it's invalid.
+	pub fn from_u8(value: u8) -> Option<InternalFunction> {
+		match value {
+			x if x == InternalFunction::SystemSetCode as u8 => Some(InternalFunction::SystemSetCode),
+			x if x == InternalFunction::StakingSetSessionsPerEra as u8 => Some(InternalFunction::StakingSetSessionsPerEra),
+			_ => None,
+		}
+	}
+}
+
+/// An internal function.
+#[cfg_attr(test, derive(PartialEq, Debug))]
+pub struct Proposal {
+	/// The priviledged function to call.
+	pub function: InternalFunction,
+	/// The serialised data to call it with.
+	pub input_data: Vec<u8>,
+}
+
+impl Slicable for Proposal {
+	fn set_as_slice<F: Fn(&mut[u8], usize) -> bool>(fill_slice: &F) -> Option<Self> {
+		Some(Proposal {
+			function: InternalFunction::from_u8(Slicable::set_as_slice(fill_slice)?)?,
+			input_data: Slicable::set_as_slice(&|s, o| fill_slice(s, o + 1))?,
+		})
+	}
+
+	fn to_vec(&self) -> Vec<u8> {
+		Vec::new()
+			.join(&(self.function as u8))
+			.join(&self.input_data)
+	}
+
+	fn size_of(data: &[u8]) -> Option<usize> {
+		let first_part = size_of::<u8>();
+		let second_part = <Vec<u8>>::size_of(&data[first_part..])?;
+		Some(first_part + second_part)
+	}
+}
+
+impl Proposal {
+	pub fn enact(&self) {
+		let mut params = StreamReader::new(&self.input_data);
+		match self.function {
+			InternalFunction::SystemSetCode => {
+				let code = params.read().unwrap();
+				staking::set_sessions_per_era(code);
+			}
+			InternalFunction::StakingSetSessionsPerEra => {
+				let value = params.read().unwrap();
+				staking::set_sessions_per_era(value);
+			}
+		}
+	}
+}
+
+#[cfg(test)]
+mod test {
+	use super::*;
+	use statichex::StaticHexInto;
+
+	#[test]
+	fn slicing_should_work() {
+		let p = Proposal {
+			function: InternalFunction::SystemSetCode,
+			input_data: b"Hello world".to_vec(),
+		};
+		let v = p.to_vec();
+		assert_eq!(v, "000b00000048656c6c6f20776f726c64".convert::<Vec<u8>>());
+
+		let o = Proposal::from_slice(&v).unwrap();
+		assert_eq!(p, o);
+	}
+}
diff --git a/substrate/wasm-runtime/polkadot/src/support/statichex.rs b/substrate/wasm-runtime/polkadot/src/support/statichex.rs
index 152ceadc0b4..b750a8ca10f 100644
--- a/substrate/wasm-runtime/polkadot/src/support/statichex.rs
+++ b/substrate/wasm-runtime/polkadot/src/support/statichex.rs
@@ -36,7 +36,16 @@ macro_rules! impl_sizes {
 	)* }
 }
 
-impl_sizes!(1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128);
+impl StaticHexConversion for Vec<u8> {
+	fn from_static_hex(hex: &'static str) -> Self {
+		FromHex::from_hex(hex).unwrap()
+	}
+}
+
+impl_sizes!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+	33, 34, 35, 36, 37, 38, 39, 40, 451, 42, 43, 44, 45, 46, 47, 48,
+	56, 64, 80, 96, 112, 128);
 
 /// Trait to allow converting from itself (only implemented for a static str) into some useful
 /// type (which must implement `StaticHexConversion`).
diff --git a/substrate/wasm-runtime/polkadot/src/support/storable.rs b/substrate/wasm-runtime/polkadot/src/support/storable.rs
index 3caf3ed19bf..5cfa1549373 100644
--- a/substrate/wasm-runtime/polkadot/src/support/storable.rs
+++ b/substrate/wasm-runtime/polkadot/src/support/storable.rs
@@ -17,28 +17,37 @@
 //! Stuff to do with the runtime's storage.
 
 use slicable::Slicable;
-use endiansensitive::EndianSensitive;
 use keyedvec::KeyedVec;
 use runtime_support::{self, twox_128, Vec};
 
 /// Trait for a value which may be stored in the storage DB.
 pub trait Storable {
 	/// Lookup the value in storage and deserialise, giving a default value if not found.
-	fn lookup_default(key: &[u8]) -> Self where Self: Sized + Default { Self::lookup(key).unwrap_or_else(Default::default) }
+	fn lookup_default(key: &[u8]) -> Self where Self: Sized + Default {
+		Self::lookup(key).unwrap_or_else(Default::default)
+	}
+
 	/// Lookup `Some` value in storage and deserialise; `None` if it's not there.
-	fn lookup(_key: &[u8]) -> Option<Self> where Self: Sized { unimplemented!() }
+	fn lookup(_key: &[u8]) -> Option<Self> where Self: Sized {
+		unimplemented!()
+	}
+
 	/// Place the value in storage under `key`.
 	fn store(&self, key: &[u8]);
 }
 
-// TODO: consider using blake256 to avoid possible eclipse attack.
+// TODO: consider using blake256 to avoid possible preimage attack.
 
 /// Remove `key` from storage.
-pub fn kill(key: &[u8]) { runtime_support::set_storage(&twox_128(key)[..], b""); }
+pub fn kill(key: &[u8]) {
+	runtime_support::set_storage(&twox_128(key)[..], b"");
+}
 
-impl<T: Default + Sized + EndianSensitive> Storable for T {
+impl<T: Sized + Slicable> Storable for T {
 	fn lookup(key: &[u8]) -> Option<Self> {
-		Slicable::set_as_slice(|out| runtime_support::read_storage(&twox_128(key)[..], out) == out.len())
+		Slicable::set_as_slice(&|out, offset|
+			runtime_support::read_storage(&twox_128(key)[..], out, offset) == out.len()
+		)
 	}
 	fn store(&self, key: &[u8]) {
 		self.as_slice_then(|slice| runtime_support::set_storage(&twox_128(key)[..], slice));
diff --git a/substrate/wasm-runtime/support/src/lib.rs b/substrate/wasm-runtime/support/src/lib.rs
index b65b5743515..5e689746c83 100644
--- a/substrate/wasm-runtime/support/src/lib.rs
+++ b/substrate/wasm-runtime/support/src/lib.rs
@@ -27,7 +27,7 @@ extern "C" {
 	fn ext_print_num(value: u64);
 	fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32);
 	fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8;
-	fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32;
+	fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32;
 	fn ext_chain_id() -> u64;
 	fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8);
 	fn ext_twox_128(data: *const u8, len: u32, out: *mut u8);
@@ -52,9 +52,9 @@ pub fn set_storage(key: &[u8], value: &[u8]) {
 	}
 }
 
-pub fn read_storage(key: &[u8], value_out: &mut [u8]) -> usize {
+pub fn read_storage(key: &[u8], value_offset: usize, value_out: &mut [u8]) -> usize {
 	unsafe {
-		ext_get_storage_into(&key[0], key.len() as u32, &mut value_out[0], value_out.len() as u32) as usize
+		ext_get_storage_into(&key[0], key.len() as u32, &mut value_out[0], value_out.len() as u32, value_offset as u32) as usize
 	}
 }
 
-- 
GitLab