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

refactor(experimental): errors: codecs-strings package #2192

Merged
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
3 changes: 2 additions & 1 deletion packages/codecs-strings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
},
"dependencies": {
"@solana/codecs-core": "workspace:*",
"@solana/codecs-numbers": "workspace:*"
"@solana/codecs-numbers": "workspace:*",
"@solana/errors": "workspace:*"
},
"devDependencies": {
"@solana/build-scripts": "workspace:*",
Expand Down
10 changes: 9 additions & 1 deletion packages/codecs-strings/src/__tests__/base10-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase10Codec } from '../base10';

describe('getBase10Codec', () => {
Expand Down Expand Up @@ -25,6 +27,12 @@ describe('getBase10Codec', () => {
expect(base10.encode('65535')).toStrictEqual(new Uint8Array([255, 255]));
expect(base10.read(new Uint8Array([255, 255]), 0)).toStrictEqual(['65535', 2]);

expect(() => base10.encode('INVALID_INPUT')).toThrow('Expected a string of base 10, got [INVALID_INPUT].');
expect(() => base10.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: '0123456789',
base: 10,
value: 'INVALID_INPUT',
}),
);
});
});
10 changes: 9 additions & 1 deletion packages/codecs-strings/src/__tests__/base16-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase16Codec } from '../base16';

describe('getBase16Codec', () => {
Expand All @@ -24,6 +26,12 @@ describe('getBase16Codec', () => {
expect(base16.encode('ffff')).toStrictEqual(new Uint8Array([255, 255]));
expect(base16.read(new Uint8Array([255, 255]), 0)).toStrictEqual(['ffff', 2]);

expect(() => base16.encode('INVALID_INPUT')).toThrow('Expected a string of base 16, got [INVALID_INPUT].');
expect(() => base16.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: '0123456789abcdef',
base: 16,
value: 'INVALID_INPUT',
}),
);
});
});
10 changes: 9 additions & 1 deletion packages/codecs-strings/src/__tests__/base58-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase58Codec } from '../base58';

describe('getBase58Codec', () => {
Expand Down Expand Up @@ -37,7 +39,13 @@ describe('getBase58Codec', () => {
expect(base58.encode(pubkey)).toStrictEqual(bytes);
expect(base58.read(bytes, 0)).toStrictEqual([pubkey, 32]);

expect(() => base58.encode('INVALID_INPUT')).toThrow('Expected a string of base 58, got [INVALID_INPUT].');
expect(() => base58.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
base: 58,
value: 'INVALID_INPUT',
}),
);
});

