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

Fix poa_getAllValidators endpoint #8700

Merged
merged 7 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 18 additions & 10 deletions framework/src/modules/poa/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ import { ValidatorStore } from './stores/validator';
import { ModuleEndpointContext } from '../../types';
import { KEY_SNAPSHOT_0 } from './constants';
import { SnapshotStore } from './stores';
import { ValidatorEndpoint } from './types';
import { Validator } from './types';

export class PoAEndpoint extends BaseEndpoint {
private _authorityRegistrationFee!: bigint;

public init(authorityRegistrationFee: bigint) {
this._authorityRegistrationFee = authorityRegistrationFee;
}
public async getValidator(context: ModuleEndpointContext): Promise<ValidatorEndpoint> {

public async getValidator(context: ModuleEndpointContext): Promise<Validator> {
const validatorSubStore = this.stores.get(ValidatorStore);
const { address } = context.params;
if (typeof address !== 'string') {
Expand Down Expand Up @@ -67,32 +68,39 @@ export class PoAEndpoint extends BaseEndpoint {

public async getAllValidators(
context: ModuleEndpointContext,
): Promise<{ validators: ValidatorEndpoint[] }> {
): Promise<{ validators: Validator[] }> {
const validatorStore = this.stores.get(ValidatorStore);
const startBuf = Buffer.alloc(20);
const endBuf = Buffer.alloc(20, 255);
const validatorStoreData = await validatorStore.iterate(context, {
gte: startBuf,
lte: endBuf,
});

const snapshotStore = this.stores.get(SnapshotStore);
const currentRoundSnapshot = await snapshotStore.get(context, KEY_SNAPSHOT_0);
const response = [];

const validatorsData: Validator[] = [];
for (const data of validatorStoreData) {
const address = cryptoAddress.getLisk32AddressFromAddress(data.key);
const name = await validatorStore.get(context, data.key);
// `name` comes from type `ValidatorName`
const { name } = await validatorStore.get(context, data.key);
const activeValidator = currentRoundSnapshot.validators.find(
v => v.address.toString('hex') === address,
v => cryptoAddress.getLisk32AddressFromAddress(v.address) === address,
);
const validatorJSON = {
...name,

const validator: Validator = {
name,
address,
weight: activeValidator ? activeValidator.weight.toString() : '',
};
response.push(validatorJSON);
validatorsData.push(validator);
}

return { validators: response };
// This is needed since response from this endpoint is returning data in unexpected sorting order on next execution
// which can result in potential test/build failure
validatorsData.sort((v1, v2) => v1.name.localeCompare(v2.name, 'en'));
return { validators: validatorsData };
}

public getRegistrationFee(): { fee: string } {
Expand Down
2 changes: 1 addition & 1 deletion framework/src/modules/poa/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export interface UpdateGeneratorKeyParams {
generatorKey: Buffer;
}

export interface ValidatorEndpoint {
export interface Validator {
address: string;
name: string;
weight: string;
Expand Down
38 changes: 31 additions & 7 deletions framework/test/unit/modules/poa/endpoint.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('PoAModuleEndpoint', () => {
},
{
address: address2,
weight: BigInt(1),
weight: BigInt(2),
},
],
};
Expand Down Expand Up @@ -132,12 +132,12 @@ describe('PoAModuleEndpoint', () => {
await validatorStore.set(createStoreGetter(stateStore), address2, { name: 'validator2' });
await snapshotStore.set(createStoreGetter(stateStore), KEY_SNAPSHOT_0, snapshot);

const { validators: validatorsDataReturned } = await poaEndpoint.getAllValidators(
const { validators } = await poaEndpoint.getAllValidators(
createTransientModuleEndpointContext({ stateStore }),
);

expect(addresses).toContain(validatorsDataReturned[0].address);
expect(addresses).toContain(validatorsDataReturned[1].address);
expect(addresses).toContain(validators[0].address);
expect(addresses).toContain(validators[1].address);
});

it('should return valid JSON output', async () => {
Expand All @@ -147,12 +147,36 @@ describe('PoAModuleEndpoint', () => {
await validatorStore.set(createStoreGetter(stateStore), address2, { name: 'validator2' });
await snapshotStore.set(createStoreGetter(stateStore), KEY_SNAPSHOT_0, snapshot);

const { validators: validatorsDataReturned } = await poaEndpoint.getAllValidators(
const { validators } = await poaEndpoint.getAllValidators(
createTransientModuleEndpointContext({ stateStore }),
);

// Here we are checking against name sorted values from endpoint
expect(validators[0].weight).toBe(snapshot.validators[0].weight.toString());
expect(validators[1].weight).toBe(snapshot.validators[1].weight.toString());
});

it('should return json with empty weight for non active validator', async () => {
await validatorStore.set(createStoreGetter(stateStore), address1, { name: 'validator1' });
await validatorStore.set(createStoreGetter(stateStore), address2, { name: 'validator2' });
const currentSnapshot = {
threshold: BigInt(2),
validators: [
{
address: address1,
weight: BigInt(1),
},
],
};
await snapshotStore.set(createStoreGetter(stateStore), KEY_SNAPSHOT_0, currentSnapshot);

const { validators } = await poaEndpoint.getAllValidators(
createTransientModuleEndpointContext({ stateStore }),
);

expect(validatorsDataReturned[0].weight).toBeString();
expect(validatorsDataReturned[1].weight).toBeString();
// Checking against name-sorted values
expect(validators[0].weight).toBe(currentSnapshot.validators[0].weight.toString());
expect(validators[1].weight).toBe('');
});
});

Expand Down