Newer
Older
XcmPallet::on_initialize(2);
assert_eq!(
take_sent_xcm(),
vec![(
Xcm(vec![SubscribeVersion { query_id: 1, max_response_weight: Weight::zero() }]),
let weight = BaseXcmWeight::get();
let message = Xcm(vec![
// Remote supports XCM v2
QueryResponse {
query_id: 1,
max_weight: Weight::zero(),
response: Response::Version(2),
querier: None,
},
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<XcmConfig>::prepare_and_execute(
remote_v2.clone(),
message,
&mut hash,
weight,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: weight });
assert_eq!(
XcmPallet::wrap_version(&remote_v2, msg_v2.clone()),
Ok(VersionedXcm::V2(msg_v2))
);
assert_eq!(XcmPallet::wrap_version(&remote_v2, msg_v4.clone()), Err(()));
})
}
#[test]
fn subscription_side_upgrades_work_with_multistage_notify() {
new_test_ext_with_balances(vec![]).execute_with(|| {
AdvertisedXcmVersion::set(1);
// An entry from a previous runtime with v0 XCM.
let v2_location = VersionedLocation::V2(xcm::v2::Junction::Parachain(1001).into());
VersionNotifyTargets::<Test>::insert(1, v2_location, (70, Weight::zero(), 1));
let v2_location = VersionedLocation::V2(xcm::v2::Junction::Parachain(1002).into());
VersionNotifyTargets::<Test>::insert(2, v2_location, (71, Weight::zero(), 1));
let v3_location = Parachain(1003).into_versioned();
VersionNotifyTargets::<Test>::insert(3, v3_location, (72, Weight::zero(), 1));
// A runtime upgrade which alters the version does send notifications.
CurrentMigration::<Test>::put(VersionMigrationStage::default());
let mut maybe_migration = CurrentMigration::<Test>::take();
let mut counter = 0;
while let Some(migration) = maybe_migration.take() {
counter += 1;
let (_, m) = XcmPallet::check_xcm_version_change(migration, Weight::zero());
maybe_migration = m;
}
assert_eq!(counter, 4);
let instr1 = QueryResponse {
query_id: 70,
max_weight: Weight::zero(),
response: Response::Version(3),
querier: None,
};
let instr2 = QueryResponse {
query_id: 71,
max_weight: Weight::zero(),
response: Response::Version(3),
querier: None,
};
let instr3 = QueryResponse {
query_id: 72,
max_weight: Weight::zero(),
response: Response::Version(3),
querier: None,
};
let mut sent = take_sent_xcm();
sent.sort_by_key(|k| match (k.1).0[0] {
QueryResponse { query_id: q, .. } => q,
_ => 0,
});
assert_eq!(
sent,
vec![
(Parachain(1001).into(), Xcm(vec![instr1])),
(Parachain(1002).into(), Xcm(vec![instr2])),
]
);
let mut contents = VersionNotifyTargets::<Test>::iter().collect::<Vec<_>>();
assert_eq!(
contents,
vec![
(XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)),
(XCM_VERSION, Parachain(1002).into_versioned(), (71, Weight::zero(), 3)),
(XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)),
#[test]
fn get_and_wrap_version_works() {
new_test_ext_with_balances_and_xcm_version(vec![], None).execute_with(|| {
let remote_a: Location = Parachain(1000).into();
let remote_b: Location = Parachain(1001).into();
let remote_c: Location = Parachain(1002).into();
// no `safe_xcm_version` version at `GenesisConfig`
assert_eq!(XcmPallet::get_version_for(&remote_a), None);
assert_eq!(XcmPallet::get_version_for(&remote_b), None);
assert_eq!(XcmPallet::get_version_for(&remote_c), None);
assert_eq!(VersionDiscoveryQueue::<Test>::get().into_inner(), vec![]);
// set default XCM version (a.k.a. `safe_xcm_version`)
assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(1)));
assert_eq!(XcmPallet::get_version_for(&remote_a), None);
assert_eq!(XcmPallet::get_version_for(&remote_b), None);
assert_eq!(XcmPallet::get_version_for(&remote_c), None);
assert_eq!(VersionDiscoveryQueue::<Test>::get().into_inner(), vec![]);
// set XCM version only for `remote_a`
assert_ok!(XcmPallet::force_xcm_version(
RuntimeOrigin::root(),
XCM_VERSION
));
assert_eq!(XcmPallet::get_version_for(&remote_a), Some(XCM_VERSION));
assert_eq!(XcmPallet::get_version_for(&remote_b), None);
assert_eq!(XcmPallet::get_version_for(&remote_c), None);
assert_eq!(VersionDiscoveryQueue::<Test>::get().into_inner(), vec![]);
let xcm = Xcm::<()>::default();
// wrap version - works because remote_a has `XCM_VERSION`
assert_eq!(
XcmPallet::wrap_version(&remote_a, xcm.clone()),
Ok(VersionedXcm::from(xcm.clone()))
);
// does not work because remote_b has unknown version and default is set to 1, and
// `XCM_VERSION` cannot be wrapped to the `1`
assert_eq!(XcmPallet::wrap_version(&remote_b, xcm.clone()), Err(()));
assert_eq!(
VersionDiscoveryQueue::<Test>::get().into_inner(),
vec![(remote_b.clone().into(), 1)]
);
// set default to the `XCM_VERSION`
assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(XCM_VERSION)));
assert_eq!(XcmPallet::get_version_for(&remote_b), None);
assert_eq!(XcmPallet::get_version_for(&remote_c), None);
// now works, because default is `XCM_VERSION`
assert_eq!(
XcmPallet::wrap_version(&remote_b, xcm.clone()),
Ok(VersionedXcm::from(xcm.clone()))
);
assert_eq!(
VersionDiscoveryQueue::<Test>::get().into_inner(),
vec![(remote_b.clone().into(), 2)]
);
// change remote_c to `1`
assert_ok!(XcmPallet::force_xcm_version(
RuntimeOrigin::root(),
Box::new(remote_c.clone()),
1
));
// does not work because remote_c has `1` and default is `XCM_VERSION` which cannot be
// wrapped to the `1`
assert_eq!(XcmPallet::wrap_version(&remote_c, xcm.clone()), Err(()));
assert_eq!(VersionDiscoveryQueue::<Test>::get().into_inner(), vec![(remote_b.into(), 2)]);
})
}
Branislav Kontur
committed
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
#[test]
fn multistage_migration_works() {
new_test_ext_with_balances(vec![]).execute_with(|| {
// An entry from a previous runtime with v3 XCM.
let v3_location = VersionedLocation::V3(xcm::v3::Junction::Parachain(1001).into());
let v3_version = xcm::v3::VERSION;
SupportedVersion::<Test>::insert(v3_version, v3_location.clone(), v3_version);
VersionNotifiers::<Test>::insert(v3_version, v3_location.clone(), 1);
VersionNotifyTargets::<Test>::insert(
v3_version,
v3_location,
(70, Weight::zero(), v3_version),
);
// A version to advertise.
AdvertisedXcmVersion::set(4);
// check `try-state`
assert!(Pallet::<Test>::do_try_state().is_err());
// closure simulates a multistage migration process
let migrate = |expected_cycle_count| {
// A runtime upgrade which alters the version does send notifications.
CurrentMigration::<Test>::put(VersionMigrationStage::default());
let mut maybe_migration = CurrentMigration::<Test>::take();
let mut counter = 0;
let mut weight_used = Weight::zero();
while let Some(migration) = maybe_migration.take() {
counter += 1;
let (w, m) = XcmPallet::check_xcm_version_change(migration, Weight::zero());
maybe_migration = m;
weight_used.saturating_accrue(w);
}
assert_eq!(counter, expected_cycle_count);
weight_used
};
// run migration for the first time
let _ = migrate(4);
// check xcm sent
assert_eq!(
take_sent_xcm(),
vec![(
Parachain(1001).into(),
Xcm(vec![QueryResponse {
query_id: 70,
max_weight: Weight::zero(),
response: Response::Version(AdvertisedXcmVersion::get()),
querier: None,
}])
),]
);
// check migrated data
assert_eq!(
SupportedVersion::<Test>::iter().collect::<Vec<_>>(),
vec![(XCM_VERSION, Parachain(1001).into_versioned(), v3_version),]
);
assert_eq!(
VersionNotifiers::<Test>::iter().collect::<Vec<_>>(),
vec![(XCM_VERSION, Parachain(1001).into_versioned(), 1),]
);
assert_eq!(
VersionNotifyTargets::<Test>::iter().collect::<Vec<_>>(),
vec![(XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 4)),]
);
// run migration again to check it can run multiple time without any harm or double sending
// messages.
let weight_used = migrate(1);
assert_eq!(weight_used, 1_u8 * <Test as Config>::WeightInfo::already_notified_target());
// check no xcm sent
assert_eq!(take_sent_xcm(), vec![]);
// check `try-state`
assert!(Pallet::<Test>::do_try_state().is_ok());
})
}