Skip to content

Snowbridge: Remove asset location check for compatibility #8473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

yrong
Copy link
Contributor

@yrong yrong commented May 9, 2025

The TokenIdOf convert is XCM version-agnostic, meaning we will get the same token ID for both V5 and legacy V4 asset. However, the extra check will break, as we store the V4 location in storage.

Therefore, we should remove this check for compatibility.

Comment on lines -177 to -178
let expected_asset_id = ConvertAssetId::convert(&token_id).ok_or(InvalidAsset)?;
ensure!(asset_id == expected_asset_id, InvalidAsset);
Copy link
Contributor

Choose a reason for hiding this comment

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

@franciscoaguirre are there perhaps other ways to check asset ID equivalence, across different XCM versions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I assume the check here is unnecessary, as the conversion alone is sufficient to verify whether the token is registered.

@yrong yrong changed the title Remove asset location check for compatibility Snowbridge: Remove asset location check for compatibility May 9, 2025
@yrong yrong marked this pull request as ready for review May 12, 2025 12:10
@paritytech-review-bot paritytech-review-bot bot requested a review from a team May 12, 2025 12:11
@acatangiu acatangiu added T15-bridges This PR/Issue is related to bridges. A4-backport-stable2503 Pull request must be backported to the stable2503 release branch labels May 12, 2025
@vgeddes
Copy link
Contributor

vgeddes commented May 12, 2025

The TokenIdOf convert is XCM version-agnostic, meaning we will get the same token ID for both V5 and legacy V4 asset

Strictly speaking, TokenIdOf can actually return different token ids for a location encoded in V4 and in V5, as newer versions of XCM can add or remove various enum variants for NetworkId, and the scale-encoded network id is used as input into the token id generator: https://github.com/vgeddes/polkadot-sdk/blob/2567a5ac3a22fe669279277d32561a918a07ae58/bridges/snowbridge/primitives/core/src/location.rs#L67

Comment on lines 414 to +416
let token_id = TokenIdOf::convert_location(&asset_id).ok_or(InvalidAsset)?;

let expected_asset_id = ConvertAssetId::convert(&token_id).ok_or(InvalidAsset)?;

ensure!(asset_id == expected_asset_id, InvalidAsset);
ConvertAssetId::convert(&token_id).ok_or(InvalidAsset)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

If the location has already been registered as a PNA and a foreign token id has been allocated in storage for it, why not just use ConvertAssetId::convert_back to retrieve the stored id?

Recreating the token id deterministically using TokenIdOf::convert_location is dangerous for the reason I mentioned in #8473 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

as newer versions of XCM can add or remove various enum variants for NetworkId

I assume removal is not allowed, or that the codec index should not chage. That's why I created PR#6503

Copy link
Contributor Author

Choose a reason for hiding this comment

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

why not just use ConvertAssetId::convert_back to retrieve the stored id?

As mentioned the token registered (in V4) is not the same as the token that was transferred (in V5). However, this reminds me that NativeToForeignId storage is actually unused, so I performed some cleanup accordingly.

dabf3bf

Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned the token registered (in V4) is not the same as the token that was transferred (in V5).

Can you give an example scenario so that we can make the discussion more concrete?

Copy link
Contributor Author

@yrong yrong May 17, 2025

Choose a reason for hiding this comment

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

Sorry for the confusion earlier. Yes, technically we can use convert_back to obtain the tokenID from the location. But in my opinion, it’s unnecessary — the tokenID is already stored on Ethereum and must be permanent. This means that TokenIdOf::convert_location(&location) should remain stable across different XCM versions.

In my view, changes like those in this PR#5390 are not good practice. Adding new fields or enums is fine, but replacing or removing existing ones should not be allowed. This should be a core principle for all upgrades — whether on Substrate or Ethereum.

To ensure the tokenID remains stable, I’ve added tests in fellow-runtime.

@yrong
Copy link
Contributor Author

yrong commented May 13, 2025

By the way, in a recent commit, I changed the storage to use VersionedLocation.

IMHO, it’s always safer to use VersionedLocation in a storage context. Although this requires a runtime upgrade to migrate from a V4 location to VersionedLocation::V4 (and pinged as V4), no further migration is needed - as long as the conversion (from V4 to V5 or V6) works correctly.

@acatangiu @bkontur Please let me know what you think.

Comment on lines 239 to 234
StorageMap<_, Blake2_128Concat, xcm::v5::Location, TokenId, OptionQuery>;
StorageMap<_, Blake2_128Concat, TokenId, VersionedLocation, OptionQuery>;
Copy link
Contributor

Choose a reason for hiding this comment

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

By the way, in a recent commit, I changed the storage to use VersionedLocation.

I am slightly leaning against this.

We support a sliding window of 3 XCM versions: [lastest, latest - 2]. So over time you still need migrations to migrate from e.g. VersionedLocation::V3() storage entries to VersionedLocation::V6() when we upgrade to XCMv6.

You get the advantage of somewhat smaller migrations (only oldest entries need migrating), but
you get the disadvantage of mixed storage holding various versions.

Neither option is truly better IMO, but I prefer consistency across pallets and storing base/unversioned types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

disadvantage of mixed storage holding various versions.

IMHO, this may not be too problematic for this specific use case, as long as the derived TokenId is (and is intended to be) XCM version-agnostic.

Copy link
Contributor Author

@yrong yrong May 15, 2025

Choose a reason for hiding this comment

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

a sliding window of 3 XCM versions: [lastest, latest - 2]

That's good. As mentioned, the current storage version is V4. Assuming we migrate from Location(V4) to VersionLocation::V5, that means we don't need to worry about a runtime migration until XCM V8.

Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer not to use VersionedLocation in storage either. I want highly normalized, consistent data in storage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted recent updates.

Comment on lines 537 to 538
fn convert_back(_: &Location) -> Option<TokenId> {
None
Copy link
Contributor

Choose a reason for hiding this comment

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

why use MaybeEquivalence if you don't provide convert_back functionality?

Can you use TryConvert/MaybeConvert instead?

Copy link
Contributor Author

@yrong yrong May 16, 2025

Choose a reason for hiding this comment

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

To keep this PR focused, I've opend a separate PR for the cleanup and refactoring work, which isn't high priority.

Copy link
Contributor

@vgeddes vgeddes left a comment

Choose a reason for hiding this comment

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

@yrong must this be backported to stable2503? If so, lets focus on the immediate issue at hand - removal of the asset location check.

@yrong
Copy link
Contributor Author

yrong commented May 16, 2025

must this be backported to stable2503?

Yeah, and I've created a runtime migration in polkadot-fellows/runtimes#730

@yrong yrong requested a review from vgeddes May 16, 2025 02:48
@yrong yrong force-pushed the remove-asset-location-check branch from 62946bb to 697f4ed Compare May 16, 2025 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A4-backport-stable2503 Pull request must be backported to the stable2503 release branch T15-bridges This PR/Issue is related to bridges.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants