Rococo & Westend People Chain (#2281)

Rococo and Westend runtimes for the "People Chain". This chain contains
the Identity pallet with plans to migrate all related data from the
Relay Chain.

Changes `IdentityInfo` to:

- Remove `additional_fields`.
- Add `github` and `discord` as first class fields. From scraping chain
data, these were the only two additional fields used (for the Fellowship
and Ambassador Program, respectively).
- Rename `riot` to `matrix`.

Note: This will use the script in
https://github.com/paritytech/polkadot-sdk/pull/2025 to generate the
genesis state.

TODO:

- [x] https://github.com/paritytech/polkadot-sdk/pull/1814 and
integration of the Identity Migrator pallet for migration.
- [x] Tests: https://github.com/paritytech/polkadot-sdk/pull/2373

---------

Co-authored-by: Muharem <ismailov.m.h@gmail.com>
Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com>
Co-authored-by: Dónal Murray <donal.murray@parity.io>
Co-authored-by: Richard Melkonian <35300528+0xmovses@users.noreply.github.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
This commit is contained in:
joe petrowski
2023-12-22 21:28:09 +01:00
committed by GitHub
parent 4c0e0e0713
commit ecbbb5a736
111 changed files with 12730 additions and 258 deletions
@@ -0,0 +1,38 @@
[package]
name = "people-rococo-integration-tests"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license = "Apache-2.0"
description = "People Rococo runtime integration tests with xcm-emulator"
publish = false
[dependencies]
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false }
assert_matches = "1.5.0"
# Substrate
sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false }
frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false }
pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false }
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false }
pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false }
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false }
pallet-identity = { path = "../../../../../../../substrate/frame/identity", default-features = false }
# Polkadot
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false }
pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false }
rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" }
rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants" }
polkadot-primitives = { path = "../../../../../../../polkadot/primitives" }
polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" }
# Cumulus
asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
parachains-common = { path = "../../../../../../parachains/common" }
people-rococo-runtime = { path = "../../../../../runtimes/people/people-rococo" }
emulated-integration-tests-common = { path = "../../../common", default-features = false }
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
rococo-system-emulated-network = { path = "../../../networks/rococo-system" }
@@ -0,0 +1,64 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub use codec::Encode;
// Substrate
pub use frame_support::{
assert_err, assert_ok,
pallet_prelude::Weight,
sp_runtime::{AccountId32, DispatchError, DispatchResult},
traits::fungibles::Inspect,
};
// Polkadot
pub use xcm::{
prelude::{AccountId32 as AccountId32Junction, *},
v3::{Error, NetworkId::Rococo as RococoId},
};
// Cumulus
pub use asset_test_utils::xcm_helpers;
pub use emulated_integration_tests_common::{
test_parachain_is_trusted_teleporter,
xcm_emulator::{
assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para,
RelayChain as Relay, Test, TestArgs, TestContext, TestExt,
},
xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution},
PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3,
};
pub use parachains_common::{AccountId, Balance};
pub use rococo_system_emulated_network::{
people_rococo_emulated_chain::{
genesis::ED as PEOPLE_ROCOCO_ED, PeopleRococoParaPallet as PeopleRococoPallet,
},
rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet},
PenpalAPara as PenpalA, PeopleRococoPara as PeopleRococo,
PeopleRococoParaReceiver as PeopleRococoReceiver, PeopleRococoParaSender as PeopleRococoSender,
RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver,
RococoRelaySender as RococoSender,
};
// pub const ASSET_ID: u32 = 1;
// pub const ASSET_MIN_BALANCE: u128 = 1000;
pub type RelayToSystemParaTest = Test<Rococo, PeopleRococo>;
pub type RelayToParaTest = Test<Rococo, PenpalA>;
pub type SystemParaToRelayTest = Test<PeopleRococo, Rococo>;
pub type SystemParaToParaTest = Test<PeopleRococo, PenpalA>;
pub type ParaToSystemParaTest = Test<PenpalA, PeopleRococo>;
#[cfg(test)]
mod tests;
@@ -0,0 +1,17 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod reap_identity;
mod teleport;
@@ -0,0 +1,549 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! # OnReapIdentity Tests
//!
//! This file contains the test cases for migrating Identity data away from the Rococo Relay
//! chain and to the PeopleRococo parachain. This migration is part of the broader Minimal Relay
//! effort:
//! https://github.com/polkadot-fellows/RFCs/blob/main/text/0032-minimal-relay.md
//!
//! ## Overview
//!
//! The tests validate the robustness and correctness of the `OnReapIdentityHandler`
//! ensuring that it behaves as expected in various scenarios. Key aspects tested include:
//!
//! - **Deposit Handling**: Confirming that deposits are correctly migrated from the Relay Chain to
//! the People parachain in various scenarios (different `IdentityInfo` fields and different
//! numbers of sub-accounts).
//!
//! ### Test Scenarios
//!
//! The tests are categorized into several scenarios, each resulting in different deposits required
//! on the destination parachain. The tests ensure:
//!
//! - Reserved deposits on the Relay Chain are fully released;
//! - The freed deposit from the Relay Chain is sufficient for the parachain deposit; and
//! - The account will exist on the parachain.
use crate::*;
use frame_support::BoundedVec;
use pallet_balances::Event as BalancesEvent;
use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent};
use people_rococo_runtime::people::{
BasicDeposit as BasicDepositParachain, ByteDeposit as ByteDepositParachain,
IdentityInfo as IdentityInfoParachain, SubAccountDeposit as SubAccountDepositParachain,
};
use rococo_runtime::{
BasicDeposit, ByteDeposit, MaxAdditionalFields, MaxSubAccounts, RuntimeOrigin as RococoOrigin,
SubAccountDeposit,
};
use rococo_runtime_constants::currency::*;
use rococo_system_emulated_network::{
rococo_emulated_chain::RococoRelayPallet, RococoRelay, RococoRelaySender,
};
type Balance = u128;
type RococoIdentity = <RococoRelay as RococoRelayPallet>::Identity;
type RococoBalances = <RococoRelay as RococoRelayPallet>::Balances;
type RococoIdentityMigrator = <RococoRelay as RococoRelayPallet>::IdentityMigrator;
type PeopleRococoIdentity = <PeopleRococo as PeopleRococoPallet>::Identity;
type PeopleRococoBalances = <PeopleRococo as PeopleRococoPallet>::Balances;
#[derive(Clone, Debug)]
struct Identity {
relay: IdentityInfo<MaxAdditionalFields>,
para: IdentityInfoParachain,
subs: Subs,
}
impl Identity {
fn new(
full: bool,
additional: Option<BoundedVec<(Data, Data), MaxAdditionalFields>>,
subs: Subs,
) -> Self {
let pgp_fingerprint = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC,
];
let make_data = |data: &[u8], full: bool| -> Data {
if full {
Data::Raw(data.to_vec().try_into().unwrap())
} else {
Data::None
}
};
let (github, discord) = additional
.as_ref()
.and_then(|vec| vec.get(0))
.map(|(g, d)| (g.clone(), d.clone()))
.unwrap_or((Data::None, Data::None));
Self {
relay: IdentityInfo {
display: make_data(b"xcm-test", full),
legal: make_data(b"The Xcm Test, Esq.", full),
web: make_data(b"https://xcm-test.io", full),
riot: make_data(b"xcm-riot", full),
email: make_data(b"xcm-test@gmail.com", full),
pgp_fingerprint: Some(pgp_fingerprint),
image: make_data(b"xcm-test.png", full),
twitter: make_data(b"@xcm-test", full),
additional: additional.unwrap_or_default(),
},
para: IdentityInfoParachain {
display: make_data(b"xcm-test", full),
legal: make_data(b"The Xcm Test, Esq.", full),
web: make_data(b"https://xcm-test.io", full),
matrix: make_data(b"xcm-matrix@server", full),
email: make_data(b"xcm-test@gmail.com", full),
pgp_fingerprint: Some(pgp_fingerprint),
image: make_data(b"xcm-test.png", full),
twitter: make_data(b"@xcm-test", full),
github,
discord,
},
subs,
}
}
}
#[derive(Clone, Debug)]
enum Subs {
Zero,
Many(u32),
}
enum IdentityOn<'a> {
Relay(&'a IdentityInfo<MaxAdditionalFields>),
Para(&'a IdentityInfoParachain),
}
impl IdentityOn<'_> {
fn calculate_deposit(self) -> Balance {
match self {
IdentityOn::Relay(id) => {
let base_deposit = BasicDeposit::get();
let byte_deposit =
ByteDeposit::get() * TryInto::<Balance>::try_into(id.encoded_size()).unwrap();
base_deposit + byte_deposit
},
IdentityOn::Para(id) => {
let base_deposit = BasicDepositParachain::get();
let byte_deposit = ByteDepositParachain::get() *
TryInto::<Balance>::try_into(id.encoded_size()).unwrap();
base_deposit + byte_deposit
},
}
}
}
/// Generate an `AccountId32` from a `u32`.
/// This creates a 32-byte array, initially filled with `255`, and then repeatedly fills it
/// with the 4-byte little-endian representation of the `u32` value, until the array is full.
///
/// **Example**:
///
/// `account_from_u32(5)` will return an `AccountId32` with the bytes
/// `[0, 5, 0, 0, 0, 0, 0, 0, 0, 5 ... ]`
fn account_from_u32(id: u32) -> AccountId32 {
let mut buffer = [255u8; 32];
let id_bytes = id.to_le_bytes();
let id_size = id_bytes.len();
for chunk in buffer.chunks_mut(id_size) {
chunk.clone_from_slice(&id_bytes);
}
AccountId32::new(buffer)
}
// Set up the Relay Chain with an identity.
fn set_id_relay(id: &Identity) -> Balance {
let mut total_deposit: Balance = 0;
// Set identity and Subs on Relay Chain
RococoRelay::execute_with(|| {
type RuntimeEvent = <RococoRelay as Chain>::RuntimeEvent;
assert_ok!(RococoIdentity::set_identity(
RococoOrigin::signed(RococoRelaySender::get()),
Box::new(id.relay.clone())
));
if let Subs::Many(n) = id.subs {
let subs: Vec<_> = (0..n)
.map(|i| (account_from_u32(i), Data::Raw(b"name".to_vec().try_into().unwrap())))
.collect();
assert_ok!(RococoIdentity::set_subs(
RococoOrigin::signed(RococoRelaySender::get()),
subs,
));
}
let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get());
let id_deposit = IdentityOn::Relay(&id.relay).calculate_deposit();
let total_deposit = match id.subs {
Subs::Zero => {
total_deposit = id_deposit; // No subs
assert_expected_events!(
RococoRelay,
vec![
RuntimeEvent::Identity(IdentityEvent::IdentitySet { .. }) => {},
RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => {
who: *who == RococoRelaySender::get(),
amount: *amount == id_deposit,
},
]
);
total_deposit
},
Subs::Many(n) => {
let sub_account_deposit = n as Balance * SubAccountDeposit::get();
total_deposit =
sub_account_deposit + IdentityOn::Relay(&id.relay).calculate_deposit();
assert_expected_events!(
RococoRelay,
vec![
RuntimeEvent::Identity(IdentityEvent::IdentitySet { .. }) => {},
RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => {
who: *who == RococoRelaySender::get(),
amount: *amount == id_deposit,
},
RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => {
who: *who == RococoRelaySender::get(),
amount: *amount == sub_account_deposit,
},
]
);
total_deposit
},
};
assert_eq!(reserved_balance, total_deposit);
});
total_deposit
}
// Set up the parachain with an identity and (maybe) sub accounts, but with zero deposits.
fn assert_set_id_parachain(id: &Identity) {
// Set identity and Subs on Parachain with zero deposit
PeopleRococo::execute_with(|| {
let free_bal = PeopleRococoBalances::free_balance(PeopleRococoSender::get());
let reserved_balance = PeopleRococoBalances::reserved_balance(PeopleRococoSender::get());
// total balance at Genesis should be zero
assert_eq!(reserved_balance + free_bal, 0);
assert_ok!(PeopleRococoIdentity::set_identity_no_deposit(
&PeopleRococoSender::get(),
id.para.clone(),
));
match id.subs {
Subs::Zero => {},
Subs::Many(n) => {
let subs: Vec<_> = (0..n)
.map(|ii| {
(account_from_u32(ii), Data::Raw(b"name".to_vec().try_into().unwrap()))
})
.collect();
assert_ok!(PeopleRococoIdentity::set_subs_no_deposit(
&PeopleRococoSender::get(),
subs,
));
},
}
// No amount should be reserved as deposit amounts are set to 0.
let reserved_balance = PeopleRococoBalances::reserved_balance(PeopleRococoSender::get());
assert_eq!(reserved_balance, 0);
assert!(PeopleRococoIdentity::identity(PeopleRococoSender::get()).is_some());
let (_, sub_accounts) = PeopleRococoIdentity::subs_of(PeopleRococoSender::get());
match id.subs {
Subs::Zero => assert_eq!(sub_accounts.len(), 0),
Subs::Many(n) => assert_eq!(sub_accounts.len(), n as usize),
}
});
}
// Reap the identity on the Relay Chain and assert that the correct things happen there.
fn assert_reap_id_relay(total_deposit: Balance, id: &Identity) {
RococoRelay::execute_with(|| {
type RuntimeEvent = <RococoRelay as Chain>::RuntimeEvent;
let free_bal_before_reap = RococoBalances::free_balance(RococoRelaySender::get());
let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get());
assert_eq!(reserved_balance, total_deposit);
assert_ok!(RococoIdentityMigrator::reap_identity(
RococoOrigin::root(),
RococoRelaySender::get()
));
let remote_deposit = match id.subs {
Subs::Zero => calculate_remote_deposit(id.relay.encoded_size() as u32, 0),
Subs::Many(n) => calculate_remote_deposit(id.relay.encoded_size() as u32, n),
};
assert_expected_events!(
RococoRelay,
vec![
// `reap_identity` sums the identity and subs deposits and unreserves them in one
// call. Therefore, we only expect one `Unreserved` event.
RuntimeEvent::Balances(BalancesEvent::Unreserved { who, amount }) => {
who: *who == RococoRelaySender::get(),
amount: *amount == total_deposit,
},
RuntimeEvent::IdentityMigrator(
polkadot_runtime_common::identity_migrator::Event::IdentityReaped {
who,
}) => {
who: *who == PeopleRococoSender::get(),
},
]
);
// Identity should be gone.
assert!(PeopleRococoIdentity::identity(RococoRelaySender::get()).is_none());
// Subs should be gone.
let (_, sub_accounts) = RococoIdentity::subs_of(RococoRelaySender::get());
assert_eq!(sub_accounts.len(), 0);
let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get());
assert_eq!(reserved_balance, 0);
// Free balance should be greater (i.e. the teleport should work even if 100% of an
// account's balance is reserved for Identity).
let free_bal_after_reap = RococoBalances::free_balance(RococoRelaySender::get());
assert!(free_bal_after_reap > free_bal_before_reap);
// Implicit: total_deposit > remote_deposit. As in, accounts should always have enough
// reserved for the parachain deposit.
assert_eq!(free_bal_after_reap, free_bal_before_reap + total_deposit - remote_deposit);
});
}
// Reaping the identity on the Relay Chain will have sent an XCM program to the parachain. Ensure
// that everything happens as expected.
fn assert_reap_parachain(id: &Identity) {
PeopleRococo::execute_with(|| {
let reserved_balance = PeopleRococoBalances::reserved_balance(PeopleRococoSender::get());
let id_deposit = IdentityOn::Para(&id.para).calculate_deposit();
let total_deposit = match id.subs {
Subs::Zero => id_deposit,
Subs::Many(n) => id_deposit + n as Balance * SubAccountDepositParachain::get(),
};
assert_reap_events(id_deposit, id);
assert_eq!(reserved_balance, total_deposit);
// Should have at least one ED after in free balance after the reap.
assert!(PeopleRococoBalances::free_balance(PeopleRococoSender::get()) >= PEOPLE_ROCOCO_ED);
});
}
// Assert the events that should happen on the parachain upon reaping an identity on the Relay
// Chain.
fn assert_reap_events(id_deposit: Balance, id: &Identity) {
type RuntimeEvent = <PeopleRococo as Chain>::RuntimeEvent;
match id.subs {
Subs::Zero => {
assert_expected_events!(
PeopleRococo,
vec![
// Deposit and Endowed from teleport
RuntimeEvent::Balances(BalancesEvent::Deposit { .. }) => {},
RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {},
// Amount reserved for identity info
RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => {
who: *who == PeopleRococoSender::get(),
amount: *amount == id_deposit,
},
// Confirmation from Migrator with individual identity and subs deposits
RuntimeEvent::IdentityMigrator(
polkadot_runtime_common::identity_migrator::Event::DepositUpdated {
who, identity, subs
}) => {
who: *who == PeopleRococoSender::get(),
identity: *identity == id_deposit,
subs: *subs == 0,
},
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { .. }) => {},
]
);
},
Subs::Many(n) => {
let subs_deposit = n as Balance * SubAccountDepositParachain::get();
assert_expected_events!(
PeopleRococo,
vec![
// Deposit and Endowed from teleport
RuntimeEvent::Balances(BalancesEvent::Deposit { .. }) => {},
RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {},
// Amount reserved for identity info
RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => {
who: *who == PeopleRococoSender::get(),
amount: *amount == id_deposit,
},
// Amount reserved for subs
RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => {
who: *who == PeopleRococoSender::get(),
amount: *amount == subs_deposit,
},
// Confirmation from Migrator with individual identity and subs deposits
RuntimeEvent::IdentityMigrator(
polkadot_runtime_common::identity_migrator::Event::DepositUpdated {
who, identity, subs
}) => {
who: *who == PeopleRococoSender::get(),
identity: *identity == id_deposit,
subs: *subs == subs_deposit,
},
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { .. }) => {},
]
);
},
};
}
/// Duplicate of the impl of `ToParachainIdentityReaper` in the Rococo runtime.
fn calculate_remote_deposit(bytes: u32, subs: u32) -> Balance {
// Note: These `deposit` functions and `EXISTENTIAL_DEPOSIT` correspond to the Relay Chain's.
// Pulled in: use rococo_runtime_constants::currency::*;
let para_basic_deposit = deposit(1, 17) / 100;
let para_byte_deposit = deposit(0, 1) / 100;
let para_sub_account_deposit = deposit(1, 53) / 100;
let para_existential_deposit = EXISTENTIAL_DEPOSIT / 10;
// pallet deposits
let id_deposit =
para_basic_deposit.saturating_add(para_byte_deposit.saturating_mul(bytes as Balance));
let subs_deposit = para_sub_account_deposit.saturating_mul(subs as Balance);
id_deposit
.saturating_add(subs_deposit)
.saturating_add(para_existential_deposit.saturating_mul(2))
}
// Represent some `additional` data that would not be migrated to the parachain. The encoded size,
// and thus the byte deposit, should decrease.
fn nonsensical_additional() -> BoundedVec<(Data, Data), MaxAdditionalFields> {
BoundedVec::try_from(vec![(
Data::Raw(b"fOo".to_vec().try_into().unwrap()),
Data::Raw(b"baR".to_vec().try_into().unwrap()),
)])
.unwrap()
}
// Represent some `additional` data that will be migrated to the parachain as first-class fields.
fn meaningful_additional() -> BoundedVec<(Data, Data), MaxAdditionalFields> {
BoundedVec::try_from(vec![
(
Data::Raw(b"github".to_vec().try_into().unwrap()),
Data::Raw(b"niels-username".to_vec().try_into().unwrap()),
),
(
Data::Raw(b"discord".to_vec().try_into().unwrap()),
Data::Raw(b"bohr-username".to_vec().try_into().unwrap()),
),
])
.unwrap()
}
// Execute a single test case.
fn assert_relay_para_flow(id: &Identity) {
let total_deposit = set_id_relay(id);
assert_set_id_parachain(id);
assert_reap_id_relay(total_deposit, id);
assert_reap_parachain(id);
}
// Tests with empty `IdentityInfo`.
#[test]
fn on_reap_identity_works_for_minimal_identity_with_zero_subs() {
assert_relay_para_flow(&Identity::new(false, None, Subs::Zero));
}
#[test]
fn on_reap_identity_works_for_minimal_identity() {
assert_relay_para_flow(&Identity::new(false, None, Subs::Many(1)));
}
#[test]
fn on_reap_identity_works_for_minimal_identity_with_max_subs() {
assert_relay_para_flow(&Identity::new(false, None, Subs::Many(MaxSubAccounts::get())));
}
// Tests with full `IdentityInfo`.
#[test]
fn on_reap_identity_works_for_full_identity_no_additional_zero_subs() {
assert_relay_para_flow(&Identity::new(true, None, Subs::Zero));
}
#[test]
fn on_reap_identity_works_for_full_identity_no_additional() {
assert_relay_para_flow(&Identity::new(true, None, Subs::Many(1)));
}
#[test]
fn on_reap_identity_works_for_full_identity_no_additional_max_subs() {
assert_relay_para_flow(&Identity::new(true, None, Subs::Many(MaxSubAccounts::get())));
}
// Tests with full `IdentityInfo` and `additional` fields that will _not_ be migrated.
#[test]
fn on_reap_identity_works_for_full_identity_nonsense_additional_zero_subs() {
assert_relay_para_flow(&Identity::new(true, Some(nonsensical_additional()), Subs::Zero));
}
#[test]
fn on_reap_identity_works_for_full_identity_nonsense_additional() {
assert_relay_para_flow(&Identity::new(true, Some(nonsensical_additional()), Subs::Many(1)));
}
#[test]
fn on_reap_identity_works_for_full_identity_nonsense_additional_max_subs() {
assert_relay_para_flow(&Identity::new(
true,
Some(nonsensical_additional()),
Subs::Many(MaxSubAccounts::get()),
));
}
// Tests with full `IdentityInfo` and `additional` fields that will be migrated.
#[test]
fn on_reap_identity_works_for_full_identity_meaningful_additional_zero_subs() {
assert_relay_para_flow(&Identity::new(true, Some(meaningful_additional()), Subs::Zero));
}
#[test]
fn on_reap_identity_works_for_full_identity_meaningful_additional() {
assert_relay_para_flow(&Identity::new(true, Some(meaningful_additional()), Subs::Many(1)));
}
#[test]
fn on_reap_identity_works_for_full_identity_meaningful_additional_max_subs() {
assert_relay_para_flow(&Identity::new(
true,
Some(meaningful_additional()),
Subs::Many(MaxSubAccounts::get()),
));
}
@@ -0,0 +1,260 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use people_rococo_runtime::xcm_config::XcmConfig as PeopleRococoXcmConfig;
use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(627_959_000, 7_200)));
assert_expected_events!(
Rococo,
vec![
// Amount to teleport is withdrawn from Sender
RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => {
who: *who == t.sender.account_id,
amount: *amount == t.args.amount,
},
// Amount to teleport is deposited in Relay's `CheckAccount`
RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => {
who: *who == <Rococo as RococoPallet>::XcmPallet::check_account(),
amount: *amount == t.args.amount,
},
]
);
}
fn relay_dest_assertions(t: SystemParaToRelayTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
Rococo::assert_ump_queue_processed(
true,
Some(PeopleRococo::para_id()),
Some(Weight::from_parts(304_266_000, 7_186)),
);
assert_expected_events!(
Rococo,
vec![
// Amount is withdrawn from Relay Chain's `CheckAccount`
RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => {
who: *who == <Rococo as RococoPallet>::XcmPallet::check_account(),
amount: *amount == t.args.amount,
},
// Amount minus fees are deposited in Receiver's account
RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => {
who: *who == t.receiver.account_id,
},
]
);
}
fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) {
Rococo::assert_ump_queue_processed(
false,
Some(PeopleRococo::para_id()),
Some(Weight::from_parts(157_718_000, 3_593)),
);
}
fn para_origin_assertions(t: SystemParaToRelayTest) {
type RuntimeEvent = <PeopleRococo as Chain>::RuntimeEvent;
PeopleRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
600_000_000,
7_000,
)));
PeopleRococo::assert_parachain_system_ump_sent();
assert_expected_events!(
PeopleRococo,
vec![
// Amount is withdrawn from Sender's account
RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => {
who: *who == t.sender.account_id,
amount: *amount == t.args.amount,
},
]
);
}
fn para_dest_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <PeopleRococo as Chain>::RuntimeEvent;
PeopleRococo::assert_dmp_queue_complete(Some(Weight::from_parts(162_456_000, 0)));
assert_expected_events!(
PeopleRococo,
vec![
// Amount minus fees are deposited in Receiver's account
RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => {
who: *who == t.receiver.account_id,
},
]
);
}
fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult {
<Rococo as RococoPallet>::XcmPallet::limited_teleport_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult {
<PeopleRococo as PeopleRococoPallet>::PolkadotXcm::limited_teleport_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
/// Limited Teleport of native asset from Relay Chain to the System Parachain should work
#[test]
fn limited_teleport_native_assets_from_relay_to_system_para_works() {
// Init values for Relay Chain
let amount_to_send: Balance = ROCOCO_ED * 1000;
let dest = Rococo::child_location_of(PeopleRococo::para_id());
let beneficiary_id = PeopleRococoReceiver::get();
let test_args = TestContext {
sender: RococoSender::get(),
receiver: PeopleRococoReceiver::get(),
args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<Rococo>(relay_origin_assertions);
test.set_assertion::<PeopleRococo>(para_dest_assertions);
test.set_dispatchable::<Rococo>(relay_limited_teleport_assets);
test.assert();
let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before);
}
/// Limited Teleport of native asset from System Parachain to Relay Chain
/// should work when there is enough balance in Relay Chain's `CheckAccount`
#[test]
fn limited_teleport_native_assets_back_from_system_para_to_relay_works() {
// Dependency - Relay Chain's `CheckAccount` should have enough balance
limited_teleport_native_assets_from_relay_to_system_para_works();
let amount_to_send: Balance = PEOPLE_ROCOCO_ED * 1000;
let destination = PeopleRococo::parent_location();
let beneficiary_id = RococoReceiver::get();
let assets = (Parent, amount_to_send).into();
// Fund a sender
PeopleRococo::fund_accounts(vec![(PeopleRococoSender::get(), ROCOCO_ED * 2_000u128)]);
let test_args = TestContext {
sender: PeopleRococoSender::get(),
receiver: RococoReceiver::get(),
args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0),
};
let mut test = SystemParaToRelayTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<PeopleRococo>(para_origin_assertions);
test.set_assertion::<Rococo>(relay_dest_assertions);
test.set_dispatchable::<PeopleRococo>(system_para_limited_teleport_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
let delivery_fees = PeopleRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<PeopleRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before);
}
/// Limited Teleport of native asset from System Parachain to Relay Chain
/// should't work when there is not enough balance in Relay Chain's `CheckAccount`
#[test]
fn limited_teleport_native_assets_from_system_para_to_relay_fails() {
// Init values for Relay Chain
let amount_to_send: Balance = ROCOCO_ED * 1000;
let destination = PeopleRococo::parent_location();
let beneficiary_id = RococoReceiver::get();
let assets = (Parent, amount_to_send).into();
// Fund a sender
PeopleRococo::fund_accounts(vec![(PeopleRococoSender::get(), ROCOCO_ED * 2_000u128)]);
let test_args = TestContext {
sender: PeopleRococoSender::get(),
receiver: RococoReceiver::get(),
args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0),
};
let mut test = SystemParaToRelayTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<PeopleRococo>(para_origin_assertions);
test.set_assertion::<Rococo>(relay_dest_assertions_fail);
test.set_dispatchable::<PeopleRococo>(system_para_limited_teleport_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
let delivery_fees = PeopleRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<PeopleRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance does not change
assert_eq!(receiver_balance_after, receiver_balance_before);
}