From ee54e62c901f5906b6f8ffd4f86e73ca8b741f7c Mon Sep 17 00:00:00 2001 From: Branislav Kontur <bkontur@gmail.com> Date: Thu, 3 Aug 2023 10:32:49 +0200 Subject: [PATCH] [xcm] `GlobalConsensusConvertsFor` for remote relay chain (based on pevious GlobalConsensusParachainConvertsFor) (#7517) * [xcm] `GlobalConsensusConvertsFor` for remote relay chain (based on previous GlobalConsensusParachainConvertsFor) * Typo * PR fix (constants in test) * Re-export of `GlobalConsensusConvertsFor` * assert to panic * Update xcm/src/v3/multiasset.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update xcm/xcm-builder/src/location_conversion.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update xcm/xcm-builder/src/location_conversion.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Review fixes --------- Co-authored-by: parity-processbot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- polkadot/xcm/src/v3/multiasset.rs | 2 +- polkadot/xcm/xcm-builder/src/lib.rs | 5 +- .../xcm-builder/src/location_conversion.rs | 135 ++++++++++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index a7a658f0601..a4900a71539 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -406,7 +406,7 @@ pub struct MultiAsset { /// The overall asset identity (aka *class*, in the case of a non-fungible). pub id: AssetId, /// The fungibility of the asset, which contains either the amount (in the case of a fungible - /// asset) or the *instance ID`, the secondary asset identifier. + /// asset) or the *instance ID*, the secondary asset identifier. pub fun: Fungibility, } diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 984ace84dc6..e3f91040963 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -33,8 +33,9 @@ pub use location_conversion::{ Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32, ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal, DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeFamily, DescribeLocation, - DescribePalletTerminal, DescribeTerminus, GlobalConsensusParachainConvertsFor, - HashedDescription, ParentIsPreset, SiblingParachainConvertsVia, + DescribePalletTerminal, DescribeTerminus, GlobalConsensusConvertsFor, + GlobalConsensusParachainConvertsFor, HashedDescription, ParentIsPreset, + SiblingParachainConvertsVia, }; mod origin_conversion; diff --git a/polkadot/xcm/xcm-builder/src/location_conversion.rs b/polkadot/xcm/xcm-builder/src/location_conversion.rs index 3a95884328a..ccc3cc040e6 100644 --- a/polkadot/xcm/xcm-builder/src/location_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/location_conversion.rs @@ -345,6 +345,42 @@ impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]> } } +/// Converts a location which is a top-level relay chain (which provides its own consensus) into a 32-byte `AccountId`. +/// +/// This will always result in the *same account ID* being returned for the same Relay-chain, regardless of the relative security of +/// this Relay-chain compared to the local chain. +/// +/// Note: No distinction is made between the cases when the given `UniversalLocation` lies within +/// the same consensus system (i.e. is itself or a parent) and when it is a foreign consensus +/// system. +pub struct GlobalConsensusConvertsFor<UniversalLocation, AccountId>( + PhantomData<(UniversalLocation, AccountId)>, +); +impl<UniversalLocation: Get<InteriorMultiLocation>, AccountId: From<[u8; 32]> + Clone> + ConvertLocation<AccountId> for GlobalConsensusConvertsFor<UniversalLocation, AccountId> +{ + fn convert_location(location: &MultiLocation) -> Option<AccountId> { + let universal_source = UniversalLocation::get(); + log::trace!( + target: "xcm::location_conversion", + "GlobalConsensusConvertsFor universal_source: {:?}, location: {:?}", + universal_source, location, + ); + let (remote_network, remote_location) = + ensure_is_remote(universal_source, *location).ok()?; + + match remote_location { + Here => Some(AccountId::from(Self::from_params(&remote_network))), + _ => None, + } + } +} +impl<UniversalLocation, AccountId> GlobalConsensusConvertsFor<UniversalLocation, AccountId> { + fn from_params(network: &NetworkId) -> [u8; 32] { + (b"glblcnsnss_", network).using_encoded(blake2_256) + } +} + /// Converts a location which is a top-level parachain (i.e. a parachain held on a /// Relay-chain which provides its own consensus) into a 32-byte `AccountId`. /// @@ -473,6 +509,105 @@ mod tests { assert_eq!(inverted, Err(())); } + #[test] + fn global_consensus_converts_for_works() { + parameter_types! { + pub UniversalLocationInNetwork1: InteriorMultiLocation = X2(GlobalConsensus(ByGenesis([1; 32])), Parachain(1234)); + pub UniversalLocationInNetwork2: InteriorMultiLocation = X2(GlobalConsensus(ByGenesis([2; 32])), Parachain(1234)); + } + let network_1 = UniversalLocationInNetwork1::get().global_consensus().expect("NetworkId"); + let network_2 = UniversalLocationInNetwork2::get().global_consensus().expect("NetworkId"); + let network_3 = ByGenesis([3; 32]); + let network_4 = ByGenesis([4; 32]); + let network_5 = ByGenesis([5; 32]); + + let test_data = vec![ + (MultiLocation::parent(), false), + (MultiLocation::new(0, Here), false), + (MultiLocation::new(0, X1(GlobalConsensus(network_1))), false), + (MultiLocation::new(1, X1(GlobalConsensus(network_1))), false), + (MultiLocation::new(2, X1(GlobalConsensus(network_1))), false), + (MultiLocation::new(0, X1(GlobalConsensus(network_2))), false), + (MultiLocation::new(1, X1(GlobalConsensus(network_2))), false), + (MultiLocation::new(2, X1(GlobalConsensus(network_2))), true), + (MultiLocation::new(0, X2(GlobalConsensus(network_2), Parachain(1000))), false), + (MultiLocation::new(1, X2(GlobalConsensus(network_2), Parachain(1000))), false), + (MultiLocation::new(2, X2(GlobalConsensus(network_2), Parachain(1000))), false), + ]; + + for (location, expected_result) in test_data { + let result = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location( + &location, + ); + match result { + Some(account) => { + assert_eq!( + true, expected_result, + "expected_result: {}, but conversion passed: {:?}, location: {:?}", + expected_result, account, location + ); + match &location { + MultiLocation { interior: X1(GlobalConsensus(network)), .. } => + assert_eq!( + account, + GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::from_params(network), + "expected_result: {}, but conversion passed: {:?}, location: {:?}", expected_result, account, location + ), + _ => panic!("expected_result: {}, conversion passed: {:?}, but MultiLocation does not match expected pattern, location: {:?}", expected_result, account, location) + } + }, + None => { + assert_eq!( + false, expected_result, + "expected_result: {} - but conversion failed, location: {:?}", + expected_result, location + ); + }, + } + } + + // all success + let res_1_gc_network_3 = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location( + &MultiLocation::new(2, X1(GlobalConsensus(network_3))), + ) + .expect("conversion is ok"); + let res_2_gc_network_3 = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location( + &MultiLocation::new(2, X1(GlobalConsensus(network_3))), + ) + .expect("conversion is ok"); + let res_1_gc_network_4 = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location( + &MultiLocation::new(2, X1(GlobalConsensus(network_4))), + ) + .expect("conversion is ok"); + let res_2_gc_network_4 = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location( + &MultiLocation::new(2, X1(GlobalConsensus(network_4))), + ) + .expect("conversion is ok"); + let res_1_gc_network_5 = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location( + &MultiLocation::new(2, X1(GlobalConsensus(network_5))), + ) + .expect("conversion is ok"); + let res_2_gc_network_5 = + GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location( + &MultiLocation::new(2, X1(GlobalConsensus(network_5))), + ) + .expect("conversion is ok"); + + assert_ne!(res_1_gc_network_3, res_1_gc_network_4); + assert_ne!(res_1_gc_network_4, res_1_gc_network_5); + assert_ne!(res_1_gc_network_3, res_1_gc_network_5); + + assert_eq!(res_1_gc_network_3, res_2_gc_network_3); + assert_eq!(res_1_gc_network_4, res_2_gc_network_4); + assert_eq!(res_1_gc_network_5, res_2_gc_network_5); + } + #[test] fn global_consensus_parachain_converts_for_works() { parameter_types! { -- GitLab