Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
🔨 Refactor code
Browse files Browse the repository at this point in the history
  • Loading branch information
sameersubudhi committed Oct 23, 2023
1 parent d069f97 commit 499e04e
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 68 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ module.exports = {
rules: {
'max-len': 'off', // Managed by prettier
'no-underscore-dangle': 'off', // Used for private variables and methods
'implicit-arrow-linebreak': 'off', // Prefered
'implicit-arrow-linebreak': 'off', // Preferred
'no-mixed-spaces-and-tabs': 'off', // Managed by prettier
'no-shadow': 'off',
'operator-linebreak': 'off',
'import/prefer-default-export': 'off',
'lines-between-class-members': 'off', // Off because typescript has members and methods
Expand All @@ -31,6 +32,7 @@ module.exports = {
'@typescript-eslint/no-unnecessary-boolean-literal-compare': ['error'],
'@typescript-eslint/no-unnecessary-qualifier': ['error'],
'@typescript-eslint/no-unnecessary-type-arguments': ['error'],
'@typescript-eslint/no-shadow': 'warn',
'@typescript-eslint/prefer-for-of': ['error'],
'@typescript-eslint/prefer-function-type': ['error'],
'@typescript-eslint/prefer-includes': ['error'],
Expand Down
11 changes: 6 additions & 5 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Migration Guide

This section explains how to migrate a Lisk Core v3.0.4 (or later) node to Lisk Core v4.x using the Lisk Migrator.
This section explains how to migrate a Lisk Core v3.1.0 node to Lisk Core v4.0.0 using the Lisk Migrator.

The Lisk Migrator CLI tool will generate a new genesis (snapshot) block for Lisk Core v4.x.
The new genesis block is created based on a snapshot of the existing blockchain (running on Lisk Core v3.0.4+) at a pre-determined height.
The Lisk Migrator CLI tool will generate a new genesis (snapshot) block for Lisk Core v4.0.0.
The new genesis block is created based on a snapshot of the existing blockchain (running on Lisk Core v3.1.0) at a pre-determined height.

Lisk Migrator automatically exports the node's Forging Status information to the file named `forgingStatus.json` under the output directory. In case, Lisk Migrator is unable to save to the disk, as a fallback, the Forging Status information is logged to the standard output.
Lisk Migrator automatically exports the node's Forging Status information to the file named `forgingStatus.json` under the output directory.
In case, the Lisk Migrator is unable to save to the disk, as a fallback, the Forging Status information is logged to the standard output.

<!--
Expand Down Expand Up @@ -67,7 +68,7 @@ export PATH="$PATH:$HOME/lisk-migrator/bin"
**Check the announced snapshot height**

- For Mainnet: `TBD`
- For Testnet: `TBD`
- For Testnet: `20449414`

### Run Lisk Migrator

Expand Down
16 changes: 12 additions & 4 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,16 @@ export const LEGACY_DB_PATH = `${DEFAULT_LISK_CORE_PATH}/${DEFAULT_DATA_DIR}/leg
export const DEFAULT_VERSION = '0.1.0';
export const EVENT_NEW_BLOCK = 'app:block:new';

/* eslint-disable-next-line no-shadow */
export const enum ERROR_CODES {
GENESIS_BLOCK_CREATE = 0,
LISK_CORE_START = 1,
export const FILE_NAME = {
COMMANDS_TO_EXEC: 'commandsToExecute.txt',
FORGING_STATUS: 'forgingStatus.json',
};

export const enum ERROR_CODE {
DEFAULT = 0,
INVALID_CONFIG = 1,
GENESIS_BLOCK_CREATE = 2,
LISK_CORE_START = 3,
BACKUP_LEGACY_DATA_DIR = 4,
COPY_LEGACY_DB = 5,
}
4 changes: 2 additions & 2 deletions src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Block } from '@liskhq/lisk-chain';
import { address } from '@liskhq/lisk-cryptography';
import { APIClient } from '@liskhq/lisk-api-client';
import { write } from './utils/fs';
import { EVENT_NEW_BLOCK } from './constants';
import { EVENT_NEW_BLOCK, FILE_NAME } from './constants';
import { ForgingStatus } from './types';

const { getLisk32AddressFromAddress } = address;
Expand All @@ -41,7 +41,7 @@ export const captureForgingStatusAtSnapshotHeight = (

if (finalForgingStatuses.length) {
try {
const forgingStatusJsonFilepath = resolve(outputDir, 'forgingStatus.json');
const forgingStatusJsonFilepath = resolve(outputDir, FILE_NAME.FORGING_STATUS);
await write(forgingStatusJsonFilepath, JSON.stringify(finalForgingStatuses, null, '\t'));
_this.log(`\nFinished exporting forging status to ${forgingStatusJsonFilepath}.`);
} catch (error) {
Expand Down
51 changes: 24 additions & 27 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
SNAPSHOT_DIR,
MIN_SUPPORTED_LISK_CORE_VERSION,
DEFAULT_LISK_CORE_PATH,
ERROR_CODES,
ERROR_CODE,
FILE_NAME,
} from './constants';
import { getAPIClient } from './client';
import {
Expand Down Expand Up @@ -56,8 +57,8 @@ import { ApplicationConfigV3, NetworkConfigLocal, NodeInfo } from './types';
import { installLiskCore, startLiskCore, isLiskCoreV3Running } from './utils/node';
import { resolveAbsolutePath, verifyOutputPath } from './utils/path';
import { execAsync } from './utils/process';
import { CustomError } from './utils/exception';
import { getCommandsToExecPostMigration, writeCommandsToExecute } from './utils/commands';
import { MigratorException } from './utils/exception';
import { writeCommandsToExec } from './utils/commands';

let configCoreV4: PartialApplicationConfig;
class LiskMigrator extends Command {
Expand Down Expand Up @@ -239,7 +240,12 @@ class LiskMigrator extends Command {
const isValidConfig = await validateConfig(migratedConfigV4);
cli.action.stop();

if (!isValidConfig) throw new Error('Migrated user configuration is invalid.');
if (!isValidConfig) {
throw new MigratorException(
'Migrated user configuration is invalid.',
ERROR_CODE.INVALID_CONFIG,
);
}

cli.action.start(`Exporting user configuration to the path: ${outputDir}`);
await writeConfig(migratedConfigV4, outputDir);
Expand Down Expand Up @@ -310,16 +316,14 @@ class LiskMigrator extends Command {
"Lisk Core v3 still running. Please stop the node, type 'yes' to proceed and 'no' to exit. [yes/no]",
);
if (!isStopReconfirmed) {
throw new CustomError(
throw new Error(
`Cannot proceed with Lisk Core v4 auto-start. Please continue manually. In order to access legacy blockchain information posts-migration, please copy the contents of the ${snapshotDirPath} directory to 'data/legacy.db' under the Lisk Core v4 data directory (e.g: ${DEFAULT_LISK_CORE_PATH}/data/legacy.db/). Exiting!!!`,
ERROR_CODES.LISK_CORE_START,
);
} else if (numTriesLeft === 0 && isStopReconfirmed) {
const isCoreV3StillRunning = await isLiskCoreV3Running(liskCoreV3DataPath);
if (isCoreV3StillRunning) {
throw new CustomError(
throw new Error(
`Cannot auto-start Lisk Core v4 as Lisk Core v3 is still running. Please continue manually. In order to access legacy blockchain information posts-migration, please copy the contents of the ${snapshotDirPath} directory to 'data/legacy.db' under the Lisk Core v4 data directory (e.g: ${DEFAULT_LISK_CORE_PATH}/data/legacy.db/). Exiting!!!`,
ERROR_CODES.LISK_CORE_START,
);
}
}
Expand All @@ -345,17 +349,13 @@ class LiskMigrator extends Command {
);
}
} else {
throw new CustomError(
throw new Error(
`User did not confirm Lisk Core v3 node shutdown. Skipping the Lisk Core v4 auto-start process. Please continue manually. In order to access legacy blockchain information posts-migration, please copy the contents of the ${snapshotDirPath} directory to 'data/legacy.db' under the Lisk Core v4 data directory (e.g: ${DEFAULT_LISK_CORE_PATH}/data/legacy.db/). Exiting!!!`,
ERROR_CODES.LISK_CORE_START,
);
}
} catch (err) {
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
throw new CustomError(
`Failed to auto-start Lisk Core v4.\nError: ${(err as Error).message}`,
ERROR_CODES.LISK_CORE_START,
);
const errorMsg = `Failed to auto-start Lisk Core v4.\nError: ${(err as Error).message}`;
throw new MigratorException(errorMsg, ERROR_CODE.LISK_CORE_START);
}
} else {
this.log(
Expand All @@ -365,40 +365,37 @@ class LiskMigrator extends Command {
}
} catch (error) {
const commandsToExecute: string[] = [];
const code = Number(`${(error as { message: string; code: number }).code}`);
const code = Number(`${(error as MigratorException).code}`);

const liskCoreStartCommand = `lisk core start--network ${networkConstant.name}`;

if (code === ERROR_CODES.GENESIS_BLOCK_CREATE) {
if (code === ERROR_CODE.GENESIS_BLOCK_CREATE) {
const genesisBlockCreateCommand = getGenesisBlockCreateCommand();
commandsToExecute.push(genesisBlockCreateCommand);
commandsToExecute.push(liskCoreStartCommand);
}

if (code === ERROR_CODES.LISK_CORE_START) {
if (code === ERROR_CODE.LISK_CORE_START) {
commandsToExecute.push(liskCoreStartCommand);
}

this.log(
`Creating file with the list of commands to execute: ${outputDir}/commandsToExecute.txt`,
);
await writeCommandsToExecute(
[...commandsToExecute, ...(await getCommandsToExecPostMigration(outputDir))],
outputDir,
`Creating file with the list of commands to execute: ${outputDir}/${FILE_NAME.COMMANDS_TO_EXEC}`,
);
await writeCommandsToExec(outputDir, commandsToExecute);
this.log(
`Successfully created file with the list of commands to execute: ${outputDir}/commandsToExecute.txt`,
`Successfully created file with the list of commands to execute: ${outputDir}/${FILE_NAME.COMMANDS_TO_EXEC}`,
);
this.error(`${(error as Error).message}`);
}

this.log('Successfully finished migration. Exiting!!!');
this.log(
`Creating file with the list of commands to execute post migration: ${outputDir}/commandsToExecute.txt`,
`Creating file with the list of commands to execute post migration: ${outputDir}/${FILE_NAME.COMMANDS_TO_EXEC}`,
);
await writeCommandsToExecute(await getCommandsToExecPostMigration(outputDir), outputDir);
await writeCommandsToExec(outputDir);
this.log(
`Successfully created file with the list of commands to execute post migration: ${outputDir}/commandsToExecute.txt`,
`Successfully created file with the list of commands to execute post migration: ${outputDir}/${FILE_NAME.COMMANDS_TO_EXEC}`,
);

process.exit(0);
Expand Down
17 changes: 12 additions & 5 deletions src/utils/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import { resolve } from 'path';

import { read, write, exists } from './fs';
import { FILE_NAME } from '../constants';

export const getCommandsToExecPostMigration = async (outputDir: string) => {
const commandsToExecute = [];
Expand All @@ -24,7 +25,7 @@ export const getCommandsToExecPostMigration = async (outputDir: string) => {
);
commandsToExecute.push('lisk-core keys:import --file-path config/keys.json');

const forgingStatusJsonFilepath = resolve(outputDir, 'forgingStatus.json');
const forgingStatusJsonFilepath = resolve(outputDir, FILE_NAME.FORGING_STATUS);
if (await exists(forgingStatusJsonFilepath)) {
const forgingStatusString = (await read(forgingStatusJsonFilepath)) as string;
const forgingStatusJson = JSON.parse(forgingStatusString);
Expand Down Expand Up @@ -53,8 +54,14 @@ export const getCommandsToExecPostMigration = async (outputDir: string) => {
return commandsToExecute;
};

export const writeCommandsToExecute = async (commandsToExecute: string[], outputDir: string) => {
const commandsToExecuteFilepath = resolve(outputDir, 'commandsToExecute.txt');
const inputCommands = commandsToExecute.join('\n\n');
await write(commandsToExecuteFilepath, inputCommands);
export const writeCommandsToExec = async (outputDir: string, preCompletionCommands?: string[]) => {
const commandsToExecPreCompletion = preCompletionCommands ?? [];
const commandsToExecPostMigration = await getCommandsToExecPostMigration(outputDir);

const allCommandsToExec = [...commandsToExecPreCompletion, ...commandsToExecPostMigration].join(
'\n\n',
);

const commandsToExecuteFilepath = resolve(outputDir, FILE_NAME.COMMANDS_TO_EXEC);
await write(commandsToExecuteFilepath, allCommandsToExec);
};
6 changes: 4 additions & 2 deletions src/utils/exception.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
*
* Removal or modification of this copyright notice is prohibited.
*/
import { ERROR_CODE } from '../constants';

export class MigratorException extends Error {
public code: number = ERROR_CODE.DEFAULT;

export class CustomError extends Error {
public code: number;
public constructor(message: string, code: number) {
super(message);
this.code = code;
Expand Down
8 changes: 4 additions & 4 deletions src/utils/genesis_block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import * as fs from 'fs-extra';
import path from 'path';
import { Command } from '@oclif/command';
import { Block as BlockVersion3 } from '@liskhq/lisk-chain';
import { ERROR_CODES, SNAPSHOT_TIME_GAP } from '../constants';
import { ERROR_CODE, SNAPSHOT_TIME_GAP } from '../constants';
import { GenesisAssetEntry } from '../types';
import { execAsync } from './process';
import { copyFile, createTarball } from './fs';
import { CustomError } from './exception';
import { MigratorException } from './exception';

/* eslint-disable func-names, @typescript-eslint/no-explicit-any */
(BigInt.prototype as any).toJSON = function () {
Expand Down Expand Up @@ -72,9 +72,9 @@ export const createGenesisBlock = async (

await execAsync(genesisBlockCreateCommand);
} catch (error) {
throw new CustomError(
throw new MigratorException(
`Failed to create genesis block.\nError: ${(error as Error).message}`,
ERROR_CODES.GENESIS_BLOCK_CREATE,
ERROR_CODE.GENESIS_BLOCK_CREATE,
);
}
};
Expand Down
44 changes: 30 additions & 14 deletions src/utils/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import * as fs from 'fs-extra';
import * as path from 'path';
import { homedir } from 'os';
import { Command } from '@oclif/command';
import { existsSync, renameSync } from 'fs-extra';
import { renameSync } from 'fs-extra';

import { PartialApplicationConfig } from 'lisk-framework';

Expand All @@ -29,11 +29,11 @@ import { getAPIClient } from '../client';
import {
DEFAULT_PORT_P2P,
DEFAULT_PORT_RPC,
ERROR_CODES,
ERROR_CODE,
LEGACY_DB_PATH,
SNAPSHOT_DIR,
} from '../constants';
import { CustomError } from './exception';
import { MigratorException } from './exception';

const INSTALL_LISK_CORE_COMMAND = 'npm i -g lisk-core@^4.0.0-rc.1';
const INSTALL_PM2_COMMAND = 'npm i -g pm2';
Expand Down Expand Up @@ -62,25 +62,37 @@ export const isLiskCoreV3Running = async (liskCorePath: string): Promise<boolean
}
};

const backupDefaultDirectoryIfExists = async (_this: Command, liskCoreV3DataPath: string) => {
if (existsSync(liskCoreV3DataPath)) {
const backupLegacyDataDir = async (_this: Command, liskCoreV3DataPath: string) => {
try {
if (!liskCoreV3DataPath.includes('.lisk/lisk-core')) {
fs.mkdirSync(`${homedir()}/.lisk`, { recursive: true });
}

_this.log(`Backing Lisk Core v3 data directory at ${liskCoreV3DataPath}`);
renameSync(liskCoreV3DataPath, LISK_V3_BACKUP_DATA_DIR);
_this.log(`Backed Lisk Core v3 data directory to: ${LISK_V3_BACKUP_DATA_DIR}`);
} catch (err) {
throw new MigratorException(
`Unable to backup Lisk Core v3 data directory due to: ${(err as Error).message}`,
ERROR_CODE.BACKUP_LEGACY_DATA_DIR,
);
}
};

const copyLegacyDB = async (_this: Command) => {
_this.log(`Copying the v3.x snapshot to legacy.db at ${LEGACY_DB_PATH}`);
await copyDir(
path.resolve(LISK_V3_BACKUP_DATA_DIR, SNAPSHOT_DIR),
resolveAbsolutePath(LEGACY_DB_PATH),
);
_this.log(`Legacy database for Lisk Core v4 has been created at ${LEGACY_DB_PATH}`);
try {
_this.log(`Copying the v3.x snapshot to legacy.db at ${LEGACY_DB_PATH}`);
await copyDir(
path.resolve(LISK_V3_BACKUP_DATA_DIR, SNAPSHOT_DIR),
resolveAbsolutePath(LEGACY_DB_PATH),
);
_this.log(`Legacy database for Lisk Core v4 has been created at ${LEGACY_DB_PATH}`);
} catch (err) {
throw new MigratorException(
`Unable to copy ${path.basename(LEGACY_DB_PATH)} due to: ${(err as Error).message}`,
ERROR_CODE.COPY_LEGACY_DB,
);
}
};

export const getFinalConfigPath = async (outputDir: string, network: string) =>
Expand Down Expand Up @@ -193,7 +205,8 @@ export const startLiskCore = async (
throw new Error(`Port ${rpcPort} is not available to start the RPC server.`);
}

await backupDefaultDirectoryIfExists(_this, liskCoreV3DataPath);
// Backup Lisk Core v3 data directory and legacy snapshot into the Core v4 legacy.db
await backupLegacyDataDir(_this, liskCoreV3DataPath);
await copyLegacyDB(_this);

const configPath = await getFinalConfigPath(outputDir, network);
Expand Down Expand Up @@ -229,7 +242,10 @@ export const startLiskCore = async (

const PM2_COMMAND_START = `pm2 start ${pm2FilePath}`;
_this.log(await execAsync(PM2_COMMAND_START));
} catch (error) {
throw new CustomError(`${(error as Error).message}`, ERROR_CODES.LISK_CORE_START);
} catch (err) {
throw new MigratorException(
`${(err as Error).message}`,
err instanceof MigratorException ? err.code : ERROR_CODE.LISK_CORE_START,
);
}
};
7 changes: 3 additions & 4 deletions test/unit/utils/commands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ import {
writeCommandsToExecute,
} from '../../../src/utils/commands';
import { exists } from '../../../src/utils/fs';
import { FILE_NAME } from '../../../src/constants';

const outputDir = join(__dirname, '../../..', 'test/unit/fixtures');

afterAll(() => {
fs.removeSync(join(outputDir, 'commandsToExecute.txt'));
});
afterAll(() => fs.removeSync(join(outputDir, FILE_NAME.COMMANDS_TO_EXEC)));

describe('Test getCommandsToExecPostMigration method', () => {
it('should create commandsToExecute text file', async () => {
const commandsToExecute = await getCommandsToExecPostMigration(outputDir);
await writeCommandsToExecute(commandsToExecute, outputDir);
expect(await exists(`${outputDir}/commandsToExecute.txt`)).toBe(true);
expect(await exists(`${outputDir}/${FILE_NAME.COMMANDS_TO_EXEC}`)).toBe(true);
});
});

0 comments on commit 499e04e

Please sign in to comment.