use super::mock::*;
use crate::{universal_exports::*, WithTopicSource};
use pezframe_support::{parameter_types, traits::Get};
use std::{cell::RefCell, marker::PhantomData};
use xcm::AlwaysLatest;
use xcm_executor::{
traits::{export_xcm, validate_export},
XcmExecutor,
};
use SendError::*;
mod local_para_para;
mod local_relay_relay;
mod paid_remote_relay_relay;
mod remote_para_para;
mod remote_para_para_via_relay;
mod remote_relay_relay;
mod universal_exports;
parameter_types! {
pub Local: NetworkId = ByGenesis([0; 32]);
pub Remote: NetworkId = ByGenesis([1; 32]);
pub Price: Assets = Assets::from((Here, 100u128));
pub static UsingTopic: bool = false;
}
std::thread_local! {
static BRIDGE_TRAFFIC: RefCell<Vec<Vec<u8>>> = RefCell::new(Vec::new());
}
fn maybe_with_topic(f: impl Fn()) {
UsingTopic::set(false);
f();
UsingTopic::set(true);
f();
}
fn xcm_with_topic<T>(topic: XcmHash, mut xcm: Vec<Instruction<T>>) -> Xcm<T> {
if UsingTopic::get() {
xcm.push(SetTopic(topic));
}
Xcm(xcm)
}
fn fake_id() -> XcmHash {
[255; 32]
}
fn test_weight(mut count: u64) -> Weight {
if UsingTopic::get() {
count += 1;
}
Weight::from_parts(count * 10, count * 10)
}
fn maybe_forward_id_for(topic: &XcmHash) -> XcmHash {
match UsingTopic::get() {
true => *topic,
false => fake_id(),
}
}
enum TestTicket<T: SendXcm> {
Basic(T::Ticket),
Topic(<WithTopicSource<T, ()> as SendXcm>::Ticket),
}
struct TestTopic<R>(PhantomData<R>);
impl<R: SendXcm> SendXcm for TestTopic<R> {
type Ticket = TestTicket<R>;
fn deliver(ticket: Self::Ticket) -> core::result::Result<XcmHash, SendError> {
match ticket {
TestTicket::Basic(t) => R::deliver(t),
TestTicket::Topic(t) => WithTopicSource::<R, ()>::deliver(t),
}
}
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
Ok(if UsingTopic::get() {
let (t, a) = WithTopicSource::<R, ()>::validate(destination, message)?;
(TestTicket::Topic(t), a)
} else {
let (t, a) = R::validate(destination, message)?;
(TestTicket::Basic(t), a)
})
}
}
struct TestBridge<D>(PhantomData<D>);
impl<D: DispatchBlob> TestBridge<D> {
fn service() -> u64 {
BRIDGE_TRAFFIC
.with(|t| t.borrow_mut().drain(..).map(|b| D::dispatch_blob(b).map_or(0, |()| 1)).sum())
}
}
impl<D: DispatchBlob> HaulBlob for TestBridge<D> {
fn haul_blob(blob: Vec<u8>) -> Result<(), HaulBlobError> {
BRIDGE_TRAFFIC.with(|t| t.borrow_mut().push(blob));
Ok(())
}
}
std::thread_local! {
static REMOTE_INCOMING_XCM: RefCell<Vec<(Location, Xcm<()>)>> = RefCell::new(Vec::new());
}
struct TestRemoteIncomingRouter;
impl SendXcm for TestRemoteIncomingRouter {
type Ticket = (Location, Xcm<()>);
fn validate(
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<(Location, Xcm<()>)> {
let pair = (dest.take().unwrap(), msg.take().unwrap());
Ok((pair, Assets::new()))
}
fn deliver(pair: (Location, Xcm<()>)) -> Result<XcmHash, SendError> {
let hash = fake_id();
REMOTE_INCOMING_XCM.with(|q| q.borrow_mut().push(pair));
Ok(hash)
}
}
fn take_received_remote_messages() -> Vec<(Location, Xcm<()>)> {
REMOTE_INCOMING_XCM.with(|r| r.replace(vec![]))
}
struct UnpaidExecutingRouter<Local, Remote, RemoteExporter>(
PhantomData<(Local, Remote, RemoteExporter)>,
);
fn price<RemoteExporter: ExportXcm>(
n: NetworkId,
c: u32,
s: &InteriorLocation,
d: &InteriorLocation,
m: &Xcm<()>,
) -> Result<Assets, SendError> {
Ok(validate_export::<RemoteExporter>(n, c, s.clone(), d.clone(), m.clone())?.1)
}
fn deliver<RemoteExporter: ExportXcm>(
n: NetworkId,
c: u32,
s: InteriorLocation,
d: InteriorLocation,
m: Xcm<()>,
) -> Result<XcmHash, SendError> {
export_xcm::<RemoteExporter>(n, c, s, d, m).map(|(hash, _)| hash)
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct LogEntry {
local: Junctions,
remote: Junctions,
id: XcmHash,
message: Xcm<()>,
outcome: Outcome,
paid: bool,
}
parameter_types! {
pub static RoutingLog: Vec<LogEntry> = vec![];
}
impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> SendXcm
for UnpaidExecutingRouter<Local, Remote, RemoteExporter>
{
type Ticket = Xcm<()>;
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Xcm<()>> {
let expect_dest = Remote::get().relative_to(&Local::get());
if destination.as_ref().ok_or(MissingArgument)? != &expect_dest {
return Err(NotApplicable);
}
let message = message.take().ok_or(MissingArgument)?;
Ok((message, Assets::new()))
}
fn deliver(message: Xcm<()>) -> Result<XcmHash, SendError> {
ExecutorUniversalLocation::set(Remote::get());
let origin = Local::get().relative_to(&Remote::get());
AllowUnpaidFrom::set(vec![origin.clone()]);
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
let mut id = fake_id();
let outcome = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message.clone().into(),
&mut id,
Weight::from_parts(2_000_000_000_000, 2_000_000_000_000),
Weight::zero(),
);
let local = Local::get();
let remote = Remote::get();
let entry = LogEntry { local, remote, id, message, outcome: outcome.clone(), paid: false };
RoutingLog::mutate(|l| l.push(entry));
match outcome {
Outcome::Complete { .. } => Ok(id),
Outcome::Incomplete { .. } => Err(Transport("Error executing")),
Outcome::Error(_) => Err(Transport("Unable to execute")),
}
}
}
struct ExecutingRouter<Local, Remote, RemoteExporter>(PhantomData<(Local, Remote, RemoteExporter)>);
impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> SendXcm
for ExecutingRouter<Local, Remote, RemoteExporter>
{
type Ticket = Xcm<()>;
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Xcm<()>> {
let expect_dest = Remote::get().relative_to(&Local::get());
if destination.as_ref().ok_or(MissingArgument)? != &expect_dest {
return Err(NotApplicable);
}
let message = message.take().ok_or(MissingArgument)?;
Ok((message, Assets::new()))
}
fn deliver(message: Xcm<()>) -> Result<XcmHash, SendError> {
ExecutorUniversalLocation::set(Remote::get());
let origin = Local::get().relative_to(&Remote::get());
AllowPaidFrom::set(vec![origin.clone()]);
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
let mut id = fake_id();
let outcome = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message.clone().into(),
&mut id,
Weight::from_parts(2_000_000_000_000, 2_000_000_000_000),
Weight::zero(),
);
let local = Local::get();
let remote = Remote::get();
let entry = LogEntry { local, remote, id, message, outcome: outcome.clone(), paid: true };
RoutingLog::mutate(|l| l.push(entry));
match outcome {
Outcome::Complete { .. } => Ok(id),
Outcome::Incomplete { .. } => Err(Transport("Error executing")),
Outcome::Error(_) => Err(Transport("Unable to execute")),
}
}
}