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

[xcm] GlobalConsensusConvertsFor for remote relay chain (based on pevious GlobalConsensusParachainConvertsFor) #7517

Merged
merged 18 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion xcm/src/v3/multiasset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 *insance ID`, the secondary asset identifier.
/// asset) or the `instance ID`, the secondary asset identifier.
bkontur marked this conversation as resolved.
Show resolved Hide resolved
pub fun: Fungibility,
}

Expand Down
125 changes: 125 additions & 0 deletions xcm/xcm-builder/src/location_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,47 @@ 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 when the local chain happens to be the relay chain in
/// question or its Relay-chain.
bkontur marked this conversation as resolved.
Show resolved Hide resolved
///
/// 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edited for clarity, however I don't particularly agree with this comment. It does not create commonalities between chains; actually it says that one chain will have the same 32-byte AccountId in other consensus systems (that use 32-byte account IDs). If this chain has a security incident, that would have effects in many other chains, but it does not put anything in common between the local chain and the "global" chain.

Unless I am missing something, I would delete this comment.

Suggested change
/// 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.
/// WARNING: This results in the same `AccountId` value being generated regardless of the relative
/// security of the local chain and the security of the input location. This may not have any
/// immediate security risks; however, because it creates commonalities between chains with
/// different security characteristics, it could possibly form part of a more sophisticated attack
/// scenario.

pub struct GlobalConsensusConvertsFor<UniversalLocation, AccountId>(
svyatonik marked this conversation as resolved.
Show resolved Hide resolved
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();
KiChjang marked this conversation as resolved.
Show resolved Hide resolved
log::trace!(
target: "xcm::location_conversion",
"GlobalConsensusConvertsFor universal_source: {:?}, location: {:?}",
universal_source, location,
);
let devolved = ensure_is_remote(universal_source, *location).ok()?;
let (remote_network, remote_location) = devolved;
bkontur marked this conversation as resolved.
Show resolved Hide resolved

match remote_location {
Here => Some(AccountId::from(Self::from_params(&remote_network))),
bkontur marked this conversation as resolved.
Show resolved Hide resolved
_ => None,
}
}
}
impl<UniversalLocation, AccountId> GlobalConsensusConvertsFor<UniversalLocation, AccountId> {
fn from_params(network: &NetworkId) -> [u8; 32] {
(b"glblcnsnss_", network).using_encoded(blake2_256)
KiChjang marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// 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`.
///
Expand Down Expand Up @@ -473,6 +514,90 @@ mod tests {
assert_eq!(inverted, Err(()));
}

#[test]
fn global_consensus_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, Here), false),
(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([9; 32])))), false),
bkontur marked this conversation as resolved.
Show resolved Hide resolved
(MultiLocation::new(1, X1(GlobalConsensus(ByGenesis([9; 32])))), false),
(MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([9; 32])))), false),
(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32])))), false),
(MultiLocation::new(1, X1(GlobalConsensus(ByGenesis([0; 32])))), false),
(MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([0; 32])))), true),
(
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))),
false,
),
];

for (location, expected_result) in test_data {
let result =
GlobalConsensusConvertsFor::<UniversalLocation, [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::<UniversalLocation, [u8; 32]>::from_params(network),
"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
bkontur marked this conversation as resolved.
Show resolved Hide resolved
)
}
},
None => {
assert_eq!(
false, expected_result,
"expected_result: {} - but conversion failed, location: {:?}",
expected_result, location
);
},
}
}

// all success
bkontur marked this conversation as resolved.
Show resolved Hide resolved
let res_gc_a = GlobalConsensusConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([3; 32])))),
bkontur marked this conversation as resolved.
Show resolved Hide resolved
)
.expect("conversion is ok");
let res_gc_b = GlobalConsensusConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([4; 32])))),
)
.expect("conversion is ok");
let res_gc_c = GlobalConsensusConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([5; 32])))),
)
.expect("conversion is ok");

assert_ne!(res_gc_a, res_gc_b);
assert_ne!(res_gc_b, res_gc_c);
assert_ne!(res_gc_a, res_gc_c);
}

#[test]
fn global_consensus_parachain_converts_for_works() {
parameter_types! {
Expand Down