common_runtime/extensions/
check_nonce.rsuse frame_system::Config;
use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
use frame_support::{
dispatch::{DispatchInfo, Pays},
sp_runtime,
};
use scale_info::TypeInfo;
#[allow(deprecated)]
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, One, SignedExtension},
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError,
ValidTransaction,
},
};
extern crate alloc;
use alloc::vec;
#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct CheckNonce<T: Config>(#[codec(compact)] pub T::Nonce);
impl<T: Config> CheckNonce<T> {
pub fn from(nonce: T::Nonce) -> Self {
Self(nonce)
}
}
impl<T: Config> core::fmt::Debug for CheckNonce<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "CheckNonce({})", self.0)
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
Ok(())
}
}
#[allow(deprecated)]
impl<T: Config> SignedExtension for CheckNonce<T>
where
T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
{
type AccountId = T::AccountId;
type Call = T::RuntimeCall;
type AdditionalSigned = ();
type Pre = ();
const IDENTIFIER: &'static str = "CheckNonce";
fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> {
Ok(())
}
fn pre_dispatch(
self,
who: &Self::AccountId,
_call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
let mut account = frame_system::Account::<T>::get(who);
if self.0 != account.nonce {
return Err(if self.0 < account.nonce {
InvalidTransaction::Stale
} else {
InvalidTransaction::Future
}
.into());
}
let existing_account =
account.providers > 0 || account.consumers > 0 || account.sufficients > 0;
account.nonce += T::Nonce::one();
if info.pays_fee == Pays::Yes || existing_account {
frame_system::Account::<T>::insert(who, account);
}
Ok(())
}
fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let account = frame_system::Account::<T>::get(who);
if self.0 < account.nonce {
return InvalidTransaction::Stale.into();
}
let provides = vec![Encode::encode(&(who, self.0))];
let requires = if account.nonce < self.0 {
vec![Encode::encode(&(who, self.0 - One::one()))]
} else {
vec![]
};
Ok(ValidTransaction {
priority: 0,
requires,
provides,
longevity: TransactionLongevity::MAX,
propagate: true,
})
}
}