Skip to content

Commit

Permalink
refactor: add ogmios error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Juan Cruz committed Jun 10, 2022
1 parent 4d4fbd1 commit a8fd810
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 79 deletions.
8 changes: 7 additions & 1 deletion cardano-rosetta-server/src/server/api-error.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
interface Details {
message: string;
}
interface Reason {
name: string;
details: string;
}

/**
* Custom error class to implement Rosetta Error Schema
Expand All @@ -9,8 +13,9 @@ export default class ApiError extends Error implements Components.Schemas.Error
code: number;
retriable: boolean;
details?: Details;
reasons?: Reason[];

constructor(code: number, message: string, retriable: boolean, details?: string) {
constructor(code: number, message: string, retriable: boolean, details?: string, reasons?: Reason[]) {
super(message);

// Set the prototype explicitly.
Expand All @@ -22,5 +27,6 @@ export default class ApiError extends Error implements Components.Schemas.Error
if (details) {
this.details = { message: details };
}
if (reasons) this.reasons = reasons;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
mapAmount,
mapToConstructionHashResponse
} from '../utils/data-mapper';
import { ErrorFactory, ErrorUtils } from '../utils/errors';
import { ErrorFactory, Errors } from '../utils/errors';
import { withNetworkValidation } from './controllers-helper';
import { NetworkService } from '../services/network-service';
import { AddressType } from '../utils/constants';
Expand Down Expand Up @@ -279,14 +279,26 @@ const configure = (
logger.info(`[constructionSubmit] About to submit ${signedTransaction}`);
await ogmiosClient.submitTransaction(logger, signedTransaction);
logger.info('[constructionHash] About to get hash of signed transaction');
const transactionHash = cardanoService.getHashOfSignedTransaction(logger, signedTransaction);
// eslint-disable-next-line camelcase
return { transaction_identifier: { hash: transactionHash } };
const hash = cardanoService.getHashOfSignedTransaction(logger, signedTransaction);
return { transaction_identifier: { hash } };
} catch (error) {
request.log.error(error);
return ErrorUtils.resolveApiErrorFromNodeError(error.message)
.then((mappedError: ApiError) => mappedError)
.catch(() => ErrorFactory.sendTransactionError(error.message));
if (Array.isArray(error)) {
const { code, message } = Errors.SEND_TRANSACTION_ERROR;
throw new ApiError(
code,
message,
false,
undefined,
// eslint-disable-next-line unicorn/prevent-abbreviations
error.map(err => ({
name: err.name,
details: JSON.parse(err.message)
}))
);
} else {
throw ErrorFactory.sendTransactionError(error.message);
}
}
},
request.log,
Expand Down
14 changes: 14 additions & 0 deletions cardano-rosetta-server/src/server/openApi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,20 @@
"address": "0x1dcc4de8dec75d7aab85b567b6",
"error": "not base64"
}
},
"reasons": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"details": {
"type": "object"
}
}
}
}
}
}
Expand Down
20 changes: 0 additions & 20 deletions cardano-rosetta-server/src/server/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,23 +276,3 @@ const nodeErrorToRosettaErrorMap: Array<nodeOutputToError> = [
retriable: false
}
];

const resolveApiErrorFromNodeSourced = (
nodeErrorMessage: string,
errorMappings: nodeOutputToError[]
): Promise<ApiError> => {
const found: nodeOutputToError[] = errorMappings.filter(error => error.inputPattern.test(nodeErrorMessage));
if (found.length > 0) {
const error = found[0].error;
return Promise.resolve(new ApiError(error.code, error.message, found[0].retriable));
}
return Promise.reject('error not found');
};

const resolveApiErrorFromNodeError = (nodeErrorMessage: string): Promise<ApiError> =>
resolveApiErrorFromNodeSourced(nodeErrorMessage, nodeErrorToRosettaErrorMap);

export const ErrorUtils = {
resolveApiErrorFromNodeSourced,
resolveApiErrorFromNodeError
};
5 changes: 4 additions & 1 deletion cardano-rosetta-server/src/types/rosetta-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ declare namespace Components {
details?: {
message: string;
};
reasons?: {
name?: string;
details?: {};
}[];
}
/**
* EventsBlocksRequest is utilized to fetch a sequence of BlockEvents indicating which blocks were added and removed from storage to reach the current state.
Expand Down Expand Up @@ -854,7 +858,6 @@ declare namespace Components {
network_identifier?: /* The network_identifier specifies which network a particular object is associated with. */ NetworkIdentifier;
transaction_identifier: /* The transaction_identifier uniquely identifies a transaction in a particular network and block or in the mempool. */ TransactionIdentifier;
direction: /* Used by RelatedTransaction to indicate the direction of the relation (i.e. cross-shard/cross-network sends may reference `backward` to an earlier transaction and async execution may reference `forward`). Can be used to indicate if a transaction relation is from child to parent or the reverse. */ Direction;
__type?: string;
}
export interface Relay {
type?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ const generatePayloadWithSignedTransaction = (blockchain: string, network: strin
signed_transaction: signedTransaction
});

