Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

relay account and tests #651

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
84 changes: 83 additions & 1 deletion xcm-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
#![allow(clippy::unused_unit)]

use frame_support::dispatch::{DispatchError, DispatchResult};
use frame_support::{ensure, weights::Weight};

use sp_runtime::traits::{CheckedConversion, Convert};
use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*};

use xcm::latest::prelude::*;
use xcm_executor::traits::{FilterAssetLocation, MatchesFungible};
use xcm_executor::traits::{FilterAssetLocation, MatchesFungible, ShouldExecute};

use orml_traits::location::Reserve;

pub use currency_adapter::MultiCurrencyAdapter;
use frame_support::pallet_prelude::Get;

mod currency_adapter;

Expand Down Expand Up @@ -75,3 +78,82 @@ impl UnknownAsset for () {
Err(DispatchError::Other(NO_UNKNOWN_ASSET_IMPL))
}
}

/// Extracts the `AccountId32` from the passed `location` if the network
/// matches or is `NetworkId::Any`.
pub struct RelayChainAccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
xcm_executor::traits::Convert<MultiLocation, AccountId> for RelayChainAccountId32Aliases<Network, AccountId>
{
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
if let MultiLocation {
parents: 1,
interior: X1(AccountId32 { id, network }),
} = location.clone()
{
if network == NetworkId::Any || network == Network::get() {
return Ok(id.into());
}
};
Err(location)
}

fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> {
Ok((
1,
AccountId32 {
id: who.into(),
network: Network::get(),
},
)
.into())
}
}

/// Allows execution from `origin` if it is `Parent`.
pub struct AllowRelayedPaidExecutionFromParent<Network>(PhantomData<Network>);
impl<Network: Get<NetworkId>> ShouldExecute for AllowRelayedPaidExecutionFromParent<Network> {
fn should_execute<Call>(
origin: &MultiLocation,
message: &mut Xcm<Call>,
max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
ensure!(origin.contains_parents_only(1), ());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to make this a configurable generic that implements Contains<MultiLocation> ?
We have a use-case for allowing sibling chains to send Transact instructions to us.

let mut iter = message.0.iter_mut();
zqhxuyuan marked this conversation as resolved.
Show resolved Hide resolved
let i = iter.next().ok_or(())?;
match i {
DescendOrigin(X1(Junction::AccountId32 { network, .. }))
if network == &NetworkId::Any || network == &Network::get() =>
{
()
}
_ => return Err(()),
}
let i = iter.next().ok_or(())?;
match i {
WithdrawAsset(..) => (),
_ => return Err(()),
}
let i = iter.next().ok_or(())?;
match i {
BuyExecution {
weight_limit: Limited(ref mut weight),
..
} if *weight >= max_weight => {
*weight = max_weight;
()
}
_ => return Err(()),
}
let i = iter.next().ok_or(())?;
match i {
Transact {
origin_type: OriginKind::SovereignAccount,
..
}
| DepositAsset { .. } => Ok(()),
_ => Err(()),
}
}
}
80 changes: 80 additions & 0 deletions xcm-support/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use super::*;

use frame_support::{assert_ok, pallet_prelude::Encode, parameter_types};
use orml_traits::{location::RelativeLocations, ConcreteFungibleAsset};
use sp_runtime::AccountId32;

#[derive(Debug, PartialEq, Eq)]
pub enum TestCurrencyId {
Expand Down Expand Up @@ -98,3 +100,81 @@ fn multi_native_asset() {
&MultiLocation::parent(),
));
}

#[test]
fn relay_account_convert() {
use xcm_executor::traits::Convert;

parameter_types! {
const RelayNetwork: NetworkId = NetworkId::Any;
}
let destination: MultiLocation = (
Parent,
Junction::AccountId32 {
network: NetworkId::Any,
id: [0; 32],
},
)
.into();
let account: Result<AccountId32, MultiLocation> =
RelayChainAccountId32Aliases::<RelayNetwork, AccountId32>::convert(destination);
assert_eq!(account, Ok(AccountId32::new([0; 32])));
}

#[test]
fn allow_relayed_paid_execution_transact_works() {
parameter_types! {
const RelayNetwork: NetworkId = NetworkId::Any;
}
let assets: MultiAsset = (Parent, 1000).into();
let mut xcm = Xcm::<()>(vec![
DescendOrigin(X1(Junction::AccountId32 {
network: NetworkId::Any,
id: [0; 32],
})),
WithdrawAsset(assets.clone().into()),
BuyExecution {
fees: assets,
weight_limit: Limited(1000),
},
Transact {
origin_type: OriginKind::SovereignAccount,
require_weight_at_most: 1000 as u64,
call: Encode::encode(&100).into(),
},
]);
let r =
AllowRelayedPaidExecutionFromParent::<RelayNetwork>::should_execute(&(Parent.into()), &mut xcm, 100, &mut 100);
assert_ok!(r);
}

