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

Commit 930492c

Browse files
authored
Add missing unit tests for certificate generation and commit pool (#9145)
* Added missing tests and updated commit pool and certificate unit tests * Update tests --------- Co-authored-by: Mitsuaki Uchimoto <[email protected]>
1 parent 8c7aba6 commit 930492c

File tree

2 files changed

+129
-20
lines changed

2 files changed

+129
-20
lines changed

Diff for: framework/test/unit/engine/consensus/certificate_generation/commit_pool.spec.ts

+116-20
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,7 @@ describe('CommitPool', () => {
100100
});
101101
});
102102

103-
describe('constructor', () => {
104-
it.todo('');
105-
});
106-
107-
describe('job', () => {
103+
describe('_job', () => {
108104
const dbMock = {
109105
get: jest.fn(),
110106
put: jest.fn(),
@@ -158,9 +154,7 @@ describe('CommitPool', () => {
158154

159155
gossipedCommits.forEach(commit => commitPool['_gossipedCommits'].add(commit));
160156
commitPool['_gossipedCommits'].add(staleGossipedCommit);
161-
// commitPool['_gossipedCommits'].set(staleGossipedCommit.height, [staleGossipedCommit]);
162157
nonGossipedCommits.forEach(commit => commitPool['_nonGossipedCommits'].add(commit));
163-
// commitPool['_nonGossipedCommits'].set(height, nonGossipedCommits);
164158
commitPool['_nonGossipedCommits'].add(staleNonGossipedCommit);
165159
(commitPool['_chain'] as any).finalizedHeight = maxHeightCertified;
166160

@@ -204,7 +198,7 @@ describe('CommitPool', () => {
204198
expect(commitPool['_gossipedCommits'].exists(staleGossipedCommit)).toBeFalse();
205199
});
206200

207-
it('should clean all the commits from nonGossipedCommit that does not have bftParams change and height is in the future', async () => {
201+
it('should clean all the commits from nonGossipedCommit that does not have bftParams change and in the future height', async () => {
208202
// Update current height so that commits will always be in the future
209203
chain.lastBlock = { header: { height: 1019 } };
210204
// it should not be deleted by the height
@@ -241,7 +235,93 @@ describe('CommitPool', () => {
241235
expect(commitPool['_gossipedCommits'].getByHeight(1070)).toBeArrayOfSize(0);
242236
});
243237

244-
it('should select non gossiped commits that are created by the generator of the engine', async () => {
238+
it(`should not clean commits for the heights ${maxHeightPrecommitted} - ${COMMIT_RANGE_STORED} until currentHeight and bftParams does not exist for height`, async () => {
239+
const testHeight = maxHeightPrecommitted - COMMIT_RANGE_STORED;
240+
// // Update current height so that commits will always be in the future
241+
chain.lastBlock = { header: { height: maxHeightPrecommitted + 19 } };
242+
243+
// it should not be deleted by the height
244+
commitPool['_nonGossipedCommits'].add({
245+
blockID: utils.getRandomBytes(32),
246+
certificateSignature: utils.getRandomBytes(96),
247+
height: testHeight,
248+
validatorAddress: utils.getRandomBytes(20),
249+
});
250+
commitPool['_gossipedCommits'].add({
251+
blockID: utils.getRandomBytes(32),
252+
certificateSignature: utils.getRandomBytes(96),
253+
height: testHeight,
254+
validatorAddress: utils.getRandomBytes(20),
255+
});
256+
// Assert
257+
expect(commitPool['_nonGossipedCommits'].getAll()).toHaveLength(7);
258+
// Arrange
259+
const bftParamsMock = jest.fn();
260+
commitPool['_bftMethod'].existBFTParameters = bftParamsMock;
261+
const context = new StateStore(new InMemoryDatabase());
262+
commitPool['_bftMethod'].getBFTHeights = jest
263+
.fn()
264+
.mockResolvedValue({ maxHeightPrecommitted });
265+
when(bftParamsMock).calledWith(context, 1071).mockResolvedValue(false);
266+
when(bftParamsMock).calledWith(context, maxHeightCertified).mockResolvedValue(true);
267+
when(bftParamsMock)
268+
.calledWith(context, height + 1)
269+
.mockResolvedValue(true);
270+
// Act
271+
await commitPool['_job'](context);
272+
// Assert
273+
// nonGossiped commits are moved to gossiped commits after posting to network
274+
expect(commitPool['_nonGossipedCommits'].getAll()).toHaveLength(0);
275+
expect(commitPool['_gossipedCommits'].getAll()).toHaveLength(10);
276+
});
277+
278+
it(`should not clean commits for the heights lower than ${maxHeightPrecommitted} - ${COMMIT_RANGE_STORED} until currentHeight and bftParams does not exist for height`, async () => {
279+
const testHeight = maxHeightPrecommitted - COMMIT_RANGE_STORED - 1;
280+
// // Update current height so that commits will always be in the future
281+
chain.lastBlock = { header: { height: maxHeightPrecommitted + 19 } };
282+
283+
// it should not be deleted by the height
284+
commitPool['_nonGossipedCommits'].add({
285+
blockID: utils.getRandomBytes(32),
286+
certificateSignature: utils.getRandomBytes(96),
287+
height: testHeight,
288+
validatorAddress: utils.getRandomBytes(20),
289+
});
290+
commitPool['_nonGossipedCommits'].add({
291+
blockID: utils.getRandomBytes(32),
292+
certificateSignature: utils.getRandomBytes(96),
293+
height: maxHeightPrecommitted - 1,
294+
validatorAddress: utils.getRandomBytes(20),
295+
});
296+
commitPool['_gossipedCommits'].add({
297+
blockID: utils.getRandomBytes(32),
298+
certificateSignature: utils.getRandomBytes(96),
299+
height: testHeight,
300+
validatorAddress: utils.getRandomBytes(20),
301+
});
302+
// Assert
303+
expect(commitPool['_nonGossipedCommits'].getAll()).toHaveLength(8);
304+
// Arrange
305+
const bftParamsMock = jest.fn();
306+
commitPool['_bftMethod'].existBFTParameters = bftParamsMock;
307+
const context = new StateStore(new InMemoryDatabase());
308+
commitPool['_bftMethod'].getBFTHeights = jest
309+
.fn()
310+
.mockResolvedValue({ maxHeightPrecommitted });
311+
when(bftParamsMock).calledWith(context, 1071).mockResolvedValue(false);
312+
when(bftParamsMock).calledWith(context, maxHeightCertified).mockResolvedValue(true);
313+
when(bftParamsMock)
314+
.calledWith(context, height + 1)
315+
.mockResolvedValue(false);
316+
// Act
317+
await commitPool['_job'](context);
318+
// Assert
319+
// nonGossiped commits at maxHeightPrecommitted - 1 is not deleted and broadcasted and moved to gossiped commits
320+
expect(commitPool['_nonGossipedCommits'].getAll()).toHaveLength(0);
321+
expect(commitPool['_gossipedCommits'].getAll()).toHaveLength(1);
322+
});
323+
324+
it('should select non gossiped local commits', async () => {
245325
// Arrange
246326
const generatorAddress = utils.getRandomBytes(20);
247327
commitPool.addCommit(
@@ -968,7 +1048,7 @@ describe('CommitPool', () => {
9681048
expect(isCommitVerified).toBeTrue();
9691049
});
9701050

971-
it('should return false when aggregate commit is not signed at height maxHeightCertified', async () => {
1051+
it('should return false when aggregate commit <= maxHeightCertified', async () => {
9721052
bftMethod.getBFTHeights.mockReturnValue({
9731053
maxHeightCertified: 1080,
9741054
maxHeightPrecommitted: 1100,
@@ -1003,6 +1083,30 @@ describe('CommitPool', () => {
10031083
expect(isCommitVerified).toBeFalse();
10041084
});
10051085

1086+
it('should return true when aggregationBits empty and certificateSignature is empty and aggregateCommit.height === getBFTHeights().maxHeightCertified', async () => {
1087+
aggregateCommit = {
1088+
aggregationBits: Buffer.alloc(0),
1089+
certificateSignature: Buffer.alloc(0),
1090+
height: maxHeightCertified,
1091+
};
1092+
1093+
const isCommitVerified = await commitPool.verifyAggregateCommit(stateStore, aggregateCommit);
1094+
1095+
expect(isCommitVerified).toBeTrue();
1096+
});
1097+
1098+
it('should return false when aggregationBits empty and certificateSignature is empty and aggregateCommit.height != getBFTHeights().maxHeightCertified', async () => {
1099+
aggregateCommit = {
1100+
aggregationBits: Buffer.alloc(0),
1101+
certificateSignature: Buffer.alloc(0),
1102+
height: maxHeightCertified - 1,
1103+
};
1104+
1105+
const isCommitVerified = await commitPool.verifyAggregateCommit(stateStore, aggregateCommit);
1106+
1107+
expect(isCommitVerified).toBeFalse();
1108+
});
1109+
10061110
it('should return false when aggregateCommit height is lesser than equal to maxHeightCertified', async () => {
10071111
aggregateCommit = {
10081112
aggregationBits,
@@ -1058,19 +1162,15 @@ describe('CommitPool', () => {
10581162
});
10591163
});
10601164

1061-
describe('getAggregateCommit', () => {
1062-
it.todo('');
1063-
});
1064-
1065-
describe('getMaxRemovalHeight', () => {
1165+
describe('_getMaxRemovalHeight', () => {
10661166
let blockHeader: BlockHeader;
10671167
const finalizedHeight = 1010;
10681168

10691169
beforeEach(() => {
10701170
chain.finalizedHeight = finalizedHeight;
10711171

10721172
blockHeader = createFakeBlockHeader({
1073-
height: finalizedHeight,
1173+
height: finalizedHeight - 1,
10741174
timestamp: finalizedHeight * 10,
10751175
aggregateCommit: {
10761176
aggregationBits: Buffer.alloc(0),
@@ -1136,10 +1236,6 @@ describe('CommitPool', () => {
11361236
});
11371237
});
11381238

1139-
describe('_aggregateSingleCommits', () => {
1140-
it.todo('');
1141-
});
1142-
11431239
describe('aggregateSingleCommits', () => {
11441240
const height = 45678;
11451241
const blockHeader1 = createFakeBlockHeader({ height });

Diff for: framework/test/unit/engine/consensus/certificate_generation/utils.spec.ts

+13
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,19 @@ describe('utils', () => {
217217
expect(isVerifiedSignature).toBeTrue();
218218
});
219219

220+
it('should return false for invalid certificate aggregationBits length', () => {
221+
signedCertificate.aggregationBits = Buffer.alloc(0);
222+
223+
const isVerifiedSignature = verifyAggregateCertificateSignature(
224+
validators,
225+
threshold,
226+
chainID,
227+
signedCertificate,
228+
);
229+
230+
expect(isVerifiedSignature).toBeFalse();
231+
});
232+
220233
it('should return false for one unmatching publicKey in keysList', () => {
221234
validators[102].blsKey = utils.getRandomBytes(BLS_PUBLIC_KEY_LENGTH);
222235

0 commit comments

Comments
 (0)