use std::marker::PhantomData;
use xcm_executor::traits::Properties;
use super::*;
fn props(weight_credit: Weight) -> Properties {
Properties { weight_credit, message_id: None }
}
#[test]
fn take_weight_credit_barrier_should_work() {
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let mut properties = props(Weight::from_parts(10, 10));
let r = TakeWeightCredit::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut properties,
);
assert_eq!(r, Ok(()));
assert_eq!(properties.weight_credit, Weight::zero());
let r = TakeWeightCredit::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut properties,
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(10, 10))));
assert_eq!(properties.weight_credit, Weight::zero());
}
#[test]
fn computed_origin_should_work() {
let mut message = Xcm::<()>(vec![
UniversalOrigin(GlobalConsensus(Kusama)),
DescendOrigin(Teyrchain(100).into()),
DescendOrigin(PalletInstance(69).into()),
WithdrawAsset((Parent, 100).into()),
BuyExecution {
fees: (Parent, 100).into(),
weight_limit: Limited(Weight::from_parts(100, 100)),
},
TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() },
]);
AllowPaidFrom::set(vec![(
Parent,
Parent,
GlobalConsensus(Kusama),
Teyrchain(100),
PalletInstance(69),
)
.into()]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = WithComputedOrigin::<
AllowTopLevelPaidExecutionFrom<IsInVec<AllowPaidFrom>>,
ExecutorUniversalLocation,
ConstU32<2>,
>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = WithComputedOrigin::<
AllowTopLevelPaidExecutionFrom<IsInVec<AllowPaidFrom>>,
ExecutorUniversalLocation,
ConstU32<5>,
>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
}
#[test]
fn allow_unpaid_should_work() {
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
AllowUnpaidFrom::set(vec![Parent.into()]);
let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
&Teyrchain(1).into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
}
#[test]
fn allow_explicit_unpaid_should_work() {
let mut bad_message1 =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let mut bad_message2 = Xcm::<()>(vec![
UnpaidExecution {
weight_limit: Limited(Weight::from_parts(10, 10)),
check_origin: Some(Parent.into()),
},
TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() },
]);
let mut good_message = Xcm::<()>(vec![
UnpaidExecution {
weight_limit: Limited(Weight::from_parts(20, 20)),
check_origin: Some(Parent.into()),
},
TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() },
]);
AllowExplicitUnpaidFrom::set(vec![Parent.into(), (Parent, Teyrchain(1000)).into()]);
type ExplicitUnpaidBarrier<T> = AllowExplicitUnpaidExecutionFrom<T, mock::Aliasers>;
let r = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Teyrchain(1).into(),
good_message.inner_mut(),
Weight::from_parts(20, 20),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
bad_message1.inner_mut(),
Weight::from_parts(20, 20),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
bad_message2.inner_mut(),
Weight::from_parts(20, 20),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
good_message.inner_mut(),
Weight::from_parts(20, 20),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
let mut message_with_different_weight_parts = Xcm::<()>(vec![
UnpaidExecution {
weight_limit: Limited(Weight::from_parts(20, 10)),
check_origin: Some(Parent.into()),
},
TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() },
]);
let r = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message_with_different_weight_parts.inner_mut(),
Weight::from_parts(20, 20),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message_with_different_weight_parts.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
let mut message = Xcm::<()>::builder_unsafe()
.receive_teleported_asset((Here, 100u128))
.alias_origin(Teyrchain(1000))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Unsupported));
let mut message = Xcm::<()>::builder_unsafe()
.receive_teleported_asset((Here, 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let mut message = Xcm::<()>::builder_unsafe()
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let mut message = Xcm::<()>::builder_unsafe()
.receive_teleported_asset((Here, 100u128))
.clear_origin()
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Unsupported));
let mut message = Xcm::<()>::builder_unsafe()
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited((Parent, 100u128))
.descend_origin(Teyrchain(1000))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(40, 40),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let mut message = Xcm::<()>::builder_unsafe()
.receive_teleported_asset((Here, 100u128))
.clear_origin()
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Unsupported));
let mut message = Xcm::<()>::builder_unsafe()
.receive_teleported_asset((Here, 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::BadFormat));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, AccountId32 { id: [128u8; 32], network: None }))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(60, 60),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Unsupported));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Limited(Weight::from_parts(50, 50)), None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(60, 60),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Overweight(Weight::from_parts(60, 60))));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, AccountId32 { id: [128u8; 32], network: None }))
.unpaid_execution(Limited(Weight::from_parts(50, 50)), None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(70, 70),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Overweight(Weight::from_parts(70, 70))));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(60, 60),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.descend_origin(Teyrchain(1000))
.unpaid_execution(Unlimited, None)
.build();
let result = ExplicitUnpaidBarrier::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(60, 60),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
}
#[test]
fn allow_explicit_unpaid_fails_with_alias_origin_if_no_aliasers() {
AllowExplicitUnpaidFrom::set(vec![(Parent, Teyrchain(1000)).into()]);
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut good_message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.descend_origin(Teyrchain(1000))
.unpaid_execution(Unlimited, None)
.build();
let result =
AllowExplicitUnpaidExecutionFrom::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
good_message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut bad_message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result =
AllowExplicitUnpaidExecutionFrom::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
bad_message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Unsupported));
}
#[test]
fn allow_explicit_unpaid_with_computed_origin() {
AllowExplicitUnpaidFrom::set(vec![
(Parent, Teyrchain(1000)).into(),
(Parent, Parent, GlobalConsensus(Pezkuwi), Teyrchain(1000)).into(),
]);
type ExplicitUnpaidBarrier<T> = AllowExplicitUnpaidExecutionFrom<T, mock::Aliasers>;
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result = WithComputedOrigin::<
ExplicitUnpaidBarrier<IsInVec<AllowExplicitUnpaidFrom>>,
ExecutorUniversalLocation,
ConstU32<2>,
>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.universal_origin(Pezkuwi)
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, Parent, GlobalConsensus(Pezkuwi), Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result = WithComputedOrigin::<
ExplicitUnpaidBarrier<IsInVec<AllowExplicitUnpaidFrom>>,
ExecutorUniversalLocation,
ConstU32<2>,
>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(result, Ok(()));
let assets: Vec<Asset> = vec![
(Parent, 100u128).into(),
((Parent, PalletInstance(10), GeneralIndex(1000)), 100u128).into(),
];
let mut message = Xcm::<()>::builder_unsafe()
.universal_origin(Pezkuwi)
.set_hints(vec![AssetClaimer {
location: AccountId32 { id: [100u8; 32], network: None }.into(),
}])
.receive_teleported_asset((Here, 100u128))
.reserve_asset_deposited(assets)
.withdraw_asset((GeneralIndex(1), 100u128))
.alias_origin((Parent, Teyrchain(1000)))
.unpaid_execution(Unlimited, None)
.build();
let result = WithComputedOrigin::<
ExplicitUnpaidBarrier<IsInVec<AllowExplicitUnpaidFrom>>,
ExecutorUniversalLocation,
ConstU32<2>,
>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(100, 100),
&mut props(Weight::zero()),
);
assert_eq!(result, Err(ProcessMessageError::Unsupported));
}
#[test]
fn allow_paid_should_work() {
AllowPaidFrom::set(vec![Parent.into()]);
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Teyrchain(1).into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let fees = (Parent, 1).into();
let mut underpaying_message = Xcm::<()>(vec![
ReserveAssetDeposited((Parent, 100).into()),
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(20, 20)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
underpaying_message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30))));
let fees = (Parent, 1).into();
let mut paying_message = Xcm::<()>(vec![
ReserveAssetDeposited((Parent, 100).into()),
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Teyrchain(1).into(),
paying_message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
let fees = (Parent, 1).into();
let mut paying_message_with_different_weight_parts = Xcm::<()>(vec![
WithdrawAsset((Parent, 100).into()),
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(20, 10)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_with_different_weight_parts.inner_mut(),
Weight::from_parts(20, 20),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_with_different_weight_parts.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()))
}
#[test]
fn allow_paid_should_deprivilege_origin() {
AllowPaidFrom::set(vec![Parent.into()]);
let fees = (Parent, 1).into();
let mut paying_message_clears_origin = Xcm::<()>(vec![
ReserveAssetDeposited((Parent, 100).into()),
ClearOrigin,
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_clears_origin.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
let mut paying_message_aliases_origin = paying_message_clears_origin.clone();
paying_message_aliases_origin.0[1] = AliasOrigin(Teyrchain(1).into());
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_aliases_origin.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
let mut paying_message_descends_origin = paying_message_clears_origin.clone();
paying_message_descends_origin.0[1] = DescendOrigin(Teyrchain(1).into());
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_descends_origin.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
let mut paying_message_fake_descends_origin = paying_message_clears_origin.clone();
paying_message_fake_descends_origin.0[1] = DescendOrigin(Here.into());
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_fake_descends_origin.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30))));
}
#[test]
fn allow_paid_should_allow_hints() {
AllowPaidFrom::set(vec![Parent.into()]);
let fees = (Parent, 1).into();
let mut paying_message_with_hints = Xcm::<()>(vec![
ReserveAssetDeposited((Parent, 100).into()),
SetHints { hints: vec![AssetClaimer { location: Location::here() }].try_into().unwrap() },
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
paying_message_with_hints.inner_mut(),
Weight::from_parts(30, 30),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
}
#[test]
fn suspension_should_work() {
TestSuspender::set_suspended(true);
AllowUnpaidFrom::set(vec![Parent.into()]);
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let r = RespectSuspension::<AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>, TestSuspender>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Err(ProcessMessageError::Yield));
TestSuspender::set_suspended(false);
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let r = RespectSuspension::<AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>, TestSuspender>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
);
assert_eq!(r, Ok(()));
}
#[test]
fn allow_subscriptions_from_should_work() {
AllowSubsFrom::set(vec![Location::parent()]);
let assert_should_execute = |mut xcm: Vec<Instruction<()>>, origin, expected_result| {
assert_eq!(
AllowSubscriptionsFrom::<IsInVec<AllowSubsFrom>>::should_execute(
&origin,
&mut xcm,
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
),
expected_result
);
};
assert_should_execute(
vec![SubscribeVersion {
query_id: Default::default(),
max_response_weight: Default::default(),
}],
Teyrchain(1).into_location(),
Err(ProcessMessageError::Unsupported),
);
assert_should_execute(
vec![UnsubscribeVersion],
Teyrchain(1).into_location(),
Err(ProcessMessageError::Unsupported),
);
assert_should_execute(
vec![
SetAppendix(Xcm(vec![])),
SubscribeVersion {
query_id: Default::default(),
max_response_weight: Default::default(),
},
],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![SetAppendix(Xcm(vec![])), UnsubscribeVersion],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![
SubscribeVersion {
query_id: Default::default(),
max_response_weight: Default::default(),
},
SetTopic([0; 32]),
],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![UnsubscribeVersion, SetTopic([0; 32])],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![SetAppendix(Xcm(vec![]))],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![SubscribeVersion {
query_id: Default::default(),
max_response_weight: Default::default(),
}],
Location::parent(),
Ok(()),
);
assert_should_execute(vec![UnsubscribeVersion], Location::parent(), Ok(()));
}
#[test]
fn allow_hrmp_notifications_from_relay_chain_should_work() {
let assert_should_execute = |mut xcm: Vec<Instruction<()>>, origin, expected_result| {
assert_eq!(
AllowHrmpNotificationsFromRelayChain::should_execute(
&origin,
&mut xcm,
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
),
expected_result
);
};
assert_should_execute(
vec![HrmpChannelAccepted { recipient: Default::default() }],
Location::new(1, [Teyrchain(1)]),
Err(ProcessMessageError::Unsupported),
);
assert_should_execute(
vec![SetAppendix(Xcm(vec![])), HrmpChannelAccepted { recipient: Default::default() }],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![HrmpChannelAccepted { recipient: Default::default() }, SetTopic([0; 32])],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![SetAppendix(Xcm(vec![]))],
Location::parent(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![HrmpChannelAccepted { recipient: Default::default() }],
Location::parent(),
Ok(()),
);
assert_should_execute(
vec![HrmpNewChannelOpenRequest {
max_capacity: Default::default(),
sender: Default::default(),
max_message_size: Default::default(),
}],
Location::parent(),
Ok(()),
);
assert_should_execute(
vec![HrmpChannelClosing {
recipient: Default::default(),
sender: Default::default(),
initiator: Default::default(),
}],
Location::parent(),
Ok(()),
);
}
#[test]
fn deny_then_try_works() {
struct DenyClearTransactStatusAsYield;
impl DenyExecution for DenyClearTransactStatusAsYield {
fn deny_execution<RuntimeCall>(
_origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
instructions.matcher().match_next_inst_while(
|_| true,
|inst| match inst {
ClearTransactStatus { .. } => Err(ProcessMessageError::Yield),
_ => Ok(ControlFlow::Continue(())),
},
)?;
Ok(())
}
}
struct DenyClearOriginFromHereAsBadFormat;
impl DenyExecution for DenyClearOriginFromHereAsBadFormat {
fn deny_execution<RuntimeCall>(
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
instructions.matcher().match_next_inst_while(
|_| true,
|inst| match inst {
ClearOrigin { .. } => {
if origin.clone() == Here.into_location() {
Err(ProcessMessageError::BadFormat)
} else {
Ok(ControlFlow::Continue(()))
}
},
_ => Ok(ControlFlow::Continue(())),
},
)?;
Ok(())
}
}
struct DenyUnsubscribeVersionAsStackLimitReached;
impl DenyExecution for DenyUnsubscribeVersionAsStackLimitReached {
fn deny_execution<RuntimeCall>(
_origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
if instructions.len() != 1 {
return Ok(());
}
match instructions.get(0).unwrap() {
UnsubscribeVersion { .. } => Err(ProcessMessageError::StackLimitReached),
_ => Ok(()),
}
}
}
struct AllowSingleClearErrorOrYield;
impl ShouldExecute for AllowSingleClearErrorOrYield {
fn should_execute<Call>(
_origin: &Location,
instructions: &mut [Instruction<Call>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
instructions.matcher().assert_remaining_insts(1)?.match_next_inst(
|inst| match inst {
ClearError { .. } => Ok(()),
_ => Err(ProcessMessageError::Yield),
},
)?;
Ok(())
}
}
struct AllowClearTopicFromHere;
impl ShouldExecute for AllowClearTopicFromHere {
fn should_execute<Call>(
origin: &Location,
instructions: &mut [Instruction<Call>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
ensure!(origin.clone() == Here.into_location(), ProcessMessageError::Unsupported);
let mut found = false;
instructions.matcher().match_next_inst_while(
|_| true,
|inst| match inst {
ClearTopic { .. } => {
found = true;
Ok(ControlFlow::Break(()))
},
_ => Ok(ControlFlow::Continue(())),
},
)?;
ensure!(found, ProcessMessageError::Unsupported);
Ok(())
}
}
let assert_should_execute = |mut xcm: Vec<Instruction<()>>, origin, expected_result| {
pub type Barrier = DenyThenTry<
(
DenyClearTransactStatusAsYield,
DenyClearOriginFromHereAsBadFormat,
DenyUnsubscribeVersionAsStackLimitReached,
),
(AllowSingleClearErrorOrYield, AllowClearTopicFromHere),
>;
assert_eq!(
Barrier::should_execute(
&origin,
&mut xcm,
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
),
expected_result
);
};
assert_should_execute(
vec![ClearTransactStatus],
Teyrchain(1).into_location(),
Err(ProcessMessageError::Yield),
);
assert_should_execute(
vec![ClearError, ClearTransactStatus],
Teyrchain(1).into_location(),
Err(ProcessMessageError::Yield),
);
assert_should_execute(
vec![ClearOrigin],
Here.into_location(),
Err(ProcessMessageError::BadFormat),
);
assert_should_execute(
vec![UnsubscribeVersion],
Here.into_location(),
Err(ProcessMessageError::StackLimitReached),
);
assert_should_execute(
vec![ClearError, ClearTopic],
Teyrchain(1).into_location(),
Err(ProcessMessageError::Unsupported),
);
assert_should_execute(vec![ClearError], Teyrchain(1).into_location(), Ok(()));
assert_should_execute(vec![ClearTopic], Here.into(), Ok(()));
assert_should_execute(vec![ClearError, ClearTopic], Here.into_location(), Ok(()));
}
#[test]
fn deny_reserve_transfer_to_relaychain_should_work() {
let assert_deny_execution = |mut xcm: Vec<Instruction<()>>, origin, expected_result| {
assert_eq!(
DenyReserveTransferToRelayChain::deny_execution(
&origin,
&mut xcm,
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
),
expected_result
);
};
assert_deny_execution(
vec![DepositReserveAsset {
assets: Wild(All),
dest: Location::parent(),
xcm: vec![].into(),
}],
Here.into_location(),
Err(ProcessMessageError::Unsupported),
);
assert_deny_execution(
vec![InitiateReserveWithdraw {
assets: Wild(All),
reserve: Location::parent(),
xcm: vec![].into(),
}],
Here.into_location(),
Err(ProcessMessageError::Unsupported),
);
assert_deny_execution(
vec![TransferReserveAsset {
assets: vec![].into(),
dest: Location::parent(),
xcm: vec![].into(),
}],
Here.into_location(),
Err(ProcessMessageError::Unsupported),
);
assert_deny_execution(
vec![DepositReserveAsset {
assets: Wild(All),
dest: Here.into_location(),
xcm: vec![].into(),
}],
Here.into_location(),
Ok(()),
);
assert_deny_execution(vec![ClearOrigin], Here.into_location(), Ok(()));
}
struct AllowAll;
impl ShouldExecute for AllowAll {
fn should_execute<RuntimeCall>(
_: &Location,
_: &mut [Instruction<RuntimeCall>],
_: Weight,
_: &mut Properties,
) -> Result<(), ProcessMessageError> {
Ok(())
}
}
struct DenyClearOrigin;
impl DenyExecution for DenyClearOrigin {
fn deny_execution<RuntimeCall>(
_: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_: Weight,
_: &mut Properties,
) -> Result<(), ProcessMessageError> {
instructions.matcher().match_next_inst_while(
|_| true,
|inst| match inst {
ClearOrigin => Err(ProcessMessageError::Unsupported),
_ => Ok(ControlFlow::Continue(())),
},
)?;
Ok(())
}
}
struct DenyNothing;
impl DenyExecution for DenyNothing {
fn deny_execution<RuntimeCall>(
_origin: &Location,
_instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
Ok(())
}
}
struct Executable<Barrier: DenyExecution>(PhantomData<Barrier>);
impl<Barrier: DenyExecution> ShouldExecute for Executable<Barrier> {
fn should_execute<RuntimeCall>(
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
Barrier::deny_execution(origin, instructions, max_weight, properties)
}
}
#[test]
fn deny_recursively_then_try_works() {
type Barrier = DenyThenTry<DenyRecursively<DenyReserveTransferToRelayChain>, AllowAll>;
let xcm = Xcm::<Instruction<()>>(vec![DepositReserveAsset {
assets: Wild(All),
dest: Location::parent(),
xcm: vec![].into(),
}]);
let origin = Here.into_location();
let max_weight = Weight::from_parts(10, 10);
let mut properties = props(Weight::zero());
let result =
Barrier::should_execute(&origin, xcm.clone().inner_mut(), max_weight, &mut properties);
assert!(result.is_err());
let mut message = Xcm::<Instruction<()>>(vec![SetAppendix(xcm.clone())]);
let result =
Barrier::should_execute(&origin, message.clone().inner_mut(), max_weight, &mut properties);
assert!(result.is_err());
type OriginalBarrier = DenyThenTry<DenyReserveTransferToRelayChain, AllowAll>;
let result =
OriginalBarrier::should_execute(&origin, message.inner_mut(), max_weight, &mut properties);
assert!(result.is_ok());
let mut message = Xcm::<Instruction<()>>(vec![SetErrorHandler(xcm.clone())]);
let result = Barrier::should_execute(&origin, message.inner_mut(), max_weight, &mut properties);
assert!(result.is_err());
let mut message = Xcm::<Instruction<()>>(vec![ExecuteWithOrigin {
xcm: xcm.clone(),
descendant_origin: None,
}]);
let result = Barrier::should_execute(&origin, message.inner_mut(), max_weight, &mut properties);
assert!(result.is_err());
let mut message = Xcm::<Instruction<()>>(vec![ExecuteWithOrigin {
xcm: vec![SetErrorHandler(vec![SetAppendix(xcm.clone())].into())].into(),
descendant_origin: None,
}]);
let result = Barrier::should_execute(&origin, message.inner_mut(), max_weight, &mut properties);
assert!(result.is_err());
let xcm = Xcm::<Instruction<()>>(vec![DepositReserveAsset {
assets: Wild(All),
dest: Here.into_location(),
xcm: vec![].into(),
}]);
let mut message = Xcm::<Instruction<()>>(vec![SetAppendix(xcm.clone())]);
let result = Barrier::should_execute(&origin, message.inner_mut(), max_weight, &mut properties);
assert!(result.is_ok());
let mut unrelated_xcm = Xcm::<Instruction<()>>(vec![BuyExecution {
fees: (Parent, 100).into(),
weight_limit: Unlimited,
}]);
let result =
Barrier::should_execute(&origin, unrelated_xcm.inner_mut(), max_weight, &mut properties);
assert!(result.is_ok());
type BarrierDenyClearOrigin = DenyThenTry<DenyRecursively<DenyClearOrigin>, AllowAll>;
assert_deny_instructions_recursively::<BarrierDenyClearOrigin>();
}
#[test]
fn deny_recursively_works() {
type Barrier = Executable<DenyRecursively<DenyClearOrigin>>;
assert_deny_instructions_recursively::<Barrier>();
}
#[test]
fn compare_deny_filters() {
type Denies = (DenyNothing, DenyReserveTransferToRelayChain);
fn assert_barrier<Barrier: ShouldExecute>(
top_level_result: Result<(), ProcessMessageError>,
nested_result: Result<(), ProcessMessageError>,
) {
let origin = Here.into_location();
let max_weight = Weight::zero();
let mut properties = props(Weight::zero());
let xcm = Xcm::<Instruction<()>>(
vec![DepositReserveAsset {
assets: Wild(All),
dest: Location::parent(),
xcm: Xcm(vec![ClearOrigin]),
}]
.into(),
);
let result =
Barrier::should_execute(&origin, xcm.clone().inner_mut(), max_weight, &mut properties);
assert_eq!(top_level_result, result);
let mut nested_xcm = Xcm::<Instruction<()>>(vec![SetErrorHandler(xcm.into())].into());
let result =
Barrier::should_execute(&origin, nested_xcm.inner_mut(), max_weight, &mut properties);
assert_eq!(nested_result, result);
}
assert_barrier::<DenyThenTry<Denies, AllowAll>>(Err(ProcessMessageError::Unsupported), Ok(()));
assert_barrier::<DenyThenTry<DenyRecursively<Denies>, AllowAll>>(
Err(ProcessMessageError::Unsupported),
Err(ProcessMessageError::Unsupported),
);
assert_barrier::<Executable<DenyRecursively<Denies>>>(
Err(ProcessMessageError::Unsupported),
Err(ProcessMessageError::Unsupported),
);
}
fn assert_deny_instructions_recursively<Barrier: ShouldExecute>() {
let test_barrier = |mut xcm: Vec<Instruction<()>>, origin| {
Barrier::should_execute(
&origin,
&mut xcm,
Weight::from_parts(10, 10),
&mut props(Weight::zero()),
)
};
assert_eq!(test_barrier(vec![ClearTransactStatus], Location::parent()), Ok(()));
assert_eq!(
test_barrier(vec![ClearOrigin], Location::parent()),
Err(ProcessMessageError::Unsupported)
);
assert_eq!(
test_barrier(vec![SetAppendix(Xcm(vec![ClearTransactStatus]))], Location::parent()),
Ok(())
);
assert_eq!(
test_barrier(
vec![DepositReserveAsset {
assets: Wild(All),
dest: Here.into(),
xcm: Xcm(vec![ClearOrigin]),
}],
Location::parent()
),
Ok(()),
);
assert_eq!(test_barrier(vec![], Location::parent()), Err(ProcessMessageError::BadFormat));
assert_eq!(
test_barrier(vec![SetAppendix(Xcm(vec![]))], Location::parent()),
Err(ProcessMessageError::BadFormat),
);
assert_eq!(
test_barrier(vec![SetAppendix(Xcm(vec![ClearOrigin]))], Location::parent()),
Err(ProcessMessageError::Unsupported),
);
assert_eq!(
test_barrier(
vec![SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![
SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![
SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![
SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![SetAppendix(Xcm(vec![
ClearOrigin
]))])),]))
]))])),]))
]))]))]),)
]))]))]))],
Location::parent()
),
Err(ProcessMessageError::StackLimitReached),
);
}