Skip to content

perf(dapi): cache getBestBlockHash endpoint #1867

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

Merged
merged 2 commits into from
May 30, 2024
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
19 changes: 17 additions & 2 deletions packages/dapi/lib/rpcServer/commands/getBestBlockHash.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
/**
* @param {Object} coreAPI
* @param {ZmqClient} coreZmqClient
* @return {getBestBlockHash}
*/
const getBestBlockHashFactory = (coreAPI) => {
const getBestBlockHashFactory = (coreAPI, coreZmqClient) => {
let hash = null;

// Reset height on a new block, so it will be obtain again on a user request
coreZmqClient.on(
coreZmqClient.topics.hashblock,
() => {
hash = null;
},
);

/**
* Layer 1 endpoint
* Returns block hash of the chaintip
* @typedef getBestBlockHash
* @return {Promise<string>} - latest block hash
*/
async function getBestBlockHash() {
return coreAPI.getBestBlockHash();
if (hash === null) {
hash = await coreAPI.getBestBlockHash();
}

return hash;
}

return getBestBlockHash;
Expand Down
13 changes: 6 additions & 7 deletions packages/dapi/lib/rpcServer/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ const getMnListDiff = require('./commands/getMnListDiff');
// Following commands are not implemented yet:
// const getVersion = require('./commands/getVersion');

const createCommands = (dashcoreAPI) => ({
getBestBlockHash: getBestBlockHash(dashcoreAPI),
const createCommands = (dashcoreAPI, coreZmqClient) => ({
getBestBlockHash: getBestBlockHash(dashcoreAPI, coreZmqClient),
getBlockHash: getBlockHash(dashcoreAPI),
getMnListDiff: getMnListDiff(dashcoreAPI),
});
Expand All @@ -18,20 +18,19 @@ const createCommands = (dashcoreAPI) => ({
* Starts RPC server
* @param options
* @param {number} options.port - port to listen for incoming RPC connections
* @param {string} options.networkType
* @param {object} options.dashcoreAPI
* @param {AbstractDriveAdapter} options.driveAPI - Drive api adapter
* @param {object} options.tendermintRpcClient
* @param {DashPlatformProtocol} options.dpp
* @param {object} options.log
* @param {Logger} options.logger
* @param {ZmqClient} options.coreZmqClient
*/
const start = ({
port,
dashcoreAPI,
logger,
coreZmqClient,
}) => {
const commands = createCommands(
dashcoreAPI,
coreZmqClient,
);
/*
Decorate all commands with decorator that will intercept errors and format
Expand Down
17 changes: 17 additions & 0 deletions packages/dapi/scripts/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const coreHandlersFactory = require(
const platformHandlersFactory = require(
'../lib/grpcServer/handlers/platform/platformHandlersFactory',
);
const ZmqClient = require('../lib/externalApis/dashcore/ZmqClient');

async function main() {
await loadWasmDpp();
Expand All @@ -53,6 +54,21 @@ async function main() {

const isProductionEnvironment = process.env.NODE_ENV === 'production';

// Subscribe to events from Dash Core
const coreZmqClient = new ZmqClient(config.dashcore.zmq.host, config.dashcore.zmq.port);

// Bind logs on ZMQ connection events
coreZmqClient.on(ZmqClient.events.DISCONNECTED, logger.warn.bind(logger));
coreZmqClient.on(ZmqClient.events.CONNECTION_DELAY, logger.warn.bind(logger));
coreZmqClient.on(ZmqClient.events.MONITOR_ERROR, logger.warn.bind(logger));

// Wait until zmq connection is established
logger.info(`Connecting to Core ZMQ on ${coreZmqClient.connectionString}`);

await coreZmqClient.start();

logger.info('Connection to ZMQ established.');

const driveClient = new PlatformPromiseClient(`http://${config.driveRpc.host}:${config.driveRpc.port}`, undefined);

const rpcClient = RpcClient.http({
Expand Down Expand Up @@ -108,6 +124,7 @@ async function main() {
port: config.rpcServer.port,
dashcoreAPI: dashCoreRpcClient,
logger,
coreZmqClient,
});
logger.info(`JSON RPC server is listening on port ${config.rpcServer.port}`);

Expand Down
36 changes: 15 additions & 21 deletions packages/dapi/test/unit/rpcServer/commands/getBestBlockHash.spec.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,32 @@
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const sinon = require('sinon');
const getBestBlockHashFactory = require('../../../../lib/rpcServer/commands/getBestBlockHash');
const coreAPIFixture = require('../../../mocks/coreAPIFixture');

chai.use(chaiAsPromised);

const { expect } = chai;
let spy;

describe('getBestBlockHash', () => {
describe('#factory', () => {
it('should return a function', () => {
const getBestBlockHash = getBestBlockHashFactory(coreAPIFixture);
expect(getBestBlockHash).to.be.a('function');
});
});
let getBestBlockHash;
let coreRPCClientMock;
let zmqClientMock;
let blockHash;

before(() => {
spy = sinon.spy(coreAPIFixture, 'getBestBlockHash');
});
beforeEach(function beforeEach() {
blockHash = '000000000074fc08fb6a92cb8994b14307038261e4266abc6994fa03955a1a59';

beforeEach(() => {
spy.resetHistory();
});
coreRPCClientMock = {
getBestBlockHash: this.sinon.stub().resolves(blockHash),
};

zmqClientMock = { on: this.sinon.stub(), topics: { hashblock: 'fake' } };

after(() => {
spy.restore();
getBestBlockHash = getBestBlockHashFactory(coreRPCClientMock, zmqClientMock);
});

it('Should return a number', async () => {
const getBestBlockHash = getBestBlockHashFactory(coreAPIFixture);
expect(spy.callCount).to.be.equal(0);
const bestBlockHash = await getBestBlockHash();
expect(bestBlockHash).to.be.an('string');
expect(spy.callCount).to.be.equal(1);
expect(bestBlockHash).to.equals(blockHash);
expect(coreRPCClientMock.getBestBlockHash).to.be.calledOnce();
});
});
Loading