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

Create BlockProcessorV0 which handles the genesis block - Closes #5278 #5457

Merged
merged 28 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8c7f4e7
Merge branch 'development' into feature/new-genesis-integration
nazarhussain Jun 22, 2020
6666524
Add encoding/decoding test case for genesis block
nazarhussain Jun 22, 2020
8b3bb7b
Update the condition for application state to include genesis block h…
nazarhussain Jun 22, 2020
d6c9f2b
Remove applyGenesis pipeline from base block processor
nazarhussain Jun 22, 2020
3e17cb7
Remove applyGenesis step from block processor v2
nazarhussain Jun 22, 2020
e78a081
Update the check for isGenesis block in lisk-dpos
nazarhussain Jun 22, 2020
46b5a57
Update lisk-chain to load genesis block by id not by height
nazarhussain Jun 22, 2020
ff0c03f
Add get/set for registered delegates to lisk-dpos
nazarhussain Jun 22, 2020
75782dc
Update the check for isGenesis in lisk-chain
nazarhussain Jun 22, 2020
fbd63b2
Remove unused functions for genesis block in lisk-chain
nazarhussain Jun 22, 2020
9e1dfd7
Add block processor for version 0
nazarhussain Jun 22, 2020
ce297e1
Update block processor to run block processor for version 0
nazarhussain Jun 22, 2020
88b52b8
Update the occurences of the genesis block version
nazarhussain Jun 22, 2020
f148180
Fix framework unit tests
nazarhussain Jun 22, 2020
de1de92
Merge branch 'feature/new-genesis-integration' into 5278-genesis-bloc…
nazarhussain Jun 23, 2020
756cf0d
Fix lisk-dpos unit tests
nazarhussain Jun 23, 2020
808525c
Fix lisk-chain unit tests
nazarhussain Jun 23, 2020
c295a16
Update the code as per feedback
nazarhussain Jun 23, 2020
630465f
Fix feedback from deepscan
nazarhussain Jun 23, 2020
6903233
Fix block_synchronization tests
ishantiw Jun 23, 2020
89f825c
Fix default value for finalized height stored in bft
nazarhussain Jun 23, 2020
257a3dc
Fix tests for lisk-chain
nazarhussain Jun 23, 2020
399bff9
Fix genesis block parsing in framework
nazarhussain Jun 23, 2020
43eacf3
Fix functional and integration tests for framework
nazarhussain Jun 23, 2020
2273e14
Merge branch '5278-genesis-block-processor' of github.com:LiskHQ/lisk…
nazarhussain Jun 23, 2020
b8d00bb
Fix block synchronization mechanism unit tets
nazarhussain Jun 23, 2020
94dc214
Fix fast chain switching mechanism unit tets
nazarhussain Jun 23, 2020
f34f9d8
Update block processor v0 to fetch the delegate usernames in one loop
nazarhussain Jun 24, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions elements/lisk-chain/src/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { DataAccess } from './data_access';
import { Slots } from './slots';
import { StateStore } from './state_store';
import {
applyGenesisTransactions,
applyTransactions,
checkAllowedTransactions,
undoTransactions,
Expand Down Expand Up @@ -222,7 +221,9 @@ export class Chain {
// Check mem tables
let genesisBlock: BlockHeader;
try {
genesisBlock = await this.dataAccess.getBlockHeaderByHeight(1);
genesisBlock = await this.dataAccess.getBlockHeaderByID(
this.genesisBlock.header.id,
);
} catch (error) {
throw new Error('Failed to load genesis block');
}
Expand Down Expand Up @@ -253,7 +254,7 @@ export class Chain {

public async newStateStore(skipLastHeights = 0): Promise<StateStore> {
const fromHeight = Math.max(
1,
0,
this._lastBlock.header.height -
this.constants.stateBlockSize -
skipLastHeights,
Expand Down Expand Up @@ -363,15 +364,6 @@ export class Chain {
await applyFeeAndRewards(block, stateStore);
}

// eslint-disable-next-line class-methods-use-this
public async applyGenesis(
block: Block,
stateStore: StateStore,
): Promise<void> {
await applyGenesisTransactions(block.payload, stateStore);
await applyFeeAndRewards(block, stateStore);
}

public async save(
block: Block,
stateStore: StateStore,
Expand Down Expand Up @@ -533,7 +525,7 @@ export class Chain {
// Cache the block headers (size=DEFAULT_MAX_BLOCK_HEADER_CACHE)
const fromHeight = Math.max(
storageLastBlock.header.height - DEFAULT_MAX_BLOCK_HEADER_CACHE,
1,
0,
);
const toHeight = storageLastBlock.header.height;

Expand Down
1 change: 0 additions & 1 deletion elements/lisk-chain/src/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ export {
applyTransactions,
checkAllowedTransactions,
undoTransactions,
applyGenesisTransactions,
} from './transactions_handlers';
23 changes: 1 addition & 22 deletions elements/lisk-chain/src/transactions/transactions_handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,13 @@ import {
} from '@liskhq/lisk-transactions';

import { StateStore } from '../state_store';
import {
Contexter,
MatcherTransaction,
WriteableTransactionResponse,
} from '../types';
import { Contexter, MatcherTransaction } from '../types';

export const validateTransactions = (
transactions: ReadonlyArray<BaseTransaction>,
): ReadonlyArray<TransactionResponse> =>
transactions.map(transaction => transaction.validate());

export const applyGenesisTransactions = async (
transactions: ReadonlyArray<BaseTransaction>,
stateStore: StateStore,
): Promise<TransactionResponse[]> => {
const transactionsResponses: TransactionResponse[] = [];
for (const transaction of transactions) {
const transactionResponse = await transaction.apply(stateStore);

// We are overriding the status of transaction because it's from genesis block
(transactionResponse as WriteableTransactionResponse).status =
TransactionStatus.OK;
transactionsResponses.push(transactionResponse);
}

return transactionsResponses;
};

export const applyTransactions = async (
transactions: ReadonlyArray<BaseTransaction>,
stateStore: StateStore,
Expand Down
7 changes: 2 additions & 5 deletions elements/lisk-chain/src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,10 @@ export const validatePreviousBlockProperty = (
): void => {
const isGenesisBlock =
block.header.id.equals(genesisBlock.header.id) &&
block.header.previousBlockID.length === 0 &&
block.header.height === 1;
block.header.version === 0;
const propertyIsValid =
isGenesisBlock ||
(!block.header.id.equals(genesisBlock.header.id) &&
block.header.previousBlockID.length > 0 &&
block.header.height !== 1);
(block.header.previousBlockID.length > 0 && block.header.version !== 0);

if (!propertyIsValid) {
throw new Error('Invalid previous block');
Expand Down
2 changes: 1 addition & 1 deletion elements/lisk-dpos/src/delegates_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface DelegatesInfoConstructor {
readonly delegatesList: DelegatesList;
}

const _isGenesisBlock = (header: BlockHeader): boolean => header.height === 1;
const _isGenesisBlock = (header: BlockHeader): boolean => header.version === 0;
const zeroRandomSeed = Buffer.from('00000000000000000000000000000000', 'hex');
const maxConsecutiveMissedBlocks = 50;
const maxLastForgedHeightDiff = 260000;
Expand Down
46 changes: 45 additions & 1 deletion elements/lisk-dpos/src/dpos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { hash } from '@liskhq/lisk-cryptography';
import { codec } from '@liskhq/lisk-codec';
import * as Debug from 'debug';
import { EventEmitter } from 'events';
import { voteWeightsSchema } from './schemas';
import { delegatesUserNamesSchema, voteWeightsSchema } from './schemas';

import {
CHAIN_STATE_DELEGATE_USERNAMES,
CONSENSUS_STATE_DELEGATE_VOTE_WEIGHTS,
DEFAULT_ACTIVE_DELEGATE,
DEFAULT_ROUND_OFFSET,
Expand All @@ -40,6 +41,7 @@ import {
ForgersList,
StateStore,
DecodedVoteWeights,
DecodedUsernames,
} from './types';

interface DposConstructor {
Expand Down Expand Up @@ -112,6 +114,48 @@ export class Dpos {
return this.delegatesList.getDelegateList(round);
}

// eslint-disable-next-line class-methods-use-this
public async getRegisteredDelegates(
stateStore: StateStore,
): Promise<{ address: Buffer; username: string }[]> {
// Data format for the registered delegates
// chain:delegateUsernames => { registeredDelegates: { username, address }[] }
const usernamesBuffer = await stateStore.chain.get(
CHAIN_STATE_DELEGATE_USERNAMES,
);

if (usernamesBuffer) {
const parsedUsernames = codec.decode<DecodedUsernames>(
delegatesUserNamesSchema,
usernamesBuffer,
);

return parsedUsernames.registeredDelegates;
}

return [];
}

// eslint-disable-next-line @typescript-eslint/require-await,class-methods-use-this
public async setRegisteredDelegates(
stateStore: StateStore,
delegates: { address: Buffer; username: string }[],
): Promise<void> {
const updatingObject = {
registeredDelegates: delegates.map(value => ({
address: value.address,
username: value.username,
})),
};

const updatingObjectBinary = codec.encode(
delegatesUserNamesSchema,
updatingObject,
);

stateStore.chain.set(CHAIN_STATE_DELEGATE_USERNAMES, updatingObjectBinary);
}

public async onBlockFinalized(
stateStore: StateStore,
finalizedHeight: number,
Expand Down
1 change: 1 addition & 0 deletions elements/lisk-dpos/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface StateStore {

export interface BlockHeader {
readonly height: number;
readonly version: number;
readonly generatorPublicKey: Buffer;
readonly reward: bigint;
readonly timestamp: number;
Expand Down
4 changes: 2 additions & 2 deletions elements/lisk-genesis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"@liskhq/lisk-cryptography": "2.5.0-alpha.0",
"@liskhq/lisk-chain": "0.1.0-alpha.0",
"@liskhq/lisk-validator": "0.4.0-alpha.0",
"@liskhq/lisk-codec": "0.1.0"
"@liskhq/lisk-codec": "0.1.0",
"lodash.clonedeep": "4.5.0"
},
"devDependencies": {
"@types/node": "12.12.11",
Expand All @@ -55,7 +56,6 @@
"jest": "25.1.0",
"jest-extended": "0.11.5",
"jest-when": "2.7.0",
"lodash.clonedeep": "4.5.0",
"prettier": "1.19.1",
"source-map-support": "0.5.16",
"ts-jest": "25.2.1",
Expand Down
2 changes: 1 addition & 1 deletion elements/lisk-genesis/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ 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_PAYLOAD: Buffer[] = [];
export const GENESIS_BLOCK_PAYLOAD = [];
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);
58 changes: 41 additions & 17 deletions elements/lisk-genesis/src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
*/

import { codec, Schema } from '@liskhq/lisk-codec';
import { Account } from '@liskhq/lisk-chain';
import { hash } from '@liskhq/lisk-cryptography';
import { LiskValidationError } from '@liskhq/lisk-validator';
import {
Expand All @@ -26,10 +25,12 @@ import {
GENESIS_BLOCK_VERSION,
} from './constants';
import {
DefaultAccountAsset,
GenesisAccountState,
GenesisBlock,
GenesisBlockHeaderWithoutId,
GenesisBlockParams,
PartialReq,
} from './types';
import { validateGenesisBlock } from './validate';
import {
Expand All @@ -39,8 +40,11 @@ import {
} from './schema';
import { getHeaderAssetSchemaWithAccountAsset } from './utils/schema';

const getBlockId = (
header: GenesisBlockHeaderWithoutId,
// eslint-disable-next-line @typescript-eslint/no-require-imports
import cloneDeep = require('lodash.clonedeep');

const getBlockId = <T>(
header: GenesisBlockHeaderWithoutId<T>,
accountAssetSchema: Schema,
): Buffer => {
// eslint-disable-next-line
Expand All @@ -60,9 +64,34 @@ const getBlockId = (
return hash(genesisBlockHeaderBuffer);
};

export const createGenesisBlock = (
params: GenesisBlockParams,
): GenesisBlock => {
const createAccount = <T>(
account: PartialReq<GenesisAccountState<T>, 'address'>,
): GenesisAccountState<T> => ({
address: account.address,
publicKey: account.publicKey ?? Buffer.alloc(0),
balance: account.balance ?? BigInt(0),
nonce: account.nonce ?? BigInt(0),
keys: account.keys
? {
mandatoryKeys: [
...account.keys.mandatoryKeys.sort((a, b) => a.compare(b)),
],
optionalKeys: [
...account.keys.optionalKeys.sort((a, b) => a.compare(b)),
],
numberOfSignatures: account.keys.numberOfSignatures,
}
: {
mandatoryKeys: [],
optionalKeys: [],
numberOfSignatures: 0,
},
asset: account.asset ? cloneDeep(account.asset) : ({} as T),
});

export const createGenesisBlock = <T = DefaultAccountAsset>(
params: GenesisBlockParams<T>,
): GenesisBlock<T> => {
// Default values
const initRounds = params.initRounds ?? 3;
const height = params.height ?? 0;
Expand All @@ -79,20 +108,15 @@ export const createGenesisBlock = (
const signature = GENESIS_BLOCK_SIGNATURE;
const transactionRoot = GENESIS_BLOCK_TRANSACTION_ROOT;

const accounts: ReadonlyArray<GenesisAccountState> = params.accounts
.map(acc => new Account(acc))
const accounts: ReadonlyArray<GenesisAccountState<T>> = params.accounts
.map(createAccount)
.sort((a, b): number => a.address.compare(b.address));

for (const account of accounts) {
account.keys.mandatoryKeys.sort((a, b) => a.compare(b));
account.keys.optionalKeys.sort((a, b) => a.compare(b));
}

const initDelegates: ReadonlyArray<Buffer> = [
...params.initDelegates,
].sort((a, b): number => a.compare(b));

const header: GenesisBlockHeaderWithoutId = {
const header: GenesisBlockHeaderWithoutId<T> = {
generatorPublicKey,
height,
previousBlockID,
Expand All @@ -116,12 +140,12 @@ export const createGenesisBlock = (
throw new LiskValidationError(errors);
}

const genesisBlock: GenesisBlock = {
const genesisBlock: GenesisBlock<T> = {
header: {
...header,
id: getBlockId(header, accountAssetSchema),
id: getBlockId<T>(header, accountAssetSchema),
},
payload,
payload: [],
};

return genesisBlock;
Expand Down
43 changes: 32 additions & 11 deletions elements/lisk-genesis/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,50 @@
* Removal or modification of this copyright notice is prohibited.
*/

import { Account, BlockHeader } from '@liskhq/lisk-chain';
import { BlockHeader } from '@liskhq/lisk-chain';
import { Schema } from '@liskhq/lisk-codec';

export type GenesisAccountState = Account;
export type PartialReq<T, Keys extends keyof T = keyof T> = Pick<
Partial<T>,
Exclude<keyof T, Keys>
> &
{
[K in Keys]: T[K];
};

export interface GenesisBlockHeaderAsset {
readonly accounts: ReadonlyArray<GenesisAccountState>;
export interface GenesisAccountState<T> {
readonly address: Buffer;
readonly balance: bigint;
readonly publicKey: Buffer;
readonly nonce: bigint;
readonly keys: {
mandatoryKeys: Buffer[];
optionalKeys: Buffer[];
numberOfSignatures: number;
};
readonly asset: T;
}

export interface GenesisBlockHeaderAsset<T> {
readonly accounts: ReadonlyArray<GenesisAccountState<T>>;
readonly initDelegates: ReadonlyArray<Buffer>;
readonly initRounds: number;
}

export type GenesisBlockHeader = BlockHeader<GenesisBlockHeaderAsset>;
export type GenesisBlockHeader<T> = BlockHeader<GenesisBlockHeaderAsset<T>>;

export type GenesisBlockHeaderWithoutId = Omit<GenesisBlockHeader, 'id'>;
export type GenesisBlockHeaderWithoutId<T> = Omit<GenesisBlockHeader<T>, 'id'>;

export interface GenesisBlock {
readonly header: GenesisBlockHeader;
readonly payload: Buffer[];
export interface GenesisBlock<T> {
readonly header: GenesisBlockHeader<T>;
readonly payload: [];
}

export interface GenesisBlockParams {
export interface GenesisBlockParams<T> {
// List of accounts in the genesis
readonly accounts: ReadonlyArray<Partial<GenesisAccountState>>;
readonly accounts: ReadonlyArray<
PartialReq<GenesisAccountState<T>, 'address'>
>;
// List fo initial delegate addresses used during the bootstrap period to forge blocks
readonly initDelegates: ReadonlyArray<Buffer>;
// Number of blocks per round
Expand Down
Loading