mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-07 07:18:03 +00:00
XCM: Remote account converter (#6662)
* Draft remote account converter * Tests and doc comments * Adapt naming, tests fix * Try with prefix in account * Revert "Try with prefix in account" This reverts commit 461759794cc9f59f768aad0e0899df6dc8cba747. * Adapt code and test to review suggestions * adapt to take into account parent in conversion * fix: docs * fix: try doc fix v2
This commit is contained in:
committed by
GitHub
parent
3f4ce6326f
commit
3f3a041631
@@ -22,6 +22,111 @@ use sp_std::{borrow::Borrow, marker::PhantomData};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::Convert;
|
||||
|
||||
/// Prefix for generating alias account for accounts coming
|
||||
/// from chains that use 32 byte long representations.
|
||||
pub const FOREIGN_CHAIN_PREFIX_PARA_32: [u8; 37] = *b"ForeignChainAliasAccountPrefix_Para32";
|
||||
|
||||
/// Prefix for generating alias account for accounts coming
|
||||
/// from chains that use 20 byte long representations.
|
||||
pub const FOREIGN_CHAIN_PREFIX_PARA_20: [u8; 37] = *b"ForeignChainAliasAccountPrefix_Para20";
|
||||
|
||||
/// Prefix for generating alias account for accounts coming
|
||||
/// from the relay chain using 32 byte long representations.
|
||||
pub const FOREIGN_CHAIN_PREFIX_RELAY: [u8; 36] = *b"ForeignChainAliasAccountPrefix_Relay";
|
||||
|
||||
/// This converter will for a given `AccountId32`/`AccountKey20`
|
||||
/// always generate the same "remote" account for a specific
|
||||
/// sending chain.
|
||||
/// I.e. the user gets the same remote account
|
||||
/// on every consuming para-chain and relay chain.
|
||||
///
|
||||
/// Can be used as a converter in `SovereignSignedViaLocation`
|
||||
///
|
||||
/// ## Example
|
||||
/// Assuming the following network layout.
|
||||
///
|
||||
/// ```notrust
|
||||
/// R
|
||||
/// / \
|
||||
/// / \
|
||||
/// P1 P2
|
||||
/// / \ / \
|
||||
/// / \ / \
|
||||
/// P1.1 P1.2 P2.1 P2.2
|
||||
/// ```
|
||||
/// Then a given account A will have the same alias accounts in the
|
||||
/// same plane. So, it is important which chain account A acts from.
|
||||
/// E.g.
|
||||
/// * From P1.2 A will act as
|
||||
/// * hash(ParaPrefix, A, 1, 1) on P1.2
|
||||
/// * hash(ParaPrefix, A, 1, 0) on P1
|
||||
/// * From P1 A will act as
|
||||
/// * hash(RelayPrefix, A, 1) on P1.2 & P1.1
|
||||
/// * hash(ParaPrefix, A, 1, 1) on P2
|
||||
/// * hash(ParaPrefix, A, 1, 0) on R
|
||||
///
|
||||
/// Note that the alias accounts have overlaps but never on the same
|
||||
/// chain when the sender comes from different chains.
|
||||
pub struct ForeignChainAliasAccount<AccountId>(PhantomData<AccountId>);
|
||||
impl<AccountId: From<[u8; 32]> + Clone> Convert<MultiLocation, AccountId>
|
||||
for ForeignChainAliasAccount<AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
let entropy = match location.borrow() {
|
||||
// Used on the relay chain for sending paras that use 32 byte accounts
|
||||
MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(Parachain(para_id), AccountId32 { id, .. }),
|
||||
} => ForeignChainAliasAccount::<AccountId>::from_para_32(para_id, id, 0),
|
||||
|
||||
// Used on the relay chain for sending paras that use 20 byte accounts
|
||||
MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(Parachain(para_id), AccountKey20 { key, .. }),
|
||||
} => ForeignChainAliasAccount::<AccountId>::from_para_20(para_id, key, 0),
|
||||
|
||||
// Used on para-chain for sending paras that use 32 byte accounts
|
||||
MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(para_id), AccountId32 { id, .. }),
|
||||
} => ForeignChainAliasAccount::<AccountId>::from_para_32(para_id, id, 1),
|
||||
|
||||
// Used on para-chain for sending paras that use 20 byte accounts
|
||||
MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(para_id), AccountKey20 { key, .. }),
|
||||
} => ForeignChainAliasAccount::<AccountId>::from_para_20(para_id, key, 1),
|
||||
|
||||
// Used on para-chain for sending from the relay chain
|
||||
MultiLocation { parents: 1, interior: X1(AccountId32 { id, .. }) } =>
|
||||
ForeignChainAliasAccount::<AccountId>::from_relay_32(id, 1),
|
||||
|
||||
// No other conversions provided
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
Ok(entropy.into())
|
||||
}
|
||||
|
||||
fn reverse_ref(_: impl Borrow<AccountId>) -> Result<MultiLocation, ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<AccountId> ForeignChainAliasAccount<AccountId> {
|
||||
fn from_para_32(para_id: &u32, id: &[u8; 32], parents: u8) -> [u8; 32] {
|
||||
(FOREIGN_CHAIN_PREFIX_PARA_32, para_id, id, parents).using_encoded(blake2_256)
|
||||
}
|
||||
|
||||
fn from_para_20(para_id: &u32, id: &[u8; 20], parents: u8) -> [u8; 32] {
|
||||
(FOREIGN_CHAIN_PREFIX_PARA_20, para_id, id, parents).using_encoded(blake2_256)
|
||||
}
|
||||
|
||||
fn from_relay_32(id: &[u8; 32], parents: u8) -> [u8; 32] {
|
||||
(FOREIGN_CHAIN_PREFIX_RELAY, id, parents).using_encoded(blake2_256)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for Account32Hash<Network, AccountId>
|
||||
@@ -225,4 +330,215 @@ mod tests {
|
||||
let inverted = UniversalLocation::get().invert_target(&input);
|
||||
assert_eq!(inverted, Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_convert_on_para_sending_para_32() {
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(1), AccountId32 { network: None, id: [0u8; 32] }),
|
||||
};
|
||||
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
181, 186, 132, 152, 52, 210, 226, 199, 8, 235, 213, 242, 94, 70, 250, 170, 19, 163,
|
||||
196, 102, 245, 14, 172, 184, 2, 148, 108, 87, 230, 163, 204, 32
|
||||
],
|
||||
rem_1
|
||||
);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(
|
||||
Parachain(1),
|
||||
AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] },
|
||||
),
|
||||
};
|
||||
|
||||
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap(), rem_1);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(2), AccountId32 { network: None, id: [0u8; 32] }),
|
||||
};
|
||||
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
183, 188, 66, 169, 82, 250, 45, 30, 142, 119, 184, 55, 177, 64, 53, 114, 12, 147,
|
||||
128, 10, 60, 45, 41, 193, 87, 18, 86, 49, 127, 233, 243, 143
|
||||
],
|
||||
rem_2
|
||||
);
|
||||
|
||||
assert_ne!(rem_1, rem_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_convert_on_para_sending_para_20() {
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(1), AccountKey20 { network: None, key: [0u8; 20] }),
|
||||
};
|
||||
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
210, 60, 37, 255, 116, 38, 221, 26, 85, 82, 252, 125, 220, 19, 41, 91, 185, 69,
|
||||
102, 83, 120, 63, 15, 212, 74, 141, 82, 203, 187, 212, 77, 120
|
||||
],
|
||||
rem_1
|
||||
);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(
|
||||
Parachain(1),
|
||||
AccountKey20 { network: Some(NetworkId::Polkadot), key: [0u8; 20] },
|
||||
),
|
||||
};
|
||||
|
||||
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap(), rem_1);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(2), AccountKey20 { network: None, key: [0u8; 20] }),
|
||||
};
|
||||
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
197, 16, 31, 199, 234, 80, 166, 55, 178, 135, 95, 48, 19, 128, 9, 167, 51, 99, 215,
|
||||
147, 94, 171, 28, 157, 29, 107, 240, 22, 10, 104, 99, 186
|
||||
],
|
||||
rem_2
|
||||
);
|
||||
|
||||
assert_ne!(rem_1, rem_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_convert_on_para_sending_relay() {
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X1(AccountId32 { network: None, id: [0u8; 32] }),
|
||||
};
|
||||
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
227, 12, 152, 241, 220, 53, 26, 27, 1, 167, 167, 214, 61, 161, 255, 96, 56, 16,
|
||||
221, 59, 47, 45, 40, 193, 88, 92, 4, 167, 164, 27, 112, 99
|
||||
],
|
||||
rem_1
|
||||
);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X1(AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] }),
|
||||
};
|
||||
|
||||
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap(), rem_1);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X1(AccountId32 { network: None, id: [1u8; 32] }),
|
||||
};
|
||||
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
143, 195, 87, 73, 129, 2, 163, 211, 239, 51, 55, 235, 82, 173, 162, 206, 158, 237,
|
||||
166, 73, 254, 62, 131, 6, 170, 241, 209, 116, 105, 69, 29, 226
|
||||
],
|
||||
rem_2
|
||||
);
|
||||
|
||||
assert_ne!(rem_1, rem_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_convert_on_relay_sending_para_20() {
|
||||
let mul = MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(Parachain(1), AccountKey20 { network: None, key: [0u8; 20] }),
|
||||
};
|
||||
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
25, 251, 15, 92, 148, 141, 236, 238, 50, 108, 133, 56, 118, 11, 250, 122, 81, 160,
|
||||
104, 160, 97, 200, 210, 49, 208, 142, 64, 144, 24, 110, 246, 101
|
||||
],
|
||||
rem_1
|
||||
);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(Parachain(2), AccountKey20 { network: None, key: [0u8; 20] }),
|
||||
};
|
||||
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
88, 157, 224, 235, 76, 88, 201, 143, 206, 227, 14, 192, 177, 245, 75, 62, 41, 10,
|
||||
107, 182, 61, 57, 239, 112, 43, 151, 58, 111, 150, 153, 234, 189
|
||||
],
|
||||
rem_2
|
||||
);
|
||||
|
||||
assert_ne!(rem_1, rem_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_convert_on_relay_sending_para_32() {
|
||||
let mul = MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(Parachain(1), AccountId32 { network: None, id: [0u8; 32] }),
|
||||
};
|
||||
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
45, 120, 232, 0, 226, 49, 106, 48, 65, 181, 184, 147, 224, 235, 198, 152, 183, 156,
|
||||
67, 57, 67, 67, 187, 104, 171, 23, 140, 21, 183, 152, 63, 20
|
||||
],
|
||||
rem_1
|
||||
);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(
|
||||
Parachain(1),
|
||||
AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] },
|
||||
),
|
||||
};
|
||||
|
||||
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap(), rem_1);
|
||||
|
||||
let mul = MultiLocation {
|
||||
parents: 0,
|
||||
interior: X2(Parachain(2), AccountId32 { network: None, id: [0u8; 32] }),
|
||||
};
|
||||
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert(mul).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
[
|
||||
97, 119, 110, 66, 239, 113, 96, 234, 127, 92, 66, 204, 53, 129, 33, 119, 213, 192,
|
||||
171, 100, 139, 51, 39, 62, 196, 163, 16, 213, 160, 44, 100, 228
|
||||
],
|
||||
rem_2
|
||||
);
|
||||
|
||||
assert_ne!(rem_1, rem_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_account_fails_with_bad_multilocation() {
|
||||
let mul = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X1(AccountKey20 { network: None, key: [0u8; 20] }),
|
||||
};
|
||||
assert!(ForeignChainAliasAccount::<[u8; 32]>::convert(mul).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user