const ERROR_WHEN_CALLING_CARDANO_CLI = 'Error when calling cardano-cli';
const ERROR_OUTSIDE_VALIDITY_INTERVAL_UTXO = 'Error when sending the transaction - OutsideValidityIntervalUTxO';
const ERROR_OUTSIDE_VALIDITY_INTERVAL_UTXO = 'Error when sending the transaction';

describe(CONSTRUCTION_SUBMIT_ENDPOINT, () => {
let database: Pool;
Expand Down Expand Up @@ -83,10 +82,11 @@ describe(CONSTRUCTION_SUBMIT_ENDPOINT, () => {
});

it('Should return an error if there is a problem when sending the transaction', async () => {
const UNKNOWN_ERROR = 'An unknown error happened';
const mock = ogmiosClientMock.submitTransaction as jest.Mock;
mock.mockClear();
mock.mockImplementation(() => {
throw new Error(ERROR_WHEN_CALLING_CARDANO_CLI);
throw new Error(UNKNOWN_ERROR);
});
const response = await server.inject({
method: 'post',
Expand All @@ -102,34 +102,35 @@ describe(CONSTRUCTION_SUBMIT_ENDPOINT, () => {
expect(response.json()).toEqual({
code: 5006,
details: {
message: ERROR_WHEN_CALLING_CARDANO_CLI
message: UNKNOWN_ERROR
},
message: 'Error when sending the transaction',
retriable: true
});
});

it('Should return an non retriable error if there is OutsideValidityIntervalUTxO error from the node', async () => {
const mock = ogmiosClientMock.submitTransaction as jest.Mock;
mock.mockClear();
mock.mockImplementation(() => {
throw ErrorFactory.sendOutsideValidityIntervalUtxoError(ERROR_OUTSIDE_VALIDITY_INTERVAL_UTXO);
});
const response = await server.inject({
method: 'post',
url: CONSTRUCTION_SUBMIT_ENDPOINT,
payload: generatePayloadWithSignedTransaction(
'cardano',
'mainnet',
CONSTRUCTION_SIGNED_TRANSACTION_WITH_EXTRA_DATA_INVALID_TTL
)
});
expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
expect((ogmiosClientMock.submitTransaction as jest.Mock).mock.calls.length).toBe(1);
expect(response.json()).toEqual({
code: 4037,
message: ERROR_OUTSIDE_VALIDITY_INTERVAL_UTXO,
retriable: false
});
});
// TODO:
// it('Should return an error with reasons if there is OutsideOfValidityInterval error from the node', async () => {
// const mock = ogmiosClientMock.submitTransaction as jest.Mock;
// mock.mockClear();
// mock.mockImplementation(() => {
// throw ErrorFactory.sendOutsideValidityIntervalUtxoError(ERROR_OUTSIDE_VALIDITY_INTERVAL_UTXO);
// });
// const response = await server.inject({
// method: 'post',
// url: CONSTRUCTION_SUBMIT_ENDPOINT,
// payload: generatePayloadWithSignedTransaction(
// 'cardano',
// 'mainnet',
// CONSTRUCTION_SIGNED_TRANSACTION_WITH_EXTRA_DATA_INVALID_TTL
// )
// });
// expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
// expect((ogmiosClientMock.submitTransaction as jest.Mock).mock.calls.length).toBe(1);
// expect(response.json()).toEqual({
// code: 4037,
// message: ERROR_OUTSIDE_VALIDITY_INTERVAL_UTXO,
// retriable: false
// });
// });
});

This file was deleted.

0 comments on commit a8fd810

Please sign in to comment.