From adba89913ea17e6444f97231b8a594e4c54f1380 Mon Sep 17 00:00:00 2001
From: Gavin Wood <gavin@parity.io>
Date: Mon, 6 May 2019 13:57:30 +0200
Subject: [PATCH] Clean up random seed to make a bit more flexible (#2456)

* Reformulate random seed to be more random

- First 80 random values come from cycling the incomplete series (
  instead of filling with zeroes)
- Calculate random material each usage (use a single amalgamated
  ring buffer to store them for avoiding 81 lookups each time)
- Mutate inputs by hashing each with:
  - its index (into the 81)
  - an additional "subject" key provided by caller

This keeps the final output low-influence while still allowing
it to be used as the seed to independent contexts. (Hashing the
result to give the final seed is no better than using parent_hash).

* Docs

* Bump runtime

* Update notes

* Remove feature(alloc)

* Update srml/system/src/lib.rs

Co-Authored-By: gavofyork <github@gavwood.com>
---
 substrate/core/executor/wasm/src/lib.rs       |  1 -
 .../finality-grandpa/primitives/src/lib.rs    |  1 -
 substrate/core/primitives/src/lib.rs          |  1 -
 substrate/core/sr-io/src/lib.rs               |  1 -
 substrate/core/sr-sandbox/src/lib.rs          |  1 -
 substrate/core/sr-std/src/lib.rs              |  1 -
 substrate/core/trie/src/lib.rs                |  1 -
 substrate/node-template/runtime/src/lib.rs    |  1 -
 substrate/node/primitives/src/lib.rs          |  1 -
 substrate/node/runtime/src/lib.rs             |  4 +-
 substrate/srml/executive/src/lib.rs           |  2 +-
 substrate/srml/support/src/lib.rs             |  1 -
 substrate/srml/system/src/lib.rs              | 81 +++++++++++++------
 13 files changed, 61 insertions(+), 36 deletions(-)

diff --git a/substrate/core/executor/wasm/src/lib.rs b/substrate/core/executor/wasm/src/lib.rs
index 842749dd5bb..193ff5c9c0d 100644
--- a/substrate/core/executor/wasm/src/lib.rs
+++ b/substrate/core/executor/wasm/src/lib.rs
@@ -1,7 +1,6 @@
 #![no_std]
 #![cfg_attr(feature = "strict", deny(warnings))]
 
-#![feature(alloc)]
 extern crate alloc;
 use alloc::vec::Vec;
 use alloc::slice;
diff --git a/substrate/core/finality-grandpa/primitives/src/lib.rs b/substrate/core/finality-grandpa/primitives/src/lib.rs
index 7016a708bd6..869b5e68fd6 100644
--- a/substrate/core/finality-grandpa/primitives/src/lib.rs
+++ b/substrate/core/finality-grandpa/primitives/src/lib.rs
@@ -17,7 +17,6 @@
 //! Primitives for GRANDPA integration, suitable for WASM compilation.
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 #[cfg(not(feature = "std"))]
 extern crate alloc;
diff --git a/substrate/core/primitives/src/lib.rs b/substrate/core/primitives/src/lib.rs
index 97f5480743c..c9008171df9 100644
--- a/substrate/core/primitives/src/lib.rs
+++ b/substrate/core/primitives/src/lib.rs
@@ -19,7 +19,6 @@
 #![warn(missing_docs)]
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 /// Initialize a key-value collection from array.
 ///
diff --git a/substrate/core/sr-io/src/lib.rs b/substrate/core/sr-io/src/lib.rs
index 5101d3b2c12..47af4de98ba 100644
--- a/substrate/core/sr-io/src/lib.rs
+++ b/substrate/core/sr-io/src/lib.rs
@@ -22,7 +22,6 @@
 #![cfg_attr(not(feature = "std"), feature(lang_items))]
 #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))]
 #![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 #![cfg_attr(feature = "std", doc = "Substrate runtime standard library as compiled when linked with Rust's standard library.")]
 #![cfg_attr(not(feature = "std"), doc = "Substrate's runtime standard library as compiled without Rust's standard library.")]
diff --git a/substrate/core/sr-sandbox/src/lib.rs b/substrate/core/sr-sandbox/src/lib.rs
index e8bdd5727ea..1e8b2b3f1df 100755
--- a/substrate/core/sr-sandbox/src/lib.rs
+++ b/substrate/core/sr-sandbox/src/lib.rs
@@ -37,7 +37,6 @@
 #![warn(missing_docs)]
 #![cfg_attr(not(feature = "std"), no_std)]
 #![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 use rstd::prelude::*;
 
diff --git a/substrate/core/sr-std/src/lib.rs b/substrate/core/sr-std/src/lib.rs
index 45857b33eda..b9874bcc201 100644
--- a/substrate/core/sr-std/src/lib.rs
+++ b/substrate/core/sr-std/src/lib.rs
@@ -19,7 +19,6 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 #![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 #![cfg_attr(feature = "std", doc = "Substrate runtime standard library as compiled when linked with Rust's standard library.")]
 #![cfg_attr(not(feature = "std"), doc = "Substrate's runtime standard library as compiled without Rust's standard library.")]
diff --git a/substrate/core/trie/src/lib.rs b/substrate/core/trie/src/lib.rs
index da6630e46d4..1322038d784 100644
--- a/substrate/core/trie/src/lib.rs
+++ b/substrate/core/trie/src/lib.rs
@@ -17,7 +17,6 @@
 //! Utility functions to interact with Substrate's Base-16 Modified Merkle Patricia tree ("trie").
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 mod error;
 mod node_header;
diff --git a/substrate/node-template/runtime/src/lib.rs b/substrate/node-template/runtime/src/lib.rs
index f7325923c76..81adf200d05 100644
--- a/substrate/node-template/runtime/src/lib.rs
+++ b/substrate/node-template/runtime/src/lib.rs
@@ -1,7 +1,6 @@
 //! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
 #![recursion_limit="256"]
 
diff --git a/substrate/node/primitives/src/lib.rs b/substrate/node/primitives/src/lib.rs
index 0d8906c47df..4dde59296f4 100644
--- a/substrate/node/primitives/src/lib.rs
+++ b/substrate/node/primitives/src/lib.rs
@@ -19,7 +19,6 @@
 #![warn(missing_docs)]
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 use runtime_primitives::{
 	generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature
diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs
index 748b5c63928..d0d603bb10d 100644
--- a/substrate/node/runtime/src/lib.rs
+++ b/substrate/node/runtime/src/lib.rs
@@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	spec_name: create_runtime_str!("node"),
 	impl_name: create_runtime_str!("substrate-node"),
 	authoring_version: 10,
-	spec_version: 71,
-	impl_version: 71,
+	spec_version: 72,
+	impl_version: 72,
 	apis: RUNTIME_API_VERSIONS,
 };
 
diff --git a/substrate/srml/executive/src/lib.rs b/substrate/srml/executive/src/lib.rs
index 6ca10bed2d5..f6dcae4a4c9 100644
--- a/substrate/srml/executive/src/lib.rs
+++ b/substrate/srml/executive/src/lib.rs
@@ -443,7 +443,7 @@ mod tests {
 				header: Header {
 					parent_hash: [69u8; 32].into(),
 					number: 1,
-					state_root: hex!("4c10fddf15e63c91ff2aa13ab3a9b7f6b19938d533829489e72ba40278a08fac").into(),
+					state_root: hex!("ac2840371d51ff2e036c8fc05af7313b7a030f735c38b2f03b94cbe87bfbb7c9").into(),
 					extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
 					digest: Digest { logs: vec![], },
 				},
diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs
index 78edc361d5e..b0fe28c63c5 100644
--- a/substrate/srml/support/src/lib.rs
+++ b/substrate/srml/support/src/lib.rs
@@ -17,7 +17,6 @@
 //! Support code for the runtime.
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 #[macro_use]
 extern crate bitmask;
diff --git a/substrate/srml/system/src/lib.rs b/substrate/srml/system/src/lib.rs
index e3d77438f9c..0d3264c5ab0 100644
--- a/substrate/srml/system/src/lib.rs
+++ b/substrate/srml/system/src/lib.rs
@@ -302,8 +302,9 @@ decl_storage! {
 		pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash;
 		/// Extrinsics data for the current block (maps an extrinsic's index to its data).
 		ExtrinsicData get(extrinsic_data): map u32 => Vec<u8>;
-		/// Random seed of the current block.
-		RandomSeed get(random_seed) build(|_| T::Hash::default()): T::Hash;
+		/// Series of block headers from the last 81 blocks that acts as random seed material. This is arranged as a
+		/// ring buffer with the `i8` prefix being the index into the `Vec` of the oldest hash.
+		RandomMaterial get(random_material): (i8, Vec<T::Hash>);
 		/// The current block number being processed. Set by `execute_block`.
 		Number get(block_number) build(|_| T::BlockNumber::sa(1u64)): T::BlockNumber;
 		/// Hash of the previous block.
@@ -395,13 +396,17 @@ impl<T: Trait> Module<T> {
 		<ParentHash<T>>::put(parent_hash);
 		<BlockHash<T>>::insert(*number - One::one(), parent_hash);
 		<ExtrinsicsRoot<T>>::put(txs_root);
-		<RandomSeed<T>>::put(Self::calculate_random());
+		<RandomMaterial<T>>::mutate(|&mut(ref mut index, ref mut values)| if values.len() < 81 {
+			values.push(parent_hash.clone())
+		} else {
+			values[*index as usize] = parent_hash.clone();
+			*index = (*index + 1) % 81;
+		});
 		<Events<T>>::kill();
 	}
 
 	/// Remove temporary "environment" entries in storage.
 	pub fn finalize() -> T::Header {
-		<RandomSeed<T>>::kill();
 		<ExtrinsicCount<T>>::kill();
 		<AllExtrinsicsLen<T>>::kill();
 
@@ -432,26 +437,13 @@ impl<T: Trait> Module<T> {
 		<Digest<T>>::put(l);
 	}
 
-	/// Calculate the current block's random seed.
-	fn calculate_random() -> T::Hash {
-		assert!(Self::block_number() > Zero::zero(), "Block number may never be zero");
-		(0..81)
-			.scan(
-				Self::block_number() - One::one(),
-				|c, _| { if *c > Zero::zero() { *c -= One::one() }; Some(*c)
-			})
-			.map(Self::block_hash)
-			.triplet_mix()
-	}
-
 	/// Get the basic externalities for this module, useful for tests.
 	#[cfg(any(feature = "std", test))]
 	pub fn externalities() -> TestExternalities<Blake2Hasher> {
 		TestExternalities::new(map![
 			twox_128(&<BlockHash<T>>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(),
 			twox_128(<Number<T>>::key()).to_vec() => T::BlockNumber::one().encode(),
-			twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode(),
-			twox_128(<RandomSeed<T>>::key()).to_vec() => T::Hash::default().encode()
+			twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode()
 		])
 	}
 
@@ -475,11 +467,54 @@ impl<T: Trait> Module<T> {
 		<ParentHash<T>>::put(n);
 	}
 
-	/// Set the random seed to something in particular. Can be used as an alternative to
-	/// `initialize` for tests that don't need to bother with the other environment entries.
-	#[cfg(any(feature = "std", test))]
-	pub fn set_random_seed(seed: T::Hash) {
-		<RandomSeed<T>>::put(seed);
+	/// Get the basic random seed.
+	///
+	/// In general you won't want to use this, but rather `Self::random` which allows you to give a subject for the
+	/// random result and whose value will be independently low-influence random from any other such seeds.
+	pub fn random_seed() -> T::Hash {
+		Self::random(&[][..])
+	}
+
+	/// Get a low-influence "random" value.
+	///
+	/// Being a deterministic block chain, real randomness is difficult to come by. This gives you something that
+	/// approximates it. `subject` is a context identifier and allows you to get a different result to other callers
+	/// of this function; use it like `random(&b"my context"[..])`.
+	///
+	/// This is initially implemented through a low-influence "triplet mix" convolution of previous block hash values.
+	/// In the future it will be generated from a secure "VRF".
+	///
+	/// ### Security Notes
+	/// This randomness uses a low-influence function, drawing upon the block hashes from the previous 81 blocks. Its
+	/// result for any given subject will be known in advance by the block producer of this block (and, indeed, anyone
+	/// who knows the block's `parent_hash`). However, it is mostly impossible for the producer of this block *alone*
+	/// to influence the value of this hash. A sizable minority of dishonest and coordinating block producers would be
+	/// required in order to affect this value. If that is an insufficient security guarantee then two things can be
+	/// used to improve this randomness:
+	/// - Name, in advance, the block number whose random value will be used; ensure your module retains a buffer of
+	/// previous random values for its subject and then index into these in order to obviate the ability of your user
+	/// to look up the parent hash and choose when to transact based upon it.
+	/// - Require your user to first commit to an additional value by first posting its hash. Require them to reveal
+	/// the value to determine the final result, hashing it with the output of this random function. This reduces the
+	/// ability of a cabal of block producers from conspiring against individuals.
+	///
+	/// WARNING: Hashing the result of this function will remove any low-infleunce properties it has and mean that
+	/// all bits of the resulting value are entirely manipulatable by the author of the parent block, who can determine
+	/// the value of `parent_hash`.
+	pub fn random(subject: &[u8]) -> T::Hash {
+		let (index, hash_series) = <RandomMaterial<T>>::get();
+		if hash_series.len() > 0 {
+			// Always the case after block 1 is initialised.
+			hash_series.iter()
+				.cycle()
+				.skip(index as usize)
+				.take(81)
+				.enumerate()
+				.map(|(i, h)| (i as i8, subject, h).using_encoded(T::Hashing::hash))
+				.triplet_mix()
+		} else {
+			T::Hash::default()
+		}
 	}
 
 	/// Increment a particular account's nonce by 1.
-- 
GitLab