Skip to content
This repository has been archived by the owner on Dec 16, 2021. It is now read-only.

refactor: getBlock without insight #344

Merged
merged 16 commits into from
Mar 9, 2021
Merged
Show file tree
Hide file tree
Changes from 14 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
2 changes: 1 addition & 1 deletion lib/externalApis/dashcore/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const getRawTransaction = txid => new Promise((resolve, reject) => {
});
});

const getRawBlock = txid => getBlock(txid, false);
const getRawBlock = blockhash => getBlock(blockhash, false);

// This is only for in-wallet transaction
const getTransaction = txid => new Promise((resolve, reject) => {
Expand Down
2 changes: 1 addition & 1 deletion lib/grpcServer/handlers/core/coreHandlersFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function coreHandlersFactory(insightAPI, coreRPCClient, isProductionEnvironment)
const wrapInErrorHandler = wrapInErrorHandlerFactory(log, isProductionEnvironment);

// getBlock
const getBlockHandler = getBlockHandlerFactory(insightAPI);
const getBlockHandler = getBlockHandlerFactory(coreRPCClient);
const wrappedGetBlock = jsonToProtobufHandlerWrapper(
jsonToProtobufFactory(
GetBlockRequest,
Expand Down
35 changes: 20 additions & 15 deletions lib/grpcServer/handlers/core/getBlockHandlerFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const {
} = require('@dashevo/grpc-common');

/**
* @param {InsightAPI} insightAPI
* @param {CoreRpcClient} coreRPCClient
* @returns {getBlockHandler}
*/
function getBlockHandlerFactory(insightAPI) {
function getBlockHandlerFactory(coreRPCClient) {
/**
* @typedef getBlockHandler
* @param {Object} call
Expand All @@ -27,34 +27,39 @@ function getBlockHandlerFactory(insightAPI) {
const { request } = call;

const height = request.getHeight();
const hash = request.getHash();
let hash = request.getHash();

if (!hash && !height) {
throw new InvalidArgumentGrpcError('hash or height is not specified');
}

let serializedBlock;

if (hash) {
if (!hash) {
try {
serializedBlock = await insightAPI.getRawBlockByHash(hash);
hash = await coreRPCClient.getBlockHash(height);
} catch (e) {
if (e.statusCode === 404) {
throw new NotFoundGrpcError('Block not found');
if (e.code === -8) {
// Block height out of range
throw new NotFoundGrpcError(e.message);
Alex-Werner marked this conversation as resolved.
Show resolved Hide resolved
}
if (e.code === -1) {
// Invalid argument (not integer or integer out of range)
throw new InvalidArgumentGrpcError(e.message);
}

throw e;
}
shumkov marked this conversation as resolved.
Show resolved Hide resolved
} else {
try {
serializedBlock = await insightAPI.getRawBlockByHeight(height);
} catch (e) {
if (e.statusCode === 400) {
throw new InvalidArgumentGrpcError('Invalid block height');
}
}

throw e;
try {
serializedBlock = await coreRPCClient.getRawBlock(hash);
} catch (e) {
if (e.code === -5) {
throw new NotFoundGrpcError('Block not found');
}

throw e;
}

const response = new GetBlockResponse();
Expand Down
75 changes: 46 additions & 29 deletions test/unit/grpcServer/handlers/core/getBlockHandlerFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('getBlockHandlerFactory', () => {
let hash;
let height;
let getBlockHandler;
let insightAPIMock;
let coreRPCClientMock;
let request;
let block;

Expand All @@ -42,12 +42,12 @@ describe('getBlockHandlerFactory', () => {

call = new GrpcCallMock(this.sinon, request);

insightAPIMock = {
getRawBlockByHash: this.sinon.stub().resolves(serializedBlock),
getRawBlockByHeight: this.sinon.stub().resolves(serializedBlock),
coreRPCClientMock = {
getRawBlock: this.sinon.stub().resolves(serializedBlock),
getBlockHash: this.sinon.stub().resolves(hash),
};

getBlockHandler = getBlockHandlerFactory(insightAPIMock);
getBlockHandler = getBlockHandlerFactory(coreRPCClientMock);
});

it('should return valid result is hash is specified', async () => {
Expand All @@ -58,8 +58,8 @@ describe('getBlockHandlerFactory', () => {

expect(result).to.be.an.instanceOf(GetBlockResponse);

expect(insightAPIMock.getRawBlockByHash).to.be.calledOnceWith(hash);
expect(insightAPIMock.getRawBlockByHeight).to.be.not.called();
expect(coreRPCClientMock.getRawBlock).to.be.calledOnceWith(hash);
expect(coreRPCClientMock.getBlockHash).to.be.not.called();

const blockBinary = result.getBlock();

Expand All @@ -78,8 +78,8 @@ describe('getBlockHandlerFactory', () => {

expect(result).to.be.an.instanceOf(GetBlockResponse);

expect(insightAPIMock.getRawBlockByHash).to.be.not.called();
expect(insightAPIMock.getRawBlockByHeight).to.be.calledOnceWith(height);
expect(coreRPCClientMock.getRawBlock).to.be.called();
expect(coreRPCClientMock.getBlockHash).to.be.calledOnceWith(height);

const blockBinary = result.getBlock();

Expand All @@ -98,18 +98,17 @@ describe('getBlockHandlerFactory', () => {
} catch (e) {
expect(e).to.be.instanceOf(InvalidArgumentGrpcError);
expect(e.getMessage()).to.equal('hash or height is not specified');
expect(insightAPIMock.getRawBlockByHash).to.be.not.called();
expect(insightAPIMock.getRawBlockByHeight).to.be.not.called();
expect(coreRPCClientMock.getRawBlock).to.be.not.called();
expect(coreRPCClientMock.getBlockHash).to.be.not.called();
}
});
it('should throw an InvalidArgumentGrpcError if getRawBlock throws error with code -1', async () => {
const error = new Error('JSON value is not an integer as expected');
error.code = -1;

it('should throw an InvalidArgumentGrpcError if getRawBlockByHeight throws error with statusCode = 400', async () => {
const error = new Error();
error.statusCode = 400;

insightAPIMock.getRawBlockByHeight.throws(error);
coreRPCClientMock.getBlockHash.throws(error);

height = 42;
height = 'abc';
request.getHeight.returns(height);

try {
Expand All @@ -118,17 +117,36 @@ describe('getBlockHandlerFactory', () => {
expect.fail('should thrown InvalidArgumentGrpcError error');
} catch (e) {
expect(e).to.be.instanceOf(InvalidArgumentGrpcError);
expect(e.getMessage()).to.equal('Invalid block height');
expect(insightAPIMock.getRawBlockByHash).to.be.not.called();
expect(insightAPIMock.getRawBlockByHeight).to.be.calledOnceWith(height);
expect(e.getMessage()).to.equal('JSON value is not an integer as expected');
expect(coreRPCClientMock.getBlockHash).to.be.calledOnceWith(height);
}
});

it('should throw an InvalidArgumentGrpcError if getRawBlock throws error with code -8', async () => {
const error = new Error('Block height out of range');
error.code = -8;

coreRPCClientMock.getBlockHash.throws(error);

height = 111111111;
request.getHeight.returns(height);

try {
await getBlockHandler(call);

expect.fail('should thrown InvalidArgumentGrpcError error');
} catch (e) {
expect(e).to.be.instanceOf(NotFoundGrpcError);
Alex-Werner marked this conversation as resolved.
Show resolved Hide resolved
expect(e.getMessage()).to.equal('Block height out of range');
expect(coreRPCClientMock.getBlockHash).to.be.calledOnceWith(height);
}
});

it('should throw an InvalidArgumentGrpcError if getRawBlockByHash throws error with statusCode = 404', async () => {
it('should throw an InvalidArgumentGrpcError if getRawBlock throws error with code -5', async () => {
const error = new Error();
error.statusCode = 404;
error.code = -5;

insightAPIMock.getRawBlockByHash.throws(error);
coreRPCClientMock.getRawBlock.throws(error);

hash = 'hash';
request.getHash.returns(hash);
Expand All @@ -140,16 +158,15 @@ describe('getBlockHandlerFactory', () => {
} catch (e) {
expect(e).to.be.instanceOf(NotFoundGrpcError);
expect(e.getMessage()).to.equal('Block not found');
expect(insightAPIMock.getRawBlockByHeight).to.be.not.called();
expect(insightAPIMock.getRawBlockByHash).to.be.calledOnceWith(hash);
expect(coreRPCClientMock.getBlockHash).to.be.not.called();
expect(coreRPCClientMock.getRawBlock).to.be.calledOnceWith(hash);
}
});

it('should throw an InternalGrpcError if getRawBlockByHash throws unknown error', async () => {
const error = new Error('Unknown error');
error.statusCode = 500;

insightAPIMock.getRawBlockByHash.throws(error);
coreRPCClientMock.getRawBlock.throws(error);

hash = 'hash';
request.getHash.returns(hash);
Expand All @@ -160,8 +177,8 @@ describe('getBlockHandlerFactory', () => {
expect.fail('should thrown InvalidArgumentGrpcError error');
} catch (e) {
expect(e).to.deep.equal(error);
expect(insightAPIMock.getRawBlockByHeight).to.be.not.called();
expect(insightAPIMock.getRawBlockByHash).to.be.calledOnceWith(hash);
expect(coreRPCClientMock.getBlockHash).to.be.not.called();
expect(coreRPCClientMock.getRawBlock).to.be.calledOnceWith(hash);
}
});
});