UNPKG

@hashgraph/hedera-local

Version:

Developer tooling for running Local Hedera Network (Consensus + Mirror Nodes).

401 lines 19.3 kB
"use strict"; // SPDX-License-Identifier: Apache-2.0 var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccountCreationState = void 0; const path_1 = __importDefault(require("path")); const fs_1 = require("fs"); const csv_parser_1 = __importDefault(require("csv-parser")); const sdk_1 = require("@hashgraph/sdk"); const LoggerService_1 = require("../services/LoggerService"); const ServiceLocator_1 = require("../services/ServiceLocator"); const EventType_1 = require("../types/EventType"); const CLIService_1 = require("../services/CLIService"); const ClientService_1 = require("../services/ClientService"); const accountConfiguration_json_1 = require("../configuration/accountConfiguration.json"); const constants_1 = require("../constants"); const local_json_1 = __importDefault(require("../configuration/local.json")); const AccountUtils_1 = require("../utils/AccountUtils"); const RetryUtils_1 = require("../utils/RetryUtils"); /** * Represents the state of account creation. * This class is responsible for initializing the AccountCreationState object. * @implements {IState} */ class AccountCreationState { /** * Represents the state of account creation. * This class is responsible for initializing the AccountCreationState object. */ constructor() { this.shouldRetry = (error) => { var _a; return (_a = error === null || error === void 0 ? void 0 : error.toString().includes(constants_1.SDK_ERRORS.FAILED_TO_FIND_A_HEALTHY_NODE)) !== null && _a !== void 0 ? _a : false; }; this.doOnRetry = (error) => { this.logger.warn(`Error occurred during task execution: "${error === null || error === void 0 ? void 0 : error.toString()}"`, this.stateName); }; this.stateName = AccountCreationState.name; this.logger = ServiceLocator_1.ServiceLocator.Current.get(LoggerService_1.LoggerService.name); this.cliService = ServiceLocator_1.ServiceLocator.Current.get(CLIService_1.CLIService.name); this.clientService = ServiceLocator_1.ServiceLocator.Current.get(ClientService_1.ClientService.name); this.nodeStartup = true; this.logger.trace(constants_1.ACCOUNT_CREATION_STATE_INIT_MESSAGE, this.stateName); } /** * Subscribes an observer to receive updates from the AccountCreationState. * @param {IOBserver} observer The observer to subscribe. */ subscribe(observer) { this.observer = observer; } /** * Starts the account creation state. * * This method retrieves the current arguments, checks if blocklisting is enabled, and if so, gets the count of blocklisted accounts. * It logs the start of the account creation state, retrieves the balance and number of accounts from the arguments, and sets the node startup. * If the mode is asynchronous, it generates accounts asynchronously, otherwise, it generates ECDSA, alias ECDSA, and ED25519 accounts. * Finally, it updates the observer with the finish event type. * * @returns {Promise<void>} A Promise that resolves when the state is started. * @emits {EventType.Finish} When the state is finished. */ onStart() { return __awaiter(this, void 0, void 0, function* () { const { async, blocklisting, accounts, balance, startup } = this.cliService.getCurrentArgv(); this.nodeStartup = startup; let blocklistedAccountsCount = 0; if (blocklisting) { blocklistedAccountsCount = yield this.getBlocklistedAccountsCount(); } const mode = async ? 'asynchronous' : 'synchronous'; const blockListedMessage = blocklisting ? `with ${blocklistedAccountsCount} blocklisted accounts` : ''; this.logger.info(`${constants_1.LOADING} Starting Account Creation state in ${mode} mode ${blockListedMessage}...`, this.stateName); const promise = this.generateAccounts(balance, accounts); if (!async) { yield promise; } this.logger.info(`${constants_1.CHECK_SUCCESS} Accounts created succefully!`, this.stateName); this.observer.update(EventType_1.EventType.Finish); }); } /** * Generates accounts. * * This method generates ECDSA, alias ECDSA, and ED25519 accounts. * * @private * @param {number} balance - The balance for the accounts. * @param {number} accounts - The number of accounts to generate. * @returns {Promise<void>} - A promise that resolves when the accounts have been generated. */ generateAccounts(balance, accounts) { return __awaiter(this, void 0, void 0, function* () { yield Promise.all([ this.generateECDSA(balance, accounts), this.generateAliasECDSA(balance, accounts), this.generateED25519(balance, accounts) ]); }); } /** * Generates ECDSA accounts. * * If the node is in startup mode: * - it uses the private keys from the ECDSA private keys array to create the account. * - otherwise, it generates new ECDSA private keys. * * @private * @param {number} balance - The balance for the accounts. * @param {number} limit - The number of accounts to generate. * @returns {Promise<Account[]>} - A promise that resolves when all the accounts have been created. */ generateECDSA(balance, limit) { return __awaiter(this, void 0, void 0, function* () { const accountData = this.nodeStartup ? accountConfiguration_json_1.privateKeysECDSA.map(privateKeyString => ({ balance, privateKey: sdk_1.PrivateKey.fromStringECDSA(privateKeyString) })) : Array.from({ length: limit }, () => ({ balance, privateKey: sdk_1.PrivateKey.generateECDSA() })); const endIndex = Math.min(accountData.length, limit); return this.createAccounts('ECDSA', accountData.slice(0, endIndex)); }); } /** * Generates alias ECDSA accounts. * * If the node is in startup mode and the private key for the alias ECDSA account exists: * - it uses the private key to create the account. * - otherwise, it generates new ECDSA private keys. * * If the mode is asynchronous: * - it creates the alias accounts asynchronously and returns a promise that resolves when they have been created, * - otherwise, it creates the alias accounts synchronously and returns them in a resolved promise. * * @private * @param {number} balance - The balance for the accounts. * @param {number} accountNum - The number of accounts to generate. * @returns {Promise<Account[]>} - A promise that resolves when all the alias accounts have been created */ generateAliasECDSA(balance, accountNum) { return __awaiter(this, void 0, void 0, function* () { const accountData = this.nodeStartup ? accountConfiguration_json_1.privateKeysAliasECDSA.map(privateKeyString => ({ balance, privateKey: sdk_1.PrivateKey.fromStringECDSA(privateKeyString) })) : Array.from({ length: accountNum }, () => ({ balance, privateKey: sdk_1.PrivateKey.generateECDSA() })); const endIndex = Math.min(accountData.length, accountNum); return this.createAliasAccounts(accountData.slice(0, endIndex)); }); } /** * Generates ED25519 accounts. * * If the node is in startup mode: * - it uses the private keys from the ED25519 private keys array to create the account. * - otherwise, it generates new ED25519 private keys. * * @param balance - The balance for the accounts. * @param limit - The number of accounts to generate. * @returns {Promise<Account[]>} - A promise that resolves when all the * accounts have been created if the mode is asynchronous, otherwise void. * @private */ generateED25519(balance, limit) { return __awaiter(this, void 0, void 0, function* () { const accountData = this.nodeStartup ? accountConfiguration_json_1.privateKeysED25519.map(privateKeyString => ({ balance, privateKey: sdk_1.PrivateKey.fromStringED25519(privateKeyString) })) : Array.from({ length: limit }, () => ({ balance, privateKey: sdk_1.PrivateKey.generateED25519() })); const endIndex = Math.min(accountData.length, limit); return this.createAccounts('ED25519', accountData.slice(0, endIndex)); }); } /** * Generates ED25519 accounts. * * @private * @param {string} title - The title to be logged for the account list. * @param {Array<{ balance: number, privateKey: PrivateKey}>} accountData - The data for the accounts that will be created. * @param {number} accountData.balance - The balance of the account to create. * @param {PrivateKey} accountData.privateKey - The private key of the account to create. * @returns {Promise<Account[]>} - A promise that resolves when all the accounts have been created. */ createAccounts(title, accountData) { return __awaiter(this, void 0, void 0, function* () { const accountPromises = []; accountData.forEach((account) => { const { privateKey, balance } = account; const client = this.clientService.getClient(); const publicKey = privateKey.publicKey; const createAccountPromise = RetryUtils_1.RetryUtils.retryTask(() => AccountUtils_1.AccountUtils.createAccount(publicKey, balance, client), { shouldRetry: error => this.shouldRetry(error), doOnRetry: error => this.doOnRetry(error) }).then((accountInfo) => { const address = accountInfo.accountId.toSolidityAddress(); return { accountId: accountInfo.accountId.toString(), balance: accountInfo.balance, privateKey, address }; }); accountPromises.push(createAccountPromise); }); return Promise.all(accountPromises) .then((accounts) => { if (accounts) { this.logAccountTitle(title); accounts.forEach((account) => this.logAccount(account.accountId, account.balance, `0x${account.privateKey.toStringRaw()}`)); this.logAccountDivider(); } return accounts; }); }); } /** * Creates alias accounts. * * @param accountData - The data for the accounts that will be created. * @param accountData.balance - The balance of the account to create. * @param accountData.privateKey - The private key of the account to create. * @returns {Promise<Account[]>} - A promise that resolves when all the alias accounts have been created * @private */ createAliasAccounts(accountData) { return __awaiter(this, void 0, void 0, function* () { const accountPromises = []; // eslint-disable-next-line no-plusplus accountData.forEach(account => { const { privateKey, balance } = account; const client = this.clientService.getClient(); const aliasAccountId = privateKey.publicKey.toAccountId(0, 0); const createAccountPromise = RetryUtils_1.RetryUtils.retryTask(() => AccountUtils_1.AccountUtils.createAliasedAccount(aliasAccountId, balance, client), { shouldRetry: error => this.shouldRetry(error), doOnRetry: error => this.doOnRetry(error) }).then((accountInfo) => { const address = privateKey.publicKey.toEvmAddress(); return { accountId: accountInfo.accountId.toString(), balance: accountInfo.balance, privateKey, address }; }); accountPromises.push(createAccountPromise); }); return Promise.all(accountPromises) .then((accounts) => { if (accounts) { this.logAliasAccountTitle(); accounts.forEach((account) => this.logAliasAccount(account.accountId, account.balance, `0x${account.address}`, `0x${account.privateKey.toStringRaw()}`)); this.logAliasAccountDivider(); } return accounts; }); }); } /** * Retrieves the blocklist file name. * * This method searches the properties of the node configuration for the property with the key 'accounts.blocklist.path' and returns its value. * * @private * @returns {string} - The blocklist file name. */ blockListFileName() { var _a; return (_a = local_json_1.default.nodeConfiguration.properties .find((prop) => prop.key === 'accounts.blocklist.path')) === null || _a === void 0 ? void 0 : _a.value; } /** * Retrieves the count of blocklisted accounts. * * This method creates a new promise that resolves with the count of blocklisted accounts. * It initializes the count to 0 and constructs the file path to the blocklist file. * It creates a read stream from the file, pipes it through a CSV parser, and increments the count for each data event. * When the end event is emitted, it resolves the promise with the count. * * @private * @returns {Promise<number>} - A promise that resolves with the count of blocklisted accounts. */ getBlocklistedAccountsCount() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve) => { let count = 0; const filepath = path_1.default.join(__dirname, constants_1.EVM_ADDRESSES_BLOCKLIST_FILE_RELATIVE_PATH, this.blockListFileName()); (0, fs_1.createReadStream)(filepath) .pipe((0, csv_parser_1.default)()) .on('data', () => { // eslint-disable-next-line no-plusplus count++; }) .on('end', () => { resolve(count); }); }); }); } /** * Logs an account. * * This method logs the account ID, the private key, and the balance of an account, along with the state name. * * @private * @param {string} accountId - The account ID. * @param {Hbar} balance - The balance of the account. * @param {string} privateKey - The private key of the account. */ logAccount(accountId, balance, privateKey) { this.logger.info(`| ${accountId} - ${privateKey} - ${balance} |`, this.stateName); } /** * Logs an alias account. * * This method logs the account ID, the account address, the private key of the account, and the balance of an alias account, along with the state name. * * @private * @param {string} accountId - The account ID. * @param {number} balance - The balance of the account. * @param {string} address - The address of the account. * @param {string} privateKey - The private key of the account. */ logAliasAccount(accountId, balance, address, privateKey) { this.logger.info(`| ${accountId} - ${address} - ${privateKey} - ${balance} |`, this.stateName); } /** * Logs the title of an account. * * This method logs a divider, the title of the account list with the account type, another divider, the headers for the account ID, private key, and balance, and a final divider. * * @private * @param {string} accountType - The type of the account. */ logAccountTitle(accountType) { this.logAccountDivider(); this.logger.info(`|-----------------------------| Accounts list (${accountType} keys) |----------------------------|`, this.stateName); this.logAccountDivider(); this.logger.info('| id | private key | balance |', this.stateName); this.logAccountDivider(); } /** * Logs the title of an alias account. * * This method logs a divider, the title of the alias account list, another divider, the headers for the account ID, public address, private key, and balance, and a final divider. * * @private */ logAliasAccountTitle() { this.logAliasAccountDivider(); this.logger.info('|------------------------------------------------| Accounts list (Alias ECDSA keys) |--------------------------------------------------|', this.stateName); this.logAliasAccountDivider(); this.logger.info('| id | public address | private key | balance |', this.stateName); this.logAliasAccountDivider(); } /** * Logs a divider for an account. * * This method logs a divider line, along with the state name. * * @private */ logAccountDivider() { this.logger.info('|-----------------------------------------------------------------------------------------|', this.stateName); } /** * Logs a divider for an alias account. * * This method logs a divider line, along with the state name. * * @private */ logAliasAccountDivider() { this.logger.info('|--------------------------------------------------------------------------------------------------------------------------------------|', this.stateName); } } exports.AccountCreationState = AccountCreationState; //# sourceMappingURL=AccountCreationState.js.map