feat: initialize Kurdistan SDK - independent fork of Polkadot SDK
This commit is contained in:
@@ -0,0 +1,281 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Pezkuwi is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Tests specific to the bridging primitives
|
||||
|
||||
use super::mock::*;
|
||||
use crate::{universal_exports::*, WithTopicSource};
|
||||
use frame_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![]))
|
||||
}
|
||||
|
||||
/// This is a dummy router which accepts messages destined for `Remote` from `Local`
|
||||
/// and then executes them for free in a context simulated to be like that of our `Remote`.
|
||||
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> {
|
||||
// We now pretend that the message was delivered from `Local` to `Remote`, and execute
|
||||
// so we need to ensure that the `TestConfig` is set up properly for executing as
|
||||
// though it is `Remote`.
|
||||
ExecutorUniversalLocation::set(Remote::get());
|
||||
let origin = Local::get().relative_to(&Remote::get());
|
||||
AllowUnpaidFrom::set(vec![origin.clone()]);
|
||||
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
|
||||
// Then we execute it:
|
||||
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")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a dummy router which accepts messages destined for `Remote` from `Local`
|
||||
/// and then executes them in a context simulated to be like that of our `Remote`. Payment is
|
||||
/// needed.
|
||||
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> {
|
||||
// We now pretend that the message was delivered from `Local` to `Remote`, and execute
|
||||
// so we need to ensure that the `TestConfig` is set up properly for executing as
|
||||
// though it is `Remote`.
|
||||
ExecutorUniversalLocation::set(Remote::get());
|
||||
let origin = Local::get().relative_to(&Remote::get());
|
||||
AllowPaidFrom::set(vec![origin.clone()]);
|
||||
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
|
||||
// Then we execute it:
|
||||
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")),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user