Browse Source

Merge branch 'proposals_v2' into proposals_v2_iteration7

# Conflicts:
#	runtime-modules/proposals/engine/src/types/stakes.rs
Shamil Gadelshin 5 years ago
parent
commit
19c09c607e

+ 1 - 1
.travis.yml

@@ -1,7 +1,7 @@
 language: rust
 
 rust:
-  - 1.41.1
+  - 1.42.0
 # Caching saves a lot of time but often causes stalled builds...
 # disabled for now
 # look into solution here: https://levans.fr/rust_travis_cache.html

+ 1 - 1
runtime-modules/content-working-group/src/lib.rs

@@ -1191,7 +1191,7 @@ decl_module! {
             // Increment NextChannelId
             NextChannelId::<T>::mutate(|id| *id += <ChannelId<T> as One>::one());
 
-            /// CREDENTIAL STUFF ///
+            // CREDENTIAL STUFF //
 
             // Dial out to membership module and inform about new role as channe owner.
             let registered_role = <members::Module<T>>::register_role_on_member(owner, &member_in_role).is_ok();

+ 0 - 1
runtime-modules/membership/src/lib.rs

@@ -3,7 +3,6 @@
 
 pub mod genesis;
 pub mod members;
-pub mod origin_validator;
 pub mod role_types;
 
 pub(crate) mod mock;

+ 5 - 5
runtime-modules/proposals/codex/Cargo.toml

@@ -101,17 +101,17 @@ default_features = false
 package = 'substrate-proposals-discussion-module'
 path = '../discussion'
 
+[dependencies.common]
+default_features = false
+package = 'substrate-common-module'
+path = '../../common'
+
 [dev-dependencies.runtime-io]
 default_features = false
 git = 'https://github.com/paritytech/substrate.git'
 package = 'sr-io'
 rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
 
-[dev-dependencies.common]
-default_features = false
-package = 'substrate-common-module'
-path = '../../common'
-
 [dev-dependencies.governance]
 default_features = false
 package = 'substrate-governance-module'

+ 39 - 9
runtime-modules/proposals/codex/src/lib.rs

@@ -23,6 +23,7 @@ use rstd::vec::Vec;
 use srml_support::{decl_error, decl_module, decl_storage, ensure, print};
 use system::{ensure_root, RawOrigin};
 
+use common::origin_validator::ActorOriginValidator;
 use proposal_engine::ProposalParameters;
 
 /// 'Proposals codex' substrate module Trait
@@ -34,6 +35,13 @@ pub trait Trait:
 
     /// Defines max wasm code length of the runtime upgrade proposal.
     type RuntimeUpgradeWasmProposalMaxLength: Get<u32>;
+
+    /// Validates member id and origin combination
+    type MembershipOriginValidator: ActorOriginValidator<
+        Self::Origin,
+        MemberId<Self>,
+        Self::AccountId,
+    >;
 }
 use srml_support::traits::{Currency, Get};
 
@@ -45,7 +53,7 @@ pub type BalanceOf<T> =
 pub type NegativeImbalance<T> =
     <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
 
