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 validation uint int sizes #6434

Merged
merged 16 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 14 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
4 changes: 3 additions & 1 deletion packages/web3-errors/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,6 @@ Documentation:

- Dependencies updated

## [Unreleased]
## [Unreleased]

- Added new SchemaFormatError (#6434)
4 changes: 4 additions & 0 deletions packages/web3-errors/src/error_codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,14 @@ export const ERR_INVALID_NIBBLE_WIDTH = 1014;
// Validation error codes
export const ERR_VALIDATION = 1100;


// Core error codes
export const ERR_CORE_HARDFORK_MISMATCH = 1101;
export const ERR_CORE_CHAIN_MISMATCH = 1102;

// Schema error codes
export const ERR_SCHEMA_FORMAT = 1200;

// RPC error codes (EIP-1474)
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1474.md
export const ERR_RPC_INVALID_JSON = -32700;
Expand Down
32 changes: 32 additions & 0 deletions packages/web3-errors/src/errors/schema_errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
This file is part of web3.js.

web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import { ERR_SCHEMA_FORMAT } from '../error_codes.js';
import { BaseWeb3Error } from '../web3_error_base.js';

export class SchemaFormatError extends BaseWeb3Error {
public code = ERR_SCHEMA_FORMAT;

public constructor(public format: string) {
super(`format ${format} is unsupported`);
luu-alex marked this conversation as resolved.
Show resolved Hide resolved
}

public toJSON() {
return { ...super.toJSON(), format: this.format };
}

}
1 change: 1 addition & 0 deletions packages/web3-errors/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export * from './errors/response_errors.js';
export * from './errors/core_errors.js';
export * from './errors/rpc_errors.js';
export * from './errors/rpc_error_messages.js';
export * from './errors/schema_errors.js';
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,16 @@ Object {
}
`;

exports[`errors SchemaFormatError should have valid json structure 1`] = `
Object {
"code": 1200,
"format": "unsupported",
"innerError": undefined,
"message": "format unsupported is unsupported",
luu-alex marked this conversation as resolved.
Show resolved Hide resolved
"name": "SchemaFormatError",
}
`;

exports[`errors TransactionError should have valid json structure 1`] = `
Object {
"code": 400,
Expand Down
11 changes: 11 additions & 0 deletions packages/web3-errors/test/unit/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import * as signatureErrors from '../../src/errors/signature_errors';
import * as transactionErrors from '../../src/errors/transaction_errors';
import * as utilsErrors from '../../src/errors/utils_errors';
import * as responseErrors from '../../src/errors/response_errors';
import * as schemaErrors from '../../src/errors/schema_errors';

import { ConvertValueToString } from '../fixtures/errors';
import { BaseWeb3Error } from '../../src/web3_error_base';
Expand All @@ -50,6 +51,7 @@ describe('errors', () => {
...signatureErrors,
...transactionErrors,
...utilsErrors,
...schemaErrors,
})) {
if (ErrorClass === transactionErrors.InvalidPropertiesForTransactionTypeError) break;
// To disable error for the abstract class
Expand Down Expand Up @@ -379,4 +381,13 @@ describe('errors', () => {
).toMatchSnapshot();
});
});

describe('SchemaFormatError', () => {
it('should have valid json structure', () => {
expect(
new schemaErrors.SchemaFormatError("unsupported"
).toJSON(),
).toMatchSnapshot();
});
});
});
2 changes: 2 additions & 0 deletions packages/web3-validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,5 @@ Documentation:

