git.delta.rocks / unique-network / refs/commits / 5ef5e6b4aa6d

difftreelog

fix make perf test seq and remove unused functions

Daniel Shiposha2023-10-02parent: #e105d72.patch.diff
in: master

2 files changed

addedtests/src/performance.seq.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/performance.seq.test.ts
@@ -0,0 +1,166 @@
+// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {ApiPromise} from '@polkadot/api';
+import {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from './util';
+import {ICrossAccountId, IProperty} from './util/playgrounds/types';
+import {UniqueHelper} from './util/playgrounds/unique';
+
+describe('Performace tests', () => {
+  let alice: IKeyringPair;
+  const MAX_TOKENS_TO_MINT = 200;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([100_000n], donor);
+    });
+  });
+
+  itSub('NFT tokens minting', async ({helper}) => {
+    const propertyKey = 'prop-a';
+    const collection = await helper.nft.mintCollection(alice, {
+      name: 'test properties',
+      description: 'test properties collection',
+      tokenPrefix: 'TPC',
+      tokenPropertyPermissions: [
+        {key: propertyKey, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
+      ],
+    });
+
+
+    const results = [];
+    const step = 1_000;
+    const sizeOfKey = sizeOfEncodedStr(propertyKey);
+    let currentSize = step;
+    let startCount = 0;
+    let minterFunc = tryMintUnsafeRPC;
+    try {
+      startCount = await tryMintUnsafeRPC(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});
+    }
+    catch (e) {
+      startCount = await tryMintExplicit(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});
+      minterFunc = tryMintExplicit;
+    }
+    results.push({propertySize: 0, tokens: startCount});
+
+    while(currentSize <= 32_000) {
+      const property = {key: propertyKey, value: 'A'.repeat(currentSize - sizeOfKey - sizeOfInt(currentSize))};
+      const maxTokens = Math.ceil(results.map(x => x.tokens).reduce((a, b) => a + b) / results.length);
+      const tokens = await minterFunc(helper, alice, maxTokens, collection.collectionId, {Substrate: alice.address}, property);
+      results.push({propertySize: sizeOfProperty(property), tokens});
+      currentSize += step;
+      await helper.wait.newBlocks(2);
+    }
+
+    expect(results).to.be.deep.equal([
+      {propertySize: 0, tokens: 200},
+      {propertySize: 1000, tokens: 149},
+      {propertySize: 2000, tokens: 149},
+      {propertySize: 3000, tokens: 149},
+      {propertySize: 4000, tokens: 149},
+      {propertySize: 5000, tokens: 149},
+      {propertySize: 6000, tokens: 149},
+      {propertySize: 7000, tokens: 149},
+      {propertySize: 8000, tokens: 149},
+      {propertySize: 9000, tokens: 149},
+      {propertySize: 10000, tokens: 149},
+      {propertySize: 11000, tokens: 149},
+      {propertySize: 12000, tokens: 149},
+      {propertySize: 13000, tokens: 149},
+      {propertySize: 14000, tokens: 149},
+      {propertySize: 15000, tokens: 149},
+      {propertySize: 16000, tokens: 149},
+      {propertySize: 17000, tokens: 149},
+      {propertySize: 18000, tokens: 149},
+      {propertySize: 19000, tokens: 149},
+      {propertySize: 20000, tokens: 149},
+      {propertySize: 21000, tokens: 149},
+      {propertySize: 22000, tokens: 149},
+      {propertySize: 23000, tokens: 149},
+      {propertySize: 24000, tokens: 149},
+      {propertySize: 25000, tokens: 149},
+      {propertySize: 26000, tokens: 149},
+      {propertySize: 27000, tokens: 145},
+      {propertySize: 28000, tokens: 140},
+      {propertySize: 29000, tokens: 135},
+      {propertySize: 30000, tokens: 130},
+      {propertySize: 31000, tokens: 126},
+      {propertySize: 32000, tokens: 122},
+    ]);
+  });
+});
+
+
+const dryRun = async (api: ApiPromise, signer: IKeyringPair, tx: any) => {
+  const signed = await tx.signAsync(signer);
+  const dryRun = await api.rpc.system.dryRun(signed.toHex());
+  return dryRun.isOk && dryRun.asOk.isOk;
+};
+
+const getTokens = (tokensCount: number, owner: ICrossAccountId, property?: IProperty) => (new Array(tokensCount)).fill(0).map(() => {
+  const token = {owner} as {owner: ICrossAccountId, properties?: IProperty[]};
+  if(property) token.properties = [property];
+  return token;
+});
+
+const tryMintUnsafeRPC = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {
+  if(tokensCount < 10) console.log('try mint', tokensCount, 'tokens');
+  const tokens = getTokens(tokensCount, owner, property);
+  const tx = helper.constructApiCall('api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
+  if(!(await dryRun(helper.getApi(), signer, tx))) {
+    if(tokensCount < 2) return 0;
+    return await tryMintUnsafeRPC(helper, signer, tokensCount - 1, collectionId, owner, property);
+  }
+  await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
+  return tokensCount;
+};
+
+const tryMintExplicit = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {
+  const tokens = getTokens(tokensCount, owner, property);
+  try {
+    await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
+  }
+  catch (e) {
+    if(tokensCount < 2) return 0;
+    return await tryMintExplicit(helper, signer, tokensCount - 1, collectionId, owner, property);
+  }
+  return tokensCount;
+};
+
+function sizeOfProperty(prop: IProperty) {
+  return sizeOfEncodedStr(prop.key) + sizeOfEncodedStr(prop.value!);
+}
+
+function sizeOfInt(i: number) {
+  if(i < 0 || i > 0xffffffff) throw new Error('out of range');
+  if(i < 0b11_1111) {
+    return 1;
+  } else if(i < 0b11_1111_1111_1111) {
+    return 2;
+  } else if(i < 0b11_1111_1111_1111_1111_1111_1111_1111) {
+    return 4;
+  } else {
+    return 5;
+  }
+}
+
+const UTF8_ENCODER = new TextEncoder();
+function sizeOfEncodedStr(v: string) {
+  const encoded = UTF8_ENCODER.encode(v);
+  return sizeOfInt(encoded.length) + encoded.length;
+}
deletedtests/src/performance.test.tsdiffbeforeafterboth
before · tests/src/performance.test.ts
1// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {ApiPromise} from '@polkadot/api';18import {IKeyringPair} from '@polkadot/types/types';19import {expect, itSub, usingPlaygrounds} from './util';20import {ICrossAccountId, IProperty} from './util/playgrounds/types';21import {UniqueHelper} from './util/playgrounds/unique';2223describe('Performace tests', () => {24  let alice: IKeyringPair;25  const MAX_TOKENS_TO_MINT = 200;2627  before(async () => {28    await usingPlaygrounds(async (helper, privateKey) => {29      const donor = await privateKey({url: import.meta.url});30      [alice] = await helper.arrange.createAccounts([100_000n], donor);31    });32  });3334  itSub('NFT tokens minting', async ({helper}) => {35    const propertyKey = 'prop-a';36    const collection = await helper.nft.mintCollection(alice, {37      name: 'test properties',38      description: 'test properties collection',39      tokenPrefix: 'TPC',40      tokenPropertyPermissions: [41        {key: propertyKey, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},42      ],43    });444546    const results = [];47    const step = 1_000;48    const sizeOfKey = sizeOfEncodedStr(propertyKey);49    let currentSize = step;50    let startCount = 0;51    let minterFunc = tryMintUnsafeRPC;52    try {53      startCount = await tryMintUnsafeRPC(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});54    }55    catch (e) {56      startCount = await tryMintExplicit(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});57      minterFunc = tryMintExplicit;58    }59    results.push({propertySize: 0, tokens: startCount});6061    while(currentSize <= 32_000) {62      const property = {key: propertyKey, value: 'A'.repeat(currentSize - sizeOfKey - sizeOfInt(currentSize))};63      const maxTokens = Math.ceil(results.map(x => x.tokens).reduce((a, b) => a + b) / results.length);64      const tokens = await minterFunc(helper, alice, maxTokens, collection.collectionId, {Substrate: alice.address}, property);65      results.push({propertySize: sizeOfProperty(property), tokens});66      currentSize += step;67      await helper.wait.newBlocks(2);68    }6970    expect(results).to.be.deep.equal([71      {propertySize: 0, tokens: 200},72      {propertySize: 1000, tokens: 149},73      {propertySize: 2000, tokens: 149},74      {propertySize: 3000, tokens: 149},75      {propertySize: 4000, tokens: 149},76      {propertySize: 5000, tokens: 149},77      {propertySize: 6000, tokens: 149},78      {propertySize: 7000, tokens: 149},79      {propertySize: 8000, tokens: 149},80      {propertySize: 9000, tokens: 149},81      {propertySize: 10000, tokens: 149},82      {propertySize: 11000, tokens: 149},83      {propertySize: 12000, tokens: 149},84      {propertySize: 13000, tokens: 149},85      {propertySize: 14000, tokens: 149},86      {propertySize: 15000, tokens: 149},87      {propertySize: 16000, tokens: 149},88      {propertySize: 17000, tokens: 149},89      {propertySize: 18000, tokens: 149},90      {propertySize: 19000, tokens: 149},91      {propertySize: 20000, tokens: 149},92      {propertySize: 21000, tokens: 149},93      {propertySize: 22000, tokens: 149},94      {propertySize: 23000, tokens: 149},95      {propertySize: 24000, tokens: 149},96      {propertySize: 25000, tokens: 149},97      {propertySize: 26000, tokens: 149},98      {propertySize: 27000, tokens: 145},99      {propertySize: 28000, tokens: 140},100      {propertySize: 29000, tokens: 135},101      {propertySize: 30000, tokens: 130},102      {propertySize: 31000, tokens: 126},103      {propertySize: 32000, tokens: 122},104    ]);105  });106});107108109const dryRun = async (api: ApiPromise, signer: IKeyringPair, tx: any) => {110  const signed = await tx.signAsync(signer);111  const dryRun = await api.rpc.system.dryRun(signed.toHex());112  return dryRun.isOk && dryRun.asOk.isOk;113};114115const getTokens = (tokensCount: number, owner: ICrossAccountId, property?: IProperty) => (new Array(tokensCount)).fill(0).map(() => {116  const token = {owner} as {owner: ICrossAccountId, properties?: IProperty[]};117  if(property) token.properties = [property];118  return token;119});120121const tryMintUnsafeRPC = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {122  if(tokensCount < 10) console.log('try mint', tokensCount, 'tokens');123  const tokens = getTokens(tokensCount, owner, property);124  const tx = helper.constructApiCall('api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);125  if(!(await dryRun(helper.getApi(), signer, tx))) {126    if(tokensCount < 2) return 0;127    return await tryMintUnsafeRPC(helper, signer, tokensCount - 1, collectionId, owner, property);128  }129  await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);130  return tokensCount;131};132133const tryMintExplicit = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {134  const tokens = getTokens(tokensCount, owner, property);135  try {136    await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);137  }138  catch (e) {139    if(tokensCount < 2) return 0;140    return await tryMintExplicit(helper, signer, tokensCount - 1, collectionId, owner, property);141  }142  return tokensCount;143};144145146function sizeOfByteProperty(prop: IProperty) {147  return sizeOfEncodedBytes(prop.key) + sizeOfEncodedBytes(prop.value!);148}149150function sizeOfProperty(prop: IProperty) {151  return sizeOfEncodedStr(prop.key) + sizeOfEncodedStr(prop.value!);152}153154function sizeOfInt(i: number) {155  if(i < 0 || i > 0xffffffff) throw new Error('out of range');156  if(i < 0b11_1111) {157    return 1;158  } else if(i < 0b11_1111_1111_1111) {159    return 2;160  } else if(i < 0b11_1111_1111_1111_1111_1111_1111_1111) {161    return 4;162  } else {163    return 5;164  }165}166167const UTF8_ENCODER = new TextEncoder();168function sizeOfEncodedStr(v: string) {169  const encoded = UTF8_ENCODER.encode(v);170  return sizeOfInt(encoded.length) + encoded.length;171}172173function sizeOfEncodedBytes(bytes: Uint8Array | string) {174  return sizeOfInt(bytes.length) + bytes.length;175}