Council events (#703)

* Initial bits

* More stuff

* Cleave voting from council

* More events

* Rearrange council a little

* Fix demo

* More info in events
This commit is contained in:
Gav Wood
2018-09-10 21:11:47 +02:00
committed by GitHub
parent 6c1b2c27d1
commit c9845f33d8
15 changed files with 1548 additions and 1389 deletions
+3 -3
View File
@@ -65,8 +65,8 @@ build_rpc_trait! {
fn storage_size(&self, StorageKey, Trailing<Hash>) -> Result<Option<u64>>;
/// Returns the runtime metadata as JSON.
#[rpc(name = "state_metadata", alias = ["state_metadataAt", ])]
fn json_metadata(&self, Trailing<Hash>) -> Result<serde_json::Value>;
#[rpc(name = "state_getMetadata")]
fn metadata(&self, Trailing<Hash>) -> Result<serde_json::Value>;
/// Query historical storage entries (by key) starting from a block given as the second parameter.
///
@@ -143,7 +143,7 @@ impl<B, E, Block> StateApi<Block::Hash> for State<B, E, Block> where
Ok(self.storage(key, block)?.map(|x| x.0.len() as u64))
}
fn json_metadata(&self, block: Trailing<Block::Hash>) -> Result<serde_json::Value> {
fn metadata(&self, block: Trailing<Block::Hash>) -> Result<serde_json::Value> {
let block = self.unwrap_or_best(block)?;
let metadata = self.client.json_metadata(&BlockId::Hash(block))?;
serde_json::from_str(&metadata).map_err(Into::into)
File diff suppressed because it is too large Load Diff
@@ -19,7 +19,7 @@
use rstd::prelude::*;
use rstd::result;
use substrate_primitives::u32_trait::Value as U32;
use primitives::traits::{Hash, EnsureOrigin, MaybeSerializeDebug};
use primitives::traits::{Hash, EnsureOrigin, MaybeSerializeDebug, OnFinalise};
use substrate_runtime_support::dispatch::{Result, Dispatchable, Parameter};
use substrate_runtime_support::{StorageValue, StorageMap};
use super::{Trait as CouncilTrait, Module as Council};
@@ -167,7 +167,7 @@ impl<T: Trait> Module<T> {
let threshold = voting.1;
let potential_votes = <Council<T>>::active_council().len() as u32;
let approved = yes_votes >= threshold;
let disapproved = potential_votes - no_votes < threshold;
let disapproved = potential_votes.saturating_sub(no_votes) < threshold;
if approved || disapproved {
if approved {
Self::deposit_event(RawEvent::Approved(proposal));
@@ -194,6 +194,11 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
}
}
/// Ensure that the origin `o` represents at least `n` council members. Returns
/// `Ok` or an `Err` otherwise.
pub fn ensure_council_members<OuterOrigin>(o: OuterOrigin, n: u32) -> result::Result<u32, &'static str>
@@ -218,13 +223,12 @@ impl<O, N: U32> EnsureOrigin<O> for EnsureMembers<N>
#[cfg(test)]
mod tests {
use super::*;
use super::RawEvent;
use ::tests::*;
use ::tests::{Call, Origin, Event as OuterEvent};
use substrate_runtime_support::Hashable;
use system::{EventRecord, Phase};
type CouncilMotions = super::Module<Test>;
#[test]
fn motions_basic_environment_works() {
with_externalities(&mut new_test_ext(true), || {
@@ -252,7 +256,7 @@ mod tests {
assert_eq!(System::events(), vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 3))
event: OuterEvent::motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 3))
}
]);
});
@@ -305,11 +309,11 @@ mod tests {
assert_eq!(System::events(), vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 2))
event: OuterEvent::motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 2))
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Voted(1, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false, 0, 1))
event: OuterEvent::motions(RawEvent::Voted(1, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false, 0, 1))
}
]);
});
@@ -327,15 +331,15 @@ mod tests {
assert_eq!(System::events(), vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 3))
event: OuterEvent::motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 3))
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Voted(2, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false, 1, 1))
event: OuterEvent::motions(RawEvent::Voted(2, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false, 1, 1))
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Disapproved(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into()))
event: OuterEvent::motions(RawEvent::Disapproved(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into()))
}
]);
});
@@ -353,19 +357,19 @@ mod tests {
assert_eq!(System::events(), vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 2))
event: OuterEvent::motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 2))
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Voted(2, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), true, 2, 0))
event: OuterEvent::motions(RawEvent::Voted(2, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), true, 2, 0))
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Approved(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into()))
event: OuterEvent::motions(RawEvent::Approved(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into()))
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: OuterEvent::council_motions(RawEvent::Executed(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false))
event: OuterEvent::motions(RawEvent::Executed(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false))
}
]);
});
File diff suppressed because it is too large Load Diff
@@ -23,9 +23,13 @@ use runtime_io::print;
use substrate_runtime_support::dispatch::Result;
use substrate_runtime_support::{StorageValue, StorageMap, IsSubType};
use {system, democracy};
use super::{Trait, Module as Council};
use super::{Trait as CouncilTrait, Module as Council};
use system::{ensure_signed, ensure_root};
pub trait Trait: CouncilTrait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn propose(origin, proposal: Box<T::Proposal>) -> Result;
@@ -49,7 +53,29 @@ decl_storage! {
}
}
pub type Event<T> = RawEvent<<T as system::Trait>::Hash>;
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<Hash> {
/// A voting tally has happened for a referendum cancelation vote. Last three are yes, no, abstain counts.
TallyCancelation(Hash, u32, u32, u32),
/// A voting tally has happened for a referendum vote. Last three are yes, no, abstain counts.
TallyReferendum(Hash, u32, u32, u32),
}
impl<N> From<RawEvent<N>> for () {
fn from(_: RawEvent<N>) -> () { () }
}
impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
pub fn is_vetoed<B: Borrow<T::Hash>>(proposal: B) -> bool {
Self::veto_of(proposal.borrow())
.map(|(expiry, _): (T::BlockNumber, Vec<T::AccountId>)| <system::Module<T>>::block_number() < expiry)
@@ -91,7 +117,8 @@ impl<T: Trait> Module<T> {
<ProposalOf<T>>::insert(proposal_hash, *proposal);
<ProposalVoters<T>>::insert(proposal_hash, vec![who.clone()]);
<CouncilVoteOf<T>>::insert((proposal_hash, who), true);
<CouncilVoteOf<T>>::insert((proposal_hash, who.clone()), true);
Ok(())
}
@@ -101,9 +128,7 @@ impl<T: Trait> Module<T> {
ensure!(Self::is_councillor(&who), "only councillors may vote on council proposals");
if Self::vote_of((proposal, who.clone())).is_none() {
let mut voters = Self::proposal_voters(&proposal);
voters.push(who.clone());
<ProposalVoters<T>>::insert(proposal, voters);
<ProposalVoters<T>>::mutate(proposal, |voters| voters.push(who.clone()));
}
<CouncilVoteOf<T>>::insert((proposal, who), approve);
Ok(())
@@ -188,10 +213,12 @@ impl<T: Trait> Module<T> {
while let Some((proposal, proposal_hash)) = Self::take_proposal_if_expiring_at(now) {
let tally = Self::take_tally(&proposal_hash);
if let Some(&democracy::Call::cancel_referendum(ref_index)) = IsSubType::<democracy::Module<T>>::is_aux_sub_type(&proposal) {
Self::deposit_event(RawEvent::TallyCancelation(proposal_hash, tally.0, tally.1, tally.2));
if let (_, 0, 0) = tally {
<democracy::Module<T>>::internal_cancel_referendum(ref_index);
}
} else {
Self::deposit_event(RawEvent::TallyReferendum(proposal_hash.clone(), tally.0, tally.1, tally.2));
if tally.0 > tally.1 + tally.2 {
Self::kill_veto_of(&proposal_hash);
match tally {
@@ -205,16 +232,12 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> OnFinalise<T::BlockNumber> for Council<T> {
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(n: T::BlockNumber) {
if let Err(e) = Self::end_block(n) {
print("Guru meditation");
print(e);
}
if let Err(e) = <Module<T>>::end_block(n) {
print("Guru meditation");
print(e);
}
}
}
@@ -226,8 +249,6 @@ mod tests {
use substrate_runtime_support::Hashable;
use democracy::VoteThreshold;
type CouncilVoting = super::Module<Test>;
#[test]
fn basic_environment_works() {
with_externalities(&mut new_test_ext(true), || {
@@ -185,13 +185,33 @@ pub trait OnFinalise<BlockNumber> {
}
impl<N> OnFinalise<N> for () {}
impl<N: Copy, A: OnFinalise<N>, B: OnFinalise<N>> OnFinalise<N> for (A, B) {
fn on_finalise(n: N) {
A::on_finalise(n);
B::on_finalise(n);
macro_rules! tuple_impl {
($one:ident,) => {
impl<Number: Copy, $one: OnFinalise<Number>> OnFinalise<Number> for ($one,) {
fn on_finalise(n: Number) {
$one::on_finalise(n);
}
}
};
($first:ident, $($rest:ident,)+) => {
impl<
Number: Copy,
$first: OnFinalise<Number>,
$($rest: OnFinalise<Number>),+
> OnFinalise<Number> for ($first, $($rest),+) {
fn on_finalise(n: Number) {
$first::on_finalise(n);
$($rest::on_finalise(n);)+
}
}
tuple_impl!($($rest,)+);
}
}
#[allow(non_snake_case)]
tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,);
/// Abstraction around hashing
pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq { // Stupid bug in the Rust compiler believes derived
// traits must be fulfilled by all type parameters.
@@ -122,6 +122,12 @@ decl_storage! {
}
impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
/// The number of validators currently.
pub fn validator_count() -> u32 {
<Validators<T>>::get().len() as u32 // TODO: can probably optimised
@@ -186,11 +192,6 @@ impl<T: Trait> Module<T> {
}
}
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
/// Move onto next session: register the new authority set.
pub fn rotate_session(is_final_block: bool, apply_rewards: bool) {
let now = <timestamp::Module<T>>::get();