use crate::{
generic::ExtensionVersion,
traits::AsTransactionAuthorizedOrigin,
transaction_validity::{InvalidTransaction, TransactionSource},
};
use super::*;
pub trait DispatchTransaction<Call: Dispatchable> {
type Origin;
type Info;
type Result;
type Val;
type Pre;
fn validate_only(
&self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
source: TransactionSource,
extension_version: ExtensionVersion,
) -> Result<(ValidTransaction, Self::Val, Self::Origin), TransactionValidityError>;
fn validate_and_prepare(
self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
extension_version: ExtensionVersion,
) -> Result<(Self::Pre, Self::Origin), TransactionValidityError>;
fn dispatch_transaction(
self,
origin: Self::Origin,
call: Call,
info: &Self::Info,
len: usize,
extension_version: ExtensionVersion,
) -> Self::Result;
fn test_run(
self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
extension_version: ExtensionVersion,
substitute: impl FnOnce(
Self::Origin,
) -> crate::DispatchResultWithInfo<<Call as Dispatchable>::PostInfo>,
) -> Self::Result;
}
impl<T: TransactionExtension<Call>, Call: Dispatchable + Encode> DispatchTransaction<Call> for T
where
<Call as Dispatchable>::RuntimeOrigin: AsTransactionAuthorizedOrigin,
{
type Origin = <Call as Dispatchable>::RuntimeOrigin;
type Info = DispatchInfoOf<Call>;
type Result = crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Call>>;
type Val = T::Val;
type Pre = T::Pre;
fn validate_only(
&self,
origin: Self::Origin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
source: TransactionSource,
extension_version: ExtensionVersion,
) -> Result<(ValidTransaction, T::Val, Self::Origin), TransactionValidityError> {
match self.validate(
origin,
call,
info,
len,
self.implicit()?,
&(extension_version, call),
source,
) {
Ok((_, _, origin)) if !origin.is_transaction_authorized() =>
Err(InvalidTransaction::UnknownOrigin.into()),
res => res,
}
}
fn validate_and_prepare(
self,
origin: Self::Origin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
extension_version: ExtensionVersion,
) -> Result<(T::Pre, Self::Origin), TransactionValidityError> {
let (_, val, origin) = self.validate_only(
origin,
call,
info,
len,
TransactionSource::InBlock,
extension_version,
)?;
let pre = self.prepare(val, &origin, &call, info, len)?;
Ok((pre, origin))
}
fn dispatch_transaction(
self,
origin: <Call as Dispatchable>::RuntimeOrigin,
call: Call,
info: &DispatchInfoOf<Call>,
len: usize,
extension_version: ExtensionVersion,
) -> Self::Result {
let (pre, origin) =
self.validate_and_prepare(origin, &call, info, len, extension_version)?;
let mut res = call.dispatch(origin);
let pd_res = res.map(|_| ()).map_err(|e| e.error);
let post_info = match &mut res {
Ok(info) => info,
Err(err) => &mut err.post_info,
};
post_info.set_extension_weight(info);
T::post_dispatch(pre, info, post_info, len, &pd_res)?;
Ok(res)
}
fn test_run(
self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
extension_version: ExtensionVersion,
substitute: impl FnOnce(
Self::Origin,
) -> crate::DispatchResultWithInfo<<Call as Dispatchable>::PostInfo>,
) -> Self::Result {
let (pre, origin) =
self.validate_and_prepare(origin, &call, info, len, extension_version)?;
let mut res = substitute(origin);
let pd_res = res.map(|_| ()).map_err(|e| e.error);
let post_info = match &mut res {
Ok(info) => info,
Err(err) => &mut err.post_info,
};
post_info.set_extension_weight(info);
T::post_dispatch(pre, info, post_info, len, &pd_res)?;
Ok(res)
}
}