use sp_std::{prelude::*, result, marker::PhantomData, ops::Div, fmt::Debug};
use codec::{FullCodec, Codec, Encode, Decode, EncodeLike};
use sp_core::u32_trait::Value as U32;
use sp_runtime::{
RuntimeDebug, ConsensusEngineId, DispatchResult, DispatchError, traits::{
MaybeSerializeDeserialize, AtLeast32Bit, Saturating, TrailingZeroInput, Bounded, Zero,
BadOrigin, AtLeast32BitUnsigned
},
};
use crate::dispatch::Parameter;
use crate::storage::StorageMap;
use crate::weights::Weight;
use impl_trait_for_tuples::impl_for_tuples;
#[doc(hidden)]
pub use sp_std::{mem::{swap, take}, cell::RefCell, vec::Vec, boxed::Box};
pub trait Filter<T> {
fn filter(_: &T) -> bool;
}
impl<T> Filter<T> for () {
fn filter(_: &T) -> bool { true }
}
pub trait FilterStack<T>: Filter<T> {
type Stack;
fn push(constraint: impl Fn(&T) -> bool + 'static);
fn pop();
fn take() -> Self::Stack;
fn restore(taken: Self::Stack);
}
pub struct FilterStackGuard<F: FilterStack<T>, T>(PhantomData<(F, T)>);
pub struct ClearFilterGuard<F: FilterStack<T>, T>(Option<F::Stack>, PhantomData<T>);
impl<F: FilterStack<T>, T> FilterStackGuard<F, T> {
pub fn new(constraint: impl Fn(&T) -> bool + 'static) -> Self {
F::push(constraint);
Self(PhantomData)
}
}
impl<F: FilterStack<T>, T> Drop for FilterStackGuard<F, T> {
fn drop(&mut self) {
F::pop();
}
}
impl<F: FilterStack<T>, T> ClearFilterGuard<F, T> {
pub fn new() -> Self {
Self(Some(F::take()), PhantomData)
}
}
impl<F: FilterStack<T>, T> Drop for ClearFilterGuard<F, T> {
fn drop(&mut self) {
if let Some(taken) = self.0.take() {
F::restore(taken);
}
}
}
pub trait InstanceFilter<T>: Sized + Send + Sync {
fn filter(&self, _: &T) -> bool;
fn is_superset(&self, _o: &Self) -> bool { false }
}
impl<T> InstanceFilter<T> for () {
fn filter(&self, _: &T) -> bool { true }
fn is_superset(&self, _o: &Self) -> bool { true }
}
#[macro_export]
macro_rules! impl_filter_stack {
($target:ty, $base:ty, $call:ty, $module:ident) => {
#[cfg(feature = "std")]
mod $module {
#[allow(unused_imports)]
use super::*;
use $crate::traits::{swap, take, RefCell, Vec, Box, Filter, FilterStack};
thread_local! {
static FILTER: RefCell<Vec<Box<dyn Fn(&$call) -> bool + 'static>>> = RefCell::new(Vec::new());
}
impl Filter<$call> for $target {
fn filter(call: &$call) -> bool {
<$base>::filter(call) &&
FILTER.with(|filter| filter.borrow().iter().all(|f| f(call)))
}
}
impl FilterStack<$call> for $target {
type Stack = Vec<Box<dyn Fn(&$call) -> bool + 'static>>;
fn push(f: impl Fn(&$call) -> bool + 'static) {
FILTER.with(|filter| filter.borrow_mut().push(Box::new(f)));
}
fn pop() {
FILTER.with(|filter| filter.borrow_mut().pop());
}
fn take() -> Self::Stack {
FILTER.with(|filter| take(filter.borrow_mut().as_mut()))
}
fn restore(mut s: Self::Stack) {
FILTER.with(|filter| swap(filter.borrow_mut().as_mut(), &mut s));
}
}
}
#[cfg(not(feature = "std"))]
mod $module {
#[allow(unused_imports)]
use super::*;
use $crate::traits::{swap, take, RefCell, Vec, Box, Filter, FilterStack};
struct ThisFilter(RefCell<Vec<Box<dyn Fn(&$call) -> bool + 'static>>>);
unsafe impl Send for ThisFilter {}
unsafe impl Sync for ThisFilter {}
static FILTER: ThisFilter = ThisFilter(RefCell::new(Vec::new()));
impl Filter<$call> for $target {
fn filter(call: &$call) -> bool {
<$base>::filter(call) && FILTER.0.borrow().iter().all(|f| f(call))
}
}
impl FilterStack<$call> for $target {
type Stack = Vec<Box<dyn Fn(&$call) -> bool + 'static>>;
fn push(f: impl Fn(&$call) -> bool + 'static) {
FILTER.0.borrow_mut().push(Box::new(f));
}
fn pop() {
FILTER.0.borrow_mut().pop();
}
fn take() -> Self::Stack {
take(FILTER.0.borrow_mut().as_mut())
}
fn restore(mut s: Self::Stack) {
swap(FILTER.0.borrow_mut().as_mut(), &mut s);
}
}
}
}
}
#[impl_for_tuples(30)]
pub trait IntegrityTest {
fn integrity_test() {}
}
#[cfg(test)]
mod test_impl_filter_stack {
use super::*;
pub struct IsCallable;
pub struct BaseFilter;
impl Filter<u32> for BaseFilter {
fn filter(x: &u32) -> bool { x % 2 == 0 }
}
impl_filter_stack!(
crate::traits::test_impl_filter_stack::IsCallable,
crate::traits::test_impl_filter_stack::BaseFilter,
u32,
is_callable
);
#[test]
fn impl_filter_stack_should_work() {
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(IsCallable::filter(&42));
assert!(!IsCallable::filter(&43));
IsCallable::push(|x| *x < 42);
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(!IsCallable::filter(&42));
IsCallable::push(|x| *x % 3 == 0);
assert!(IsCallable::filter(&36));
assert!(!IsCallable::filter(&40));
IsCallable::pop();
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(!IsCallable::filter(&42));
let saved = IsCallable::take();
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(IsCallable::filter(&42));
assert!(!IsCallable::filter(&43));
IsCallable::restore(saved);
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(!IsCallable::filter(&42));
IsCallable::pop();
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(IsCallable::filter(&42));
assert!(!IsCallable::filter(&43));
}
#[test]
fn guards_should_work() {
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(IsCallable::filter(&42));
assert!(!IsCallable::filter(&43));
{
let _guard_1 = FilterStackGuard::<IsCallable, u32>::new(|x| *x < 42);
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(!IsCallable::filter(&42));
{
let _guard_2 = FilterStackGuard::<IsCallable, u32>::new(|x| *x % 3 == 0);
assert!(IsCallable::filter(&36));
assert!(!IsCallable::filter(&40));
}
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(!IsCallable::filter(&42));
{
let _guard_2 = ClearFilterGuard::<IsCallable, u32>::new();
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(IsCallable::filter(&42));
assert!(!IsCallable::filter(&43));
}
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(!IsCallable::filter(&42));
}
assert!(IsCallable::filter(&36));
assert!(IsCallable::filter(&40));
assert!(IsCallable::filter(&42));
assert!(!IsCallable::filter(&43));
}
}
pub trait StoredMap<K, T> {
fn get(k: &K) -> T;
fn is_explicit(k: &K) -> bool;
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> R;
fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> R;
fn try_mutate_exists<R, E>(k: &K, f: impl FnOnce(&mut Option<T>) -> Result<R, E>) -> Result<R, E>;
fn insert(k: &K, t: T) { Self::mutate(k, |i| *i = t); }
fn remove(k: &K);
}
pub trait Happened<T> {
fn happened(t: &T);
}
impl<T> Happened<T> for () {
fn happened(_: &T) {}
}
pub struct StorageMapShim<
S,
Created,
Removed,
K,
T
>(sp_std::marker::PhantomData<(S, Created, Removed, K, T)>);
impl<
S: StorageMap<K, T, Query=T>,
Created: Happened<K>,
Removed: Happened<K>,
K: FullCodec,
T: FullCodec,
> StoredMap<K, T> for StorageMapShim<S, Created, Removed, K, T> {
fn get(k: &K) -> T { S::get(k) }
fn is_explicit(k: &K) -> bool { S::contains_key(k) }
fn insert(k: &K, t: T) {
let existed = S::contains_key(&k);
S::insert(k, t);
if !existed {
Created::happened(k);
}
}
fn remove(k: &K) {
let existed = S::contains_key(&k);
S::remove(k);
if existed {
Removed::happened(&k);
}
}
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> R {
let existed = S::contains_key(&k);
let r = S::mutate(k, f);
if !existed {
Created::happened(k);
}
r
}
fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> R {
let (existed, exists, r) = S::mutate_exists(k, |maybe_value| {
let existed = maybe_value.is_some();
let r = f(maybe_value);
(existed, maybe_value.is_some(), r)
});
if !existed && exists {
Created::happened(k);
} else if existed && !exists {
Removed::happened(k);
}
r
}
fn try_mutate_exists<R, E>(k: &K, f: impl FnOnce(&mut Option<T>) -> Result<R, E>) -> Result<R, E> {
S::try_mutate_exists(k, |maybe_value| {
let existed = maybe_value.is_some();
f(maybe_value).map(|v| (existed, maybe_value.is_some(), v))
}).map(|(existed, exists, v)| {
if !existed && exists {
Created::happened(k);
} else if existed && !exists {
Removed::happened(k);
}
v
})
}
}
pub trait EstimateNextSessionRotation<BlockNumber> {
fn estimate_next_session_rotation(now: BlockNumber) -> Option<BlockNumber>;
fn weight(now: BlockNumber) -> Weight;
}
impl<BlockNumber: Bounded> EstimateNextSessionRotation<BlockNumber> for () {
fn estimate_next_session_rotation(_: BlockNumber) -> Option<BlockNumber> {
Default::default()
}
fn weight(_: BlockNumber) -> Weight {
0
}
}
pub trait EstimateNextNewSession<BlockNumber> {
fn estimate_next_new_session(now: BlockNumber) -> Option<BlockNumber>;
fn weight(now: BlockNumber) -> Weight;
}
impl<BlockNumber: Bounded> EstimateNextNewSession<BlockNumber> for () {
fn estimate_next_new_session(_: BlockNumber) -> Option<BlockNumber> {
Default::default()
}
fn weight(_: BlockNumber) -> Weight {
0
}
}
pub trait Len {
fn len(&self) -> usize;
}
impl<T: IntoIterator + Clone,> Len for T where <T as IntoIterator>::IntoIter: ExactSizeIterator {
fn len(&self) -> usize {
self.clone().into_iter().len()
}
}
pub trait Get<T> {
fn get() -> T;
}
impl<T: Default> Get<T> for () {
fn get() -> T { T::default() }
}
pub trait Contains<T: Ord> {
fn contains(t: &T) -> bool { Self::sorted_members().binary_search(t).is_ok() }
fn sorted_members() -> Vec<T>;
fn count() -> usize { Self::sorted_members().len() }
#[cfg(feature = "runtime-benchmarks")]
fn add(_t: &T) { unimplemented!() }
}
pub trait ContainsLengthBound {
fn min_len() -> usize;
fn max_len() -> usize;
}
pub trait IsDeadAccount<AccountId> {
fn is_dead_account(who: &AccountId) -> bool;
}
impl<AccountId> IsDeadAccount<AccountId> for () {
fn is_dead_account(_who: &AccountId) -> bool {
true
}
}
#[impl_for_tuples(30)]
pub trait OnNewAccount<AccountId> {
fn on_new_account(who: &AccountId);
}
#[impl_for_tuples(30)]
pub trait OnKilledAccount<AccountId> {
fn on_killed_account(who: &AccountId);
}
pub trait FindAuthor<Author> {
fn find_author<'a, I>(digests: I) -> Option<Author>
where I: 'a + IntoIterator<Item=(ConsensusEngineId, &'a [u8])>;
}
impl<A> FindAuthor<A> for () {
fn find_author<'a, I>(_: I) -> Option<A>
where I: 'a + IntoIterator<Item=(ConsensusEngineId, &'a [u8])>
{
None
}
}
pub trait VerifySeal<Header, Author> {
fn verify_seal(header: &Header) -> Result<Option<Author>, &'static str>;
}
pub trait KeyOwnerProofSystem<Key> {
type Proof: Codec;
type IdentificationTuple: Codec;
fn prove(key: Key) -> Option<Self::Proof>;
fn check_proof(key: Key, proof: Self::Proof) -> Option<Self::IdentificationTuple>;
}
impl<Key> KeyOwnerProofSystem<Key> for () {
type Proof = crate::Void;
type IdentificationTuple = crate::Void;
fn prove(_key: Key) -> Option<Self::Proof> {
None
}
fn check_proof(_key: Key, _proof: Self::Proof) -> Option<Self::IdentificationTuple> {
None
}
}
pub trait OnUnbalanced<Imbalance: TryDrop> {
fn on_unbalanceds<B>(amounts: impl Iterator<Item=Imbalance>) where Imbalance: crate::traits::Imbalance<B> {
Self::on_unbalanced(amounts.fold(Imbalance::zero(), |i, x| x.merge(i)))
}
fn on_unbalanced(amount: Imbalance) {
amount.try_drop().unwrap_or_else(Self::on_nonzero_unbalanced)
}
fn on_nonzero_unbalanced(amount: Imbalance) { drop(amount); }
}
impl<Imbalance: TryDrop> OnUnbalanced<Imbalance> for () {}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum ExistenceRequirement {
KeepAlive,
AllowDeath,
}
pub trait TryDrop: Sized {
fn try_drop(self) -> Result<(), Self>;
}
#[must_use]
pub trait Imbalance<Balance>: Sized + TryDrop {
type Opposite: Imbalance<Balance>;
fn zero() -> Self;
fn drop_zero(self) -> Result<(), Self>;
fn split(self, amount: Balance) -> (Self, Self);
fn ration(self, first: u32, second: u32) -> (Self, Self)
where Balance: From<u32> + Saturating + Div<Output=Balance>
{
let total: u32 = first.saturating_add(second);
let amount1 = self.peek().saturating_mul(first.into()) / total.into();
self.split(amount1)
}
fn split_merge(self, amount: Balance, others: (Self, Self)) -> (Self, Self) {
let (a, b) = self.split(amount);
(a.merge(others.0), b.merge(others.1))
}
fn ration_merge(self, first: u32, second: u32, others: (Self, Self)) -> (Self, Self)
where Balance: From<u32> + Saturating + Div<Output=Balance>
{
let (a, b) = self.ration(first, second);
(a.merge(others.0), b.merge(others.1))
}
fn split_merge_into(self, amount: Balance, others: &mut (Self, Self)) {
let (a, b) = self.split(amount);
others.0.subsume(a);
others.1.subsume(b);
}
fn ration_merge_into(self, first: u32, second: u32, others: &mut (Self, Self))
where Balance: From<u32> + Saturating + Div<Output=Balance>
{
let (a, b) = self.ration(first, second);
others.0.subsume(a);
others.1.subsume(b);
}
fn merge(self, other: Self) -> Self;
fn merge_into(self, other: &mut Self) {
other.subsume(self)
}
fn maybe_merge(self, other: Option<Self>) -> Self {
if let Some(o) = other {
self.merge(o)
} else {
self
}
}
fn subsume(&mut self, other: Self);
fn maybe_subsume(&mut self, other: Option<Self>) {
if let Some(o) = other {
self.subsume(o)
}
}
fn offset(self, other: Self::Opposite) -> Result<Self, Self::Opposite>;
fn peek(&self) -> Balance;
}
pub enum SignedImbalance<B, P: Imbalance<B>>{
Positive(P),
Negative(P::Opposite),
}
impl<
P: Imbalance<B, Opposite=N>,
N: Imbalance<B, Opposite=P>,
B: AtLeast32BitUnsigned + FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default,
> SignedImbalance<B, P> {
pub fn zero() -> Self {
SignedImbalance::Positive(P::zero())
}
pub fn drop_zero(self) -> Result<(), Self> {
match self {
SignedImbalance::Positive(x) => x.drop_zero().map_err(SignedImbalance::Positive),
SignedImbalance::Negative(x) => x.drop_zero().map_err(SignedImbalance::Negative),
}
}
pub fn merge(self, other: Self) -> Self {
match (self, other) {
(SignedImbalance::Positive(one), SignedImbalance::Positive(other)) =>
SignedImbalance::Positive(one.merge(other)),
(SignedImbalance::Negative(one), SignedImbalance::Negative(other)) =>
SignedImbalance::Negative(one.merge(other)),
(SignedImbalance::Positive(one), SignedImbalance::Negative(other)) =>
if one.peek() > other.peek() {
SignedImbalance::Positive(one.offset(other).ok().unwrap_or_else(P::zero))
} else {
SignedImbalance::Negative(other.offset(one).ok().unwrap_or_else(N::zero))
},
(one, other) => other.merge(one),
}
}
}
pub struct SplitTwoWays<
Balance,
Imbalance,
Part1,
Target1,
Part2,
Target2,
>(PhantomData<(Balance, Imbalance, Part1, Target1, Part2, Target2)>);
impl<
Balance: From<u32> + Saturating + Div<Output=Balance>,
I: Imbalance<Balance>,
Part1: U32,
Target1: OnUnbalanced<I>,
Part2: U32,
Target2: OnUnbalanced<I>,
> OnUnbalanced<I> for SplitTwoWays<Balance, I, Part1, Target1, Part2, Target2>
{
fn on_nonzero_unbalanced(amount: I) {
let total: u32 = Part1::VALUE + Part2::VALUE;
let amount1 = amount.peek().saturating_mul(Part1::VALUE.into()) / total.into();
let (imb1, imb2) = amount.split(amount1);
Target1::on_unbalanced(imb1);
Target2::on_unbalanced(imb2);
}
}
pub trait Currency<AccountId> {
type Balance: AtLeast32BitUnsigned + FullCodec + Copy + MaybeSerializeDeserialize + Debug +
Default;
type PositiveImbalance: Imbalance<Self::Balance, Opposite=Self::NegativeImbalance>;
type NegativeImbalance: Imbalance<Self::Balance, Opposite=Self::PositiveImbalance>;
fn total_balance(who: &AccountId) -> Self::Balance;
fn can_slash(who: &AccountId, value: Self::Balance) -> bool;
fn total_issuance() -> Self::Balance;
fn minimum_balance() -> Self::Balance;
fn burn(amount: Self::Balance) -> Self::PositiveImbalance;
fn issue(amount: Self::Balance) -> Self::NegativeImbalance;
fn pair(amount: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) {
(Self::burn(amount.clone()), Self::issue(amount))
}
fn free_balance(who: &AccountId) -> Self::Balance;
fn ensure_can_withdraw(
who: &AccountId,
_amount: Self::Balance,
reasons: WithdrawReasons,
new_balance: Self::Balance,
) -> DispatchResult;
fn transfer(
source: &AccountId,
dest: &AccountId,
value: Self::Balance,
existence_requirement: ExistenceRequirement,
) -> DispatchResult;
fn slash(
who: &AccountId,
value: Self::Balance
) -> (Self::NegativeImbalance, Self::Balance);
fn deposit_into_existing(
who: &AccountId,
value: Self::Balance
) -> result::Result<Self::PositiveImbalance, DispatchError>;
fn resolve_into_existing(
who: &AccountId,
value: Self::NegativeImbalance,
) -> result::Result<(), Self::NegativeImbalance> {
let v = value.peek();
match Self::deposit_into_existing(who, v) {
Ok(opposite) => Ok(drop(value.offset(opposite))),
_ => Err(value),
}
}
fn deposit_creating(
who: &AccountId,
value: Self::Balance,
) -> Self::PositiveImbalance;
fn resolve_creating(
who: &AccountId,
value: Self::NegativeImbalance,
) {
let v = value.peek();
drop(value.offset(Self::deposit_creating(who, v)));
}
fn withdraw(
who: &AccountId,
value: Self::Balance,
reasons: WithdrawReasons,
liveness: ExistenceRequirement,
) -> result::Result<Self::NegativeImbalance, DispatchError>;
fn settle(
who: &AccountId,
value: Self::PositiveImbalance,
reasons: WithdrawReasons,
liveness: ExistenceRequirement,
) -> result::Result<(), Self::PositiveImbalance> {
let v = value.peek();
match Self::withdraw(who, v, reasons, liveness) {
Ok(opposite) => Ok(drop(value.offset(opposite))),
_ => Err(value),
}
}
fn make_free_balance_be(
who: &AccountId,
balance: Self::Balance,
) -> SignedImbalance<Self::Balance, Self::PositiveImbalance>;
}
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)]
pub enum BalanceStatus {
Free,
Reserved,
}
pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
fn can_reserve(who: &AccountId, value: Self::Balance) -> bool;
fn slash_reserved(
who: &AccountId,
value: Self::Balance
) -> (Self::NegativeImbalance, Self::Balance);
fn reserved_balance(who: &AccountId) -> Self::Balance;
fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult;
fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance;
fn repatriate_reserved(
slashed: &AccountId,
beneficiary: &AccountId,
value: Self::Balance,
status: BalanceStatus,
) -> result::Result<Self::Balance, DispatchError>;
}
pub type LockIdentifier = [u8; 8];
pub trait LockableCurrency<AccountId>: Currency<AccountId> {
type Moment;
type MaxLocks: Get<u32>;
fn set_lock(
id: LockIdentifier,
who: &AccountId,
amount: Self::Balance,
reasons: WithdrawReasons,
);
fn extend_lock(
id: LockIdentifier,
who: &AccountId,
amount: Self::Balance,
reasons: WithdrawReasons,
);
fn remove_lock(
id: LockIdentifier,
who: &AccountId,
);
}
pub trait VestingSchedule<AccountId> {
type Moment;
type Currency: Currency<AccountId>;
fn vesting_balance(who: &AccountId) -> Option<<Self::Currency as Currency<AccountId>>::Balance>;
fn add_vesting_schedule(
who: &AccountId,
locked: <Self::Currency as Currency<AccountId>>::Balance,
per_block: <Self::Currency as Currency<AccountId>>::Balance,
starting_block: Self::Moment,
) -> DispatchResult;
fn remove_vesting_schedule(who: &AccountId);
}
bitmask! {
#[derive(Encode, Decode)]
pub mask WithdrawReasons: i8 where
#[derive(Encode, Decode)]
flags WithdrawReason {
TransactionPayment = 0b00000001,
Transfer = 0b00000010,
Reserve = 0b00000100,
Fee = 0b00001000,
Tip = 0b00010000,
}
}
pub trait Time {
type Moment: AtLeast32Bit + Parameter + Default + Copy;
fn now() -> Self::Moment;
}
pub trait UnixTime {
fn now() -> core::time::Duration;
}
impl WithdrawReasons {
pub fn except(one: WithdrawReason) -> WithdrawReasons {
let mut mask = Self::all();
mask.toggle(one);
mask
}
}
pub trait ChangeMembers<AccountId: Clone + Ord> {
fn change_members(incoming: &[AccountId], outgoing: &[AccountId], mut new: Vec<AccountId>) {
new.sort();
Self::change_members_sorted(incoming, outgoing, &new[..]);
}
fn change_members_sorted(
incoming: &[AccountId],
outgoing: &[AccountId],
sorted_new: &[AccountId],
);
fn set_members_sorted(new_members: &[AccountId], old_members: &[AccountId]) {
let (incoming, outgoing) = Self::compute_members_diff(new_members, old_members);
Self::change_members_sorted(&incoming[..], &outgoing[..], &new_members);
}
fn compute_members_diff(
new_members: &[AccountId],
old_members: &[AccountId]
) -> (Vec<AccountId>, Vec<AccountId>) {
let mut old_iter = old_members.iter();
let mut new_iter = new_members.iter();
let mut incoming = Vec::new();
let mut outgoing = Vec::new();
let mut old_i = old_iter.next();
let mut new_i = new_iter.next();
loop {
match (old_i, new_i) {
(None, None) => break,
(Some(old), Some(new)) if old == new => {
old_i = old_iter.next();
new_i = new_iter.next();
}
(Some(old), Some(new)) if old < new => {
outgoing.push(old.clone());
old_i = old_iter.next();
}
(Some(old), None) => {
outgoing.push(old.clone());
old_i = old_iter.next();
}
(_, Some(new)) => {
incoming.push(new.clone());
new_i = new_iter.next();
}
}
}
(incoming, outgoing)
}
fn set_prime(_prime: Option<AccountId>) {}
}
impl<T: Clone + Ord> ChangeMembers<T> for () {
fn change_members(_: &[T], _: &[T], _: Vec<T>) {}
fn change_members_sorted(_: &[T], _: &[T], _: &[T]) {}
fn set_members_sorted(_: &[T], _: &[T]) {}
fn set_prime(_: Option<T>) {}
}
pub trait InitializeMembers<AccountId> {
fn initialize_members(members: &[AccountId]);
}
impl<T> InitializeMembers<T> for () {
fn initialize_members(_: &[T]) {}
}
pub trait Randomness<Output> {
fn random(subject: &[u8]) -> Output;
fn random_seed() -> Output {
Self::random(&[][..])
}
}
pub struct TestRandomness;
impl<Output: Decode + Default> Randomness<Output> for TestRandomness {
fn random(subject: &[u8]) -> Output {
Output::decode(&mut TrailingZeroInput::new(subject)).unwrap_or_default()
}
}
pub trait Lateness<N> {
fn lateness(&self) -> N;
}
impl<N: Zero> Lateness<N> for () {
fn lateness(&self) -> N {
Zero::zero()
}
}
pub trait ValidatorRegistration<ValidatorId> {
fn is_registered(id: &ValidatorId) -> bool;
}
pub trait PalletInfo {
fn index<P: 'static>() -> Option<usize>;
fn name<P: 'static>() -> Option<&'static str>;
}
impl PalletInfo for () {
fn index<P: 'static>() -> Option<usize> { Some(0) }
fn name<P: 'static>() -> Option<&'static str> { Some("test") }
}
#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug)]
pub struct CallMetadata {
pub function_name: &'static str,
pub pallet_name: &'static str,
}
pub trait GetCallName {
fn get_call_names() -> &'static [&'static str];
fn get_call_name(&self) -> &'static str;
}
pub trait GetCallMetadata {
fn get_module_names() -> &'static [&'static str];
fn get_call_names(module: &str) -> &'static [&'static str];
fn get_call_metadata(&self) -> CallMetadata;
}
#[impl_for_tuples(30)]
pub trait OnFinalize<BlockNumber> {
fn on_finalize(_n: BlockNumber) {}
}
pub trait OnInitialize<BlockNumber> {
fn on_initialize(_n: BlockNumber) -> crate::weights::Weight { 0 }
}
#[impl_for_tuples(30)]
impl<BlockNumber: Clone> OnInitialize<BlockNumber> for Tuple {
fn on_initialize(_n: BlockNumber) -> crate::weights::Weight {
let mut weight = 0;
for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(_n.clone())); )* );
weight
}
}
pub trait OnRuntimeUpgrade {
fn on_runtime_upgrade() -> crate::weights::Weight { 0 }
}
#[impl_for_tuples(30)]
impl OnRuntimeUpgrade for Tuple {
fn on_runtime_upgrade() -> crate::weights::Weight {
let mut weight = 0;
for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* );
weight
}
}
#[impl_for_tuples(30)]
pub trait OffchainWorker<BlockNumber> {
fn offchain_worker(_n: BlockNumber) {}
}
pub mod schedule {
use super::*;
pub type Period<BlockNumber> = (BlockNumber, u32);
pub type Priority = u8;
#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)]
pub enum DispatchTime<BlockNumber> {
At(BlockNumber),
After(BlockNumber),
}
pub const HIGHEST_PRIORITY: Priority = 0;
pub const HARD_DEADLINE: Priority = 63;
pub const LOWEST_PRIORITY: Priority = 255;
pub trait Anon<BlockNumber, Call, Origin> {
type Address: Codec + Clone + Eq + EncodeLike + Debug;
fn schedule(
when: DispatchTime<BlockNumber>,
maybe_periodic: Option<Period<BlockNumber>>,
priority: Priority,
origin: Origin,
call: Call
) -> Result<Self::Address, DispatchError>;
fn cancel(address: Self::Address) -> Result<(), ()>;
}
pub trait Named<BlockNumber, Call, Origin> {
type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug;
fn schedule_named(
id: Vec<u8>,
when: DispatchTime<BlockNumber>,
maybe_periodic: Option<Period<BlockNumber>>,
priority: Priority,
origin: Origin,
call: Call
) -> Result<Self::Address, ()>;
fn cancel_named(id: Vec<u8>) -> Result<(), ()>;
}
}
pub trait EnsureOrigin<OuterOrigin> {
type Success;
fn ensure_origin(o: OuterOrigin) -> result::Result<Self::Success, BadOrigin> {
Self::try_origin(o).map_err(|_| BadOrigin)
}
fn try_origin(o: OuterOrigin) -> result::Result<Self::Success, OuterOrigin>;
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OuterOrigin;
}
pub trait UnfilteredDispatchable {
type Origin;
fn dispatch_bypass_filter(self, origin: Self::Origin) -> crate::dispatch::DispatchResultWithPostInfo;
}
pub trait OriginTrait: Sized {
type Call;
type PalletsOrigin;
fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static);
fn reset_filter(&mut self);
fn set_caller_from(&mut self, other: impl Into<Self>);
fn filter_call(&self, call: &Self::Call) -> bool;
fn caller(&self) -> &Self::PalletsOrigin;
}
pub trait IsType<T>: Into<T> + From<T> {
fn from_ref(t: &T) -> &Self;
fn into_ref(&self) -> &T;
fn from_mut(t: &mut T) -> &mut Self;
fn into_mut(&mut self) -> &mut T;
}
impl<T> IsType<T> for T {
fn from_ref(t: &T) -> &Self { t }
fn into_ref(&self) -> &T { self }
fn from_mut(t: &mut T) -> &mut Self { t }
fn into_mut(&mut self) -> &mut T { self }
}
pub trait Instance: 'static {
const PREFIX: &'static str ;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn on_initialize_and_on_runtime_upgrade_weight_merge_works() {
struct Test;
impl OnInitialize<u8> for Test {
fn on_initialize(_n: u8) -> crate::weights::Weight {
10
}
}
impl OnRuntimeUpgrade for Test {
fn on_runtime_upgrade() -> crate::weights::Weight {
20
}
}
assert_eq!(<(Test, Test)>::on_initialize(0), 20);
assert_eq!(<(Test, Test)>::on_runtime_upgrade(), 40);
}
}