From bd4f760c619dc2871faa4154db03d7fbd171548e Mon Sep 17 00:00:00 2001 From: shuse2 Date: Mon, 15 Nov 2021 22:08:46 +0100 Subject: [PATCH] :seedling: Update function to create genesis block - Remove genesis block package since genesis block cannot be created without application registered with modules - Create genesis block creation function in generator and expose from application --- Jenkinsfile.sdk | 2 +- commander/package.json | 1 - elements/README.md | 1 - elements/lisk-chain/src/block.ts | 24 +- elements/lisk-chain/src/block_assets.ts | 10 + elements/lisk-chain/src/block_header.ts | 23 +- elements/lisk-chain/src/index.ts | 4 +- elements/lisk-chain/src/transaction.ts | 16 +- elements/lisk-chain/src/types.ts | 11 + elements/lisk-elements/README.md | 1 - elements/lisk-elements/package.json | 1 - elements/lisk-genesis/.eslintignore | 3 - elements/lisk-genesis/.eslintrc.js | 7 - elements/lisk-genesis/.npmignore | 1 - elements/lisk-genesis/.npmrc | 1 - elements/lisk-genesis/.prettierignore | 1 - elements/lisk-genesis/.prettierrc.json | 1 - elements/lisk-genesis/README.md | 28 - elements/lisk-genesis/jest.config.js | 1 - elements/lisk-genesis/package.json | 66 - elements/lisk-genesis/scripts | 1 - elements/lisk-genesis/src/constants.ts | 25 - elements/lisk-genesis/src/create.ts | 140 -- elements/lisk-genesis/src/index.ts | 18 - elements/lisk-genesis/src/types.ts | 52 - elements/lisk-genesis/test/.eslintrc.js | 7 - .../test/__snapshots__/create.spec.ts.snap | 1193 ----------------- elements/lisk-genesis/test/_setup.js | 3 - elements/lisk-genesis/test/codec.spec.ts | 107 -- elements/lisk-genesis/test/create.spec.ts | 208 --- elements/lisk-genesis/test/fixtures/index.ts | 220 --- elements/lisk-genesis/test/tsconfig.json | 1 - elements/lisk-genesis/tsconfig.json | 1 - .../lisk-framework-forger-plugin/package.json | 1 - framework/package.json | 1 - framework/src/application.ts | 28 +- framework/src/node/consensus/consensus.ts | 2 +- framework/src/node/generator/constants.ts | 6 + framework/src/node/generator/generator.ts | 109 +- framework/src/node/generator/index.ts | 8 +- framework/src/node/generator/types.ts | 23 +- framework/src/node/node.ts | 11 +- framework/src/testing/app_env.ts | 15 +- framework/src/testing/block_processing_env.ts | 27 +- framework/src/testing/create_genesis_block.ts | 78 -- framework/src/testing/index.ts | 1 - framework/test/unit/application.spec.ts | 53 +- framework/test/unit/controller/bus.spec.ts | 1 + .../unit/node/generator/generator.spec.ts | 136 +- framework/test/unit/node/node.spec.ts | 42 +- .../test/unit/testing/create_block.spec.ts | 7 +- .../unit/testing/create_genesis_block.spec.ts | 17 - package.json | 4 +- sdk/package.json | 1 - 54 files changed, 422 insertions(+), 2328 deletions(-) delete mode 100644 elements/lisk-genesis/.eslintignore delete mode 100644 elements/lisk-genesis/.eslintrc.js delete mode 120000 elements/lisk-genesis/.npmignore delete mode 120000 elements/lisk-genesis/.npmrc delete mode 120000 elements/lisk-genesis/.prettierignore delete mode 120000 elements/lisk-genesis/.prettierrc.json delete mode 100644 elements/lisk-genesis/README.md delete mode 120000 elements/lisk-genesis/jest.config.js delete mode 100644 elements/lisk-genesis/package.json delete mode 120000 elements/lisk-genesis/scripts delete mode 100644 elements/lisk-genesis/src/constants.ts delete mode 100644 elements/lisk-genesis/src/create.ts delete mode 100644 elements/lisk-genesis/src/index.ts delete mode 100644 elements/lisk-genesis/src/types.ts delete mode 100644 elements/lisk-genesis/test/.eslintrc.js delete mode 100644 elements/lisk-genesis/test/__snapshots__/create.spec.ts.snap delete mode 100644 elements/lisk-genesis/test/_setup.js delete mode 100644 elements/lisk-genesis/test/codec.spec.ts delete mode 100644 elements/lisk-genesis/test/create.spec.ts delete mode 100644 elements/lisk-genesis/test/fixtures/index.ts delete mode 120000 elements/lisk-genesis/test/tsconfig.json delete mode 120000 elements/lisk-genesis/tsconfig.json delete mode 100644 framework/src/testing/create_genesis_block.ts delete mode 100644 framework/test/unit/testing/create_genesis_block.spec.ts diff --git a/Jenkinsfile.sdk b/Jenkinsfile.sdk index 4ae28b4faa6..83b6a7b367a 100644 --- a/Jenkinsfile.sdk +++ b/Jenkinsfile.sdk @@ -117,7 +117,7 @@ pipeline { steps { setup() nvm(getNodejsVersion()) { - sh 'npx lerna run test:ci --ignore lisk-framework --ignore lisk-commander --ignore=@liskhq/lisk-framework-* --ignore @liskhq/lisk-p2p --ignore @liskhq/lisk-genesis --ignore @liskhq/lisk-api-client --ignore lisk-elements' + sh 'npx lerna run test:ci --ignore lisk-framework --ignore lisk-commander --ignore=@liskhq/lisk-framework-* --ignore @liskhq/lisk-p2p --ignore @liskhq/lisk-api-client --ignore lisk-elements' } } post { diff --git a/commander/package.json b/commander/package.json index 3a7c38e3321..9913aa09801 100644 --- a/commander/package.json +++ b/commander/package.json @@ -97,7 +97,6 @@ "@liskhq/lisk-codec": "^0.2.1", "@liskhq/lisk-cryptography": "^3.2.0", "@liskhq/lisk-db": "^0.2.0", - "@liskhq/lisk-genesis": "^0.2.3", "@liskhq/lisk-passphrase": "^3.1.0", "@liskhq/lisk-transactions": "^5.2.0", "@liskhq/lisk-utils": "^0.2.0", diff --git a/elements/README.md b/elements/README.md index c288b7b43e2..b4d6de204a1 100644 --- a/elements/README.md +++ b/elements/README.md @@ -20,7 +20,6 @@ Lisk Elements supports the modular architecture of the Lisk SDK, where libraries | [@liskhq/lisk-codec](./lisk-codec) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-codec) | Decoder and encoder using Lisk JSON schema according to the Lisk protocol | | [@liskhq/lisk-cryptography](./lisk-cryptography) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-cryptography) | General cryptographic functions for use with Lisk-related software | | [@liskhq/lisk-db](./lisk-db) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-db) | A database access implementation for use with Lisk-related software | -| [@liskhq/lisk-genesis](./lisk-genesis) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-genesis) | Genesis block creation functions according to the Lisk protocol | | [@liskhq/lisk-p2p](./lisk-p2p) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-p2p) | _unstructured_ P2P library for the Lisk protocol | | [@liskhq/lisk-passphrase](./lisk-passphrase) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-passphrase) | Mnemonic passphrase helpers for use with Lisk-related software | | [@liskhq/lisk-transactions](./lisk-transactions) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-transactions) | Everything related to transactions according to the Lisk protocol | diff --git a/elements/lisk-chain/src/block.ts b/elements/lisk-chain/src/block.ts index e424cac9b89..9ce854a73f7 100644 --- a/elements/lisk-chain/src/block.ts +++ b/elements/lisk-chain/src/block.ts @@ -14,10 +14,10 @@ import { codec } from '@liskhq/lisk-codec'; import { regularMerkleTree } from '@liskhq/lisk-tree'; -import { BlockAssets } from './block_assets'; -import { BlockHeader } from './block_header'; +import { BlockAssetJSON, BlockAssets } from './block_assets'; +import { BlockHeader, BlockHeaderJSON } from './block_header'; import { blockSchema } from './schema'; -import { Transaction } from './transaction'; +import { Transaction, TransactionJSON } from './transaction'; interface BlockAttrs { header: Buffer; @@ -25,6 +25,12 @@ interface BlockAttrs { assets: Buffer[]; } +export interface BlockJSON { + header: BlockHeaderJSON; + payload: TransactionJSON[]; + assets: BlockAssetJSON[]; +} + export class Block { // eslint-disable-next-line no-useless-constructor public constructor( @@ -45,7 +51,7 @@ export class Block { ); } - public static fromJSON(value: Record): Block { + public static fromJSON(value: BlockJSON): Block { const { header, payload, assets } = value; if (typeof header !== 'object') { throw new Error('Invalid block format. header must be an object.'); @@ -59,7 +65,7 @@ export class Block { return new Block( BlockHeader.fromJSON(value.header as Record), - payload.map(v => Transaction.fromBytes(v)), + payload.map(v => Transaction.fromJSON(v)), BlockAssets.fromJSON(assets), ); } @@ -72,6 +78,14 @@ export class Block { }); } + public toJSON(): BlockJSON { + return { + header: this.header.toJSON(), + payload: this.payload.map(p => p.toJSON()), + assets: this.assets.toJSON(), + }; + } + public validate(): void { this.header.validate(); for (const tx of this.payload) { diff --git a/elements/lisk-chain/src/block_assets.ts b/elements/lisk-chain/src/block_assets.ts index c2e0479eeab..f2a1f8b15fa 100644 --- a/elements/lisk-chain/src/block_assets.ts +++ b/elements/lisk-chain/src/block_assets.ts @@ -17,12 +17,15 @@ import { codec } from '@liskhq/lisk-codec'; import { MerkleTree } from '@liskhq/lisk-tree'; import { blockAssetSchema } from './schema'; import { MAX_ASSET_DATA_SIZE_BYTES } from './constants'; +import { JSONObject } from './types'; export interface BlockAsset { moduleID: number; data: Buffer; } +export type BlockAssetJSON = JSONObject; + export class BlockAssets { private readonly _assets: BlockAsset[] = []; private _assetRoot!: Buffer; @@ -60,6 +63,13 @@ export class BlockAssets { return [...this._assets]; } + public toJSON(): BlockAssetJSON[] { + return this._assets.map(asset => ({ + moduleID: asset.moduleID, + data: asset.data.toString('hex'), + })); + } + public setAsset(moduleID: number, value: Buffer): void { const asset = this.getAsset(moduleID); if (asset) { diff --git a/elements/lisk-chain/src/block_header.ts b/elements/lisk-chain/src/block_header.ts index a39a09ce069..32561400f01 100644 --- a/elements/lisk-chain/src/block_header.ts +++ b/elements/lisk-chain/src/block_header.ts @@ -17,6 +17,7 @@ import { codec } from '@liskhq/lisk-codec'; import { validator, LiskValidationError } from '@liskhq/lisk-validator'; import { EMPTY_BUFFER, EMPTY_HASH, TAG_BLOCK_HEADER } from './constants'; import { blockHeaderSchema, blockHeaderSchemaWithId, signingBlockHeaderSchema } from './schema'; +import { JSONObject } from './types'; export interface BlockHeaderAttrs { readonly version: number; @@ -39,26 +40,7 @@ export interface BlockHeaderAttrs { id?: Buffer; } -export interface BlockHeaderJSON { - readonly version: number; - readonly timestamp: number; - readonly height: number; - readonly generatorAddress: string; - readonly previousBlockID: string; - readonly maxHeightPrevoted: number; - readonly maxHeightGenerated: number; - readonly aggregateCommit: { - readonly height: number; - readonly aggregationBits: string; - readonly certificateSignature: string; - }; - readonly validatorsHash: string; - readonly stateRoot: string; - readonly transactionRoot: string; - readonly assetsRoot: string; - readonly signature: string; - readonly id: string; -} +export type BlockHeaderJSON = JSONObject; export class BlockHeader { public readonly version: number; @@ -335,7 +317,6 @@ export class BlockHeader { private _resetComputedValues() { this._id = undefined; - this._signature = undefined; } private _getSigningProps() { diff --git a/elements/lisk-chain/src/index.ts b/elements/lisk-chain/src/index.ts index cb57ab700e6..d3f44250de0 100644 --- a/elements/lisk-chain/src/index.ts +++ b/elements/lisk-chain/src/index.ts @@ -32,7 +32,7 @@ export { Slots } from './slots'; export { concatDBKeys } from './utils'; export { StateStore, NotFoundError, CurrentState, SMTStore } from './state_store'; -export { Block } from './block'; -export { BlockAsset, BlockAssets } from './block_assets'; +export { Block, BlockJSON } from './block'; +export { BlockAsset, BlockAssets, BlockAssetJSON } from './block_assets'; export { BlockHeader, BlockHeaderAttrs, BlockHeaderJSON } from './block_header'; export { DataAccess } from './data_access'; diff --git a/elements/lisk-chain/src/transaction.ts b/elements/lisk-chain/src/transaction.ts index 1f9e138aaae..a8f0ae5410e 100644 --- a/elements/lisk-chain/src/transaction.ts +++ b/elements/lisk-chain/src/transaction.ts @@ -16,6 +16,7 @@ import { codec } from '@liskhq/lisk-codec'; import { hash, getAddressFromPublicKey, signDataWithPrivateKey } from '@liskhq/lisk-cryptography'; import { validator, LiskValidationError } from '@liskhq/lisk-validator'; import { TAG_TRANSACTION } from './constants'; +import { JSONObject } from './types'; export interface TransactionAttrs { readonly moduleID: number; @@ -27,16 +28,7 @@ export interface TransactionAttrs { readonly signatures: ReadonlyArray; readonly id?: Buffer; } - -export interface TransactionJSON { - readonly moduleID: number; - readonly commandID: number; - readonly senderPublicKey: string; - readonly nonce: string; - readonly fee: string; - readonly params: string; - readonly signatures: ReadonlyArray; -} +export type TransactionJSON = JSONObject; export const transactionSchema = { $id: 'lisk/transaction', @@ -118,7 +110,7 @@ export class Transaction { return new Transaction(tx); } - public static fromJSON(value: Record): Transaction { + public static fromJSON(value: TransactionJSON): Transaction { const tx = codec.fromJSON(transactionSchema, value); return new Transaction(tx); } @@ -177,7 +169,7 @@ export class Transaction { } } - public toJSON(): TransactionJSON { + public toJSON(): JSONObject { return codec.toJSON(transactionSchema, this._getProps()); } diff --git a/elements/lisk-chain/src/types.ts b/elements/lisk-chain/src/types.ts index b105e4e1596..409fb211852 100644 --- a/elements/lisk-chain/src/types.ts +++ b/elements/lisk-chain/src/types.ts @@ -39,3 +39,14 @@ export interface UpdatedDiff { readonly key: Buffer; readonly value: Buffer; } + +type Primitive = string | number | bigint | boolean | null | undefined; +type Replaced = T extends TReplace | TKeep + ? T extends TReplace + ? TWith | Exclude + : T + : { + [P in keyof T]: Replaced; + }; + +export type JSONObject = Replaced; diff --git a/elements/lisk-elements/README.md b/elements/lisk-elements/README.md index 323505aef5a..3978f7a5516 100644 --- a/elements/lisk-elements/README.md +++ b/elements/lisk-elements/README.md @@ -42,7 +42,6 @@ const { transactions } = require('lisk-elements'); | [@liskhq/lisk-codec](https://www.npmjs.com/package/@liskhq/lisk-codec) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-codec) | Decoder and encoder using Lisk JSON schema according to the Lisk protocol | | [@liskhq/lisk-cryptography](https://www.npmjs.com/package/@liskhq/lisk-cryptography) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-cryptography) | General cryptographic functions for use with Lisk-related software | | [@liskhq/lisk-db](https://www.npmjs.com/package/@liskhq/lisk-db) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-db) | A database access implementation for use with Lisk-related software | -| [@liskhq/lisk-genesis](https://www.npmjs.com/package/@liskhq/lisk-genesis) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-genesis) | Genesis block creation functions according to the Lisk protocol | | [@liskhq/lisk-p2p](https://www.npmjs.com/package/@liskhq/lisk-p2p) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-p2p) | _unstructured_ P2P library for the Lisk protocol | | [@liskhq/lisk-passphrase](https://www.npmjs.com/package/@liskhq/lisk-passphrase) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-passphrase) | Mnemonic passphrase helpers for use with Lisk-related software | | [@liskhq/lisk-transactions](https://www.npmjs.com/package/@liskhq/lisk-transactions) | ![npm](https://img.shields.io/npm/v/@liskhq/lisk-transactions) | Everything related to transactions according to the Lisk protocol | diff --git a/elements/lisk-elements/package.json b/elements/lisk-elements/package.json index bd8a9a198e2..8b9a660d95f 100644 --- a/elements/lisk-elements/package.json +++ b/elements/lisk-elements/package.json @@ -41,7 +41,6 @@ "@liskhq/lisk-codec": "^0.2.1", "@liskhq/lisk-cryptography": "^3.2.0", "@liskhq/lisk-db": "^0.2.0", - "@liskhq/lisk-genesis": "^0.2.3", "@liskhq/lisk-p2p": "^0.7.2", "@liskhq/lisk-passphrase": "^3.1.0", "@liskhq/lisk-transaction-pool": "^0.5.1", diff --git a/elements/lisk-genesis/.eslintignore b/elements/lisk-genesis/.eslintignore deleted file mode 100644 index 3680bf52001..00000000000 --- a/elements/lisk-genesis/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -dist-node -jest.config.js -.eslintrc.js diff --git a/elements/lisk-genesis/.eslintrc.js b/elements/lisk-genesis/.eslintrc.js deleted file mode 100644 index 8b7fd410b8d..00000000000 --- a/elements/lisk-genesis/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: '../../.eslintrc.js', - parserOptions: { - project: './tsconfig.json', - tsconfigRootDir: __dirname, - }, -}; diff --git a/elements/lisk-genesis/.npmignore b/elements/lisk-genesis/.npmignore deleted file mode 120000 index 8a0be70f3ed..00000000000 --- a/elements/lisk-genesis/.npmignore +++ /dev/null @@ -1 +0,0 @@ -../../templates/.npmignore.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/.npmrc b/elements/lisk-genesis/.npmrc deleted file mode 120000 index 5cc817c4313..00000000000 --- a/elements/lisk-genesis/.npmrc +++ /dev/null @@ -1 +0,0 @@ -../../templates/.npmrc.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/.prettierignore b/elements/lisk-genesis/.prettierignore deleted file mode 120000 index 044e4a3df69..00000000000 --- a/elements/lisk-genesis/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -../../templates/.prettierignore.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/.prettierrc.json b/elements/lisk-genesis/.prettierrc.json deleted file mode 120000 index 00ecd510aaf..00000000000 --- a/elements/lisk-genesis/.prettierrc.json +++ /dev/null @@ -1 +0,0 @@ -../../templates/.prettierrc.json.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/README.md b/elements/lisk-genesis/README.md deleted file mode 100644 index 3c06eaa90f5..00000000000 --- a/elements/lisk-genesis/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# @liskhq/lisk-genesis - -@liskhq/lisk-genesis contains genesis block creation functions according to the Lisk protocol. - -## Installation - -```sh -$ npm install --save @liskhq/lisk-genesis -``` - -## License - -Copyright 2016-2020 Lisk Foundation - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -[lisk core github]: https://github.com/LiskHQ/lisk -[lisk documentation site]: https://lisk.com/documentation/lisk-sdk/references/lisk-elements/genesis.html diff --git a/elements/lisk-genesis/jest.config.js b/elements/lisk-genesis/jest.config.js deleted file mode 120000 index 475ff02b18a..00000000000 --- a/elements/lisk-genesis/jest.config.js +++ /dev/null @@ -1 +0,0 @@ -../../templates/jest.config.js.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/package.json b/elements/lisk-genesis/package.json deleted file mode 100644 index cac2c475a6c..00000000000 --- a/elements/lisk-genesis/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "@liskhq/lisk-genesis", - "version": "0.2.3", - "description": "Library containing genesis block creation functions according to the Lisk protocol", - "author": "Lisk Foundation , lightcurve GmbH ", - "license": "Apache-2.0", - "keywords": [ - "lisk", - "blockchain" - ], - "homepage": "https://github.com/LiskHQ/lisk-sdk/tree/master/elements/lisk-genesis#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/LiskHQ/lisk-sdk.git" - }, - "bugs": { - "url": "https://github.com/LiskHQ/lisk-sdk/issues" - }, - "engines": { - "node": ">=12.13.0", - "npm": ">=6.12.0" - }, - "main": "dist-node/index.js", - "scripts": { - "clean": "./scripts/clean.sh", - "format": "prettier --write '**/*'", - "lint": "eslint --ext .js,.ts .", - "lint:fix": "eslint --fix --ext .js,.ts .", - "test": "jest", - "test:coverage": "jest --coverage=true --coverage-reporters=text", - "test:ci": "jest --coverage=true --coverage-reporters=json --verbose", - "test:watch": "npm test -- --watch", - "prebuild": "rm -r dist-node/* || mkdir dist-node || true", - "build": "tsc", - "build:check": "node -e \"require('./dist-node')\"", - "prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check" - }, - "dependencies": { - "@liskhq/lisk-chain": "^0.3.3", - "@liskhq/lisk-codec": "^0.2.1", - "@liskhq/lisk-cryptography": "^3.2.0", - "@liskhq/lisk-utils": "^0.2.0", - "@liskhq/lisk-validator": "^0.6.1", - "lodash.clonedeep": "4.5.0" - }, - "devDependencies": { - "@types/jest": "26.0.21", - "@types/jest-when": "2.7.2", - "@types/node": "12.20.6", - "@typescript-eslint/eslint-plugin": "4.19.0", - "@typescript-eslint/parser": "4.19.0", - "eslint": "7.22.0", - "eslint-config-lisk-base": "2.0.1", - "eslint-plugin-import": "2.22.1", - "eslint-plugin-jest": "24.3.2", - "jest": "26.6.3", - "jest-extended": "0.11.5", - "jest-when": "3.2.1", - "prettier": "2.2.1", - "source-map-support": "0.5.19", - "ts-jest": "26.5.4", - "ts-node": "9.1.1", - "tsconfig-paths": "3.9.0", - "typescript": "4.2.3" - } -} diff --git a/elements/lisk-genesis/scripts b/elements/lisk-genesis/scripts deleted file mode 120000 index f81ccd0a763..00000000000 --- a/elements/lisk-genesis/scripts +++ /dev/null @@ -1 +0,0 @@ -../../templates/scripts.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/src/constants.ts b/elements/lisk-genesis/src/constants.ts deleted file mode 100644 index a8a8203feaf..00000000000 --- a/elements/lisk-genesis/src/constants.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { hash } from '@liskhq/lisk-cryptography'; - -export const EMPTY_BUFFER = Buffer.alloc(0); -export const EMPTY_HASH = hash(EMPTY_BUFFER); - -export const GENESIS_BLOCK_VERSION = 0; -export const GENESIS_BLOCK_GENERATOR_PUBLIC_KEY = EMPTY_BUFFER; -export const GENESIS_BLOCK_REWARD = BigInt(0); -export const GENESIS_BLOCK_SIGNATURE = EMPTY_BUFFER; -export const GENESIS_BLOCK_TRANSACTION_ROOT = EMPTY_HASH; -export const GENESIS_BLOCK_MAX_BALANCE = BigInt(2) ** BigInt(63) - BigInt(1); diff --git a/elements/lisk-genesis/src/create.ts b/elements/lisk-genesis/src/create.ts deleted file mode 100644 index a2b43a4690e..00000000000 --- a/elements/lisk-genesis/src/create.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { codec, Schema } from '@liskhq/lisk-codec'; -import { hash } from '@liskhq/lisk-cryptography'; -import { - getAccountSchemaWithDefault, - getGenesisBlockHeaderAssetSchema, - Account, - GenesisBlock, - blockHeaderSchema, - blockSchema, - AccountDefaultProps, -} from '@liskhq/lisk-chain'; -import { objects } from '@liskhq/lisk-utils'; -import { - EMPTY_BUFFER, - GENESIS_BLOCK_GENERATOR_PUBLIC_KEY, - GENESIS_BLOCK_REWARD, - GENESIS_BLOCK_SIGNATURE, - GENESIS_BLOCK_TRANSACTION_ROOT, - GENESIS_BLOCK_VERSION, -} from './constants'; -import { - GenesisBlockHeaderWithoutId, - GenesisBlockParams, - GenesisBlockJSONParams, - accountAssetSchemas, -} from './types'; - -export const getGenesisBlockSchema = (accountSchema: accountAssetSchemas): Schema => - objects.mergeDeep({}, blockSchema, { - properties: { - header: objects.mergeDeep({}, blockHeaderSchema, { - $id: '/block/genesis/header/id', - properties: { - id: { - dataType: 'bytes', - }, - asset: getGenesisBlockHeaderAssetSchema(getAccountSchemaWithDefault(accountSchema)), - }, - }), - }, - }) as Schema; - -const getBlockId = (header: GenesisBlockHeaderWithoutId, accountSchema: Schema): Buffer => { - // eslint-disable-next-line - const genesisBlockAssetBuffer = codec.encode( - getGenesisBlockHeaderAssetSchema(accountSchema), - header.asset, - ); - - const genesisBlockHeaderBuffer = codec.encode(blockHeaderSchema, { - ...header, - asset: genesisBlockAssetBuffer, - }); - - return hash(genesisBlockHeaderBuffer); -}; - -const createAccount = ( - account: Partial> & { address: Buffer }, - defaultAccount: Record, -): Account => objects.mergeDeep({}, objects.cloneDeep(defaultAccount), account) as Account; - -export const createGenesisBlock = ( - params: GenesisBlockParams, -): GenesisBlock => { - // Default values - const initRounds = params.initRounds ?? 3; - const height = params.height ?? 0; - const timestamp = params.timestamp ?? Math.floor(Date.now() / 1000); - const previousBlockID = params.previousBlockID ?? Buffer.from(EMPTY_BUFFER); - const { default: defaultAccount, ...accountSchema } = getAccountSchemaWithDefault( - params.accountAssetSchemas, - ); - - // Constant values - const version = GENESIS_BLOCK_VERSION; - const generatorPublicKey = GENESIS_BLOCK_GENERATOR_PUBLIC_KEY; - const reward = GENESIS_BLOCK_REWARD; - const signature = GENESIS_BLOCK_SIGNATURE; - const transactionRoot = GENESIS_BLOCK_TRANSACTION_ROOT; - - const accounts: ReadonlyArray> = params.accounts - .map(account => createAccount(account, defaultAccount)) - .sort((a, b): number => { - if (a.address.length < b.address.length) { - return -1; - } - if (a.address.length > b.address.length) { - return 1; - } - return a.address.compare(b.address); - }); - - const initDelegates: ReadonlyArray = [...params.initDelegates].sort((a, b): number => - a.compare(b), - ); - - const header: GenesisBlockHeaderWithoutId = { - generatorPublicKey, - height, - previousBlockID, - reward, - signature, - timestamp, - transactionRoot, - version, - asset: { - initRounds, - initDelegates, - accounts, - }, - }; - - const genesisBlock: GenesisBlock = { - header: { - ...header, - id: getBlockId(header, accountSchema), - }, - payload: [], - }; - - return genesisBlock; -}; - -export const getGenesisBlockJSON = (params: GenesisBlockJSONParams): Record => - codec.toJSON(getGenesisBlockSchema(params.accountAssetSchemas), params.genesisBlock); diff --git a/elements/lisk-genesis/src/index.ts b/elements/lisk-genesis/src/index.ts deleted file mode 100644 index 7bed4bd1ac5..00000000000 --- a/elements/lisk-genesis/src/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { createGenesisBlock, getGenesisBlockJSON, getGenesisBlockSchema } from './create'; - -export * from './types'; -export { createGenesisBlock, getGenesisBlockJSON, getGenesisBlockSchema }; diff --git a/elements/lisk-genesis/src/types.ts b/elements/lisk-genesis/src/types.ts deleted file mode 100644 index c6d18ea2aeb..00000000000 --- a/elements/lisk-genesis/src/types.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { - AccountSchema, - Account, - GenesisBlockHeader, - GenesisBlock, - AccountDefaultProps, -} from '@liskhq/lisk-chain'; - -export type PartialReq = Pick< - Partial, - Exclude -> & - { - [K in Keys]: T[K]; - }; - -export type GenesisBlockHeaderWithoutId = Omit, 'id'>; - -export type accountAssetSchemas = { [moduleName: string]: AccountSchema }; - -export interface GenesisBlockJSONParams { - readonly genesisBlock: GenesisBlock; - readonly accountAssetSchemas: accountAssetSchemas; -} - -export interface GenesisBlockParams { - // List of accounts in the genesis - readonly accounts: ReadonlyArray> & { address: Buffer }>; - // List fo initial delegate addresses used during the bootstrap period to forge blocks - readonly initDelegates: ReadonlyArray; - // Account Schema for the genesis block - readonly accountAssetSchemas: accountAssetSchemas; - // Number of rounds for bootstrap period, default is 3 - readonly initRounds?: number; - readonly height?: number; - readonly timestamp?: number; - readonly previousBlockID?: Buffer; -} diff --git a/elements/lisk-genesis/test/.eslintrc.js b/elements/lisk-genesis/test/.eslintrc.js deleted file mode 100644 index a98dfb6d823..00000000000 --- a/elements/lisk-genesis/test/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: '../../../.eslintrc.test.js', - parserOptions: { - project: './tsconfig.json', - tsconfigRootDir: __dirname, - }, -}; diff --git a/elements/lisk-genesis/test/__snapshots__/create.spec.ts.snap b/elements/lisk-genesis/test/__snapshots__/create.spec.ts.snap deleted file mode 100644 index 4911886f065..00000000000 --- a/elements/lisk-genesis/test/__snapshots__/create.spec.ts.snap +++ /dev/null @@ -1,1193 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`create createGenesisBlock should create genesis block 1`] = ` -Object { - "header": Object { - "asset": Object { - "accounts": Array [ - Object { - "address": Object { - "data": Array [ - 35, - 112, - 186, - 152, - 69, - 30, - 31, - 240, - 7, - 2, - 159, - 30, - 96, - 46, - 20, - 187, - 9, - 123, - 81, - 111, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 2620126571n, - }, - }, - Object { - "address": Object { - "data": Array [ - 37, - 212, - 193, - 237, - 45, - 162, - 75, - 168, - 86, - 184, - 148, - 194, - 9, - 24, - 143, - 112, - 224, - 202, - 171, - 110, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 2874239947n, - }, - }, - Object { - "address": Object { - "data": Array [ - 52, - 179, - 218, - 222, - 213, - 80, - 245, - 176, - 197, - 9, - 71, - 216, - 225, - 119, - 98, - 185, - 115, - 12, - 241, - 249, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 2384412768n, - }, - }, - Object { - "address": Object { - "data": Array [ - 55, - 43, - 157, - 7, - 109, - 211, - 126, - 124, - 24, - 60, - 246, - 237, - 3, - 193, - 125, - 216, - 205, - 192, - 211, - 18, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 28138131n, - }, - }, - Object { - "address": Object { - "data": Array [ - 76, - 149, - 19, - 239, - 123, - 11, - 204, - 238, - 2, - 69, - 89, - 71, - 71, - 0, - 170, - 215, - 3, - 119, - 4, - 59, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 476696623n, - }, - }, - Object { - "address": Object { - "data": Array [ - 82, - 201, - 93, - 36, - 167, - 234, - 67, - 210, - 2, - 218, - 138, - 13, - 167, - 240, - 140, - 51, - 164, - 235, - 109, - 92, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 4218444994n, - }, - }, - Object { - "address": Object { - "data": Array [ - 98, - 21, - 12, - 207, - 145, - 204, - 22, - 52, - 249, - 48, - 238, - 208, - 183, - 118, - 15, - 66, - 23, - 82, - 166, - 152, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 1340967959n, - }, - }, - Object { - "address": Object { - "data": Array [ - 110, - 53, - 133, - 177, - 23, - 81, - 66, - 58, - 114, - 235, - 91, - 73, - 245, - 121, - 64, - 190, - 80, - 144, - 71, - 87, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 2165380961n, - }, - }, - Object { - "address": Object { - "data": Array [ - 128, - 224, - 141, - 50, - 44, - 36, - 181, - 50, - 154, - 37, - 124, - 91, - 27, - 215, - 87, - 128, - 50, - 211, - 185, - 33, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 3116632800n, - }, - }, - Object { - "address": Object { - "data": Array [ - 157, - 52, - 166, - 149, - 81, - 216, - 184, - 94, - 192, - 245, - 82, - 214, - 94, - 168, - 221, - 53, - 114, - 77, - 238, - 144, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 4056778033n, - }, - }, - Object { - "address": Object { - "data": Array [ - 192, - 24, - 181, - 221, - 125, - 164, - 182, - 183, - 191, - 78, - 108, - 104, - 142, - 141, - 126, - 152, - 65, - 212, - 170, - 143, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 2910960211n, - }, - }, - Object { - "address": Object { - "data": Array [ - 195, - 195, - 7, - 23, - 78, - 90, - 227, - 1, - 196, - 148, - 57, - 108, - 15, - 219, - 99, - 7, - 236, - 78, - 198, - 12, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 1966001160n, - }, - }, - Object { - "address": Object { - "data": Array [ - 195, - 198, - 54, - 21, - 36, - 4, - 51, - 37, - 232, - 171, - 206, - 140, - 193, - 248, - 153, - 226, - 194, - 255, - 217, - 176, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 3756324977n, - }, - }, - Object { - "address": Object { - "data": Array [ - 217, - 251, - 219, - 79, - 34, - 250, - 166, - 9, - 54, - 160, - 17, - 52, - 87, - 218, - 1, - 158, - 182, - 28, - 61, - 119, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 489340925n, - }, - }, - Object { - "address": Object { - "data": Array [ - 222, - 223, - 189, - 76, - 106, - 26, - 209, - 239, - 13, - 122, - 149, - 205, - 105, - 7, - 17, - 69, - 72, - 216, - 198, - 216, - ], - "type": "Buffer", - }, - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": 0n, - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": 653021139n, - }, - }, - ], - "initDelegates": Array [ - Object { - "data": Array [ - 35, - 112, - 186, - 152, - 69, - 30, - 31, - 240, - 7, - 2, - 159, - 30, - 96, - 46, - 20, - 187, - 9, - 123, - 81, - 111, - ], - "type": "Buffer", - }, - Object { - "data": Array [ - 37, - 212, - 193, - 237, - 45, - 162, - 75, - 168, - 86, - 184, - 148, - 194, - 9, - 24, - 143, - 112, - 224, - 202, - 171, - 110, - ], - "type": "Buffer", - }, - Object { - "data": Array [ - 52, - 179, - 218, - 222, - 213, - 80, - 245, - 176, - 197, - 9, - 71, - 216, - 225, - 119, - 98, - 185, - 115, - 12, - 241, - 249, - ], - "type": "Buffer", - }, - Object { - "data": Array [ - 55, - 43, - 157, - 7, - 109, - 211, - 126, - 124, - 24, - 60, - 246, - 237, - 3, - 193, - 125, - 216, - 205, - 192, - 211, - 18, - ], - "type": "Buffer", - }, - Object { - "data": Array [ - 110, - 53, - 133, - 177, - 23, - 81, - 66, - 58, - 114, - 235, - 91, - 73, - 245, - 121, - 64, - 190, - 80, - 144, - 71, - 87, - ], - "type": "Buffer", - }, - ], - "initRounds": 5, - }, - "generatorPublicKey": Object { - "data": Array [], - "type": "Buffer", - }, - "height": 5, - "id": Object { - "data": Array [ - 225, - 58, - 175, - 73, - 200, - 178, - 31, - 71, - 166, - 79, - 72, - 112, - 66, - 70, - 110, - 142, - 47, - 208, - 227, - 210, - 110, - 179, - 6, - 228, - 177, - 61, - 196, - 82, - 77, - 240, - 136, - 152, - ], - "type": "Buffer", - }, - "previousBlockID": Object { - "data": Array [ - 69, - 70, - 144, - 161, - 195, - 120, - 56, - 50, - 96, - 7, - 81, - 154, - 124, - 225, - 200, - 166, - 164, - 149, - 223, - 80, - 137, - 143, - 30, - 189, - 105, - 210, - 47, - 188, - 237, - 249, - 104, - 154, - ], - "type": "Buffer", - }, - "reward": 0n, - "signature": Object { - "data": Array [], - "type": "Buffer", - }, - "timestamp": 1591873718, - "transactionRoot": Object { - "data": Array [ - 227, - 176, - 196, - 66, - 152, - 252, - 28, - 20, - 154, - 251, - 244, - 200, - 153, - 111, - 185, - 36, - 39, - 174, - 65, - 228, - 100, - 155, - 147, - 76, - 164, - 149, - 153, - 27, - 120, - 82, - 184, - 85, - ], - "type": "Buffer", - }, - "version": 0, - }, - "payload": Array [], -} -`; - -exports[`create getGenesisBlockJSON should generate the JSON object for the given genesis block 1`] = ` -Object { - "header": Object { - "asset": Object { - "accounts": Array [ - Object { - "address": "2370ba98451e1ff007029f1e602e14bb097b516f", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "2620126571", - }, - }, - Object { - "address": "25d4c1ed2da24ba856b894c209188f70e0caab6e", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "2874239947", - }, - }, - Object { - "address": "34b3daded550f5b0c50947d8e17762b9730cf1f9", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "2384412768", - }, - }, - Object { - "address": "372b9d076dd37e7c183cf6ed03c17dd8cdc0d312", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "28138131", - }, - }, - Object { - "address": "4c9513ef7b0bccee024559474700aad70377043b", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "476696623", - }, - }, - Object { - "address": "52c95d24a7ea43d202da8a0da7f08c33a4eb6d5c", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "4218444994", - }, - }, - Object { - "address": "62150ccf91cc1634f930eed0b7760f421752a698", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "1340967959", - }, - }, - Object { - "address": "6e3585b11751423a72eb5b49f57940be50904757", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "2165380961", - }, - }, - Object { - "address": "80e08d322c24b5329a257c5b1bd7578032d3b921", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "3116632800", - }, - }, - Object { - "address": "9d34a69551d8b85ec0f552d65ea8dd35724dee90", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "4056778033", - }, - }, - Object { - "address": "c018b5dd7da4b6b7bf4e6c688e8d7e9841d4aa8f", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "2910960211", - }, - }, - Object { - "address": "c3c307174e5ae301c494396c0fdb6307ec4ec60c", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "1966001160", - }, - }, - Object { - "address": "c3c6361524043325e8abce8cc1f899e2c2ffd9b0", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "3756324977", - }, - }, - Object { - "address": "d9fbdb4f22faa60936a0113457da019eb61c3d77", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "489340925", - }, - }, - Object { - "address": "dedfbd4c6a1ad1ef0d7a95cd6907114548d8c6d8", - "dpos": Object { - "delegate": Object { - "consecutiveMissedBlocks": 0, - "isBanned": false, - "lastForgedHeight": 0, - "pomHeights": Array [], - "totalVotesReceived": "0", - "username": "", - }, - "sentVotes": Array [], - "unlocking": Array [], - }, - "token": Object { - "balance": "653021139", - }, - }, - ], - "initDelegates": Array [ - "2370ba98451e1ff007029f1e602e14bb097b516f", - "25d4c1ed2da24ba856b894c209188f70e0caab6e", - "34b3daded550f5b0c50947d8e17762b9730cf1f9", - "372b9d076dd37e7c183cf6ed03c17dd8cdc0d312", - "6e3585b11751423a72eb5b49f57940be50904757", - ], - "initRounds": 5, - }, - "generatorPublicKey": "", - "height": 5, - "id": "e13aaf49c8b21f47a64f487042466e8e2fd0e3d26eb306e4b13dc4524df08898", - "previousBlockID": "454690a1c37838326007519a7ce1c8a6a495df50898f1ebd69d22fbcedf9689a", - "reward": "0", - "signature": "", - "timestamp": 1591873718, - "transactionRoot": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "version": 0, - }, - "payload": Array [], -} -`; diff --git a/elements/lisk-genesis/test/_setup.js b/elements/lisk-genesis/test/_setup.js deleted file mode 100644 index e2a8f3c32b8..00000000000 --- a/elements/lisk-genesis/test/_setup.js +++ /dev/null @@ -1,3 +0,0 @@ -require('jest-extended'); - -process.env.NODE_ENV = 'test'; diff --git a/elements/lisk-genesis/test/codec.spec.ts b/elements/lisk-genesis/test/codec.spec.ts deleted file mode 100644 index 664adba7b8e..00000000000 --- a/elements/lisk-genesis/test/codec.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { codec } from '@liskhq/lisk-codec'; -import { hash } from '@liskhq/lisk-cryptography'; -import { - RawBlockHeader, - getGenesisBlockHeaderAssetSchema, - GenesisBlock, - GenesisBlockHeader, - blockHeaderSchema, - blockSchema, -} from '@liskhq/lisk-chain'; -import { createGenesisBlock } from '../src'; - -import { validGenesisBlockParams, defaultAccountSchema } from './fixtures'; - -const encodeGenesisBlock = (genesisBlock: GenesisBlock) => { - const blockHeaderWithAccountAssetSchema = getGenesisBlockHeaderAssetSchema(defaultAccountSchema); - const genesisBlockAssetBuffer = codec.encode( - blockHeaderWithAccountAssetSchema, - genesisBlock.header.asset, - ); - - const genesisBlockHeaderBuffer = codec.encode(blockHeaderSchema, { - ...genesisBlock.header, - asset: genesisBlockAssetBuffer, - }); - - const genesisBlockBuffer = codec.encode(blockSchema, { - header: genesisBlockHeaderBuffer, - payload: genesisBlock.payload, - }); - - return { - genesisBlockBuffer, - genesisBlockHeaderBuffer, - }; -}; - -const decodeGenesisBlock = (genesisBlockBuffer: Buffer): GenesisBlock => { - const { header, payload } = codec.decode<{ - header: Buffer; - payload: []; - }>(blockSchema, genesisBlockBuffer); - - const blockHeaderWithAssetBuffer = codec.decode(blockHeaderSchema, header); - - const blockHeaderAssetSchema = getGenesisBlockHeaderAssetSchema(defaultAccountSchema); - - const blockHeaderAsset = codec.decode( - blockHeaderAssetSchema, - blockHeaderWithAssetBuffer.asset, - ); - - return { - header: { - ...blockHeaderWithAssetBuffer, - asset: blockHeaderAsset, - }, - payload, - }; -}; - -describe('encoding/decoding', () => { - it('should be able to encode the genesis block', () => { - // Arrange - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Act - const { genesisBlockBuffer, genesisBlockHeaderBuffer } = encodeGenesisBlock(genesisBlock); - - // Assert - expect(genesisBlockBuffer).toBeInstanceOf(Buffer); - expect(hash(genesisBlockHeaderBuffer)).toEqual(genesisBlock.header.id); - }); - - it('should be able to decode the genesis block', () => { - // Arrange - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - const { id, ...genesisBlockHeaderWithoutId } = genesisBlock.header; - const genesisBlockWithoutId = { - header: genesisBlockHeaderWithoutId, - payload: genesisBlock.payload, - }; - const { genesisBlockBuffer: encodedBlockBuffer } = encodeGenesisBlock(genesisBlock); - - // Act - const decodedBlock = decodeGenesisBlock(encodedBlockBuffer); - const { genesisBlockBuffer: doubleEncodedBlockBuffer } = encodeGenesisBlock(decodedBlock); - - // Assert - expect(decodedBlock).toEqual(genesisBlockWithoutId); - expect(encodedBlockBuffer).toEqual(doubleEncodedBlockBuffer); - }); -}); diff --git a/elements/lisk-genesis/test/create.spec.ts b/elements/lisk-genesis/test/create.spec.ts deleted file mode 100644 index ff8dbaad112..00000000000 --- a/elements/lisk-genesis/test/create.spec.ts +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { hash, getRandomBytes } from '@liskhq/lisk-cryptography'; -import { objects } from '@liskhq/lisk-utils'; -import { Account } from '@liskhq/lisk-chain'; -import { createGenesisBlock, getGenesisBlockJSON } from '../src'; -import { validGenesisBlockParams } from './fixtures'; - -describe('create', () => { - describe('createGenesisBlock', () => { - it('should create genesis block', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock).toMatchSnapshot(); - }); - - it('should set "version" to zero', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock.header.version).toEqual(0); - }); - - it('should set "reward" to zero', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock.header.reward).toEqual(BigInt(0)); - }); - - it('should set "transactionRoot" to empty hash', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock.header.transactionRoot).toEqual(hash(Buffer.alloc(0))); - }); - - it('should set "generatorPublicKey" to empty buffer', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock.header.generatorPublicKey).toEqual(Buffer.alloc(0)); - }); - - it('should set "signature" to empty buffer', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock.header.signature).toEqual(Buffer.alloc(0)); - }); - - it('should set "payload" to empty array', () => { - // Arrange & Act - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Assert - expect(genesisBlock.payload).toEqual([]); - }); - - it('should set "height" to provided height', () => { - // Arrange - const height = 10; - - // Act - const genesisBlock = createGenesisBlock({ - ...validGenesisBlockParams, - height, - }); - - // Assert - expect(genesisBlock.header.height).toEqual(height); - }); - - it('should set "timestamp" to provided timestamp', () => { - // Arrange - const timestamp = 1592227157; - - // Act - const genesisBlock = createGenesisBlock({ - ...validGenesisBlockParams, - timestamp, - }); - - // Assert - expect(genesisBlock.header.timestamp).toEqual(timestamp); - }); - - it('should set "previousBlockID" to provided previousBlockID', () => { - // Arrange - const previousBlockID = getRandomBytes(20); - - // Act - const genesisBlock = createGenesisBlock({ - ...validGenesisBlockParams, - previousBlockID, - }); - - // Assert - expect(genesisBlock.header.previousBlockID).toEqual(previousBlockID); - }); - - it('should set "initRounds" ordering lexicographically', () => { - // Arrange - const initDelegates = objects.cloneDeep(validGenesisBlockParams.initDelegates); - const initDelegatesSorted = objects.cloneDeep(initDelegates) as Buffer[]; - const initDelegatesUnSorted = objects.cloneDeep(initDelegates) as Buffer[]; - initDelegatesSorted.sort((a, b) => a.compare(b)); - initDelegatesUnSorted.sort((a, b) => b.compare(a)); - - // Act - const genesisBlock = createGenesisBlock({ - ...validGenesisBlockParams, - initDelegates: initDelegatesUnSorted, - }); - - // Assert - expect(genesisBlock.header.asset.initDelegates).toEqual(initDelegatesSorted); - }); - - it('should set "accounts" ordering lexicographically by "address"', () => { - // Arrange - const accounts = objects.cloneDeep(validGenesisBlockParams.accounts) as Account[]; - accounts.sort((a, b) => b.address.compare(a.address)); - - const accountsSortedAddresses = accounts.map(a => a.address).sort((a, b) => a.compare(b)); - - // Act - const genesisBlock = createGenesisBlock({ - ...validGenesisBlockParams, - accounts, - }); - - // Assert - expect(genesisBlock.header.asset.accounts.map(a => a.address)).toEqual( - accountsSortedAddresses, - ); - }); - - it('should sort accounts with variable lengths of address lexicographically', () => { - // Arrange - const accounts = objects.cloneDeep(validGenesisBlockParams.accounts) as Account[]; - accounts.push({ - address: Buffer.from('8789de4316d79d22', 'hex'), - token: { - balance: BigInt('12300000000'), - }, - }); - - const accountsSortedAddresses = accounts - .map(a => a.address) - .sort((a, b) => { - if (a.length < b.length) { - return -1; - } - if (a.length > b.length) { - return 1; - } - return a.compare(b); - }); - - // Act - const genesisBlock = createGenesisBlock({ - ...validGenesisBlockParams, - accounts, - }); - - // Assert - expect(genesisBlock.header.asset.accounts.map(a => a.address)).toEqual( - accountsSortedAddresses, - ); - }); - }); - - describe('getGenesisBlockJSON', () => { - it('should generate the JSON object for the given genesis block', () => { - // Arrange - const genesisBlock = createGenesisBlock(validGenesisBlockParams); - - // Act - const genesisBlockJSON = getGenesisBlockJSON({ - genesisBlock, - accountAssetSchemas: validGenesisBlockParams.accountAssetSchemas, - }); - - // Assert - expect(genesisBlockJSON).toMatchSnapshot(); - }); - }); -}); diff --git a/elements/lisk-genesis/test/fixtures/index.ts b/elements/lisk-genesis/test/fixtures/index.ts deleted file mode 100644 index 9e023797dbd..00000000000 --- a/elements/lisk-genesis/test/fixtures/index.ts +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright © 2020 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -import { Account, getAccountSchemaWithDefault } from '@liskhq/lisk-chain'; -import { GenesisBlockParams } from '../../src'; - -const delegates = [ - { - address: '25d4c1ed2da24ba856b894c209188f70e0caab6e', - token: { balance: 2874239947 }, - dpos: { delegate: { username: 'ef374a2e8fb9934ad1db0fd5346eb7' } }, - }, - { - address: '2370ba98451e1ff007029f1e602e14bb097b516f', - token: { balance: 2620126571 }, - dpos: { delegate: { username: '13462f8e59880cfde6280d34dfd044' } }, - }, - { - address: '34b3daded550f5b0c50947d8e17762b9730cf1f9', - token: { balance: 2384412768 }, - dpos: { delegate: { username: '920cc701231b2f8c624d4bc8f4c267' } }, - }, - { - address: '372b9d076dd37e7c183cf6ed03c17dd8cdc0d312', - token: { balance: 28138131 }, - dpos: { delegate: { username: '4a1076aa54533dce1c9b7ed51c509b' } }, - }, - { - address: '6e3585b11751423a72eb5b49f57940be50904757', - token: { balance: 2165380961 }, - dpos: { delegate: { username: '98beeddc903498ed7cdd36b417b40f' } }, - }, -]; - -const accounts = [ - { - address: 'dedfbd4c6a1ad1ef0d7a95cd6907114548d8c6d8', - token: { balance: 653021139 }, - }, - { - address: 'c3c307174e5ae301c494396c0fdb6307ec4ec60c', - token: { balance: 1966001160 }, - }, - { - address: '80e08d322c24b5329a257c5b1bd7578032d3b921', - token: { balance: 3116632800 }, - }, - { - address: 'c018b5dd7da4b6b7bf4e6c688e8d7e9841d4aa8f', - token: { balance: 2910960211 }, - }, - { - address: '52c95d24a7ea43d202da8a0da7f08c33a4eb6d5c', - token: { balance: 4218444994 }, - }, - { - address: '4c9513ef7b0bccee024559474700aad70377043b', - token: { balance: 476696623 }, - }, - { - address: '9d34a69551d8b85ec0f552d65ea8dd35724dee90', - token: { balance: 4056778033 }, - }, - { - address: 'c3c6361524043325e8abce8cc1f899e2c2ffd9b0', - token: { balance: 3756324977 }, - }, - { - address: 'd9fbdb4f22faa60936a0113457da019eb61c3d77', - token: { balance: 489340925 }, - }, - { - address: '62150ccf91cc1634f930eed0b7760f421752a698', - token: { balance: 1340967959 }, - }, -]; - -const prepareAccounts = ( - data: { - address: string; - token: { balance: number }; - }[], -): Account[] => { - return data.map(acc => ({ - address: Buffer.from(acc.address, 'hex'), - token: { balance: BigInt(acc.token.balance) }, - })); -}; - -export const validAccounts = prepareAccounts(accounts); - -export const validDelegateAccounts = prepareAccounts(delegates); - -export const defaultAccountModules = { - token: { - type: 'object', - fieldNumber: 2, - properties: { - balance: { - fieldNumber: 1, - dataType: 'uint64', - }, - }, - default: { - balance: BigInt(0), - }, - }, - dpos: { - type: 'object', - fieldNumber: 5, - properties: { - delegate: { - type: 'object', - fieldNumber: 1, - properties: { - username: { dataType: 'string', fieldNumber: 1 }, - pomHeights: { - type: 'array', - items: { dataType: 'uint32' }, - fieldNumber: 2, - }, - consecutiveMissedBlocks: { dataType: 'uint32', fieldNumber: 3 }, - lastForgedHeight: { dataType: 'uint32', fieldNumber: 4 }, - isBanned: { dataType: 'boolean', fieldNumber: 5 }, - totalVotesReceived: { dataType: 'uint64', fieldNumber: 6 }, - }, - required: [ - 'username', - 'pomHeights', - 'consecutiveMissedBlocks', - 'lastForgedHeight', - 'isBanned', - 'totalVotesReceived', - ], - }, - sentVotes: { - type: 'array', - fieldNumber: 2, - items: { - type: 'object', - properties: { - delegateAddress: { - dataType: 'bytes', - fieldNumber: 1, - }, - amount: { - dataType: 'uint64', - fieldNumber: 2, - }, - }, - required: ['delegateAddress', 'amount'], - }, - }, - unlocking: { - type: 'array', - fieldNumber: 3, - items: { - type: 'object', - properties: { - delegateAddress: { - dataType: 'bytes', - fieldNumber: 1, - }, - amount: { - dataType: 'uint64', - fieldNumber: 2, - }, - unvoteHeight: { - dataType: 'uint32', - fieldNumber: 3, - }, - }, - required: ['delegateAddress', 'amount', 'unvoteHeight'], - }, - }, - }, - default: { - delegate: { - username: '', - pomHeights: [], - consecutiveMissedBlocks: 0, - lastForgedHeight: 0, - isBanned: false, - totalVotesReceived: BigInt(0), - }, - sentVotes: [], - unlocking: [], - }, - }, -}; - -const { default: defaultAccount, ...defaultAccountSchema } = getAccountSchemaWithDefault( - defaultAccountModules, -); - -export { defaultAccountSchema }; - -export const validGenesisBlockParams = { - initRounds: 5, - height: 5, - timestamp: 1591873718, - previousBlockID: Buffer.from( - '454690a1c37838326007519a7ce1c8a6a495df50898f1ebd69d22fbcedf9689a', - 'hex', - ), - initDelegates: validDelegateAccounts.map(a => a.address), - accounts: [...validAccounts, ...validDelegateAccounts] as Account[], - accountAssetSchemas: defaultAccountModules, -} as GenesisBlockParams; diff --git a/elements/lisk-genesis/test/tsconfig.json b/elements/lisk-genesis/test/tsconfig.json deleted file mode 120000 index c73c54e77b4..00000000000 --- a/elements/lisk-genesis/test/tsconfig.json +++ /dev/null @@ -1 +0,0 @@ -../../../templates/test/tsconfig.json.tmpl \ No newline at end of file diff --git a/elements/lisk-genesis/tsconfig.json b/elements/lisk-genesis/tsconfig.json deleted file mode 120000 index 900bb05c680..00000000000 --- a/elements/lisk-genesis/tsconfig.json +++ /dev/null @@ -1 +0,0 @@ -../../templates/tsconfig.json.tmpl \ No newline at end of file diff --git a/framework-plugins/lisk-framework-forger-plugin/package.json b/framework-plugins/lisk-framework-forger-plugin/package.json index 1fa392d4eb5..522a13fcfd5 100644 --- a/framework-plugins/lisk-framework-forger-plugin/package.json +++ b/framework-plugins/lisk-framework-forger-plugin/package.json @@ -44,7 +44,6 @@ }, "devDependencies": { "@liskhq/lisk-api-client": "^5.1.4", - "@liskhq/lisk-genesis": "^0.2.3", "@types/debug": "4.1.5", "@types/jest": "26.0.21", "@types/jest-when": "2.7.2", diff --git a/framework/package.json b/framework/package.json index e5dd590de6d..e526cb62aa5 100644 --- a/framework/package.json +++ b/framework/package.json @@ -46,7 +46,6 @@ "@liskhq/lisk-codec": "^0.2.1", "@liskhq/lisk-cryptography": "^3.2.0", "@liskhq/lisk-db": "^0.2.0", - "@liskhq/lisk-genesis": "^0.2.3", "@liskhq/lisk-p2p": "^0.7.2", "@liskhq/lisk-transaction-pool": "^0.5.1", "@liskhq/lisk-transactions": "^5.2.0", diff --git a/framework/src/application.ts b/framework/src/application.ts index c353722163e..8f03ae48f0a 100644 --- a/framework/src/application.ts +++ b/framework/src/application.ts @@ -49,6 +49,7 @@ import { FeeModule, FeeAPI } from './modules/fee'; import { RewardModule, RewardAPI } from './modules/reward'; import { RandomModule, RandomAPI } from './modules/random'; import { DPoSModule, DPoSAPI } from './modules/dpos_v2'; +import { GenesisBlockGenerateInput } from './node/generator'; const MINIMUM_EXTERNAL_MODULE_ID = 1000; @@ -121,16 +122,13 @@ export class Application { private readonly _node: Node; private readonly _controller: Controller; - private _genesisBlock!: Record | undefined; private _blockchainDB!: KVStore; private _nodeDB!: KVStore; private _forgerDB!: KVStore; private readonly _mutex = new jobHandlers.Mutex(); - public constructor(genesisBlock: Record, config: PartialApplicationConfig = {}) { - // Don't change the object parameters provided - this._genesisBlock = genesisBlock; + public constructor(config: PartialApplicationConfig = {}) { const appConfig = objects.cloneDeep(applicationConfigSchema.default); appConfig.label = @@ -174,11 +172,8 @@ export class Application { return this._node.bftAPI; } - public static defaultApplication( - genesisBlock: Record, - config: PartialApplicationConfig = {}, - ): DefaultApplication { - const application = new Application(genesisBlock, config); + public static defaultApplication(config: PartialApplicationConfig = {}): DefaultApplication { + const application = new Application(config); // create module instances const authModule = new AuthModule(); const tokenModule = new TokenModule(); @@ -239,7 +234,7 @@ export class Application { return this._node.getRegisteredModules(); } - public async run(): Promise { + public async run(genesisBlock: Block): Promise { Object.freeze(this.config); registerProcessHooks(this); @@ -276,12 +271,6 @@ export class Application { networkIdentifier: this.networkIdentifier, }); - if (!this._genesisBlock) { - throw new Error('Genesis block must exist.'); - } - - const genesisBlock = Block.fromJSON(this._genesisBlock); - await this._node.init({ channel: this.channel, genesisBlock, @@ -297,9 +286,6 @@ export class Application { this.logger.debug(this._controller.getEndpoints(), 'Application ready for actions'); this.channel.publish(APP_EVENT_READY); - // TODO: Update genesis block to be provided in this function - // For now, the memory should be free up - delete this._genesisBlock; }); } @@ -331,6 +317,10 @@ export class Application { } } + public async generateGenesisBlock(input: GenesisBlockGenerateInput): Promise { + return this._node.generateGenesisBlock(input); + } + // -------------------------------------- // Private // -------------------------------------- diff --git a/framework/src/node/consensus/consensus.ts b/framework/src/node/consensus/consensus.ts index 72bf6709687..3e6ced7dde7 100644 --- a/framework/src/node/consensus/consensus.ts +++ b/framework/src/node/consensus/consensus.ts @@ -191,7 +191,7 @@ export class Consensus { const apiContext = createAPIContext({ stateStore: state.stateStore, eventQueue }); const bftParams = await this._bftAPI.getBFTParameters( apiContext, - args.genesisBlock.header.height, + args.genesisBlock.header.height + 1, ); if ( diff --git a/framework/src/node/generator/constants.ts b/framework/src/node/generator/constants.ts index ee02b73729d..aa4bb70da35 100644 --- a/framework/src/node/generator/constants.ts +++ b/framework/src/node/generator/constants.ts @@ -12,6 +12,8 @@ * Removal or modification of this copyright notice is prohibited. */ +import { hash } from '@liskhq/lisk-cryptography'; + export const DEFAULT_RELEASE_LIMIT = 100; export const DEFAULT_RELEASE_INTERVAL = 5000; export const DEFAULT_RATE_LIMIT_FREQUENCY = 3; @@ -22,3 +24,7 @@ export const NETWORK_RPC_GET_TRANSACTIONS = 'getTransactions'; export const NETWORK_EVENT_POST_TRANSACTIONS_ANNOUNCEMENT = 'postTransactionsAnnouncement'; export const GENERATOR_STORE_RESERVED_PREFIX = 0; + +export const EMPTY_BUFFER = Buffer.alloc(0); +export const EMPTY_HASH = hash(Buffer.alloc(0)); +export const GENESIS_BLOCK_VERSION = 0; diff --git a/framework/src/node/generator/generator.ts b/framework/src/node/generator/generator.ts index d3f3b2dca9e..bba946ec8a3 100644 --- a/framework/src/node/generator/generator.ts +++ b/framework/src/node/generator/generator.ts @@ -28,7 +28,7 @@ import { getPrivateAndPublicKeyFromPassphrase, parseEncryptedPassphrase, } from '@liskhq/lisk-cryptography'; -import { KVStore } from '@liskhq/lisk-db'; +import { InMemoryKVStore, KVStore } from '@liskhq/lisk-db'; import { TransactionPool, events } from '@liskhq/lisk-transaction-pool'; import { MerkleTree, SparseMerkleTree } from '@liskhq/lisk-tree'; import { dataStructures, jobHandlers } from '@liskhq/lisk-utils'; @@ -43,6 +43,7 @@ import { TransactionContext, VerifyStatus, BlockContext, + GenesisBlockContext, } from '../state_machine'; import { Broadcaster } from './broadcaster'; import { @@ -52,6 +53,9 @@ import { LOAD_TRANSACTION_RETRIES, NETWORK_RPC_GET_TRANSACTIONS, NETWORK_EVENT_POST_TRANSACTIONS_ANNOUNCEMENT, + EMPTY_BUFFER, + EMPTY_HASH, + GENESIS_BLOCK_VERSION, } from './constants'; import { GenerationContext } from './context'; import { Endpoint } from './endpoint'; @@ -59,7 +63,14 @@ import { GeneratorStore } from './generator_store'; import { NetworkEndpoint } from './network_endpoint'; import { GetTransactionResponse, getTransactionsResponseSchema } from './schemas'; import { HighFeeGenerationStrategy } from './strategies'; -import { Consensus, GeneratorModule, BFTAPI, ValidatorAPI } from './types'; +import { + Consensus, + GeneratorModule, + BFTAPI, + ValidatorAPI, + BlockGenerateInput, + GenesisBlockGenerateInput, +} from './types'; import { createAPIContext, createNewAPIContext } from '../state_machine/api_context'; import { getOrDefaultLastGeneratedInfo, setLastGeneratedInfo } from './generated_info'; @@ -262,6 +273,68 @@ export class Generator { } } + public async generateGenesisBlock(input: GenesisBlockGenerateInput): Promise { + const assets = new BlockAssets( + input.assets.map(asset => ({ + moduleID: asset.moduleID, + data: codec.encode(asset.schema, asset.data), + })), + ); + assets.sort(); + const assetsRoot = await assets.getRoot(); + const height = input.height ?? 0; + const previousBlockID = input.previousBlockID ?? Buffer.alloc(32, 0); + const timestamp = input.timestamp ?? Math.floor(Date.now() / 1000); + const header = new BlockHeader({ + version: GENESIS_BLOCK_VERSION, + previousBlockID, + height, + timestamp, + generatorAddress: EMPTY_BUFFER, + maxHeightGenerated: 0, + maxHeightPrevoted: height, + signature: EMPTY_BUFFER, + transactionRoot: EMPTY_HASH, + assetsRoot, + aggregateCommit: { + height: 0, + aggregationBits: EMPTY_BUFFER, + certificateSignature: EMPTY_BUFFER, + }, + }); + // Information is not stored in the database + const db = new InMemoryKVStore(); + const eventQueue = new EventQueue(); + const stateStore = new StateStore(db); + const blockCtx = new GenesisBlockContext({ + eventQueue, + header, + assets, + logger: this._logger, + stateStore, + }); + + await this._stateMachine.executeGenesisBlock(blockCtx); + + const smtStore = new SMTStore(new InMemoryKVStore()); + const smt = new SparseMerkleTree({ db: smtStore }); + await stateStore.finalize(db.batch(), smt); + + const apiContext = createAPIContext({ stateStore, eventQueue }); + const bftParams = await this._bftAPI.getBFTParameters(apiContext, height + 1); + header.stateRoot = smt.rootHash; + header.validatorsHash = bftParams.validatorsHash; + + return new Block(header, [], assets); + } + + public async generateBlock(input: BlockGenerateInput): Promise { + const block = await this._generateBlock({ + ...input, + }); + return block; + } + public async _loadTransactionsFromNetwork(): Promise { for (let retry = 0; retry < LOAD_TRANSACTION_RETRIES; retry += 1) { try { @@ -419,7 +492,12 @@ export class Generator { ); return; } - const generatedBlock = await this._generateBlock(generator, validatorKeypair, currentTime); + const generatedBlock = await this._generateBlock({ + height: this._chain.lastBlock.header.height + 1, + generatorAddress: generator, + privateKey: validatorKeypair.privateKey, + timestamp: currentTime, + }); this._logger.info( { id: generatedBlock.header.id, @@ -432,25 +510,25 @@ export class Generator { await this._consensus.execute(generatedBlock as never); } - private async _generateBlock( - generatorAddress: Buffer, - keypair: Keypair, - timestamp: number, - ): Promise { + private async _generateBlock(input: BlockGenerateInput): Promise { + const { generatorAddress, timestamp, privateKey, height } = input; const stateStore = new StateStore(this._blockchainDB); - const generatorStore = new GeneratorStore(this._generatorDB); + const generatorStore = new GeneratorStore(input.db ?? this._generatorDB); const apiContext = createAPIContext({ stateStore, eventQueue: new EventQueue() }); const { maxHeightPrevoted } = await this._bftAPI.getBFTHeights(apiContext); - const { height } = await getOrDefaultLastGeneratedInfo(generatorStore, generatorAddress); + const { height: maxHeightGenerated } = await getOrDefaultLastGeneratedInfo( + generatorStore, + generatorAddress, + ); const blockHeader = new BlockHeader({ generatorAddress, - height: this._chain.lastBlock.header.height + 1, + height, previousBlockID: this._chain.lastBlock.header.id, version: BLOCK_VERSION, maxHeightPrevoted, - maxHeightGenerated: height, + maxHeightGenerated, aggregateCommit: { height: 0, aggregationBits: Buffer.alloc(0), @@ -487,7 +565,8 @@ export class Generator { }); await this._stateMachine.beforeExecuteBlock(blockCtx); - const transactions = await this._forgingStrategy.getTransactionsForBlock(blockHeader); + const transactions = + input.transactions ?? (await this._forgingStrategy.getTransactionsForBlock(blockHeader)); blockCtx.setTransactions(transactions); @@ -516,9 +595,9 @@ export class Generator { // Assign root hash calculated in SMT to state root of block header blockHeader.stateRoot = smt.rootHash; // Set validatorsHash - const { validatorsHash } = await this._bftAPI.getBFTParameters(apiContext, height); + const { validatorsHash } = await this._bftAPI.getBFTParameters(apiContext, height + 1); blockHeader.validatorsHash = validatorsHash; - blockHeader.sign(this._chain.networkIdentifier, keypair.privateKey); + blockHeader.sign(this._chain.networkIdentifier, privateKey); const generatedBlock = new Block(blockHeader, transactions, blockAssets); diff --git a/framework/src/node/generator/index.ts b/framework/src/node/generator/index.ts index 2fe0be8d123..0f6bfe87388 100644 --- a/framework/src/node/generator/index.ts +++ b/framework/src/node/generator/index.ts @@ -13,4 +13,10 @@ */ export { Generator } from './generator'; -export { BlockGenerateContext, Keypair, GeneratorStore } from './types'; +export { + BlockGenerateContext, + Keypair, + GeneratorStore, + GenesisBlockGenerateInput, + BlockGenerateInput, +} from './types'; diff --git a/framework/src/node/generator/types.ts b/framework/src/node/generator/types.ts index 62f1a17186d..0d2258add5d 100644 --- a/framework/src/node/generator/types.ts +++ b/framework/src/node/generator/types.ts @@ -12,7 +12,8 @@ * Removal or modification of this copyright notice is prohibited. */ -import { Block } from '@liskhq/lisk-chain'; +import { Block, Transaction } from '@liskhq/lisk-chain'; +import { Schema } from '@liskhq/lisk-codec'; import { Options } from '@liskhq/lisk-db'; import { Logger } from '../../logger'; import { BFTParameters } from '../../modules/bft/schemas'; @@ -75,3 +76,23 @@ export interface GeneratorDB { get: (key: Buffer) => Promise; exists(key: Buffer): Promise; } + +export interface GenesisBlockGenerateInput { + height?: number; + timestamp?: number; + previousBlockID?: Buffer; + assets: { + schema: Schema; + moduleID: number; + data: Record; + }[]; +} + +export interface BlockGenerateInput { + height: number; + timestamp: number; + generatorAddress: Buffer; + privateKey: Buffer; + transactions?: Transaction[]; + db?: GeneratorDB; +} diff --git a/framework/src/node/node.ts b/framework/src/node/node.ts index 90539b72c64..086cc9ee298 100644 --- a/framework/src/node/node.ts +++ b/framework/src/node/node.ts @@ -24,7 +24,7 @@ import { BaseModule } from '../modules/base_module'; import { BaseCommand } from '../modules/base_command'; import { StateMachine } from './state_machine'; import { Consensus, CONSENSUS_EVENT_BLOCK_DELETE, CONSENSUS_EVENT_BLOCK_NEW } from './consensus'; -import { Generator } from './generator'; +import { BlockGenerateInput, Generator, GenesisBlockGenerateInput } from './generator'; import { Endpoint } from './endpoint'; import { getRegisteredModules, getSchema } from './utils/modules'; import { getEndpointHandlers, mergeEndpointHandlers } from '../endpoint'; @@ -110,6 +110,7 @@ export class Node { consensus: this._consensus, generator: this._generator, }); + this._bftModule.addDependencies(this._validatorsModule.api); this._stateMachine.registerSystemModule(this._validatorsModule); this._stateMachine.registerSystemModule(this._bftModule); this._generator.registerModule(this._validatorsModule); @@ -258,6 +259,14 @@ export class Node { this._logger.info('Node ready and launched'); } + public async generateGenesisBlock(input: GenesisBlockGenerateInput): Promise { + return this._generator.generateGenesisBlock(input); + } + + public async generateBlock(input: BlockGenerateInput): Promise { + return this._generator.generateBlock(input); + } + public get bftAPI(): BFTAPI { return this._bftModule.api; } diff --git a/framework/src/testing/app_env.ts b/framework/src/testing/app_env.ts index 2e228836cb8..697864b6a99 100644 --- a/framework/src/testing/app_env.ts +++ b/framework/src/testing/app_env.ts @@ -21,7 +21,6 @@ import { objects } from '@liskhq/lisk-utils'; import { homedir } from 'os'; import { existsSync, rmdirSync } from 'fs-extra'; import { defaultConfig } from './fixtures'; -import { createGenesisBlock } from './create_genesis_block'; import { PartialApplicationConfig } from '../types'; import { Application } from '../application'; import { BaseModule } from '../modules'; @@ -40,7 +39,7 @@ export class ApplicationEnv { private _application!: Application; private _dataPath!: string; private _ipcClient!: APIClient; - private _genesisBlock!: Record; + private _genesisBlock!: Block; public constructor(appConfig: ApplicationEnvConfig) { this._initApplication(appConfig); @@ -68,10 +67,11 @@ export class ApplicationEnv { } public async startApplication(): Promise { - // eslint-disable-next-line dot-notation - this._application['_genesisBlock'] = this._genesisBlock; + this._genesisBlock = await this._application.generateGenesisBlock({ + assets: [], + }); await Promise.race([ - this._application.run(), + this._application.run(this._genesisBlock), new Promise(resolve => setTimeout(resolve, 3000)), ]); // Only start client when ipc is enabled @@ -111,17 +111,14 @@ export class ApplicationEnv { // As we can call this function with different configuration // so we need to make sure existing schemas are already clear codec.clearCache(); - const { genesisBlockJSON } = createGenesisBlock({}); - this._genesisBlock = genesisBlockJSON; // In order for application to start forging, update force to true const config = objects.mergeDeep({}, defaultConfig, appConfig.config ?? {}); const { label } = config; - const application = new Application(this._genesisBlock, config as PartialApplicationConfig); + const application = new Application(config as PartialApplicationConfig); appConfig.modules.map(module => application.registerModule(module)); appConfig.plugins?.map(plugin => application.registerPlugin(plugin)); this._dataPath = join(application.config.rootPath, label); - this._application = application; return application; } diff --git a/framework/src/testing/block_processing_env.ts b/framework/src/testing/block_processing_env.ts index fac5fc294cf..6cc291dde26 100644 --- a/framework/src/testing/block_processing_env.ts +++ b/framework/src/testing/block_processing_env.ts @@ -25,7 +25,6 @@ import { loggerMock, channelMock } from './mocks'; import { defaultConfig, getPassphraseFromDefaultConfig } from './fixtures'; import { createDB, removeDB } from './utils'; import { ApplicationConfig, GenesisConfig } from '../types'; -import { createGenesisBlock } from './create_genesis_block'; import { Consensus } from '../node/consensus'; import { APIContext } from '../node/state_machine'; import { Node } from '../node'; @@ -95,11 +94,13 @@ const createProcessableBlock = async ( for (const tx of payload) { await node['_generator']['_pool'].add(tx); } - const block = await node['_generator']['_generateBlock']( - validator, - getKeys(passphrase), - nextTimestamp, - ); + const { privateKey } = getKeys(passphrase); + const block = await node.generateBlock({ + generatorAddress: validator, + height: previousBlockHeader.height + 1, + privateKey, + timestamp: nextTimestamp, + }); return block; }; @@ -108,17 +109,16 @@ export const getBlockProcessingEnv = async ( params: BlockProcessingParams, ): Promise => { const appConfig = getAppConfig(params.options?.genesisConfig); - const { genesisBlock } = createGenesisBlock({}); - const networkIdentifier = getNetworkIdentifier( - genesisBlock.header.id, - appConfig.genesisConfig.communityIdentifier, - ); + removeDB(params.options?.databasePath); const blockchainDB = createDB('blockchain', params.options?.databasePath); const forgerDB = createDB('forger', params.options?.databasePath); const node = new Node({ options: appConfig, }); + const genesisBlock = await node.generateGenesisBlock({ + assets: [], + }); await node.init({ blockchainDB, channel: channelMock as InMemoryChannel, @@ -128,6 +128,11 @@ export const getBlockProcessingEnv = async ( nodeDB: (new InMemoryKVStore() as unknown) as KVStore, }); + const networkIdentifier = getNetworkIdentifier( + genesisBlock.header.id, + appConfig.genesisConfig.communityIdentifier, + ); + return { createBlock: async (payload: Transaction[] = [], timestamp?: number): Promise => createProcessableBlock(node, payload, timestamp), diff --git a/framework/src/testing/create_genesis_block.ts b/framework/src/testing/create_genesis_block.ts deleted file mode 100644 index 09d83828d77..00000000000 --- a/framework/src/testing/create_genesis_block.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright © 2021 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - * - */ - -import { - Block, - BlockAssets, - BlockHeader, - BlockHeaderJSON, - TransactionJSON, -} from '@liskhq/lisk-chain'; -import { hash } from '@liskhq/lisk-cryptography'; -import { GenesisConfig } from '../types'; - -interface CreateGenesisBlock { - genesisConfig?: GenesisConfig; - initDelegates?: ReadonlyArray; - height?: number; - timestamp?: number; - previousBlockID?: Buffer; - assets?: BlockAssets; -} - -export const createGenesisBlock = ( - params: CreateGenesisBlock, -): { - genesisBlock: Block; - genesisBlockJSON: { header: BlockHeaderJSON; payload: TransactionJSON[] }; -} => { - const height = params.height ?? 0; - // Set genesis block timestamp to 1 day in past relative to current date - const today = new Date(); - const yesterday = new Date(today.getTime() - 1000 * 60 * 60 * 24); - const defaultTimestamp = Math.floor(yesterday.getTime() / 1000); - const timestamp = params.timestamp ?? defaultTimestamp; - const previousBlockID = params.previousBlockID ?? Buffer.alloc(0); - - const header = new BlockHeader({ - previousBlockID, - generatorAddress: Buffer.alloc(0), - height, - timestamp, - version: 0, - transactionRoot: hash(Buffer.alloc(0)), - stateRoot: hash(Buffer.alloc(0)), - signature: Buffer.alloc(0), - maxHeightGenerated: 0, - maxHeightPrevoted: 0, - assetsRoot: hash(Buffer.alloc(0)), - aggregateCommit: { - height: 0, - aggregationBits: Buffer.alloc(0), - certificateSignature: Buffer.alloc(0), - }, - validatorsHash: hash(Buffer.alloc(0)), - }); - - const genesisBlock = new Block(header, [], params.assets ?? new BlockAssets()); - - return { - genesisBlock, - genesisBlockJSON: { - header: header.toJSON(), - payload: [], - }, - }; -}; diff --git a/framework/src/testing/index.ts b/framework/src/testing/index.ts index 48dd5339fa6..203bd97e91e 100644 --- a/framework/src/testing/index.ts +++ b/framework/src/testing/index.ts @@ -16,7 +16,6 @@ import * as fixtures from './fixtures'; import * as mocks from './mocks'; export { createTransaction } from './create_transaction'; -export { createGenesisBlock } from './create_genesis_block'; export * from './create_block'; export * from './app_env'; export * from './create_contexts'; diff --git a/framework/test/unit/application.spec.ts b/framework/test/unit/application.spec.ts index b3bba3d3fa4..046e87586e6 100644 --- a/framework/test/unit/application.spec.ts +++ b/framework/test/unit/application.spec.ts @@ -17,6 +17,7 @@ import { objects } from '@liskhq/lisk-utils'; import * as fs from 'fs-extra'; import * as os from 'os'; import { join } from 'path'; +import { Block, BlockAssets } from '@liskhq/lisk-chain'; import { BaseChannel, BasePlugin } from '../../src'; import { Application } from '../../src/application'; import { Bus } from '../../src/controller/bus'; @@ -25,9 +26,9 @@ import { WSServer } from '../../src/controller/ws/ws_server'; import { createLogger } from '../../src/logger'; import { Node } from '../../src/node'; import { systemDirs } from '../../src/system_dirs'; -import { genesisBlock } from '../fixtures/blocks'; import * as basePluginModule from '../../src/plugins/base_plugin'; import * as networkConfig from '../fixtures/config/devnet/config.json'; +import { createFakeBlockHeader } from '../fixtures'; jest.mock('fs-extra'); jest.mock('zeromq', () => { @@ -68,8 +69,6 @@ describe('Application', () => { trace: jest.fn(), fatal: jest.fn(), }; - const { id, ...header } = genesisBlock().header.toJSON(); - const genesisBlockJSON = { header, payload: [], assets: [] }; (createLogger as jest.Mock).mockReturnValue(loggerMock); @@ -83,7 +82,7 @@ describe('Application', () => { describe('#constructor', () => { it('should be able to start the application with default parameters if config is not provided', () => { - const { app } = Application.defaultApplication(genesisBlockJSON); + const { app } = Application.defaultApplication(); expect(app.config).toBeDefined(); }); @@ -94,13 +93,13 @@ describe('Application', () => { const configWithoutLabel = objects.cloneDeep(config); delete configWithoutLabel.label; - const { app } = Application.defaultApplication(genesisBlockJSON, configWithoutLabel); + const { app } = Application.defaultApplication(configWithoutLabel); expect(app.config.label).toBe(label); }); it('should use the same app label if provided', () => { - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); expect(app.config.label).toBe(config.label); }); @@ -112,7 +111,7 @@ describe('Application', () => { delete configWithoutRootPath.rootPath; // Act - const { app } = Application.defaultApplication(genesisBlockJSON, configWithoutRootPath); + const { app } = Application.defaultApplication(configWithoutRootPath); // Assert expect(app.config.rootPath).toBe(rootPath); @@ -125,7 +124,7 @@ describe('Application', () => { configWithCustomRootPath.rootPath = customRootPath; // Act - const { app } = Application.defaultApplication(genesisBlockJSON, configWithCustomRootPath); + const { app } = Application.defaultApplication(configWithCustomRootPath); // Assert expect(app.config.rootPath).toBe(customRootPath); @@ -137,7 +136,7 @@ describe('Application', () => { configWithoutLogger.logger = {}; // Act - const { app } = Application.defaultApplication(genesisBlockJSON, configWithoutLogger); + const { app } = Application.defaultApplication(configWithoutLogger); // Assert expect(app.config.logger.logFileName).toBe('lisk.log'); @@ -158,17 +157,16 @@ describe('Application', () => { }, }; - const { app } = Application.defaultApplication(genesisBlockJSON, customConfig); + const { app } = Application.defaultApplication(customConfig); expect(app.config.genesisConfig.maxPayloadLength).toBe(15 * 1024); }); it('should set internal variables', () => { // Act - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); // Assert - expect(app['_genesisBlock']).toEqual(genesisBlockJSON); expect(app.config).toMatchSnapshot(); expect(app['_node']).not.toBeUndefined(); expect(app['_controller']).not.toBeUndefined(); @@ -176,7 +174,7 @@ describe('Application', () => { it('should not initialize logger', () => { // Act - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); // Assert expect(app.logger).toBeUndefined(); @@ -203,7 +201,7 @@ describe('Application', () => { // Act & Assert expect.assertions(5); try { - Application.defaultApplication(genesisBlockJSON, invalidConfig); + Application.defaultApplication(invalidConfig); } catch (error) { /* eslint-disable jest/no-try-expect */ expect(error.errors).toHaveLength(4); @@ -219,7 +217,7 @@ describe('Application', () => { describe('#registerPlugin', () => { it('should throw error when plugin name is missing', () => { // Arrange - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); class MyPlugin extends TestPlugin { public name = ''; } @@ -230,7 +228,7 @@ describe('Application', () => { it('should throw error when plugin with same name is already registered', () => { // Arrange - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); class MyPlugin extends TestPlugin { public name = 'my-plugin'; } @@ -244,7 +242,7 @@ describe('Application', () => { it('should call validatePluginSpec function', () => { // Arrange - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); jest.spyOn(basePluginModule, 'validatePluginSpec').mockReturnValue(); // Act @@ -257,7 +255,7 @@ describe('Application', () => { it('should throw error when plugin is required to load as child process and not exported', () => { // Arrange - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); jest.spyOn(basePluginModule, 'getPluginExportPath').mockReturnValue(undefined); // Act && Assert @@ -270,7 +268,7 @@ describe('Application', () => { it('should add plugin to the collection', () => { // Arrange - const { app } = Application.defaultApplication(genesisBlockJSON, config); + const { app } = Application.defaultApplication(config); const plugin = new TestPlugin(); jest.spyOn(app['_controller'], 'registerPlugin'); app.registerPlugin(plugin); @@ -287,14 +285,15 @@ describe('Application', () => { let dirs: any; beforeEach(async () => { - ({ app } = Application.defaultApplication(genesisBlockJSON, config)); + ({ app } = Application.defaultApplication(config)); jest.spyOn(app['_node']['_network'], 'start').mockResolvedValue(); jest.spyOn(fs, 'readdirSync').mockReturnValue([]); // jest.spyOn(IPCServer.prototype, 'start').mockResolvedValue(); jest.spyOn(Bus.prototype, 'publish').mockResolvedValue(jest.fn() as never); jest.spyOn(WSServer.prototype, 'start').mockResolvedValue(jest.fn() as never); + jest.spyOn(app['_node']['_stateMachine'], 'executeGenesisBlock').mockResolvedValue(); - await app.run(); + await app.run(new Block(createFakeBlockHeader(), [], new BlockAssets())); dirs = systemDirs(app.config.label, app.config.rootPath); }); @@ -331,15 +330,16 @@ describe('Application', () => { const fakeSocketFiles = ['1.sock' as any, '2.sock' as any]; beforeEach(async () => { - ({ app } = Application.defaultApplication(genesisBlockJSON, config)); + ({ app } = Application.defaultApplication(config)); jest.spyOn(app['_node'], 'init').mockResolvedValue(); jest.spyOn(app['_node'], 'start').mockResolvedValue(); jest.spyOn(app['_node'], 'stop').mockResolvedValue(); jest.spyOn(fs, 'readdirSync').mockReturnValue(fakeSocketFiles); jest.spyOn(Bus.prototype, 'publish').mockResolvedValue(jest.fn() as never); jest.spyOn(fs, 'unlink').mockResolvedValue(); + jest.spyOn(app['_node']['_stateMachine'], 'executeGenesisBlock').mockResolvedValue(); - await app.run(); + await app.run(new Block(createFakeBlockHeader(), [], new BlockAssets())); await app.shutdown(); }); @@ -365,9 +365,12 @@ describe('Application', () => { beforeEach(async () => { jest.spyOn(Bus.prototype, 'publish').mockResolvedValue(jest.fn() as never); - ({ app } = Application.defaultApplication(genesisBlockJSON, config)); + ({ app } = Application.defaultApplication(config)); jest.spyOn(app['_node']['_network'], 'start').mockResolvedValue(); - await app.run(); + jest.spyOn(app['_node']['_stateMachine'], 'executeGenesisBlock').mockResolvedValue(); + + await app.run(new Block(createFakeBlockHeader(), [], new BlockAssets())); + jest.spyOn(fs, 'readdirSync').mockReturnValue(fakeSocketFiles); nodeCleanupSpy = jest.spyOn(app['_node'], 'stop').mockResolvedValue(); jest.spyOn(app['_controller'], 'stop'); diff --git a/framework/test/unit/controller/bus.spec.ts b/framework/test/unit/controller/bus.spec.ts index 329377bc60b..3889c6c26ad 100644 --- a/framework/test/unit/controller/bus.spec.ts +++ b/framework/test/unit/controller/bus.spec.ts @@ -21,6 +21,7 @@ import { WSServer } from '../../../src/controller/ws/ws_server'; import { IPCServer } from '../../../src/controller/ipc/ipc_server'; import { EndpointInfo } from '../../../src'; +jest.mock('ws'); jest.mock('eventemitter2'); jest.mock('zeromq', () => { return { diff --git a/framework/test/unit/node/generator/generator.spec.ts b/framework/test/unit/node/generator/generator.spec.ts index aeb471578fd..bc33c982c1b 100644 --- a/framework/test/unit/node/generator/generator.spec.ts +++ b/framework/test/unit/node/generator/generator.spec.ts @@ -11,7 +11,7 @@ * * Removal or modification of this copyright notice is prohibited. */ -import { BlockAssets, Chain, Transaction } from '@liskhq/lisk-chain'; +import { Block, BlockAssets, Chain, Transaction } from '@liskhq/lisk-chain'; import { getAddressFromPublicKey, getRandomBytes, hash } from '@liskhq/lisk-cryptography'; import { InMemoryKVStore, KVStore } from '@liskhq/lisk-db'; import { codec } from '@liskhq/lisk-codec'; @@ -128,6 +128,7 @@ describe('generator', () => { verifyTransaction: jest.fn(), beforeExecuteBlock: jest.fn(), afterExecuteBlock: jest.fn(), + executeGenesisBlock: jest.fn(), } as never; network = { registerEndpoint: jest.fn(), @@ -439,7 +440,109 @@ describe('generator', () => { }); }); - describe('_generateBlock', () => { + describe('generateGenesisBlock', () => { + let mod1: GeneratorModule; + let mod2: GeneratorModule; + + const validatorsHash = hash(getRandomBytes(32)); + const assetSchema1 = { + $id: 'assetSchema1', + type: 'object', + properties: { + data: { fieldNumber: 1, dataType: 'uint32' }, + }, + }; + const assetSchema2 = { + $id: 'assetSchema2', + type: 'object', + properties: { + data: { fieldNumber: 1, dataType: 'string' }, + }, + }; + const assets = [ + { + moduleID: 5, + data: { data: 'asset-schema2' }, + schema: assetSchema2, + }, + { + moduleID: 2, + data: { data: 123 }, + schema: assetSchema1, + }, + ]; + + beforeEach(async () => { + mod1 = { + id: 1, + initBlock: jest.fn(), + }; + mod2 = { + id: 2, + sealBlock: jest.fn(), + }; + generator.registerModule(mod1); + generator.registerModule(mod2); + jest.spyOn(stateMachine, 'executeGenesisBlock'); + jest + .spyOn(generator['_bftAPI'], 'getBFTParameters') + .mockResolvedValue({ validatorsHash } as never); + await generator.init({ + blockchainDB, + generatorDB, + logger, + }); + }); + + it('should execute genesis block', async () => { + const genesisBlock = await generator.generateGenesisBlock({ assets }); + + expect(stateMachine.executeGenesisBlock).toHaveBeenCalledTimes(1); + expect(genesisBlock).toBeInstanceOf(Block); + }); + + it('should get BFT parameters using next height', async () => { + const genesisBlock = await generator.generateGenesisBlock({ assets, height: 100 }); + + expect(generator['_bftAPI'].getBFTParameters).toHaveBeenCalledWith(expect.anything(), 101); + expect(genesisBlock).toBeInstanceOf(Block); + }); + + it('should set height, previousBlockID and timestamp to the genesis block', async () => { + const previousBlockID = getRandomBytes(32); + const timestamp = 1121222; + const height = 100; + const genesisBlock = await generator.generateGenesisBlock({ + assets, + height, + timestamp, + previousBlockID, + }); + + expect(genesisBlock.header.previousBlockID).toEqual(previousBlockID); + expect(genesisBlock.header.timestamp).toEqual(timestamp); + expect(genesisBlock.header.height).toEqual(height); + }); + + it('should include sorted assets to the genesis block', async () => { + const genesisBlock = await generator.generateGenesisBlock({ assets }); + + expect(genesisBlock.assets['_assets'][0].moduleID).toEqual(2); + expect(genesisBlock.assets['_assets'][1].moduleID).toEqual(5); + expect(genesisBlock.header.validatorsHash).toEqual(validatorsHash); + expect(genesisBlock.header.assetsRoot).not.toBeUndefined(); + }); + + it('should set default value to height, previousBlockID and timestamp to the genesis block', async () => { + const genesisBlock = await generator.generateGenesisBlock({ assets }); + + expect(genesisBlock.header.previousBlockID).toEqual(Buffer.alloc(32, 0)); + expect(genesisBlock.header.timestamp).toBeGreaterThan(Math.floor(Date.now() / 1000) - 60000); + expect(genesisBlock.header.height).toEqual(0); + }); + }); + + describe('generateBlock', () => { let mod1: GeneratorModule; let mod2: GeneratorModule; @@ -477,7 +580,12 @@ describe('generator', () => { }); it('should call all hooks', async () => { - const block = await generator['_generateBlock'](generatorAddress, keypair, currentTime); + const block = await generator.generateBlock({ + generatorAddress, + timestamp: currentTime, + privateKey: keypair.privateKey, + height: 2, + }); expect(mod1.initBlock).toHaveBeenCalledTimes(1); expect(mod2.sealBlock).toHaveBeenCalledTimes(1); expect(stateMachine.beforeExecuteBlock).toHaveBeenCalledTimes(1); @@ -489,20 +597,36 @@ describe('generator', () => { }); it('should have finalizedHeight in the context', async () => { - await generator['_generateBlock'](generatorAddress, keypair, currentTime); + await generator.generateBlock({ + generatorAddress, + timestamp: currentTime, + privateKey: keypair.privateKey, + height: 2, + }); + expect((mod1.initBlock as jest.Mock).mock.calls[0][0].getFinalizedHeight()).toEqual(100); expect((mod2.sealBlock as jest.Mock).mock.calls[0][0].getFinalizedHeight()).toEqual(100); }); it('should assign validatorsHash to the block', async () => { - const block = await generator['_generateBlock'](generatorAddress, keypair, currentTime); + const block = await generator.generateBlock({ + generatorAddress, + timestamp: currentTime, + privateKey: keypair.privateKey, + height: 2, + }); expect(block.header.validatorsHash).toEqual(validatorsHash); }); it('should assign assetRoot to the block', async () => { jest.spyOn(BlockAssets.prototype, 'getRoot').mockResolvedValue(assetHash); - const block = await generator['_generateBlock'](generatorAddress, keypair, currentTime); + const block = await generator.generateBlock({ + generatorAddress, + timestamp: currentTime, + privateKey: keypair.privateKey, + height: 2, + }); expect(block.header.assetsRoot).toEqual(assetHash); }); diff --git a/framework/test/unit/node/node.spec.ts b/framework/test/unit/node/node.spec.ts index 1ac924007ee..080ed52c4d9 100644 --- a/framework/test/unit/node/node.spec.ts +++ b/framework/test/unit/node/node.spec.ts @@ -13,9 +13,15 @@ * Removal or modification of this copyright notice is prohibited. */ import { InMemoryKVStore, KVStore } from '@liskhq/lisk-db'; +import { + generatePrivateKey, + getPublicKeyFromPrivateKey, + getRandomBytes, + blsPopProve, + getAddressAndPublicKeyFromPassphrase, +} from '@liskhq/lisk-cryptography'; import { Node } from '../../../src/node/node'; import { nodeOptions } from '../../fixtures/node'; -import { createGenesisBlock } from '../../../src/testing/create_genesis_block'; import { InMemoryChannel } from '../../../src/controller'; import { fakeLogger } from '../../utils/node'; import { BaseAPI, BaseCommand, BaseEndpoint, BaseModule } from '../../../src'; @@ -24,8 +30,10 @@ import { CONSENSUS_EVENT_BLOCK_DELETE, CONSENSUS_EVENT_BLOCK_NEW, } from '../../../src/node/consensus'; +import { BFTAPI } from '../../../src/modules/bft'; +import { GenesisBlockExecuteContext } from '../../../src/node/state_machine'; +import { ValidatorsAPI } from '../../../src/modules/validators'; -jest.mock('@liskhq/lisk-db'); jest.mock('fs-extra'); class SampleEndpoint extends BaseEndpoint { @@ -38,7 +46,32 @@ class SampleNodeModule extends BaseModule { public id = 1000; public name = 'sample'; + private _bftAPI!: BFTAPI; + private _validatorAPI!: ValidatorsAPI; + public async init(_args: ModuleInitArgs): Promise {} + + public addDependencies(bftAPI: BFTAPI, validatorAPI: ValidatorsAPI) { + this._bftAPI = bftAPI; + this._validatorAPI = validatorAPI; + } + + public async afterGenesisBlockExecute(context: GenesisBlockExecuteContext): Promise { + const keys = getAddressAndPublicKeyFromPassphrase('passphrase'); + const blsSK = generatePrivateKey(getRandomBytes(64)); + const blsPK = getPublicKeyFromPrivateKey(blsSK); + const blsPop = blsPopProve(blsSK); + await this._validatorAPI.registerValidatorKeys( + context.getAPIContext(), + keys.address, + blsPK, + keys.publicKey, + blsPop, + ); + await this._bftAPI.setBFTParameters(context.getAPIContext(), BigInt(68), BigInt(68), [ + { address: keys.address, bftWeight: BigInt(100) }, + ]); + } } describe('Node', () => { @@ -50,8 +83,6 @@ describe('Node', () => { let nodeDB: KVStore; let sampleNodeModule: SampleNodeModule; - const { genesisBlock } = createGenesisBlock({}); - beforeEach(() => { // Arrange subscribedEvents = {}; @@ -75,6 +106,7 @@ describe('Node', () => { options: nodeOptions, }); sampleNodeModule = new SampleNodeModule(); + sampleNodeModule.addDependencies(node.bftAPI, node.validatorAPI); node.registerModule(sampleNodeModule); }); @@ -108,6 +140,7 @@ describe('Node', () => { jest.spyOn(node['_consensus'], 'init'); jest.spyOn(node['_consensus'].events, 'on'); jest.spyOn(sampleNodeModule, 'init'); + const genesisBlock = await node.generateGenesisBlock({ assets: [] }); await node.init({ channel, blockchainDB, @@ -324,6 +357,7 @@ describe('Node', () => { jest.spyOn(node['_chain'], 'loadLastBlocks').mockResolvedValue(); jest.spyOn(node['_network'], 'start'); jest.spyOn(node['_generator'], 'start'); + const genesisBlock = await node.generateGenesisBlock({ assets: [] }); await node.init({ channel, blockchainDB, diff --git a/framework/test/unit/testing/create_block.spec.ts b/framework/test/unit/testing/create_block.spec.ts index 13d0ee23743..25de4fba62c 100644 --- a/framework/test/unit/testing/create_block.spec.ts +++ b/framework/test/unit/testing/create_block.spec.ts @@ -11,14 +11,14 @@ * * Removal or modification of this copyright notice is prohibited. */ -import { Block } from '@liskhq/lisk-chain'; +import { Block, BlockAssets } from '@liskhq/lisk-chain'; import { getNetworkIdentifier } from '@liskhq/lisk-cryptography'; import { createBlock } from '../../../src/testing/create_block'; import * as devnetConfig from '../../fixtures/config/devnet/config.json'; import * as devnetGenesisBlock from '../../fixtures/config/devnet/genesis_block.json'; -import { createGenesisBlock } from '../../../src/testing'; import { defaultConfig } from '../../../src/testing/fixtures/config'; +import { createFakeBlockHeader } from '../../fixtures'; describe('Create Block', () => { const networkIdentifier = getNetworkIdentifier( @@ -42,8 +42,7 @@ describe('Create Block', () => { let genesisBlock: Block; beforeAll(() => { - genesisBlock = createGenesisBlock({ timestamp: Math.floor(Date.now() / 1000 - 24 * 3600) }) - .genesisBlock; + genesisBlock = new Block(createFakeBlockHeader(), [], new BlockAssets()); }); it('should return a valid default block', async () => { diff --git a/framework/test/unit/testing/create_genesis_block.spec.ts b/framework/test/unit/testing/create_genesis_block.spec.ts deleted file mode 100644 index 1489710e498..00000000000 --- a/framework/test/unit/testing/create_genesis_block.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright © 2021 Lisk Foundation - * - * See the LICENSE file at the top-level directory of this distribution - * for licensing information. - * - * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, - * no part of this software, including this file, may be copied, modified, - * propagated, or distributed except according to the terms contained in the - * LICENSE file. - * - * Removal or modification of this copyright notice is prohibited. - */ - -describe('Create Genesis Block', () => { - it.todo('should return a valid genesis block'); -}); diff --git a/package.json b/package.json index e716642ebe4..fceb774100f 100644 --- a/package.json +++ b/package.json @@ -43,14 +43,14 @@ "clean:node_modules": "lerna clean --yes", "clean:full": "npm run clean:node_modules && rm -rf node_modules && yarn && yarn build", "format": "lerna run format", - "lint": "lerna run lint --ignore=@liskhq/lisk-genesis --ignore=lisk-elements --ignore=lisk-commander", + "lint": "lerna run lint --ignore=lisk-elements --ignore=lisk-commander", "lint:fix": "lerna run lint:fix", "test": "lerna run test", "test:elements": "lerna run test --ignore=lisk-commander --ignore=lisk-framework --ignore=lisk-sdk --ignore=@liskhq/lisk-framework*", "test:framework": "lerna run test --scope=lisk-framework", "test:framework-plugins": "lerna run test --scope=@liskhq/lisk-framework-*", "test:commander": "lerna run test --scope=lisk-commander", - "build": "lerna run build --ignore=@liskhq/lisk-genesis --ignore=lisk-commander", + "build": "lerna run build --ignore=lisk-commander", "init": "./scripts/init.sh", "prepare": "husky install", "postinstall": "husky install" diff --git a/sdk/package.json b/sdk/package.json index ef4ed2b8da8..26ad9411b26 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -34,7 +34,6 @@ "@liskhq/lisk-codec": "^0.2.1", "@liskhq/lisk-cryptography": "^3.2.0", "@liskhq/lisk-db": "^0.2.0", - "@liskhq/lisk-genesis": "^0.2.3", "@liskhq/lisk-p2p": "^0.7.2", "@liskhq/lisk-passphrase": "^3.1.0", "@liskhq/lisk-transaction-pool": "^0.5.1",