Skip to content

Commit

Permalink
fix(dapi): internal errors if broadcasting failed (#1673)
Browse files Browse the repository at this point in the history
  • Loading branch information
shumkov authored Jan 16, 2024
1 parent 535429a commit 77febff
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
InvalidArgumentGrpcError,
AlreadyExistsGrpcError,
ResourceExhaustedGrpcError,
UnavailableGrpcError,
},
},
} = require('@dashevo/grpc-common');
Expand Down Expand Up @@ -44,7 +45,11 @@ function broadcastStateTransitionHandlerFactory(rpcClient, createGrpcErrorFromDr
try {
response = await rpcClient.request('broadcast_tx_sync', { tx });
} catch (e) {
logger.error(e, 'Failed broadcasting state transition');
logger.error(`Failed broadcasting state transition: ${e}`);

if (e.message === 'socket hang up') {
throw new UnavailableGrpcError('Tenderdash is not available');
}

throw e;
}
Expand All @@ -65,12 +70,18 @@ function broadcastStateTransitionHandlerFactory(rpcClient, createGrpcErrorFromDr
if (jsonRpcError.data.startsWith('mempool is full')) {
throw new ResourceExhaustedGrpcError(jsonRpcError.data);
}

if (jsonRpcError.data.startsWith('broadcast confirmation not received:')) {
logger.error(`Failed broadcasting state transition: ${jsonRpcError.data}`);

throw new UnavailableGrpcError(jsonRpcError.data);
}
}

const error = new Error();
Object.assign(error, jsonRpcError);

logger.error(error, 'Unexpected JSON RPC error during broadcasting state transition');
logger.error(error, `Unexpected JSON RPC error during broadcasting state transition: ${JSON.stringify(jsonRpcError)}`);

throw error;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const {
error: {
InvalidArgumentGrpcError,
AlreadyExistsGrpcError,
UnavailableGrpcError,
ResourceExhaustedGrpcError,
},
},
} = require('@dashevo/grpc-common');
Expand Down Expand Up @@ -115,23 +117,72 @@ describe('broadcastStateTransitionHandlerFactory', () => {
expect(rpcClientMock.request).to.be.calledOnceWith('broadcast_tx_sync', { tx });
});

it('should throw an error if transaction broadcast returns error', async () => {
const error = { code: -1, message: "Something didn't work", data: 'Some data' };
it('should throw a UnavailableGrpcError if tenderdash hands up', async () => {
const error = new Error('socket hang up');
rpcClientMock.request.throws(error);

response.error = error;
try {
await broadcastStateTransitionHandler(call);

expect.fail('should throw UnavailableGrpcError');
} catch (e) {
expect(e).to.be.an.instanceOf(UnavailableGrpcError);
expect(e.getMessage()).to.equal('Tenderdash is not available');
}
});

it('should throw a UnavailableGrpcError if broadcast confirmation not received', async () => {
response.error = {
code: -32603,
message: 'Internal error',
data: 'broadcast confirmation not received: heya',
};

try {
await broadcastStateTransitionHandler(call);

expect.fail('should throw an error');
expect.fail('should throw UnavailableGrpcError');
} catch (e) {
expect(e.message).to.equal(error.message);
expect(e.data).to.equal(error.data);
expect(e.code).to.equal(error.code);
expect(e).to.be.an.instanceOf(UnavailableGrpcError);
expect(e.getMessage()).to.equal(response.error.data);
}
});

it('should throw FailedPreconditionGrpcError if transaction was broadcasted twice', async () => {
it('should throw an InvalidArgumentGrpcError if state transition size is too big', async () => {
response.error = {
code: -32603,
message: 'Internal error',
data: 'Tx too large. La la la',
};

try {
await broadcastStateTransitionHandler(call);

expect.fail('should throw UnavailableGrpcError');
} catch (e) {
expect(e).to.be.an.instanceOf(InvalidArgumentGrpcError);
expect(e.getMessage()).to.equal('state transition is too large. La la la');
}
});

it('should throw a ResourceExhaustedGrpcError if mempool is full', async () => {
response.error = {
code: -32603,
message: 'Internal error',
data: 'mempool is full: heya',
};

try {
await broadcastStateTransitionHandler(call);

expect.fail('should throw UnavailableGrpcError');
} catch (e) {
expect(e).to.be.an.instanceOf(ResourceExhaustedGrpcError);
expect(e.getMessage()).to.equal(response.error.data);
}
});

it('should throw AlreadyExistsGrpcError if transaction was broadcasted twice', async () => {
response.error = {
code: -32603,
message: 'Internal error',
Expand All @@ -148,7 +199,7 @@ describe('broadcastStateTransitionHandlerFactory', () => {
}
});

it('should throw call createGrpcErrorFromDriveResponse if error code is not 0', async () => {
it('should throw a gRPC error based on drive\'s response', async () => {
const message = 'not found';
const metadata = {
data: 'some data',
Expand Down Expand Up @@ -176,4 +227,20 @@ describe('broadcastStateTransitionHandlerFactory', () => {
);
}
});

it('should throw an error if transaction broadcast returns unknown error', async () => {
const error = { code: -1, message: "Something didn't work", data: 'Some data' };

response.error = error;

try {
await broadcastStateTransitionHandler(call);

expect.fail('should throw an error');
} catch (e) {
expect(e.message).to.equal(error.message);
expect(e.data).to.equal(error.data);
expect(e.code).to.equal(error.code);
}
});
});

0 comments on commit 77febff

Please sign in to comment.