Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

[xcm] Foreign global consensus parachain LocationToAccountId converter #7016

Merged
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions xcm/xcm-builder/src/location_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,35 @@ impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]>
}
}

/// Tries to convert global consensus parachain to accountId.
///
/// (E.g.: can be used for sovereign account conversion)
bkontur marked this conversation as resolved.
Show resolved Hide resolved
pub struct GlobalConsensusParachainConvert<AccountId>(PhantomData<AccountId>);
bkontur marked this conversation as resolved.
Show resolved Hide resolved
impl<AccountId: From<[u8; 32]> + Clone> Convert<MultiLocation, AccountId>
for GlobalConsensusParachainConvert<AccountId>
{
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
match location.borrow() {
MultiLocation {
interior: X2(GlobalConsensus(network), Parachain(para_id)), ..
bkontur marked this conversation as resolved.
Show resolved Hide resolved
} => Ok(AccountId::from(GlobalConsensusParachainConvert::<AccountId>::from_params(
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<AccountId> GlobalConsensusParachainConvert<AccountId> {
fn from_params(network: &NetworkId, para_id: &u32) -> [u8; 32] {
(network, para_id).using_encoded(blake2_256)
bkontur marked this conversation as resolved.
Show resolved Hide resolved
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -225,4 +254,89 @@ mod tests {
let inverted = UniversalLocation::get().invert_target(&input);
assert_eq!(inverted, Err(()));
}

#[test]
fn global_consensus_parachain_convert_works() {
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))), true),
(MultiLocation::new(1, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))), true),
(MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))), true),
(MultiLocation::new(3, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))), true),
(MultiLocation::new(9, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))), true),
];

for (location, expected_result) in test_data {
let result = GlobalConsensusParachainConvert::<[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,
GlobalConsensusParachainConvert::<[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_2_1000 = GlobalConsensusParachainConvert::<[u8; 32]>::convert_ref(
MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
)
.expect("conversion is ok");
let res_2_1001 = GlobalConsensusParachainConvert::<[u8; 32]>::convert_ref(
MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1001))),
)
.expect("conversion is ok");
let res_3_1000 = GlobalConsensusParachainConvert::<[u8; 32]>::convert_ref(
MultiLocation::new(3, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
)
.expect("conversion is ok");
let res_3_1001 = GlobalConsensusParachainConvert::<[u8; 32]>::convert_ref(
MultiLocation::new(3, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1001))),
)
.expect("conversion is ok");
assert_ne!(res_2_1000, res_2_1001);
assert_ne!(res_3_1000, res_3_1001);

assert_ne!(res_2_1000, res_3_1001);
assert_ne!(res_2_1001, res_3_1000);

assert_eq!(res_2_1000, res_3_1000);
assert_eq!(res_2_1001, res_3_1001);
}
}