Przeglądaj źródła

council - skeleton

ondratra 4 lat temu
rodzic
commit
d5a2c0e3c3

+ 1 - 0
Cargo.toml

@@ -6,6 +6,7 @@ members = [
 	"runtime-modules/proposals/discussion",
 	"runtime-modules/common",
 	"runtime-modules/content-working-group",
+	"runtime-modules/council",
 	"runtime-modules/forum",
 	"runtime-modules/governance",
 	"runtime-modules/hiring",

+ 49 - 0
runtime-modules/council/Cargo.toml

@@ -0,0 +1,49 @@
+[package]
+name = 'substrate-council-module'
+version = '1.0.0'
+authors = ['Joystream contributors']
+edition = '2018'
+
+[dependencies]
+codec = { package = 'parity-scale-codec', version = '1.0.0', default-features = false, features = ['derive'] }
+serde = { version = '1.0.101', optional = true}
+
+[dependencies.srml-support]
+default_features = false
+git = 'https://github.com/paritytech/substrate.git'
+package = 'srml-support'
+rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
+
+[dependencies.system]
+default_features = false
+git = 'https://github.com/paritytech/substrate.git'
+package = 'srml-system'
+rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
+
+[dependencies.sr-primitives]
+default_features = false
+git = 'https://github.com/paritytech/substrate.git'
+package = 'sr-primitives'
+rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
+
+[dependencies.primitives]
+default_features = false
+git = 'https://github.com/paritytech/substrate.git'
+package = 'substrate-primitives'
+rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
+
+[dev-dependencies]
+runtime-io = { package = 'sr-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'}
+
+[features]
+default = ['std']
+std = [
+    'codec/std',
+    'primitives/std',
+    'runtime-io/std',
+    'serde',
+    'sr-primitives/std',
+    'srml-support/std',
+    'system/std',
+]
+

+ 159 - 0
runtime-modules/council/src/lib.rs

@@ -0,0 +1,159 @@
+// TODO: module documentation
+
+/////////////////// Configuration //////////////////////////////////////////////
+#![cfg_attr(not(feature = "std"), no_std)]
+
+// used dependencies
+use codec::{Codec, Decode, Encode};
+use sr_primitives::traits::{MaybeSerialize, Member, One, SimpleArithmetic};
+use srml_support::{decl_error, decl_event, decl_module, decl_storage, traits::Get, Parameter};
+use std::marker::PhantomData;
+use system::ensure_signed;
+
+// declared modules
+mod mock;
+mod tests;
+
+/////////////////// Data Structures ////////////////////////////////////////////
+
+#[derive(Encode, Decode, PartialEq, Eq, Debug)]
+pub enum CouncilStage {
+    Void,
+}
+
+impl Default for CouncilStage {
+    fn default() -> CouncilStage {
+        CouncilStage::Void
+    }
+}
+
+
+/////////////////// Trait, Storage, Errors, and Events /////////////////////////
+
+pub trait Trait: system::Trait {
+    /// The overarching event type.
+    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
+
+    type Tmp: Parameter // needed to provide some parameter to event
+        + Member
+        + SimpleArithmetic
+        + Codec
+        + Default
+        + Copy
+        + MaybeSerialize
+        + PartialEq;
+
+    fn is_super_user(account_id: &<Self as system::Trait>::AccountId) -> bool;
+}
+
+decl_storage! {
+    trait Store for Module<T: Trait> as Referendum {
+        /// Current referendum stage
+        pub Stage get(stage) config(): (CouncilStage, T::BlockNumber);
+    }
+}
+
+decl_event! {
+    pub enum Event<T>
+    where
+        <T as Trait>::Tmp
+    {
+        /// New council was elected
+        ElectionCycleStarted(Tmp),
+    }
+}
+
+decl_error! {
+    #[derive(Copy)]
+    /// Referendum errors
+    pub enum Error {
+        /// Origin doesn't correspond to any superuser
+        OriginNotSuperUser,
+    }
+}
+
+impl From<system::Error> for Error {
+    fn from(error: system::Error) -> Self {
+        match error {
+            system::Error::Other(msg) => Error::Other(msg),
+            system::Error::RequireRootOrigin => Error::OriginNotSuperUser,
+            _ => Error::Other(error.into()),
+        }
+    }
+}
+
+/////////////////// Module definition and implementation ///////////////////////
+
+decl_module! {
+    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
+        /// Predefined errors
+        type Error = Error;
+
+        /// Setup events
+        fn deposit_event() = default;
+
+        /////////////////// Lifetime ///////////////////////////////////////////
+
+        // start new council election period
+        pub fn start_election_cycle(origin) -> Result<(), Error> {
+            // ensure action can be started
+            EnsureChecks::<T>::can_start_election_cycle(origin)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            // update state
+            Mutations::<T>::start_election_cycle();
+
+            // emit event
+            Self::deposit_event(RawEvent::ElectionCycleStarted(1.into())); // TODO
+
+            Ok(())
+        }
+    }
+}
+
+/////////////////// Mutations //////////////////////////////////////////////////
+
+struct Mutations<T: Trait> {
+    _dummy: PhantomData<T>, // 0-sized data meant only to bound generic parameters
+}
+
+impl<T: Trait> Mutations<T> {
+    fn start_election_cycle() -> () {
+
+    }
+}
+
+/////////////////// Ensure checks //////////////////////////////////////////////
+
+struct EnsureChecks<T: Trait> {
+    _dummy: PhantomData<T>, // 0-sized data meant only to bound generic parameters
+}
+
+impl<T: Trait> EnsureChecks<T> {
+    /////////////////// Common checks //////////////////////////////////////////
+
+    fn ensure_super_user(origin: T::Origin) -> Result<T::AccountId, Error> {
+        let account_id = ensure_signed(origin)?;
+
+        // ensure superuser requested action
+        if !T::is_super_user(&account_id) {
+            return Err(Error::OriginNotSuperUser);
+        }
+
+        Ok(account_id)
+    }
+
+    /////////////////// Action checks //////////////////////////////////////////
+
+    fn can_start_election_cycle(
+        origin: T::Origin,
+    ) -> Result<(), Error> {
+        // ensure superuser requested action
+        Self::ensure_super_user(origin)?;
+
+        Ok(())
+    }
+}

