Skip to content

Commit d557688

Browse files
committed
changed foreign asset mapping from hash to sequential index
1 parent 5f78f44 commit d557688

File tree

6 files changed

+222
-279
lines changed

6 files changed

+222
-279
lines changed

substrate/frame/assets/precompiles/src/foreign_assets.rs

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@ pub use pallet::*;
2424
pub struct ForeignAssetId<T, I = ()>(PhantomData<(T, I)>);
2525
impl<T: Config, I> AssetsCallback<T::AssetId, T::AccountId> for ForeignAssetId<T, I>
2626
where
27-
T::AssetId: ToAssetIndex,
2827
T: pallet::Config<ForeignAssetId = T::AssetId> + pallet_assets::Config<I>,
2928
I: 'static,
3029
{
3130
fn created(id: &T::AssetId, _: &T::AccountId) -> Result<(), ()> {
32-
pallet::Pallet::<T>::insert_asset_mapping(id.to_asset_index(), id)
31+
pallet::Pallet::<T>::insert_asset_mapping(id).map(|_| ())
3332
}
3433

3534
fn destroyed(id: &T::AssetId) -> Result<(), ()> {
@@ -38,27 +37,6 @@ where
3837
}
3938
}
4039

41-
/// Trait to convert various types to u32 asset index used internally by the pallet.
42-
pub trait ToAssetIndex {
43-
fn to_asset_index(&self) -> u32;
44-
}
45-
46-
/// Implemented for trust-backed assets and pool assets.
47-
impl ToAssetIndex for u32 {
48-
fn to_asset_index(&self) -> u32 {
49-
*self
50-
}
51-
}
52-
53-
/// Implemented for foreign assets.
54-
impl ToAssetIndex for xcm::v5::Location {
55-
fn to_asset_index(&self) -> u32 {
56-
use codec::Encode;
57-
let h = sp_core::hashing::blake2_256(&self.encode());
58-
u32::from_le_bytes([h[0], h[1], h[2], h[3]])
59-
}
60-
}
61-
6240
#[frame_support::pallet]
6341
pub mod pallet {
6442
use super::*;
@@ -68,17 +46,17 @@ pub mod pallet {
6846
pub trait Config: frame_system::Config {
6947
/// The foreign asset ID type. This must match the `AssetId` type used by the
7048
/// `pallet_assets` instance for foreign assets.
71-
type ForeignAssetId: Member
72-
+ Parameter
73-
+ Clone
74-
+ MaybeSerializeDeserialize
75-
+ MaxEncodedLen
76-
+ ToAssetIndex;
49+
type ForeignAssetId: Member + Parameter + Clone + MaybeSerializeDeserialize + MaxEncodedLen;
7750
}
7851

7952
#[pallet::pallet]
8053
pub struct Pallet<T>(_);
8154

55+
/// The next available asset index for foreign assets.
56+
/// This is incremented each time a new foreign asset mapping is created.
57+
#[pallet::storage]
58+
pub type NextAssetIndex<T: Config> = StorageValue<_, u32, ValueQuery>;
59+
8260
/// Mapping an asset index (derived from the precompile address) to a `ForeignAssetId`.
8361
#[pallet::storage]
8462
pub type AssetIndexToForeignAssetId<T: Config> =
@@ -100,21 +78,31 @@ pub mod pallet {
10078
ForeignAssetIdToAssetIndex::<T>::get(asset_id)
10179
}
10280

103-
pub fn insert_asset_mapping(
104-
asset_index: u32,
105-
asset_id: &T::ForeignAssetId,
106-
) -> Result<(), ()> {
107-
if AssetIndexToForeignAssetId::<T>::contains_key(asset_index) {
108-
log::debug!(target: LOG_TARGET, "Asset index {:?} already mapped", asset_index);
109-
return Err(());
110-
}
81+
/// Get the next available asset index without incrementing it.
82+
pub fn next_asset_index() -> u32 {
83+
NextAssetIndex::<T>::get()
84+
}
85+
86+
/// Insert a new asset mapping, allocating a sequential index.
87+
/// Returns the allocated asset index on success.
88+
pub fn insert_asset_mapping(asset_id: &T::ForeignAssetId) -> Result<u32, ()> {
11189
if ForeignAssetIdToAssetIndex::<T>::contains_key(asset_id) {
11290
log::debug!(target: LOG_TARGET, "Asset id {:?} already mapped", asset_id);
11391
return Err(());
11492
}
93+
94+
let asset_index = NextAssetIndex::<T>::get();
95+
let next_index = asset_index.checked_add(1).ok_or_else(|| {
96+
log::error!(target: LOG_TARGET, "Asset index overflow");
97+
()
98+
})?;
99+
115100
AssetIndexToForeignAssetId::<T>::insert(asset_index, asset_id.clone());
116101
ForeignAssetIdToAssetIndex::<T>::insert(asset_id, asset_index);
117-
Ok(())
102+
NextAssetIndex::<T>::put(next_index);
103+
104+
log::debug!(target: LOG_TARGET, "Mapped asset {:?} to index {:?}", asset_id, asset_index);
105+
Ok(asset_index)
118106
}
119107

120108
pub fn remove_asset_mapping(asset_id: &T::ForeignAssetId) {

substrate/frame/assets/precompiles/src/foreign_assets_tests.rs

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
2020
use super::*;
2121
use crate::{
22-
foreign_assets::{pallet::Pallet as ForeignAssetsPallet, ForeignAssetId, ToAssetIndex},
22+
foreign_assets::{pallet::Pallet as ForeignAssetsPallet, ForeignAssetId},
2323
mock::{new_test_ext, Test},
2424
};
2525
use frame_support::assert_ok;
@@ -29,10 +29,12 @@ use pallet_assets::AssetsCallback;
2929
fn asset_mapping_insert_works() {
3030
new_test_ext().execute_with(|| {
3131
let asset_id = 123u32;
32-
let asset_index = asset_id.to_asset_index();
3332

34-
// Insert mapping
35-
assert_ok!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index, &asset_id));
33+
// Insert mapping - now returns the allocated index
34+
let asset_index = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id).unwrap();
35+
36+
// First asset should get index 0
37+
assert_eq!(asset_index, 0);
3638

3739
// Verify both directions of lookup work
3840
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(asset_index), Some(asset_id));
@@ -41,49 +43,51 @@ fn asset_mapping_insert_works() {
4143
}
4244

4345
#[test]
44-
fn asset_mapping_insert_prevents_duplicate_index() {
46+
fn asset_mapping_insert_sequential_indices() {
4547
new_test_ext().execute_with(|| {
46-
let asset_id1 = 123u32;
47-
let asset_id2 = 456u32;
48-
let asset_index = 100u32;
49-
50-
// Insert first mapping
51-
assert_ok!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index, &asset_id1));
52-
53-
// Try to insert different asset with same index - should fail
54-
assert!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index, &asset_id2).is_err());
55-
56-
// Original mapping should still exist
57-
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(asset_index), Some(asset_id1));
48+
let asset_id1 = 100u32;
49+
let asset_id2 = 200u32;
50+
let asset_id3 = 300u32;
51+
52+
// Insert mappings - should get sequential indices
53+
let index1 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id1).unwrap();
54+
let index2 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id2).unwrap();
55+
let index3 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id3).unwrap();
56+
57+
assert_eq!(index1, 0);
58+
assert_eq!(index2, 1);
59+
assert_eq!(index3, 2);
60+
61+
// Verify lookups
62+
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(0), Some(asset_id1));
63+
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(1), Some(asset_id2));
64+
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(2), Some(asset_id3));
5865
});
5966
}
6067

