Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Split off System random functions into a new Randomness module #3699

Merged
merged 33 commits into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
80f98b1
split off system randomness functions into a new module
Sep 26, 2019
b6dbab6
bump spec and impl version
Sep 27, 2019
5c59f76
Move randomness to bottom of construct_runtime calls, move initializa…
Sep 27, 2019
81d082f
Update srml/randomness/Cargo.toml
expenses Sep 27, 2019
fb41b38
Update srml/randomness/src/lib.rs
expenses Sep 27, 2019
6fafe55
Update srml/randomness/src/lib.rs
expenses Sep 27, 2019
8755b97
Update srml/randomness/Cargo.toml
expenses Sep 27, 2019
12158e3
Improve system example
expenses Sep 27, 2019
2bbc03a
Merge branch 'master' into randomness-module
expenses Sep 27, 2019
71bf01c
Merge branch 'randomness-module' of https://github.com/expenses/subst…
expenses Sep 27, 2019
394ad49
Update Cargo.lock
expenses Sep 27, 2019
664fc3c
Fix randomness example
expenses Sep 27, 2019
e3761d2
Get rid of the stored index
expenses Sep 27, 2019
907a29a
Add tests
expenses Sep 27, 2019
d98c7db
Add a random test
expenses Sep 27, 2019
64e3c22
Merge branch 'master' into randomness-module
expenses Sep 29, 2019
908d00f
Improve docs
expenses Sep 29, 2019
15011d1
Merge branch 'randomness-module' of https://github.com/expenses/subst…
expenses Sep 29, 2019
fb96026
Fix executive test :^)
expenses Sep 29, 2019
bc15acc
Add a utility function to tests
expenses Sep 29, 2019
f7e4d4d
Update srml/randomness/Cargo.toml
expenses Oct 1, 2019
8c8f70b
Update srml/randomness/src/lib.rs
expenses Oct 1, 2019
b71e627
Update srml/randomness/src/lib.rs
expenses Oct 2, 2019
44a3cc1
Merge branch 'master' into randomness-module
expenses Oct 2, 2019
d491ac8
Change interpretation of block numbers
expenses Oct 2, 2019
23b29af
Merge branch 'master' into randomness-module
expenses Oct 6, 2019
bb84094
rename crate
expenses Oct 7, 2019
3a28382
Merge branch 'randomness-module' of https://github.com/expenses/subst…
expenses Oct 7, 2019
742b3db
refactor randomess module usage
expenses Oct 7, 2019
8388726
Merge branch 'master' of https://github.com/paritytech/substrate into…
expenses Oct 7, 2019
b5cd993
change random material len to a const
expenses Oct 8, 2019
0db8a8b
Update srml/randomness-collective-flip/src/lib.rs
expenses Oct 8, 2019
6a88d62
Update srml/randomness-collective-flip/src/lib.rs
expenses Oct 8, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ members = [
"srml/membership",
"srml/metadata",
"srml/offences",
"srml/randomness",
"srml/scored-pool",
"srml/session",
"srml/staking",
Expand Down
2 changes: 2 additions & 0 deletions node-template/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../
executive = { package = "srml-executive", path = "../../srml/executive", default_features = false }
indices = { package = "srml-indices", path = "../../srml/indices", default_features = false }
grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false }
randomness = { package = "srml-randomness", path = "../../srml/randomness", default_features = false }
system = { package = "srml-system", path = "../../srml/system", default_features = false }
timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false }
sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = false }
Expand All @@ -46,6 +47,7 @@ std = [
"grandpa/std",
"primitives/std",
"sr-primitives/std",
"randomness/std",
"system/std",
"timestamp/std",
"sudo/std",
Expand Down
3 changes: 2 additions & 1 deletion node-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ construct_runtime!(
Sudo: sudo,
// Used for the module template in `./template.rs`
TemplateModule: template::{Module, Call, Storage, Event<T>},
Randomness: randomness::{Module, Call, Storage},
}
);

Expand Down Expand Up @@ -339,7 +340,7 @@ impl_runtime_apis! {
}

fn random_seed() -> <Block as BlockT>::Hash {
System::random_seed()
Randomness::random_seed()
}
}