+ 165 - 0
runtime-modules/council/src/mock.rs

@@ -0,0 +1,165 @@
+#![cfg(test)]
+
+/////////////////// Configuration //////////////////////////////////////////////
+use crate::{Error, Event, Module, CouncilStage, GenesisConfig, Trait};
+
+use primitives::H256;
+use runtime_io;
+use sr_primitives::{
+    testing::Header,
+    traits::{BlakeTwo256, IdentityLookup},
+    Perbill,
+};
+use srml_support::{impl_outer_event, impl_outer_origin, parameter_types, StorageValue, StorageMap};
+use std::marker::PhantomData;
+use system::RawOrigin;
+use codec::{Encode};
+
+pub const USER_ADMIN: u64 = 1;
+pub const USER_REGULAR: u64 = 2;
+
+/////////////////// Runtime and Instances //////////////////////////////////////
+// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Runtime;
+
+// module instances
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Instance0;
+
+parameter_types! {
+    pub const MaxReferendumOptions: u64 = 10;
+    pub const VoteStageDuration: u64 = 5;
+    pub const RevealStageDuration: u64 = 5;
+    pub const MinimumStake: u64 = 10000;
+}
+
+impl Trait for Runtime {
+    type Event = TestEvent;
+
+    type Tmp = u64;
+
+    fn is_super_user(account_id: &<Self as system::Trait>::AccountId) -> bool {
+        *account_id == USER_ADMIN
+    }
+}
+
+/////////////////// Module implementation //////////////////////////////////////
+
+impl_outer_origin! {
+    pub enum Origin for Runtime {}
+}
+
+mod event_mod {
+    pub use crate::Event;
+}
+
+impl_outer_event! {
+    pub enum TestEvent for Runtime {
+        event_mod<T>,
+    }
+}
+
+parameter_types! {
+    pub const BlockHashCount: u64 = 250;
+    pub const MaximumBlockWeight: u32 = 1024;
+    pub const MaximumBlockLength: u32 = 2 * 1024;
+    pub const AvailableBlockRatio: Perbill = Perbill::one();
+    pub const MinimumPeriod: u64 = 5;
+}
+
+impl system::Trait for Runtime {
+    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 Event = TestEvent;
+    type BlockHashCount = BlockHashCount;
+    type MaximumBlockWeight = MaximumBlockWeight;
+    type MaximumBlockLength = MaximumBlockLength;
+    type AvailableBlockRatio = AvailableBlockRatio;
+    type Version = ();
+}
+
+/////////////////// Data structures ////////////////////////////////////////////
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub enum OriginType<AccountId> {
+    Signed(AccountId),
+    //Inherent, <== did not find how to make such an origin yet
+    Root,
+}
+
+/////////////////// Utility mocks //////////////////////////////////////////////
+
+pub fn default_genesis_config() -> GenesisConfig<Runtime> {
+    GenesisConfig::<Runtime> {
+        stage: (CouncilStage::default(), 0),
+    }
+}
+
+pub fn build_test_externalities(
+    config: GenesisConfig<Runtime>,
+) -> runtime_io::TestExternalities {
+    let mut t = system::GenesisConfig::default()
+        .build_storage::<Runtime>()
+        .unwrap();
+
+    config.assimilate_storage(&mut t).unwrap();
+
+    t.into()
+}
+
+pub struct InstanceMockUtils<T: Trait> {
+    _dummy: PhantomData<T>, // 0-sized data meant only to bound generic parameters
+}
+
+impl<T: Trait> InstanceMockUtils<T> {
+
+    pub fn mock_origin(origin: OriginType<T::AccountId>) -> T::Origin {
+        match origin {
+            OriginType::Signed(account_id) => T::Origin::from(RawOrigin::Signed(account_id)),
+            _ => panic!("not implemented"),
+        }
+    }
+
+    pub fn origin_access<F: Fn(OriginType<T::AccountId>) -> ()>(
+        origin_account_id: T::AccountId,
+        f: F,
+    ) {
+        let config = default_genesis_config();
+
+        build_test_externalities(config).execute_with(|| {
+            let origin = OriginType::Signed(origin_account_id);
+
+            f(origin)
+        });
+    }
+}
+
+/////////////////// Mocks of Module's actions //////////////////////////////////
+
+pub struct InstanceMocks<T: Trait> {
+    _dummy: PhantomData<T>, // 0-sized data meant only to bound generic parameters
+}
+
+impl<T: Trait> InstanceMocks<T> {
+
+    pub fn start_election_cycle(
+        origin: OriginType<T::AccountId>,
+        expected_result: Result<(), Error>,
+    ) -> () {
+        // check method returns expected result
+        assert_eq!(
+            Module::<T>::start_election_cycle(InstanceMockUtils::<T>::mock_origin(origin),),
+            expected_result,
+        );
+    }
+}

+ 18 - 0
runtime-modules/council/src/tests.rs

@@ -0,0 +1,18 @@
+#![cfg(test)]
+
+use super::{Error, Trait};
+use crate::mock::*;
+
+type Mocks = InstanceMocks<Runtime>;
+type MockUtils = InstanceMockUtils<Runtime>;
+
+/////////////////// Lifetime - election cycle start ////////////////////////////
+#[test]
+#[ignore]
+fn election_() {
+    MockUtils::origin_access(USER_ADMIN, |origin| {
+        let options = vec![0];
+
+        Mocks::start_election_cycle(origin, Ok(()));
+    });
+}

+ 1 - 1
runtime-modules/referendum/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'substrate-referendum-module'
-version = '2.0.0'
+version = '1.0.0'
 authors = ['Joystream contributors']
 edition = '2018'