mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Split off System random functions into a new Randomness module (#3699)
* split off system randomness functions into a new module * bump spec and impl version * Move randomness to bottom of construct_runtime calls, move initialization into on_initialize * Update srml/randomness/Cargo.toml Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update srml/randomness/src/lib.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update srml/randomness/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Update srml/randomness/Cargo.toml Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Improve system example * Update Cargo.lock * Fix randomness example * Get rid of the stored index * Add tests * Add a random test * Improve docs * Fix executive test :^) * Add a utility function to tests * Update srml/randomness/Cargo.toml Co-Authored-By: Gavin Wood <github@gavwood.com> * Update srml/randomness/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Update srml/randomness/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Change interpretation of block numbers * rename crate * refactor randomess module usage * change random material len to a const * Update srml/randomness-collective-flip/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Update srml/randomness-collective-flip/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
committed by
Robert Habermeier
parent
520009973f
commit
968a30685f
Generated
+17
@@ -2478,6 +2478,7 @@ dependencies = [
|
||||
"srml-indices 2.0.0",
|
||||
"srml-membership 2.0.0",
|
||||
"srml-offences 1.0.0",
|
||||
"srml-randomness-collective-flip 2.0.0",
|
||||
"srml-session 2.0.0",
|
||||
"srml-staking 2.0.0",
|
||||
"srml-staking-reward-curve 2.0.0",
|
||||
@@ -2544,6 +2545,7 @@ dependencies = [
|
||||
"srml-executive 2.0.0",
|
||||
"srml-grandpa 2.0.0",
|
||||
"srml-indices 2.0.0",
|
||||
"srml-randomness-collective-flip 2.0.0",
|
||||
"srml-sudo 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
@@ -4011,6 +4013,7 @@ dependencies = [
|
||||
"sr-sandbox 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"srml-balances 2.0.0",
|
||||
"srml-randomness-collective-flip 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"srml-timestamp 2.0.0",
|
||||
@@ -4224,6 +4227,20 @@ dependencies = [
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srml-randomness-collective-flip"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srml-scored-pool"
|
||||
version = "1.0.0"
|
||||
|
||||
@@ -95,6 +95,7 @@ members = [
|
||||
"srml/membership",
|
||||
"srml/metadata",
|
||||
"srml/offences",
|
||||
"srml/randomness-collective-flip",
|
||||
"srml/scored-pool",
|
||||
"srml/session",
|
||||
"srml/staking",
|
||||
|
||||
@@ -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-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", 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 }
|
||||
@@ -46,6 +47,7 @@ std = [
|
||||
"grandpa/std",
|
||||
"primitives/std",
|
||||
"sr-primitives/std",
|
||||
"randomness-collective-flip/std",
|
||||
"system/std",
|
||||
"timestamp/std",
|
||||
"sudo/std",
|
||||
|
||||
@@ -272,6 +272,7 @@ construct_runtime!(
|
||||
Sudo: sudo,
|
||||
// Used for the module template in `./template.rs`
|
||||
TemplateModule: template::{Module, Call, Storage, Event<T>},
|
||||
RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -340,7 +341,7 @@ impl_runtime_apis! {
|
||||
}
|
||||
|
||||
fn random_seed() -> <Block as BlockT>::Hash {
|
||||
System::random_seed()
|
||||
RandomnessCollectiveFlip::random_seed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", 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"}
|
||||
@@ -78,6 +79,7 @@ std = [
|
||||
"offchain-primitives/std",
|
||||
"offences/std",
|
||||
"primitives/std",
|
||||
"randomness-collective-flip/std",
|
||||
"rstd/std",
|
||||
"rustc-hex",
|
||||
"safe-mix/std",
|
||||
|
||||
@@ -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: 172,
|
||||
impl_version: 172,
|
||||
spec_version: 173,
|
||||
impl_version: 173,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
@@ -518,6 +518,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},
|
||||
RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -589,7 +590,7 @@ impl_runtime_apis! {
|
||||
}
|
||||
|
||||
fn random_seed() -> <Block as BlockT>::Hash {
|
||||
System::random_seed()
|
||||
RandomnessCollectiveFlip::random_seed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ 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-collective-flip = { package = "srml-randomness-collective-flip", path = "../randomness-collective-flip", default-features = false }
|
||||
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.9.2"
|
||||
@@ -33,6 +35,7 @@ std = [
|
||||
"codec/std",
|
||||
"primitives/std",
|
||||
"sr-primitives/std",
|
||||
"randomness-collective-flip/std",
|
||||
"runtime-io/std",
|
||||
"rstd/std",
|
||||
"sandbox/std",
|
||||
|
||||
@@ -753,7 +753,7 @@ where
|
||||
}
|
||||
|
||||
fn random(&self, subject: &[u8]) -> SeedOf<T> {
|
||||
system::Module::<T>::random(subject)
|
||||
randomness_collective_flip::Module::<T>::random(subject)
|
||||
}
|
||||
|
||||
fn now(&self) -> &MomentOf<T> {
|
||||
|
||||
@@ -451,7 +451,7 @@ mod tests {
|
||||
header: Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
state_root: hex!("3e51b47b6cc8449eece93eee4b01f03b00a0ca7981c0b6c0447b6e0d50ca886d").into(),
|
||||
state_root: hex!("a6378d7fdd31029d13718d54bdff10a370e75cc624aaf94a90e7e7d4a24e0bcc").into(),
|
||||
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
|
||||
digest: Digest { logs: vec![], },
|
||||
},
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "srml-randomness-collective-flip"
|
||||
version = "2.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
safe-mix = { version = "1.0", default-features = false }
|
||||
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 }
|
||||
|
||||
[dev-dependencies]
|
||||
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
|
||||
runtime-io = { package = "sr-io", path = "../../core/sr-io" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"safe-mix/std",
|
||||
"system/std",
|
||||
"codec/std",
|
||||
"support/std",
|
||||
"sr-primitives/std",
|
||||
"rstd/std",
|
||||
]
|
||||
@@ -0,0 +1,289 @@
|
||||
// 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 Collective Flip 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. Low-influence randomness can be useful when defending against relatively weak
|
||||
//! adversaries.
|
||||
//!
|
||||
//! ## Public Functions
|
||||
//!
|
||||
//! See the [`Module`](./struct.Module.html) struct for details of publicly available functions.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! ### Prerequisites
|
||||
//!
|
||||
//! Import the Randomness Collective Flip 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};
|
||||
//!
|
||||
//! pub 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_randomness_collective_flip::Module<T>>::random_seed();
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! # fn main() { }
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use rstd::{prelude::*, convert::TryInto};
|
||||
use sr_primitives::traits::Hash;
|
||||
use support::{decl_module, decl_storage};
|
||||
use safe_mix::TripletMix;
|
||||
use codec::Encode;
|
||||
use system::Trait;
|
||||
|
||||
const RANDOM_MATERIAL_LEN: u32 = 81;
|
||||
|
||||
fn block_number_to_index<T: Trait>(block_number: T::BlockNumber) -> usize {
|
||||
// on_initialize is called on the first block after genesis
|
||||
let index = (block_number - 1.into()) % RANDOM_MATERIAL_LEN.into();
|
||||
index.try_into().ok().expect("Something % 81 is always smaller than usize; qed")
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
fn on_initialize(block_number: T::BlockNumber) {
|
||||
let parent_hash = <system::Module<T>>::parent_hash();
|
||||
|
||||
<RandomMaterial<T>>::mutate(|ref mut values| if values.len() < RANDOM_MATERIAL_LEN as usize {
|
||||
values.push(parent_hash)
|
||||
} else {
|
||||
let index = block_number_to_index::<T>(block_number);
|
||||
values[index] = parent_hash;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as RandomnessCollectiveFlip {
|
||||
/// Series of block headers from the last 81 blocks that acts as random seed material. This
|
||||
/// is arranged as a ring buffer with `block_number % 81` being the index into the `Vec` of
|
||||
/// the oldest hash.
|
||||
RandomMaterial get(random_material): 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 far in advance by anyone
|
||||
/// observing the chain. Any block producer has significant influence over their block hashes
|
||||
/// bounded only by their computational resources. Our low-influence function reduces the actual
|
||||
/// block producer's influence over the randomness, but increases the influence of small
|
||||
/// colluding groups of recent block producers.
|
||||
///
|
||||
/// Some BABE blocks have VRF outputs where the block producer has exactly one bit of influence,
|
||||
/// either they make the block or they do not make the block and thus someone else makes the
|
||||
/// next block. Yet, this randomness is not fresh in all BABE blocks.
|
||||
///
|
||||
/// 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-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 block_number = <system::Module<T>>::block_number();
|
||||
let index = block_number_to_index::<T>(block_number);
|
||||
|
||||
let hash_series = <RandomMaterial<T>>::get();
|
||||
if !hash_series.is_empty() {
|
||||
// Always the case after block 1 is initialised.
|
||||
hash_series.iter()
|
||||
.cycle()
|
||||
.skip(index)
|
||||
.take(RANDOM_MATERIAL_LEN as usize)
|
||||
.enumerate()
|
||||
.map(|(i, h)| (i as i8, subject, h).using_encoded(T::Hashing::hash))
|
||||
.triplet_mix()
|
||||
} else {
|
||||
T::Hash::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::{H256, Blake2Hasher};
|
||||
use sr_primitives::{Perbill, traits::{BlakeTwo256, OnInitialize, Header as _, IdentityLookup}, testing::Header};
|
||||
use support::{impl_outer_origin, parameter_types};
|
||||
use runtime_io::with_externalities;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Test;
|
||||
|
||||
impl_outer_origin! {
|
||||
pub enum Origin for Test {}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
pub const MaximumBlockWeight: u32 = 1024;
|
||||
pub const MaximumBlockLength: u32 = 2 * 1024;
|
||||
pub const AvailableBlockRatio: Perbill = Perbill::one();
|
||||
}
|
||||
|
||||
impl system::Trait for Test {
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Call = ();
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = u64;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type WeightMultiplierUpdate = ();
|
||||
type Event = ();
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type MaximumBlockWeight = MaximumBlockWeight;
|
||||
type AvailableBlockRatio = AvailableBlockRatio;
|
||||
type MaximumBlockLength = MaximumBlockLength;
|
||||
type Version = ();
|
||||
}
|
||||
|
||||
type System = system::Module<Test>;
|
||||
type Randomness = Module<Test>;
|
||||
|
||||
fn new_test_ext() -> runtime_io::TestExternalities<Blake2Hasher> {
|
||||
let t = system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
||||
t.into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_number_to_index() {
|
||||
for i in 1 .. 1000 {
|
||||
assert_eq!((i - 1) as usize % 81, block_number_to_index::<Test>(i));
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_blocks(blocks: u64) {
|
||||
let mut parent_hash = System::parent_hash();
|
||||
|
||||
for i in 1 .. (blocks + 1) {
|
||||
System::initialize(&i, &parent_hash, &Default::default(), &Default::default());
|
||||
Randomness::on_initialize(i);
|
||||
|
||||
let header = System::finalize();
|
||||
parent_hash = header.hash();
|
||||
System::set_block_number(*header.number());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_material_parital() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
let genesis_hash = System::parent_hash();
|
||||
|
||||
setup_blocks(38);
|
||||
|
||||
let random_material = Randomness::random_material();
|
||||
|
||||
assert_eq!(random_material.len(), 38);
|
||||
assert_eq!(random_material[0], genesis_hash);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_material_filled() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
let genesis_hash = System::parent_hash();
|
||||
|
||||
setup_blocks(81);
|
||||
|
||||
let random_material = Randomness::random_material();
|
||||
|
||||
assert_eq!(random_material.len(), 81);
|
||||
assert_ne!(random_material[0], random_material[1]);
|
||||
assert_eq!(random_material[0], genesis_hash);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_material_filled_twice() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
let genesis_hash = System::parent_hash();
|
||||
|
||||
setup_blocks(162);
|
||||
|
||||
let random_material = Randomness::random_material();
|
||||
|
||||
assert_eq!(random_material.len(), 81);
|
||||
assert_ne!(random_material[0], random_material[1]);
|
||||
assert_ne!(random_material[0], genesis_hash);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
setup_blocks(162);
|
||||
|
||||
assert_eq!(System::block_number(), 162);
|
||||
assert_eq!(Randomness::random_seed(), Randomness::random_seed());
|
||||
assert_ne!(Randomness::random(b"random_1"), Randomness::random(b"random_2"));
|
||||
|
||||
let random = Randomness::random_seed();
|
||||
|
||||
assert_ne!(random, H256::zero());
|
||||
assert!(!Randomness::random_material().contains(&random));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@
|
||||
//!
|
||||
//! Import the System module and derive your module's configuration trait from the system trait.
|
||||
//!
|
||||
//! ### Example - Get random seed and extrinsic count for the current block
|
||||
//! ### Example - Get extrinsic count and parent hash for the current block
|
||||
//!
|
||||
//! ```
|
||||
//! use support::{decl_module, dispatch::Result};
|
||||
@@ -77,8 +77,8 @@
|
||||
//! pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
//! pub fn system_module_example(origin) -> Result {
|
||||
//! let _sender = ensure_signed(origin)?;
|
||||
//! let _random_seed = <system::Module<T>>::random_seed();
|
||||
//! let _extrinsic_count = <system::Module<T>>::extrinsic_count();
|
||||
//! let _parent_hash = <system::Module<T>>::parent_hash();
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
@@ -114,7 +114,6 @@ use support::{
|
||||
decl_module, decl_event, decl_storage, decl_error, storage, Parameter,
|
||||
traits::{Contains, Get},
|
||||
};
|
||||
use safe_mix::TripletMix;
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
#[cfg(any(feature = "std", test))]
|
||||
@@ -389,9 +388,6 @@ 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>;
|
||||
/// 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(|_| 1.into()): T::BlockNumber;
|
||||
/// Hash of the previous block.
|
||||
@@ -641,12 +637,6 @@ impl<T: Trait> Module<T> {
|
||||
<ParentHash<T>>::put(parent_hash);
|
||||
<BlockHash<T>>::insert(*number - One::one(), parent_hash);
|
||||
<ExtrinsicsRoot<T>>::put(txs_root);
|
||||
<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();
|
||||
EventCount::kill();
|
||||
<EventTopics<T>>::remove_prefix(&());
|
||||
@@ -736,69 +726,6 @@ impl<T: Trait> Module<T> {
|
||||
/// Return the chain's current runtime version.
|
||||
pub fn runtime_version() -> RuntimeVersion { T::Version::get() }
|
||||
|
||||
/// 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:
|
||||
///
|
||||
/// - 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-influnce 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.
|
||||
pub fn inc_account_nonce(who: &T::AccountId) {
|
||||
<AccountNonce<T>>::insert(who, Self::account_nonce(who) + T::Index::one());
|
||||
|
||||
Reference in New Issue
Block a user