use crate::{
scale_info::{MetaType, StaticTypeInfo},
transaction_validity::{
TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction,
},
DispatchResult,
};
use codec::{Codec, Decode, Encode};
use impl_trait_for_tuples::impl_for_tuples;
#[doc(hidden)]
pub use sp_std::marker::PhantomData;
use sp_std::{self, fmt::Debug, prelude::*};
use sp_weights::Weight;
use tuplex::{PopFront, PushBack};
use super::{
DispatchInfoOf, DispatchOriginOf, Dispatchable, ExtensionPostDispatchWeightHandler,
PostDispatchInfoOf, RefundWeight,
};
mod as_transaction_extension;
mod dispatch_transaction;
#[allow(deprecated)]
pub use as_transaction_extension::AsTransactionExtension;
pub use dispatch_transaction::DispatchTransaction;
pub type ValidateResult<Val, Call> =
Result<(ValidTransaction, Val, DispatchOriginOf<Call>), TransactionValidityError>;
pub trait TransactionExtension<Call: Dispatchable>:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo
{
const IDENTIFIER: &'static str;
type Implicit: Codec + StaticTypeInfo;
fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
use crate::transaction_validity::InvalidTransaction::IndeterminateImplicit;
Ok(Self::Implicit::decode(&mut &[][..]).map_err(|_| IndeterminateImplicit)?)
}
fn metadata() -> Vec<TransactionExtensionMetadata> {
sp_std::vec![TransactionExtensionMetadata {
identifier: Self::IDENTIFIER,
ty: scale_info::meta_type::<Self>(),
implicit: scale_info::meta_type::<Self::Implicit>()
}]
}
type Val;
type Pre;
fn weight(&self, call: &Call) -> Weight;
fn validate(
&self,
origin: DispatchOriginOf<Call>,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
self_implicit: Self::Implicit,
inherited_implication: &impl Encode,
source: TransactionSource,
) -> ValidateResult<Self::Val, Call>;
fn prepare(
self,
val: Self::Val,
origin: &DispatchOriginOf<Call>,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError>;
fn post_dispatch_details(
_pre: Self::Pre,
_info: &DispatchInfoOf<Call>,
_post_info: &PostDispatchInfoOf<Call>,
_len: usize,
_result: &DispatchResult,
) -> Result<Weight, TransactionValidityError> {
Ok(Weight::zero())
}
fn post_dispatch(
pre: Self::Pre,
info: &DispatchInfoOf<Call>,
post_info: &mut PostDispatchInfoOf<Call>,
len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
let unspent_weight = Self::post_dispatch_details(pre, info, &post_info, len, result)?;
post_info.refund(unspent_weight);
Ok(())
}
fn bare_validate(
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
) -> TransactionValidity {
Ok(ValidTransaction::default())
}
fn bare_validate_and_prepare(
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
Ok(())
}
fn bare_post_dispatch(
_info: &DispatchInfoOf<Call>,
_post_info: &mut PostDispatchInfoOf<Call>,
_len: usize,
_result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
Ok(())
}
}
#[macro_export]
macro_rules! impl_tx_ext_default {
($call:ty ; , $( $rest:tt )*) => {
impl_tx_ext_default!{$call ; $( $rest )*}
};
($call:ty ; validate $( $rest:tt )*) => {
fn validate(
&self,
origin: $crate::traits::DispatchOriginOf<$call>,
_call: &$call,
_info: &$crate::traits::DispatchInfoOf<$call>,
_len: usize,
_self_implicit: Self::Implicit,
_inherited_implication: &impl $crate::codec::Encode,
_source: $crate::transaction_validity::TransactionSource,
) -> $crate::traits::ValidateResult<Self::Val, $call> {
Ok((Default::default(), Default::default(), origin))
}
impl_tx_ext_default!{$call ; $( $rest )*}
};
($call:ty ; prepare $( $rest:tt )*) => {
fn prepare(
self,
_val: Self::Val,
_origin: &$crate::traits::DispatchOriginOf<$call>,
_call: &$call,
_info: &$crate::traits::DispatchInfoOf<$call>,
_len: usize,
) -> Result<Self::Pre, $crate::transaction_validity::TransactionValidityError> {
Ok(Default::default())
}
impl_tx_ext_default!{$call ; $( $rest )*}
};
($call:ty ; weight $( $rest:tt )*) => {
fn weight(&self, _call: &$call) -> $crate::Weight {
$crate::Weight::zero()
}
impl_tx_ext_default!{$call ; $( $rest )*}
};
($call:ty ;) => {};
}
pub struct TransactionExtensionMetadata {
pub identifier: &'static str,
pub ty: MetaType,
pub implicit: MetaType,
}
#[impl_for_tuples(1, 12)]
impl<Call: Dispatchable> TransactionExtension<Call> for Tuple {
const IDENTIFIER: &'static str = "Use `metadata()`!";
for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); );
fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
Ok(for_tuples!( ( #( Tuple.implicit()? ),* ) ))
}
fn metadata() -> Vec<TransactionExtensionMetadata> {
let mut ids = Vec::new();
for_tuples!( #( ids.extend(Tuple::metadata()); )* );
ids
}
for_tuples!( type Val = ( #( Tuple::Val ),* ); );
for_tuples!( type Pre = ( #( Tuple::Pre ),* ); );
fn weight(&self, call: &Call) -> Weight {
let mut weight = Weight::zero();
for_tuples!( #( weight = weight.saturating_add(Tuple.weight(call)); )* );
weight
}
fn validate(
&self,
origin: <Call as Dispatchable>::RuntimeOrigin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
self_implicit: Self::Implicit,
inherited_implication: &impl Encode,
source: TransactionSource,
) -> Result<
(ValidTransaction, Self::Val, <Call as Dispatchable>::RuntimeOrigin),
TransactionValidityError,
> {
let valid = ValidTransaction::default();
let val = ();
let following_explicit_implications = for_tuples!( ( #( &self.Tuple ),* ) );
let following_implicit_implications = self_implicit;
for_tuples!(#(
let (_item, following_explicit_implications) = following_explicit_implications.pop_front();
let (item_implicit, following_implicit_implications) = following_implicit_implications.pop_front();
let (item_valid, item_val, origin) = {
let implications = (
inherited_implication,
&following_explicit_implications,
&following_implicit_implications,
);
Tuple.validate(origin, call, info, len, item_implicit, &implications, source)?
};
let valid = valid.combine_with(item_valid);
let val = val.push_back(item_val);
)* );
Ok((valid, val, origin))
}
fn prepare(
self,
val: Self::Val,
origin: &<Call as Dispatchable>::RuntimeOrigin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
Ok(for_tuples!( ( #(
Tuple::prepare(self.Tuple, val.Tuple, origin, call, info, len)?
),* ) ))
}
fn post_dispatch_details(
pre: Self::Pre,
info: &DispatchInfoOf<Call>,
post_info: &PostDispatchInfoOf<Call>,
len: usize,
result: &DispatchResult,
) -> Result<Weight, TransactionValidityError> {
let mut total_unspent_weight = Weight::zero();
for_tuples!( #({
let unspent_weight = Tuple::post_dispatch_details(pre.Tuple, info, post_info, len, result)?;
total_unspent_weight = total_unspent_weight.saturating_add(unspent_weight);
})* );
Ok(total_unspent_weight)
}
fn post_dispatch(
pre: Self::Pre,
info: &DispatchInfoOf<Call>,
post_info: &mut PostDispatchInfoOf<Call>,
len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, post_info, len, result)?; )* );
Ok(())
}
fn bare_validate(call: &Call, info: &DispatchInfoOf<Call>, len: usize) -> TransactionValidity {
let valid = ValidTransaction::default();
for_tuples!(#(
let item_valid = Tuple::bare_validate(call, info, len)?;
let valid = valid.combine_with(item_valid);
)* );
Ok(valid)
}
fn bare_validate_and_prepare(
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
for_tuples!( #( Tuple::bare_validate_and_prepare(call, info, len)?; )* );
Ok(())
}
fn bare_post_dispatch(
info: &DispatchInfoOf<Call>,
post_info: &mut PostDispatchInfoOf<Call>,
len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
for_tuples!( #( Tuple::bare_post_dispatch(info, post_info, len, result)?; )* );
Ok(())
}
}
impl<Call: Dispatchable> TransactionExtension<Call> for () {
const IDENTIFIER: &'static str = "UnitTransactionExtension";
type Implicit = ();
fn implicit(&self) -> sp_std::result::Result<Self::Implicit, TransactionValidityError> {
Ok(())
}
type Val = ();
type Pre = ();
fn weight(&self, _call: &Call) -> Weight {
Weight::zero()
}
fn validate(
&self,
origin: <Call as Dispatchable>::RuntimeOrigin,
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
_self_implicit: Self::Implicit,
_inherited_implication: &impl Encode,
_source: TransactionSource,
) -> Result<
(ValidTransaction, (), <Call as Dispatchable>::RuntimeOrigin),
TransactionValidityError,
> {
Ok((ValidTransaction::default(), (), origin))
}
fn prepare(
self,
_val: (),
_origin: &<Call as Dispatchable>::RuntimeOrigin,
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
Ok(())
}
}