use super::*;
#[test]
fn fixed_rate_of_fungible_should_work() {
parameter_types! {
pub static WeightPrice: (AssetId, u128, u128) =
(Here.into(), WEIGHT_REF_TIME_PER_SECOND.into(), WEIGHT_PROOF_SIZE_PER_MB.into());
}
let mut trader = FixedRateOfFungible::<WeightPrice, ()>::new();
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
assert_eq!(
trader.buy_weight(
Weight::from_parts(10, 10),
fungible_multi_asset(Here.into(), 100).into(),
&ctx,
),
Ok(fungible_multi_asset(Here.into(), 80).into()),
);
assert_eq!(
trader.buy_weight(
Weight::from_parts(5, 5),
fungible_multi_asset(Here.into(), 10).into(),
&ctx,
),
Ok(vec![].into()),
);
assert_eq!(
trader.buy_weight(
Weight::from_parts(5, 0),
fungible_multi_asset(Here.into(), 10).into(),
&ctx,
),
Ok(fungible_multi_asset(Here.into(), 5).into()),
);
assert_err!(
trader.buy_weight(
Weight::from_parts(5, 5),
fungible_multi_asset(Here.into(), 5).into(),
&ctx,
),
XcmError::TooExpensive,
);
}
#[test]
fn errors_should_return_unused_weight() {
AllowUnpaidFrom::set(vec![Here.into()]);
add_asset(Here, (Here, 11u128));
let mut message = Xcm(vec![
TransferAsset {
assets: (Here, 1u128).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
TransferAsset {
assets: (Here, 2u128).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
TransferAsset {
assets: (Here, 4u128).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
]);
let limit = <TestConfig as Config>::Weigher::weight(&mut message, Weight::MAX).unwrap();
assert_eq!(limit, Weight::from_parts(30, 30));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(30, 30) });
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 7u128).into()]);
assert_eq!(asset_list(Here), vec![(Here, 4u128).into()]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(30, 30),
error: InstructionError { index: 2, error: XcmError::NotWithdrawable },
}
);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 10u128).into()]);
assert_eq!(asset_list(Here), vec![(Here, 1u128).into()]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(20, 20),
error: InstructionError { index: 1, error: XcmError::NotWithdrawable },
}
);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11u128).into()]);
assert_eq!(asset_list(Here), vec![]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message,
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(10, 10),
error: InstructionError { index: 0, error: XcmError::NotWithdrawable },
}
);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11u128).into()]);
assert_eq!(asset_list(Here), vec![]);
assert_eq!(sent_xcm(), vec![]);
}
#[test]
fn weight_bounds_should_respect_instructions_limit() {
use pezsp_tracing::capture_test_logs;
pezsp_tracing::init_for_tests();
MaxInstructions::set(3);
let log_capture = capture_test_logs!({
let mut message = Xcm(vec![ClearOrigin; 4]);
assert_eq!(
<TestConfig as Config>::Weigher::weight(&mut message, Weight::MAX),
Err(InstructionError { index: 3, error: XcmError::ExceedsStackLimit })
);
});
assert!(log_capture.contains(
"Weight calculation failed for message error=InstructionError { index: 3, error: ExceedsStackLimit } instructions_left=0 message_length=4"
));
let log_capture = capture_test_logs!({
let mut message =
Xcm(vec![SetErrorHandler(Xcm(vec![ClearOrigin])), SetAppendix(Xcm(vec![ClearOrigin]))]);
assert_eq!(
<TestConfig as Config>::Weigher::weight(&mut message, Weight::MAX),
Err(InstructionError { index: 1, error: XcmError::ExceedsStackLimit })
);
});
assert!(log_capture.contains(
"Weight calculation failed for message error=InstructionError { index: 1, error: ExceedsStackLimit } instructions_left=0 message_length=2"
));
let log_capture = capture_test_logs!({
let mut message =
Xcm(vec![SetErrorHandler(Xcm(vec![SetErrorHandler(Xcm(vec![SetErrorHandler(
Xcm(vec![ClearOrigin]),
)]))]))]);
assert_eq!(
<TestConfig as Config>::Weigher::weight(&mut message, Weight::MAX),
Err(InstructionError { index: 0, error: XcmError::ExceedsStackLimit })
);
});
assert!(log_capture.contains(
"Weight calculation failed for message error=InstructionError { index: 0, error: ExceedsStackLimit } instructions_left=0 message_length=1"
));
let log_capture = capture_test_logs!({
let mut message =
Xcm(vec![SetErrorHandler(Xcm(vec![SetErrorHandler(Xcm(vec![ClearOrigin]))]))]);
assert_eq!(
<TestConfig as Config>::Weigher::weight(&mut message, Weight::MAX),
Ok(Weight::from_parts(30, 30))
);
});
assert!(!log_capture.contains("Weight calculation failed for message"));
}
#[test]
fn weigher_returns_correct_instruction_index_on_error() {
MaxInstructions::set(10);
let max_weight = UnitWeightCost::get() * 3;
let mut message = Xcm(vec![ClearOrigin; 4]);
assert_eq!(
<TestConfig as Config>::Weigher::weight(&mut message, max_weight),
Err(InstructionError {
index: 3,
error: XcmError::WeightLimitReached(UnitWeightCost::get() * 4)
})
);
}
#[test]
fn weigher_weight_limit_correctly_accounts_for_nested_instructions() {
MaxInstructions::set(10);
let max_weight = UnitWeightCost::get() * 3;
let mut message = Xcm(vec![SetAppendix(Xcm(vec![ClearOrigin; 7]))]);
assert_eq!(
<TestConfig as Config>::Weigher::weight(&mut message, max_weight),
Err(InstructionError {
index: 0,
error: XcmError::WeightLimitReached(UnitWeightCost::get() * 4)
})
);
}
#[test]
fn weight_trader_tuple_should_work() {
let para_1: Location = Teyrchain(1).into();
let para_2: Location = Teyrchain(2).into();
parameter_types! {
pub static HereWeightPrice: (AssetId, u128, u128) =
(Here.into(), WEIGHT_REF_TIME_PER_SECOND.into(), WEIGHT_PROOF_SIZE_PER_MB.into());
pub static Para1WeightPrice: (AssetId, u128, u128) =
(Teyrchain(1).into(), WEIGHT_REF_TIME_PER_SECOND.into(), WEIGHT_PROOF_SIZE_PER_MB.into());
}
type Traders = (
FixedRateOfFungible<HereWeightPrice, ()>,
FixedRateOfFungible<Para1WeightPrice, ()>,
);
let mut traders = Traders::new();
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
assert_eq!(
traders.buy_weight(
Weight::from_parts(5, 5),
fungible_multi_asset(Here.into(), 10).into(),
&ctx
),
Ok(vec![].into()),
);
assert_eq!(
traders.refund_weight(Weight::from_parts(2, 2), &ctx),
Some(fungible_multi_asset(Here.into(), 4))
);
let mut traders = Traders::new();
assert_eq!(
traders.buy_weight(
Weight::from_parts(5, 5),
fungible_multi_asset(para_1.clone(), 10).into(),
&ctx
),
Ok(vec![].into()),
);
assert_eq!(
traders.refund_weight(Weight::from_parts(2, 2), &ctx),
Some(fungible_multi_asset(para_1, 4))
);
let mut traders = Traders::new();
assert_err!(
traders.buy_weight(Weight::from_parts(5, 5), fungible_multi_asset(para_2, 10).into(), &ctx),
XcmError::TooExpensive,
);
assert_eq!(traders.refund_weight(Weight::from_parts(2, 2), &ctx), None);
}