Skip to content

Commit

Permalink
refactor!: classify TxSubmission errors as variant of CardanoNode error
Browse files Browse the repository at this point in the history
- remove lifecycle methods from CardanoNode interface, inherit them from RunnableModule
- make TxSubmissionError a variant of CardanoNodeError
- reuse Ogmios-related errors across CardanoNode and TxSubmitProvider
- adjust src and tests with the new error namespace
- generalize error names
  • Loading branch information
Ivaylo Andonov committed Nov 14, 2022
1 parent 7602507 commit 234305e
Show file tree
Hide file tree
Showing 27 changed files with 176 additions and 208 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Cardano, ProviderError, ProviderFailure, TxSubmitProvider } from '@cardano-sdk/core';
import { CardanoNodeErrors, ProviderError, ProviderFailure, TxSubmitProvider } from '@cardano-sdk/core';
import { CreateHttpProviderConfig, HttpProviderConfigPaths, createHttpProvider } from '../HttpProvider';
import { mapHealthCheckError } from '../mapHealthCheckError';

Expand All @@ -11,21 +11,21 @@ const paths: HttpProviderConfigPaths<TxSubmitProvider> = {
submitTx: '/submit'
};

const toTxSubmissionError = (error: any): Cardano.TxSubmissionError | null => {
const toTxSubmissionError = (error: any): CardanoNodeErrors.TxSubmissionError | null => {
if (typeof error === 'object' && typeof error?.name === 'string' && typeof error?.message === 'string') {
const rawError = error as Cardano.TxSubmissionError;
const rawError = error as CardanoNodeErrors.TxSubmissionError;

const txSubmissionErrorName = rawError.name as keyof typeof Cardano.TxSubmissionErrors;
const ErrorClass = Cardano.TxSubmissionErrors[txSubmissionErrorName];
const txSubmissionErrorName = rawError.name as keyof typeof CardanoNodeErrors.TxSubmissionErrors;
const ErrorClass = CardanoNodeErrors.TxSubmissionErrors[txSubmissionErrorName];
if (ErrorClass) {
Object.setPrototypeOf(error, ErrorClass.prototype);
return error;
}
if (rawError.name === Cardano.UnknownTxSubmissionError.name) {
Object.setPrototypeOf(error, Cardano.UnknownTxSubmissionError.prototype);
if (rawError.name === CardanoNodeErrors.UnknownTxSubmissionError.name) {
Object.setPrototypeOf(error, CardanoNodeErrors.UnknownTxSubmissionError.prototype);
return error;
}
return new Cardano.UnknownTxSubmissionError(error);
return new CardanoNodeErrors.UnknownTxSubmissionError(error);
}
return null;
};
Expand All @@ -36,7 +36,7 @@ const toTxSubmissionError = (error: any): Cardano.TxSubmissionError | null => {
* @param config The configuration object fot the TxSubmit Provider.
* @returns {TxSubmitProvider} TxSubmitProvider
* @throws {ProviderError} if reason === ProviderFailure.BadRequest then
* innerError is set to either one of Cardano.TxSubmissionErrors or Cardano.UnknownTxSubmissionError
* innerError is set to either one of CardanoNodeErrors.TxSubmissionErrors or Cardano.UnknownTxSubmissionError
*/
export const txSubmitHttpProvider = (config: CreateHttpProviderConfig<TxSubmitProvider>): TxSubmitProvider =>
createHttpProvider<TxSubmitProvider>({
Expand All @@ -51,7 +51,7 @@ export const txSubmitHttpProvider = (config: CreateHttpProviderConfig<TxSubmitPr
const txSubmissionError = toTxSubmissionError(error.innerError);
if (txSubmissionError) {
const failure =
txSubmissionError instanceof Cardano.UnknownTxSubmissionError
txSubmissionError instanceof CardanoNodeErrors.UnknownTxSubmissionError
? ProviderFailure.Unknown
: ProviderFailure.BadRequest;
throw new ProviderError(failure, txSubmissionError);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Cardano, ProviderError, ProviderFailure } from '@cardano-sdk/core';
import { CardanoNodeErrors, ProviderError, ProviderFailure } from '@cardano-sdk/core';
import { axiosError, healthCheckResponseWithState } from '../util';
import { bufferToHexString } from '@cardano-sdk/util';
import { logger } from '@cardano-sdk/util-dev';
Expand Down Expand Up @@ -66,7 +66,7 @@ describe('txSubmitHttpProvider', () => {
} catch (error) {
if (error instanceof ProviderError) {
expect(error.reason).toBe(providerFailure);
const innerError = error.innerError as Cardano.TxSubmissionError;
const innerError = error.innerError as CardanoNodeErrors.TxSubmissionError;
expect(innerError).toBeInstanceOf(providerErrorType);
} else {
throw new TypeError('Expected ProviderError');
Expand All @@ -77,30 +77,30 @@ describe('txSubmitHttpProvider', () => {
it(
'rehydrates errors',
testError(
new Cardano.TxSubmissionErrors.BadInputsError({ badInputs: [] }),
new CardanoNodeErrors.TxSubmissionErrors.BadInputsError({ badInputs: [] }),
ProviderFailure.BadRequest,
Cardano.TxSubmissionErrors.BadInputsError
CardanoNodeErrors.TxSubmissionErrors.BadInputsError
)
);

it(
'maps unrecognized errors to UnknownTxSubmissionError',
testError(new Error('Unknown error'), ProviderFailure.Unknown, Cardano.UnknownTxSubmissionError)
testError(new Error('Unknown error'), ProviderFailure.Unknown, CardanoNodeErrors.UnknownTxSubmissionError)
);

it('does not re-wrap UnknownTxSubmissionError', async () => {
expect.assertions(3);
axiosMock.onPost().replyOnce(() => {
throw axiosError(new Cardano.UnknownTxSubmissionError('Unknown error'));
throw axiosError(new CardanoNodeErrors.UnknownTxSubmissionError('Unknown error'));
});
const provider = txSubmitHttpProvider(config);
try {
await provider.submitTx({ signedTransaction: emptyUintArrayAsHexString });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
expect(error).toBeInstanceOf(ProviderError);
expect(error.innerError).toBeInstanceOf(Cardano.UnknownTxSubmissionError);
expect(error.innerError.innerError.name).not.toBe(Cardano.UnknownTxSubmissionError.name);
expect(error.innerError).toBeInstanceOf(CardanoNodeErrors.UnknownTxSubmissionError);
expect(error.innerError.innerError.name).not.toBe(CardanoNodeErrors.UnknownTxSubmissionError.name);
}
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Cardano,
CardanoNodeErrors,
HealthCheckResponse,
ProviderError,
ProviderFailure,
Expand Down Expand Up @@ -219,7 +220,7 @@ export class RabbitMqTxSubmitProvider implements TxSubmitProvider {
} catch (error) {
this.#dependencies.logger.error(`${moduleName}: while queuing transaction: ${txId}`);
this.#dependencies.logger.error(error);
done(Cardano.util.asTxSubmissionError(error) || new Cardano.UnknownTxSubmissionError(error));
done(Cardano.util.asTxSubmissionError(error) || new CardanoNodeErrors.UnknownTxSubmissionError(error));
}
});
}
Expand Down
10 changes: 5 additions & 5 deletions packages/cardano-services/src/TxSubmit/rabbitmq/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Cardano } from '@cardano-sdk/core';
import { CardanoNodeErrors } from '@cardano-sdk/core';
import { Ogmios } from '@cardano-sdk/ogmios';
import { toSerializableObject } from '@cardano-sdk/util';

Expand All @@ -14,11 +14,11 @@ export const TX_SUBMISSION_QUEUE = 'cardano-tx-submit';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getErrorPrototype = (error: unknown) => {
if (typeof error === 'object') {
const rawError = error as Cardano.TxSubmissionError;
const rawError = error as CardanoNodeErrors.TxSubmissionError;

if (typeof rawError.name === 'string' && typeof rawError.message === 'string') {
const txSubmissionErrorName = rawError.name as keyof typeof Cardano.TxSubmissionErrors;
const ErrorClass = Cardano.TxSubmissionErrors[txSubmissionErrorName];
const txSubmissionErrorName = rawError.name as keyof typeof CardanoNodeErrors.TxSubmissionErrors;
const ErrorClass = CardanoNodeErrors.TxSubmissionErrors[txSubmissionErrorName];

if (ErrorClass) return ErrorClass.prototype;
}
Expand All @@ -37,7 +37,7 @@ export const serializeError = (err: unknown) => {

const serializableError = toSerializableObject(err);

if (err instanceof Cardano.TxSubmissionErrors.OutsideOfValidityIntervalError) {
if (err instanceof CardanoNodeErrors.TxSubmissionErrors.OutsideOfValidityIntervalError) {
const details = JSON.parse(err.message) as Ogmios.Schema.OutsideOfValidityInterval['outsideOfValidityInterval'];

if (details.interval.invalidBefore && details.currentSlot <= details.interval.invalidBefore) isRetryable = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable sonarjs/no-identical-functions */
/* eslint-disable sonarjs/no-duplicate-string */
/* eslint-disable max-len */
import { Cardano, CardanoNodeErrors, TxSubmitProvider } from '@cardano-sdk/core';
import { CardanoNodeErrors, TxSubmitProvider } from '@cardano-sdk/core';
import { Connection } from '@cardano-ogmios/client';
import { DbSyncEpochPollService, listenPromise, serverClosePromise } from '../../../src/util';
import { DbSyncNetworkInfoProvider, NetworkInfoHttpService } from '../../../src/NetworkInfo';
Expand Down Expand Up @@ -336,7 +336,7 @@ describe('Service dependency abstractions', () => {
await provider.start();
await expect(
provider.submitTx({ signedTransaction: bufferToHexString(Buffer.from(new Uint8Array([]))) })
).rejects.toBeInstanceOf(Cardano.TxSubmissionErrors.EraMismatchError);
).rejects.toBeInstanceOf(CardanoNodeErrors.TxSubmissionErrors.EraMismatchError);
expect(dnsResolverMock).toBeCalledTimes(2);
await provider.shutdown();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable sonarjs/no-duplicate-string */
/* eslint-disable max-len */
import { Cardano, TxSubmitProvider } from '@cardano-sdk/core';
import { CardanoNodeErrors, TxSubmitProvider } from '@cardano-sdk/core';
import { Connection } from '@cardano-ogmios/client';
import {
HttpServer,
Expand Down Expand Up @@ -199,7 +199,7 @@ describe('Program/services/rabbitmq', () => {
const txs = await txsPromise;
await expect(
provider.submitTx({ signedTransaction: bufferToHexString(Buffer.from(txs[0].txBodyUint8Array)) })
).rejects.toBeInstanceOf(Cardano.TxSubmissionErrors.EraMismatchError);
).rejects.toBeInstanceOf(CardanoNodeErrors.TxSubmissionErrors.EraMismatchError);
expect(dnsResolverMock).toBeCalledTimes(2);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable max-len */
import { APPLICATION_JSON, CONTENT_TYPE, HttpServer, HttpServerConfig, TxSubmitHttpService } from '../../src';
import { Cardano, ProviderError, ProviderFailure, TxSubmitProvider } from '@cardano-sdk/core';
import { CardanoNodeErrors, ProviderError, ProviderFailure, TxSubmitProvider } from '@cardano-sdk/core';
import { CreateHttpProviderConfig, txSubmitHttpProvider } from '@cardano-sdk/cardano-services-client';
import { FATAL, createLogger } from 'bunyan';
import { OgmiosTxSubmitProvider } from '@cardano-sdk/ogmios';
Expand Down Expand Up @@ -182,7 +182,7 @@ describe('TxSubmitHttpService', () => {

describe('healthy but failing submission', () => {
describe('/submit', () => {
const stubErrors = [new Cardano.TxSubmissionErrors.BadInputsError({ badInputs: [] })];
const stubErrors = [new CardanoNodeErrors.TxSubmissionErrors.BadInputsError({ badInputs: [] })];

beforeAll(async () => {
txSubmitProvider = txSubmitProviderMock(
Expand All @@ -209,8 +209,8 @@ describe('TxSubmitHttpService', () => {
await clientProvider.submitTx({ signedTransaction: emptyUintArrayAsHexString });
} catch (error: any) {
if (error instanceof ProviderError) {
const innerError = error.innerError as Cardano.TxSubmissionError;
expect(innerError).toBeInstanceOf(Cardano.TxSubmissionErrors.BadInputsError);
const innerError = error.innerError as CardanoNodeErrors.TxSubmissionError;
expect(innerError).toBeInstanceOf(CardanoNodeErrors.TxSubmissionErrors.BadInputsError);
expect(innerError.message).toBe(stubErrors[0].message);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BAD_CONNECTION_URL, txsPromise } from './utils';
import { Cardano, ProviderError } from '@cardano-sdk/core';
import { CardanoNodeErrors, ProviderError } from '@cardano-sdk/core';
import { OgmiosTxSubmitProvider, urlToConnectionConfig } from '@cardano-sdk/ogmios';
import { RabbitMQContainer } from './docker';
import { RabbitMqTxSubmitProvider, TxSubmitWorker } from '../../../src';
Expand Down Expand Up @@ -134,7 +134,7 @@ describe('TxSubmitWorker', () => {

// Tx submission by RabbitMqTxSubmitProvider must reject with the same error got by TxSubmitWorker
await expect(container.enqueueTx(logger, 0)).rejects.toBeInstanceOf(
Cardano.TxSubmissionErrors.EraMismatchError
CardanoNodeErrors.TxSubmissionErrors.EraMismatchError
);
};

Expand Down
84 changes: 0 additions & 84 deletions packages/core/src/Cardano/types/TxSubmissionErrors.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/core/src/Cardano/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ export * from './Asset';
export * from './AuxiliaryData';
export * from './Key';
export * from './Script';
export * from './TxSubmissionErrors';
export * from './ProtocolParameters';
10 changes: 5 additions & 5 deletions packages/core/src/Cardano/util/txSubmissionErrors.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { TxSubmissionError, TxSubmissionErrors } from '../types/TxSubmissionErrors';
import { CardanoNodeErrors } from '../../CardanoNode';

/**
* Tests the provided error for an instanceof match in the TxSubmissionErrors object
*
* @param {TxSubmissionError} error the error under test
* @param {CardanoNodeErrors.TxSubmissionError} error the error under test
*/
export const isTxSubmissionError = (error: unknown): error is TxSubmissionError =>
Object.values(TxSubmissionErrors).some((TxSubmitError) => error instanceof TxSubmitError);
export const isTxSubmissionError = (error: unknown): error is CardanoNodeErrors.TxSubmissionError =>
Object.values(CardanoNodeErrors.TxSubmissionErrors).some((TxSubmitError) => error instanceof TxSubmitError);

/**
* Attempts to convert the provided error or array of errors into TxSubmissionError object
*
* @param {any} error the error or array of errors under test
*/
export const asTxSubmissionError = (error: unknown): TxSubmissionError | null => {
export const asTxSubmissionError = (error: unknown): CardanoNodeErrors.TxSubmissionError | null => {
if (Array.isArray(error)) {
for (const err of error) {
if (isTxSubmissionError(err)) {
Expand Down
Loading

0 comments on commit 234305e

Please sign in to comment.