Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core-api): add active delegates endpoint #2205

Merged
merged 7 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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
19 changes: 19 additions & 0 deletions __tests__/integration/core-api/v2/handlers/delegates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,25 @@ describe("API 2.0 - Delegates", () => {
);
});

describe("GET /delegates/active", () => {
describe.each([["API-Version", "request"], ["Accept", "requestWithAcceptHeader"]])(
"using the %s header",
(header, request) => {
it("should GET all the active delegates at a specified height", async () => {
const activeDelegates = app.getConfig().getMilestone(1).activeDelegates;

const response = await utils[request]("GET", "delegates/active", { height: 1 });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArray();
expect(response.data.data).toHaveLength(activeDelegates);

response.data.data.forEach(utils.expectDelegate);
expect(response.data.data.sort((a, b) => a.rank < b.rank)).toEqual(response.data.data);
});
},
);
});

describe("GET /delegates/:id", () => {
describe.each([["API-Version", "request"], ["Accept", "requestWithAcceptHeader"]])(
"using the %s header",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,10 +405,7 @@ describe("Delegate Repository", () => {

expect(results).toBeArray();
expect(results[0].username).toBeString();
expect(results[0].approval).toBeNumber();
expect(results[0].productivity).toBeNumber();
expect(results[0].approval).toBe(delegateCalculator.calculateApproval(delegate, height));
expect(results[0].productivity).toBe(delegateCalculator.calculateProductivity(delegate));
expect(results[0].username).toEqual(delegate.username);
});
});
});
11 changes: 11 additions & 0 deletions packages/core-api/src/versions/2/delegates/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ export class DelegatesController extends Controller {
}
}

public async active(request: Hapi.Request, h: Hapi.ResponseToolkit) {
try {
// @ts-ignore
const data = await request.server.methods.v2.delegates.active(request);

return super.respondWithCache(data, h);
} catch (error) {
return Boom.badImplementation(error);
}
}

public async show(request: Hapi.Request, h: Hapi.ResponseToolkit) {
try {
// @ts-ignore
Expand Down
18 changes: 17 additions & 1 deletion packages/core-api/src/versions/2/delegates/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { orderBy } from "@arkecosystem/utils";
import Boom from "boom";
import { blocksRepository } from "../../../repositories";
import { ServerCache } from "../../../services";
import { paginate, respondWithResource, toPagination } from "../utils";
import { paginate, respondWithResource, respondWithCollection, toPagination } from "../utils";

const config = app.getConfig();
const databaseService = app.resolvePlugin<Database.IDatabaseService>("database");

const index = async request => {
Expand All @@ -17,6 +18,16 @@ const index = async request => {
return toPagination(request, delegates, "delegate");
};

const active = async request => {
const delegates = await databaseService.delegates.getActiveAtHeight(request.query.height);
dated marked this conversation as resolved.
Show resolved Hide resolved

if (!delegates.length) {
return Boom.notFound("Delegates not found");
}

return respondWithCollection(request, delegates, "delegate");
};

const show = async request => {
const delegate = await databaseService.delegates.findById(request.params.id);

Expand Down Expand Up @@ -82,11 +93,16 @@ const voterBalances = async request => {
};

export function registerMethods(server) {
const { activeDelegates, blocktime } = config.getMilestone();

ServerCache.make(server)
.method("v2.delegates.index", index, 8, request => ({
...request.query,
...paginate(request),
}))
.method("v2.delegates.active", active, activeDelegates * blocktime, request => ({
...request.query
}))
.method("v2.delegates.show", show, 8, request => ({ id: request.params.id }))
.method("v2.delegates.search", search, 30, request => ({
...request.payload,
Expand Down
9 changes: 9 additions & 0 deletions packages/core-api/src/versions/2/delegates/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ export function registerRoutes(server: Hapi.Server): void {
},
});

server.route({
method: "GET",
path: "/delegates/active",
handler: controller.active,
options: {
validate: Schema.active,
},
});

server.route({
method: "GET",
path: "/delegates/{id}",
Expand Down
9 changes: 9 additions & 0 deletions packages/core-api/src/versions/2/delegates/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ export const index: object = {
},
};

export const active: object = {
query: {
height: Joi.number()
.integer()
.min(1)
.required(),
}
};

export const show: object = {
params: {
id: schemaIdentifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,7 @@ export class DelegatesBusinessRepository implements Database.IDelegatesBusinessR
const delegates = await this.databaseServiceProvider().getActiveDelegates(height);

return delegates.map(delegate => {
const wallet = this.databaseServiceProvider().wallets.findById(delegate.publicKey);

return {
username: wallet.username,
approval: delegateCalculator.calculateApproval(delegate, height),
productivity: delegateCalculator.calculateProductivity(wallet),
};
return this.databaseServiceProvider().wallets.findById(delegate.publicKey);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export interface IDelegatesBusinessRepository {

findById(id: string): models.Wallet;

getActiveAtHeight(height: number): Promise<Array<{ username: string; approval: number; productivity: number }>>;
getActiveAtHeight(height: number): Promise<models.Wallet[]>;
}
6 changes: 3 additions & 3 deletions packages/core-p2p/src/peer-verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ export class PeerVerifier {
// the last block in a round (so that the delegates calculations are still the same for
// both chains).

const delegates = await this.getDelegates(round);
const delegates = await this.getDelegatesByRound(round);

const hisBlocksByHeight = {};

Expand All @@ -324,10 +324,10 @@ export class PeerVerifier {

/**
* Get the delegates for the given round.
* @param {Object} round round to get delegates for
* @param {Object} round to get delegates for
* @return {Object} a map of { publicKey: delegate, ... } of all delegates for the given round
*/
private async getDelegates(round: any): Promise<any> {
private async getDelegatesByRound(round: any): Promise<any> {
const numDelegates = round.maxDelegates;

const heightOfFirstBlockInRound = (round.round - 1) * numDelegates + 1;
Expand Down