Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Accept bigints in RPC error factories
Browse files Browse the repository at this point in the history
lorisleiva committed Nov 5, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 478bebb commit 2ee94ba
Showing 8 changed files with 36 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-otters-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@solana/errors': patch
---

Accept bigints in RPC error factories, fixing functions such as `isProgramError`
6 changes: 3 additions & 3 deletions packages/errors/src/__tests__/instruction-error-test.ts
Original file line number Diff line number Diff line change
@@ -70,10 +70,10 @@ describe('getSolanaErrorFromInstructionError', () => {
expect(error).toEqual(new SolanaError(expectedCode as SolanaErrorCode, { index: 123 }));
},
);
it.failing.each(EXPECTED_ERROR_CODES)(
it.each(EXPECTED_ERROR_CODES)(
'produces the correct `SolanaError` for a `%s` error with a bigint index',
(transactionError, expectedCode) => {
const error = getSolanaErrorFromInstructionError(123n as unknown as number, transactionError);
const error = getSolanaErrorFromInstructionError(123n, transactionError);
expect(error).toEqual(new SolanaError(expectedCode as SolanaErrorCode, { index: 123 }));
},
);
@@ -86,7 +86,7 @@ describe('getSolanaErrorFromInstructionError', () => {
}),
);
});
it.failing('produces the correct `SolanaError` for a `Custom` error with a bigint code', () => {
it('produces the correct `SolanaError` for a `Custom` error with a bigint code', () => {
const error = getSolanaErrorFromInstructionError(123, { Custom: 789n });
expect(error).toEqual(
new SolanaError(SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM, {
4 changes: 2 additions & 2 deletions packages/errors/src/__tests__/json-rpc-error-test.ts
Original file line number Diff line number Diff line change
@@ -35,9 +35,9 @@ describe('getSolanaErrorFromJsonRpcError', () => {
const error = getSolanaErrorFromJsonRpcError({ code, message: 'o no' });
expect(error).toHaveProperty('context.__code', 123);
});
it.failing('converts bigint codes to numbers', () => {
it('converts bigint codes to numbers', () => {
const code = 123n;
const error = getSolanaErrorFromJsonRpcError({ code: code as unknown as number, message: 'o no' });
const error = getSolanaErrorFromJsonRpcError({ code, message: 'o no' });
expect(error).toHaveProperty('context.__code', 123);
});
describe.each([
27 changes: 12 additions & 15 deletions packages/errors/src/__tests__/transaction-error-test.ts
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ describe('getSolanaErrorFromTransactionError', () => {
}),
);
});
it.failing('produces the correct `SolanaError` for a `DuplicateInstruction` error with a bigint index', () => {
it('produces the correct `SolanaError` for a `DuplicateInstruction` error with a bigint index', () => {
const error = getSolanaErrorFromTransactionError({ DuplicateInstruction: 1n });
expect(error).toEqual(
new SolanaError(SOLANA_ERROR__TRANSACTION_ERROR__DUPLICATE_INSTRUCTION, {
@@ -74,7 +74,7 @@ describe('getSolanaErrorFromTransactionError', () => {
}),
);
});
it.failing('produces the correct `SolanaError` for a `InsufficientFundsForRent` error with a bigint index', () => {
it('produces the correct `SolanaError` for a `InsufficientFundsForRent` error with a bigint index', () => {
const error = getSolanaErrorFromTransactionError({ InsufficientFundsForRent: { account_index: 1n } });
expect(error).toEqual(
new SolanaError(SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS_FOR_RENT, {
@@ -92,19 +92,16 @@ describe('getSolanaErrorFromTransactionError', () => {
}),
);
});
it.failing(
'produces the correct `SolanaError` for a `ProgramExecutionTemporarilyRestricted` error with a bigint index',
() => {
const error = getSolanaErrorFromTransactionError({
ProgramExecutionTemporarilyRestricted: { account_index: 1n },
});
expect(error).toEqual(
new SolanaError(SOLANA_ERROR__TRANSACTION_ERROR__PROGRAM_EXECUTION_TEMPORARILY_RESTRICTED, {
accountIndex: 1,
}),
);
},
);
it('produces the correct `SolanaError` for a `ProgramExecutionTemporarilyRestricted` error with a bigint index', () => {
const error = getSolanaErrorFromTransactionError({
ProgramExecutionTemporarilyRestricted: { account_index: 1n },
});
expect(error).toEqual(
new SolanaError(SOLANA_ERROR__TRANSACTION_ERROR__PROGRAM_EXECUTION_TEMPORARILY_RESTRICTED, {
accountIndex: 1,
}),
);
});
it("returns the unknown error when encountering an enum name that's missing from the map", () => {
const error = getSolanaErrorFromTransactionError('ThisDoesNotExist');
expect(error).toEqual(
13 changes: 7 additions & 6 deletions packages/errors/src/instruction-error.ts
Original file line number Diff line number Diff line change
@@ -67,31 +67,32 @@ const ORDERED_ERROR_NAMES = [
];

export function getSolanaErrorFromInstructionError(
index: number,
index: bigint | number,
instructionError: string | { [key: string]: unknown },
): SolanaError {
const numberIndex = Number(index);
return getSolanaErrorFromRpcError(
{
errorCodeBaseOffset: 4615001,
getErrorContext(errorCode, rpcErrorName, rpcErrorContext) {
if (errorCode === SOLANA_ERROR__INSTRUCTION_ERROR__UNKNOWN) {
return {
errorName: rpcErrorName,
index,
index: numberIndex,
...(rpcErrorContext !== undefined ? { instructionErrorContext: rpcErrorContext } : null),
};
} else if (errorCode === SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM) {
return {
code: rpcErrorContext as number,
index,
code: Number(rpcErrorContext as bigint | number),
index: numberIndex,
};
} else if (errorCode === SOLANA_ERROR__INSTRUCTION_ERROR__BORSH_IO_ERROR) {
return {
encodedData: rpcErrorContext as string,
index,
index: numberIndex,
};
}
return { index };
return { index: numberIndex };
},
orderedErrorNames: ORDERED_ERROR_NAMES,
rpcEnumError: instructionError,
5 changes: 3 additions & 2 deletions packages/errors/src/json-rpc-error.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import { safeCaptureStackTrace } from './stack-trace';
import { getSolanaErrorFromTransactionError } from './transaction-error';

interface RpcErrorResponse {
code: number;
code: bigint | number;
data?: unknown;
message: string;
}
@@ -88,8 +88,9 @@ export interface RpcSimulateTransactionResult {
unitsConsumed: number | null;
}

export function getSolanaErrorFromJsonRpcError({ code, data, message }: RpcErrorResponse): SolanaError {
export function getSolanaErrorFromJsonRpcError({ code: rawCode, data, message }: RpcErrorResponse): SolanaError {
let out: SolanaError;
const code = Number(rawCode);
if (code === SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE) {
const { err, ...preflightErrorContext } = data as RpcSimulateTransactionResult;
const causeObject = err ? { cause: getSolanaErrorFromTransactionError(err) } : null;
4 changes: 2 additions & 2 deletions packages/errors/src/transaction-error.ts
Original file line number Diff line number Diff line change
@@ -75,14 +75,14 @@ export function getSolanaErrorFromTransactionError(transactionError: string | {
};
} else if (errorCode === SOLANA_ERROR__TRANSACTION_ERROR__DUPLICATE_INSTRUCTION) {
return {
index: rpcErrorContext as number,
index: Number(rpcErrorContext as bigint | number),
};
} else if (
errorCode === SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS_FOR_RENT ||
errorCode === SOLANA_ERROR__TRANSACTION_ERROR__PROGRAM_EXECUTION_TEMPORARILY_RESTRICTED
) {
return {
accountIndex: (rpcErrorContext as { account_index: number }).account_index,
accountIndex: Number((rpcErrorContext as { account_index: bigint | number }).account_index),
};
}
},
22 changes: 2 additions & 20 deletions packages/rpc-transport-http/src/http-transport-for-solana-rpc.ts
Original file line number Diff line number Diff line change
@@ -15,27 +15,9 @@ type Config = Readonly<{
export function createHttpTransportForSolanaRpc(config: Config): RpcTransport {
return createHttpTransport({
...config,
fromJson: (rawResponse: string, payload: unknown) => {
if (!isSolanaRequest(payload)) return JSON.parse(rawResponse);
const response = parseJsonWithBigInts(rawResponse);
// Error codes are always numbers.
if (isErrorResponse(response)) {
return { ...response, error: { ...response.error, code: Number(response.error.code) } };
}
return response;
},
fromJson: (rawResponse: string, payload: unknown) =>
isSolanaRequest(payload) ? parseJsonWithBigInts(rawResponse) : JSON.parse(rawResponse),
toJson: (payload: unknown) =>
isSolanaRequest(payload) ? stringifyJsonWithBigints(payload) : JSON.stringify(payload),
});
}

function isErrorResponse(value: unknown): value is { error: { code: bigint } } {
return (
!!value &&
typeof value === 'object' &&
'error' in value &&
!!value.error &&
typeof value.error === 'object' &&
'code' in value.error
);
}

0 comments on commit 2ee94ba

Please sign in to comment.