difftreelog
feat(repair-item) change to force_repair_item + add force_repair_collection + tests
in: master
10 files changed
pallets/common/src/lib.rsdiffbeforeafterboth1731 Ok(new_permission)1731 Ok(new_permission)1732 }1732 }17331734 /// 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 });17391740 Ok(())1741 }1733}1742}173417431735/// 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;182018291821 /// 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}182418331825/// Weight info extension trait for refungible pallet.1834/// Weight info extension trait for refungible pallet.pallets/fungible/src/common.rsdiffbeforeafterboth113 Weight::zero()113 Weight::zero()114 }114 }115115116 fn repair_item() -> Weight {116 fn force_repair_item() -> Weight {117 Weight::zero()117 Weight::zero()118 }118 }119}119}pallets/nonfungible/src/common.rsdiffbeforeafterboth127 <SelfWeightOf<T>>::set_allowance_for_all()127 <SelfWeightOf<T>>::set_allowance_for_all()128 }128 }129129130 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}pallets/refungible/src/common.rsdiffbeforeafterboth157 <SelfWeightOf<T>>::set_allowance_for_all()157 <SelfWeightOf<T>>::set_allowance_for_all()158 }158 }159159160 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}pallets/unique/src/lib.rsdiffbeforeafterboth82 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 }985985986 /// Repairs a broken item986 /// Repairs a collection's properties if the data was somehow corrupted.987 ///988 /// # Arguments989 ///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 }9991000 /// Repairs a token's properties if the data was somehow corrupted.987 ///1001 ///988 /// # Arguments1002 /// # Arguments989 ///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 })pallets/unique/src/weights.rsdiffbeforeafterboth45 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}495050/// 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}143150144// For backwards compatibility and tests151// For backwards compatibility and tests232 .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}236249runtime/common/weights.rsdiffbeforeafterboth125 max_weight_of!(set_allowance_for_all())125 max_weight_of!(set_allowance_for_all())126 }126 }127127128 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}132132tests/package.jsondiffbeforeafterboth46 "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",tests/src/nesting/collectionProperties.test.tsdiffbeforeafterboth18import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util';18import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util';191920describe('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 });204205 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});211212 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);216217 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 });336337 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 ]});342343 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true))344 .to.be.rejectedWith(/BadOrigin/);345 });317 }));346 }));318});347});319 348 tests/src/nesting/tokenProperties.test.tsdiffbeforeafterboth19import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';19import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';202021describe('Integration Test: Token Properties', () => {21describe('Integration Test: Token Properties', () => {22 let superuser: IKeyringPair;22 let alice: IKeyringPair; // collection owner23 let alice: IKeyringPair; // collection owner23 let bob: IKeyringPair; // collection admin24 let bob: IKeyringPair; // collection admin24 let charlie: IKeyringPair; // token owner25 let charlie: IKeyringPair; // token owner272828 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';411413412 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);432434433 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 }));702703 [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';709710 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.pieces720 ? collection.mintToken(alice, testCase.pieces)721 : collection.mintToken(alice)722 );723724 const propDataSize = 4096;725 const propData = 'a'.repeat(propDataSize);726 await token.setProperties(alice, [{key: propKey, value: propData}]);727728 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true))729 .to.be.rejectedWith(/BadOrigin/);730 }));700});731});701732702describe('ReFungible token properties permissions tests', () => {733describe('ReFungible token properties permissions tests', () => {