mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 15:47:58 +00:00
Migrate pallet-tips to the new pallet attribute macro (#9711)
* Migrate pallet-tips to the new pallet attribute macro Signed-off-by: koushiro <koushiro.cqx@gmail.com> * Fix migration Signed-off-by: koushiro <koushiro.cqx@gmail.com>
This commit is contained in:
@@ -19,13 +19,13 @@
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use super::*;
|
||||
|
||||
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
|
||||
use frame_support::ensure;
|
||||
use frame_system::RawOrigin;
|
||||
use sp_runtime::traits::Saturating;
|
||||
|
||||
use crate::Module as TipsMod;
|
||||
use super::*;
|
||||
use crate::Pallet as TipsMod;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
|
||||
+153
-134
@@ -15,7 +15,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Tipping Module ( pallet-tips )
|
||||
//! # Tipping Pallet ( pallet-tips )
|
||||
//!
|
||||
//! > NOTE: This pallet is tightly coupled with pallet-treasury.
|
||||
//!
|
||||
@@ -56,55 +56,31 @@
|
||||
|
||||
mod benchmarking;
|
||||
mod tests;
|
||||
|
||||
pub mod migrations;
|
||||
pub mod weights;
|
||||
|
||||
use frame_support::{
|
||||
decl_error, decl_event, decl_module, decl_storage, ensure,
|
||||
traits::{Currency, ExistenceRequirement::KeepAlive, Get, ReservableCurrency},
|
||||
Parameter,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::traits::{ContainsLengthBound, EnsureOrigin, OnUnbalanced, SortedMembers};
|
||||
use frame_system::{self as system, ensure_signed};
|
||||
use sp_runtime::{
|
||||
traits::{AccountIdConversion, BadOrigin, Hash, Zero},
|
||||
Percent, RuntimeDebug,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
traits::{
|
||||
ContainsLengthBound, Currency, EnsureOrigin, ExistenceRequirement::KeepAlive, Get,
|
||||
OnUnbalanced, ReservableCurrency, SortedMembers, StorageVersion,
|
||||
},
|
||||
Parameter,
|
||||
};
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
pub type BalanceOf<T> = pallet_treasury::BalanceOf<T>;
|
||||
pub type NegativeImbalanceOf<T> = pallet_treasury::NegativeImbalanceOf<T>;
|
||||
|
||||
pub trait Config: frame_system::Config + pallet_treasury::Config {
|
||||
/// Maximum acceptable reason length.
|
||||
type MaximumReasonLength: Get<u32>;
|
||||
|
||||
/// The amount held on deposit per byte within the tip report reason or bounty description.
|
||||
type DataDepositPerByte: Get<BalanceOf<Self>>;
|
||||
|
||||
/// Origin from which tippers must come.
|
||||
///
|
||||
/// `ContainsLengthBound::max_len` must be cost free (i.e. no storage read or heavy operation).
|
||||
type Tippers: SortedMembers<Self::AccountId> + ContainsLengthBound;
|
||||
|
||||
/// The period for which a tip remains open after is has achieved threshold tippers.
|
||||
type TipCountdown: Get<Self::BlockNumber>;
|
||||
|
||||
/// The percent of the final tip which goes to the original reporter of the tip.
|
||||
type TipFindersFee: Get<Percent>;
|
||||
|
||||
/// The amount held on deposit for placing a tip report.
|
||||
type TipReportDepositBase: Get<BalanceOf<Self>>;
|
||||
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
|
||||
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// An open tipping "motion". Retains all details of a tip including information on the finder
|
||||
/// and the members who have voted.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
|
||||
@@ -132,50 +108,96 @@ pub struct OpenTip<
|
||||
finders_fee: bool,
|
||||
}
|
||||
|
||||
// Note :: For backward compatability reasons,
|
||||
// pallet-tips uses Treasury for storage.
|
||||
// This is temporary solution, soon will get replaced with
|
||||
// Own storage identifier.
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Config> as Treasury {
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// TipsMap that are not yet completed. Keyed by the hash of `(reason, who)` from the value.
|
||||
/// This has the insecure enumerable hash function since the key itself is already
|
||||
/// guaranteed to be a secure hash.
|
||||
pub Tips get(fn tips):
|
||||
map hasher(twox_64_concat) T::Hash
|
||||
=> Option<OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>>;
|
||||
/// The current storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
/// Simple preimage lookup from the reason's hash to the original data. Again, has an
|
||||
/// insecure enumerable hash since the key is guaranteed to be the result of a secure hash.
|
||||
pub Reasons get(fn reasons): map hasher(identity) T::Hash => Option<Vec<u8>>;
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config + pallet_treasury::Config {
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
|
||||
/// Maximum acceptable reason length.
|
||||
#[pallet::constant]
|
||||
type MaximumReasonLength: Get<u32>;
|
||||
|
||||
/// The amount held on deposit per byte within the tip report reason or bounty description.
|
||||
#[pallet::constant]
|
||||
type DataDepositPerByte: Get<BalanceOf<Self>>;
|
||||
|
||||
/// The period for which a tip remains open after is has achieved threshold tippers.
|
||||
#[pallet::constant]
|
||||
type TipCountdown: Get<Self::BlockNumber>;
|
||||
|
||||
/// The percent of the final tip which goes to the original reporter of the tip.
|
||||
#[pallet::constant]
|
||||
type TipFindersFee: Get<Percent>;
|
||||
|
||||
/// The amount held on deposit for placing a tip report.
|
||||
#[pallet::constant]
|
||||
type TipReportDepositBase: Get<BalanceOf<Self>>;
|
||||
|
||||
/// Origin from which tippers must come.
|
||||
///
|
||||
/// `ContainsLengthBound::max_len` must be cost free (i.e. no storage read or heavy
|
||||
/// operation).
|
||||
type Tippers: SortedMembers<Self::AccountId> + ContainsLengthBound;
|
||||
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
pub enum Event<T>
|
||||
where
|
||||
Balance = BalanceOf<T>,
|
||||
<T as frame_system::Config>::AccountId,
|
||||
<T as frame_system::Config>::Hash,
|
||||
{
|
||||
/// TipsMap that are not yet completed. Keyed by the hash of `(reason, who)` from the value.
|
||||
/// This has the insecure enumerable hash function since the key itself is already
|
||||
/// guaranteed to be a secure hash.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn tips)]
|
||||
pub type Tips<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
T::Hash,
|
||||
OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
|
||||
OptionQuery,
|
||||
>;
|
||||
|
||||
/// Simple preimage lookup from the reason's hash to the original data. Again, has an
|
||||
/// insecure enumerable hash since the key is guaranteed to be the result of a secure hash.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn reasons)]
|
||||
pub type Reasons<T: Config> = StorageMap<_, Identity, T::Hash, Vec<u8>, OptionQuery>;
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::metadata(T::Hash = "Hash", T::AccountId = "AccountId", BalanceOf<T> = "Balance")]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A new tip suggestion has been opened. \[tip_hash\]
|
||||
NewTip(Hash),
|
||||
NewTip(T::Hash),
|
||||
/// A tip suggestion has reached threshold and is closing. \[tip_hash\]
|
||||
TipClosing(Hash),
|
||||
TipClosing(T::Hash),
|
||||
/// A tip suggestion has been closed. \[tip_hash, who, payout\]
|
||||
TipClosed(Hash, AccountId, Balance),
|
||||
TipClosed(T::Hash, T::AccountId, BalanceOf<T>),
|
||||
/// A tip suggestion has been retracted. \[tip_hash\]
|
||||
TipRetracted(Hash),
|
||||
TipRetracted(T::Hash),
|
||||
/// A tip suggestion has been slashed. \[tip_hash, finder, deposit\]
|
||||
TipSlashed(Hash, AccountId, Balance),
|
||||
TipSlashed(T::Hash, T::AccountId, BalanceOf<T>),
|
||||
}
|
||||
);
|
||||
|
||||
decl_error! {
|
||||
/// Error for the tips module.
|
||||
pub enum Error for Module<T: Config> {
|
||||
/// Old name generated by `decl_event`.
|
||||
#[deprecated(note = "use `Event` instead")]
|
||||
pub type RawEvent<T> = Event<T>;
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The reason given is just too big.
|
||||
ReasonTooBig,
|
||||
/// The tip was already found/started.
|
||||
@@ -189,32 +211,9 @@ decl_error! {
|
||||
/// The tip cannot be claimed/closed because it's still in the countdown period.
|
||||
Premature,
|
||||
}
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Config>
|
||||
for enum Call
|
||||
where origin: T::Origin
|
||||
{
|
||||
/// The period for which a tip remains open after is has achieved threshold tippers.
|
||||
const TipCountdown: T::BlockNumber = T::TipCountdown::get();
|
||||
|
||||
/// The amount of the final tip which goes to the original reporter of the tip.
|
||||
const TipFindersFee: Percent = T::TipFindersFee::get();
|
||||
|
||||
/// The amount held on deposit for placing a tip report.
|
||||
const TipReportDepositBase: BalanceOf<T> = T::TipReportDepositBase::get();
|
||||
|
||||
/// The amount held on deposit per byte within the tip report reason.
|
||||
const DataDepositPerByte: BalanceOf<T> = T::DataDepositPerByte::get();
|
||||
|
||||
/// Maximum acceptable reason length.
|
||||
const MaximumReasonLength: u32 = T::MaximumReasonLength::get();
|
||||
|
||||
type Error = Error<T>;
|
||||
|
||||
fn deposit_event() = default;
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Report something `reason` that deserves a tip and claim any eventual the finder's fee.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_.
|
||||
@@ -234,19 +233,26 @@ decl_module! {
|
||||
/// - DbReads: `Reasons`, `Tips`
|
||||
/// - DbWrites: `Reasons`, `Tips`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::report_awesome(reason.len() as u32)]
|
||||
fn report_awesome(origin, reason: Vec<u8>, who: T::AccountId) {
|
||||
#[pallet::weight(<T as Config>::WeightInfo::report_awesome(reason.len() as u32))]
|
||||
pub fn report_awesome(
|
||||
origin: OriginFor<T>,
|
||||
reason: Vec<u8>,
|
||||
who: T::AccountId,
|
||||
) -> DispatchResult {
|
||||
let finder = ensure_signed(origin)?;
|
||||
|
||||
ensure!(reason.len() <= T::MaximumReasonLength::get() as usize, Error::<T>::ReasonTooBig);
|
||||
ensure!(
|
||||
reason.len() <= T::MaximumReasonLength::get() as usize,
|
||||
Error::<T>::ReasonTooBig
|
||||
);
|
||||
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
ensure!(!Reasons::<T>::contains_key(&reason_hash), Error::<T>::AlreadyKnown);
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &who));
|
||||
ensure!(!Tips::<T>::contains_key(&hash), Error::<T>::AlreadyKnown);
|
||||
|
||||
let deposit = T::TipReportDepositBase::get()
|
||||
+ T::DataDepositPerByte::get() * (reason.len() as u32).into();
|
||||
let deposit = T::TipReportDepositBase::get() +
|
||||
T::DataDepositPerByte::get() * (reason.len() as u32).into();
|
||||
T::Currency::reserve(&finder, deposit)?;
|
||||
|
||||
Reasons::<T>::insert(&reason_hash, &reason);
|
||||
@@ -257,10 +263,11 @@ decl_module! {
|
||||
deposit,
|
||||
closes: None,
|
||||
tips: vec![],
|
||||
finders_fee: true
|
||||
finders_fee: true,
|
||||
};
|
||||
Tips::<T>::insert(&hash, tip);
|
||||
Self::deposit_event(RawEvent::NewTip(hash));
|
||||
Self::deposit_event(Event::NewTip(hash));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retract a prior tip-report from `report_awesome`, and cancel the process of tipping.
|
||||
@@ -282,8 +289,8 @@ decl_module! {
|
||||
/// - DbReads: `Tips`, `origin account`
|
||||
/// - DbWrites: `Reasons`, `Tips`, `origin account`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::retract_tip()]
|
||||
fn retract_tip(origin, hash: T::Hash) {
|
||||
#[pallet::weight(<T as Config>::WeightInfo::retract_tip())]
|
||||
pub fn retract_tip(origin: OriginFor<T>, hash: T::Hash) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
let tip = Tips::<T>::get(&hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
ensure!(tip.finder == who, Error::<T>::NotFinder);
|
||||
@@ -294,7 +301,8 @@ decl_module! {
|
||||
let err_amount = T::Currency::unreserve(&who, tip.deposit);
|
||||
debug_assert!(err_amount.is_zero());
|
||||
}
|
||||
Self::deposit_event(RawEvent::TipRetracted(hash));
|
||||
Self::deposit_event(Event::TipRetracted(hash));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Give a tip for something new; no finder's fee will be taken.
|
||||
@@ -312,15 +320,20 @@ decl_module! {
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(R + T)` where `R` length of `reason`, `T` is the number of tippers.
|
||||
/// - `O(T)`: decoding `Tipper` vec of length `T`
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
/// - `O(T)`: decoding `Tipper` vec of length `T`. `T` is charged as upper bound given by
|
||||
/// `ContainsLengthBound`. The actual cost depends on the implementation of
|
||||
/// `T::Tippers`.
|
||||
/// - `O(R)`: hashing and encoding of reason of length `R`
|
||||
/// - DbReads: `Tippers`, `Reasons`
|
||||
/// - DbWrites: `Reasons`, `Tips`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::tip_new(reason.len() as u32, T::Tippers::max_len() as u32)]
|
||||
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, #[compact] tip_value: BalanceOf<T>) {
|
||||
#[pallet::weight(<T as Config>::WeightInfo::tip_new(reason.len() as u32, T::Tippers::max_len() as u32))]
|
||||
pub fn tip_new(
|
||||
origin: OriginFor<T>,
|
||||
reason: Vec<u8>,
|
||||
who: T::AccountId,
|
||||
#[pallet::compact] tip_value: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let tipper = ensure_signed(origin)?;
|
||||
ensure!(T::Tippers::contains(&tipper), BadOrigin);
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
@@ -328,7 +341,7 @@ decl_module! {
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &who));
|
||||
|
||||
Reasons::<T>::insert(&reason_hash, &reason);
|
||||
Self::deposit_event(RawEvent::NewTip(hash.clone()));
|
||||
Self::deposit_event(Event::NewTip(hash.clone()));
|
||||
let tips = vec![(tipper.clone(), tip_value)];
|
||||
let tip = OpenTip {
|
||||
reason: reason_hash,
|
||||
@@ -340,6 +353,7 @@ decl_module! {
|
||||
finders_fee: false,
|
||||
};
|
||||
Tips::<T>::insert(&hash, tip);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Declare a tip value for an already-open tip.
|
||||
@@ -357,26 +371,30 @@ decl_module! {
|
||||
/// has started.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(T)` where `T` is the number of tippers.
|
||||
/// decoding `Tipper` vec of length `T`, insert tip and check closing,
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
/// - Complexity: `O(T)` where `T` is the number of tippers. decoding `Tipper` vec of length
|
||||
/// `T`, insert tip and check closing, `T` is charged as upper bound given by
|
||||
/// `ContainsLengthBound`. The actual cost depends on the implementation of `T::Tippers`.
|
||||
///
|
||||
/// Actually weight could be lower as it depends on how many tips are in `OpenTip` but it
|
||||
/// is weighted as if almost full i.e of length `T-1`.
|
||||
/// - DbReads: `Tippers`, `Tips`
|
||||
/// - DbWrites: `Tips`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::tip(T::Tippers::max_len() as u32)]
|
||||
fn tip(origin, hash: T::Hash, #[compact] tip_value: BalanceOf<T>) {
|
||||
#[pallet::weight(<T as Config>::WeightInfo::tip(T::Tippers::max_len() as u32))]
|
||||
pub fn tip(
|
||||
origin: OriginFor<T>,
|
||||
hash: T::Hash,
|
||||
#[pallet::compact] tip_value: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let tipper = ensure_signed(origin)?;
|
||||
ensure!(T::Tippers::contains(&tipper), BadOrigin);
|
||||
|
||||
let mut tip = Tips::<T>::get(hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) {
|
||||
Self::deposit_event(RawEvent::TipClosing(hash.clone()));
|
||||
Self::deposit_event(Event::TipClosing(hash.clone()));
|
||||
}
|
||||
Tips::<T>::insert(&hash, tip);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close and payout a tip.
|
||||
@@ -389,24 +407,24 @@ decl_module! {
|
||||
/// as the hash of the tuple of the original tip `reason` and the beneficiary account ID.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(T)` where `T` is the number of tippers.
|
||||
/// decoding `Tipper` vec of length `T`.
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
/// - Complexity: `O(T)` where `T` is the number of tippers. decoding `Tipper` vec of length
|
||||
/// `T`. `T` is charged as upper bound given by `ContainsLengthBound`. The actual cost
|
||||
/// depends on the implementation of `T::Tippers`.
|
||||
/// - DbReads: `Tips`, `Tippers`, `tip finder`
|
||||
/// - DbWrites: `Reasons`, `Tips`, `Tippers`, `tip finder`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::close_tip(T::Tippers::max_len() as u32)]
|
||||
fn close_tip(origin, hash: T::Hash) {
|
||||
#[pallet::weight(<T as Config>::WeightInfo::close_tip(T::Tippers::max_len() as u32))]
|
||||
pub fn close_tip(origin: OriginFor<T>, hash: T::Hash) -> DispatchResult {
|
||||
ensure_signed(origin)?;
|
||||
|
||||
let tip = Tips::<T>::get(hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
let n = tip.closes.as_ref().ok_or(Error::<T>::StillOpen)?;
|
||||
ensure!(system::Pallet::<T>::block_number() >= *n, Error::<T>::Premature);
|
||||
ensure!(frame_system::Pallet::<T>::block_number() >= *n, Error::<T>::Premature);
|
||||
// closed.
|
||||
Reasons::<T>::remove(&tip.reason);
|
||||
Tips::<T>::remove(hash);
|
||||
Self::payout_tip(hash, tip);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove and slash an already-open tip.
|
||||
@@ -421,8 +439,8 @@ decl_module! {
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::slash_tip(T::Tippers::max_len() as u32)]
|
||||
fn slash_tip(origin, hash: T::Hash) {
|
||||
#[pallet::weight(<T as Config>::WeightInfo::slash_tip(T::Tippers::max_len() as u32))]
|
||||
pub fn slash_tip(origin: OriginFor<T>, hash: T::Hash) -> DispatchResult {
|
||||
T::RejectOrigin::ensure_origin(origin)?;
|
||||
|
||||
let tip = Tips::<T>::take(hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
@@ -432,12 +450,13 @@ decl_module! {
|
||||
T::OnSlash::on_unbalanced(imbalance);
|
||||
}
|
||||
Reasons::<T>::remove(&tip.reason);
|
||||
Self::deposit_event(RawEvent::TipSlashed(hash, tip.finder, tip.deposit));
|
||||
Self::deposit_event(Event::TipSlashed(hash, tip.finder, tip.deposit));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Module<T> {
|
||||
impl<T: Config> Pallet<T> {
|
||||
// Add public immutables and private mutables.
|
||||
|
||||
/// The account ID of the treasury pot.
|
||||
@@ -464,7 +483,7 @@ impl<T: Config> Module<T> {
|
||||
Self::retain_active_tips(&mut tip.tips);
|
||||
let threshold = (T::Tippers::count() + 1) / 2;
|
||||
if tip.tips.len() >= threshold && tip.closes.is_none() {
|
||||
tip.closes = Some(system::Pallet::<T>::block_number() + T::TipCountdown::get());
|
||||
tip.closes = Some(frame_system::Pallet::<T>::block_number() + T::TipCountdown::get());
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -526,10 +545,10 @@ impl<T: Config> Module<T> {
|
||||
// same as above: best-effort only.
|
||||
let res = T::Currency::transfer(&treasury, &tip.who, payout, KeepAlive);
|
||||
debug_assert!(res.is_ok());
|
||||
Self::deposit_event(RawEvent::TipClosed(hash, tip.who, payout));
|
||||
Self::deposit_event(Event::TipClosed(hash, tip.who, payout));
|
||||
}
|
||||
|
||||
pub fn migrate_retract_tip_for_tip_new() {
|
||||
pub fn migrate_retract_tip_for_tip_new(module: &[u8], item: &[u8]) {
|
||||
/// An open tipping "motion". Retains all details of a tip including information on the
|
||||
/// finder and the members who have voted.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
|
||||
@@ -559,7 +578,7 @@ impl<T: Config> Module<T> {
|
||||
T::Hash,
|
||||
OldOpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
|
||||
Twox64Concat,
|
||||
>(b"Treasury", b"Tips")
|
||||
>(module, item)
|
||||
.drain()
|
||||
{
|
||||
let (finder, deposit, finders_fee) = match old_tip.finder {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// Version 4.
|
||||
///
|
||||
/// For backward compatability reasons, pallet-tips uses `Treasury` for storage module prefix
|
||||
/// before calling this migration. After calling this migration, it will get replaced with
|
||||
/// own storage identifier.
|
||||
pub mod v4;
|
||||
@@ -0,0 +1,195 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use sp_io::hashing::twox_128;
|
||||
use sp_std::str;
|
||||
|
||||
use frame_support::{
|
||||
storage::StoragePrefixedMap,
|
||||
traits::{
|
||||
Get, GetStorageVersion, PalletInfoAccess, StorageVersion,
|
||||
STORAGE_VERSION_STORAGE_KEY_POSTFIX,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
|
||||
use crate as pallet_tips;
|
||||
|
||||
/// Migrate the entire storage of this pallet to a new prefix.
|
||||
///
|
||||
/// This new prefix must be the same as the one set in construct_runtime.
|
||||
/// For safety, use `PalletInfo` to get it, as:
|
||||
/// `<Runtime as frame_system::Config>::PalletInfo::name::<TipsPallet>`.
|
||||
///
|
||||
/// The migration will look into the storage version in order not to trigger a migration on an up
|
||||
/// to date storage. Thus the on chain storage version must be less than 4 in order to trigger the
|
||||
/// migration.
|
||||
pub fn migrate<T: pallet_tips::Config, P: GetStorageVersion + PalletInfoAccess, N: AsRef<str>>(
|
||||
old_pallet_name: N,
|
||||
) -> Weight {
|
||||
let old_pallet_name = old_pallet_name.as_ref();
|
||||
let new_pallet_name = <P as PalletInfoAccess>::name();
|
||||
|
||||
if new_pallet_name == old_pallet_name {
|
||||
log::info!(
|
||||
target: "runtime::tips",
|
||||
"New pallet name is equal to the old prefix. No migration needs to be done.",
|
||||
);
|
||||
return 0
|
||||
}
|
||||
|
||||
let on_chain_storage_version = <P as GetStorageVersion>::on_chain_storage_version();
|
||||
log::info!(
|
||||
target: "runtime::tips",
|
||||
"Running migration to v4 for tips with storage version {:?}",
|
||||
on_chain_storage_version,
|
||||
);
|
||||
|
||||
if on_chain_storage_version < 4 {
|
||||
let storage_prefix = pallet_tips::Tips::<T>::storage_prefix();
|
||||
frame_support::storage::migration::move_storage_from_pallet(
|
||||
storage_prefix,
|
||||
old_pallet_name.as_bytes(),
|
||||
new_pallet_name.as_bytes(),
|
||||
);
|
||||
log_migration("migration", storage_prefix, old_pallet_name, new_pallet_name);
|
||||
|
||||
let storage_prefix = pallet_tips::Reasons::<T>::storage_prefix();
|
||||
frame_support::storage::migration::move_storage_from_pallet(
|
||||
storage_prefix,
|
||||
old_pallet_name.as_bytes(),
|
||||
new_pallet_name.as_bytes(),
|
||||
);
|
||||
log_migration("migration", storage_prefix, old_pallet_name, new_pallet_name);
|
||||
|
||||
StorageVersion::new(4).put::<P>();
|
||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||
} else {
|
||||
log::warn!(
|
||||
target: "runtime::tips",
|
||||
"Attempted to apply migration to v4 but failed because storage version is {:?}",
|
||||
on_chain_storage_version,
|
||||
);
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Some checks prior to migration. This can be linked to
|
||||
/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing.
|
||||
///
|
||||
/// Panics if anything goes wrong.
|
||||
pub fn pre_migrate<
|
||||
T: pallet_tips::Config,
|
||||
P: GetStorageVersion + PalletInfoAccess,
|
||||
N: AsRef<str>,
|
||||
>(
|
||||
old_pallet_name: N,
|
||||
) {
|
||||
let old_pallet_name = old_pallet_name.as_ref();
|
||||
let new_pallet_name = <P as PalletInfoAccess>::name();
|
||||
|
||||
let storage_prefix_tips = pallet_tips::Tips::<T>::storage_prefix();
|
||||
let storage_prefix_reasons = pallet_tips::Reasons::<T>::storage_prefix();
|
||||
|
||||
log_migration("pre-migration", storage_prefix_tips, old_pallet_name, new_pallet_name);
|
||||
log_migration("pre-migration", storage_prefix_reasons, old_pallet_name, new_pallet_name);
|
||||
|
||||
if new_pallet_name == old_pallet_name {
|
||||
return
|
||||
}
|
||||
|
||||
let new_pallet_prefix = twox_128(new_pallet_name.as_bytes());
|
||||
let storage_version_key = twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX);
|
||||
|
||||
let mut new_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new(
|
||||
new_pallet_prefix.to_vec(),
|
||||
new_pallet_prefix.to_vec(),
|
||||
|key| Ok(key.to_vec()),
|
||||
);
|
||||
|
||||
// Ensure nothing except the storage_version_key is stored in the new prefix.
|
||||
assert!(new_pallet_prefix_iter.all(|key| key == storage_version_key));
|
||||
|
||||
assert!(<P as GetStorageVersion>::on_chain_storage_version() < 4);
|
||||
}
|
||||
|
||||
/// Some checks for after migration. This can be linked to
|
||||
/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing.
|
||||
///
|
||||
/// Panics if anything goes wrong.
|
||||
pub fn post_migrate<
|
||||
T: pallet_tips::Config,
|
||||
P: GetStorageVersion + PalletInfoAccess,
|
||||
N: AsRef<str>,
|
||||
>(
|
||||
old_pallet_name: N,
|
||||
) {
|
||||
let old_pallet_name = old_pallet_name.as_ref();
|
||||
let new_pallet_name = <P as PalletInfoAccess>::name();
|
||||
|
||||
let storage_prefix_tips = pallet_tips::Tips::<T>::storage_prefix();
|
||||
let storage_prefix_reasons = pallet_tips::Reasons::<T>::storage_prefix();
|
||||
|
||||
log_migration("post-migration", storage_prefix_tips, old_pallet_name, new_pallet_name);
|
||||
log_migration("post-migration", storage_prefix_reasons, old_pallet_name, new_pallet_name);
|
||||
|
||||
if new_pallet_name == old_pallet_name {
|
||||
return
|
||||
}
|
||||
|
||||
// Assert that no `Tips` and `Reasons` storages remains at the old prefix.
|
||||
let old_pallet_prefix = twox_128(old_pallet_name.as_bytes());
|
||||
let old_tips_key = [&old_pallet_prefix, &twox_128(storage_prefix_tips)[..]].concat();
|
||||
let old_tips_key_iter = frame_support::storage::KeyPrefixIterator::new(
|
||||
old_tips_key.to_vec(),
|
||||
old_tips_key.to_vec(),
|
||||
|_| Ok(()),
|
||||
);
|
||||
assert_eq!(old_tips_key_iter.count(), 0);
|
||||
|
||||
let old_reasons_key = [&old_pallet_prefix, &twox_128(storage_prefix_reasons)[..]].concat();
|
||||
let old_reasons_key_iter = frame_support::storage::KeyPrefixIterator::new(
|
||||
old_reasons_key.to_vec(),
|
||||
old_reasons_key.to_vec(),
|
||||
|_| Ok(()),
|
||||
);
|
||||
assert_eq!(old_reasons_key_iter.count(), 0);
|
||||
|
||||
// Assert that the `Tips` and `Reasons` storages (if they exist) have been moved to the new
|
||||
// prefix.
|
||||
// NOTE: storage_version_key is already in the new prefix.
|
||||
let new_pallet_prefix = twox_128(new_pallet_name.as_bytes());
|
||||
let new_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new(
|
||||
new_pallet_prefix.to_vec(),
|
||||
new_pallet_prefix.to_vec(),
|
||||
|_| Ok(()),
|
||||
);
|
||||
assert!(new_pallet_prefix_iter.count() >= 1);
|
||||
|
||||
assert_eq!(<P as GetStorageVersion>::on_chain_storage_version(), 4);
|
||||
}
|
||||
|
||||
fn log_migration(stage: &str, storage_prefix: &[u8], old_pallet_name: &str, new_pallet_name: &str) {
|
||||
log::info!(
|
||||
target: "runtime::tips",
|
||||
"{} prefix of storage '{}': '{}' ==> '{}'",
|
||||
stage,
|
||||
str::from_utf8(storage_prefix).unwrap_or("<Invalid UTF8>"),
|
||||
old_pallet_name,
|
||||
new_pallet_name,
|
||||
);
|
||||
}
|
||||
@@ -19,19 +19,23 @@
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use super::*;
|
||||
use crate as tips;
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, traits::SortedMembers,
|
||||
weights::Weight, PalletId,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
traits::{BadOrigin, BlakeTwo256, IdentityLookup},
|
||||
Perbill, Permill,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use sp_storage::Storage;
|
||||
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types,
|
||||
storage::StoragePrefixedMap, traits::SortedMembers, weights::Weight, PalletId,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::{self as pallet_tips, Event as TipEvent};
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
@@ -45,7 +49,7 @@ frame_support::construct_runtime!(
|
||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>},
|
||||
TipsModTestInst: tips::{Pallet, Call, Storage, Event<T>},
|
||||
Tips: pallet_tips::{Pallet, Call, Storage, Event<T>},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -173,11 +177,11 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
t.into()
|
||||
}
|
||||
|
||||
fn last_event() -> RawEvent<u64, u128, H256> {
|
||||
fn last_event() -> TipEvent<Test> {
|
||||
System::events()
|
||||
.into_iter()
|
||||
.map(|r| r.event)
|
||||
.filter_map(|e| if let Event::TipsModTestInst(inner) = e { Some(inner) } else { None })
|
||||
.filter_map(|e| if let Event::Tips(inner) = e { Some(inner) } else { None })
|
||||
.last()
|
||||
.unwrap()
|
||||
}
|
||||
@@ -198,9 +202,9 @@ fn tip_hash() -> H256 {
|
||||
fn tip_new_cannot_be_used_twice() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
assert_noop!(
|
||||
TipsModTestInst::tip_new(Origin::signed(11), b"awesome.dot".to_vec(), 3, 10),
|
||||
Tips::tip_new(Origin::signed(11), b"awesome.dot".to_vec(), 3, 10),
|
||||
Error::<Test>::AlreadyKnown
|
||||
);
|
||||
});
|
||||
@@ -210,23 +214,23 @@ fn tip_new_cannot_be_used_twice() {
|
||||
fn report_awesome_and_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
assert_eq!(Balances::reserved_balance(0), 12);
|
||||
assert_eq!(Balances::free_balance(0), 88);
|
||||
|
||||
// other reports don't count.
|
||||
assert_noop!(
|
||||
TipsModTestInst::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3),
|
||||
Tips::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3),
|
||||
Error::<Test>::AlreadyKnown
|
||||
);
|
||||
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(TipsModTestInst::tip(Origin::signed(9), h.clone(), 10), BadOrigin);
|
||||
assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(Tips::tip(Origin::signed(9), h.clone(), 10), BadOrigin);
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(100), h.into()));
|
||||
assert_ok!(Tips::close_tip(Origin::signed(100), h.into()));
|
||||
assert_eq!(Balances::reserved_balance(0), 0);
|
||||
assert_eq!(Balances::free_balance(0), 102);
|
||||
assert_eq!(Balances::free_balance(3), 8);
|
||||
@@ -237,15 +241,15 @@ fn report_awesome_and_tip_works() {
|
||||
fn report_awesome_from_beneficiary_and_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0));
|
||||
assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0));
|
||||
assert_eq!(Balances::reserved_balance(0), 12);
|
||||
assert_eq!(Balances::free_balance(0), 88);
|
||||
let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u128));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10));
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(100), h.into()));
|
||||
assert_ok!(Tips::close_tip(Origin::signed(100), h.into()));
|
||||
assert_eq!(Balances::reserved_balance(0), 0);
|
||||
assert_eq!(Balances::free_balance(0), 110);
|
||||
});
|
||||
@@ -259,39 +263,30 @@ fn close_tip_works() {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_eq!(Treasury::pot(), 100);
|
||||
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
|
||||
let h = tip_hash();
|
||||
|
||||
assert_eq!(last_event(), RawEvent::NewTip(h));
|
||||
assert_eq!(last_event(), TipEvent::NewTip(h));
|
||||
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
|
||||
|
||||
assert_noop!(
|
||||
TipsModTestInst::close_tip(Origin::signed(0), h.into()),
|
||||
Error::<Test>::StillOpen
|
||||
);
|
||||
assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::<Test>::StillOpen);
|
||||
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10));
|
||||
|
||||
assert_eq!(last_event(), RawEvent::TipClosing(h));
|
||||
assert_eq!(last_event(), TipEvent::TipClosing(h));
|
||||
|
||||
assert_noop!(
|
||||
TipsModTestInst::close_tip(Origin::signed(0), h.into()),
|
||||
Error::<Test>::Premature
|
||||
);
|
||||
assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::<Test>::Premature);
|
||||
|
||||
System::set_block_number(2);
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::none(), h.into()), BadOrigin);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(0), h.into()));
|
||||
assert_noop!(Tips::close_tip(Origin::none(), h.into()), BadOrigin);
|
||||
assert_ok!(Tips::close_tip(Origin::signed(0), h.into()));
|
||||
assert_eq!(Balances::free_balance(3), 10);
|
||||
|
||||
assert_eq!(last_event(), RawEvent::TipClosed(h, 3, 10));
|
||||
assert_eq!(last_event(), TipEvent::TipClosed(h, 3, 10));
|
||||
|
||||
assert_noop!(
|
||||
TipsModTestInst::close_tip(Origin::signed(100), h.into()),
|
||||
Error::<Test>::UnknownTip
|
||||
);
|
||||
assert_noop!(Tips::close_tip(Origin::signed(100), h.into()), Error::<Test>::UnknownTip);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -305,20 +300,20 @@ fn slash_tip_works() {
|
||||
assert_eq!(Balances::reserved_balance(0), 0);
|
||||
assert_eq!(Balances::free_balance(0), 100);
|
||||
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
|
||||
assert_eq!(Balances::reserved_balance(0), 12);
|
||||
assert_eq!(Balances::free_balance(0), 88);
|
||||
|
||||
let h = tip_hash();
|
||||
assert_eq!(last_event(), RawEvent::NewTip(h));
|
||||
assert_eq!(last_event(), TipEvent::NewTip(h));
|
||||
|
||||
// can't remove from any origin
|
||||
assert_noop!(TipsModTestInst::slash_tip(Origin::signed(0), h.clone()), BadOrigin);
|
||||
assert_noop!(Tips::slash_tip(Origin::signed(0), h.clone()), BadOrigin);
|
||||
|
||||
// can remove from root.
|
||||
assert_ok!(TipsModTestInst::slash_tip(Origin::root(), h.clone()));
|
||||
assert_eq!(last_event(), RawEvent::TipSlashed(h, 0, 12));
|
||||
assert_ok!(Tips::slash_tip(Origin::root(), h.clone()));
|
||||
assert_eq!(last_event(), TipEvent::TipSlashed(h, 0, 12));
|
||||
|
||||
// tipper slashed
|
||||
assert_eq!(Balances::reserved_balance(0), 0);
|
||||
@@ -331,38 +326,26 @@ fn retract_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// with report awesome
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(
|
||||
TipsModTestInst::retract_tip(Origin::signed(10), h.clone()),
|
||||
Error::<Test>::NotFinder
|
||||
);
|
||||
assert_ok!(TipsModTestInst::retract_tip(Origin::signed(0), h.clone()));
|
||||
assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(Tips::retract_tip(Origin::signed(10), h.clone()), Error::<Test>::NotFinder);
|
||||
assert_ok!(Tips::retract_tip(Origin::signed(0), h.clone()));
|
||||
System::set_block_number(2);
|
||||
assert_noop!(
|
||||
TipsModTestInst::close_tip(Origin::signed(0), h.into()),
|
||||
Error::<Test>::UnknownTip
|
||||
);
|
||||
assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::<Test>::UnknownTip);
|
||||
|
||||
// with tip new
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(
|
||||
TipsModTestInst::retract_tip(Origin::signed(0), h.clone()),
|
||||
Error::<Test>::NotFinder
|
||||
);
|
||||
assert_ok!(TipsModTestInst::retract_tip(Origin::signed(10), h.clone()));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(Tips::retract_tip(Origin::signed(0), h.clone()), Error::<Test>::NotFinder);
|
||||
assert_ok!(Tips::retract_tip(Origin::signed(10), h.clone()));
|
||||
System::set_block_number(2);
|
||||
assert_noop!(
|
||||
TipsModTestInst::close_tip(Origin::signed(10), h.into()),
|
||||
Error::<Test>::UnknownTip
|
||||
);
|
||||
assert_noop!(Tips::close_tip(Origin::signed(10), h.into()), Error::<Test>::UnknownTip);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -370,12 +353,12 @@ fn retract_tip_works() {
|
||||
fn tip_median_calculation_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 0));
|
||||
assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 0));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 1000000));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 1000000));
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(0), h.into()));
|
||||
assert_ok!(Tips::close_tip(Origin::signed(0), h.into()));
|
||||
assert_eq!(Balances::free_balance(3), 10);
|
||||
});
|
||||
}
|
||||
@@ -384,25 +367,23 @@ fn tip_median_calculation_works() {
|
||||
fn tip_changing_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10000));
|
||||
assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10000));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10000));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10000));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(13), h.clone(), 0));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(14), h.clone(), 0));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 1000));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 100));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10000));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10000));
|
||||
assert_ok!(Tips::tip(Origin::signed(13), h.clone(), 0));
|
||||
assert_ok!(Tips::tip(Origin::signed(14), h.clone(), 0));
|
||||
assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 1000));
|
||||
assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 100));
|
||||
assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10));
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(0), h.into()));
|
||||
assert_ok!(Tips::close_tip(Origin::signed(0), h.into()));
|
||||
assert_eq!(Balances::free_balance(3), 10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_reward_migration() {
|
||||
use sp_storage::Storage;
|
||||
|
||||
let mut s = Storage::default();
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
|
||||
@@ -449,18 +430,20 @@ fn test_last_reward_migration() {
|
||||
};
|
||||
|
||||
let data = vec![
|
||||
(Tips::<Test>::hashed_key_for(hash1), old_tip_finder.encode().to_vec()),
|
||||
(Tips::<Test>::hashed_key_for(hash2), old_tip_no_finder.encode().to_vec()),
|
||||
(pallet_tips::Tips::<Test>::hashed_key_for(hash1), old_tip_finder.encode().to_vec()),
|
||||
(pallet_tips::Tips::<Test>::hashed_key_for(hash2), old_tip_no_finder.encode().to_vec()),
|
||||
];
|
||||
|
||||
s.top = data.into_iter().collect();
|
||||
|
||||
sp_io::TestExternalities::new(s).execute_with(|| {
|
||||
TipsModTestInst::migrate_retract_tip_for_tip_new();
|
||||
let module = pallet_tips::Tips::<Test>::module_prefix();
|
||||
let item = pallet_tips::Tips::<Test>::storage_prefix();
|
||||
Tips::migrate_retract_tip_for_tip_new(module, item);
|
||||
|
||||
// Test w/ finder
|
||||
assert_eq!(
|
||||
Tips::<Test>::get(hash1),
|
||||
pallet_tips::Tips::<Test>::get(hash1),
|
||||
Some(OpenTip {
|
||||
reason: reason1,
|
||||
who: 10,
|
||||
@@ -474,7 +457,7 @@ fn test_last_reward_migration() {
|
||||
|
||||
// Test w/o finder
|
||||
assert_eq!(
|
||||
Tips::<Test>::get(hash2),
|
||||
pallet_tips::Tips::<Test>::get(hash2),
|
||||
Some(OpenTip {
|
||||
reason: reason2,
|
||||
who: 20,
|
||||
@@ -488,6 +471,62 @@ fn test_last_reward_migration() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migration_v4() {
|
||||
let reason1 = BlakeTwo256::hash(b"reason1");
|
||||
let hash1 = BlakeTwo256::hash_of(&(reason1, 10u64));
|
||||
|
||||
let tip = OpenTip::<u128, u64, u64, H256> {
|
||||
reason: reason1,
|
||||
who: 10,
|
||||
finder: 20,
|
||||
deposit: 30,
|
||||
closes: Some(13),
|
||||
tips: vec![(40, 50), (60, 70)],
|
||||
finders_fee: true,
|
||||
};
|
||||
|
||||
let data = vec![
|
||||
(pallet_tips::Reasons::<Test>::hashed_key_for(hash1), reason1.encode().to_vec()),
|
||||
(pallet_tips::Tips::<Test>::hashed_key_for(hash1), tip.encode().to_vec()),
|
||||
];
|
||||
|
||||
let mut s = Storage::default();
|
||||
s.top = data.into_iter().collect();
|
||||
|
||||
sp_io::TestExternalities::new(s).execute_with(|| {
|
||||
use frame_support::traits::PalletInfoAccess;
|
||||
|
||||
let old_pallet = "Treasury";
|
||||
let new_pallet = <Tips as PalletInfoAccess>::name();
|
||||
frame_support::storage::migration::move_pallet(
|
||||
new_pallet.as_bytes(),
|
||||
old_pallet.as_bytes(),
|
||||
);
|
||||
StorageVersion::new(0).put::<Tips>();
|
||||
|
||||
crate::migrations::v4::pre_migrate::<Test, Tips, _>(old_pallet);
|
||||
crate::migrations::v4::migrate::<Test, Tips, _>(old_pallet);
|
||||
crate::migrations::v4::post_migrate::<Test, Tips, _>(old_pallet);
|
||||
});
|
||||
|
||||
sp_io::TestExternalities::new(Storage::default()).execute_with(|| {
|
||||
use frame_support::traits::PalletInfoAccess;
|
||||
|
||||
let old_pallet = "Treasury";
|
||||
let new_pallet = <Tips as PalletInfoAccess>::name();
|
||||
frame_support::storage::migration::move_pallet(
|
||||
new_pallet.as_bytes(),
|
||||
old_pallet.as_bytes(),
|
||||
);
|
||||
StorageVersion::new(0).put::<Tips>();
|
||||
|
||||
crate::migrations::v4::pre_migrate::<Test, Tips, _>(old_pallet);
|
||||
crate::migrations::v4::migrate::<Test, Tips, _>(old_pallet);
|
||||
crate::migrations::v4::post_migrate::<Test, Tips, _>(old_pallet);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_funding_works() {
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user