Expand Down
2 changes: 2 additions & 0 deletions node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ im-online = { package = "srml-im-online", path = "../../srml/im-online", default
indices = { package = "srml-indices", path = "../../srml/indices", default-features = false }
membership = { package = "srml-membership", path = "../../srml/membership", default-features = false }
offences = { package = "srml-offences", path = "../../srml/offences", default-features = false }
randomness = { package = "srml-randomness", path = "../../srml/randomness", default-features = false }
session = { package = "srml-session", path = "../../srml/session", default-features = false, features = ["historical"] }
staking = { package = "srml-staking", path = "../../srml/staking", default-features = false }
srml-staking-reward-curve = { path = "../../srml/staking/reward-curve"}
Expand Down Expand Up @@ -77,6 +78,7 @@ std = [
"offchain-primitives/std",
"offences/std",
"primitives/std",
"randomness/std",
"rstd/std",
"rustc-hex",
"safe-mix/std",
Expand Down
7 changes: 4 additions & 3 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// and set impl_version to equal spec_version. If only runtime
// implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version.
spec_version: 165,
impl_version: 165,
spec_version: 166,
impl_version: 166,
apis: RUNTIME_API_VERSIONS,
};

Expand Down Expand Up @@ -508,6 +508,7 @@ construct_runtime!(
ImOnline: im_online::{Module, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
AuthorityDiscovery: authority_discovery::{Module, Call, Config<T>},
Offences: offences::{Module, Call, Storage, Event},
Randomness: randomness::{Module, Call, Storage},
}
);

Expand Down Expand Up @@ -579,7 +580,7 @@ impl_runtime_apis! {
}

fn random_seed() -> <Block as BlockT>::Hash {
System::random_seed()
Randomness::random_seed()
}
}

Expand Down
2 changes: 2 additions & 0 deletions srml/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals
sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", default-features = false }
support = { package = "srml-support", path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
randomness = { package = "srml-randomness", path = "../randomness", default-features = false }
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }

[dev-dependencies]
Expand All @@ -33,6 +34,7 @@ std = [
"codec/std",
"primitives/std",
"sr-primitives/std",
"randomness/std",
"runtime-io/std",
"rstd/std",
"sandbox/std",
Expand Down
2 changes: 1 addition & 1 deletion srml/contracts/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ where
}

fn random(&self, subject: &[u8]) -> SeedOf<T> {
system::Module::<T>::random(subject)
randomness::Module::<T>::random(subject)
}

fn now(&self) -> &T::Moment {
Expand Down
24 changes: 24 additions & 0 deletions srml/randomness/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "srml-randomness"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"

[dependencies]
safe-mix = { version = "1.0", default-features = false}
expenses marked this conversation as resolved.
Show resolved Hide resolved
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
sr-primitives = { path = "../../core/sr-primitives", default-features = false }
support = { package = "srml-support", path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false }

[features]
default = ["std"]
std = [
"safe-mix/std",
"system/std",
"codec/std",
"support/std",
"sr-primitives/std",
"rstd/std",
]
145 changes: 145 additions & 0 deletions srml/randomness/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate 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.

// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.

//! # Randomness Module
//!
//! The Randomness module provides a [`random`](./struct.Module.html#method.random) function that
//! generates low-influence random values based on the block hashes from the previous 81 blocks.
expenses marked this conversation as resolved.
Show resolved Hide resolved
//!
//! ## Public Functions
//!
//! See the [`Module`](./struct.Module.html) struct for details of publicly available functions.
//!
//! ## Usage
//!
//! ### Prerequisites
//!
//! Import the Randomness module and derive your module's configuration trait from the system trait.
//!
//! ### Example - Get random seed for the current block
//!
//! ```
//! use support::{decl_module, dispatch::Result};
//!
//! trait Trait: system::Trait {}
//!
//! decl_module! {
//! pub struct Module<T: Trait> for enum Call where origin: T::Origin {
//! pub fn random_module_example(origin) -> Result {
//! let _random_seed = <srml_random::Module<T>>::random_seed();
//! Ok(())
//! }
//! }
//! }
//! # fn main() { }
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

use rstd::prelude::*;
use sr_primitives::traits::Hash;
use support::{decl_module, decl_storage};
use safe_mix::TripletMix;
use codec::Encode;
use system::Trait;

decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
bkchr marked this conversation as resolved.
Show resolved Hide resolved
fn on_initialize() {
let parent_hash = <system::Module<T>>::parent_hash();

<RandomMaterial<T>>::mutate(|&mut(ref mut index, ref mut values)| if values.len() < 81 {
values.push(parent_hash)
} else {
values[*index as usize] = parent_hash;
*index = (*index + 1) % 81;
expenses marked this conversation as resolved.
Show resolved Hide resolved
});
}
}
}

decl_storage! {
trait Store for Module<T: Trait> as System {
/// 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>);
}
}

impl<T: Trait> Module<T> {
/// 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 verifiable random function (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:
expenses marked this conversation as resolved.
Show resolved Hide resolved
///
/// - 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-influence 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 {
expenses marked this conversation as resolved.
Show resolved Hide resolved
// 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()
}
}
}