diff --git a/Cargo.lock b/Cargo.lock index d34c4ff2..1f9678a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8771,14 +8771,17 @@ name = "primitives" version = "1.0.0" dependencies = [ "frame-support", + "impl-trait-for-tuples", "orml-traits", "parity-scale-codec", "scale-info", "sp-consensus-aura", "sp-core", + "sp-io", "sp-runtime", "sp-std", "xcm", + "xcm-executor", ] [[package]] diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 6df79612..1d538efe 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -9,6 +9,7 @@ repository = 'https://github.com/OAK-Foundation/OAK-blockchain' edition = "2021" [dependencies] +impl-trait-for-tuples = "0.2.2" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ], default-features = false } @@ -22,12 +23,14 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" } ## Substrate FRAME Dependencies frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" } ## Polkdadot deps xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.43" } ## ORML deps orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.43" } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index fee2c132..891ab3fa 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -94,3 +94,118 @@ impl> Reserve }) } } + +// https://github.com/AstarNetwork/Astar/blob/2a8df8d098f6abc3fdf5aaf6514e94f615f9bdab/primitives/src/xcm/mod.rs#L276-L418 +// TODO: remove this after uplift to `polkadot-v0.9.44` or beyond, and replace it with code in XCM builder. + +use codec::{Compact, Encode}; +use sp_io::hashing::blake2_256; +use sp_std::prelude::*; +use xcm_executor::traits::Convert as XcmConvert; + +/// Means of converting a location into a stable and unique descriptive identifier. +pub trait DescribeLocation { + /// Create a description of the given `location` if possible. No two locations should have the + /// same descriptor. + fn describe_location(location: &MultiLocation) -> Option>; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl DescribeLocation for Tuple { + fn describe_location(l: &MultiLocation) -> Option> { + for_tuples!( #( + match Tuple::describe_location(l) { + Some(result) => return Some(result), + None => {}, + } + )* ); + None + } +} + +pub struct DescribeTerminus; +impl DescribeLocation for DescribeTerminus { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, &l.interior) { + (0, Here) => Some(Vec::new()), + _ => return None, + } + } +} + +pub struct DescribePalletTerminal; +impl DescribeLocation for DescribePalletTerminal { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, &l.interior) { + (0, X1(PalletInstance(i))) => + Some((b"Pallet", Compact::::from(*i as u32)).encode()), + _ => return None, + } + } +} + +pub struct DescribeAccountId32Terminal; +impl DescribeLocation for DescribeAccountId32Terminal { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, &l.interior) { + (0, X1(AccountId32 { id, .. })) => Some((b"AccountId32", id).encode()), + _ => return None, + } + } +} + +pub struct DescribeAccountKey20Terminal; +impl DescribeLocation for DescribeAccountKey20Terminal { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, &l.interior) { + (0, X1(AccountKey20 { key, .. })) => Some((b"AccountKey20", key).encode()), + _ => return None, + } + } +} + +pub type DescribeAccountIdTerminal = (DescribeAccountId32Terminal, DescribeAccountKey20Terminal); + +pub type DescribeAllTerminal = ( + DescribeTerminus, + DescribePalletTerminal, + DescribeAccountId32Terminal, + DescribeAccountKey20Terminal, +); + +pub struct DescribeFamily(PhantomData); +impl DescribeLocation for DescribeFamily { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, l.interior.first()) { + (0, Some(Parachain(index))) => { + let tail = l.interior.split_first().0; + let interior = Suffix::describe_location(&tail.into())?; + Some((b"ChildChain", Compact::::from(*index), interior).encode()) + }, + (1, Some(Parachain(index))) => { + let tail = l.interior.split_first().0; + let interior = Suffix::describe_location(&tail.into())?; + Some((b"SiblingChain", Compact::::from(*index), interior).encode()) + }, + (1, _) => { + let tail = l.interior.into(); + let interior = Suffix::describe_location(&tail)?; + Some((b"ParentChain", interior).encode()) + }, + _ => return None, + } + } +} + +pub struct HashedDescription(PhantomData<(AccountId, Describe)>); +impl + Clone, Describe: DescribeLocation> + XcmConvert for HashedDescription +{ + fn convert(value: MultiLocation) -> Result { + if let Some(description) = Describe::describe_location(&value) { + Ok(blake2_256(&description).into()) + } else { + Err(value) + } + } +} diff --git a/runtime/neumann/src/xcm_config.rs b/runtime/neumann/src/xcm_config.rs index ef751ed1..f5f16dab 100644 --- a/runtime/neumann/src/xcm_config.rs +++ b/runtime/neumann/src/xcm_config.rs @@ -36,7 +36,9 @@ use orml_xcm_support::{ DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset, }; -use primitives::AbsoluteAndRelativeReserveProvider; +use primitives::{ + AbsoluteAndRelativeReserveProvider, DescribeAllTerminal, DescribeFamily, HashedDescription, +}; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); @@ -55,7 +57,9 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, - Account32Hash, + // Generates private `AccountId`s from `MultiLocation`s, in a stable & safe way. + // Replaces the old `Account32Hash` approach. + HashedDescription>, ); pub type LocalAssetTransactor = MultiCurrencyAdapter< diff --git a/runtime/oak/src/xcm_config.rs b/runtime/oak/src/xcm_config.rs index 34c0bef7..18973a51 100644 --- a/runtime/oak/src/xcm_config.rs +++ b/runtime/oak/src/xcm_config.rs @@ -38,7 +38,9 @@ use orml_xcm_support::{ DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset, }; -use primitives::AbsoluteAndRelativeReserveProvider; +use primitives::{ + AbsoluteAndRelativeReserveProvider, DescribeAllTerminal, DescribeFamily, HashedDescription, +}; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); @@ -57,7 +59,9 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, - Account32Hash, + // Generates private `AccountId`s from `MultiLocation`s, in a stable & safe way. + // Replaces the old `Account32Hash` approach. + HashedDescription>, ); pub type LocalAssetTransactor = MultiCurrencyAdapter< diff --git a/runtime/turing/src/xcm_config.rs b/runtime/turing/src/xcm_config.rs index a0915481..c2634638 100644 --- a/runtime/turing/src/xcm_config.rs +++ b/runtime/turing/src/xcm_config.rs @@ -37,7 +37,9 @@ use orml_xcm_support::{ DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset, }; -use primitives::AbsoluteAndRelativeReserveProvider; +use primitives::{ + AbsoluteAndRelativeReserveProvider, DescribeAllTerminal, DescribeFamily, HashedDescription, +}; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); @@ -57,7 +59,9 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, - Account32Hash, + // Generates private `AccountId`s from `MultiLocation`s, in a stable & safe way. + // Replaces the old `Account32Hash` approach. + HashedDescription>, ); pub type LocalAssetTransactor = MultiCurrencyAdapter<