pub use crate::v3::{Error, Result, SendError, XcmHash};
use codec::{Decode, Encode};
use core::result;
use scale_info::TypeInfo;
pub use pezsp_weights::Weight;
use super::*;
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
pub enum Outcome {
Complete { used: Weight },
Incomplete { used: Weight, error: Error },
Error { error: Error },
}
impl Outcome {
pub fn ensure_complete(self) -> Result {
match self {
Outcome::Complete { .. } => Ok(()),
Outcome::Incomplete { error, .. } => Err(error),
Outcome::Error { error, .. } => Err(error),
}
}
pub fn ensure_execution(self) -> result::Result<Weight, Error> {
match self {
Outcome::Complete { used, .. } => Ok(used),
Outcome::Incomplete { used, .. } => Ok(used),
Outcome::Error { error, .. } => Err(error),
}
}
pub fn weight_used(&self) -> Weight {
match self {
Outcome::Complete { used, .. } => *used,
Outcome::Incomplete { used, .. } => *used,
Outcome::Error { .. } => Weight::zero(),
}
}
}
impl From<Error> for Outcome {
fn from(error: Error) -> Self {
Self::Error { error }
}
}
pub trait PreparedMessage {
fn weight_of(&self) -> Weight;
}
pub trait ExecuteXcm<Call> {
type Prepared: PreparedMessage;
fn prepare(message: Xcm<Call>) -> result::Result<Self::Prepared, Xcm<Call>>;
fn execute(
origin: impl Into<Location>,
pre: Self::Prepared,
id: &mut XcmHash,
weight_credit: Weight,
) -> Outcome;
fn prepare_and_execute(
origin: impl Into<Location>,
message: Xcm<Call>,
id: &mut XcmHash,
weight_limit: Weight,
weight_credit: Weight,
) -> Outcome {
let pre = match Self::prepare(message) {
Ok(x) => x,
Err(_) => return Outcome::Error { error: Error::WeightNotComputable },
};
let xcm_weight = pre.weight_of();
if xcm_weight.any_gt(weight_limit) {
return Outcome::Error { error: Error::WeightLimitReached(xcm_weight) };
}
Self::execute(origin, pre, id, weight_credit)
}
fn charge_fees(location: impl Into<Location>, fees: Assets) -> Result;
}
pub enum Weightless {}
impl PreparedMessage for Weightless {
fn weight_of(&self) -> Weight {
unreachable!()
}
}
impl<C> ExecuteXcm<C> for () {
type Prepared = Weightless;
fn prepare(message: Xcm<C>) -> result::Result<Self::Prepared, Xcm<C>> {
Err(message)
}
fn execute(_: impl Into<Location>, _: Self::Prepared, _: &mut XcmHash, _: Weight) -> Outcome {
unreachable!()
}
fn charge_fees(_location: impl Into<Location>, _fees: Assets) -> Result {
Err(Error::Unimplemented)
}
}
pub trait Reanchorable: Sized {
type Error: Debug;
fn reanchor(
&mut self,
target: &Location,
context: &InteriorLocation,
) -> core::result::Result<(), ()>;
fn reanchored(
self,
target: &Location,
context: &InteriorLocation,
) -> core::result::Result<Self, Self::Error>;
}
pub type SendResult<T> = result::Result<(T, Assets), SendError>;
pub trait SendXcm {
type Ticket;
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket>;
fn deliver(ticket: Self::Ticket) -> result::Result<XcmHash, SendError>;
}
#[impl_trait_for_tuples::impl_for_tuples(30)]
impl SendXcm for Tuple {
for_tuples! { type Ticket = (#( Option<Tuple::Ticket> ),* ); }
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
let mut maybe_cost: Option<Assets> = None;
let one_ticket: Self::Ticket = (for_tuples! { #(
if maybe_cost.is_some() {
None
} else {
match Tuple::validate(destination, message) {
Err(SendError::NotApplicable) => None,
Err(e) => { return Err(e) },
Ok((v, c)) => {
maybe_cost = Some(c);
Some(v)
},
}
}
),* });
if let Some(cost) = maybe_cost {
Ok((one_ticket, cost))
} else {
Err(SendError::NotApplicable)
}
}
fn deliver(one_ticket: Self::Ticket) -> result::Result<XcmHash, SendError> {
for_tuples!( #(
if let Some(validated) = one_ticket.Tuple {
return Tuple::deliver(validated);
}
)* );
Err(SendError::Unroutable)
}
}
pub fn validate_send<T: SendXcm>(dest: Location, msg: Xcm<()>) -> SendResult<T::Ticket> {
T::validate(&mut Some(dest), &mut Some(msg))
}
pub fn send_xcm<T: SendXcm>(
dest: Location,
msg: Xcm<()>,
) -> result::Result<(XcmHash, Assets), SendError> {
let (ticket, price) = T::validate(&mut Some(dest), &mut Some(msg))?;
let hash = T::deliver(ticket)?;
Ok((hash, price))
}