6168
#[test]
6269
fn asset_mapping_insert_prevents_duplicate_asset_id() {
6370
new_test_ext().execute_with(|| {
6471
let asset_id = 123u32;
65-
let asset_index1 = 100u32;
66-
let asset_index2 = 200u32;
6772

6873
// Insert first mapping
69-
assert_ok!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index1, &asset_id));
74+
let index1 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id).unwrap();
7075

71-
// Try to insert same asset with different index - should fail
72-
assert!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index2, &asset_id).is_err());
76+
// Try to insert same asset again - should fail
77+
assert!(ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id).is_err());
7378

7479
// Original mapping should still exist
75-
assert_eq!(ForeignAssetsPallet::<Test>::asset_index_of(&asset_id), Some(asset_index1));
80+
assert_eq!(ForeignAssetsPallet::<Test>::asset_index_of(&asset_id), Some(index1));
7681
});
7782
}
7883

7984
#[test]
8085
fn asset_mapping_remove_works() {
8186
new_test_ext().execute_with(|| {
8287
let asset_id = 123u32;
83-
let asset_index = asset_id.to_asset_index();
8488

8589
// Insert and verify
86-
assert_ok!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index, &asset_id));
90+
let asset_index = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id).unwrap();
8791
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(asset_index), Some(asset_id));
8892

