Improve event json metadata (#710)

* Introduce `impl_event!` for declaring the Event/RawEvent for a module

* Implements a function for generating the event json metadata

* Update runtime `json_metadata` to include the new event json metadata

* Switch to `impl_event!` for new modules

* Remove unused module declaration in `impl_event!`

* Rename `impl_event!` to `decl_event!`

* Fixes some style nits
This commit is contained in:
Bastian Köcher
2018-09-11 14:05:09 +02:00
committed by Gav Wood
parent da56ae7e46
commit fd2ec13ed8
14 changed files with 522 additions and 277 deletions
+4 -1
View File
@@ -802,6 +802,9 @@ mod tests {
client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap();
assert_eq!(client.json_metadata(&BlockId::Number(1)).unwrap(), r#"{ "events": "events" }"#);
assert_eq!(
client.json_metadata(&BlockId::Number(1)).unwrap(),
r#"{ "events": { "name": "Test", "events": { "event": hallo } } }"#
);
}
}
+205 -23
View File
@@ -14,6 +14,123 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
/// Implement an `Event`/`RawEvent` for a module.
#[macro_export]
macro_rules! decl_event {
(
$(#[$attr:meta])*
pub enum Event<$( $evt_generic_param:ident )*> with RawEvent<$( $generic_param:ident ),*>
where $( <$generic:ident as $trait:path>::$trait_type:ident),* {
$(
$(#[doc = $doc_attr:tt])*
$event:ident( $( $param:path ),* ),
)*
}
) => {
pub type Event<$( $evt_generic_param )*> = RawEvent<$( <$generic as $trait>::$trait_type ),*>;
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
$(#[$attr])*
pub enum RawEvent<$( $generic_param ),*> {
$(
$( #[doc = $doc_attr] )*
$event($( $param ),*),
)*
}
impl<$( $generic_param ),*> From<RawEvent<$( $generic_param ),*>> for () {
fn from(_: RawEvent<$( $generic_param ),*>) -> () { () }
}
impl<$( $generic_param ),*> RawEvent<$( $generic_param ),*> {
#[allow(dead_code)]
pub fn event_json_metadata() -> &'static str {
concat!(
"{",
__impl_event_json_metadata!("";
$(
$event ( $( $param ),* );
__function_doc_to_json!(""; $($doc_attr)*);
)*
),
" }"
)
}
}
};
(
$(#[$attr:meta])*
pub enum Event {
$(
$(#[doc = $doc_attr:tt])*
$event:ident,
)*
}
) => {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
$(#[$attr])*
pub enum Event {
$(
$( #[doc = $doc_attr] )*
$event,
)*
}
impl From<Event> for () {
fn from(_: Event) -> () { () }
}
impl Event {
#[allow(dead_code)]
pub fn event_json_metadata() -> &'static str {
concat!(
"{",
__impl_event_json_metadata!("";
$(
$event;
__function_doc_to_json!(""; $($doc_attr)*);
)*
),
" }"
)
}
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_event_json_metadata {
(
$prefix_str:expr;
$event:ident( $first_param:path $(, $param:path )* );
$event_doc:expr;
$( $rest:tt )*
) => {
concat!($prefix_str, " ", "\"", stringify!($event), r#"": { "params": [ ""#,
stringify!($first_param), "\""
$(, concat!(", \"", stringify!($param), "\"") )*, r#" ], "description": ["#,
$event_doc, " ] }",
__impl_event_json_metadata!(","; $( $rest )*)
)
};
(
$prefix_str:expr;
$event:ident;
$event_doc:expr;
$( $rest:tt )*
) => {
concat!($prefix_str, " ", "\"", stringify!($event),
r#"": { "params": null, "description": ["#, $event_doc, " ] }",
__impl_event_json_metadata!(","; $( $rest )*)
)
};
(
$prefix_str:expr;
) => {
""
}
}
#[macro_export]
macro_rules! impl_outer_event {
($(#[$attr:meta])* pub enum $name:ident for $runtime:ident { $( $module:ident ),* }) => {
@@ -54,39 +171,84 @@ macro_rules! __impl_outer_event_json_metadata {
) => {
impl $runtime {
#[allow(dead_code)]
pub fn outer_event_json_metadata() -> &'static str {
concat!(r#"{ "name": ""#, stringify!($event_name), r#"", "items": { "#,
r#""system": "system::Event""#,
$(concat!(", \"", stringify!($module), r#"": ""#,
stringify!($module), "::Event<", stringify!($runtime), r#">""#),)*
" } }")
pub fn outer_event_json_metadata() -> (&'static str, &'static [(&'static str, fn() -> &'static str)]) {
static METADATA: &[(&str, fn() -> &'static str)] = &[
("system", system::Event::event_json_metadata)
$(
, (
stringify!($module),
$module::Event::<$runtime>::event_json_metadata
)
)*
];
(
stringify!($event_name),
METADATA
)
}
}
}
}
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use serde;
use serde_json;
mod system {
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
pub struct Event;
pub trait Trait {
type Origin;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
decl_event!(
pub enum Event {
SystemEvent,
}
);
}
mod event_module {
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
pub struct Event<T> {
t: T,
pub trait Trait {
type Origin;
type Balance;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
decl_event!(
pub enum Event<T> with RawEvent<Balance>
where <T as Trait>::Balance
{
/// Hi, I am a comment.
TestEvent(Balance),
}
);
}
mod event_module2 {
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
pub struct Event<T> {
t: T,
pub trait Trait {
type Origin;
type Balance;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
decl_event!(
pub enum Event<T> with RawEvent<Balance>
where <T as Trait>::Balance
{
TestEvent(Balance),
}
);
}
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
@@ -98,19 +260,39 @@ mod tests {
}
}
const EXPECTED_METADATA: &str = concat!(
r#"{ "name": "TestEvent", "items": { "#,
r#""system": "system::Event", "#,
r#""event_module": "event_module::Event<TestRuntime>", "#,
r#""event_module2": "event_module2::Event<TestRuntime>" "#,
r#"} }"#
impl event_module::Trait for TestRuntime {
type Origin = u32;
type Balance = u32;
}
impl event_module2::Trait for TestRuntime {
type Origin = u32;
type Balance = u32;
}
impl system::Trait for TestRuntime {
type Origin = u32;
}
const EXPECTED_METADATA: (&str, &[(&str, &str)]) = (
"TestEvent", &[
("system", r#"{ "SystemEvent": { "params": null, "description": [ ] } }"#),
("event_module", r#"{ "TestEvent": { "params": [ "Balance" ], "description": [ " Hi, I am a comment." ] } }"#),
("event_module2", r#"{ "TestEvent": { "params": [ "Balance" ], "description": [ ] } }"#),
]
);
#[test]
fn outer_event_json_metadata() {
let metadata = TestRuntime::outer_event_json_metadata();
assert_eq!(EXPECTED_METADATA, metadata);
let _: serde::de::IgnoredAny =
serde_json::from_str(metadata).expect("Is valid json syntax");
assert_eq!(EXPECTED_METADATA.0, metadata.0);
assert_eq!(EXPECTED_METADATA.1.len(), metadata.1.len());
for (expected, got) in EXPECTED_METADATA.1.iter().zip(metadata.1.iter()) {
assert_eq!(expected.0, got.0);
assert_eq!(expected.1, got.1());
let _: serde::de::IgnoredAny =
serde_json::from_str(got.1()).expect(&format!("Is valid json syntax: {}", got.1()));
}
}
}
@@ -40,9 +40,11 @@ macro_rules! impl_json_metadata {
) => {
impl $runtime {
pub fn json_metadata() -> $crate::metadata::Vec<$crate::metadata::JSONMetadata> {
let events = Self::outer_event_json_metadata();
__impl_json_metadata!($runtime;
$crate::metadata::JSONMetadata::Events {
events: Self::outer_event_json_metadata()
name: events.0,
events: events.1,
};
$( $rest )*
)
@@ -52,10 +54,10 @@ macro_rules! impl_json_metadata {
}
/// The metadata of a runtime encoded as JSON.
#[derive(Eq, PartialEq)]
#[derive(Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum JSONMetadata {
Events { events: &'static str },
Events { name: &'static str, events: &'static [(&'static str, fn() -> &'static str)] },
Module { module: &'static str, prefix: &'static str },
ModuleWithStorage { module: &'static str, prefix: &'static str, storage: &'static str }
}
@@ -63,9 +65,14 @@ pub enum JSONMetadata {
impl Encode for JSONMetadata {
fn encode_to<W: Output>(&self, dest: &mut W) {
match self {
JSONMetadata::Events { events } => {
JSONMetadata::Events { name, events } => {
0i8.encode_to(dest);
events.encode_to(dest);
name.encode_to(dest);
events.iter().fold(0u32, |count, _| count + 1).encode_to(dest);
events
.iter()
.map(|(module, data)| (module, data()))
.for_each(|val| val.encode_to(dest));
},
JSONMetadata::Module { module, prefix } => {
1i8.encode_to(dest);
@@ -82,11 +89,39 @@ impl Encode for JSONMetadata {
}
}
impl PartialEq<JSONMetadata> for JSONMetadata {
fn eq(&self, other: &JSONMetadata) -> bool {
match (self, other) {
(
JSONMetadata::Events { name: lname, events: left },
JSONMetadata::Events { name: rname, events: right }
) => {
lname == rname && left.iter().zip(right.iter()).fold(true, |res, (l, r)| {
res && l.0 == r.0 && l.1() == r.1()
})
},
(
JSONMetadata::Module { prefix: lpre, module: lmod },
JSONMetadata::Module { prefix: rpre, module: rmod }
) => {
lpre == rpre && lmod == rmod
},
(
JSONMetadata::ModuleWithStorage { prefix: lpre, module: lmod, storage: lstore },
JSONMetadata::ModuleWithStorage { prefix: rpre, module: rmod, storage: rstore }
) => {
lpre == rpre && lmod == rmod && lstore == rstore
},
_ => false,
}
}
}
/// Utility struct for making `JSONMetadata` decodeable.
#[derive(Eq, PartialEq, Debug)]
#[cfg(feature = "std")]
pub enum JSONMetadataDecodable {
Events { events: String },
Events { name: String, events: Vec<(String, String)> },
Module { module: String, prefix: String },
ModuleWithStorage { module: String, prefix: String, storage: String }
}
@@ -97,15 +132,33 @@ impl JSONMetadataDecodable {
/// The first value of the tuple is the name of the metadata type and the second in the JSON string.
pub fn into_json_string(self) -> (&'static str, String) {
match self {
JSONMetadataDecodable::Events { events } => {
("events", events)
JSONMetadataDecodable::Events { name, events } => {
(
"events",
format!(
r#"{{ "name": "{}", "events": {{ {} }} }}"#, name,
events.iter().enumerate()
.fold(String::from(""), |mut json, (i, (name, data))| {
if i > 0 {
json.push_str(", ");
}
json.push_str(&format!(r#""{}": {}"#, name, data));
json
})
)
)
},
JSONMetadataDecodable::Module { prefix, module } => {
("module", format!(r#"{{ "prefix": "{}", "module": {} }}"#, prefix, module))
},
JSONMetadataDecodable::ModuleWithStorage { prefix, module, storage } => {
("moduleWithStorage",
format!(r#"{{ "prefix": "{}", "module": {}, "storage": {} }}"#, prefix, module, storage))
(
"moduleWithStorage",
format!(
r#"{{ "prefix": "{}", "module": {}, "storage": {} }}"#,
prefix, module, storage
)
)
}
}
}
@@ -117,7 +170,8 @@ impl Decode for JSONMetadataDecodable {
i8::decode(input).and_then(|variant| {
match variant {
0 => String::decode(input)
.and_then(|events| Some(JSONMetadataDecodable::Events { events })),
.and_then(|name| Vec::<(String, String)>::decode(input).map(|events| (name, events)))
.and_then(|(name, events)| Some(JSONMetadataDecodable::Events { name, events })),
1 => String::decode(input)
.and_then(|prefix| String::decode(input).map(|v| (prefix, v)))
.and_then(|(prefix, module)| Some(JSONMetadataDecodable::Module { prefix, module })),
@@ -136,10 +190,12 @@ impl PartialEq<JSONMetadata> for JSONMetadataDecodable {
fn eq(&self, other: &JSONMetadata) -> bool {
match (self, other) {
(
JSONMetadataDecodable::Events { events: left },
JSONMetadata::Events { events: right }
JSONMetadataDecodable::Events { name: lname, events: left },
JSONMetadata::Events { name: rname, events: right }
) => {
left == right
lname == rname && left.iter().zip(right.iter()).fold(true, |res, (l, r)| {
res && l.0 == r.0 && l.1 == r.1()
})
},
(
JSONMetadataDecodable::Module { prefix: lpre, module: lmod },
@@ -228,21 +284,42 @@ macro_rules! __impl_json_metadata {
#[allow(dead_code)]
mod tests {
use super::*;
use dispatch::Result;
use serde;
use serde_json;
mod system {
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
pub struct Event;
pub trait Trait {
type Origin;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
decl_event!(
pub enum Event {
SystemEvent,
}
);
}
mod event_module {
use super::*;
use dispatch::Result;
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
pub struct Event<T> {
t: T,
pub trait Trait {
type Origin;
type Balance;
}
decl_event!(
pub enum Event<T> with RawEvent<Balance>
where <T as Trait>::Balance
{
/// Hi, I am a comment.
TestEvent(Balance),
}
);
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn aux_0(origin) -> Result;
@@ -257,13 +334,19 @@ mod tests {
}
mod event_module2 {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Deserialize, Serialize)]
pub struct Event<T> {
t: T,
pub trait Trait {
type Origin;
type Balance;
}
decl_event!(
pub enum Event<T> with RawEvent<Balance>
where <T as Trait>::Balance
{
TestEvent(Balance),
}
);
decl_module! {
pub struct ModuleWithStorage<T: Trait> for enum Call where origin: T::Origin {}
}
@@ -284,11 +367,17 @@ mod tests {
}
}
pub trait Trait {
type Origin;
impl event_module::Trait for TestRuntime {
type Origin = u32;
type Balance = u32;
}
impl Trait for TestRuntime {
impl event_module2::Trait for TestRuntime {
type Origin = u32;
type Balance = u32;
}
impl system::Trait for TestRuntime {
type Origin = u32;
}
@@ -298,13 +387,26 @@ mod tests {
event_module2::ModuleWithStorage with Storage
);
fn system_event_json() -> &'static str {
r#"{ "SystemEvent": { "params": null, "description": [ ] } }"#
}
fn event_module_event_json() -> &'static str {
r#"{ "TestEvent": { "params": [ "Balance" ], "description": [ " Hi, I am a comment." ] } }"#
}
fn event_module2_event_json() -> &'static str {
r#"{ "TestEvent": { "params": [ "Balance" ], "description": [ ] } }"#
}
const EXPECTED_METADATA: &[JSONMetadata] = &[
JSONMetadata::Events {
events: concat!(
r#"{ "name": "TestEvent", "items": "#,
r#"{ "system": "system::Event", "#,
r#""event_module": "event_module::Event<TestRuntime>", "#,
r#""event_module2": "event_module2::Event<TestRuntime>" } }"#)
name: "TestEvent",
events: &[
("system", system_event_json),
("event_module", event_module_event_json),
("event_module2", event_module2_event_json),
]
},
JSONMetadata::Module {
module: concat!(
@@ -341,4 +443,17 @@ mod tests {
assert_eq!(&metadata_decoded.unwrap()[..], &metadata[..]);
}
#[test]
fn into_json_string_is_valid_json() {
let metadata = TestRuntime::json_metadata();
let metadata_encoded = metadata.encode();
let metadata_decoded = Vec::<JSONMetadataDecodable>::decode(&mut &metadata_encoded[..]);
for mdata in metadata_decoded.unwrap().into_iter() {
let json = mdata.into_json_string();
let _: serde::de::IgnoredAny =
serde_json::from_str(&json.1).expect(&format!("Is valid json syntax: {}", json.1));
}
}
}
+14 -24
View File
@@ -67,12 +67,6 @@ const RECLAIM_INDEX_MAGIC: usize = 0x69;
pub type Address<T> = RawAddress<<T as system::Trait>::AccountId, <T as Trait>::AccountIndex>;
pub type Event<T> = RawEvent<
<T as system::Trait>::AccountId,
<T as Trait>::AccountIndex,
<T as Trait>::Balance,
>;
/// The account with the given id was killed.
pub trait OnFreeBalanceZero<AccountId> {
/// The account was the given id was killed.
@@ -130,7 +124,7 @@ pub trait Trait: system::Trait {
/// A function that returns true iff a given account can transfer its funds to another account.
type EnsureAccountLiquid: EnsureAccountLiquid<Self::AccountId>;
/// The overarching event type.
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
@@ -141,21 +135,17 @@ decl_module! {
}
}
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<AccountId, AccountIndex, Balance> {
/// A new account was created.
NewAccount(AccountId, AccountIndex, NewAccountOutcome),
/// An account was reaped.
ReapedAccount(AccountId),
/// Transfer succeeded (from, to, value, fees).
Transfer(AccountId, AccountId, Balance, Balance),
}
impl<A, I, B> From<RawEvent<A, I, B>> for () {
fn from(_: RawEvent<A, I, B>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<AccountId, AccountIndex, Balance>
where <T as system::Trait>::AccountId, <T as Trait>::AccountIndex, <T as Trait>::Balance {
/// A new account was created.
NewAccount(AccountId, AccountIndex, NewAccountOutcome),
/// An account was reaped.
ReapedAccount(AccountId),
/// Transfer succeeded (from, to, value, fees).
Transfer(AccountId, AccountId, Balance, Balance),
}
);
decl_storage! {
trait Store for Module<T: Trait> as Balances {
@@ -313,7 +303,7 @@ impl<T: Trait> Module<T> {
};
if transactor != dest {
Self::set_free_balance(&transactor, new_from_balance);
Self::set_free_balance(&transactor, new_from_balance);
Self::decrease_total_stake_by(fee);
Self::set_free_balance_creating(&dest, new_to_balance);
Self::deposit_event(RawEvent::Transfer(transactor, dest, value, fee));
@@ -400,7 +390,7 @@ impl<T: Trait> Module<T> {
};
Self::set_free_balance(who, credit);
Self::increase_total_stake_by(credit - balance);
} else {
} else {
Self::set_free_balance(who, balance);
}
@@ -39,7 +39,7 @@ pub trait Trait: CouncilTrait + MaybeSerializeDebug {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
/// Origin for the council module.
/// Origin for the council module.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Origin {
@@ -47,29 +47,24 @@ pub enum Origin {
Members(u32),
}
/// Outwardly visible event.
pub type Event<T> = RawEvent<<T as system::Trait>::Hash, <T as system::Trait>::AccountId>;
/// Event for this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<Hash, AccountId> {
/// A motion (given hash) has been proposed (by given account) with a threshold (given u32).
Proposed(AccountId, ProposalIndex, Hash, u32),
/// A motion (given hash) has been voted on by given account, leaving
/// a tally (yes votes and no votes given as u32s respectively).
Voted(AccountId, Hash, bool, u32, u32),
/// A motion was approved by the required threshold.
Approved(Hash),
/// A motion was not approved by the required threshold.
Disapproved(Hash),
/// A motion was executed; `bool` is true if returned without error.
Executed(Hash, bool),
}
impl<H, A> From<RawEvent<H, A>> for () {
fn from(_: RawEvent<H, A>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<Hash, AccountId>
where <T as system::Trait>::Hash, <T as system::Trait>::AccountId
{
/// A motion (given hash) has been proposed (by given account) with a threshold (given u32).
Proposed(AccountId, ProposalIndex, Hash, u32),
/// A motion (given hash) has been voted on by given account, leaving
/// a tally (yes votes and no votes given as u32s respectively).
Voted(AccountId, Hash, bool, u32, u32),
/// A motion was approved by the required threshold.
Approved(Hash),
/// A motion was not approved by the required threshold.
Disapproved(Hash),
/// A motion was executed; `bool` is true if returned without error.
Executed(Hash, bool),
}
);
decl_module! {
#[cfg_attr(feature = "std", serde(bound(deserialize = "<T as Trait>::Proposal: ::serde::de::DeserializeOwned")))]
@@ -154,25 +154,21 @@ decl_storage! {
}
}
pub type Event<T> = RawEvent<<T as system::Trait>::AccountId>;
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<AccountId> {
/// reaped voter, reaper
VoterReaped(AccountId, AccountId),
/// slashed reaper
BadReaperSlashed(AccountId),
/// A tally (for approval votes of council seat(s)) has started.
TallyStarted(u32),
/// A tally (for approval votes of council seat(s)) has ended (with one or more new members).
TallyFinalised(Vec<AccountId>, Vec<AccountId>),
}
impl<N> From<RawEvent<N>> for () {
fn from(_: RawEvent<N>) -> () { () }
}
decl_event!(
/// An event in this module.
pub enum Event<T> with RawEvent<AccountId>
where <T as system::Trait>::AccountId
{
/// reaped voter, reaper
VoterReaped(AccountId, AccountId),
/// slashed reaper
BadReaperSlashed(AccountId),
/// A tally (for approval votes of council seat(s)) has started.
TallyStarted(u32),
/// A tally (for approval votes of council seat(s)) has ended (with one or more new members).
TallyFinalised(Vec<AccountId>, Vec<AccountId>),
}
);
impl<T: Trait> Module<T> {
@@ -235,7 +231,7 @@ impl<T: Trait> Module<T> {
/// are registered.
fn set_approvals(origin: T::Origin, votes: Vec<bool>, index: VoteIndex) -> Result {
let who = ensure_signed(origin)?;
ensure!(!Self::presentation_active(), "no approval changes during presentation period");
ensure!(index == Self::vote_index(), "incorrect vote index");
if !<LastActiveOf<T>>::exists(&who) {
@@ -267,7 +263,7 @@ impl<T: Trait> Module<T> {
assumed_vote_index: VoteIndex
) -> Result {
let reporter = ensure_signed(origin)?;
let who = <balances::Module<T>>::lookup(who)?;
ensure!(!Self::presentation_active(), "cannot reap during presentation period");
ensure!(Self::voter_last_active(&reporter).is_some(), "reporter must be a voter");
@@ -310,7 +306,7 @@ impl<T: Trait> Module<T> {
/// Remove a voter. All votes are cancelled and the voter deposit is returned.
fn retract_voter(origin: T::Origin, index: u32) -> Result {
let who = ensure_signed(origin)?;
ensure!(!Self::presentation_active(), "cannot retract when presenting");
ensure!(<LastActiveOf<T>>::exists(&who), "cannot retract non-voter");
let voters = Self::voters();
@@ -328,7 +324,7 @@ impl<T: Trait> Module<T> {
/// Account must have enough transferrable funds in it to pay the bond.
fn submit_candidacy(origin: T::Origin, slot: u32) -> Result {
let who = ensure_signed(origin)?;
ensure!(!Self::is_a_candidate(&who), "duplicate candidate submission");
let slot = slot as usize;
let count = Self::candidate_count() as usize;
@@ -1356,4 +1352,4 @@ mod tests {
assert_eq!(Council::candidate_reg_info(4), Some((0, 3)));
});
}
}
}
@@ -53,21 +53,19 @@ 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>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<Hash>
where <T as system::Trait>::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<T: Trait> Module<T> {
@@ -108,26 +108,19 @@ decl_storage! {
}
}
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<Balance, AccountId> {
Tabled(PropIndex, Balance, Vec<AccountId>),
Started(ReferendumIndex, VoteThreshold),
Passed(ReferendumIndex),
NotPassed(ReferendumIndex),
Cancelled(ReferendumIndex),
Executed(ReferendumIndex, bool),
}
impl<B, A> From<RawEvent<B, A>> for () {
fn from(_: RawEvent<B, A>) -> () { () }
}
pub type Event<T> = RawEvent<
<T as balances::Trait>::Balance,
<T as system::Trait>::AccountId,
>;
decl_event!(
/// An event in this module.
pub enum Event<T> with RawEvent<Balance, AccountId>
where <T as balances::Trait>::Balance, <T as system::Trait>::AccountId
{
Tabled(PropIndex, Balance, Vec<AccountId>),
Started(ReferendumIndex, VoteThreshold),
Passed(ReferendumIndex),
NotPassed(ReferendumIndex),
Cancelled(ReferendumIndex),
Executed(ReferendumIndex, bool),
}
);
impl<T: Trait> Module<T> {
+19 -32
View File
@@ -65,10 +65,10 @@ use system::{ensure_signed, ensure_root};
/// Our module's configuration trait. All our types and consts go in here. If the
/// module is dependent on specific other modules, then their configuration traits
/// should be added to our implied traits list.
///
///
/// `system::Trait` should always be included in our implied traits.
pub trait Trait: balances::Trait {
/// The overarching event type.
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
@@ -87,12 +87,12 @@ pub trait Trait: balances::Trait {
//
// Information about where this dispatch initiated from is provided as the first argument
// "origin". As such functions must always look like:
//
//
// `fn foo(origin, bar: Bar, baz: Baz) -> Result = 0;`
//
// The `Result` is required as part of the syntax (and expands to the conventional dispatch
// result of `Result<(), &'static str>`).
//
//
// When you come to `impl` them later in the module, you must specify the full type for `origin`:
//
// `fn foo(origin: T::Origin, bar: Bar, baz: Baz) { ... }`
@@ -101,7 +101,7 @@ pub trait Trait: balances::Trait {
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::Inherent`. You should always match
// against them as the first thing you do in your function. There are three convenience calls
// in system that do the matching for you and return a convenient result: `ensure_signed`,
// `ensure_root` and `ensure_inherent`.
// `ensure_root` and `ensure_inherent`.
decl_module! {
// Simple declaration of the `Module` type. Lets the macro know what its working on.
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
@@ -117,31 +117,18 @@ decl_module! {
}
}
/// Exported Event type that's generic over the configuration trait.
// NOTE: External macro-fu expects this type to exist and be generic over
// the configuration trait.
pub type Event<T> = RawEvent<
<T as balances::Trait>::Balance,
>;
/// An event in this module. Events are simple means of reporting specific conditions and
/// circumstances that have happened that users, Dapps and/or chain explorers would find
/// interesting and otherwise difficult to detect.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<B> {
// Just a normal `enum`, here's a dummy event to ensure it compiles.
/// Dummy event, just here so there's a generic type that's used.
Dummy(B),
}
// By convention we implement any trait for which a "null implementation" makes sense
// for `()`. This is the case for conversion of module `Event` types and hook traits. It
// is helpful for test code and production configurations where no eventing is necessary
// or the hook is unused.
impl<B> From<RawEvent<B>> for () {
fn from(_: RawEvent<B>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<B>
where <T as balances::Trait>::Balance
{
// Just a normal `enum`, here's a dummy event to ensure it compiles.
/// Dummy event, just here so there's a generic type that's used.
Dummy(B),
}
);
decl_storage! {
// A macro for the Storage trait, and its implementation, for this module.
@@ -205,15 +192,15 @@ impl<T: Trait> Module<T> {
//
// - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an
// irreparably damaged state) must this function panic.
// - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return
// - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return
// `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`.
//
// The first is relatively easy to audit for - just ensure all panickers are removed from
// logic that executes in production (which you do anyway, right?!). To ensure the second
// logic that executes in production (which you do anyway, right?!). To ensure the second
// is followed, you should do all tests for validity at the top of your function. This
// is stuff like checking the sender (`origin`) or that state is such that the operation
// makes sense.
//
//
// Once you've determined that it's all good, then enact the operation and change storage.
// If you can't be certain that the operation will succeed without substantial computation
// then you have a classic blockchain attack scenario. The normal way of managing this is
@@ -322,10 +309,10 @@ impl<T: Trait> Default for GenesisConfig<T> {
// This expresses the specific key/value pairs that must be placed in storage in order
// to initialise the module and properly reflect the configuration.
//
//
// Ideally this would re-use the `::put` logic in the storage item type for introducing
// the values into the `StorageMap` (which is just a `HashMap<Vec<u8>, Vec<u8>>`). That
// is not yet in place, though, so for now we do everything "manually", using `hash`,
// is not yet in place, though, so for now we do everything "manually", using `hash`,
// `::key()` and `.to_vec()` for the key and `.encode()` for the value.
#[cfg(feature = "std")]
impl<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T>
+9 -13
View File
@@ -73,8 +73,6 @@ pub trait Trait: timestamp::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
pub type Event<T> = RawEvent<<T as system::Trait>::BlockNumber>;
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn set_key(origin, key: T::SessionKey) -> Result;
@@ -85,17 +83,15 @@ decl_module! {
}
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<BlockNumber> {
/// New session has happened. Note that the argument is the session index, not the block number
/// as the type might suggest.
NewSession(BlockNumber),
}
impl<N> From<RawEvent<N>> for () {
fn from(_: RawEvent<N>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<BlockNumber>
where <T as system::Trait>::BlockNumber
{
/// New session has happened. Note that the argument is the session index, not the block
/// number as the type might suggest.
NewSession(BlockNumber),
}
);
decl_storage! {
trait Store for Module<T: Trait> as Session {
+19 -23
View File
@@ -6,6 +6,8 @@
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -64,11 +66,6 @@ pub use genesis_config::GenesisConfig;
const DEFAULT_MINIMUM_VALIDATOR_COUNT: usize = 4;
pub type Event<T> = RawEvent<
<T as balances::Trait>::Balance,
<T as system::Trait>::AccountId
>;
#[derive(PartialEq, Clone)]
#[cfg_attr(test, derive(Debug))]
pub enum LockStatus<BlockNumber: Parameter> {
@@ -100,7 +97,7 @@ pub trait Trait: balances::Trait + session::Trait {
/// Some tokens minted.
type OnRewardMinted: OnDilution<<Self as balances::Trait>::Balance>;
/// The overarching event type.
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
@@ -122,20 +119,19 @@ decl_module! {
}
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<Balance, AccountId> {
/// All validators have been rewarded by the given balance.
Reward(Balance),
/// One validator (and their nominators) has been given a offline-warning (they're still within
/// their grace). The accrued number of slashes is recorded, too.
OfflineWarning(AccountId, u32),
/// One validator (and their nominators) has been slashed by the given amount.
OfflineSlash(AccountId, Balance),
}
impl<B, A> From<RawEvent<B, A>> for () {
fn from(_: RawEvent<B, A>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<Balance, AccountId>
where <T as balances::Trait>::Balance, <T as system::Trait>::AccountId
{
/// All validators have been rewarded by the given balance.
Reward(Balance),
/// One validator (and their nominators) has been given a offline-warning (they're still
/// within their grace). The accrued number of slashes is recorded, too.
OfflineWarning(AccountId, u32),
/// One validator (and their nominators) has been slashed by the given amount.
OfflineSlash(AccountId, Balance),
}
);
pub type PairOf<T> = (T, T);
@@ -307,8 +303,8 @@ impl<T: Trait> Module<T> {
Ok(())
}
/// Set the given account's preference for slashing behaviour should they be a validator.
///
/// Set the given account's preference for slashing behaviour should they be a validator.
///
/// An error (no-op) if `Self::intentions()[intentions_index] != origin`.
fn register_preferences(
origin: T::Origin,
@@ -320,7 +316,7 @@ impl<T: Trait> Module<T> {
if Self::intentions().get(intentions_index as usize) != Some(&who) {
return Err("Invalid index")
}
<ValidatorPreferences<T>>::insert(who, prefs);
Ok(())
+11 -15
View File
@@ -110,21 +110,17 @@ pub struct EventRecord<E: Parameter + Member> {
pub event: E,
}
/// Event for the system module.
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub enum Event {
/// An extrinsic completed successfully.
ExtrinsicSuccess,
/// An extrinsic failed.
ExtrinsicFailed,
}
/// Event for the system module.
decl_event!(
pub enum Event {
/// An extrinsic completed successfully.
ExtrinsicSuccess,
/// An extrinsic failed.
ExtrinsicFailed,
}
);
impl From<Event> for () {
fn from(_: Event) -> () { () }
}
/// Origin for the system module.
/// Origin for the system module.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum RawOrigin<AccountId> {
@@ -388,7 +384,7 @@ mod tests {
impl From<Event> for u16 {
fn from(e: Event) -> u16 {
match e {
match e {
Event::ExtrinsicSuccess => 100,
Event::ExtrinsicFailed => 101,
}
+22 -30
View File
@@ -51,7 +51,7 @@ use system::{ensure_signed, ensure_root};
/// Our module's configuration trait. All our types and consts go in here. If the
/// module is dependent on specific other modules, then their configuration traits
/// should be added to our implied traits list.
///
///
/// `system::Trait` should always be included in our implied traits.
pub trait Trait: balances::Trait {
/// Origin from which approvals must come.
@@ -60,7 +60,7 @@ pub trait Trait: balances::Trait {
/// Origin from which rejections must come.
type RejectOrigin: EnsureOrigin<Self::Origin>;
/// The overarching event type.
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
@@ -108,7 +108,7 @@ decl_storage! {
/// Proportion of funds that should be bonded in order to place a proposal. An accepted
/// proposal gets these back. A rejected proposal doesn't.
ProposalBond get(proposal_bond): required Permill;
/// Minimum amount of funds that should be placed ina deposit for making a proposal.
ProposalBondMinimum get(proposal_bond_minimum): required T::Balance;
@@ -134,31 +134,23 @@ decl_storage! {
}
}
/// Exported Event type that's generic over the configuration trait.
pub type Event<T> = RawEvent<
<T as balances::Trait>::Balance,
<T as system::Trait>::AccountId,
>;
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<Balance, AccountId> {
/// New proposal.
Proposed(ProposalIndex),
/// We have ended a spend period and will now allocate funds.
Spending(Balance),
/// Some funds have been allocated.
Awarded(ProposalIndex, Balance, AccountId),
/// Some of our funds have been burnt.
Burnt(Balance),
/// Spending has finished; this is the amount that rolls over until next spend.
Rollover(Balance),
}
impl<B, A> From<RawEvent<B, A>> for () {
fn from(_: RawEvent<B, A>) -> () { () }
}
decl_event!(
pub enum Event<T> with RawEvent<Balance, AccountId>
where <T as balances::Trait>::Balance, <T as system::Trait>::AccountId
{
/// New proposal.
Proposed(ProposalIndex),
/// We have ended a spend period and will now allocate funds.
Spending(Balance),
/// Some funds have been allocated.
Awarded(ProposalIndex, Balance, AccountId),
/// Some of our funds have been burnt.
Burnt(Balance),
/// Spending has finished; this is the amount that rolls over until next spend.
Rollover(Balance),
}
);
impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
@@ -188,7 +180,7 @@ impl<T: Trait> Module<T> {
T::RejectOrigin::ensure_origin(origin)?;
let proposal = <Proposals<T>>::take(proposal_id).ok_or("No proposal at that index")?;
let value = proposal.bond;
let _ = <balances::Module<T>>::slash_reserved(&proposal.proposer, value);
@@ -215,7 +207,7 @@ impl<T: Trait> Module<T> {
}
fn configure(
origin: T::Origin,
origin: T::Origin,
proposal_bond: Permill,
proposal_bond_minimum: T::Balance,
spend_period: T::BlockNumber,
@@ -260,7 +252,7 @@ impl<T: Trait> Module<T> {
true
}
} else {
false
false
}
}).collect();
<Approvals<T>>::put(remaining_approvals);
+7 -1
View File
@@ -134,13 +134,19 @@ pub fn run_tests(mut input: &[u8]) -> Vec<u8> {
[stxs.len() as u8].encode()
}
fn test_event_json() -> &'static str {
"hallo"
}
pub mod api {
use system;
impl_stubs!(
version => |()| super::version(),
json_metadata => |()| {
let mut vec = ::runtime_support::metadata::Vec::new();
vec.push(::runtime_support::metadata::JSONMetadata::Events { events: r#""events""# });
vec.push(::runtime_support::metadata::JSONMetadata::Events {
name: "Test", events: &[ ("event", super::test_event_json) ]
});
vec
},
authorities => |()| system::authorities(),