-use membership::origin_validator::MemberId;
+type MemberId<T> = <T as membership::members::Trait>::MemberId;
 
 decl_error! {
     pub enum Error {
@@ -123,24 +131,35 @@ decl_module! {
             text: Vec<u8>,
             stake_balance: Option<BalanceOf<T>>,
         ) {
+            let account_id = T::MembershipOriginValidator::ensure_actor_origin(origin, member_id.clone())?;
+
             let parameters = proposal_types::parameters::text_proposal::<T>();
 
             ensure!(!text.is_empty(), Error::TextProposalIsEmpty);
             ensure!(text.len() as u32 <=  T::TextProposalMaxLength::get(),
                 Error::TextProposalSizeExceeded);
 
-            let proposal_code = <Call<T>>::text_proposal(title.clone(), description.clone(), text);
+            <proposal_engine::Module<T>>::ensure_create_proposal_parameters_are_valid(
+                &parameters,
+                &title,
+                &description,
+                stake_balance,
+            )?;
 
-            let (cloned_origin1, cloned_origin2) =  Self::double_origin(origin);
+            <proposal_discussion::Module<T>>::ensure_can_create_thread(
+                &title,
+                member_id.clone(),
+            )?;
+
+            let proposal_code = <Call<T>>::text_proposal(title.clone(), description.clone(), text);
 
             let discussion_thread_id = <proposal_discussion::Module<T>>::create_thread(
-                cloned_origin1,
                 member_id,
                 title.clone(),
             )?;
 
             let proposal_id = <proposal_engine::Module<T>>::create_proposal(
-                cloned_origin2,
+                account_id,
                 member_id,
                 parameters,
                 title,
@@ -161,24 +180,35 @@ decl_module! {
             wasm: Vec<u8>,
             stake_balance: Option<BalanceOf<T>>,
         ) {
+            let account_id = T::MembershipOriginValidator::ensure_actor_origin(origin, member_id.clone())?;
+
             let parameters = proposal_types::parameters::upgrade_runtime::<T>();
 
             ensure!(!wasm.is_empty(), Error::RuntimeProposalIsEmpty);
             ensure!(wasm.len() as u32 <= T::RuntimeUpgradeWasmProposalMaxLength::get(),
                 Error::RuntimeProposalSizeExceeded);
 
-            let proposal_code = <Call<T>>::text_proposal(title.clone(), description.clone(), wasm);
+            <proposal_engine::Module<T>>::ensure_create_proposal_parameters_are_valid(
+                &parameters,
+                &title,
+                &description,
+                stake_balance,
+            )?;
 
-            let (cloned_origin1, cloned_origin2) =  Self::double_origin(origin);
+            <proposal_discussion::Module<T>>::ensure_can_create_thread(
+                &title,
+                member_id.clone(),
+            )?;
+
+            let proposal_code = <Call<T>>::text_proposal(title.clone(), description.clone(), wasm);
 
             let discussion_thread_id = <proposal_discussion::Module<T>>::create_thread(
-                cloned_origin1,
                 member_id,
                 title.clone(),
             )?;
 
             let proposal_id = <proposal_engine::Module<T>>::create_proposal(
-                cloned_origin2,
+                account_id,
                 member_id,
                 parameters,
                 title,

+ 2 - 2
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -100,7 +100,7 @@ impl proposal_engine::Trait for Test {
     type TitleMaxLength = TitleMaxLength;
     type DescriptionMaxLength = DescriptionMaxLength;
     type MaxActiveProposalLimit = MaxActiveProposalLimit;
-    type ProposalCode = crate::Call<Test>;
+    type DispatchableCallCode = crate::Call<Test>;
 }
 
 impl Default for crate::Call<Test> {
@@ -129,7 +129,6 @@ parameter_types! {
 
 impl proposal_discussion::Trait for Test {
     type Event = ();
-    type ThreadAuthorOriginValidator = ();
     type PostAuthorOriginValidator = ();
     type ThreadId = u32;
     type PostId = u32;
@@ -154,6 +153,7 @@ parameter_types! {
 impl crate::Trait for Test {
     type TextProposalMaxLength = TextProposalMaxLength;
     type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength;
+    type MembershipOriginValidator = ();
 }
 
 impl system::Trait for Test {

+ 32 - 24
runtime-modules/proposals/discussion/src/lib.rs

@@ -28,7 +28,9 @@ use srml_support::traits::Get;
 use types::{Post, Thread, ThreadCounter};
 
 use common::origin_validator::ActorOriginValidator;
-use membership::origin_validator::MemberId;
+use srml_support::dispatch::DispatchResult;
+
+type MemberId<T> = <T as membership::members::Trait>::MemberId;
 
 decl_event!(
     /// Proposals engine events
@@ -54,13 +56,6 @@ pub trait Trait: system::Trait + membership::members::Trait {
     /// Engine event type.
     type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
 
-    /// Validates thread author id and origin combination
-    type ThreadAuthorOriginValidator: ActorOriginValidator<
-        Self::Origin,
-        MemberId<Self>,
-        Self::AccountId,
-    >;
-
     /// Validates post author id and origin combination
     type PostAuthorOriginValidator: ActorOriginValidator<
         Self::Origin,
@@ -257,25 +252,10 @@ impl<T: Trait> Module<T> {
     /// Create the discussion thread. Cannot add more threads than 'predefined limit = MaxThreadInARowNumber'
     /// times in a row by the same author.
     pub fn create_thread(
-        origin: T::Origin,
         thread_author_id: MemberId<T>,
         title: Vec<u8>,
     ) -> Result<T::ThreadId, Error> {
-        T::ThreadAuthorOriginValidator::ensure_actor_origin(origin, thread_author_id.clone())?;
-
-        ensure!(!title.is_empty(), Error::EmptyTitleProvided);
-        ensure!(
-            title.len() as u32 <= T::ThreadTitleLengthLimit::get(),
-            Error::TitleIsTooLong
-        );
-
-        // get new 'threads in a row' counter for the author
-        let current_thread_counter = Self::get_updated_thread_counter(thread_author_id.clone());
-
-        ensure!(
-            current_thread_counter.counter as u32 <= T::MaxThreadInARowNumber::get(),
-            Error::MaxThreadInARowLimitExceeded
-        );
+        Self::ensure_can_create_thread(&title, thread_author_id.clone())?;
 
         let next_thread_count_value = Self::thread_count() + 1;
         let new_thread_id = next_thread_count_value;
@@ -286,6 +266,9 @@ impl<T: Trait> Module<T> {
             author_id: thread_author_id.clone(),
         };
 
+        // get new 'threads in a row' counter for the author
+        let current_thread_counter = Self::get_updated_thread_counter(thread_author_id.clone());
+
         // mutation
 
         let thread_id = T::ThreadId::from(new_thread_id);
@@ -310,4 +293,29 @@ impl<T: Trait> Module<T> {
         // else return new counter (set with 1 thread number)
         ThreadCounter::new(author_id)
     }
+
+    /// Ensures thread can be created.
+    /// Checks:
+    /// - title is valid
+    /// - max thread in a row by the same author
+    pub fn ensure_can_create_thread(
+        title: &[u8],
+        thread_author_id: MemberId<T>,
+    ) -> DispatchResult<Error> {
+        ensure!(!title.is_empty(), Error::EmptyTitleProvided);
+        ensure!(
+            title.len() as u32 <= T::ThreadTitleLengthLimit::get(),
+            Error::TitleIsTooLong
+        );
+
+        // get new 'threads in a row' counter for the author
+        let current_thread_counter = Self::get_updated_thread_counter(thread_author_id.clone());
+
+        ensure!(
+            current_thread_counter.counter as u32 <= T::MaxThreadInARowNumber::get(),
+            Error::MaxThreadInARowLimitExceeded
+        );
+
+        Ok(())
+    }
 }

+ 0 - 1
runtime-modules/proposals/discussion/src/tests/mock.rs

@@ -86,7 +86,6 @@ impl membership::members::Trait for Test {
 
 impl crate::Trait for Test {
     type Event = TestEvent;
-    type ThreadAuthorOriginValidator = ();
     type PostAuthorOriginValidator = ();
     type ThreadId = u32;
     type PostId = u32;

+ 2 - 29
runtime-modules/proposals/discussion/src/tests/mod.rs

@@ -81,23 +81,9 @@ impl DiscussionFixture {
         DiscussionFixture { title, ..self }
     }
 
-    fn with_author(self, author_id: u64) -> Self {
-        DiscussionFixture { author_id, ..self }
-    }
-
-    fn with_origin(self, origin: RawOrigin<u64>) -> Self {
-        DiscussionFixture {
-            origin: origin.into(),
-            ..self
-        }
-    }
-
     fn create_discussion_and_assert(&self, result: Result<u32, Error>) -> Option<u32> {
-        let create_discussion_result = Discussions::create_thread(
-            self.origin.clone().into(),
-            self.author_id,
-            self.title.clone(),
-        );
+        let create_discussion_result =
+            Discussions::create_thread(self.author_id, self.title.clone());
 
         assert_eq!(create_discussion_result, result);
 
@@ -413,16 +399,3 @@ fn add_discussion_thread_fails_because_of_max_thread_by_same_author_in_a_row_lim
         discussion_fixture.create_discussion_and_assert(Err(Error::MaxThreadInARowLimitExceeded));
     });
 }
-
-#[test]
-fn add_discussion_thread_fails_because_of_invalid_author_origin() {
-    initial_test_ext().execute_with(|| {
-        let discussion_fixture = DiscussionFixture::default().with_author(2);
-        discussion_fixture.create_discussion_and_assert(Err(Error::Other("Invalid author")));
-
-        let discussion_fixture = DiscussionFixture::default()
-            .with_origin(RawOrigin::Signed(3))
-            .with_author(2);
-        discussion_fixture.create_discussion_and_assert(Err(Error::Other("Invalid author")));
-    });
-}

+ 0 - 6
runtime-modules/proposals/engine/Cargo.toml

@@ -18,7 +18,6 @@ std = [
     'stake/std',
     'balances/std',
     'sr-primitives/std',
-    'governance/std',
     'membership/std',
     'common/std',
 
@@ -97,11 +96,6 @@ default_features = false
 package = 'substrate-common-module'
 path = '../../common'
 
-[dependencies.governance]
-default_features = false
-package = 'substrate-governance-module'
-path = '../../governance'
-
 [dev-dependencies]
 mockall = "0.6.0"
 

+ 175 - 164
runtime-modules/proposals/engine/src/lib.rs

@@ -20,12 +20,11 @@
 // TODO: Test StakingEventHandler
 // TODO: Test refund_proposal_stake()
 
-pub use types::CouncilManager;
 use types::FinalizedProposalData;
 use types::ProposalStakeManager;
 pub use types::{
-    ApprovedProposalStatus, FinalizationData, Proposal, ProposalDecisionStatus, ProposalParameters,
-    ProposalStatus, StakeData, StakingEventsHandler, VotingResults,
+    ActiveStake, ApprovedProposalStatus, FinalizationData, Proposal, ProposalDecisionStatus,
+    ProposalParameters, ProposalStatus, VotingResults,
 };
 pub use types::{BalanceOf, CurrencyOf, NegativeImbalance};
 pub use types::{DefaultStakeHandlerProvider, StakeHandler, StakeHandlerProvider};
@@ -42,21 +41,19 @@ use rstd::prelude::*;
 use sr_primitives::traits::{DispatchResult, Zero};
 use srml_support::traits::{Currency, Get};
 use srml_support::{
-    decl_error, decl_event, decl_module, decl_storage, ensure, Parameter, StorageDoubleMap,
+    decl_error, decl_event, decl_module, decl_storage, ensure, print, Parameter, StorageDoubleMap,
 };
 use system::{ensure_root, RawOrigin};
 
+use crate::types::ApprovedProposalData;
 use common::origin_validator::ActorOriginValidator;
-use membership::origin_validator::MemberId;
 use srml_support::dispatch::Dispatchable;
 
+type MemberId<T> = <T as membership::members::Trait>::MemberId;
+
 /// Proposals engine trait.
 pub trait Trait:
-    system::Trait
-    + timestamp::Trait
-    + stake::Trait
-    + membership::members::Trait
-    + governance::council::Trait
+    system::Trait + timestamp::Trait + stake::Trait + membership::members::Trait
 {
     /// Engine event type.
     type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
@@ -96,7 +93,7 @@ pub trait Trait:
     type MaxActiveProposalLimit: Get<u32>;
 
     /// Proposals executable code. Can be instantiated by external module Call enum members.
-    type ProposalCode: Parameter + Dispatchable<Origin = Self::Origin> + Default;
+    type DispatchableCallCode: Parameter + Dispatchable<Origin = Self::Origin> + Default;
 }
 
 decl_event!(
@@ -106,6 +103,8 @@ decl_event!(
         <T as Trait>::ProposalId,
         MemberId = MemberId<T>,
         <T as system::Trait>::BlockNumber,
+        <T as system::Trait>::AccountId,
+        <T as stake::Trait>::StakeId,
     {
     	/// Emits on proposal creation.
         /// Params:
@@ -117,7 +116,7 @@ decl_event!(
         /// Params:
         /// - Id of a updated proposal.
         /// - New proposal status
-        ProposalStatusUpdated(ProposalId, ProposalStatus<BlockNumber>),
+        ProposalStatusUpdated(ProposalId, ProposalStatus<BlockNumber, StakeId, AccountId>),
 
         /// Emits on voting for the proposal
         /// Params:
@@ -191,13 +190,13 @@ impl From<system::Error> for Error {
 decl_storage! {
     pub trait Store for Module<T: Trait> as ProposalEngine{
         /// Map proposal by its id.
-        pub Proposals get(fn proposals): map T::ProposalId => ProposalObject<T>;
+        pub Proposals get(fn proposals): map T::ProposalId => ProposalOf<T>;
 
         /// Count of all proposals that have been created.
         pub ProposalCount get(fn proposal_count): u32;
 
         /// Map proposal executable code by proposal id.
-        pub ProposalCode get(fn proposal_codes): map T::ProposalId =>  Vec<u8>;
+        pub DispatchableCallCode get(fn proposal_codes): map T::ProposalId =>  Vec<u8>;
 
         /// Count of active proposals.
         pub ActiveProposalCount get(fn active_proposal_count): u32;
@@ -236,7 +235,7 @@ decl_module! {
             ensure!(<Proposals<T>>::exists(proposal_id), Error::ProposalNotFound);
             let mut proposal = Self::proposals(proposal_id);
 
-            ensure!(proposal.status == ProposalStatus::Active, Error::ProposalFinalized);
+            ensure!(matches!(proposal.status, ProposalStatus::Active{..}), Error::ProposalFinalized);
 
             let did_not_vote_before = !<VoteExistsByProposalByVoter<T>>::exists(
                 proposal_id,
@@ -265,7 +264,7 @@ decl_module! {
             let proposal = Self::proposals(proposal_id);
 
             ensure!(proposer_id == proposal.proposer_id, Error::NotAuthor);
-            ensure!(proposal.status == ProposalStatus::Active, Error::ProposalFinalized);
+            ensure!(matches!(proposal.status, ProposalStatus::Active{..}), Error::ProposalFinalized);
 
             // mutation
 
@@ -279,7 +278,7 @@ decl_module! {
             ensure!(<Proposals<T>>::exists(proposal_id), Error::ProposalNotFound);
             let proposal = Self::proposals(proposal_id);
 
-            ensure!(proposal.status == ProposalStatus::Active, Error::ProposalFinalized);
+            ensure!(matches!(proposal.status, ProposalStatus::Active{..}), Error::ProposalFinalized);
 
             // mutation
 
@@ -300,12 +299,12 @@ decl_module! {
                 Self::finalize_proposal(proposal_data.proposal_id, proposal_data.status);
             }
 
-            let executable_proposal_ids =
-                Self::get_approved_proposal_with_expired_grace_period_ids();
+            let executable_proposals =
+                Self::get_approved_proposal_with_expired_grace_period();
 
             // Execute approved proposals with expired grace period
-            for  proposal_id in executable_proposal_ids {
-                Self::execute_proposal(proposal_id);
+            for approved_proosal in executable_proposals {
+                Self::execute_proposal(approved_proosal);
             }
         }
     }
@@ -314,17 +313,14 @@ decl_module! {
 impl<T: Trait> Module<T> {
     /// Create proposal. Requires 'proposal origin' membership.
     pub fn create_proposal(
-        origin: T::Origin,
+        account_id: T::AccountId,
         proposer_id: MemberId<T>,
         parameters: ProposalParameters<T::BlockNumber, types::BalanceOf<T>>,
         title: Vec<u8>,
         description: Vec<u8>,
         stake_balance: Option<types::BalanceOf<T>>,
-        proposal_code: Vec<u8>,
+        encoded_dispatchable_call_code: Vec<u8>,
     ) -> Result<T::ProposalId, Error> {
-        let account_id =
-            T::ProposerOriginValidator::ensure_actor_origin(origin, proposer_id.clone())?;
-
         Self::ensure_create_proposal_parameters_are_valid(
             &parameters,
             &title,
@@ -349,7 +345,7 @@ impl<T: Trait> Module<T> {
 
         let mut stake_data = None;
         if let Some(stake_id) = stake_id_result {
-            stake_data = Some(StakeData {
+            stake_data = Some(ActiveStake {
                 stake_id,
                 source_account_id: account_id,
             });
@@ -363,13 +359,12 @@ impl<T: Trait> Module<T> {
             title,
             description,
             proposer_id: proposer_id.clone(),
-            status: ProposalStatus::Active,
+            status: ProposalStatus::Active(stake_data),
             voting_results: VotingResults::default(),
-            stake_data,
         };
 
         <Proposals<T>>::insert(proposal_id, new_proposal);
-        <ProposalCode<T>>::insert(proposal_id, proposal_code);
+        <DispatchableCallCode<T>>::insert(proposal_id, encoded_dispatchable_call_code);
         <ActiveProposalIds<T>>::insert(proposal_id, ());
         ProposalCount::put(next_proposal_count_value);
         Self::increase_active_proposal_counter();
@@ -378,6 +373,87 @@ impl<T: Trait> Module<T> {
 
         Ok(proposal_id)
     }
+
+    /// Performs all checks for the proposal creation:
+    /// - title, body lengths
+    /// - mac active proposal
+    /// - provided parameters: approval_threshold_percentage and slashing_threshold_percentage > 0
+    /// - provided stake balance and parameters.required_stake are valid
+    pub fn ensure_create_proposal_parameters_are_valid(
+        parameters: &ProposalParameters<T::BlockNumber, types::BalanceOf<T>>,
+        title: &[u8],
+        description: &[u8],
+        stake_balance: Option<types::BalanceOf<T>>,
+    ) -> DispatchResult<Error> {
+        ensure!(!title.is_empty(), Error::EmptyTitleProvided);
+        ensure!(
+            title.len() as u32 <= T::TitleMaxLength::get(),
+            Error::TitleIsTooLong
+        );
+
+        ensure!(!description.is_empty(), Error::EmptyDescriptionProvided);
+        ensure!(
+            description.len() as u32 <= T::DescriptionMaxLength::get(),
+            Error::DescriptionIsTooLong
+        );
+
+        ensure!(
+            (Self::active_proposal_count()) < T::MaxActiveProposalLimit::get(),
+            Error::MaxActiveProposalNumberExceeded
+        );
+
+        ensure!(
+            parameters.approval_threshold_percentage > 0,
+            Error::InvalidParameterApprovalThreshold
+        );
+
+        ensure!(
+            parameters.slashing_threshold_percentage > 0,
+            Error::InvalidParameterSlashingThreshold
+        );
+
+        // check stake parameters
+        if let Some(required_stake) = parameters.required_stake {
+            if let Some(staked_balance) = stake_balance {
+                ensure!(
+                    required_stake == staked_balance,
+                    Error::StakeDiffersFromRequired
+                );
+            } else {
+                return Err(Error::EmptyStake);
+            }
+        }
+
+        if stake_balance.is_some() && parameters.required_stake.is_none() {
+            return Err(Error::StakeShouldBeEmpty);
+        }
+
+        Ok(())
+    }
+
+    //TODO: candidate for invariant break or error saving to the state
+    /// Callback from StakingEventsHandler. Refunds unstaked imbalance back to the source account
+    pub fn refund_proposal_stake(stake_id: T::StakeId, imbalance: NegativeImbalance<T>) {
+        if <StakesProposals<T>>::exists(stake_id) {
+            //TODO: handle non existence
+
+            let proposal_id = Self::stakes_proposals(stake_id);
+
+            if <Proposals<T>>::exists(proposal_id) {
+                let proposal = Self::proposals(proposal_id);
+
+                if let ProposalStatus::Active(active_stake_result) = proposal.status {
+                    if let Some(active_stake) = active_stake_result {
+                        //TODO: handle the result
+                        let _ = CurrencyOf::<T>::resolve_into_existing(
+                            &active_stake.source_account_id,
+                            imbalance,
+                        );
+                    }
+                }
+            }
+        }
+    }
 }
 
 impl<T: Trait> Module<T> {
@@ -415,43 +491,38 @@ impl<T: Trait> Module<T> {
     }
 
     // Executes approved proposal code
-    fn execute_proposal(proposal_id: T::ProposalId) {
-        let mut proposal = Self::proposals(proposal_id);
+    fn execute_proposal(approved_proposal: ApprovedProposal<T>) {
+        let proposal_code = Self::proposal_codes(approved_proposal.proposal_id);
 
-        // Execute only proposals with correct status
-        if let ProposalStatus::Finalized(finalized_status) = proposal.status.clone() {
-            let proposal_code = Self::proposal_codes(proposal_id);
+        let proposal_code_result = T::DispatchableCallCode::decode(&mut &proposal_code[..]);
 
-            let proposal_code_result = T::ProposalCode::decode(&mut &proposal_code[..]);
-
-            let approved_proposal_status = match proposal_code_result {
-                Ok(proposal_code) => {
-                    if let Err(error) = proposal_code.dispatch(T::Origin::from(RawOrigin::Root)) {
-                        ApprovedProposalStatus::failed_execution(
-                            error.into().message.unwrap_or("Dispatch error"),
-                        )
-                    } else {
-                        ApprovedProposalStatus::Executed
-                    }
+        let approved_proposal_status = match proposal_code_result {
+            Ok(proposal_code) => {
+                if let Err(error) = proposal_code.dispatch(T::Origin::from(RawOrigin::Root)) {
+                    ApprovedProposalStatus::failed_execution(
+                        error.into().message.unwrap_or("Dispatch error"),
+                    )
+                } else {
+                    ApprovedProposalStatus::Executed
                 }
-                Err(error) => ApprovedProposalStatus::failed_execution(error.what()),
-            };
+            }
+            Err(error) => ApprovedProposalStatus::failed_execution(error.what()),
+        };
 
-            let proposal_execution_status =
-                finalized_status.create_approved_proposal_status(approved_proposal_status);
+        let proposal_execution_status = approved_proposal
+            .finalisation_status_data
+            .create_approved_proposal_status(approved_proposal_status);
 
-            proposal.status = proposal_execution_status.clone();
-            <Proposals<T>>::insert(proposal_id, proposal);
+        let mut proposal = approved_proposal.proposal;
+        proposal.status = proposal_execution_status.clone();
+        <Proposals<T>>::insert(approved_proposal.proposal_id, proposal);
 
-            Self::deposit_event(RawEvent::ProposalStatusUpdated(
-                proposal_id,
-                proposal_execution_status,
-            ));
-        }
+        Self::deposit_event(RawEvent::ProposalStatusUpdated(
+            approved_proposal.proposal_id,
+            proposal_execution_status,
+        ));
 
-        // Remove proposals from the 'pending execution' queue even in case of not finalized status
-        // to prevent eternal cycles.
-        <PendingExecutionProposalIds<T>>::remove(&proposal_id);
+        <PendingExecutionProposalIds<T>>::remove(&approved_proposal.proposal_id);
     }
 
     // Performs all actions on proposal finalization:
@@ -466,36 +537,36 @@ impl<T: Trait> Module<T> {
 
         let mut proposal = Self::proposals(proposal_id);
 
-        if let ProposalDecisionStatus::Approved { .. } = decision_status {
-            <PendingExecutionProposalIds<T>>::insert(proposal_id, ());
-        }
-
-        // deal with stakes if necessary
-        let slash_balance = Self::calculate_slash_balance(&decision_status, &proposal.parameters);
-        let slash_and_unstake_result =
-            Self::slash_and_unstake(proposal.stake_data.clone(), slash_balance);
+        if let ProposalStatus::Active(active_stake) = proposal.status.clone() {
+            if let ProposalDecisionStatus::Approved { .. } = decision_status {
+                <PendingExecutionProposalIds<T>>::insert(proposal_id, ());
+            }
 
-        //TODO: leave stake data as is?
-        if slash_and_unstake_result.is_ok() {
-            proposal.stake_data = None;
-        }
+            // deal with stakes if necessary
+            let slash_balance =
+                Self::calculate_slash_balance(&decision_status, &proposal.parameters);
+            let slash_and_unstake_result =
+                Self::slash_and_unstake(active_stake.clone(), slash_balance);
 
-        // create finalized proposal status with error if any
-        let new_proposal_status = //TODO rename without an error
-            ProposalStatus::finalized_with_error(decision_status, slash_and_unstake_result.err(), Self::current_block());
+            // create finalized proposal status with error if any
+            let new_proposal_status = //TODO rename without an error
+            ProposalStatus::finalized_with_error(decision_status, slash_and_unstake_result.err(), active_stake, Self::current_block());
 
-        proposal.status = new_proposal_status.clone();
-        <Proposals<T>>::insert(proposal_id, proposal);
+            proposal.status = new_proposal_status.clone();
+            <Proposals<T>>::insert(proposal_id, proposal);
 
-        Self::deposit_event(RawEvent::ProposalStatusUpdated(
-            proposal_id,
-            new_proposal_status,
-        ));
+            Self::deposit_event(RawEvent::ProposalStatusUpdated(
+                proposal_id,
+                new_proposal_status,
+            ));
+        } else {
+            print("Broken invariant: proposal cannot be non-active during the finalisation");
+        }
     }
 
     // Slashes the stake and perform unstake only in case of existing stake
     fn slash_and_unstake(
-        current_stake_data: Option<StakeData<T::StakeId, T::AccountId>>,
+        current_stake_data: Option<ActiveStake<T::StakeId, T::AccountId>>,
         slash_balance: BalanceOf<T>,
     ) -> Result<(), &'static str> {
         // only if stake exists
@@ -531,13 +602,22 @@ impl<T: Trait> Module<T> {
     }
 
     // Enumerates approved proposals and checks their grace period expiration
-    fn get_approved_proposal_with_expired_grace_period_ids() -> Vec<T::ProposalId> {
+    fn get_approved_proposal_with_expired_grace_period() -> Vec<ApprovedProposal<T>> {
         <PendingExecutionProposalIds<T>>::enumerate()
             .filter_map(|(proposal_id, _)| {
                 let proposal = Self::proposals(proposal_id);
 
                 if proposal.is_grace_period_expired(Self::current_block()) {
-                    Some(proposal_id)
+                    // this should be true, because it was tested inside is_grace_period_expired()
+                    if let ProposalStatus::Finalized(finalisation_data) = proposal.status.clone() {
+                        Some(ApprovedProposalData {
+                            proposal_id,
+                            proposal,
+                            finalisation_status_data: finalisation_data,
+                        })
+                    } else {
+                        None
+                    }
                 } else {
                     None
                 }
@@ -560,85 +640,6 @@ impl<T: Trait> Module<T> {
             ActiveProposalCount::put(next_active_proposal_count_value);
         };
     }
-
-    // Performs all checks for the proposal creation:
-    // - title, body lengths
-    // - mac active proposal
-    // - provided parameters: approval_threshold_percentage and slashing_threshold_percentage > 0
-    // - provided stake balance and parameters.required_stake are valid
-    fn ensure_create_proposal_parameters_are_valid(
-        parameters: &ProposalParameters<T::BlockNumber, types::BalanceOf<T>>,
-        title: &[u8],
-        description: &[u8],
-        stake_balance: Option<types::BalanceOf<T>>,
-    ) -> DispatchResult<Error> {
-        ensure!(!title.is_empty(), Error::EmptyTitleProvided);
-        ensure!(
-            title.len() as u32 <= T::TitleMaxLength::get(),
-            Error::TitleIsTooLong
-        );
-
-        ensure!(!description.is_empty(), Error::EmptyDescriptionProvided);
-        ensure!(
-            description.len() as u32 <= T::DescriptionMaxLength::get(),
-            Error::DescriptionIsTooLong
-        );
-
-        ensure!(
-            (Self::active_proposal_count()) < T::MaxActiveProposalLimit::get(),
-            Error::MaxActiveProposalNumberExceeded
-        );
-
-        ensure!(
-            parameters.approval_threshold_percentage > 0,
-            Error::InvalidParameterApprovalThreshold
-        );
-
-        ensure!(
-            parameters.slashing_threshold_percentage > 0,
-            Error::InvalidParameterSlashingThreshold
-        );
-
-        // check stake parameters
-        if let Some(required_stake) = parameters.required_stake {
-            if let Some(staked_balance) = stake_balance {
-                ensure!(
-                    required_stake == staked_balance,
-                    Error::StakeDiffersFromRequired
-                );
-            } else {
-                return Err(Error::EmptyStake);
-            }
-        }
-
-        if stake_balance.is_some() && parameters.required_stake.is_none() {
-            return Err(Error::StakeShouldBeEmpty);
-        }
-
-        Ok(())
-    }
-
-    //TODO: candidate for invariant break or error saving to the state
-    /// Callback from StakingEventsHandler. Refunds unstaked imbalance back to the source account
-    pub(crate) fn refund_proposal_stake(stake_id: T::StakeId, imbalance: NegativeImbalance<T>) {
-        if <StakesProposals<T>>::exists(stake_id) {
-            //TODO: handle non existence
-
-            let proposal_id = Self::stakes_proposals(stake_id);
-
-            if <Proposals<T>>::exists(proposal_id) {
-                let proposal = Self::proposals(proposal_id);
-
-                if let Some(stake_data) = proposal.stake_data {
-                    //TODO: handle the result
-                    let _ = CurrencyOf::<T>::resolve_into_existing(
-                        &stake_data.source_account_id,
-                        imbalance,
-                    );
-                }
-            }
-        }
-    }
 }
 
 // Simplification of the 'FinalizedProposalData' type
@@ -651,8 +652,18 @@ type FinalizedProposal<T> = FinalizedProposalData<
     <T as system::Trait>::AccountId,
 >;
 
+// Simplification of the 'ApprovedProposalData' type
+type ApprovedProposal<T> = ApprovedProposalData<
+    <T as Trait>::ProposalId,
+    <T as system::Trait>::BlockNumber,
+    MemberId<T>,
+    types::BalanceOf<T>,
+    <T as stake::Trait>::StakeId,
+    <T as system::Trait>::AccountId,
+>;
+
 // Simplification of the 'Proposal' type
-type ProposalObject<T> = Proposal<
+type ProposalOf<T> = Proposal<
     <T as system::Trait>::BlockNumber,
     MemberId<T>,
     types::BalanceOf<T>,

+ 1 - 17
runtime-modules/proposals/engine/src/tests/mock/mod.rs

@@ -41,22 +41,11 @@ mod membership_mod {
     pub use membership::members::Event;
 }
 
-mod council_mod {
-    pub use governance::council::Event;
-}
-
-// impl_outer_dispatch! {
-//     pub enum Call for Test where origin: Origin {
-//         engine::ProposalsEngine,
-//     }
-// }
-
 impl_outer_event! {
     pub enum TestEvent for Test {
         balances<T>,
         engine<T>,
         membership_mod<T>,
-        council_mod<T>,
     }
 }
 
@@ -87,11 +76,6 @@ impl common::currency::GovernanceCurrency for Test {
     type Currency = balances::Module<Self>;
 }
 
-impl governance::council::Trait for Test {
-    type Event = TestEvent;
-    type CouncilTermEnded = ();
-}
-
 impl proposals::Trait for Test {}
 
 impl stake::Trait for Test {
@@ -131,7 +115,7 @@ impl crate::Trait for Test {
     type TitleMaxLength = TitleMaxLength;
     type DescriptionMaxLength = DescriptionMaxLength;
     type MaxActiveProposalLimit = MaxActiveProposalLimit;
-    type ProposalCode = proposals::Call<Test>;
+    type DispatchableCallCode = proposals::Call<Test>;
 }
 
 impl Default for proposals::Call<Test> {

+ 36 - 52
runtime-modules/proposals/engine/src/tests/mod.rs

@@ -58,7 +58,7 @@ impl Default for ProposalParametersFixture {
 #[derive(Clone)]
 struct DummyProposalFixture {
     parameters: ProposalParameters<u64, u64>,
-    origin: RawOrigin<u64>,
+    account_id: u64,
     proposer_id: u64,
     proposal_code: Vec<u8>,
     title: Vec<u8>,
@@ -83,7 +83,7 @@ impl Default for DummyProposalFixture {
                 grace_period: 0,
                 required_stake: None,
             },
-            origin: RawOrigin::Signed(1),
+            account_id: 1,
             proposer_id: 1,
             proposal_code: dummy_proposal.encode(),
             title,
@@ -106,8 +106,8 @@ impl DummyProposalFixture {
         DummyProposalFixture { parameters, ..self }
     }
 
-    fn with_origin(self, origin: RawOrigin<u64>) -> Self {
-        DummyProposalFixture { origin, ..self }
+    fn with_account_id(self, account_id: u64) -> Self {
+        DummyProposalFixture { account_id, ..self }
     }
 
     fn with_stake(self, stake_balance: BalanceOf<Test>) -> Self {
@@ -126,7 +126,7 @@ impl DummyProposalFixture {
 
     fn create_proposal_and_assert(self, result: Result<u32, Error>) -> Option<u32> {
         let proposal_id_result = ProposalsEngine::create_proposal(
-            self.origin.into(),
+            self.account_id,
             self.proposer_id,
             self.parameters,
             self.title,
@@ -243,7 +243,7 @@ impl VoteGenerator {
 
 struct EventFixture;
 impl EventFixture {
-    fn assert_events(expected_raw_events: Vec<RawEvent<u32, u64, u64>>) {
+    fn assert_events(expected_raw_events: Vec<RawEvent<u32, u64, u64, u64, u64>>) {
         let expected_events = expected_raw_events
             .iter()
             .map(|ev| EventRecord {
@@ -283,14 +283,6 @@ fn create_dummy_proposal_succeeds() {
     });
 }
 
-#[test]
-fn create_dummy_proposal_fails_with_insufficient_rights() {
-    initial_test_ext().execute_with(|| {
-        let dummy_proposal = DummyProposalFixture::default().with_origin(RawOrigin::None);
-        dummy_proposal.create_proposal_and_assert(Err(Error::Other("RequireSignedOrigin")));
-    });
-}
-
 #[test]
 fn vote_succeeds() {
     initial_test_ext().execute_with(|| {
@@ -348,7 +340,6 @@ fn proposal_execution_succeeds() {
                     rejections: 0,
                     slashes: 0,
                 },
-                stake_data: None,
             }
         );
 
@@ -401,7 +392,6 @@ fn proposal_execution_failed() {
                     rejections: 0,
                     slashes: 0,
                 },
-                stake_data: None,
             }
         )
     });
@@ -580,7 +570,6 @@ fn cancel_proposal_succeeds() {
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
-                stake_data: None,
             }
         )
     });
@@ -649,7 +638,6 @@ fn veto_proposal_succeeds() {
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
-                stake_data: None,
             }
         );
 
@@ -734,7 +722,8 @@ fn cancel_proposal_event_emitted() {
                 1,
                 ProposalStatus::Finalized(FinalizationData {
                     proposal_status: ProposalDecisionStatus::Canceled,
-                    finalization_error: None,
+                    encoded_unstaking_error_due_to_broken_runtime: None,
+                    stake_data_after_unstaking_error: None,
                     finalized_at: 1,
                 }),
             ),
@@ -780,7 +769,6 @@ fn create_proposal_and_expire_it() {
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
-                stake_data: None,
             }
         )
     });
@@ -826,7 +814,6 @@ fn proposal_execution_postponed_because_of_grace_period() {
                     rejections: 0,
                     slashes: 0,
                 },
-                stake_data: None,
             }
         );
     });
@@ -868,7 +855,6 @@ fn proposal_execution_succeeds_after_the_grace_period() {
                 rejections: 0,
                 slashes: 0,
             },
-            stake_data: None,
         };
 
         assert_eq!(proposal, expected_proposal);
@@ -948,7 +934,7 @@ fn create_dummy_proposal_succeeds_with_stake() {
 
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters_fixture.params())
-            .with_origin(RawOrigin::Signed(account_id))
+            .with_account_id(account_id)
             .with_stake(200);
 
         let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 500);
@@ -963,14 +949,13 @@ fn create_dummy_proposal_succeeds_with_stake() {
                 parameters: parameters_fixture.params(),
                 proposer_id: 1,
                 created_at: 1,
-                status: ProposalStatus::Active,
+                status: ProposalStatus::Active(Some(ActiveStake {
+                    stake_id: 0, // valid stake_id
+                    source_account_id: 1
+                })),
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
-                stake_data: Some(StakeData {
-                    stake_id: 0, // valid stake_id
-                    source_account_id: 1
-                }),
             }
         )
     });
@@ -986,7 +971,7 @@ fn create_dummy_proposal_fail_with_stake_on_empty_account() {
             ProposalParametersFixture::default().with_required_stake(required_stake);
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters_fixture.params())
-            .with_origin(RawOrigin::Signed(account_id))
+            .with_account_id(account_id)
             .with_stake(required_stake);
 
         dummy_proposal
@@ -1037,7 +1022,7 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
         };
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters)
-            .with_origin(RawOrigin::Signed(account_id))
+            .with_account_id(account_id)
             .with_stake(stake_amount);
 
         let account_balance = 500;
@@ -1061,14 +1046,13 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
             parameters,
             proposer_id: 1,
             created_at: 1,
-            status: ProposalStatus::Active,
+            status: ProposalStatus::Active(Some(ActiveStake {
+                stake_id: 0,
+                source_account_id: 1,
+            })),
             title: b"title".to_vec(),
             description: b"description".to_vec(),
             voting_results: VotingResults::default(),
-            stake_data: Some(StakeData {
-                stake_id: 0,
-                source_account_id: 1,
-            }),
         };
 
         assert_eq!(proposal, expected_proposal);
@@ -1080,9 +1064,9 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
         expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
             proposal_status: ProposalDecisionStatus::Expired,
             finalized_at: 4,
-            finalization_error: None,
+            encoded_unstaking_error_due_to_broken_runtime: None,
+            stake_data_after_unstaking_error: None,
         });
-        expected_proposal.stake_data = None;
 
         assert_eq!(proposal, expected_proposal);
 
@@ -1111,7 +1095,7 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
         };
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters)
-            .with_origin(RawOrigin::Signed(account_id))
+            .with_account_id(account_id.clone())
             .with_stake(stake_amount);
 
         let account_balance = 500;
@@ -1135,14 +1119,13 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
             parameters,
             proposer_id: 1,
             created_at: 1,
-            status: ProposalStatus::Active,
+            status: ProposalStatus::Active(Some(ActiveStake {
+                stake_id: 0,
+                source_account_id: 1,
+            })),
             title: b"title".to_vec(),
             description: b"description".to_vec(),
             voting_results: VotingResults::default(),
-            stake_data: Some(StakeData {
-                stake_id: 0,
-                source_account_id: 1,
-            }),
         };
 
         assert_eq!(proposal, expected_proposal);
@@ -1156,9 +1139,9 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
         expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
             proposal_status: ProposalDecisionStatus::Canceled,
             finalized_at: 1,
-            finalization_error: None,
+            encoded_unstaking_error_due_to_broken_runtime: None,
+            stake_data_after_unstaking_error: None,
         });
-        expected_proposal.stake_data = None;
 
         assert_eq!(proposal, expected_proposal);
 
@@ -1201,7 +1184,7 @@ fn finalize_proposal_using_stake_mocks_succeeds() {
                 ProposalParametersFixture::default().with_required_stake(stake_amount);
             let dummy_proposal = DummyProposalFixture::default()
                 .with_parameters(parameters_fixture.params())
-                .with_origin(RawOrigin::Signed(account_id))
+                .with_account_id(account_id)
                 .with_stake(stake_amount);
 
             let _proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
@@ -1243,8 +1226,9 @@ fn proposal_slashing_succeeds() {
             proposal.status,
             ProposalStatus::Finalized(FinalizationData {
                 proposal_status: ProposalDecisionStatus::Slashed,
-                finalization_error: None,
+                encoded_unstaking_error_due_to_broken_runtime: None,
                 finalized_at: 1,
+                stake_data_after_unstaking_error: None,
             }),
         );
         assert!(!<ActiveProposalIds<Test>>::exists(proposal_id));
@@ -1284,7 +1268,7 @@ fn finalize_proposal_using_stake_mocks_failed() {
                 ProposalParametersFixture::default().with_required_stake(stake_amount);
             let dummy_proposal = DummyProposalFixture::default()
                 .with_parameters(parameters_fixture.params())
-                .with_origin(RawOrigin::Signed(account_id))
+                .with_account_id(account_id)
                 .with_stake(stake_amount);
 
             let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
@@ -1301,15 +1285,15 @@ fn finalize_proposal_using_stake_mocks_failed() {
                     status: ProposalStatus::finalized_with_error(
                         ProposalDecisionStatus::Expired,
                         Some("Cannot remove stake"),
+                        Some(ActiveStake {
+                            stake_id: 1,
+                            source_account_id: 1
+                        }),
                         4,
                     ),
                     title: b"title".to_vec(),
                     description: b"description".to_vec(),
                     voting_results: VotingResults::default(),
-                    stake_data: Some(StakeData {
-                        stake_id: 1,
-                        source_account_id: 1
-                    }),
                 }
             );
         });

+ 26 - 11
runtime-modules/proposals/engine/src/types/mod.rs

@@ -11,19 +11,14 @@ use serde::{Deserialize, Serialize};
 use srml_support::dispatch;
 use srml_support::traits::Currency;
 
-mod council_origin_validator;
 mod proposal_statuses;
 mod stakes;
 
-pub use council_origin_validator::CouncilManager;
-
 pub use proposal_statuses::{
     ApprovedProposalStatus, FinalizationData, ProposalDecisionStatus, ProposalStatus,
 };
 pub(crate) use stakes::ProposalStakeManager;
-pub use stakes::{
-    DefaultStakeHandlerProvider, StakeHandler, StakeHandlerProvider, StakingEventsHandler,
-};
+pub use stakes::{DefaultStakeHandlerProvider, StakeHandler, StakeHandlerProvider};
 
 #[cfg(test)]
 pub(crate) use stakes::DefaultStakeHandler;
@@ -119,7 +114,7 @@ impl VotingResults {
 /// Contains created stake id and source account for the stake balance
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, Debug)]
-pub struct StakeData<StakeId, AccountId> {
+pub struct ActiveStake<StakeId, AccountId> {
     /// Created stake id for the proposal
     pub stake_id: StakeId,
 
@@ -147,19 +142,18 @@ pub struct Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId> {
     pub created_at: BlockNumber,
 
     /// Current proposal status
-    pub status: ProposalStatus<BlockNumber>,
+    pub status: ProposalStatus<BlockNumber, StakeId, AccountId>,
 
     /// Curring voting result for the proposal
     pub voting_results: VotingResults,
-
-    /// Stake data for the proposal
-    pub stake_data: Option<StakeData<StakeId, AccountId>>,
 }
 
 impl<BlockNumber, ProposerId, Balance, StakeId, AccountId>
     Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId>
 where
     BlockNumber: Add<Output = BlockNumber> + PartialOrd + Copy,
+    StakeId: Clone,
+    AccountId: Clone,
 {
     /// Returns whether voting period expired by now
     pub fn is_voting_period_expired(&self, now: BlockNumber) -> bool {
@@ -238,6 +232,8 @@ impl<'a, BlockNumber, ProposerId, Balance, StakeId, AccountId>
     ProposalStatusResolution<'a, BlockNumber, ProposerId, Balance, StakeId, AccountId>
 where
     BlockNumber: Add<Output = BlockNumber> + PartialOrd + Copy,
+    StakeId: Clone,
+    AccountId: Clone,
 {
     // Proposal has been expired and quorum not reached.
     pub fn is_expired(&self) -> bool {
@@ -342,6 +338,25 @@ pub(crate) struct FinalizedProposalData<
     pub finalized_at: BlockNumber,
 }
 
+/// Data container for the approved proposal results
+pub(crate) struct ApprovedProposalData<
+    ProposalId,
+    BlockNumber,
+    ProposerId,
+    Balance,
+    StakeId,
+    AccountId,
+> {
+    /// Proposal id
+    pub proposal_id: ProposalId,
+
+    /// Proposal to be finalized
+    pub proposal: Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId>,
+
+    /// Proposal finalisation status data
+    pub finalisation_status_data: FinalizationData<BlockNumber, StakeId, AccountId>,
+}
+
 #[cfg(test)]
 mod tests {
     use crate::*;

+ 27 - 19
runtime-modules/proposals/engine/src/types/proposal_statuses.rs

@@ -1,45 +1,49 @@
 use codec::{Decode, Encode};
 use rstd::prelude::*;
 
+use crate::ActiveStake;
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
 
 /// Current status of the proposal
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum ProposalStatus<BlockNumber> {
-    /// A new proposal that is available for voting.
-    Active,
+pub enum ProposalStatus<BlockNumber, StakeId, AccountId> {
+    /// A new proposal status that is available for voting (with optional stake data).
+    Active(Option<ActiveStake<StakeId, AccountId>>),
 
     /// The proposal decision was made.
-    Finalized(FinalizationData<BlockNumber>),
+    Finalized(FinalizationData<BlockNumber, StakeId, AccountId>),
 }
 
-impl<BlockNumber> Default for ProposalStatus<BlockNumber> {
+impl<BlockNumber, StakeId, AccountId> Default for ProposalStatus<BlockNumber, StakeId, AccountId> {
     fn default() -> Self {
-        ProposalStatus::Active
+        ProposalStatus::Active(None)
     }
 }
 
-impl<BlockNumber> ProposalStatus<BlockNumber> {
+impl<BlockNumber, StakeId, AccountId> ProposalStatus<BlockNumber, StakeId, AccountId> {
     /// Creates finalized proposal status with provided ProposalDecisionStatus
     pub fn finalized(
         decision_status: ProposalDecisionStatus,
         now: BlockNumber,
-    ) -> ProposalStatus<BlockNumber> {
-        Self::finalized_with_error(decision_status, None, now)
+    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
+        Self::finalized_with_error(decision_status, None, None, now)
     }
 
     /// Creates finalized proposal status with provided ProposalDecisionStatus and error
     pub fn finalized_with_error(
         decision_status: ProposalDecisionStatus,
-        finalization_error: Option<&str>,
+        encoded_unstaking_error_due_to_broken_runtime: Option<&str>,
+        active_stake: Option<ActiveStake<StakeId, AccountId>>,
         now: BlockNumber,
-    ) -> ProposalStatus<BlockNumber> {
+    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
         ProposalStatus::Finalized(FinalizationData {
             proposal_status: decision_status,
-            finalization_error: finalization_error.map(|err| err.as_bytes().to_vec()),
+            encoded_unstaking_error_due_to_broken_runtime:
+                encoded_unstaking_error_due_to_broken_runtime.map(|err| err.as_bytes().to_vec()),
             finalized_at: now,
+            stake_data_after_unstaking_error: active_stake,
         })
     }
 
@@ -47,11 +51,12 @@ impl<BlockNumber> ProposalStatus<BlockNumber> {
     pub fn approved(
         approved_status: ApprovedProposalStatus,
         now: BlockNumber,
-    ) -> ProposalStatus<BlockNumber> {
+    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
         ProposalStatus::Finalized(FinalizationData {
             proposal_status: ProposalDecisionStatus::Approved(approved_status),
-            finalization_error: None,
+            encoded_unstaking_error_due_to_broken_runtime: None,
             finalized_at: now,
+            stake_data_after_unstaking_error: None,
         })
     }
 }
@@ -59,23 +64,26 @@ impl<BlockNumber> ProposalStatus<BlockNumber> {
 /// Final proposal status and potential error.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub struct FinalizationData<BlockNumber> {
+pub struct FinalizationData<BlockNumber, StakeId, AccountId> {
     /// Final proposal status
     pub proposal_status: ProposalDecisionStatus,
 
     /// Proposal finalization block number
     pub finalized_at: BlockNumber,
 
-    /// Error occured during the proposal finalization
-    pub finalization_error: Option<Vec<u8>>,
+    /// Error occured during the proposal finalization - unstaking failed in the stake module
+    pub encoded_unstaking_error_due_to_broken_runtime: Option<Vec<u8>>,
+
+    /// Stake data for the proposal, filled if the unstaking wasn't successful
+    pub stake_data_after_unstaking_error: Option<ActiveStake<StakeId, AccountId>>,
 }
 
-impl<BlockNumber> FinalizationData<BlockNumber> {
+impl<BlockNumber, StakeId, AccountId> FinalizationData<BlockNumber, StakeId, AccountId> {
     /// FinalizationData helper, creates ApprovedProposalStatus
     pub fn create_approved_proposal_status(
         self,
         approved_status: ApprovedProposalStatus,
-    ) -> ProposalStatus<BlockNumber> {
+    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
         ProposalStatus::Finalized(FinalizationData {
             proposal_status: ProposalDecisionStatus::Approved(approved_status),
             ..self

+ 1 - 36
runtime-modules/proposals/engine/src/types/stakes.rs

@@ -3,8 +3,7 @@ use crate::Trait;
 use rstd::convert::From;
 use rstd::marker::PhantomData;
 use rstd::rc::Rc;
-use srml_support::traits::{Currency, ExistenceRequirement, Imbalance, WithdrawReasons};
-use srml_support::StorageMap;
+use srml_support::traits::{Currency, ExistenceRequirement, WithdrawReasons};
 
 // Mocking dependencies for testing
 #[cfg(test)]
@@ -12,40 +11,6 @@ use mockall::predicate::*;
 #[cfg(test)]
 use mockall::*;
 
-/// Proposal implementation of the staking event handler from the stake module.
-/// 'marker' responsible for the 'Trait' binding.
-pub struct StakingEventsHandler<T> {
-    pub marker: PhantomData<T>,
-}
-
-impl<T: Trait> stake::StakingEventsHandler<T> for StakingEventsHandler<T> {
-    /// Unstake remaining sum back to the source_account_id
-    fn unstaked(
-        id: &<T as stake::Trait>::StakeId,
-        _unstaked_amount: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        if <crate::StakesProposals<T>>::exists(id) {
-            <crate::Module<T>>::refund_proposal_stake(*id, remaining_imbalance);
-
-            return <NegativeImbalance<T>>::zero(); // imbalance was consumed
-        }
-
-        remaining_imbalance
-    }
-
-    /// Empty handler for slashing
-    fn slashed(
-        _: &<T as stake::Trait>::StakeId,
-        _: Option<<T as stake::Trait>::SlashId>,
-        _: BalanceOf<T>,
-        _: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        remaining_imbalance
-    }
-}
-
 /// Returns registered stake handler. This is scaffolds for the mocking of the stake module.
 pub trait StakeHandlerProvider<T: Trait> {
     /// Returns stake logic handler

+ 1 - 0
runtime/src/integration/mod.rs

@@ -0,0 +1 @@
+pub mod proposals;

+ 76 - 35
runtime-modules/proposals/engine/src/types/council_origin_validator.rs → runtime/src/integration/proposals/council_origin_validator.rs

@@ -1,8 +1,9 @@
 use rstd::marker::PhantomData;
 
-use crate::VotersParameters;
 use common::origin_validator::ActorOriginValidator;
-use membership::origin_validator::{MemberId, MembershipOriginValidator};
+use proposals_engine::VotersParameters;
+
+use super::{MemberId, MembershipOriginValidator};
 
 /// Handles work with the council.
 /// Provides implementations for ActorOriginValidator and VotersParameters.
@@ -10,7 +11,7 @@ pub struct CouncilManager<T> {
     marker: PhantomData<T>,
 }
 
-impl<T: crate::Trait>
+impl<T: governance::council::Trait + membership::members::Trait>
     ActorOriginValidator<<T as system::Trait>::Origin, MemberId<T>, <T as system::Trait>::AccountId>
     for CouncilManager<T>
 {
@@ -30,7 +31,7 @@ impl<T: crate::Trait>
     }
 }
 
-impl<T: crate::Trait> VotersParameters for CouncilManager<T> {
+impl<T: governance::council::Trait> VotersParameters for CouncilManager<T> {
     /// Implement total_voters_count() as council size
     fn total_voters_count() -> u32 {
         <governance::council::Module<T>>::active_council().len() as u32
@@ -39,25 +40,35 @@ impl<T: crate::Trait> VotersParameters for CouncilManager<T> {
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::mock::{initial_test_ext, Test};
-    use crate::CouncilManager;
-    use crate::VotersParameters;
+    use super::CouncilManager;
+    use crate::Runtime;
     use common::origin_validator::ActorOriginValidator;
     use membership::members::UserInfo;
+    use proposals_engine::VotersParameters;
+    use sr_primitives::AccountId32;
     use system::RawOrigin;
 
-    type Membership = membership::members::Module<Test>;
-    type Council = governance::council::Module<Test>;
+    type Council = governance::council::Module<Runtime>;
+
+    fn initial_test_ext() -> runtime_io::TestExternalities {
+        let t = system::GenesisConfig::default()
+            .build_storage::<Runtime>()
+            .unwrap();
+
+        t.into()
+    }
+
+    type Membership = membership::members::Module<Runtime>;
 
     #[test]
     fn council_origin_validator_fails_with_unregistered_member() {
         initial_test_ext().execute_with(|| {
-            let origin = RawOrigin::Signed(1);
+            let origin = RawOrigin::Signed(AccountId32::default());
             let member_id = 1;
             let error = "Membership validation failed: cannot find a profile for a member";
 
             let validation_result =
-                CouncilManager::<Test>::ensure_actor_origin(origin.into(), member_id);
+                CouncilManager::<Runtime>::ensure_actor_origin(origin.into(), member_id);
 
             assert_eq!(validation_result, Err(error));
         });
@@ -66,17 +77,28 @@ mod tests {
     #[test]
     fn council_origin_validator_succeeds() {
         initial_test_ext().execute_with(|| {
-            assert!(Council::set_council(system::RawOrigin::Root.into(), vec![1, 2, 3]).is_ok());
+            let councilor1 = AccountId32::default();
+            let councilor2: [u8; 32] = [2; 32];
+            let councilor3: [u8; 32] = [3; 32];
 
-            let account_id = 1;
-            let origin = RawOrigin::Signed(account_id);
-            let authority_account_id = 10;
-            Membership::set_screening_authority(RawOrigin::Root.into(), authority_account_id)
-                .unwrap();
+            assert!(Council::set_council(
+                system::RawOrigin::Root.into(),
+                vec![councilor1, councilor2.into(), councilor3.into()]
+            )
+            .is_ok());
+
+            let account_id = AccountId32::default();
+            let origin = RawOrigin::Signed(account_id.clone());
+            let authority_account_id = AccountId32::default();
+            Membership::set_screening_authority(
+                RawOrigin::Root.into(),
+                authority_account_id.clone(),
+            )
+            .unwrap();
 
             Membership::add_screened_member(
                 RawOrigin::Signed(authority_account_id).into(),
-                account_id,
+                account_id.clone(),
                 UserInfo {
                     handle: Some(b"handle".to_vec()),
                     avatar_uri: None,
@@ -87,7 +109,7 @@ mod tests {
             let member_id = 0; // newly created member_id
 
             let validation_result =
-                CouncilManager::<Test>::ensure_actor_origin(origin.into(), member_id);
+                CouncilManager::<Runtime>::ensure_actor_origin(origin.into(), member_id);
 
             assert_eq!(validation_result, Ok(account_id));
         });
@@ -96,16 +118,19 @@ mod tests {
     #[test]
     fn council_origin_validator_fails_with_incompatible_account_id_and_member_id() {
         initial_test_ext().execute_with(|| {
-            let account_id = 1;
+            let account_id = AccountId32::default();
             let error =
                 "Membership validation failed: given account doesn't match with profile accounts";
-            let authority_account_id = 10;
-            Membership::set_screening_authority(RawOrigin::Root.into(), authority_account_id)
-                .unwrap();
+            let authority_account_id = AccountId32::default();
+            Membership::set_screening_authority(
+                RawOrigin::Root.into(),
+                authority_account_id.clone(),
+            )
+            .unwrap();
 
             Membership::add_screened_member(
                 RawOrigin::Signed(authority_account_id).into(),
-                account_id,
+                account_id.clone(),
                 UserInfo {
                     handle: Some(b"handle".to_vec()),
                     avatar_uri: None,
@@ -115,9 +140,9 @@ mod tests {
             .unwrap();
             let member_id = 0; // newly created member_id
 
-            let invalid_account_id = 2;
-            let validation_result = CouncilManager::<Test>::ensure_actor_origin(
-                RawOrigin::Signed(invalid_account_id).into(),
+            let invalid_account_id: [u8; 32] = [2; 32];
+            let validation_result = CouncilManager::<Runtime>::ensure_actor_origin(
+                RawOrigin::Signed(invalid_account_id.into()).into(),
                 member_id,
             );
 
@@ -128,12 +153,15 @@ mod tests {
     #[test]
     fn council_origin_validator_fails_with_not_council_account_id() {
         initial_test_ext().execute_with(|| {
-            let account_id = 1;
-            let origin = RawOrigin::Signed(account_id);
+            let account_id = AccountId32::default();
+            let origin = RawOrigin::Signed(account_id.clone());
             let error = "Council validation failed: account id doesn't belong to a council member";
-            let authority_account_id = 10;
-            Membership::set_screening_authority(RawOrigin::Root.into(), authority_account_id)
-                .unwrap();
+            let authority_account_id = AccountId32::default();
+            Membership::set_screening_authority(
+                RawOrigin::Root.into(),
+                authority_account_id.clone(),
+            )
+            .unwrap();
 
             Membership::add_screened_member(
                 RawOrigin::Signed(authority_account_id).into(),
@@ -148,7 +176,7 @@ mod tests {
             let member_id = 0; // newly created member_id
 
             let validation_result =
-                CouncilManager::<Test>::ensure_actor_origin(origin.into(), member_id);
+                CouncilManager::<Runtime>::ensure_actor_origin(origin.into(), member_id);
 
             assert_eq!(validation_result, Err(error));
         });
@@ -157,9 +185,22 @@ mod tests {
     #[test]
     fn council_size_calculation_aka_total_voters_count_succeeds() {
         initial_test_ext().execute_with(|| {
-            assert!(Council::set_council(system::RawOrigin::Root.into(), vec![1, 2, 3, 7]).is_ok());
+            let councilor1 = AccountId32::default();
+            let councilor2: [u8; 32] = [2; 32];
+            let councilor3: [u8; 32] = [3; 32];
+            let councilor4: [u8; 32] = [4; 32];
+            assert!(Council::set_council(
+                system::RawOrigin::Root.into(),
+                vec![
+                    councilor1,
+                    councilor2.into(),
+                    councilor3.into(),
+                    councilor4.into()
+                ]
+            )
+            .is_ok());
 
-            assert_eq!(CouncilManager::<Test>::total_voters_count(), 4)
+            assert_eq!(CouncilManager::<Runtime>::total_voters_count(), 4)
         });
     }
 }

+ 34 - 23
runtime-modules/membership/src/origin_validator.rs → runtime/src/integration/proposals/membership_origin_validator.rs

@@ -29,7 +29,7 @@ impl<T: crate::members::Trait>
 
         if let Ok(profile) = profile_result {
             // whether the account_id belongs to the actor
-            if profile.root_account == account_id || profile.controller_account == account_id {
+            if profile.controller_account == account_id {
                 return Ok(account_id);
             } else {
                 return Err("Membership validation failed: given account doesn't match with profile accounts");
@@ -42,27 +42,32 @@ impl<T: crate::members::Trait>
 
 #[cfg(test)]
 mod tests {
-    use crate::members::UserInfo;
-    use crate::mock::{Test, TestExternalitiesBuilder};
-    use crate::origin_validator::MembershipOriginValidator;
+    use super::MembershipOriginValidator;
+    use crate::Runtime;
     use common::origin_validator::ActorOriginValidator;
+    use membership::members::UserInfo;
+    use sr_primitives::AccountId32;
     use system::RawOrigin;
 
-    type Membership = crate::members::Module<Test>;
+    type Membership = crate::members::Module<Runtime>;
 
-    pub fn initial_test_ext() -> runtime_io::TestExternalities {
-        TestExternalitiesBuilder::<Test>::default().build()
+    fn initial_test_ext() -> runtime_io::TestExternalities {
+        let t = system::GenesisConfig::default()
+            .build_storage::<Runtime>()
+            .unwrap();
+
+        t.into()
     }
 
     #[test]
     fn membership_origin_validator_fails_with_unregistered_member() {
         initial_test_ext().execute_with(|| {
-            let origin = RawOrigin::Signed(1);
+            let origin = RawOrigin::Signed(AccountId32::default());
             let member_id = 1;
             let error = "Membership validation failed: cannot find a profile for a member";
 
             let validation_result =
-                MembershipOriginValidator::<Test>::ensure_actor_origin(origin.into(), member_id);
+                MembershipOriginValidator::<Runtime>::ensure_actor_origin(origin.into(), member_id);
 
             assert_eq!(validation_result, Err(error));
         });
@@ -71,15 +76,18 @@ mod tests {
     #[test]
     fn membership_origin_validator_succeeds() {
         initial_test_ext().execute_with(|| {
-            let account_id = 1;
-            let origin = RawOrigin::Signed(account_id);
-            let authority_account_id = 10;
-            Membership::set_screening_authority(RawOrigin::Root.into(), authority_account_id)
-                .unwrap();
+            let account_id = AccountId32::default();
+            let origin = RawOrigin::Signed(account_id.clone());
+            let authority_account_id = AccountId32::default();
+            Membership::set_screening_authority(
+                RawOrigin::Root.into(),
+                authority_account_id.clone(),
+            )
+            .unwrap();
 
             Membership::add_screened_member(
                 RawOrigin::Signed(authority_account_id).into(),
-                account_id,
+                account_id.clone(),
                 UserInfo {
                     handle: Some(b"handle".to_vec()),
                     avatar_uri: None,
@@ -90,7 +98,7 @@ mod tests {
             let member_id = 0; // newly created member_id
 
             let validation_result =
-                MembershipOriginValidator::<Test>::ensure_actor_origin(origin.into(), member_id);
+                MembershipOriginValidator::<Runtime>::ensure_actor_origin(origin.into(), member_id);
 
             assert_eq!(validation_result, Ok(account_id));
         });
@@ -99,12 +107,15 @@ mod tests {
     #[test]
     fn membership_origin_validator_fails_with_incompatible_account_id_and_member_id() {
         initial_test_ext().execute_with(|| {
-            let account_id = 1;
+            let account_id = AccountId32::default();
             let error =
                 "Membership validation failed: given account doesn't match with profile accounts";
-            let authority_account_id = 10;
-            Membership::set_screening_authority(RawOrigin::Root.into(), authority_account_id)
-                .unwrap();
+            let authority_account_id = AccountId32::default();
+            Membership::set_screening_authority(
+                RawOrigin::Root.into(),
+                authority_account_id.clone(),
+            )
+            .unwrap();
 
             Membership::add_screened_member(
                 RawOrigin::Signed(authority_account_id).into(),
@@ -118,9 +129,9 @@ mod tests {
             .unwrap();
             let member_id = 0; // newly created member_id
 
-            let invalid_account_id = 2;
-            let validation_result = MembershipOriginValidator::<Test>::ensure_actor_origin(
-                RawOrigin::Signed(invalid_account_id).into(),
+            let invalid_account_id: [u8; 32] = [2; 32];
+            let validation_result = MembershipOriginValidator::<Runtime>::ensure_actor_origin(
+                RawOrigin::Signed(invalid_account_id.into()).into(),
                 member_id,
             );
 

+ 7 - 0
runtime/src/integration/proposals/mod.rs

@@ -0,0 +1,7 @@
+mod council_origin_validator;
+mod membership_origin_validator;
+mod staking_events_handler;
+
+pub use council_origin_validator::CouncilManager;
+pub use membership_origin_validator::{MemberId, MembershipOriginValidator};
+pub use staking_events_handler::StakingEventsHandler;

+ 47 - 0
runtime/src/integration/proposals/staking_events_handler.rs

@@ -0,0 +1,47 @@
+use rstd::marker::PhantomData;
+use srml_support::traits::{Currency, Imbalance};
+use srml_support::StorageMap;
+
+// Balance alias
+type BalanceOf<T> =
+    <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
+
+// Balance alias for staking
+type NegativeImbalance<T> =
+    <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
+
+/// Proposal implementation of the staking event handler from the stake module.
+/// 'marker' responsible for the 'Trait' binding.
+pub struct StakingEventsHandler<T> {
+    pub marker: PhantomData<T>,
+}
+
+impl<T: stake::Trait + proposals_engine::Trait> stake::StakingEventsHandler<T>
+    for StakingEventsHandler<T>
+{
+    /// Unstake remaining sum back to the source_account_id
+    fn unstaked(
+        id: &<T as stake::Trait>::StakeId,
+        _unstaked_amount: BalanceOf<T>,
+        remaining_imbalance: NegativeImbalance<T>,
+    ) -> NegativeImbalance<T> {
+        if <proposals_engine::StakesProposals<T>>::exists(id) {
+            <proposals_engine::Module<T>>::refund_proposal_stake(*id, remaining_imbalance);
+
+            return <NegativeImbalance<T>>::zero(); // imbalance was consumed
+        }
+
+        remaining_imbalance
+    }
+
+    /// Empty handler for slashing
+    fn slashed(
+        _: &<T as stake::Trait>::StakeId,
+        _: Option<<T as stake::Trait>::SlashId>,
+        _: BalanceOf<T>,
+        _: BalanceOf<T>,
+        remaining_imbalance: NegativeImbalance<T>,
+    ) -> NegativeImbalance<T> {
+        remaining_imbalance
+    }
+}

+ 8 - 6
runtime/src/lib.rs

@@ -16,6 +16,8 @@ mod test;
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
+mod integration;
+
 use authority_discovery_primitives::{
     AuthorityId as EncodedAuthorityId, Signature as EncodedSignature,
 };
@@ -57,7 +59,7 @@ pub use srml_support::{
 pub use staking::StakerStatus;
 pub use timestamp::Call as TimestampCall;
 
-use membership::origin_validator::MembershipOriginValidator;
+use integration::proposals::{CouncilManager, MembershipOriginValidator};
 
 /// An index to a block.
 pub type BlockNumber = u32;
@@ -587,7 +589,7 @@ impl stake::Trait for Runtime {
     type StakePoolId = StakePoolId;
     type StakingEventsHandler = (
         ContentWorkingGroupStakingEventHandler,
-        proposals_engine::StakingEventsHandler<Self>,
+        crate::integration::proposals::StakingEventsHandler<Self>,
     );
     type StakeId = u64;
     type SlashId = u64;
@@ -819,8 +821,8 @@ parameter_types! {
 impl proposals_engine::Trait for Runtime {
     type Event = Event;
     type ProposerOriginValidator = MembershipOriginValidator<Self>;
-    type VoterOriginValidator = proposals_engine::CouncilManager<Self>;
-    type TotalVotersCounter = proposals_engine::CouncilManager<Self>;
+    type VoterOriginValidator = CouncilManager<Self>;
+    type TotalVotersCounter = CouncilManager<Self>;
     type ProposalId = u32;
     type StakeHandlerProvider = proposals_engine::DefaultStakeHandlerProvider;
     type CancellationFee = ProposalCancellationFee;
@@ -828,7 +830,7 @@ impl proposals_engine::Trait for Runtime {
     type TitleMaxLength = ProposalTitleMaxLength;
     type DescriptionMaxLength = ProposalDescriptionMaxLength;
     type MaxActiveProposalLimit = ProposalMaxActiveProposalLimit;
-    type ProposalCode = Call;
+    type DispatchableCallCode = Call;
 }
 impl Default for Call {
     fn default() -> Self {
@@ -845,7 +847,6 @@ parameter_types! {
 
 impl proposals_discussion::Trait for Runtime {
     type Event = Event;
-    type ThreadAuthorOriginValidator = MembershipOriginValidator<Self>;
     type PostAuthorOriginValidator = MembershipOriginValidator<Self>;
     type ThreadId = u32;
     type PostId = u32;
@@ -861,6 +862,7 @@ parameter_types! {
 }
 
 impl proposals_codex::Trait for Runtime {
+    type MembershipOriginValidator = MembershipOriginValidator<Self>;
     type TextProposalMaxLength = TextProposalMaxLength;
     type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength;
 }

+ 15 - 17
runtime/src/test/proposals_integration.rs

@@ -6,8 +6,8 @@ use crate::{ProposalCancellationFee, Runtime};
 use codec::Encode;
 use membership::members;
 use proposals_engine::{
-    BalanceOf, Error, FinalizationData, Proposal, ProposalDecisionStatus, ProposalParameters,
-    ProposalStatus, StakeData, VotingResults,
+    ActiveStake, BalanceOf, Error, FinalizationData, Proposal, ProposalDecisionStatus,
+    ProposalParameters, ProposalStatus, VotingResults,
 };
 use sr_primitives::traits::DispatchResult;
 use sr_primitives::AccountId32;
@@ -28,7 +28,7 @@ type ProposalsEngine = proposals_engine::Module<Runtime>;
 #[derive(Clone)]
 struct DummyProposalFixture {
     parameters: ProposalParameters<u32, u128>,
-    origin: RawOrigin<AccountId32>,
+    account_id: AccountId32,
     proposer_id: u64,
     proposal_code: Vec<u8>,
     title: Vec<u8>,
@@ -56,7 +56,7 @@ impl Default for DummyProposalFixture {
                 grace_period: 0,
                 required_stake: None,
             },
-            origin: RawOrigin::Signed(<Runtime as system::Trait>::AccountId::default()),
+            account_id: <Runtime as system::Trait>::AccountId::default(),
             proposer_id: 0,
             proposal_code: dummy_proposal.encode(),
             title,
@@ -71,8 +71,8 @@ impl DummyProposalFixture {
         DummyProposalFixture { parameters, ..self }
     }
 
-    fn with_origin(self, origin: RawOrigin<AccountId32>) -> Self {
-        DummyProposalFixture { origin, ..self }
+    fn with_account_id(self, account_id: AccountId32) -> Self {
+        DummyProposalFixture { account_id, ..self }
     }
 
     fn with_stake(self, stake_balance: BalanceOf<Runtime>) -> Self {
@@ -91,7 +91,7 @@ impl DummyProposalFixture {
 
     fn create_proposal_and_assert(self, result: Result<u32, Error>) -> Option<u32> {
         let proposal_id_result = ProposalsEngine::create_proposal(
-            self.origin.into(),
+            self.account_id,
             self.proposer_id,
             self.parameters,
             self.title,
@@ -122,7 +122,7 @@ impl CancelProposalFixture {
     }
 
     fn with_proposer(self, proposer_id: u64) -> Self {
-		CancelProposalFixture {
+        CancelProposalFixture {
             proposer_id,
             ..self
         }
@@ -140,7 +140,6 @@ impl CancelProposalFixture {
     }
 }
 
-
 /// Main purpose of this integration test: check balance of the member on proposal finalization (cancellation)
 /// It tests StakingEventsHandler integration. Also, membership module is tested during the proposal creation (ActorOriginValidator).
 #[test]
@@ -174,7 +173,7 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
         };
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters)
-            .with_origin(RawOrigin::Signed(account_id.clone()))
+            .with_account_id(account_id.clone())
             .with_stake(stake_amount)
             .with_proposer(member_id);
 
@@ -199,14 +198,13 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
             parameters,
             proposer_id: member_id,
             created_at: 1,
-            status: ProposalStatus::Active,
+            status: ProposalStatus::Active(Some(ActiveStake {
+                stake_id: 0,
+                source_account_id: account_id.clone(),
+            })),
             title: b"title".to_vec(),
             description: b"description".to_vec(),
             voting_results: VotingResults::default(),
-            stake_data: Some(StakeData {
-                stake_id: 0,
-                source_account_id: account_id.clone(),
-            }),
         };
 
         assert_eq!(proposal, expected_proposal);
@@ -221,9 +219,9 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
         expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
             proposal_status: ProposalDecisionStatus::Canceled,
             finalized_at: 1,
-            finalization_error: None,
+            encoded_unstaking_error_due_to_broken_runtime: None,
+            stake_data_after_unstaking_error: None,
         });
-        expected_proposal.stake_data = None;
 
         assert_eq!(proposal, expected_proposal);