git.delta.rocks / unique-network / refs/commits / e4eea6c1f0ba

difftreelog

source

js-packages/scripts/transfer.nload.ts5.3 KiBsourcehistory
1// Copyright 2019-2022 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/>.1617/* eslint-disable @typescript-eslint/no-floating-promises */18import os from 'os';19import type {IKeyringPair} from '@polkadot/types/types';20import {usingPlaygrounds} from '@unique/test-utils/util.js';21import {UniqueHelper} from '@unique-nft/playgrounds/unique.js';22import * as notReallyCluster from 'cluster'; // https://github.com/nodejs/node/issues/42271#issuecomment-106341534623const cluster = notReallyCluster as unknown as notReallyCluster.Cluster;2425async function findUnusedAddress(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, seedAddition = ''): Promise<IKeyringPair> {26  let bal = 0n;27  let unused;28  do {29    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;30    unused = await privateKey(`//${randomSeed}`);31    bal = await helper.balance.getSubstrate(unused.address);32  } while(bal !== 0n);33  return unused;34}3536function findUnusedAddresses(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, amount: number): Promise<IKeyringPair[]> {37  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(helper, privateKey, '_' + Date.now())));38}3940// Innacurate transfer fee41const FEE = 10n ** 8n;4243let counters: { [key: string]: number } = {};44function increaseCounter(name: string, amount: number) {45  if(!counters[name]) {46    counters[name] = 0;47  }48  counters[name] += amount;49}50function flushCounterToMaster() {51  if(Object.keys(counters).length === 0) {52    return;53  }54    process.send!(counters);55    counters = {};56}5758async function distributeBalance(source: IKeyringPair, helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, totalAmount: bigint, stages: number) {59  const accounts = [source];60  // we don't need source in output array61  const failedAccounts = [0];6263  const finalUserAmount = 2 ** stages - 1;64  accounts.push(...await findUnusedAddresses(helper, privateKey, finalUserAmount));65  // findUnusedAddresses produces at least 1 request per user66  increaseCounter('requests', finalUserAmount);6768  for(let stage = 0; stage < stages; stage++) {69    const usersWithBalance = 2 ** stage;70    const amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage);71    // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`);72    const txs: Promise<boolean | void>[] = [];73    for(let i = 0; i < usersWithBalance; i++) {74      const newUser = accounts[i + usersWithBalance];75      // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`);76      const tx = helper.balance.transferToSubstrate(accounts[i], newUser.address, amount);77      txs.push(tx.catch(() => {78        failedAccounts.push(i + usersWithBalance);79        increaseCounter('txFailed', 1);80      }));81      increaseCounter('tx', 1);82    }83    await Promise.all(txs);84  }8586  for(const account of failedAccounts.reverse()) {87    accounts.splice(account, 1);88  }89  return accounts;90}9192if(cluster.isMaster) {93  let testDone = false;94  usingPlaygrounds(async (helper) => {95    const prevCounters: { [key: string]: number } = {};96    while(!testDone) {97      for(const name in counters) {98        if(!(name in prevCounters)) {99          prevCounters[name] = 0;100        }101        if(counters[name] === prevCounters[name]) {102          continue;103        }104        console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`);105        prevCounters[name] = counters[name];106      }107      await helper.wait.newBlocks(1);108    }109  });110  const waiting: Promise<void>[] = [];111  console.log(`Starting ${os.cpus().length} workers`);112  usingPlaygrounds(async (helper, privateKey) => {113    const alice = await privateKey('//Alice');114    for(const id in os.cpus()) {115      const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`;116      const workerAccount = await privateKey(WORKER_NAME);117      await helper.balance.transferToSubstrate(alice, workerAccount.address, 400n * 10n ** 23n);118119      const worker = cluster.fork({120        WORKER_NAME,121        STAGES: id + 2,122      });123      worker.on('message', msg => {124        for(const key in msg) {125          increaseCounter(key, msg[key]);126        }127      });128      waiting.push(new Promise(res => worker.on('exit', res)));129    }130    await Promise.all(waiting);131    testDone = true;132  });133} else {134  increaseCounter('startedWorkers', 1);135  usingPlaygrounds(async (helper, privateKey) => {136    await distributeBalance(await privateKey(process.env.WORKER_NAME as string), helper, privateKey, 400n * 10n ** 22n, 10);137  });138  const interval = setInterval(() => {139    flushCounterToMaster();140  }, 100);141  interval.unref();142}