- Multi-dimensional arrays are now handled properly when parsing ABIs (#6435)
- Fix issue with default config with babel (and React): "TypeError: Cannot convert a BigInt value to a number #6187" (#6506)
- Validator will now properly handle all valid numeric type sizes: intN / uintN where 8 <= N <= 256 and N % 8 == 0 (#6434)
- Will now throw SchemaFormatError when unsupported format is given in `convertToZod` method (#6434)
3 changes: 1 addition & 2 deletions packages/web3-validator/src/formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ const formats: { [key: string]: (data: unknown) => boolean } = {
string: (data: unknown) => isString(data as ValidInputTypes),
};
// generate formats for all numbers types
for (let i = 3; i <= 8; i += 1) {
const bitSize = 2 ** i;
for (let bitSize = 8; bitSize <= 256; bitSize += 8) {
formats[`int${bitSize}`] = data => isInt(data as ValidInputTypes, { bitSize });
formats[`uint${bitSize}`] = data => isUInt(data as ValidInputTypes, { bitSize });
}
Expand Down
5 changes: 5 additions & 0 deletions packages/web3-validator/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
import { SchemaFormatError } from 'web3-errors';
import { Web3ValidationErrorObject } from 'web3-types';

import { z, ZodType, ZodIssue, ZodIssueCode, ZodTypeAny } from 'zod';
Expand Down Expand Up @@ -67,6 +68,10 @@ const convertToZod = (schema: JsonSchema): ZodType => {
}

if (schema?.format) {
if (!formats[schema.format]) {
throw new SchemaFormatError(schema.format);
}

return z.any().refine(formats[schema.format], (value: unknown) => ({
params: { value, format: schema.format },
}));
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-validator/test/config/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
},
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
},
verbose: false,
collectCoverage: false,
coverageReporters: ['json'],
Expand Down
35 changes: 34 additions & 1 deletion packages/web3-validator/test/fixtures/abi_to_json_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type AbiToJsonSchemaCase = {
data: Record<string, unknown> | Array<unknown>;
};
};
export const abiToJsonSchemaCases: AbiToJsonSchemaCase[] = [
const abiToJsonSchemaCases: AbiToJsonSchemaCase[] = [
{
title: 'single param uint',
abi: {
Expand Down Expand Up @@ -1659,3 +1659,36 @@ export const abiToJsonSchemaCases: AbiToJsonSchemaCase[] = [
},
},
];

function generateSingleParamNumericCase(type: string, bitSize: number) {
return {
title: `single param ${type}${bitSize}`,
abi: {
fullSchema: [{ name: 'a', type: `${type}${bitSize}` }],
shortSchema: [`${type}${bitSize}`],
data: [12],
},
json: {
fullSchema: {
type: 'array',
items: [{ $id: 'a', format: `${type}${bitSize}`, required: true }],
minItems: 1,
maxItems: 1,
},
shortSchema: {
type: 'array',
items: [{ $id: '/0/0', format: `${type}${bitSize}`, required: true }],
minItems: 1,
maxItems: 1,
},
data: [12],
},
};
}

for (let i = 256; i >= 8; i -= 8) {
abiToJsonSchemaCases.unshift(generateSingleParamNumericCase('int', i));
abiToJsonSchemaCases.unshift(generateSingleParamNumericCase('uint', i));
}

export { abiToJsonSchemaCases };
2 changes: 1 addition & 1 deletion packages/web3-validator/test/unit/load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import { Web3Validator } from '../../src/web3_validator';
import { Json, JsonSchema, ValidationSchemaInput } from '../..';
import { Json, JsonSchema, ValidationSchemaInput } from '../../src/types';

const abi = [
{ indexed: true, internalType: 'address', name: 'from', type: 'address' },
Expand Down
31 changes: 25 additions & 6 deletions packages/web3-validator/test/unit/web3_validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
import { SchemaFormatError } from 'web3-errors'
import { abiToJsonSchemaCases } from '../fixtures/abi_to_json_schema';
import { Web3Validator } from '../../src/web3_validator';
import { Web3ValidatorError } from '../../src/errors';
Expand Down Expand Up @@ -101,14 +102,32 @@ describe('web3-validator', () => {
),
).toBeUndefined();
});

it('should throw due to unsupported format', () => {
expect(() => {
validator.validateJSONSchema(
{
type: 'array',
items: [{ $id: 'a', format: 'unsupportedFormat', required: true }],
minItems: 1,
maxItems: 1,
},
['0x2df0879f1ee2b2b1f2448c64c089c29e3ad7ccc5'],
);
}).toThrow(SchemaFormatError);
});
});
describe('validateJsonSchema', () => {
it.each(abiToJsonSchemaCases.slice(0, 5))('should pass for valid data', abi => {
const jsonSchema = abi.json;
expect(
validator.validateJSONSchema(jsonSchema.fullSchema, jsonSchema.data),
).toBeUndefined();
});
// only single param test cases
it.each(abiToJsonSchemaCases.slice(0, 69))(
`$title - should pass for valid data`,
abi => {
const jsonSchema = abi.json;
expect(
validator.validateJSONSchema(jsonSchema.fullSchema, jsonSchema.data),
).toBeUndefined();
},
);

it('should throw', () => {
expect(() => {
Expand Down
Loading