8993
// Remove mapping
@@ -113,14 +117,14 @@ fn foreign_asset_callback_created_inserts_mapping() {
113117
new_test_ext().execute_with(|| {
114118
let asset_id = 42u32;
115119
let owner = 123u64;
116-
let asset_index = asset_id.to_asset_index();
117120

118121
// Simulate asset creation callback
119122
assert_ok!(ForeignAssetId::<Test>::created(&asset_id, &owner));
120123

121-
// Verify mapping was inserted
124+
// Verify mapping was inserted with sequential index (first asset gets 0)
125+
let asset_index = ForeignAssetsPallet::<Test>::asset_index_of(&asset_id).unwrap();
126+
assert_eq!(asset_index, 0);
122127
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(asset_index), Some(asset_id));
123-
assert_eq!(ForeignAssetsPallet::<Test>::asset_index_of(&asset_id), Some(asset_index));
124128
});
125129
}
126130

@@ -129,10 +133,10 @@ fn foreign_asset_callback_destroyed_removes_mapping() {
129133
new_test_ext().execute_with(|| {
130134
let asset_id = 42u32;
131135
let owner = 123u64;
132-
let asset_index = asset_id.to_asset_index();
133136

134137
// Setup: create asset mapping via callback
135138
assert_ok!(ForeignAssetId::<Test>::created(&asset_id, &owner));
139+
let asset_index = ForeignAssetsPallet::<Test>::asset_index_of(&asset_id).unwrap();
136140
assert_eq!(ForeignAssetsPallet::<Test>::asset_id_of(asset_index), Some(asset_id));
137141

138142
// Simulate asset destruction callback
@@ -148,10 +152,9 @@ fn foreign_asset_callback_destroyed_removes_mapping() {
148152
fn foreign_asset_id_extractor_works_with_valid_mapping() {
149153
new_test_ext().execute_with(|| {
150154
let asset_id = 555u32;
151-
let asset_index = 0x0000_0001u32; // Will be in first 4 bytes of address
152155

153-
// Setup mapping
154-
assert_ok!(ForeignAssetsPallet::<Test>::insert_asset_mapping(asset_index, &asset_id));
156+
// Setup mapping - gets index 0
157+
let asset_index = ForeignAssetsPallet::<Test>::insert_asset_mapping(&asset_id).unwrap();
155158

156159
// Create address with the asset index in the first 4 bytes
157160
let mut address = [0u8; 20];
@@ -194,3 +197,26 @@ fn foreign_id_config_matcher_works() {
194197
non_matching_address[16..18].copy_from_slice(&0x0120u16.to_be_bytes());
195198
assert!(!matcher.matches(&non_matching_address));
196199
}
200+
201+
#[test]
202+
fn next_asset_index_increments_correctly() {
203+
new_test_ext().execute_with(|| {
204+
// Initial state
205+
assert_eq!(ForeignAssetsPallet::<Test>::next_asset_index(), 0);
206+
207+
// Insert first asset
208+
let index1 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&100u32).unwrap();
209+
assert_eq!(index1, 0);
210+
assert_eq!(ForeignAssetsPallet::<Test>::next_asset_index(), 1);
211+
212+
// Insert second asset
213+
let index2 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&200u32).unwrap();
214+
assert_eq!(index2, 1);
215+
assert_eq!(ForeignAssetsPallet::<Test>::next_asset_index(), 2);
216+
217+
// Insert third asset
218+
let index3 = ForeignAssetsPallet::<Test>::insert_asset_mapping(&300u32).unwrap();
219+
assert_eq!(index3, 2);
220+
assert_eq!(ForeignAssetsPallet::<Test>::next_asset_index(), 3);
221+
});
222+
}

substrate/frame/assets/precompiles/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ mod mock;
4848
#[cfg(test)]
4949
mod tests;
5050

51-
pub use foreign_assets::{
52-
pallet, pallet::Config as ForeignAssetsConfig, ForeignAssetId, ToAssetIndex,
53-
};
51+
pub use foreign_assets::{pallet, pallet::Config as ForeignAssetsConfig, ForeignAssetId};
5452
pub use migration::{MigrateForeignAssetPrecompileMappings, MigrationState};
5553

5654
/// Mean of extracting the asset id from the precompile address.

0 commit comments

Comments
 (0)