From 60d41b7319b446d5bfbe8e32f6ecd177245cfc90 Mon Sep 17 00:00:00 2001 From: Stanly Johnson Date: Sat, 8 May 2021 23:26:36 +0530 Subject: [PATCH 1/6] update to pallet macro --- frame/offences/benchmarking/src/mock.rs | 2 +- frame/offences/src/lib.rs | 434 +++++++++++++----------- frame/offences/src/mock.rs | 2 +- 3 files changed, 230 insertions(+), 208 deletions(-) diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 9047120923ad6..f72165ad74d5b 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -216,7 +216,7 @@ frame_support::construct_runtime!( Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config}, - Offences: pallet_offences::{Pallet, Call, Storage, Event}, + Offences: pallet_offences::{Pallet, Call, Storage, Event}, Historical: pallet_session_historical::{Pallet}, } ); diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index cd25ca1ef1dc4..99bd306f98b03 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Offences Module +//! # Offences Pallet //! //! Tracks reported offences @@ -26,16 +26,16 @@ mod mock; mod tests; mod migration; -use sp_std::vec::Vec; -use frame_support::{ - decl_module, decl_event, decl_storage, Parameter, weights::Weight, -}; +use sp_std::prelude::*; +use frame_support::weights::Weight; use sp_runtime::{traits::Hash, Perbill}; use sp_staking::{ - SessionIndex, - offence::{Offence, ReportOffence, Kind, OnOffenceHandler, OffenceDetails, OffenceError}, + offence::{Kind, Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, + SessionIndex }; -use codec::{Encode, Decode}; +use codec::{Decode, Encode}; + +pub use pallet::*; /// A binary blob which represents a SCALE codec-encoded `O::TimeSlot`. type OpaqueTimeSlot = Vec; @@ -57,168 +57,190 @@ impl WeightInfo for () { fn on_initialize(_d: u32, ) -> Weight { 1_000_000_000 } } -/// Offences trait -pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From + Into<::Event>; - /// Full identification of the validator. - type IdentificationTuple: Parameter + Ord; - /// A handler called for every offence report. - type OnOffenceHandler: OnOffenceHandler; -} - -decl_storage! { - trait Store for Module as Offences { - /// The primary structure that holds all offence records keyed by report identifiers. - Reports get(fn reports): - map hasher(twox_64_concat) ReportIdOf - => Option>; - - /// A vector of reports of the same kind that happened at the same time slot. - ConcurrentReportsIndex: - double_map hasher(twox_64_concat) Kind, hasher(twox_64_concat) OpaqueTimeSlot - => Vec>; - - /// Enumerates all reports of a kind along with the time they happened. - /// - /// All reports are sorted by the time of offence. - /// - /// Note that the actual type of this mapping is `Vec`, this is because values of - /// different types are not supported at the moment so we are doing the manual serialization. - ReportsByKindIndex: map hasher(twox_64_concat) Kind => Vec; // (O::TimeSlot, ReportIdOf) - } -} - -decl_event!( - pub enum Event { - /// There is an offence reported of the given `kind` happened at the `session_index` and - /// (kind-specific) time slot. This event is not deposited for duplicate slashes. - /// \[kind, timeslot\]. - Offence(Kind, OpaqueTimeSlot), - } -); - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; - +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + /// The pallet's config trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + /// Full identification of the validator. + type IdentificationTuple: Parameter + Ord; + /// A handler called for every offence report. + type OnOffenceHandler: OnOffenceHandler; + } + + /// The primary structure that holds all offence records keyed by report identifiers. + #[pallet::storage] + #[pallet::getter(fn reports)] + pub type Reports = StorageMap< + _, + Twox64Concat, + ReportIdOf, + OffenceDetails, + >; + + /// A vector of reports of the same kind that happened at the same time slot. + #[pallet::storage] + pub type ConcurrentReportsIndex = + StorageDoubleMap<_, Twox64Concat, Kind, Twox64Concat, OpaqueTimeSlot, Vec>, ValueQuery>; + + /// Enumerates all reports of a kind along with the time they happened. + /// + /// All reports are sorted by the time of offence. + /// + /// Note that the actual type of this mapping is `Vec`, this is because values of + /// different types are not supported at the moment so we are doing the manual serialization. + #[pallet::storage] + pub type ReportsByKindIndex = StorageMap< + _, + Twox64Concat, + Kind, + Vec, // (O::TimeSlot, ReportIdOf) + >; + + /// Events type. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// There is an offence reported of the given `kind` happened at the `session_index` and + /// (kind-specific) time slot. This event is not deposited for duplicate slashes. + /// \[kind, timeslot\]. + Offence(Kind, OpaqueTimeSlot), + } + + #[pallet::hooks] + impl Hooks> for Pallet + { fn on_runtime_upgrade() -> Weight { - migration::remove_deferred_storage::() - } + migration::remove_deferred_storage::() + } } + + #[pallet::call] + impl Pallet { + } } impl> - ReportOffence for Module + ReportOffence for Pallet where - T::IdentificationTuple: Clone, + T::IdentificationTuple: Clone, { - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { - let offenders = offence.offenders(); - let time_slot = offence.time_slot(); - let validator_set_count = offence.validator_set_count(); - - // Go through all offenders in the offence report and find all offenders that were spotted - // in unique reports. - let TriageOutcome { concurrent_offenders } = match Self::triage_offence_report::( - reporters, - &time_slot, - offenders, - ) { - Some(triage) => triage, - // The report contained only duplicates, so there is no need to slash again. - None => return Err(OffenceError::DuplicateReport), - }; - - let offenders_count = concurrent_offenders.len() as u32; - - // The amount new offenders are slashed - let new_fraction = O::slash_fraction(offenders_count, validator_set_count); - - let slash_perbill: Vec<_> = (0..concurrent_offenders.len()) - .map(|_| new_fraction.clone()).collect(); - - T::OnOffenceHandler::on_offence( - &concurrent_offenders, - &slash_perbill, - offence.session_index(), - ); - - // Deposit the event. - Self::deposit_event(Event::Offence(O::ID, time_slot.encode())); - - Ok(()) - } - - fn is_known_offence(offenders: &[T::IdentificationTuple], time_slot: &O::TimeSlot) -> bool { - let any_unknown = offenders.iter().any(|offender| { - let report_id = Self::report_id::(time_slot, offender); - !>::contains_key(&report_id) - }); - - !any_unknown - } + fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { + let offenders = offence.offenders(); + let time_slot = offence.time_slot(); + let validator_set_count = offence.validator_set_count(); + + // Go through all offenders in the offence report and find all offenders that were spotted + // in unique reports. + let TriageOutcome { + concurrent_offenders, + } = match Self::triage_offence_report::(reporters, &time_slot, offenders) { + Some(triage) => triage, + // The report contained only duplicates, so there is no need to slash again. + None => return Err(OffenceError::DuplicateReport), + }; + + let offenders_count = concurrent_offenders.len() as u32; + + // The amount new offenders are slashed + let new_fraction = O::slash_fraction(offenders_count, validator_set_count); + + let slash_perbill: Vec<_> = (0..concurrent_offenders.len()) + .map(|_| new_fraction.clone()) + .collect(); + + T::OnOffenceHandler::on_offence( + &concurrent_offenders, + &slash_perbill, + offence.session_index(), + ); + + // Deposit the event. + Self::deposit_event(Event::Offence(O::ID, time_slot.encode())); + + Ok(()) + } + + fn is_known_offence(offenders: &[T::IdentificationTuple], time_slot: &O::TimeSlot) -> bool { + let any_unknown = offenders.iter().any(|offender| { + let report_id = Self::report_id::(time_slot, offender); + !>::contains_key(&report_id) + }); + + !any_unknown + } } -impl Module { - /// Compute the ID for the given report properties. - /// - /// The report id depends on the offence kind, time slot and the id of offender. - fn report_id>( - time_slot: &O::TimeSlot, - offender: &T::IdentificationTuple, - ) -> ReportIdOf { - (O::ID, time_slot.encode(), offender).using_encoded(T::Hashing::hash) - } - - /// Triages the offence report and returns the set of offenders that was involved in unique - /// reports along with the list of the concurrent offences. - fn triage_offence_report>( - reporters: Vec, - time_slot: &O::TimeSlot, - offenders: Vec, - ) -> Option> { - let mut storage = ReportIndexStorage::::load(time_slot); - - let mut any_new = false; - for offender in offenders { - let report_id = Self::report_id::(time_slot, &offender); - - if !>::contains_key(&report_id) { - any_new = true; - >::insert( - &report_id, - OffenceDetails { - offender, - reporters: reporters.clone(), - }, - ); - - storage.insert(time_slot, report_id); - } - } - - if any_new { - // Load report details for the all reports happened at the same time. - let concurrent_offenders = storage.concurrent_reports - .iter() - .filter_map(|report_id| >::get(report_id)) - .collect::>(); - - storage.save(); - - Some(TriageOutcome { - concurrent_offenders, - }) - } else { - None - } - } +impl Pallet { + /// Compute the ID for the given report properties. + /// + /// The report id depends on the offence kind, time slot and the id of offender. + fn report_id>( + time_slot: &O::TimeSlot, + offender: &T::IdentificationTuple, + ) -> ReportIdOf { + (O::ID, time_slot.encode(), offender).using_encoded(T::Hashing::hash) + } + + /// Triages the offence report and returns the set of offenders that was involved in unique + /// reports along with the list of the concurrent offences. + fn triage_offence_report>( + reporters: Vec, + time_slot: &O::TimeSlot, + offenders: Vec, + ) -> Option> { + let mut storage = ReportIndexStorage::::load(time_slot); + + let mut any_new = false; + for offender in offenders { + let report_id = Self::report_id::(time_slot, &offender); + + if !>::contains_key(&report_id) { + any_new = true; + >::insert( + &report_id, + OffenceDetails { + offender, + reporters: reporters.clone(), + }, + ); + + storage.insert(time_slot, report_id); + } + } + + if any_new { + // Load report details for the all reports happened at the same time. + let concurrent_offenders = storage + .concurrent_reports + .iter() + .filter_map(|report_id| >::get(report_id)) + .collect::>(); + + storage.save(); + + Some(TriageOutcome { + concurrent_offenders, + }) + } else { + None + } + } } struct TriageOutcome { - /// Other reports for the same report kinds. - concurrent_offenders: Vec>, + /// Other reports for the same report kinds. + concurrent_offenders: Vec>, } /// An auxiliary struct for working with storage of indexes localized for a specific offence @@ -228,55 +250,55 @@ struct TriageOutcome { /// accessed directly meanwhile. #[must_use = "The changes are not saved without called `save`"] struct ReportIndexStorage> { - opaque_time_slot: OpaqueTimeSlot, - concurrent_reports: Vec>, - same_kind_reports: Vec<(O::TimeSlot, ReportIdOf)>, + opaque_time_slot: OpaqueTimeSlot, + concurrent_reports: Vec>, + same_kind_reports: Vec<(O::TimeSlot, ReportIdOf)>, } impl> ReportIndexStorage { - /// Preload indexes from the storage for the specific `time_slot` and the kind of the offence. - fn load(time_slot: &O::TimeSlot) -> Self { - let opaque_time_slot = time_slot.encode(); - - let same_kind_reports = ::get(&O::ID); - let same_kind_reports = - Vec::<(O::TimeSlot, ReportIdOf)>::decode(&mut &same_kind_reports[..]) - .unwrap_or_default(); - - let concurrent_reports = >::get(&O::ID, &opaque_time_slot); - - Self { - opaque_time_slot, - concurrent_reports, - same_kind_reports, - } - } - - /// Insert a new report to the index. - fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf) { - // Insert the report id into the list while maintaining the ordering by the time - // slot. - let pos = match self - .same_kind_reports - .binary_search_by_key(&time_slot, |&(ref when, _)| when) - { - Ok(pos) => pos, - Err(pos) => pos, - }; - self.same_kind_reports - .insert(pos, (time_slot.clone(), report_id)); - - // Update the list of concurrent reports. - self.concurrent_reports.push(report_id); - } - - /// Dump the indexes to the storage. - fn save(self) { - ::insert(&O::ID, self.same_kind_reports.encode()); - >::insert( - &O::ID, - &self.opaque_time_slot, - &self.concurrent_reports, - ); - } + /// Preload indexes from the storage for the specific `time_slot` and the kind of the offence. + fn load(time_slot: &O::TimeSlot) -> Self { + let opaque_time_slot = time_slot.encode(); + + let same_kind_reports = ReportsByKindIndex::::get(&O::ID).unwrap_or_default(); + let same_kind_reports = + Vec::<(O::TimeSlot, ReportIdOf)>::decode(&mut &same_kind_reports[..]) + .unwrap_or_default(); + + let concurrent_reports = >::get(&O::ID, &opaque_time_slot); + + Self { + opaque_time_slot, + concurrent_reports, + same_kind_reports, + } + } + + /// Insert a new report to the index. + fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf) { + // Insert the report id into the list while maintaining the ordering by the time + // slot. + let pos = match self + .same_kind_reports + .binary_search_by_key(&time_slot, |&(ref when, _)| when) + { + Ok(pos) => pos, + Err(pos) => pos, + }; + self.same_kind_reports + .insert(pos, (time_slot.clone(), report_id)); + + // Update the list of concurrent reports. + self.concurrent_reports.push(report_id); + } + + /// Dump the indexes to the storage. + fn save(self) { + ReportsByKindIndex::::insert(&O::ID, self.same_kind_reports.encode()); + >::insert( + &O::ID, + &self.opaque_time_slot, + &self.concurrent_reports, + ); + } } diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 4176a54d9ecec..4bfba5963583e 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -75,7 +75,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Offences: offences::{Pallet, Call, Storage, Event}, + Offences: offences::{Pallet, Call, Storage, Event}, } ); From 502e3af75093c171a8df6941a08181c5bb3336a2 Mon Sep 17 00:00:00 2001 From: Stanly Johnson Date: Sun, 9 May 2021 23:38:36 +0530 Subject: [PATCH 2/6] fixes --- frame/offences/src/lib.rs | 437 +++++++++++++++++++------------------ frame/offences/src/mock.rs | 2 +- 2 files changed, 222 insertions(+), 217 deletions(-) diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 99bd306f98b03..bc251b52444cc 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -59,188 +59,193 @@ impl WeightInfo for () { #[frame_support::pallet] pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - /// The pallet's config trait. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From> + IsType<::Event>; - /// Full identification of the validator. - type IdentificationTuple: Parameter + Ord; - /// A handler called for every offence report. - type OnOffenceHandler: OnOffenceHandler; - } - - /// The primary structure that holds all offence records keyed by report identifiers. - #[pallet::storage] - #[pallet::getter(fn reports)] - pub type Reports = StorageMap< - _, - Twox64Concat, - ReportIdOf, - OffenceDetails, - >; - - /// A vector of reports of the same kind that happened at the same time slot. - #[pallet::storage] - pub type ConcurrentReportsIndex = - StorageDoubleMap<_, Twox64Concat, Kind, Twox64Concat, OpaqueTimeSlot, Vec>, ValueQuery>; - - /// Enumerates all reports of a kind along with the time they happened. - /// - /// All reports are sorted by the time of offence. - /// - /// Note that the actual type of this mapping is `Vec`, this is because values of - /// different types are not supported at the moment so we are doing the manual serialization. - #[pallet::storage] - pub type ReportsByKindIndex = StorageMap< - _, - Twox64Concat, - Kind, - Vec, // (O::TimeSlot, ReportIdOf) - >; - - /// Events type. - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// There is an offence reported of the given `kind` happened at the `session_index` and - /// (kind-specific) time slot. This event is not deposited for duplicate slashes. - /// \[kind, timeslot\]. - Offence(Kind, OpaqueTimeSlot), - } - - #[pallet::hooks] - impl Hooks> for Pallet - { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + /// The pallet's config trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + /// Full identification of the validator. + type IdentificationTuple: Parameter + Ord; + /// A handler called for every offence report. + type OnOffenceHandler: OnOffenceHandler; + } + + /// The primary structure that holds all offence records keyed by report identifiers. + #[pallet::storage] + #[pallet::getter(fn reports)] + pub type Reports = StorageMap< + _, + Twox64Concat, + ReportIdOf, + OffenceDetails, + >; + + /// A vector of reports of the same kind that happened at the same time slot. + #[pallet::storage] + pub type ConcurrentReportsIndex = StorageDoubleMap< + _, + Twox64Concat, + Kind, + Twox64Concat, + OpaqueTimeSlot, + Vec>, + ValueQuery, + >; + + /// Enumerates all reports of a kind along with the time they happened. + /// + /// All reports are sorted by the time of offence. + /// + /// Note that the actual type of this mapping is `Vec`, this is because values of + /// different types are not supported at the moment so we are doing the manual serialization. + #[pallet::storage] + pub type ReportsByKindIndex = StorageMap< + _, + Twox64Concat, + Kind, + Vec, // (O::TimeSlot, ReportIdOf) + >; + + /// Events type. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// There is an offence reported of the given `kind` happened at the `session_index` and + /// (kind-specific) time slot. This event is not deposited for duplicate slashes. + /// \[kind, timeslot\]. + Offence(Kind, OpaqueTimeSlot), + } + + #[pallet::hooks] + impl Hooks> for Pallet { fn on_runtime_upgrade() -> Weight { - migration::remove_deferred_storage::() - } + migration::remove_deferred_storage::() + } } - #[pallet::call] - impl Pallet { - } + #[pallet::call] + impl Pallet {} } impl> - ReportOffence for Pallet + ReportOffence for Pallet where - T::IdentificationTuple: Clone, + T::IdentificationTuple: Clone, { - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { - let offenders = offence.offenders(); - let time_slot = offence.time_slot(); - let validator_set_count = offence.validator_set_count(); - - // Go through all offenders in the offence report and find all offenders that were spotted - // in unique reports. - let TriageOutcome { - concurrent_offenders, - } = match Self::triage_offence_report::(reporters, &time_slot, offenders) { - Some(triage) => triage, - // The report contained only duplicates, so there is no need to slash again. - None => return Err(OffenceError::DuplicateReport), - }; - - let offenders_count = concurrent_offenders.len() as u32; - - // The amount new offenders are slashed - let new_fraction = O::slash_fraction(offenders_count, validator_set_count); - - let slash_perbill: Vec<_> = (0..concurrent_offenders.len()) - .map(|_| new_fraction.clone()) - .collect(); - - T::OnOffenceHandler::on_offence( - &concurrent_offenders, - &slash_perbill, - offence.session_index(), - ); - - // Deposit the event. - Self::deposit_event(Event::Offence(O::ID, time_slot.encode())); - - Ok(()) - } - - fn is_known_offence(offenders: &[T::IdentificationTuple], time_slot: &O::TimeSlot) -> bool { - let any_unknown = offenders.iter().any(|offender| { - let report_id = Self::report_id::(time_slot, offender); - !>::contains_key(&report_id) - }); - - !any_unknown - } + fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { + let offenders = offence.offenders(); + let time_slot = offence.time_slot(); + let validator_set_count = offence.validator_set_count(); + + // Go through all offenders in the offence report and find all offenders that were spotted + // in unique reports. + let TriageOutcome { + concurrent_offenders, + } = match Self::triage_offence_report::(reporters, &time_slot, offenders) { + Some(triage) => triage, + // The report contained only duplicates, so there is no need to slash again. + None => return Err(OffenceError::DuplicateReport), + }; + + let offenders_count = concurrent_offenders.len() as u32; + + // The amount new offenders are slashed + let new_fraction = O::slash_fraction(offenders_count, validator_set_count); + + let slash_perbill: Vec<_> = (0..concurrent_offenders.len()) + .map(|_| new_fraction.clone()) + .collect(); + + T::OnOffenceHandler::on_offence( + &concurrent_offenders, + &slash_perbill, + offence.session_index(), + ); + + // Deposit the event. + Self::deposit_event(Event::Offence(O::ID, time_slot.encode())); + + Ok(()) + } + + fn is_known_offence(offenders: &[T::IdentificationTuple], time_slot: &O::TimeSlot) -> bool { + let any_unknown = offenders.iter().any(|offender| { + let report_id = Self::report_id::(time_slot, offender); + !>::contains_key(&report_id) + }); + + !any_unknown + } } impl Pallet { - /// Compute the ID for the given report properties. - /// - /// The report id depends on the offence kind, time slot and the id of offender. - fn report_id>( - time_slot: &O::TimeSlot, - offender: &T::IdentificationTuple, - ) -> ReportIdOf { - (O::ID, time_slot.encode(), offender).using_encoded(T::Hashing::hash) - } - - /// Triages the offence report and returns the set of offenders that was involved in unique - /// reports along with the list of the concurrent offences. - fn triage_offence_report>( - reporters: Vec, - time_slot: &O::TimeSlot, - offenders: Vec, - ) -> Option> { - let mut storage = ReportIndexStorage::::load(time_slot); - - let mut any_new = false; - for offender in offenders { - let report_id = Self::report_id::(time_slot, &offender); - - if !>::contains_key(&report_id) { - any_new = true; - >::insert( - &report_id, - OffenceDetails { - offender, - reporters: reporters.clone(), - }, - ); - - storage.insert(time_slot, report_id); - } - } - - if any_new { - // Load report details for the all reports happened at the same time. - let concurrent_offenders = storage - .concurrent_reports - .iter() - .filter_map(|report_id| >::get(report_id)) - .collect::>(); - - storage.save(); - - Some(TriageOutcome { - concurrent_offenders, - }) - } else { - None - } - } + /// Compute the ID for the given report properties. + /// + /// The report id depends on the offence kind, time slot and the id of offender. + fn report_id>( + time_slot: &O::TimeSlot, + offender: &T::IdentificationTuple, + ) -> ReportIdOf { + (O::ID, time_slot.encode(), offender).using_encoded(T::Hashing::hash) + } + + /// Triages the offence report and returns the set of offenders that was involved in unique + /// reports along with the list of the concurrent offences. + fn triage_offence_report>( + reporters: Vec, + time_slot: &O::TimeSlot, + offenders: Vec, + ) -> Option> { + let mut storage = ReportIndexStorage::::load(time_slot); + + let mut any_new = false; + for offender in offenders { + let report_id = Self::report_id::(time_slot, &offender); + + if !>::contains_key(&report_id) { + any_new = true; + >::insert( + &report_id, + OffenceDetails { + offender, + reporters: reporters.clone(), + }, + ); + + storage.insert(time_slot, report_id); + } + } + + if any_new { + // Load report details for the all reports happened at the same time. + let concurrent_offenders = storage + .concurrent_reports + .iter() + .filter_map(|report_id| >::get(report_id)) + .collect::>(); + + storage.save(); + + Some(TriageOutcome { + concurrent_offenders, + }) + } else { + None + } + } } struct TriageOutcome { - /// Other reports for the same report kinds. - concurrent_offenders: Vec>, + /// Other reports for the same report kinds. + concurrent_offenders: Vec>, } /// An auxiliary struct for working with storage of indexes localized for a specific offence @@ -250,55 +255,55 @@ struct TriageOutcome { /// accessed directly meanwhile. #[must_use = "The changes are not saved without called `save`"] struct ReportIndexStorage> { - opaque_time_slot: OpaqueTimeSlot, - concurrent_reports: Vec>, - same_kind_reports: Vec<(O::TimeSlot, ReportIdOf)>, + opaque_time_slot: OpaqueTimeSlot, + concurrent_reports: Vec>, + same_kind_reports: Vec<(O::TimeSlot, ReportIdOf)>, } impl> ReportIndexStorage { - /// Preload indexes from the storage for the specific `time_slot` and the kind of the offence. - fn load(time_slot: &O::TimeSlot) -> Self { - let opaque_time_slot = time_slot.encode(); - - let same_kind_reports = ReportsByKindIndex::::get(&O::ID).unwrap_or_default(); - let same_kind_reports = - Vec::<(O::TimeSlot, ReportIdOf)>::decode(&mut &same_kind_reports[..]) - .unwrap_or_default(); - - let concurrent_reports = >::get(&O::ID, &opaque_time_slot); - - Self { - opaque_time_slot, - concurrent_reports, - same_kind_reports, - } - } - - /// Insert a new report to the index. - fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf) { - // Insert the report id into the list while maintaining the ordering by the time - // slot. - let pos = match self - .same_kind_reports - .binary_search_by_key(&time_slot, |&(ref when, _)| when) - { - Ok(pos) => pos, - Err(pos) => pos, - }; - self.same_kind_reports - .insert(pos, (time_slot.clone(), report_id)); - - // Update the list of concurrent reports. - self.concurrent_reports.push(report_id); - } - - /// Dump the indexes to the storage. - fn save(self) { - ReportsByKindIndex::::insert(&O::ID, self.same_kind_reports.encode()); - >::insert( - &O::ID, - &self.opaque_time_slot, - &self.concurrent_reports, - ); - } + /// Preload indexes from the storage for the specific `time_slot` and the kind of the offence. + fn load(time_slot: &O::TimeSlot) -> Self { + let opaque_time_slot = time_slot.encode(); + + let same_kind_reports = ReportsByKindIndex::::get(&O::ID).unwrap_or_default(); + let same_kind_reports = + Vec::<(O::TimeSlot, ReportIdOf)>::decode(&mut &same_kind_reports[..]) + .unwrap_or_default(); + + let concurrent_reports = >::get(&O::ID, &opaque_time_slot); + + Self { + opaque_time_slot, + concurrent_reports, + same_kind_reports, + } + } + + /// Insert a new report to the index. + fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf) { + // Insert the report id into the list while maintaining the ordering by the time + // slot. + let pos = match self + .same_kind_reports + .binary_search_by_key(&time_slot, |&(ref when, _)| when) + { + Ok(pos) => pos, + Err(pos) => pos, + }; + self.same_kind_reports + .insert(pos, (time_slot.clone(), report_id)); + + // Update the list of concurrent reports. + self.concurrent_reports.push(report_id); + } + + /// Dump the indexes to the storage. + fn save(self) { + ReportsByKindIndex::::insert(&O::ID, self.same_kind_reports.encode()); + >::insert( + &O::ID, + &self.opaque_time_slot, + &self.concurrent_reports, + ); + } } diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 4bfba5963583e..0397d4ed2e733 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -31,7 +31,7 @@ use sp_runtime::testing::Header; use sp_runtime::traits::{IdentityLookup, BlakeTwo256}; use sp_core::H256; use frame_support::{ - parameter_types, StorageMap, StorageDoubleMap, + parameter_types, weights::{Weight, constants::{WEIGHT_PER_SECOND, RocksDbWeight}}, }; use crate as offences; From 6963257c0ca1355f180ada7854b4f86fc737c7c4 Mon Sep 17 00:00:00 2001 From: Stanly Johnson Date: Sun, 9 May 2021 23:56:35 +0530 Subject: [PATCH 3/6] fix tests --- frame/babe/src/mock.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- frame/offences/benchmarking/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 40ee782e721d6..48cf60b03b8a8 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -54,7 +54,7 @@ frame_support::construct_runtime!( Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Historical: pallet_session_historical::{Pallet}, - Offences: pallet_offences::{Pallet, Call, Storage, Event}, + Offences: pallet_offences::{Pallet, Call, Storage, Event}, Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, Staking: pallet_staking::{Pallet, Call, Storage, Config, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index e26020b600348..dfa708865fe9a 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -57,7 +57,7 @@ frame_support::construct_runtime!( Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, - Offences: pallet_offences::{Pallet, Call, Storage, Event}, + Offences: pallet_offences::{Pallet, Call, Storage, Event}, Historical: pallet_session_historical::{Pallet}, } ); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index f65bdddd36d02..e27c66c75a669 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -38,7 +38,7 @@ use pallet_balances::Config as BalancesConfig; use pallet_babe::BabeEquivocationOffence; use pallet_grandpa::{GrandpaEquivocationOffence, GrandpaTimeSlot}; use pallet_im_online::{Config as ImOnlineConfig, Pallet as ImOnline, UnresponsivenessOffence}; -use pallet_offences::{Config as OffencesConfig, Module as Offences}; +use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; use pallet_session::historical::{Config as HistoricalConfig, IdentificationTuple}; use pallet_session::{Config as SessionConfig, SessionManager}; use pallet_staking::{ From 9f357b3bbf66c3e576871f3ce77dc48e0d0477e7 Mon Sep 17 00:00:00 2001 From: Stanly Johnson Date: Mon, 10 May 2021 00:09:33 +0530 Subject: [PATCH 4/6] remove unwanted generic --- frame/offences/benchmarking/src/lib.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/offences/src/lib.rs | 4 ++-- frame/offences/src/mock.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index f65bdddd36d02..e27c66c75a669 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -38,7 +38,7 @@ use pallet_balances::Config as BalancesConfig; use pallet_babe::BabeEquivocationOffence; use pallet_grandpa::{GrandpaEquivocationOffence, GrandpaTimeSlot}; use pallet_im_online::{Config as ImOnlineConfig, Pallet as ImOnline, UnresponsivenessOffence}; -use pallet_offences::{Config as OffencesConfig, Module as Offences}; +use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; use pallet_session::historical::{Config as HistoricalConfig, IdentificationTuple}; use pallet_session::{Config as SessionConfig, SessionManager}; use pallet_staking::{ diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index f72165ad74d5b..9047120923ad6 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -216,7 +216,7 @@ frame_support::construct_runtime!( Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config}, - Offences: pallet_offences::{Pallet, Call, Storage, Event}, + Offences: pallet_offences::{Pallet, Call, Storage, Event}, Historical: pallet_session_historical::{Pallet}, } ); diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index bc251b52444cc..9890292bcec98 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -71,7 +71,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type Event: From + IsType<::Event>; /// Full identification of the validator. type IdentificationTuple: Parameter + Ord; /// A handler called for every offence report. @@ -117,7 +117,7 @@ pub mod pallet { /// Events type. #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event { /// There is an offence reported of the given `kind` happened at the `session_index` and /// (kind-specific) time slot. This event is not deposited for duplicate slashes. /// \[kind, timeslot\]. diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 0397d4ed2e733..e7655d7ee29a7 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -75,7 +75,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Offences: offences::{Pallet, Call, Storage, Event}, + Offences: offences::{Pallet, Call, Storage, Event}, } ); From 1ef76a31910ffdb55b7acebc050146169820c652 Mon Sep 17 00:00:00 2001 From: Stanly Johnson Date: Mon, 10 May 2021 00:12:20 +0530 Subject: [PATCH 5/6] fix conflict --- frame/babe/src/mock.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 48cf60b03b8a8..40ee782e721d6 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -54,7 +54,7 @@ frame_support::construct_runtime!( Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Historical: pallet_session_historical::{Pallet}, - Offences: pallet_offences::{Pallet, Call, Storage, Event}, + Offences: pallet_offences::{Pallet, Call, Storage, Event}, Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, Staking: pallet_staking::{Pallet, Call, Storage, Config, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index dfa708865fe9a..e26020b600348 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -57,7 +57,7 @@ frame_support::construct_runtime!( Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, - Offences: pallet_offences::{Pallet, Call, Storage, Event}, + Offences: pallet_offences::{Pallet, Call, Storage, Event}, Historical: pallet_session_historical::{Pallet}, } ); From 25a144034bbd7bb9e2339b2f912f47dfbcd3254f Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Wed, 12 May 2021 18:09:56 +0200 Subject: [PATCH 6/6] Fix storage and tabs --- frame/offences/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 9890292bcec98..84a7414927d69 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -30,7 +30,7 @@ use sp_std::prelude::*; use frame_support::weights::Weight; use sp_runtime::{traits::Hash, Perbill}; use sp_staking::{ - offence::{Kind, Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, + offence::{Kind, Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, SessionIndex }; use codec::{Decode, Encode}; @@ -112,6 +112,7 @@ pub mod pallet { Twox64Concat, Kind, Vec, // (O::TimeSlot, ReportIdOf) + ValueQuery, >; /// Events type. @@ -265,7 +266,7 @@ impl> ReportIndexStorage { fn load(time_slot: &O::TimeSlot) -> Self { let opaque_time_slot = time_slot.encode(); - let same_kind_reports = ReportsByKindIndex::::get(&O::ID).unwrap_or_default(); + let same_kind_reports = ReportsByKindIndex::::get(&O::ID); let same_kind_reports = Vec::<(O::TimeSlot, ReportIdOf)>::decode(&mut &same_kind_reports[..]) .unwrap_or_default();