diff --git a/Cargo.lock b/Cargo.lock index b3117086cc..02c6d0e8ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9586,6 +9586,7 @@ dependencies = [ "emulated-integration-tests-common", "frame-support", "kusama-emulated-chain", + "kusama-runtime-constants", "parachains-common", "people-kusama-runtime", "sp-core 34.0.0", @@ -9696,6 +9697,7 @@ dependencies = [ "parachains-common", "people-polkadot-runtime", "polkadot-emulated-chain", + "polkadot-runtime-constants", "sp-core 34.0.0", ] diff --git a/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml index a72f24e626..f6bb6403ee 100644 --- a/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml +++ b/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml @@ -18,6 +18,9 @@ parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } +# Runtimes +kusama-runtime-constants = { workspace = true, default-features = true } + # Local people-kusama-runtime = { workspace = true } kusama-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs index 6e034d6ebf..cca03c7d8e 100644 --- a/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs +++ b/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs @@ -18,14 +18,21 @@ use sp_core::storage::Storage; // Cumulus use cumulus_primitives_core::ParaId; -use emulated_integration_tests_common::{build_genesis_storage, collators, SAFE_XCM_VERSION}; +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; +use kusama_runtime_constants::currency::UNITS as KSM; use parachains_common::Balance; +const ENDOWMENT: u128 = 1_000 * KSM; pub const PARA_ID: u32 = 1004; pub const ED: Balance = people_kusama_runtime::ExistentialDeposit::get(); pub fn genesis() -> Storage { let genesis_config = people_kusama_runtime::RuntimeGenesisConfig { + balances: people_kusama_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ENDOWMENT)).collect(), + }, system: people_kusama_runtime::SystemConfig::default(), parachain_info: people_kusama_runtime::ParachainInfoConfig { parachain_id: ParaId::from(PARA_ID), diff --git a/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml index 8649747813..6414084696 100644 --- a/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml +++ b/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml @@ -18,6 +18,9 @@ parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } +# Runtimes +polkadot-runtime-constants = { workspace = true, default-features = true } + # Local people-polkadot-runtime = { workspace = true } polkadot-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs index 93c6788ebb..177eaa64e2 100644 --- a/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs +++ b/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs @@ -18,14 +18,21 @@ use sp_core::storage::Storage; // Cumulus use cumulus_primitives_core::ParaId; -use emulated_integration_tests_common::{build_genesis_storage, collators, SAFE_XCM_VERSION}; +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; use parachains_common::Balance; +use polkadot_runtime_constants::currency::UNITS as DOT; +const ENDOWMENT: u128 = 1_000 * DOT; pub const PARA_ID: u32 = 1004; pub const ED: Balance = people_polkadot_runtime::ExistentialDeposit::get(); pub fn genesis() -> Storage { let genesis_config = people_polkadot_runtime::RuntimeGenesisConfig { + balances: people_polkadot_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ENDOWMENT)).collect(), + }, system: people_polkadot_runtime::SystemConfig::default(), parachain_info: people_polkadot_runtime::ParachainInfoConfig { parachain_id: ParaId::from(PARA_ID), diff --git a/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs b/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs index 8d06089947..be3b18acf9 100644 --- a/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs +++ b/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs @@ -14,8 +14,13 @@ // limitations under the License. use crate::*; -use frame_support::sp_runtime::traits::Dispatchable; +use emulated_integration_tests_common::accounts::{ALICE, BOB}; + +use frame_support::{sp_runtime::traits::Dispatchable, traits::ProcessMessageError}; use kusama_runtime::governance::pallet_custom_origins::Origin::GeneralAdmin as GeneralAdminOrigin; +use people_kusama_runtime::people::IdentityInfo; + +use pallet_identity::Data; #[test] fn relay_commands_add_registrar() { @@ -43,6 +48,9 @@ fn relay_commands_add_registrar() { UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind, + // TODO: + // This and the below weight data in the XCM can be removed once XCMv5 is + // used. require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), call: add_registrar_call.encode().into(), } @@ -72,3 +80,456 @@ fn relay_commands_add_registrar() { }); } } + +#[test] +fn relay_commands_add_registrar_wrong_origin() { + let people_kusama_alice = PeopleKusama::account_id_of(ALICE); + + let (origin_kind, origin) = ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_kusama_alice), + ); + + let registrar: AccountId = [1; 32].into(); + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let add_registrar_call = + PeopleCall::Identity(pallet_identity::Call::::add_registrar { + account: registrar.into(), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), + call: add_registrar_call.encode().into(), + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_kill_identity() { + // To kill an identity, first one must be set + PeopleKusama::execute_with(|| { + type PeopleRuntime = ::Runtime; + type PeopleRuntimeEvent = ::RuntimeEvent; + + let people_kusama_alice = + ::RuntimeOrigin::signed(PeopleKusama::account_id_of(ALICE)); + + let identity_info = IdentityInfo { + email: Data::Raw(b"test@test.io".to_vec().try_into().unwrap()), + ..Default::default() + }; + let identity: Box<::IdentityInformation> = + Box::new(identity_info); + + assert_ok!(::Identity::set_identity( + people_kusama_alice, + identity + )); + + assert_expected_events!( + PeopleKusama, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::IdentitySet { .. }) => {}, + ] + ); + }); + + let (origin_kind, origin) = (OriginKind::Superuser, ::RuntimeOrigin::root()); + + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type PeopleCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleRuntime = ::Runtime; + + let kill_identity_call = + PeopleCall::Identity(pallet_identity::Call::::kill_identity { + target: people_kusama_runtime::MultiAddress::Id(PeopleKusama::account_id_of(ALICE)), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + // Making the weight's ref time any lower will prevent the XCM from triggering + // execution of the intended extrinsic on the People chain - beware of spurious + // test failure due to this. + require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), + call: kill_identity_call.encode().into(), + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::IdentityKilled { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_kill_identity_wrong_origin() { + let people_kusama_alice = PeopleKusama::account_id_of(BOB); + + let (origin_kind, origin) = ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_kusama_alice), + ); + + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type PeopleCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleRuntime = ::Runtime; + + let kill_identity_call = + PeopleCall::Identity(pallet_identity::Call::::kill_identity { + target: people_kusama_runtime::MultiAddress::Id(PeopleKusama::account_id_of(ALICE)), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), + call: kill_identity_call.encode().into(), + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_add_remove_username_authority() { + let people_kusama_alice = PeopleKusama::account_id_of(ALICE); + let people_kusama_bob = PeopleKusama::account_id_of(BOB); + + let origins = vec![ + (OriginKind::Xcm, GeneralAdminOrigin.into(), "generaladmin"), + (OriginKind::Superuser, ::RuntimeOrigin::root(), "rootusername"), + ]; + for (origin_kind, origin, usr) in origins { + // First, add a username authority. + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let add_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::add_username_authority { + authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), + suffix: b"suffix1".into(), + allocation: 10, + }); + + let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: add_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(add_authority_xcm_msg.dispatch(origin.clone())); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Check events system-parachain-side + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::AuthorityAdded { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); + + // Now, use the previously added username authority to concede a username to an account. + PeopleKusama::execute_with(|| { + type PeopleRuntimeEvent = ::RuntimeEvent; + + assert_ok!(::Identity::set_username_for( + ::RuntimeOrigin::signed(people_kusama_alice.clone()), + people_kusama_runtime::MultiAddress::Id(people_kusama_bob.clone()), + usr.to_owned().into_bytes(), + None, + )); + + assert_expected_events!( + PeopleKusama, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameQueued { .. }) => {}, + ] + ); + }); + + // Accept the given username + PeopleKusama::execute_with(|| { + type PeopleRuntimeEvent = ::RuntimeEvent; + let full_username = [usr.to_owned(), ".suffix1".to_owned()].concat().into_bytes(); + + assert_ok!(::Identity::accept_username( + ::RuntimeOrigin::signed(people_kusama_bob.clone()), + full_username.try_into().unwrap(), + )); + + assert_expected_events!( + PeopleKusama, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameSet { .. }) => {}, + ] + ); + }); + + // Now, remove the username authority with another privileged XCM call. + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::remove_username_authority { + authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), + }); + + let remove_authority_xcm_msg = + RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + // TODO: + // this and all other references to `require_weight_at_most` can be + // removed once XCMv5 is in use. + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: remove_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(remove_authority_xcm_msg.dispatch(origin)); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Final event check. + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::AuthorityRemoved { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); + } +} + +#[test] +fn relay_commands_add_remove_username_authority_wrong_origin() { + let people_kusama_alice = PeopleKusama::account_id_of(ALICE); + + let (origin_kind, origin) = ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_kusama_alice.clone()), + ); + + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let add_username_authority = + PeopleCall::Identity(pallet_identity::Call::::add_username_authority { + authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), + suffix: b"suffix1".into(), + allocation: 10, + }); + + let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: add_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(add_authority_xcm_msg.dispatch(origin)); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Check events system-parachain-side + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); + + // Since the origin check is the very first instruction in `remove_username_authority`, an + // authority need not exist to test the safety of the origin check. + Kusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::remove_username_authority { + authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), + }); + + let remove_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: remove_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(remove_authority_xcm_msg + .dispatch(::RuntimeOrigin::signed(people_kusama_alice))); + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleKusama::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleKusama, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); +} diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs b/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs index 11ebf954a3..4c3ac649a9 100644 --- a/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs +++ b/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs @@ -14,9 +14,14 @@ // limitations under the License. use crate::*; -use frame_support::sp_runtime::traits::Dispatchable; +use emulated_integration_tests_common::accounts::{ALICE, BOB}; + +use frame_support::{sp_runtime::traits::Dispatchable, traits::ProcessMessageError}; +use people_polkadot_runtime::people::IdentityInfo; use polkadot_runtime::governance::pallet_custom_origins::Origin::GeneralAdmin as GeneralAdminOrigin; +use pallet_identity::Data; + #[test] fn relay_commands_add_registrar() { let origins = vec![ @@ -72,3 +77,457 @@ fn relay_commands_add_registrar() { }); } } + +#[test] +fn relay_commands_add_registrar_wrong_origin() { + let people_polkadot_alice = PeoplePolkadot::account_id_of(ALICE); + + let (origin_kind, origin) = ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_polkadot_alice), + ); + + let registrar: AccountId = [1; 32].into(); + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let add_registrar_call = + PeopleCall::Identity(pallet_identity::Call::::add_registrar { + account: registrar.into(), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), + call: add_registrar_call.encode().into(), + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_kill_identity() { + // To kill an identity, first one must be set + PeoplePolkadot::execute_with(|| { + type PeopleRuntime = ::Runtime; + type PeopleRuntimeEvent = ::RuntimeEvent; + + let people_polkadot_alice = + ::RuntimeOrigin::signed(PeoplePolkadot::account_id_of(ALICE)); + + let identity_info = IdentityInfo { + email: Data::Raw(b"test@test.io".to_vec().try_into().unwrap()), + ..Default::default() + }; + let identity: Box<::IdentityInformation> = + Box::new(identity_info); + + assert_ok!(::Identity::set_identity( + people_polkadot_alice, + identity + )); + + assert_expected_events!( + PeoplePolkadot, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::IdentitySet { .. }) => {}, + ] + ); + }); + + let (origin_kind, origin) = (OriginKind::Superuser, ::RuntimeOrigin::root()); + + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type PeopleCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleRuntime = ::Runtime; + + let kill_identity_call = + PeopleCall::Identity(pallet_identity::Call::::kill_identity { + target: people_polkadot_runtime::MultiAddress::Id(PeoplePolkadot::account_id_of( + ALICE, + )), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + // Making the weight's ref time any lower will prevent the XCM from triggering + // execution of the intended extrinsic on the People chain - beware of spurious + // test failure due to this. + require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), + call: kill_identity_call.encode().into(), + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::IdentityKilled { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_kill_identity_wrong_origin() { + let people_polkadot_alice = PeoplePolkadot::account_id_of(BOB); + + let (origin_kind, origin) = ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_polkadot_alice), + ); + + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type PeopleCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleRuntime = ::Runtime; + + let kill_identity_call = + PeopleCall::Identity(pallet_identity::Call::::kill_identity { + target: people_polkadot_runtime::MultiAddress::Id(PeoplePolkadot::account_id_of( + ALICE, + )), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), + call: kill_identity_call.encode().into(), + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_add_remove_username_authority() { + let people_polkadot_alice = PeoplePolkadot::account_id_of(ALICE); + let people_polkadot_bob = PeoplePolkadot::account_id_of(BOB); + + let origins = vec![ + (OriginKind::Xcm, GeneralAdminOrigin.into(), "generaladmin"), + (OriginKind::Superuser, ::RuntimeOrigin::root(), "rootusername"), + ]; + for (origin_kind, origin, usr) in origins { + // First, add a username authority. + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let add_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::add_username_authority { + authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), + suffix: b"suffix1".into(), + allocation: 10, + }); + + let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: add_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(add_authority_xcm_msg.dispatch(origin.clone())); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Check events system-parachain-side + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::AuthorityAdded { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); + + // Now, use the previously added username authority to concede a username to an account. + PeoplePolkadot::execute_with(|| { + type PeopleRuntimeEvent = ::RuntimeEvent; + + assert_ok!(::Identity::set_username_for( + ::RuntimeOrigin::signed(people_polkadot_alice.clone()), + people_polkadot_runtime::MultiAddress::Id(people_polkadot_bob.clone()), + usr.to_owned().into_bytes(), + None, + )); + + assert_expected_events!( + PeoplePolkadot, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameQueued { .. }) => {}, + ] + ); + }); + + // Accept the given username + PeoplePolkadot::execute_with(|| { + type PeopleRuntimeEvent = ::RuntimeEvent; + let full_username = [usr.to_owned(), ".suffix1".to_owned()].concat().into_bytes(); + + assert_ok!(::Identity::accept_username( + ::RuntimeOrigin::signed(people_polkadot_bob.clone()), + full_username.try_into().unwrap(), + )); + + assert_expected_events!( + PeoplePolkadot, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameSet { .. }) => {}, + ] + ); + }); + + // Now, remove the username authority with another privileged XCM call. + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::remove_username_authority { + authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), + }); + + let remove_authority_xcm_msg = + RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: remove_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(remove_authority_xcm_msg.dispatch(origin)); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Final event check. + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::AuthorityRemoved { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); + } +} + +#[test] +fn relay_commands_add_remove_username_authority_wrong_origin() { + let people_polkadot_alice = PeoplePolkadot::account_id_of(ALICE); + + let (origin_kind, origin) = ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_polkadot_alice.clone()), + ); + + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let add_username_authority = + PeopleCall::Identity(pallet_identity::Call::::add_username_authority { + authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), + suffix: b"suffix1".into(), + allocation: 10, + }); + + let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: add_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(add_authority_xcm_msg.dispatch(origin)); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Check events system-parachain-side + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); + + // Since the origin check is the very first instruction in `remove_username_authority`, + // an authority need not exist to test the safety of the origin check. + Polkadot::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::remove_username_authority { + authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), + }); + + let remove_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: Weight::from_parts(500_000_000, 500_000), + call: remove_username_authority.encode().into(), + } + ]))), + }); + + assert_ok!(remove_authority_xcm_msg + .dispatch(::RuntimeOrigin::signed(people_polkadot_alice))); + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeoplePolkadot::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeoplePolkadot, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + }); +}