From bab6ffec254b180afaa4aa80b6402ff5daef3c99 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Fri, 12 Feb 2021 06:35:37 +0000 Subject: [PATCH] Merge branch 'develop' into feature/NFTPAR-281_overflow_tests --- --- a/tests/package.json +++ b/tests/package.json @@ -20,6 +20,7 @@ "scripts": { "test": "mocha --timeout 9999999 -r ts-node/register ./**/*.test.ts", "load": "mocha --timeout 9999999 -r ts-node/register ./**/*.load.ts", + "loadTransfer": "ts-node src/transfer.nload.ts", "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts", "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts", "testSetVariableMetaData": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetaData.test.ts", --- /dev/null +++ b/tests/src/transfer.nload.ts @@ -0,0 +1,113 @@ +import { ApiPromise } from "@polkadot/api"; +import { IKeyringPair } from '@polkadot/types/types'; +import privateKey from "./substrate/privateKey"; +import usingApi, { submitTransactionAsync } from "./substrate/substrate-api"; +import waitNewBlocks from "./substrate/wait-new-blocks"; +import { findUnusedAddresses } from "./util/helpers"; +import * as cluster from 'cluster'; +import os from 'os'; + +// Innacurate transfer fee +const FEE = 10n ** 8n; + +let counters: { [key: string]: number } = {}; +function increaseCounter(name: string, amount: number) { + if (!counters[name]) { + counters[name] = 0; + } + counters[name] += amount; +} +function flushCounterToMaster() { + if (Object.keys(counters).length === 0) { + return; + } + process.send!(counters); + counters = {}; +} + +async function distributeBalance(source: IKeyringPair, api: ApiPromise, totalAmount: bigint, stages: number) { + let accounts = [source]; + // we don't need source in output array + const failedAccounts = [0]; + + const finalUserAmount = 2 ** stages - 1; + accounts.push(...await findUnusedAddresses(api, finalUserAmount)); + // findUnusedAddresses produces at least 1 request per user + increaseCounter('requests', finalUserAmount); + + for (let stage = 0; stage < stages; stage++) { + let usersWithBalance = 2 ** stage; + let amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage); + // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`); + let txs = []; + for (let i = 0; i < usersWithBalance; i++) { + let newUser = accounts[i + usersWithBalance]; + // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`); + const tx = api.tx.balances.transfer(newUser.address, amount); + txs.push(submitTransactionAsync(accounts[i], tx).catch(e => { + failedAccounts.push(i + usersWithBalance); + increaseCounter('txFailed', 1); + })); + increaseCounter('tx', 1); + } + await Promise.all(txs); + } + + for (let account of failedAccounts.reverse()) { + accounts.splice(account, 1); + } + return accounts; +} + +if (cluster.isMaster) { + let testDone = false; + usingApi(async (api) => { + let prevCounters: { [key: string]: number } = {}; + while (!testDone) { + for (let name in counters) { + if (!(name in prevCounters)) { + prevCounters[name] = 0; + } + if(counters[name] === prevCounters[name]) { + continue; + } + console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`); + prevCounters[name] = counters[name]; + } + await waitNewBlocks(api, 1); + } + }); + let waiting: Promise[] = []; + console.log(`Starting ${os.cpus().length} workers`); + usingApi(async (api) => { + const alice = privateKey('//Alice'); + for (let id in os.cpus()) { + const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`; + const workerAccount = privateKey(WORKER_NAME); + const tx = api.tx.balances.transfer(workerAccount.address, 400n * 10n ** 23n); + await submitTransactionAsync(alice, tx); + + let worker = cluster.fork({ + WORKER_NAME, + STAGES: id + 2 + }); + worker.on('message', msg => { + for (let key in msg) { + increaseCounter(key, msg[key]); + } + }); + waiting.push(new Promise(res => worker.on('exit', res))); + } + await Promise.all(waiting); + testDone = true; + }) +} else { + increaseCounter('startedWorkers', 1); + usingApi(async (api) => { + await distributeBalance(privateKey(process.env.WORKER_NAME as string), api, 400n * 10n ** 22n, 10); + }); + const interval = setInterval(() => { + flushCounterToMaster(); + }, 100); + interval.unref(); +} \ No newline at end of file --- a/tests/src/util/helpers.ts +++ b/tests/src/util/helpers.ts @@ -228,11 +228,11 @@ }); } -export async function findUnusedAddress(api: ApiPromise): Promise { +export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise { let bal = new BigNumber(0); let unused; do { - const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)); + const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition; const keyring = new Keyring({ type: 'sr25519' }); unused = keyring.addFromUri(`//${randomSeed}`); bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString()); -- gitstuff