it('computes the buffer size of base 58 strings', () => {
Expand Down
26 changes: 23 additions & 3 deletions packages/codecs-strings/src/__tests__/base64-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase16Codec } from '../base16';
import { getBase64Codec } from '../base64';

Expand Down Expand Up @@ -27,7 +29,13 @@ describe('getBase64Codec', () => {
expect(base64.encode(sentence)).toStrictEqual(bytes);
expect(base64.read(bytes, 0)).toStrictEqual([sentence, 27]);

expect(() => base64.encode('INVALID_INPUT')).toThrow('Expected a string of base 64, got [INVALID_INPUT].');
expect(() => base64.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base: 64,
value: 'INVALID_INPUT',
}),
);

const base64TokenData =
'AShNrkm2joOHhfQnRCzfSbrtDUkUcJSS7PJryR4PPjsnyyIWxL0ESVFoE7QWBowtz2B/iTtUGdb2EEyKbLuN5gEAAAAAAAAAAQAAAGCtpnOhgF7t+dM8By+nG51mKI9Dgb0RtO/6xvPX1w52AgAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
Expand All @@ -41,8 +49,20 @@ describe('getBase64Codec', () => {
if (__BROWSER__) {
it('fails if base64 strings do not have the expected padding', () => {
// This is because atob is not tolerant to missing padding.
expect(() => base64.encode('A')).toThrow('Expected a string of base 64, got [A].');
expect(() => base64.encode('AA=')).toThrow('Expected a string of base 64, got [AA=].');
expect(() => base64.encode('A')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base: 64,
value: 'A',
}),
);
expect(() => base64.encode('AA=')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base: 64,
value: 'AA=',
}),
);
});
} else {
it('tolerate base64 string with less padding than expected', () => {
Expand Down
9 changes: 7 additions & 2 deletions packages/codecs-strings/src/assertions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

/**
* Asserts that a given string matches a given alphabet.
*/
export function assertValidBaseString(alphabet: string, testValue: string, givenValue = testValue) {
if (!testValue.match(new RegExp(`^[${alphabet}]*$`))) {
// TODO: Coded error.
throw new Error(`Expected a string of base ${alphabet.length}, got [${givenValue}].`);
throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet,
base: alphabet.length,
value: givenValue,
});
}
}
15 changes: 11 additions & 4 deletions packages/codecs-strings/src/base64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
VariableSizeDecoder,
VariableSizeEncoder,
} from '@solana/codecs-core';
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { assertValidBaseString } from './assertions';
import { getBaseXResliceDecoder, getBaseXResliceEncoder } from './baseX-reslice';
Expand All @@ -22,8 +23,11 @@ export const getBase64Encoder = (): VariableSizeEncoder<string> => {
try {
return (atob as Window['atob'])(value).length;
} catch (e) {
// TODO: Coded error.
throw new Error(`Expected a string of base 64, got [${value}].`);
throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet,
base: 64,
value,
});
}
},
write(value: string, bytes, offset) {
Expand All @@ -34,8 +38,11 @@ export const getBase64Encoder = (): VariableSizeEncoder<string> => {
bytes.set(bytesToAdd, offset);
return bytesToAdd.length + offset;
} catch (e) {
// TODO: Coded error.
throw new Error(`Expected a string of base 64, got [${value}].`);
throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet,
base: 64,
value,
});
}
},
});
Expand Down
2 changes: 2 additions & 0 deletions packages/errors/src/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC = 43 a
export const SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX = 44 as const;
export const SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE = 45 as const;
export const SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE = 46 as const;
export const SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE = 47 as const;
// Reserve error codes starting with [4615000-4615999] for the Rust enum `InstructionError`
export const SOLANA_ERROR__INSTRUCTION_ERROR_UNKNOWN = 4615000 as const;
export const SOLANA_ERROR__INSTRUCTION_ERROR_GENERIC_ERROR = 4615001 as const;
Expand Down Expand Up @@ -219,6 +220,7 @@ export type SolanaErrorCode =
| typeof SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC
| typeof SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX
| typeof SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE
| typeof SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE
| typeof SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE
| typeof SOLANA_ERROR__INSTRUCTION_ERROR_UNKNOWN
| typeof SOLANA_ERROR__INSTRUCTION_ERROR_GENERIC_ERROR
Expand Down
6 changes: 6 additions & 0 deletions packages/errors/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SOLANA_ERROR__CODECS_FIXED_SIZE_ENCODER_DECODER_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_INVALID_DATA_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE,
SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE,
SOLANA_ERROR__CODECS_VARIABLE_SIZE_ENCODER_DECODER_MAX_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_WRONG_NUMBER_OF_BYTES,
Expand Down Expand Up @@ -197,6 +198,11 @@ export type SolanaErrorContext = DefaultUnspecifiedErrorContextToUndefined<
value: number | string;
variants: string[];
};
[SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE]: {
alphabet: string;
base: number;
value: string;
};
[SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE]: {
codecDescription: string;
max: bigint | number;
Expand Down
2 changes: 2 additions & 0 deletions packages/errors/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
SOLANA_ERROR__CODECS_FIXED_SIZE_ENCODER_DECODER_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_INVALID_DATA_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE,
SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE,
SOLANA_ERROR__CODECS_VARIABLE_SIZE_ENCODER_DECODER_MAX_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_WRONG_NUMBER_OF_BYTES,
Expand Down Expand Up @@ -185,6 +186,7 @@ export const SolanaErrorMessages: Readonly<{
'Invalid data enum variant. Expected one of [$variants], got $value.',
[SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT]:
'Invalid scalar enum variant. Expected one of [$variants] or a number between $minRange and $maxRange, got $value.',
[SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE]: 'Invalid value $value for base $base with alphabet $alphabet.',
[SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE]:
'Codec [$codecDescription] expected number to be in the range [$min, $max], got $value.',
[SOLANA_ERROR__CODECS_VARIABLE_SIZE_ENCODER_DECODER_MAX_SIZE_MISMATCH]:
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading