mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 22:11:01 +00:00
Removes ReportsByKindIndex (#13936)
* Removes ReportsByKind * Minor build fixes * adds migration * Addresses review comment * Uses clear but weight check fails * Uses unique * Updates test to commit the change before migration * Uses reads_writes * ".git/.scripts/commands/fmt/fmt.sh" * Fixes build * Addresses review comments * ".git/.scripts/commands/fmt/fmt.sh" * fixes typo --------- Co-authored-by: command-bot <>
This commit is contained in:
@@ -26,7 +26,9 @@ pub mod migration;
|
|||||||
mod mock;
|
mod mock;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use codec::{Decode, Encode};
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use codec::Encode;
|
||||||
use frame_support::weights::Weight;
|
use frame_support::weights::Weight;
|
||||||
use sp_runtime::{traits::Hash, Perbill};
|
use sp_runtime::{traits::Hash, Perbill};
|
||||||
use sp_staking::{
|
use sp_staking::{
|
||||||
@@ -43,12 +45,17 @@ type OpaqueTimeSlot = Vec<u8>;
|
|||||||
/// A type alias for a report identifier.
|
/// A type alias for a report identifier.
|
||||||
type ReportIdOf<T> = <T as frame_system::Config>::Hash;
|
type ReportIdOf<T> = <T as frame_system::Config>::Hash;
|
||||||
|
|
||||||
|
const LOG_TARGET: &str = "runtime::offences";
|
||||||
|
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use super::*;
|
use super::*;
|
||||||
use frame_support::pallet_prelude::*;
|
use frame_support::pallet_prelude::*;
|
||||||
|
|
||||||
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
#[pallet::without_storage_info]
|
#[pallet::without_storage_info]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
@@ -85,21 +92,6 @@ pub mod pallet {
|
|||||||
ValueQuery,
|
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<u8>`, 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<T> = StorageMap<
|
|
||||||
_,
|
|
||||||
Twox64Concat,
|
|
||||||
Kind,
|
|
||||||
Vec<u8>, // (O::TimeSlot, ReportIdOf<T>)
|
|
||||||
ValueQuery,
|
|
||||||
>;
|
|
||||||
|
|
||||||
/// Events type.
|
/// Events type.
|
||||||
#[pallet::event]
|
#[pallet::event]
|
||||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||||
@@ -190,7 +182,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
OffenceDetails { offender, reporters: reporters.clone() },
|
OffenceDetails { offender, reporters: reporters.clone() },
|
||||||
);
|
);
|
||||||
|
|
||||||
storage.insert(time_slot, report_id);
|
storage.insert(report_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +217,7 @@ struct TriageOutcome<T: Config> {
|
|||||||
struct ReportIndexStorage<T: Config, O: Offence<T::IdentificationTuple>> {
|
struct ReportIndexStorage<T: Config, O: Offence<T::IdentificationTuple>> {
|
||||||
opaque_time_slot: OpaqueTimeSlot,
|
opaque_time_slot: OpaqueTimeSlot,
|
||||||
concurrent_reports: Vec<ReportIdOf<T>>,
|
concurrent_reports: Vec<ReportIdOf<T>>,
|
||||||
same_kind_reports: Vec<(O::TimeSlot, ReportIdOf<T>)>,
|
_phantom: PhantomData<O>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config, O: Offence<T::IdentificationTuple>> ReportIndexStorage<T, O> {
|
impl<T: Config, O: Offence<T::IdentificationTuple>> ReportIndexStorage<T, O> {
|
||||||
@@ -233,30 +225,19 @@ impl<T: Config, O: Offence<T::IdentificationTuple>> ReportIndexStorage<T, O> {
|
|||||||
fn load(time_slot: &O::TimeSlot) -> Self {
|
fn load(time_slot: &O::TimeSlot) -> Self {
|
||||||
let opaque_time_slot = time_slot.encode();
|
let opaque_time_slot = time_slot.encode();
|
||||||
|
|
||||||
let same_kind_reports = ReportsByKindIndex::<T>::get(&O::ID);
|
|
||||||
let same_kind_reports =
|
|
||||||
Vec::<(O::TimeSlot, ReportIdOf<T>)>::decode(&mut &same_kind_reports[..])
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let concurrent_reports = <ConcurrentReportsIndex<T>>::get(&O::ID, &opaque_time_slot);
|
let concurrent_reports = <ConcurrentReportsIndex<T>>::get(&O::ID, &opaque_time_slot);
|
||||||
|
|
||||||
Self { opaque_time_slot, concurrent_reports, same_kind_reports }
|
Self { opaque_time_slot, concurrent_reports, _phantom: Default::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a new report to the index.
|
/// Insert a new report to the index.
|
||||||
fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf<T>) {
|
fn insert(&mut self, report_id: ReportIdOf<T>) {
|
||||||
// Insert the report id into the list while maintaining the ordering by the time
|
|
||||||
// slot.
|
|
||||||
let pos = self.same_kind_reports.partition_point(|(when, _)| when <= time_slot);
|
|
||||||
self.same_kind_reports.insert(pos, (time_slot.clone(), report_id));
|
|
||||||
|
|
||||||
// Update the list of concurrent reports.
|
// Update the list of concurrent reports.
|
||||||
self.concurrent_reports.push(report_id);
|
self.concurrent_reports.push(report_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dump the indexes to the storage.
|
/// Dump the indexes to the storage.
|
||||||
fn save(self) {
|
fn save(self) {
|
||||||
ReportsByKindIndex::<T>::insert(&O::ID, self.same_kind_reports.encode());
|
|
||||||
<ConcurrentReportsIndex<T>>::insert(
|
<ConcurrentReportsIndex<T>>::insert(
|
||||||
&O::ID,
|
&O::ID,
|
||||||
&self.opaque_time_slot,
|
&self.opaque_time_slot,
|
||||||
|
|||||||
@@ -15,11 +15,84 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::{Config, OffenceDetails, Perbill, SessionIndex};
|
use super::{Config, Kind, OffenceDetails, Pallet, Perbill, SessionIndex, LOG_TARGET};
|
||||||
use frame_support::{pallet_prelude::ValueQuery, storage_alias, traits::Get, weights::Weight};
|
use frame_support::{
|
||||||
|
dispatch::GetStorageVersion,
|
||||||
|
pallet_prelude::ValueQuery,
|
||||||
|
storage_alias,
|
||||||
|
traits::{Get, OnRuntimeUpgrade},
|
||||||
|
weights::Weight,
|
||||||
|
Twox64Concat,
|
||||||
|
};
|
||||||
use sp_staking::offence::{DisableStrategy, OnOffenceHandler};
|
use sp_staking::offence::{DisableStrategy, OnOffenceHandler};
|
||||||
use sp_std::vec::Vec;
|
use sp_std::vec::Vec;
|
||||||
|
|
||||||
|
#[cfg(feature = "try-runtime")]
|
||||||
|
use frame_support::ensure;
|
||||||
|
|
||||||
|
mod v0 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[storage_alias]
|
||||||
|
pub type ReportsByKindIndex<T: Config> = StorageMap<
|
||||||
|
Pallet<T>,
|
||||||
|
Twox64Concat,
|
||||||
|
Kind,
|
||||||
|
Vec<u8>, // (O::TimeSlot, ReportIdOf<T>)
|
||||||
|
ValueQuery,
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod v1 {
|
||||||
|
use frame_support::traits::StorageVersion;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||||
|
#[cfg(feature = "try-runtime")]
|
||||||
|
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
|
||||||
|
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||||
|
ensure!(onchain < 1, "pallet_offences::MigrateToV1 migration can be deleted");
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
"Number of reports to refund and delete: {}",
|
||||||
|
v0::ReportsByKindIndex::<T>::iter_keys().count()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_runtime_upgrade() -> Weight {
|
||||||
|
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||||
|
|
||||||
|
if onchain > 0 {
|
||||||
|
log::info!(target: LOG_TARGET, "pallet_offences::MigrateToV1 should be removed");
|
||||||
|
return T::DbWeight::get().reads(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let keys_removed = v0::ReportsByKindIndex::<T>::clear(u32::MAX, None).unique as u64;
|
||||||
|
let weight = T::DbWeight::get().reads_writes(keys_removed, keys_removed);
|
||||||
|
|
||||||
|
StorageVersion::new(1).put::<Pallet<T>>();
|
||||||
|
|
||||||
|
weight
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "try-runtime")]
|
||||||
|
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
|
||||||
|
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||||
|
ensure!(onchain == 1, "pallet_offences::MigrateToV1 needs to be run");
|
||||||
|
ensure!(
|
||||||
|
v0::ReportsByKindIndex::<T>::iter_keys().count() == 0,
|
||||||
|
"there are some dangling reports that need to be destroyed and refunded"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Type of data stored as a deferred offence
|
/// Type of data stored as a deferred offence
|
||||||
type DeferredOffenceOf<T> = (
|
type DeferredOffenceOf<T> = (
|
||||||
Vec<OffenceDetails<<T as frame_system::Config>::AccountId, <T as Config>::IdentificationTuple>>,
|
Vec<OffenceDetails<<T as frame_system::Config>::AccountId, <T as Config>::IdentificationTuple>>,
|
||||||
@@ -36,7 +109,7 @@ type DeferredOffences<T: Config> =
|
|||||||
pub fn remove_deferred_storage<T: Config>() -> Weight {
|
pub fn remove_deferred_storage<T: Config>() -> Weight {
|
||||||
let mut weight = T::DbWeight::get().reads_writes(1, 1);
|
let mut weight = T::DbWeight::get().reads_writes(1, 1);
|
||||||
let deferred = <DeferredOffences<T>>::take();
|
let deferred = <DeferredOffences<T>>::take();
|
||||||
log::info!(target: "runtime::offences", "have {} deferred offences, applying.", deferred.len());
|
log::info!(target: LOG_TARGET, "have {} deferred offences, applying.", deferred.len());
|
||||||
for (offences, perbill, session) in deferred.iter() {
|
for (offences, perbill, session) in deferred.iter() {
|
||||||
let consumed = T::OnOffenceHandler::on_offence(
|
let consumed = T::OnOffenceHandler::on_offence(
|
||||||
offences,
|
offences,
|
||||||
@@ -53,10 +126,32 @@ pub fn remove_deferred_storage<T: Config>() -> Weight {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mock::{new_test_ext, with_on_offence_fractions, Runtime as T};
|
use crate::mock::{new_test_ext, with_on_offence_fractions, Runtime as T, KIND};
|
||||||
|
use codec::Encode;
|
||||||
use sp_runtime::Perbill;
|
use sp_runtime::Perbill;
|
||||||
use sp_staking::offence::OffenceDetails;
|
use sp_staking::offence::OffenceDetails;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn migration_to_v1_works() {
|
||||||
|
let mut ext = new_test_ext();
|
||||||
|
|
||||||
|
ext.execute_with(|| {
|
||||||
|
<v0::ReportsByKindIndex<T>>::insert(KIND, 2u32.encode());
|
||||||
|
assert!(<v0::ReportsByKindIndex<T>>::iter_values().count() > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
ext.commit_all().unwrap();
|
||||||
|
|
||||||
|
ext.execute_with(|| {
|
||||||
|
assert_eq!(
|
||||||
|
v1::MigrateToV1::<T>::on_runtime_upgrade(),
|
||||||
|
<T as frame_system::Config>::DbWeight::get().reads_writes(1, 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(<v0::ReportsByKindIndex<T>>::iter_values().count() == 0);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_resubmit_deferred_offences() {
|
fn should_resubmit_deferred_offences() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
|
|||||||
@@ -164,8 +164,3 @@ impl offence::Offence<u64> for Offence {
|
|||||||
Perbill::from_percent(5 + offenders_count * 100 / self.validator_set_count)
|
Perbill::from_percent(5 + offenders_count * 100 / self.validator_set_count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the report id for the given `offender` and `time_slot` combination.
|
|
||||||
pub fn report_id(time_slot: u128, offender: u64) -> H256 {
|
|
||||||
Offences::report_id::<Offence>(&time_slot, &offender)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mock::{
|
use crate::mock::{
|
||||||
new_test_ext, offence_reports, report_id, with_on_offence_fractions, Offence, Offences,
|
new_test_ext, offence_reports, with_on_offence_fractions, Offence, Offences, RuntimeEvent,
|
||||||
RuntimeEvent, System, KIND,
|
System, KIND,
|
||||||
};
|
};
|
||||||
use frame_system::{EventRecord, Phase};
|
use frame_system::{EventRecord, Phase};
|
||||||
use sp_runtime::Perbill;
|
use sp_runtime::Perbill;
|
||||||
@@ -245,48 +245,3 @@ fn should_properly_count_offences() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We insert offences in sorted order using the time slot in the `same_kind_reports`.
|
|
||||||
/// This test ensures that it works as expected.
|
|
||||||
#[test]
|
|
||||||
fn should_properly_sort_offences() {
|
|
||||||
new_test_ext().execute_with(|| {
|
|
||||||
// given
|
|
||||||
let time_slot = 42;
|
|
||||||
assert_eq!(offence_reports(KIND, time_slot), vec![]);
|
|
||||||
|
|
||||||
let offence1 = Offence { validator_set_count: 5, time_slot, offenders: vec![5] };
|
|
||||||
let offence2 = Offence { validator_set_count: 5, time_slot, offenders: vec![4] };
|
|
||||||
let offence3 =
|
|
||||||
Offence { validator_set_count: 5, time_slot: time_slot + 1, offenders: vec![6, 7] };
|
|
||||||
let offence4 =
|
|
||||||
Offence { validator_set_count: 5, time_slot: time_slot - 1, offenders: vec![3] };
|
|
||||||
Offences::report_offence(vec![], offence1).unwrap();
|
|
||||||
with_on_offence_fractions(|f| {
|
|
||||||
assert_eq!(f.clone(), vec![Perbill::from_percent(25)]);
|
|
||||||
f.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
// when
|
|
||||||
// report for the second time
|
|
||||||
Offences::report_offence(vec![], offence2).unwrap();
|
|
||||||
Offences::report_offence(vec![], offence3).unwrap();
|
|
||||||
Offences::report_offence(vec![], offence4).unwrap();
|
|
||||||
|
|
||||||
// then
|
|
||||||
let same_kind_reports = Vec::<(u128, sp_core::H256)>::decode(
|
|
||||||
&mut &crate::ReportsByKindIndex::<crate::mock::Runtime>::get(KIND)[..],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
same_kind_reports,
|
|
||||||
vec![
|
|
||||||
(time_slot - 1, report_id(time_slot - 1, 3)),
|
|
||||||
(time_slot, report_id(time_slot, 5)),
|
|
||||||
(time_slot, report_id(time_slot, 4)),
|
|
||||||
(time_slot + 1, report_id(time_slot + 1, 6)),
|
|
||||||
(time_slot + 1, report_id(time_slot + 1, 7)),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user