Skip to content

Commit

Permalink
Revert error should not be retried (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpuri authored Oct 23, 2023
1 parent ff2bd2f commit 0cbbfd6
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 1 deletion.
42 changes: 42 additions & 0 deletions src/retryOnEmpty.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { providerFromEngine } from '@metamask/eth-json-rpc-provider';
import type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import { errorCodes, rpcErrors } from '@metamask/rpc-errors';
import type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils';
import { PollingBlockTracker } from 'eth-block-tracker';

Expand Down Expand Up @@ -627,6 +628,47 @@ describe('createRetryOnEmptyMiddleware', () => {
);
});
});

describe('when provider return execution revert error', () => {
it('returns the same error to caller', async () => {
await withTestSetup(
{
configureMiddleware: ({ provider, blockTracker }) => {
return {
middlewareUnderTest: createRetryOnEmptyMiddleware({
provider,
blockTracker,
}),
};
},
},
async ({ engine, provider }) => {
const request: JsonRpcRequest<string[]> = {
id: 123,
jsonrpc: '2.0',
method: 'eth_call',
params: buildMockParamsWithBlockParamAt(1, '100'),
};
stubProviderRequests(provider, [
buildStubForBlockNumberRequest(),
{
request,
response: () => {
throw rpcErrors.invalidInput('execution reverted');
},
},
]);
const promiseForResponse = engine.handle(request);
expect(await promiseForResponse).toMatchObject({
error: expect.objectContaining({
code: errorCodes.rpc.invalidInput,
message: 'execution reverted',
}),
});
},
);
});
});
});

/**
Expand Down
6 changes: 5 additions & 1 deletion src/retryOnEmpty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import pify from 'pify';
import { projectLogger, createModuleLogger } from './logging-utils';
import type { Block } from './types';
import { blockTagParamIndex } from './utils/cache';
import { isExecutionRevertedError } from './utils/error';
import { timeout } from './utils/timeout';

//
Expand Down Expand Up @@ -140,7 +141,10 @@ async function retry(
for (let index = 0; index < maxRetries; index++) {
try {
return await asyncFn();
} catch (err) {
} catch (err: unknown) {
if (isExecutionRevertedError(err)) {
throw err as unknown;
}
log('(call %i) Request failed, waiting 1s to retry again...', index + 1);
await timeout(1000);
}
Expand Down
36 changes: 36 additions & 0 deletions src/utils/error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { errorCodes } from '@metamask/rpc-errors';

import { isExecutionRevertedError } from './error';

const executionRevertedError = {
code: errorCodes.rpc.invalidInput,
message: 'execution reverted',
};

describe('isExecutionRevertedError', () => {
it('return false if object is not valid JSON RPC error', async () => {
const result = isExecutionRevertedError({ test: 'dummy' });
expect(result).toBe(false);
});

it('return false if error code is not same as errorCodes.rpc.invalidInput', async () => {
const result = isExecutionRevertedError({
...executionRevertedError,
code: 123,
});
expect(result).toBe(false);
});

it('return false if error message is not "execution reverted"', async () => {
const result = isExecutionRevertedError({
...executionRevertedError,
message: 'test',
});
expect(result).toBe(false);
});

it('return true for correct executionRevertedError', async () => {
const result = isExecutionRevertedError(executionRevertedError);
expect(result).toBe(true);
});
});
13 changes: 13 additions & 0 deletions src/utils/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { errorCodes } from '@metamask/rpc-errors';
import { isJsonRpcError } from '@metamask/utils';
import type { JsonRpcError } from '@metamask/utils';

export function isExecutionRevertedError(
error: unknown,
): error is JsonRpcError {
return (
isJsonRpcError(error) &&
error.code === errorCodes.rpc.invalidInput &&
error.message === 'execution reverted'
);
}

0 comments on commit 0cbbfd6

Please sign in to comment.