git.delta.rocks / unique-network / refs/commits / 2a4f1af36afb

difftreelog

feat(repair-item) change to force_repair_item + add force_repair_collection + tests

Fahrrader2022-12-16parent: #669456d.patch.diff
in: master

10 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
1731 Ok(new_permission)1731 Ok(new_permission)
1732 }1732 }
1733
1734 /// Repair possibly broken properties of a collection.
1735 pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {
1736 CollectionProperties::<T>::mutate(collection_id, |properties| {
1737 properties.recompute_consumed_space();
1738 });
1739
1740 Ok(())
1741 }
1733}1742}
17341743
1735/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1744/// Indicates unsupported methods by returning [Error::UnsupportedOperation].
1819 fn set_allowance_for_all() -> Weight;1828 fn set_allowance_for_all() -> Weight;
18201829
1821 /// The price of repairing an item.1830 /// The price of repairing an item.
1822 fn repair_item() -> Weight;1831 fn force_repair_item() -> Weight;
1823}1832}
18241833
1825/// Weight info extension trait for refungible pallet.1834/// Weight info extension trait for refungible pallet.
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
113 Weight::zero()113 Weight::zero()
114 }114 }
115115
116 fn repair_item() -> Weight {116 fn force_repair_item() -> Weight {
117 Weight::zero()117 Weight::zero()
118 }118 }
119}119}
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
127 <SelfWeightOf<T>>::set_allowance_for_all()127 <SelfWeightOf<T>>::set_allowance_for_all()
128 }128 }
129129
130 fn repair_item() -> Weight {130 fn force_repair_item() -> Weight {
131 <SelfWeightOf<T>>::repair_item()131 <SelfWeightOf<T>>::repair_item()
132 }132 }
133}133}
540 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {540 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {
541 with_weight(541 with_weight(
542 <Pallet<T>>::repair_item(self, token),542 <Pallet<T>>::repair_item(self, token),
543 <CommonWeights<T>>::repair_item(),543 <CommonWeights<T>>::force_repair_item(),
544 )544 )
545 }545 }
546}546}
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
157 <SelfWeightOf<T>>::set_allowance_for_all()157 <SelfWeightOf<T>>::set_allowance_for_all()
158 }158 }
159159
160 fn repair_item() -> Weight {160 fn force_repair_item() -> Weight {
161 <SelfWeightOf<T>>::repair_item()161 <SelfWeightOf<T>>::repair_item()
162 }162 }
163}163}
544 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {544 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {
545 with_weight(545 with_weight(
546 <Pallet<T>>::repair_item(self, token),546 <Pallet<T>>::repair_item(self, token),
547 <CommonWeights<T>>::repair_item(),547 <CommonWeights<T>>::force_repair_item(),
548 )548 )
549 }549 }
550}550}
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
82 BoundedVec,82 BoundedVec,
83};83};
84use scale_info::TypeInfo;84use scale_info::TypeInfo;
85use frame_system::{self as system, ensure_signed};85use frame_system::{self as system, ensure_signed, ensure_root};
86use sp_std::{vec, vec::Vec};86use sp_std::{vec, vec::Vec};
87use up_data_structs::{87use up_data_structs::{
88 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,88 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
983 })983 })
984 }984 }
985985
986 /// Repairs a broken item986 /// Repairs a collection's properties if the data was somehow corrupted.
987 ///
988 /// # Arguments
989 ///
990 /// * `collection_id`: ID of the collection to repair.
991 #[weight = <SelfWeightOf<T>>::force_repair_collection()]
992 pub fn force_repair_collection(
993 origin,
994 collection_id: CollectionId,
995 ) -> DispatchResult {
996 ensure_root(origin)?;
997 <PalletCommon<T>>::repair_collection(collection_id)
998 }
999
1000 /// Repairs a token's properties if the data was somehow corrupted.
987 ///1001 ///
988 /// # Arguments1002 /// # Arguments
989 ///1003 ///
990 /// * `collection_id`: ID of the collection the item belongs to.1004 /// * `collection_id`: ID of the collection the item belongs to.
991 /// * `item_id`: ID of the item.1005 /// * `item_id`: ID of the item.
992 #[weight = T::CommonWeightInfo::repair_item()]1006 #[weight = T::CommonWeightInfo::force_repair_item()]
993 pub fn repair_item(1007 pub fn force_repair_item(
994 _origin,1008 origin,
995 collection_id: CollectionId,1009 collection_id: CollectionId,
996 item_id: TokenId,1010 item_id: TokenId,
997 ) -> DispatchResultWithPostInfo {1011 ) -> DispatchResultWithPostInfo {
1012 ensure_root(origin)?;
998 dispatch_tx::<T, _>(collection_id, |d| {1013 dispatch_tx::<T, _>(collection_id, |d| {
999 d.repair_item(item_id)1014 d.repair_item(item_id)
1000 })1015 })
modifiedpallets/unique/src/weights.rsdiffbeforeafterboth
45 fn remove_collection_sponsor() -> Weight;45 fn remove_collection_sponsor() -> Weight;
46 fn set_transfers_enabled_flag() -> Weight;46 fn set_transfers_enabled_flag() -> Weight;
47 fn set_collection_limits() -> Weight;47 fn set_collection_limits() -> Weight;
48 fn force_repair_collection() -> Weight;
48}49}
4950
50/// Weights for pallet_unique using the Substrate node and recommended hardware.51/// Weights for pallet_unique using the Substrate node and recommended hardware.
139 .saturating_add(T::DbWeight::get().reads(1 as u64))140 .saturating_add(T::DbWeight::get().reads(1 as u64))
140 .saturating_add(T::DbWeight::get().writes(1 as u64))141 .saturating_add(T::DbWeight::get().writes(1 as u64))
141 }142 }
143 // Storage: Common CollectionProperties (r:1 w:1)
144 fn force_repair_collection() -> Weight {
145 Weight::from_ref_time(5_701_000 as u64)
146 .saturating_add(T::DbWeight::get().reads(1 as u64))
147 .saturating_add(T::DbWeight::get().writes(1 as u64))
148 }
142}149}
143150
144// For backwards compatibility and tests151// For backwards compatibility and tests
232 .saturating_add(RocksDbWeight::get().reads(1 as u64))239 .saturating_add(RocksDbWeight::get().reads(1 as u64))
233 .saturating_add(RocksDbWeight::get().writes(1 as u64))240 .saturating_add(RocksDbWeight::get().writes(1 as u64))
234 }241 }
242 // Storage: Common CollectionProperties (r:1 w:1)
243 fn force_repair_collection() -> Weight {
244 Weight::from_ref_time(5_701_000 as u64)
245 .saturating_add(RocksDbWeight::get().reads(1 as u64))
246 .saturating_add(RocksDbWeight::get().writes(1 as u64))
247 }
235}248}
236249
modifiedruntime/common/weights.rsdiffbeforeafterboth
125 max_weight_of!(set_allowance_for_all())125 max_weight_of!(set_allowance_for_all())
126 }126 }
127127
128 fn repair_item() -> Weight {128 fn force_repair_item() -> Weight {
129 max_weight_of!(repair_item())129 max_weight_of!(force_repair_item())
130 }130 }
131}131}
132132
modifiedtests/package.jsondiffbeforeafterboth
46 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",46 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",
47 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts ./**/tokenProperties.test.ts ./**/getPropertiesRpc.test.ts",47 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts ./**/tokenProperties.test.ts ./**/getPropertiesRpc.test.ts",
48 "testCollectionProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts",48 "testCollectionProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts",
49 "testTokenProperties": "mocha --timeout 9999999 -r ts-node/register ./**/tokenProperties.test.ts",
49 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",50 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",
50 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",51 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",
51 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",52 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",
modifiedtests/src/nesting/collectionProperties.test.tsdiffbeforeafterboth
18import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util';18import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util';
1919
20describe('Integration Test: Collection Properties', () => {20describe('Integration Test: Collection Properties', () => {
21 let superuser: IKeyringPair;
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
22 let bob: IKeyringPair;23 let bob: IKeyringPair;
23 24
24 before(async () => {25 before(async () => {
25 await usingPlaygrounds(async (helper, privateKey) => {26 await usingPlaygrounds(async (helper, privateKey) => {
27 superuser = await privateKey('//Alice');
26 const donor = await privateKey({filename: __filename});28 const donor = await privateKey({filename: __filename});
27 [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor);29 [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor);
28 });30 });
200 expect(consumedSpace).to.be.equal(biggerPropDataSize - expectedConsumedSpaceDiff);202 expect(consumedSpace).to.be.equal(biggerPropDataSize - expectedConsumedSpaceDiff);
201 });203 });
204
205 itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {
206 const properties = [
207 {key: 'sea-creatures', value: 'mermaids'},
208 {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
209 ];
210 const collection = await helper[testSuite.mode].mintCollection(alice, {properties});
211
212 const newProperty = ' '.repeat(4096);
213 await collection.setProperties(alice, [{key: 'space', value: newProperty}]);
214 const originalSpace = await collection.getPropertiesConsumedSpace();
215 expect(originalSpace).to.be.equal(properties[0].value.length + properties[1].value.length + newProperty.length);
216
217 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true);
218 const recomputedSpace = await collection.getPropertiesConsumedSpace();
219 expect(recomputedSpace).to.be.equal(originalSpace);
220 });
202 }));221 }));
203});222});
204 223
315 }334 }
316 });335 });
336
337 itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {
338 const collection = await helper[testSuite.mode].mintCollection(alice, {properties: [
339 {key: 'sea-creatures', value: 'mermaids'},
340 {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
341 ]});
342
343 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true))
344 .to.be.rejectedWith(/BadOrigin/);
345 });
317 }));346 }));
318});347});
319 348
modifiedtests/src/nesting/tokenProperties.test.tsdiffbeforeafterboth
19import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';19import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';
2020
21describe('Integration Test: Token Properties', () => {21describe('Integration Test: Token Properties', () => {
22 let superuser: IKeyringPair;
22 let alice: IKeyringPair; // collection owner23 let alice: IKeyringPair; // collection owner
23 let bob: IKeyringPair; // collection admin24 let bob: IKeyringPair; // collection admin
24 let charlie: IKeyringPair; // token owner25 let charlie: IKeyringPair; // token owner
2728
28 before(async () => {29 before(async () => {
29 await usingPlaygrounds(async (helper, privateKey) => {30 await usingPlaygrounds(async (helper, privateKey) => {
31 superuser = await privateKey('//Alice');
30 const donor = await privateKey({filename: __filename});32 const donor = await privateKey({filename: __filename});
31 [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);33 [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);
32 });34 });
406 {mode: 'nft' as const, pieces: undefined, requiredPallets: []},408 {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
407 {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, 409 {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
408 ].map(testCase =>410 ].map(testCase =>
409 itSub.ifWithPallets(`repair_item preserves valid consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {411 itSub.ifWithPallets(`force_repair_item preserves valid consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
410 const propKey = 'tok-prop';412 const propKey = 'tok-prop';
411413
412 const collection = await helper[testCase.mode].mintCollection(alice, {414 const collection = await helper[testCase.mode].mintCollection(alice, {
430 const originalSpace = await token.getTokenPropertiesConsumedSpace();432 const originalSpace = await token.getTokenPropertiesConsumedSpace();
431 expect(originalSpace).to.be.equal(propDataSize);433 expect(originalSpace).to.be.equal(propDataSize);
432434
433 await helper.executeExtrinsic(alice, 'api.tx.unique.repairItem', [token.collectionId, token.tokenId], true);435 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true);
434 const recomputedSpace = await token.getTokenPropertiesConsumedSpace();436 const recomputedSpace = await token.getTokenPropertiesConsumedSpace();
435 expect(recomputedSpace).to.be.equal(originalSpace);437 expect(recomputedSpace).to.be.equal(originalSpace);
436 }));438 }));
698 }])).to.be.rejectedWith(/common\.PropertyLimitReached/);700 }])).to.be.rejectedWith(/common\.PropertyLimitReached/);
699 }));701 }));
702
703 [
704 {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
705 {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
706 ].map(testCase =>
707 itSub.ifWithPallets(`Forbids force_repair_item from non-sudo (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
708 const propKey = 'tok-prop';
709
710 const collection = await helper[testCase.mode].mintCollection(alice, {
711 tokenPropertyPermissions: [
712 {
713 key: propKey,
714 permission: {mutable: true, tokenOwner: true},
715 },
716 ],
717 });
718 const token = await (
719 testCase.pieces
720 ? collection.mintToken(alice, testCase.pieces)
721 : collection.mintToken(alice)
722 );
723
724 const propDataSize = 4096;
725 const propData = 'a'.repeat(propDataSize);
726 await token.setProperties(alice, [{key: propKey, value: propData}]);
727
728 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true))
729 .to.be.rejectedWith(/BadOrigin/);
730 }));
700});731});
701732
702describe('ReFungible token properties permissions tests', () => {733describe('ReFungible token properties permissions tests', () => {