Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: demote server connection errors and contract clarity errors to be non-retryable #249

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 src/token-processor/images/image-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
throw new ImageSizeExceededError(`ImageCache image too large: ${imgUrl}`);
}
if ((typeError.cause as any).toString().includes('ECONNRESET')) {
throw new RetryableJobError(`ImageCache server connection interrupted`, typeError);
throw new ImageHttpError(`ImageCache server connection interrupted`, typeError);

Check warning on line 161 in src/token-processor/images/image-cache.ts

View check run for this annotation

Codecov / codecov/patch

src/token-processor/images/image-cache.ts#L161

Added line #L161 was not covered by tests
}
}
throw error;
Expand Down
4 changes: 2 additions & 2 deletions src/token-processor/queue/job/process-token-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
DbTokenType,
} from '../../../pg/types';
import { StacksNodeRpcClient } from '../../stacks-node/stacks-node-rpc-client';
import { StacksNodeClarityError, TooManyRequestsHttpError } from '../../util/errors';
import { SmartContractClarityError, TooManyRequestsHttpError } from '../../util/errors';
import {
fetchAllMetadataLocalesFromBaseUri,
getFetchableDecentralizedStorageUrl,
Expand Down Expand Up @@ -108,7 +108,7 @@ export class ProcessTokenJob extends Job {
} catch (error) {
// We'll treat Clarity errors here as if the supply was `undefined` to accommodate ALEX's
// wrapped tokens which return an error in `get-total-supply`.
if (!(error instanceof StacksNodeClarityError)) {
if (!(error instanceof SmartContractClarityError)) {
throw error;
}
}
Expand Down
19 changes: 7 additions & 12 deletions src/token-processor/stacks-node/stacks-node-rpc-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { ENV } from '../../env';
import { RetryableJobError } from '../queue/errors';
import {
StacksNodeClarityError,
SmartContractClarityError,
StacksNodeJsonParseError,
StacksNodeHttpError,
} from '../util/errors';
Expand Down Expand Up @@ -72,7 +72,7 @@
try {
return BigInt(uintVal.value.toString());
} catch (error) {
throw new RetryableJobError(`Invalid uint value '${uintVal.value}'`);
throw new SmartContractClarityError(`Invalid uint value '${uintVal.value}'`);

Check warning on line 75 in src/token-processor/stacks-node/stacks-node-rpc-client.ts

View check run for this annotation

Codecov / codecov/patch

src/token-processor/stacks-node/stacks-node-rpc-client.ts#L75

Added line #L75 was not covered by tests
}
}

Expand Down Expand Up @@ -131,23 +131,18 @@
functionName: string,
functionArgs: ClarityValue[]
): Promise<ClarityValue> {
let result: ReadOnlyContractCallResponse;
try {
result = await this.sendReadOnlyContractCall(functionName, functionArgs);
} catch (error) {
throw new RetryableJobError(`Error making read-only contract call: ${error}`, error);
}
const result = await this.sendReadOnlyContractCall(functionName, functionArgs);
if (!result.okay) {
if (result.cause.startsWith('Runtime')) {
throw new RetryableJobError(
`Runtime error while calling read-only function ${functionName}`
);
} else if (result.cause.includes('NoSuchContract')) {
throw new RetryableJobError(
throw new SmartContractClarityError(

Check warning on line 141 in src/token-processor/stacks-node/stacks-node-rpc-client.ts

View check run for this annotation

Codecov / codecov/patch

src/token-processor/stacks-node/stacks-node-rpc-client.ts#L141

Added line #L141 was not covered by tests
`Contract not available yet when calling read-only function ${functionName}`
);
}
throw new StacksNodeClarityError(`Read-only error ${functionName}: ${result.cause}`);
throw new SmartContractClarityError(`Read-only error ${functionName}: ${result.cause}`);

Check warning on line 145 in src/token-processor/stacks-node/stacks-node-rpc-client.ts

View check run for this annotation

Codecov / codecov/patch

src/token-processor/stacks-node/stacks-node-rpc-client.ts#L145

Added line #L145 was not covered by tests
}
return decodeClarityValue(result.result);
}
Expand All @@ -168,7 +163,7 @@
if (unwrappedClarityValue.type_id === ClarityTypeID.UInt) {
return unwrappedClarityValue;
}
throw new StacksNodeClarityError(
throw new SmartContractClarityError(
`Unexpected Clarity type '${unwrappedClarityValue.type_id}' while unwrapping uint`
);
}
Expand All @@ -183,7 +178,7 @@
} else if (unwrappedClarityValue.type_id === ClarityTypeID.OptionalNone) {
return undefined;
}
throw new StacksNodeClarityError(
throw new SmartContractClarityError(
`Unexpected Clarity type '${unwrappedClarityValue.type_id}' while unwrapping string`
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/token-processor/util/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class MetadataParseError extends UserError {

export class ImageParseError extends MetadataParseError {}

export class StacksNodeClarityError extends UserError {
export class SmartContractClarityError extends UserError {
constructor(message: string) {
super();
this.message = message;
Expand Down Expand Up @@ -111,7 +111,7 @@ export function getUserErrorInvalidReason(error: UserError): DbJobInvalidReason
return DbJobInvalidReason.metadataHttpError;
case error instanceof ImageHttpError:
return DbJobInvalidReason.imageHttpError;
case error instanceof StacksNodeClarityError:
case error instanceof SmartContractClarityError:
return DbJobInvalidReason.tokenContractClarityError;
default:
return DbJobInvalidReason.unknown;
Expand Down
10 changes: 1 addition & 9 deletions src/token-processor/util/metadata-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,6 @@
break;
} catch (error) {
fetchImmediateRetryCount++;
if (
error instanceof MetadataTimeoutError &&
isUriFromDecentralizedStorage(error.url.toString())
) {
// Gateways like IPFS and Arweave commonly time out when a resource can't be found quickly.
// Try again later if this is the case.
throw new RetryableJobError(`Gateway timeout for ${error.url}`, error);
}
if (error instanceof TooManyRequestsHttpError) {
// 429 status codes are common when fetching metadata for thousands of tokens in the same
// server.
Expand Down Expand Up @@ -268,7 +260,7 @@
error instanceof TypeError &&
((error as UndiciCauseTypeError).cause as any).toString().includes('ECONNRESET')
) {
throw new RetryableJobError(`Server connection interrupted`, error);
throw new MetadataHttpError(`Server connection interrupted`, error);

Check warning on line 263 in src/token-processor/util/metadata-helpers.ts

View check run for this annotation

Codecov / codecov/patch

src/token-processor/util/metadata-helpers.ts#L263

Added line #L263 was not covered by tests
}
throw new MetadataHttpError(`${url}: ${error}`, error);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/token-queue/metadata-helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,6 @@ describe('Metadata Helpers', () => {
.replyWithError(Object.assign(new TypeError(), { cause: new Error('read ECONNRESET') }));
setGlobalDispatcher(agent);

await expect(fetchMetadata(url)).rejects.toThrow(RetryableJobError);
await expect(fetchMetadata(url)).rejects.toThrow(MetadataHttpError);
});
});
11 changes: 4 additions & 7 deletions tests/token-queue/stacks-node-rpc-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { StacksNodeRpcClient } from '../../src/token-processor/stacks-node/stack
import {
StacksNodeJsonParseError,
StacksNodeHttpError,
SmartContractClarityError,
} from '../../src/token-processor/util/errors';

describe('StacksNodeRpcClient', () => {
Expand Down Expand Up @@ -69,7 +70,7 @@ describe('StacksNodeRpcClient', () => {
setGlobalDispatcher(agent);

await expect(client.readStringFromContract('get-token-uri', [])).rejects.toThrow(
RetryableJobError
SmartContractClarityError
);
});

Expand Down Expand Up @@ -110,9 +111,7 @@ describe('StacksNodeRpcClient', () => {
try {
await client.readStringFromContract('get-token-uri', []);
} catch (error) {
expect(error).toBeInstanceOf(RetryableJobError);
const err = error as RetryableJobError;
expect(err.cause).toBeInstanceOf(StacksNodeHttpError);
expect(error).toBeInstanceOf(StacksNodeHttpError);
}
});

Expand All @@ -131,9 +130,7 @@ describe('StacksNodeRpcClient', () => {
try {
await client.readStringFromContract('get-token-uri', []);
} catch (error) {
expect(error).toBeInstanceOf(RetryableJobError);
const err = error as RetryableJobError;
expect(err.cause).toBeInstanceOf(StacksNodeJsonParseError);
expect(error).toBeInstanceOf(StacksNodeJsonParseError);
}
});

Expand Down
Loading