mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 21:31:02 +00:00
[xcm] Foreign global consensus parachain LocationToAccountId converter (#7016)
* **Foreign** global consensus parachain LocationToAccount converter * Review fix * Added `UniversalLocation` + `ensure_is_remote` handling * Added unique id to encoding * Update xcm/xcm-builder/src/location_conversion.rs Co-authored-by: Gavin Wood <gavin@parity.io> * Re-export `ensure_is_remote` * Test * fmt * Update xcm/xcm-builder/src/location_conversion.rs * Update xcm/xcm-builder/src/universal_exports.rs Co-authored-by: Gavin Wood <gavin@parity.io> --------- Co-authored-by: parity-processbot <> Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
@@ -84,7 +84,7 @@ pub use filter_asset_location::{Case, NativeAsset};
|
||||
|
||||
mod universal_exports;
|
||||
pub use universal_exports::{
|
||||
BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError, ExporterFor, HaulBlob,
|
||||
HaulBlobError, HaulBlobExporter, NetworkExportTable, SovereignPaidRemoteExporter,
|
||||
UnpaidLocalExporter, UnpaidRemoteExporter,
|
||||
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
|
||||
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable,
|
||||
SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::universal_exports::ensure_is_remote;
|
||||
use frame_support::traits::Get;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use sp_io::hashing::blake2_256;
|
||||
@@ -252,6 +253,58 @@ impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]>
|
||||
}
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
///
|
||||
/// This will always result in the *same account ID* being returned for the same
|
||||
/// parachain index under the same Relay-chain, regardless of the relative security of
|
||||
/// this Relay-chain compared to the local chain.
|
||||
///
|
||||
/// Note: No distinction is made when the local chain happens to be the parachain in
|
||||
/// question or its Relay-chain.
|
||||
///
|
||||
/// WARNING: This results in the same `AccountId` value being generated regardless
|
||||
/// of the relative security of the local chain and the Relay-chain of the input
|
||||
/// location. This may not have any immediate security risks, however since it creates
|
||||
/// commonalities between chains with different security characteristics, it could
|
||||
/// possibly form part of a more sophisticated attack scenario.
|
||||
pub struct GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>(
|
||||
PhantomData<(UniversalLocation, AccountId)>,
|
||||
);
|
||||
impl<UniversalLocation: Get<InteriorMultiLocation>, AccountId: From<[u8; 32]> + Clone>
|
||||
Convert<MultiLocation, AccountId>
|
||||
for GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
let universal_source = UniversalLocation::get();
|
||||
log::trace!(
|
||||
target: "xcm::location_conversion",
|
||||
"GlobalConsensusParachainConvertsFor universal_source: {:?}, location: {:?}",
|
||||
universal_source, location.borrow(),
|
||||
);
|
||||
let devolved = ensure_is_remote(universal_source, *location.borrow()).map_err(|_| ())?;
|
||||
let (remote_network, remote_location) = devolved;
|
||||
|
||||
match remote_location {
|
||||
X1(Parachain(remote_network_para_id)) =>
|
||||
Ok(AccountId::from(Self::from_params(&remote_network, &remote_network_para_id))),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn reverse_ref(_: impl Borrow<AccountId>) -> Result<MultiLocation, ()> {
|
||||
// if this will be needed, we could implement some kind of guessing, if we have configuration for supported networkId+paraId
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
impl<UniversalLocation, AccountId>
|
||||
GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>
|
||||
{
|
||||
fn from_params(network: &NetworkId, para_id: &u32) -> [u8; 32] {
|
||||
(b"glblcnsnss/prchn_", network, para_id).using_encoded(blake2_256)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -331,6 +384,112 @@ mod tests {
|
||||
assert_eq!(inverted, Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_consensus_parachain_converts_for_works() {
|
||||
parameter_types! {
|
||||
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ByGenesis([9; 32])), Parachain(1234));
|
||||
}
|
||||
|
||||
let test_data = vec![
|
||||
(MultiLocation::parent(), false),
|
||||
(MultiLocation::new(0, X1(Parachain(1000))), false),
|
||||
(MultiLocation::new(1, X1(Parachain(1000))), false),
|
||||
(
|
||||
MultiLocation::new(
|
||||
2,
|
||||
X3(
|
||||
GlobalConsensus(ByGenesis([0; 32])),
|
||||
Parachain(1000),
|
||||
AccountId32 { network: None, id: [1; 32].into() },
|
||||
),
|
||||
),
|
||||
false,
|
||||
),
|
||||
(MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([0; 32])))), false),
|
||||
(
|
||||
MultiLocation::new(0, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
|
||||
false,
|
||||
),
|
||||
(
|
||||
MultiLocation::new(1, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
|
||||
false,
|
||||
),
|
||||
(MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))), true),
|
||||
(
|
||||
MultiLocation::new(3, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
|
||||
false,
|
||||
),
|
||||
(
|
||||
MultiLocation::new(9, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
|
||||
false,
|
||||
),
|
||||
];
|
||||
|
||||
for (location, expected_result) in test_data {
|
||||
let result =
|
||||
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_ref(
|
||||
&location,
|
||||
);
|
||||
match result {
|
||||
Ok(account) => {
|
||||
assert_eq!(
|
||||
true, expected_result,
|
||||
"expected_result: {}, but conversion passed: {:?}, location: {:?}",
|
||||
expected_result, account, location
|
||||
);
|
||||
match &location {
|
||||
MultiLocation { interior: X2(GlobalConsensus(network), Parachain(para_id)), .. } =>
|
||||
assert_eq!(
|
||||
account,
|
||||
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::from_params(network, para_id),
|
||||
"expected_result: {}, but conversion passed: {:?}, location: {:?}", expected_result, account, location
|
||||
),
|
||||
_ => assert_eq!(
|
||||
true,
|
||||
expected_result,
|
||||
"expected_result: {}, conversion passed: {:?}, but MultiLocation does not match expected pattern, location: {:?}", expected_result, account, location
|
||||
)
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
assert_eq!(
|
||||
false, expected_result,
|
||||
"expected_result: {} - but conversion failed, location: {:?}",
|
||||
expected_result, location
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// all success
|
||||
let res_gc_a_p1000 =
|
||||
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_ref(
|
||||
MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([3; 32])), Parachain(1000))),
|
||||
)
|
||||
.expect("conversion is ok");
|
||||
let res_gc_a_p1001 =
|
||||
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_ref(
|
||||
MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([3; 32])), Parachain(1001))),
|
||||
)
|
||||
.expect("conversion is ok");
|
||||
let res_gc_b_p1000 =
|
||||
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_ref(
|
||||
MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([4; 32])), Parachain(1000))),
|
||||
)
|
||||
.expect("conversion is ok");
|
||||
let res_gc_b_p1001 =
|
||||
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_ref(
|
||||
MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([4; 32])), Parachain(1001))),
|
||||
)
|
||||
.expect("conversion is ok");
|
||||
assert_ne!(res_gc_a_p1000, res_gc_a_p1001);
|
||||
assert_ne!(res_gc_a_p1000, res_gc_b_p1000);
|
||||
assert_ne!(res_gc_a_p1000, res_gc_b_p1001);
|
||||
assert_ne!(res_gc_b_p1000, res_gc_b_p1001);
|
||||
assert_ne!(res_gc_b_p1000, res_gc_a_p1001);
|
||||
assert_ne!(res_gc_b_p1001, res_gc_a_p1001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_convert_on_para_sending_para_32() {
|
||||
let mul = MultiLocation {
|
||||
|
||||
@@ -23,7 +23,11 @@ use xcm::prelude::*;
|
||||
use xcm_executor::traits::{validate_export, ExportXcm};
|
||||
use SendError::*;
|
||||
|
||||
fn ensure_is_remote(
|
||||
/// Returns the network ID and consensus location within that network of the remote
|
||||
/// location `dest` which is itself specified as a location relative to the local
|
||||
/// chain, itself situated at `universal_local` within the consensus universe. If
|
||||
/// `dest` is not a location in remote consensus, then an error is returned.
|
||||
pub fn ensure_is_remote(
|
||||
universal_local: impl Into<InteriorMultiLocation>,
|
||||
dest: impl Into<MultiLocation>,
|
||||
) -> Result<(NetworkId, InteriorMultiLocation), MultiLocation> {
|
||||
|
||||
Reference in New Issue
Block a user