Make Polkadot use the Substrate traity libraries (#105)

* Initial stuff.

* Various fixes.

* Fix tests.

* Fix another test

* Fix another test.

* Docs in polkadot runtime.

* Fix up ser/de tests.

* Update god keys

* Syntax

* Fix

* Merge remote-tracking branch 'origin/master' into gav-merge-runtime

* Permissions on init.sh

* Port-over the whitespace from @rphmeier

* Rename

* Merge branch 'master' into gav-merge-runtime

* Fix typo.

* Fix grumbles.

* Make more idiomatic.

* Move `Ed25519Signature` out of traits.
This commit is contained in:
Gav Wood
2018-04-05 17:13:12 +02:00
committed by Robert Habermeier
parent 6b83f11a11
commit 1d8a9a6dd3
60 changed files with 1335 additions and 3636 deletions
@@ -7,18 +7,22 @@ authors = ["Parity Technologies <admin@parity.io>"]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
substrate-runtime-system = { path = "../system", default_features = false }
[features]
default = ["std"]
std = [
"serde/std",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-system/std",
]
@@ -28,10 +28,15 @@ extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_runtime_primitives as primitives;
extern crate substrate_codec as codec;
extern crate substrate_runtime_system as system;
extern crate substrate_primitives;
use rstd::prelude::*;
use runtime_support::{storage, Parameter};
use runtime_support::storage::unhashed::StorageVec;
use primitives::traits::RefInto;
use substrate_primitives::bft::MisbehaviorReport;
pub const AUTHORITY_AT: &'static[u8] = b":auth:";
pub const AUTHORITY_COUNT: &'static[u8] = b":auth:len";
@@ -44,15 +49,18 @@ impl<S: codec::Slicable + Default> StorageVec for AuthorityStorageVec<S> {
pub const CODE: &'static [u8] = b":code";
pub trait Trait {
type SessionKey: Parameter + Default;
pub trait Trait: system::Trait {
type PublicAux: RefInto<Self::AccountId>;
type SessionKey: Parameter + Default;
}
decl_module! {
pub struct Module<T: Trait>;
pub enum Call where aux: T::PublicAux {
fn report_misbehavior(aux, report: MisbehaviorReport) = 0;
}
pub enum PrivCall {
fn set_code(new: Vec<u8>) = 0;
fn dummy() = 1;
}
}
@@ -67,7 +75,10 @@ impl<T: Trait> Module<T> {
storage::unhashed::put_raw(CODE, &new);
}
fn dummy() {}
/// Report some misbehaviour.
fn report_misbehavior(_aux: &T::PublicAux, _report: MisbehaviorReport) {
// TODO.
}
/// Set the current set of authorities' session keys.
///
@@ -85,6 +96,7 @@ impl<T: Trait> Module<T> {
#[cfg(any(feature = "std", test))]
pub struct GenesisConfig<T: Trait> {
pub authorities: Vec<T::SessionKey>,
pub code: Vec<u8>,
}
#[cfg(any(feature = "std", test))]
@@ -92,6 +104,7 @@ impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
authorities: vec![],
code: vec![],
}
}
}
@@ -103,9 +116,10 @@ impl<T: Trait> primitives::BuildExternalities for GenesisConfig<T>
use codec::{Slicable, KeyedVec};
let auth_count = self.authorities.len() as u32;
let mut r: runtime_io::TestExternalities = self.authorities.into_iter().enumerate().map(|(i, v)|
((i as u32).to_keyed_vec(b":auth:"), v.encode())
((i as u32).to_keyed_vec(AUTHORITY_AT), v.encode())
).collect();
r.insert(b":auth:len".to_vec(), auth_count.encode());
r.insert(AUTHORITY_COUNT.to_vec(), auth_count.encode());
r.insert(CODE.to_vec(), self.code);
r
}
}
@@ -584,6 +584,7 @@ mod tests {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = u64;
}
impl system::Trait for Test {
@@ -596,7 +597,6 @@ mod tests {
type Header = Header;
}
impl session::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
impl staking::Trait for Test {
@@ -611,6 +611,7 @@ mod tests {
pub fn new_test_ext(with_council: bool) -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
authorities: vec![],
}.build_externalities());
t.extend(session::GenesisConfig::<Test>{
@@ -345,6 +345,7 @@ mod tests {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = u64;
}
impl system::Trait for Test {
@@ -357,7 +358,6 @@ mod tests {
type Header = Header;
}
impl session::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
impl staking::Trait for Test {
@@ -371,6 +371,7 @@ mod tests {
fn new_test_ext() -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
authorities: vec![],
}.build_externalities());
t.extend(session::GenesisConfig::<Test>{
@@ -18,6 +18,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")] extern crate serde;
extern crate substrate_runtime_std as rstd;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_io as runtime_io;
@@ -41,11 +43,10 @@ extern crate substrate_runtime_session as session;
#[cfg(test)]
extern crate substrate_runtime_staking as staking;
#[cfg(feature = "std")] extern crate serde;
use rstd::prelude::*;
use rstd::marker::PhantomData;
use runtime_io::Hashing;
use runtime_support::StorageValue;
use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, Executable, MakePayment};
use codec::Slicable;
@@ -122,27 +123,29 @@ impl<
/// Apply outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block.
pub fn apply_extrinsic(utx: Block::Extrinsic) {
pub fn apply_extrinsic(uxt: Block::Extrinsic) {
// Verify the signature is good.
let tx = match utx.check() {
Ok(tx) => tx,
let xt = match uxt.check() {
Ok(xt) => xt,
Err(_) => panic!("All transactions should be properly signed"),
};
{
if xt.sender() != &Default::default() {
// check index
let expected_index = <system::Module<System>>::account_index(tx.sender());
assert!(tx.index() == &expected_index, "All transactions should have the correct nonce");
let expected_index = <system::Module<System>>::account_index(xt.sender());
assert!(xt.index() == &expected_index, "All transactions should have the correct nonce");
// increment nonce in storage
<system::Module<System>>::inc_account_index(tx.sender());
<system::Module<System>>::inc_account_index(xt.sender());
// pay any fees.
Payment::make_payment(xt.sender());
}
// pay any fees.
Payment::make_payment(tx.sender());
// decode parameters and dispatch
tx.apply();
xt.apply();
<system::ExtrinsicIndex<System>>::put(<system::ExtrinsicIndex<System>>::get() + 1u32);
}
fn final_checks(header: &System::Header) {
@@ -180,6 +183,7 @@ mod tests {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = u64;
}
impl system::Trait for Test {
@@ -192,7 +196,6 @@ mod tests {
type Header = Header;
}
impl session::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
impl staking::Trait for Test {
@@ -239,7 +242,7 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("9228e363883f4f5a01981985b5598d1a767e987eb3ccea017a0e14cac7acc79d").into(),
state_root: hex!("aa0cff04242e55fc780861b890aa8deba555f6ed95bd8fa575dfd80864f3b93e").into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
digest: Digest { logs: vec![], },
},
@@ -273,7 +276,7 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("93dde1251278e65430baf291337ba219bacfa9ad583c52513b12cf1974109a97").into(),
state_root: hex!("aa0cff04242e55fc780861b890aa8deba555f6ed95bd8fa575dfd80864f3b93e").into(),
extrinsics_root: [0u8; 32].into(),
digest: Digest { logs: vec![], },
},
@@ -86,7 +86,7 @@ pub struct UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
Signature: Member, // TODO: should be Option<Signature>
{
/// The actual extrinsic information.
pub extrinsic: Extrinsic<AccountId, Index, Call>,
@@ -94,6 +94,19 @@ pub struct UncheckedExtrinsic<AccountId, Index, Call, Signature> where
pub signature: Signature,
}
impl<AccountId, Index, Call, Signature> UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member + Default,
Index: Member,
Call: Member,
Signature: Member + Default,
{
/// Is this extrinsic signed?
pub fn is_signed(&self) -> bool {
// TODO: should be Option<Signature> and Option<AccountId>
self.signature != Signature::default() || self.extrinsic.signed != AccountId::default()
}
}
impl<AccountId, Index, Call, Signature> Slicable for UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member + Slicable,
Index: Member + Slicable,
@@ -145,21 +158,25 @@ impl<AccountId, Index, Call, Signature> fmt::Debug for UncheckedExtrinsic<Accoun
}
impl<AccountId, Index, Call, Signature> traits::Checkable for UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member,
AccountId: Member + Default,
Index: Member,
Call: Member,
Signature: Member + traits::Verify<Signer = AccountId>,
Signature: Member + Default + traits::Verify<Signer = AccountId>,
Extrinsic<AccountId, Index, Call>: Slicable
{
type Checked = CheckedExtrinsic<AccountId, Index, Call, Signature>;
fn check(self) -> Result<Self::Checked, Self> {
if ::codec::Slicable::using_encoded(&self.extrinsic, |msg|
self.signature.verify(msg, &self.extrinsic.signed)
) {
if !self.is_signed() {
Ok(CheckedExtrinsic(self))
} else {
Err(self)
if ::codec::Slicable::using_encoded(&self.extrinsic, |msg|
self.signature.verify(msg, &self.extrinsic.signed)
) {
Ok(CheckedExtrinsic(self))
} else {
Err(self)
}
}
}
}
@@ -186,6 +203,16 @@ where
pub fn signature(&self) -> &Signature {
&self.0.signature
}
/// Get a reference to the checked signature.
pub fn as_unchecked(&self) -> &UncheckedExtrinsic<AccountId, Index, Call, Signature> {
&self.0
}
/// Get a reference to the checked signature.
pub fn into_unchecked(self) -> UncheckedExtrinsic<AccountId, Index, Call, Signature> {
self.0
}
}
impl<AccountId, Index, Call, Signature> ops::Deref
@@ -34,7 +34,10 @@ extern crate substrate_runtime_support as runtime_support;
extern crate substrate_codec as codec;
extern crate substrate_primitives;
#[cfg(feature = "std")] use std::collections::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;
use substrate_primitives::hash::H512;
#[cfg(feature = "std")]
pub mod testing;
@@ -50,6 +53,26 @@ pub trait BuildExternalities {
fn build_externalities(self) -> BuiltExternalities;
}
/// Ed25519 signature verify.
#[derive(Eq, PartialEq, Clone, Default)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
pub struct Ed25519Signature(H512);
impl traits::Verify for Ed25519Signature {
type Signer = [u8; 32];
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool {
runtime_io::ed25519_verify(&(self.0).0, msg, &signer[..])
}
}
impl codec::Slicable for Ed25519Signature {
fn decode<I: codec::Input>(input: &mut I) -> Option<Self> { Some(Ed25519Signature(codec::Slicable::decode(input)?,)) }
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R { self.0.using_encoded(f) }
}
impl From<H512> for Ed25519Signature {
fn from(h: H512) -> Ed25519Signature {
Ed25519Signature(h)
}
}
#[macro_export]
macro_rules! __impl_outer_config_types {
($concrete:ident $config:ident $snake:ident $($rest:ident)*) => {
@@ -20,8 +20,7 @@ use rstd::prelude::*;
use rstd;
#[cfg(not(feature = "std"))] use runtime_io;
use substrate_primitives;
use codec::{Input, Slicable};
use substrate_primitives::hash::H512;
use codec::Slicable;
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{Zero, One, Bounded};
use rstd::ops::{Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
@@ -34,26 +33,6 @@ pub trait Verify {
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool;
}
/// Ed25519 signature verify.
#[derive(Eq, PartialEq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
pub struct Ed25519Signature(H512);
impl Verify for Ed25519Signature {
type Signer = [u8; 32];
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool {
::runtime_io::ed25519_verify(&(self.0).0, msg, &signer[..])
}
}
impl Slicable for Ed25519Signature {
fn decode<I: Input>(input: &mut I) -> Option<Self> { Some(Ed25519Signature(Slicable::decode(input)?,)) }
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R { self.0.using_encoded(f) }
}
impl From<H512> for Ed25519Signature {
fn from(h: H512) -> Ed25519Signature {
Ed25519Signature(h)
}
}
/// Simple payment making trait, operating on a single generic `AccountId` type.
pub trait MakePayment<AccountId> {
/// Make some sort of payment concerning `who`.
@@ -102,8 +81,18 @@ impl<T> Convert<T, T> for Identity {
fn convert(a: T) -> T { a }
}
pub trait MaybeEmpty {
fn is_empty(&self) -> bool;
}
impl<T: Default + PartialEq> MaybeEmpty for T {
fn is_empty(&self) -> bool {
*self == T::default()
}
}
pub trait HasPublicAux {
type PublicAux;
type PublicAux: MaybeEmpty;
}
pub trait RefInto<T> {
+3 -25
View File
@@ -44,8 +44,7 @@ use rstd::prelude::*;
use primitives::traits::{Zero, One, RefInto, Executable, Convert};
use runtime_support::{StorageValue, StorageMap};
pub trait Trait: consensus::Trait + system::Trait {
type PublicAux: RefInto<Self::AccountId>;
pub trait Trait: consensus::Trait {
type ConvertAccountIdToSessionKey: Convert<Self::AccountId, Self::SessionKey>;
}
@@ -162,28 +161,6 @@ pub struct GenesisConfig<T: Trait> {
pub validators: Vec<T::AccountId>,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> GenesisConfig<T> where T::AccountId: From<keyring::Keyring> {
pub fn simple() -> Self where T::AccountId: From<[u8; 32]> {
use primitives::traits::As;
use keyring::Keyring::*;
let three = [3u8; 32];
GenesisConfig {
session_length: T::BlockNumber::sa(2),
validators: vec![T::AccountId::from(One), T::AccountId::from(Two), T::AccountId::from(three)],
}
}
pub fn extended() -> Self {
use primitives::traits::As;
use keyring::Keyring::*;
GenesisConfig {
session_length: T::BlockNumber::sa(1),
validators: vec![T::AccountId::from(Alice), T::AccountId::from(Bob), T::AccountId::from(Charlie)],
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
@@ -224,6 +201,7 @@ mod tests {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = u64;
}
impl system::Trait for Test {
@@ -236,7 +214,6 @@ mod tests {
type Header = Header;
}
impl Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
@@ -247,6 +224,7 @@ mod tests {
fn new_test_ext() -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
authorities: vec![1, 2, 3],
}.build_externalities());
t.extend(GenesisConfig::<Test>{
@@ -685,6 +685,7 @@ mod tests {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = u64;
}
impl system::Trait for Test {
@@ -697,7 +698,6 @@ mod tests {
type Header = Header;
}
impl session::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
impl Trait for Test {
@@ -708,6 +708,7 @@ mod tests {
fn new_test_ext(session_length: u64, sessions_per_era: u64, current_era: u64, monied: bool) -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
authorities: vec![],
}.build_externalities());
t.extend(session::GenesisConfig::<Test>{
+19 -1
View File
@@ -67,6 +67,7 @@ decl_storage! {
pub AccountIndex get(account_index): b"sys:non" => default map [ T::AccountId => T::Index ];
pub BlockHash get(block_hash): b"sys:old" => required map [ T::BlockNumber => T::Hash ];
pub ExtrinsicIndex get(extrinsic_index): b"sys:xti" => required u32;
RandomSeed get(random_seed): b"sys:rnd" => required T::Hash;
// The current block number being processed. Set by `execute_block`.
Number get(block_number): b"sys:num" => required T::BlockNumber;
@@ -83,11 +84,13 @@ impl<T: Trait> Module<T> {
<ParentHash<T>>::put(parent_hash);
<ExtrinsicsRoot<T>>::put(txs_root);
<RandomSeed<T>>::put(Self::calculate_random());
<ExtrinsicIndex<T>>::put(0);
}
/// Remove temporary "environment" entries in storage.
pub fn finalise() -> T::Header {
<RandomSeed<T>>::kill();
<ExtrinsicIndex<T>>::kill();
let number = <Number<T>>::take();
let parent_hash = <ParentHash<T>>::take();
@@ -145,6 +148,20 @@ impl<T: Trait> Module<T> {
<Number<T>>::put(n);
}
/// Set the parent hash number to something in particular. Can be used as an alternative to
/// `initialise` for tests that don't need to bother with the other environment entries.
#[cfg(any(feature = "std", test))]
pub fn set_parent_hash(n: T::Hash) {
<ParentHash<T>>::put(n);
}
/// Set the random seed to something in particular. Can be used as an alternative to
/// `initialise` for tests that don't need to bother with the other environment entries.
#[cfg(any(feature = "std", test))]
pub fn set_random_seed(n: T::Hash) {
<RandomSeed<T>>::put(n);
}
/// Increment a particular account's nonce by 1.
pub fn inc_account_index(who: &T::AccountId) {
<AccountIndex<T>>::insert(who, Self::account_index(who) + T::Index::one());
@@ -172,7 +189,8 @@ impl<T: Trait> primitives::BuildExternalities for GenesisConfig<T>
twox_128(&<BlockHash<T>>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(),
twox_128(<Number<T>>::key()).to_vec() => 1u64.encode(),
twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode(),
twox_128(<RandomSeed<T>>::key()).to_vec() => [0u8; 32].encode()
twox_128(<RandomSeed<T>>::key()).to_vec() => [0u8; 32].encode(),
twox_128(<ExtrinsicIndex<T>>::key()).to_vec() => [0u8; 4].encode()
]
}
}
@@ -7,9 +7,12 @@ authors = ["Parity Technologies <admin@parity.io>"]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-system = { path = "../system", default_features = false }
[dev-dependencies]
substrate-runtime-io = { path = "../../runtime-io", default_features = true }
@@ -18,8 +21,11 @@ substrate-runtime-io = { path = "../../runtime-io", default_features = true }
default = ["std"]
std = [
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"serde/std",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-system/std",
]
@@ -18,22 +18,25 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg_attr(test, macro_use)]
#[cfg_attr(any(feature = "std", test), macro_use)]
extern crate substrate_runtime_std as rstd;
#[macro_use]
extern crate substrate_runtime_support as runtime_support;
#[cfg(test)]
#[cfg(any(feature = "std", test))]
extern crate substrate_runtime_io as runtime_io;
#[cfg(test)]
extern crate substrate_primitives;
extern crate substrate_runtime_primitives as runtime_primitives;
extern crate substrate_runtime_system as system;
extern crate substrate_codec as codec;
use runtime_support::{StorageValue, Parameter};
use runtime_primitives::traits::HasPublicAux;
use runtime_primitives::traits::{HasPublicAux, Executable, MaybeEmpty};
pub trait Trait: HasPublicAux {
pub trait Trait: HasPublicAux + system::Trait {
type Value: Parameter + Default;
}
@@ -45,8 +48,11 @@ decl_module! {
}
decl_storage! {
pub trait Store for Module<T: Trait>;
trait Store for Module<T: Trait>;
pub Now get(now): b"tim:val" => required T::Value;
// Did the timestamp get updated in this block?
DidUpdate: b"tim:did" => default bool;
}
impl<T: Trait> Module<T> {
@@ -55,8 +61,36 @@ impl<T: Trait> Module<T> {
}
/// Set the current time.
fn set(_aux: &T::PublicAux, now: T::Value) {
fn set(aux: &T::PublicAux, now: T::Value) {
assert!(aux.is_empty());
assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block");
assert!(<system::Module<T>>::extrinsic_index() == 0, "Timestamp must be first extrinsic in the block");
<Self as Store>::Now::put(now);
<Self as Store>::DidUpdate::put(true);
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
assert!(<Self as Store>::DidUpdate::take(), "Timestamp must be updated once in the block");
}
}
#[cfg(any(feature = "std", test))]
#[derive(Default)]
pub struct GenesisConfig<T: Trait> {
pub now: T::Value,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> runtime_primitives::BuildExternalities for GenesisConfig<T>
{
fn build_externalities(self) -> runtime_primitives::BuiltExternalities {
use runtime_io::twox_128;
use codec::Slicable;
map![
twox_128(<Now<T>>::key()).to_vec() => self.now.encode()
]
}
}
@@ -64,25 +98,35 @@ impl<T: Trait> Module<T> {
mod tests {
use super::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::Joiner;
use runtime_io::with_externalities;
use runtime_support::storage::StorageValue;
use substrate_primitives::H256;
use runtime_primitives::BuildExternalities;
use runtime_primitives::traits::{HasPublicAux};
use runtime_primitives::testing::{Digest, Header};
struct TraitImpl;
impl HasPublicAux for TraitImpl {
pub struct Test;
impl HasPublicAux for Test {
type PublicAux = u64;
}
impl Trait for TraitImpl {
impl system::Trait for Test {
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = runtime_io::BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Header = Header;
}
impl Trait for Test {
type Value = u64;
}
type Timestamp = Module<TraitImpl>;
type Timestamp = Module<Test>;
#[test]
fn timestamp_works() {
let mut t: TestExternalities = map![
twox_128(<Timestamp as Store>::Now::key()).to_vec() => vec![].and(&42u64)
];
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(GenesisConfig::<Test> { now: 42 }.build_externalities());
with_externalities(&mut t, || {
assert_eq!(<Timestamp as Store>::Now::get(), 42);