#[test]
fn allow_relayed_paid_execution_weight_not_works() {
parameter_types! {
const RelayNetwork: NetworkId = NetworkId::Any;
}
let bob = X1(Junction::AccountId32 {
network: NetworkId::Kusama,
id: [1; 32],
});
let assets: MultiAsset = (Parent, 1000).into();
let mut xcm = Xcm::<()>(vec![
DescendOrigin(X1(Junction::AccountId32 {
network: NetworkId::Any,
id: [0; 32],
})),
WithdrawAsset(assets.clone().into()),
BuyExecution {
fees: assets,
weight_limit: Limited(1000),
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: (0, bob).into(),
},
]);
let r =
AllowRelayedPaidExecutionFromParent::<RelayNetwork>::should_execute(&(Parent.into()), &mut xcm, 2000, &mut 100);
assert_eq!(r, Err(()));
}
34 changes: 30 additions & 4 deletions xtokens/src/mock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,39 @@ use serde::{Deserialize, Serialize};
use sp_io::TestExternalities;
use sp_runtime::AccountId32;

use cumulus_primitives_core::ParaId;
use polkadot_parachain::primitives::{AccountIdConversion, Sibling};
use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain};

pub mod para;
pub mod relay;

pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]);
pub const BOB: AccountId32 = AccountId32::new([1u8; 32]);
pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
pub const BOB: AccountId32 = AccountId32::new([2u8; 32]);
pub const INITIAL_BALANCE: u128 = 1_000;

pub fn para_a_account() -> AccountId32 {
ParaId::from(1).into_account()
}

pub fn para_b_account() -> AccountId32 {
ParaId::from(2).into_account()
}

pub fn sibling_a_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(1).into_account()
}

pub fn sibling_b_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(2).into_account()
}

pub fn sibling_c_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(3).into_account()
}

#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -135,7 +161,7 @@ pub fn para_ext(para_id: u32) -> TestExternalities {
.unwrap();

orml_tokens::GenesisConfig::<Runtime> {
balances: vec![(ALICE, CurrencyId::R, 1_000)],
balances: vec![(ALICE, CurrencyId::R, INITIAL_BALANCE)],
}
.assimilate_storage(&mut t)
.unwrap();
Expand All @@ -153,7 +179,7 @@ pub fn relay_ext() -> sp_io::TestExternalities {
.unwrap();

pallet_balances::GenesisConfig::<Runtime> {
balances: vec![(ALICE, 1_000)],
balances: vec![(ALICE, INITIAL_BALANCE)],
}
.assimilate_storage(&mut t)
.unwrap();
Expand Down
12 changes: 10 additions & 2 deletions xtokens/src/mock/para.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ use xcm_builder::{
use xcm_executor::{traits::WeightTrader, Assets, Config, XcmExecutor};

use orml_traits::parameter_type_with_key;
use orml_xcm_support::{IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset};
use orml_xcm_support::{
AllowRelayedPaidExecutionFromParent, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset,
RelayChainAccountId32Aliases,
};

pub type AccountId = AccountId32;

Expand Down Expand Up @@ -114,6 +117,7 @@ pub type LocationToAccountId = (
ParentIsDefault<AccountId>,
SiblingParachainConvertsVia<Sibling, AccountId>,
AccountId32Aliases<RelayNetwork, AccountId>,
RelayChainAccountId32Aliases<RelayNetwork, AccountId>,
);

pub type XcmOriginToCallOrigin = (
Expand All @@ -140,7 +144,11 @@ pub type LocalAssetTransactor = MultiCurrencyAdapter<
>;

pub type XcmRouter = ParachainXcmRouter<ParachainInfo>;
pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom<Everything>);
pub type Barrier = (
TakeWeightCredit,
AllowTopLevelPaidExecutionFrom<Everything>,
AllowRelayedPaidExecutionFromParent<RelayNetwork>,
);

/// A trader who believes all tokens are created equal to "weight" of any chain,
/// which is not true, but good enough to mock the fee payment of XCM execution.
Expand Down
27 changes: 0 additions & 27 deletions xtokens/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,11 @@
#![cfg(test)]

use super::*;
use codec::Encode;
use cumulus_primitives_core::ParaId;
use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency};
use mock::*;
use orml_traits::{ConcreteFungibleAsset, MultiCurrency};
use polkadot_parachain::primitives::{AccountIdConversion, Sibling};
use sp_runtime::AccountId32;
use xcm_simulator::TestExt;

fn para_a_account() -> AccountId32 {
ParaId::from(1).into_account()
}

fn para_b_account() -> AccountId32 {
ParaId::from(2).into_account()
}

fn sibling_a_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(1).into_account()
}

fn sibling_b_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(2).into_account()
}

fn sibling_c_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(3).into_account()
}

// Not used in any unit tests, but it's super helpful for debugging. Let's
// keep it here.
#[allow(dead_code)]
Expand Down