pallet_offences/
migration.rs1use super::{Config, Kind, OffenceDetails, Pallet, Perbill, SessionIndex, LOG_TARGET};
19use alloc::vec::Vec;
20use frame_support::{
21 pallet_prelude::ValueQuery,
22 storage_alias,
23 traits::{Get, GetStorageVersion, OnRuntimeUpgrade},
24 weights::Weight,
25 Twox64Concat,
26};
27use sp_staking::offence::OnOffenceHandler;
28
29#[cfg(feature = "try-runtime")]
30use frame_support::ensure;
31#[cfg(feature = "try-runtime")]
32use sp_runtime::TryRuntimeError;
33
34mod v0 {
35 use super::*;
36
37 #[storage_alias]
38 pub type ReportsByKindIndex<T: Config> = StorageMap<
39 Pallet<T>,
40 Twox64Concat,
41 Kind,
42 Vec<u8>, ValueQuery,
44 >;
45}
46
47pub mod v1 {
48 use frame_support::traits::StorageVersion;
49
50 use super::*;
51
52 pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
53 impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
54 #[cfg(feature = "try-runtime")]
55 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
56 log::info!(
57 target: LOG_TARGET,
58 "Number of reports to refund and delete: {}",
59 v0::ReportsByKindIndex::<T>::iter_keys().count()
60 );
61
62 Ok(Vec::new())
63 }
64
65 fn on_runtime_upgrade() -> Weight {
66 if Pallet::<T>::on_chain_storage_version() > 0 {
67 log::info!(target: LOG_TARGET, "pallet_offences::MigrateToV1 should be removed");
68 return T::DbWeight::get().reads(1)
69 }
70
71 let keys_removed = v0::ReportsByKindIndex::<T>::clear(u32::MAX, None).unique as u64;
72 StorageVersion::new(1).put::<Pallet<T>>();
73
74 T::DbWeight::get().reads_writes(keys_removed + 1, keys_removed + 1)
76 }
77
78 #[cfg(feature = "try-runtime")]
79 fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
80 let onchain = Pallet::<T>::on_chain_storage_version();
81 ensure!(onchain == 1, "pallet_offences::MigrateToV1 needs to be run");
82 ensure!(
83 v0::ReportsByKindIndex::<T>::iter_keys().count() == 0,
84 "there are some dangling reports that need to be destroyed and refunded"
85 );
86 Ok(())
87 }
88 }
89}
90
91type DeferredOffenceOf<T> = (
93 Vec<OffenceDetails<<T as frame_system::Config>::AccountId, <T as Config>::IdentificationTuple>>,
94 Vec<Perbill>,
95 SessionIndex,
96);
97
98#[storage_alias]
101type DeferredOffences<T: Config> =
102 StorageValue<crate::Pallet<T>, Vec<DeferredOffenceOf<T>>, ValueQuery>;
103
104pub fn remove_deferred_storage<T: Config>() -> Weight {
105 let mut weight = T::DbWeight::get().reads_writes(1, 1);
106 let deferred = <DeferredOffences<T>>::take();
107 log::info!(target: LOG_TARGET, "have {} deferred offences, applying.", deferred.len());
108 for (offences, perbill, session) in deferred.iter() {
109 let consumed = T::OnOffenceHandler::on_offence(offences, perbill, *session);
110 weight = weight.saturating_add(consumed);
111 }
112
113 weight
114}
115
116#[cfg(test)]
117mod test {
118 use super::*;
119 use crate::mock::{new_test_ext, with_on_offence_fractions, Runtime as T, KIND};
120 use codec::Encode;
121 use sp_runtime::Perbill;
122 use sp_staking::offence::OffenceDetails;
123
124 #[test]
125 fn migration_to_v1_works() {
126 let mut ext = new_test_ext();
127
128 ext.execute_with(|| {
129 <v0::ReportsByKindIndex<T>>::insert(KIND, 2u32.encode());
130 assert!(<v0::ReportsByKindIndex<T>>::iter_values().count() > 0);
131 });
132
133 ext.commit_all().unwrap();
134
135 ext.execute_with(|| {
136 assert_eq!(
137 v1::MigrateToV1::<T>::on_runtime_upgrade(),
138 <T as frame_system::Config>::DbWeight::get().reads_writes(2, 2),
139 );
140
141 assert!(<v0::ReportsByKindIndex<T>>::iter_values().count() == 0);
142 })
143 }
144
145 #[test]
146 fn should_resubmit_deferred_offences() {
147 new_test_ext().execute_with(|| {
148 assert_eq!(<DeferredOffences<T>>::get().len(), 0);
150 with_on_offence_fractions(|f| {
151 assert_eq!(f.clone(), vec![]);
152 });
153
154 let offence_details = OffenceDetails::<
155 <T as frame_system::Config>::AccountId,
156 <T as Config>::IdentificationTuple,
157 > {
158 offender: 5,
159 reporters: vec![],
160 };
161
162 <DeferredOffences<T>>::append((
164 vec![offence_details],
165 vec![Perbill::from_percent(5 + 1 * 100 / 5)],
166 1,
167 ));
168
169 assert_eq!(
171 remove_deferred_storage::<T>(),
172 <T as frame_system::Config>::DbWeight::get().reads_writes(1, 1),
173 );
174
175 assert!(!<DeferredOffences<T>>::exists());
177 with_on_offence_fractions(|f| {
178 assert_eq!(f.clone(), vec![Perbill::from_percent(5 + 1 * 100 / 5)]);
179 });
180 })
181 }
182}