mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-23 18:55:48 +00:00
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>
This commit is contained in:
committed by
Sergei Pepyakin
parent
b42e37589e
commit
adba89913e
@@ -1,7 +1,6 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(feature = "strict", deny(warnings))]
|
#![cfg_attr(feature = "strict", deny(warnings))]
|
||||||
|
|
||||||
#![feature(alloc)]
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use alloc::slice;
|
use alloc::slice;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
//! Primitives for GRANDPA integration, suitable for WASM compilation.
|
//! Primitives for GRANDPA integration, suitable for WASM compilation.
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
/// Initialize a key-value collection from array.
|
/// Initialize a key-value collection from array.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#![cfg_attr(not(feature = "std"), feature(lang_items))]
|
#![cfg_attr(not(feature = "std"), feature(lang_items))]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))]
|
#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))]
|
||||||
#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
|
#![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(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.")]
|
#![cfg_attr(not(feature = "std"), doc = "Substrate's runtime standard library as compiled without Rust's standard library.")]
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
|
#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
|
#![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(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.")]
|
#![cfg_attr(not(feature = "std"), doc = "Substrate's runtime standard library as compiled without Rust's standard library.")]
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
//! Utility functions to interact with Substrate's Base-16 Modified Merkle Patricia tree ("trie").
|
//! 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"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod node_header;
|
mod node_header;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.
|
//! 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"), 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.
|
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
||||||
#![recursion_limit="256"]
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
use runtime_primitives::{
|
use runtime_primitives::{
|
||||||
generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature
|
generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("node"),
|
spec_name: create_runtime_str!("node"),
|
||||||
impl_name: create_runtime_str!("substrate-node"),
|
impl_name: create_runtime_str!("substrate-node"),
|
||||||
authoring_version: 10,
|
authoring_version: 10,
|
||||||
spec_version: 71,
|
spec_version: 72,
|
||||||
impl_version: 71,
|
impl_version: 72,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ mod tests {
|
|||||||
header: Header {
|
header: Header {
|
||||||
parent_hash: [69u8; 32].into(),
|
parent_hash: [69u8; 32].into(),
|
||||||
number: 1,
|
number: 1,
|
||||||
state_root: hex!("4c10fddf15e63c91ff2aa13ab3a9b7f6b19938d533829489e72ba40278a08fac").into(),
|
state_root: hex!("ac2840371d51ff2e036c8fc05af7313b7a030f735c38b2f03b94cbe87bfbb7c9").into(),
|
||||||
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
|
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
|
||||||
digest: Digest { logs: vec![], },
|
digest: Digest { logs: vec![], },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
//! Support code for the runtime.
|
//! Support code for the runtime.
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitmask;
|
extern crate bitmask;
|
||||||
|
|||||||
@@ -302,8 +302,9 @@ decl_storage! {
|
|||||||
pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash;
|
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).
|
/// Extrinsics data for the current block (maps an extrinsic's index to its data).
|
||||||
ExtrinsicData get(extrinsic_data): map u32 => Vec<u8>;
|
ExtrinsicData get(extrinsic_data): map u32 => Vec<u8>;
|
||||||
/// Random seed of the current block.
|
/// Series of block headers from the last 81 blocks that acts as random seed material. This is arranged as a
|
||||||
RandomSeed get(random_seed) build(|_| T::Hash::default()): T::Hash;
|
/// 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`.
|
/// The current block number being processed. Set by `execute_block`.
|
||||||
Number get(block_number) build(|_| T::BlockNumber::sa(1u64)): T::BlockNumber;
|
Number get(block_number) build(|_| T::BlockNumber::sa(1u64)): T::BlockNumber;
|
||||||
/// Hash of the previous block.
|
/// Hash of the previous block.
|
||||||
@@ -395,13 +396,17 @@ impl<T: Trait> Module<T> {
|
|||||||
<ParentHash<T>>::put(parent_hash);
|
<ParentHash<T>>::put(parent_hash);
|
||||||
<BlockHash<T>>::insert(*number - One::one(), parent_hash);
|
<BlockHash<T>>::insert(*number - One::one(), parent_hash);
|
||||||
<ExtrinsicsRoot<T>>::put(txs_root);
|
<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();
|
<Events<T>>::kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove temporary "environment" entries in storage.
|
/// Remove temporary "environment" entries in storage.
|
||||||
pub fn finalize() -> T::Header {
|
pub fn finalize() -> T::Header {
|
||||||
<RandomSeed<T>>::kill();
|
|
||||||
<ExtrinsicCount<T>>::kill();
|
<ExtrinsicCount<T>>::kill();
|
||||||
<AllExtrinsicsLen<T>>::kill();
|
<AllExtrinsicsLen<T>>::kill();
|
||||||
|
|
||||||
@@ -432,26 +437,13 @@ impl<T: Trait> Module<T> {
|
|||||||
<Digest<T>>::put(l);
|
<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.
|
/// Get the basic externalities for this module, useful for tests.
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
pub fn externalities() -> TestExternalities<Blake2Hasher> {
|
pub fn externalities() -> TestExternalities<Blake2Hasher> {
|
||||||
TestExternalities::new(map![
|
TestExternalities::new(map![
|
||||||
twox_128(&<BlockHash<T>>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(),
|
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(<Number<T>>::key()).to_vec() => T::BlockNumber::one().encode(),
|
||||||
twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode(),
|
twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode()
|
||||||
twox_128(<RandomSeed<T>>::key()).to_vec() => T::Hash::default().encode()
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,11 +467,54 @@ impl<T: Trait> Module<T> {
|
|||||||
<ParentHash<T>>::put(n);
|
<ParentHash<T>>::put(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the random seed to something in particular. Can be used as an alternative to
|
/// Get the basic random seed.
|
||||||
/// `initialize` for tests that don't need to bother with the other environment entries.
|
///
|
||||||
#[cfg(any(feature = "std", test))]
|
/// In general you won't want to use this, but rather `Self::random` which allows you to give a subject for the
|
||||||
pub fn set_random_seed(seed: T::Hash) {
|
/// random result and whose value will be independently low-influence random from any other such seeds.
|
||||||
<RandomSeed<T>>::put(seed);
|
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.
|
/// Increment a particular account's nonce by 1.
|
||||||
|
|||||||
Reference in New Issue
Block a user