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

Commit

Permalink
Merge pull request #5469 from LiskHQ/5281-update_dpos_bft_genesis_han…
Browse files Browse the repository at this point in the history
…dling

Add genesis block and bootstrap handling for dpos and bft - Closes #5281 and #5282
  • Loading branch information
shuse2 authored Jun 29, 2020
2 parents b6df9db + 367c8e5 commit b9c3d7d
Show file tree
Hide file tree
Showing 36 changed files with 3,522 additions and 3,231 deletions.
23 changes: 7 additions & 16 deletions elements/lisk-bft/src/bft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { codec } from '@liskhq/lisk-codec';
import * as assert from 'assert';
import { EventEmitter } from 'events';

import { BFT_MIGRATION_ROUND_OFFSET } from './constant';
import {
EVENT_BFT_FINALIZED_HEIGHT_CHANGED,
FinalityManager,
Expand Down Expand Up @@ -55,7 +54,7 @@ codec.addSchema(BFTFinalizedHeightCodecSchema);
export class BFT extends EventEmitter {
public readonly constants: {
activeDelegates: number;
startingHeight: number;
genesisHeight: number;
};

private _finalityManager?: FinalityManager;
Expand All @@ -66,19 +65,19 @@ export class BFT extends EventEmitter {
chain,
dpos,
activeDelegates,
startingHeight,
genesisHeight,
}: {
readonly chain: Chain;
readonly dpos: DPoS;
readonly activeDelegates: number;
readonly startingHeight: number;
readonly genesisHeight: number;
}) {
super();
this._chain = chain;
this._dpos = dpos;
this.constants = {
activeDelegates,
startingHeight,
genesisHeight,
};
}

Expand Down Expand Up @@ -225,23 +224,15 @@ export class BFT extends EventEmitter {
CONSENSUS_STATE_FINALIZED_HEIGHT_KEY,
);

const finalizedHeightStored =
// Choose max between stored finalized height or genesis height
const finalizedHeight =
storedFinalizedHeightBuffer === undefined
? 0
? this.constants.genesisHeight
: codec.decode<BFTPersistedValues>(
BFTFinalizedHeightCodecSchema,
storedFinalizedHeightBuffer,
).finalizedHeight;

/* Check BFT migration height
https://github.com/LiskHQ/lips/blob/master/proposals/lip-0014.md#backwards-compatibility */
const bftMigrationHeight =
this.constants.startingHeight -
this.constants.activeDelegates * BFT_MIGRATION_ROUND_OFFSET;

// Choose max between stored finalized height or migration height
const finalizedHeight = Math.max(finalizedHeightStored, bftMigrationHeight);

// Initialize consensus manager
return new FinalityManager({
dpos: this._dpos,
Expand Down
1 change: 0 additions & 1 deletion elements/lisk-bft/src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@
*/

export const BFT_ROUND_THRESHOLD = 3;
export const BFT_MIGRATION_ROUND_OFFSET = 2;
6 changes: 6 additions & 0 deletions elements/lisk-bft/src/finality_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ export class FinalityManager extends EventEmitter {
bftBlockHeaders: ReadonlyArray<BlockHeader>,
): Promise<boolean> {
debug('updatePreVotesPreCommits invoked');

// If the block is in the bootstrap period, it does not have vote weight
if (this._dpos.isBootstrapPeriod(header.height)) {
return false;
}

// If delegate forged a block with higher or same height previously
// That means he is forging on other chain and we don't count any
// Pre-votes and pre-commits from him
Expand Down
1 change: 1 addition & 0 deletions elements/lisk-bft/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface DPoS {
height: number,
stateStore: StateStore,
): Promise<boolean>;
isBootstrapPeriod(height: number): boolean;
}

export interface Chain {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('FinalityManager', () => {
let dposStub: {
getMinActiveHeight: jest.Mock;
isStandbyDelegate: jest.Mock;
isBootstrapPeriod: jest.Mock;
};
let stateStore: StateStoreMock;

Expand All @@ -80,6 +81,7 @@ describe('FinalityManager', () => {
dposStub = {
getMinActiveHeight: jest.fn(),
isStandbyDelegate: jest.fn(),
isBootstrapPeriod: jest.fn().mockReturnValue(false),
};

finalityManager = new FinalityManager({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const constants = {
describe('bft', () => {
describe('forkChoice', () => {
let activeDelegates;
let startingHeight;
let genesisHeight;
let bftParams;
let bftInstance: BFT;

Expand All @@ -36,6 +36,7 @@ describe('bft', () => {
let dposStub: {
getMinActiveHeight: jest.Mock;
isStandbyDelegate: jest.Mock;
isBootstrapPeriod: jest.Mock;
};

beforeEach(() => {
Expand All @@ -49,16 +50,17 @@ describe('bft', () => {
dposStub = {
getMinActiveHeight: jest.fn(),
isStandbyDelegate: jest.fn(),
isBootstrapPeriod: jest.fn().mockReturnValue(false),
};

activeDelegates = 101;
startingHeight = 0;
genesisHeight = 0;

bftParams = {
chain: chainStub,
dpos: dposStub,
activeDelegates,
startingHeight,
genesisHeight,
};

bftInstance = new BFT(bftParams);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ describe('FinalityManager', () => {
let dposStub: {
getMinActiveHeight: jest.Mock;
isStandbyDelegate: jest.Mock;
isBootstrapPeriod: jest.Mock;
};
let stateStore: StateStoreMock;

beforeEach(() => {
dposStub = {
getMinActiveHeight: jest.fn(),
isStandbyDelegate: jest.fn(),
isBootstrapPeriod: jest.fn().mockReturnValue(false),
};
stateStore = new StateStoreMock();
});
Expand Down
12 changes: 7 additions & 5 deletions elements/lisk-bft/test/unit/bft.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ const generateBlocks = ({
describe('bft', () => {
describe('BFT', () => {
let activeDelegates: number;
let startingHeight: number;
let genesisHeight: number;
let bftParams: {
readonly chain: Chain;
readonly dpos: DPoS;
readonly activeDelegates: number;
readonly startingHeight: number;
readonly genesisHeight: number;
};

let chainStub: {
Expand All @@ -75,6 +75,7 @@ describe('bft', () => {
let dposStub: {
getMinActiveHeight: jest.Mock;
isStandbyDelegate: jest.Mock;
isBootstrapPeriod: jest.Mock;
};
let lastBlock: BlockHeader;

Expand All @@ -91,14 +92,15 @@ describe('bft', () => {
dposStub = {
getMinActiveHeight: jest.fn(),
isStandbyDelegate: jest.fn(),
isBootstrapPeriod: jest.fn().mockReturnValue(false),
};
activeDelegates = 101;
startingHeight = 0;
genesisHeight = 0;
bftParams = {
chain: chainStub,
dpos: dposStub,
activeDelegates,
startingHeight,
genesisHeight,
};
});

Expand All @@ -113,7 +115,7 @@ describe('bft', () => {
expect(bft.finalityManager).toBeUndefined();
expect((bft as any)._chain).toBe(chainStub);
expect((bft as any)._dpos).toBe(dposStub);
expect(bft.constants).toEqual({ activeDelegates, startingHeight });
expect(bft.constants).toEqual({ activeDelegates, genesisHeight });
});
});

Expand Down
33 changes: 33 additions & 0 deletions elements/lisk-bft/test/unit/finality_manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@ describe('finality_manager', () => {
let dposStub: {
getMinActiveHeight: jest.Mock;
isStandbyDelegate: jest.Mock;
isBootstrapPeriod: jest.Mock;
};

beforeEach(() => {
dposStub = {
getMinActiveHeight: jest.fn(),
isStandbyDelegate: jest.fn(),
isBootstrapPeriod: jest.fn().mockReturnValue(false),
};

finalityManager = new FinalityManager({
Expand Down Expand Up @@ -301,6 +303,37 @@ describe('finality_manager', () => {
);
});

it('should not update prevotes and precommits in case of within bootstrap period', async () => {
const header1 = createFakeBlockHeader({
height: 2,
asset: {
maxHeightPreviouslyForged: 0,
},
});

dposStub.isBootstrapPeriod.mockResolvedValue(true);
jest.spyOn(finalityManager, 'updatePreVotesPreCommits');
await finalityManager.addBlockHeader(header1, stateStore);

expect(finalityManager.updatePreVotesPreCommits).toHaveBeenCalledTimes(
1,
);
expect(finalityManager.updatePreVotesPreCommits).toHaveBeenCalledWith(
header1,
stateStore,
bftHeaders,
);

// Ignores a standby delegate from prevotes and precommit calculations
await expect(
finalityManager.updatePreVotesPreCommits(
header1,
stateStore,
bftHeaders,
),
).resolves.toEqual(false);
});

it('should not update prevotes and precommits in case of a standby delegate', async () => {
const header1 = createFakeBlockHeader({
height: 2,
Expand Down
Loading

0 comments on commit b9c3d7d

Please sign in to comment.