Skip to content

Commit

Permalink
6156 find replacement for is my json valid (#6264)
Browse files Browse the repository at this point in the history
* change internal validation to jsonschema lib

* implement validation with zod

* load test

* add load test

* add changelog

* increase test coverage

* fix test timing

* fix test timing

* fix timing

* re-run tests

* add ValidationError wrapper

* add json-schema

* add change log

* fix change log

* revert type changes

* increase coverage

* changelog sync
  • Loading branch information
avkos authored Jul 17, 2023
1 parent ad377d1 commit b93934a
Show file tree
Hide file tree
Showing 23 changed files with 493 additions and 375 deletions.
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1776,3 +1776,43 @@ If there are any bugs, improvements, optimizations or any new feature proposal f
- Dependencies updated

## [Unreleased]

### Added

#### web3-errors

- `RpcErrorMessages` that contains mapping for standard RPC Errors and their messages. (#6230)

#### web3-validator

- Added `json-schema` as a main json schema type (#6264)

### Fixed

#### web3-core

- Fixed the issue: "Version 4.x does not fire connected event for subscriptions. #6252". (#6262)

#### web3-errors

- Fixed: "'disconnect' in Eip1193 provider must emit ProviderRpcError #6003".(#6230)

### Changed

#### web3-core

- No need to pass `CommonSubscriptionEvents &` at every child class of `Web3Subscription` (#6262)
- Implementation of `_processSubscriptionResult` and `_processSubscriptionError` has been written in the base class `Web3Subscription` and maid `public`. (#6262)
- A new optional protected method `formatSubscriptionResult` could be used to customize data formatting instead of re-implementing `_processSubscriptionResult`. (#6262)
- No more needed to pass `CommonSubscriptionEvents & ` for the first generic parameter of `Web3Subscription` when inheriting from it. (#6262)

#### web3-validator

- Replace `is-my-json-valid` with `zod` dependency. Related code was changed (#6264)
- Types `ValidationError` and `JsonSchema` were changed (#6264)

### Removed

#### web3-validator

- Type `RawValidationError` was removed (#6264)
9 changes: 1 addition & 8 deletions packages/web3-errors/src/errors/transaction_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,14 +555,7 @@ export class InvalidPropertiesForTransactionTypeError extends BaseWeb3Error {
txType: '0x0' | '0x1' | '0x2',
) {
const invalidPropertyNames: string[] = [];
validationError.forEach(error =>
invalidPropertyNames.push(
// These errors are erroneously reported, error
// has type Web3ValidationErrorObject, but eslint doesn't recognize it
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
(error.keyword.match(/data.(.+)/) as string[])[1],
),
);
validationError.forEach(error => invalidPropertyNames.push(error.keyword));
super(
`The following properties are invalid for the transaction type ${txType}: ${invalidPropertyNames.join(
', ',
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-errors/test/unit/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ describe('errors', () => {
new transactionErrors.InvalidPropertiesForTransactionTypeError(
[
{
keyword: 'data.property',
keyword: 'property',
instancePath: '',
schemaPath: '',
params: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ contract SimpleOverload {
return secret + numToAdd;
}

function getSecret(
uint256 numToAdd,
string calldata _someString
) public view returns (uint256, string memory) {
function getSecret(uint256 numToAdd, string calldata _someString)
public
view
returns (uint256, string memory)
{
return (secret + numToAdd, string.concat(someString, _someString));
}

Expand All @@ -37,14 +38,14 @@ contract SimpleOverload {
}

function multicall(bytes[] calldata datas) external {
for (uint i = 0; i < datas.length; i++) {
for (uint256 i = 0; i < datas.length; i++) {
address(this).call(datas[i]);
}
}

function multicall(uint deadline, bytes[] calldata datas) external {
function multicall(uint256 deadline, bytes[] calldata datas) external {
require(block.timestamp <= deadline);
for (uint i = 0; i < datas.length; i++) {
for (uint256 i = 0; i < datas.length; i++) {
address(this).call(datas[i]);
}
}
Expand Down
24 changes: 1 addition & 23 deletions packages/web3-eth/test/integration/block/rpc.getBlock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,29 +131,7 @@ describe('rpc with block', () => {
b.totalDifficulty = '0x0';
}

// just fix tests for oneOf validation
// @TODO: when use schemasafe remove this fix
const schema = JSON.parse(JSON.stringify(blockSchema));
if (
b.transactions &&
Array.isArray(b.transactions) &&
typeof b.transactions[0] === 'object'
) {
// eslint-disable-next-line prefer-destructuring
schema.properties.transactions = schema.properties.transactions.oneOf[0];
// @ts-expect-error add leading zeros remove when fixes https://github.com/web3/web3.js/issues/6060
b.transactions[0].s = `0x${`000000000000000${b?.transactions[0]?.s.slice(2)}`.slice(
-64,
)}`;
// @ts-expect-error add leading zeros remove when fixes https://github.com/web3/web3.js/issues/6060
b.transactions[0].r = `0x${`000000000000000${b?.transactions[0]?.r.slice(2)}`.slice(
-64,
)}`;
} else {
// eslint-disable-next-line prefer-destructuring
schema.properties.transactions = schema.properties.transactions.oneOf[1];
}
expect(validator.validateJSONSchema(schema, b)).toBeUndefined();
expect(validator.validateJSONSchema(blockSchema, b)).toBeUndefined();
if (hydrated && b.transactions?.length > 0) {
// eslint-disable-next-line jest/no-conditional-expect
expect(b.transactions).toBeInstanceOf(Array<Transaction>);
Expand Down
44 changes: 22 additions & 22 deletions packages/web3-utils/test/fixtures/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ export const bytesToHexValidData: [Bytes, HexString][] = [
];

export const bytesToHexInvalidData: [any, string][] = [
[[9.5, 12.9], 'value "9.5,12.9" at "/0" must pass "bytes" validation'],
[[-72, 12], 'value "-72,12" at "/0" must pass "bytes" validation'],
[[567, 10098], 'value "567,10098" at "/0" must pass "bytes" validation'],
[[786, 12, 34, -2, 3], 'value "786,12,34,-2,3" at "/0" must pass "bytes" validation'],
[[9.5, 12.9], 'value "[9.5,12.9]" at "/0" must pass "bytes" validation'],
[[-72, 12], 'value "[-72,12]" at "/0" must pass "bytes" validation'],
[[567, 10098], 'value "[567,10098]" at "/0" must pass "bytes" validation'],
[[786, 12, 34, -2, 3], 'value "[786,12,34,-2,3]" at "/0" must pass "bytes" validation'],
['0x0c1g', 'value "0x0c1g" at "/0" must pass "bytes" validation'],
['0c1g', 'value "0c1g" at "/0" must pass "bytes" validation'],
['0x123', 'value "0x123" at "/0" must pass "bytes" validation'],
['data', 'value "data" at "/0" must pass "bytes" validation'],
[12, 'value "12" at "/0" must pass "bytes" validation'],
[['string'], 'value "string" at "/0" must pass "bytes" validation'],
[['string'], 'value "["string"]" at "/0" must pass "bytes" validation'],
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[null, 'value at "/0" must pass "bytes" validation'],
[null, 'value "null" at "/0" must pass "bytes" validation'],
[undefined, 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[{}, 'value "[object Object]" at "/0" must pass "bytes" validation'],
[{}, 'value "{}" at "/0" must pass "bytes" validation'],
['1', 'value "1" at "/0" must pass "bytes" validation'],
['0', 'value "0" at "/0" must pass "bytes" validation'],
];
Expand All @@ -56,21 +56,21 @@ export const hexToBytesValidData: [HexString, Uint8Array][] = [
];

export const hexToBytesInvalidData: [any, string][] = [
[[9.5, 12.9], 'value "9.5,12.9" at "/0" must pass "bytes" validation'],
[[-72, 12], 'value "-72,12" at "/0" must pass "bytes" validation'],
[[567, 10098], 'value "567,10098" at "/0" must pass "bytes" validation'],
[[786, 12, 34, -2, 3], 'value "786,12,34,-2,3" at "/0" must pass "bytes" validation'],
[[9.5, 12.9], 'value "[9.5,12.9]" at "/0" must pass "bytes" validation'],
[[-72, 12], 'value "[-72,12]" at "/0" must pass "bytes" validation'],
[[567, 10098], 'value "[567,10098]" at "/0" must pass "bytes" validation'],
[[786, 12, 34, -2, 3], 'value "[786,12,34,-2,3]" at "/0" must pass "bytes" validation'],
['0x0c1g', 'value "0x0c1g" at "/0" must pass "bytes" validation'],
['0c1g', 'value "0x0c1g" at "/0" must pass "bytes" validation'],
['0x123', 'value "0x123" at "/0" must pass "bytes" validation'],
['data', 'value "0xdata" at "/0" must pass "bytes" validation'],
[12, 'value "12" at "/0" must pass "bytes" validation'],
[['string'], 'value "string" at "/0" must pass "bytes" validation'],
[['string'], 'value "["string"]" at "/0" must pass "bytes" validation'],
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[null, 'Web3 validator found 1 error[s]:\nvalue at "/0" must pass "bytes" validation'],
[null, 'Web3 validator found 1 error[s]:\nvalue "null" at "/0" must pass "bytes" validation'],
[undefined, 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[{}, 'value "[object Object]" at "/0" must pass "bytes" validation'],
[{}, 'value "{}" at "/0" must pass "bytes" validation'],
];

export const numberToHexValidData: [Numbers, HexString][] = [
Expand Down Expand Up @@ -109,9 +109,9 @@ export const numberToHexInvalidData: [any, string][] = [
['122g', 'value "122g" at "/0" must pass "int" validation'],
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[null, 'value at "/0" must pass "int" validation'],
[null, 'value "null" at "/0" must pass "int" validation'],
[undefined, 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[{}, 'value "[object Object]" at "/0" must pass "int" validation'],
[{}, 'value "{}" at "/0" must pass "int" validation'],
];

export const hexToNumberValidData: [HexString, Numbers][] = [
Expand Down Expand Up @@ -154,9 +154,9 @@ export const utf8ToHexInvalidData: [any, string][] = [
[BigInt(12), 'value "12" at "/0" must pass "string" validation'],
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[null, 'value at "/0" must pass "string" validation'],
[null, 'value "null" at "/0" must pass "string" validation'],
[undefined, 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[{}, 'value "[object Object]" at "/0" must pass "string" validation'],
[{}, 'value "{}" at "/0" must pass "string" validation'],
[true, 'value "true" at "/0" must pass "string" validation'],
[false, 'value "false" at "/0" must pass "string" validation'],
];
Expand Down Expand Up @@ -185,9 +185,9 @@ export const hexToUtf8InvalidData: [any, string][] = [
],
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[null, 'value at "/0" must pass "bytes" validation'],
[null, 'value "null" at "/0" must pass "bytes" validation'],
[undefined, 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[{}, 'value "[object Object]" at "/0" must pass "bytes" validation'],
[{}, 'value "{}" at "/0" must pass "bytes" validation'],
[true, 'value "true" at "/0" must pass "bytes" validation'],
];

Expand Down Expand Up @@ -302,9 +302,9 @@ export const fromWeiInvalidData: [[any, any], string][] = [
export const toWeiInvalidData: [[any, any], string][] = [
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[[null, 'kwei'], 'value at "/0" must pass "number" validation'],
[[null, 'kwei'], 'value "null" at "/0" must pass "number" validation'],
[[undefined, 'kwei'], 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[[{}, 'kwei'], 'value "[object Object]" at "/0" must pass "number" validation'],
[[{}, 'kwei'], 'value "{}" at "/0" must pass "number" validation'],
[['data', 'kwei'], 'value "data" at "/0" must pass "number" validation'],
[['1234', 'uwei'], 'Invalid value given "uwei". Error: invalid unit.'],
];
Expand Down
9 changes: 6 additions & 3 deletions packages/web3-utils/test/fixtures/string_manipulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ export const padLeftData: [[Numbers, number, string], HexString][] = [
export const padInvalidData: [[any, number, string], string][] = [
[[9.5, 64, 'f'], 'value "9.5" at "/0" must pass "int" validation'],
// Using "null" value intentionally for validation
// eslint-disable-next-line no-null/no-null
[[null, 8, '0'], 'Web3 validator found 1 error[s]:\nvalue at "/0" must pass "int" validation'],
[
// eslint-disable-next-line no-null/no-null
[null, 8, '0'],
'Web3 validator found 1 error[s]:\nvalue "null" at "/0" must pass "int" validation',
],
[[undefined, 8, '0'], 'Web3 validator found 1 error[s]:\nvalue at "/0" is required'],
[[{}, 3, 'f'], 'value "[object Object]" at "/0" must pass "int" validation'],
[[{}, 3, 'f'], 'value "{}" at "/0" must pass "int" validation'],
];

export const padRightData: [[Numbers, number, string], HexString][] = [
Expand Down
13 changes: 13 additions & 0 deletions packages/web3-validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,16 @@ Documentation:
- Dependencies updated

## [Unreleased]

### Changed

- Replace `is-my-json-valid` with `zod` dependency. Related code was changed (#6264)
- Types `ValidationError` and `JsonSchema` were changed (#6264)

### Removed

- Type `RawValidationError` was removed (#6264)

### Added

- Added `json-schema` as a main json schema type (#6264)
4 changes: 2 additions & 2 deletions packages/web3-validator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@
},
"dependencies": {
"ethereum-cryptography": "^2.0.0",
"is-my-json-valid": "^2.20.6",
"util": "^0.12.5",
"web3-errors": "^1.0.2",
"web3-types": "^1.0.2"
"web3-types": "^1.0.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/jest": "^28.1.6",
Expand Down
20 changes: 1 addition & 19 deletions packages/web3-validator/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
import { BaseWeb3Error, ERR_VALIDATION } from 'web3-errors';
import { Web3ValidationErrorObject } from 'web3-types';

import { isNullish } from './validation/object.js';

const errorFormatter = (error: Web3ValidationErrorObject): string => {
if (error.message && error.instancePath && error.params && !isNullish(error.params.value)) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
return `value "${(error.params as { value: unknown }).value}" at "${error.instancePath}" ${
error.message
}`;
}

if (error.message && error.instancePath) {
return `value at "${error.instancePath}" ${error.message}`;
}

if (error.instancePath) {
return `value at "${error.instancePath}" caused unspecified error`;
}

if (error.message) {
return error.message;
}
Expand All @@ -58,7 +41,6 @@ export class Web3ValidatorError extends BaseWeb3Error {
}

private _compileErrors(): string[] {
const errorMsgs = this.errors.map(errorFormatter);
return errorMsgs;
return this.errors.map(errorFormatter);
}
}
4 changes: 2 additions & 2 deletions packages/web3-validator/src/formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
import { Filter } from 'web3-types';
import { ValidInputTypes } from './types.js';
import { isAddress } from './validation/address.js';
import { isBlockNumber,isBlockNumberOrTag,
isBlockTag, } from './validation/block.js';
import { isBlockNumber, isBlockNumberOrTag, isBlockTag } from './validation/block.js';
import { isBloom } from './validation/bloom.js';
import { isBoolean } from './validation/boolean.js';
import { isBytes } from './validation/bytes.js';
Expand Down Expand Up @@ -52,5 +51,6 @@ for (let size = 1; size <= 32; size += 1) {
formats[`bytes${size}`] = data =>
isBytes(data as ValidInputTypes | Uint8Array | number[], { size });
}
formats.bytes256 = formats.bytes;

export default formats;
24 changes: 9 additions & 15 deletions packages/web3-validator/src/types.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 { AbiParameter } from 'web3-types';
import { ValidationError } from 'is-my-json-valid';
import { ZodIssueBase } from 'zod';

export type ValidInputTypes = Uint8Array | bigint | string | number | boolean;
export type EthBaseTypes = 'bool' | 'bytes' | 'string' | 'uint' | 'int' | 'address' | 'tuple';
Expand Down Expand Up @@ -44,22 +44,23 @@ export type EthExtendedTypes =

export type FullValidationSchema = ReadonlyArray<AbiParameter>;
export type ShortValidationSchema = ReadonlyArray<
| string
| EthBaseTypes
| EthExtendedTypes
| EthBaseTypesWithMeta
| EthBaseTypesWithMeta
| ShortValidationSchema
string | EthBaseTypes | EthExtendedTypes | EthBaseTypesWithMeta | ShortValidationSchema
>;
export type ValidationSchemaInput = FullValidationSchema | ShortValidationSchema;

export type Web3ValidationOptions = {
readonly silent: boolean;
};

// is-my-json-valid types
export type Json = string | number | boolean | Array<Json> | { [id: string]: Json };

export type ValidationError = ZodIssueBase;

export interface Validate {
(value: Json): boolean;
errors?: ValidationError[];
}

export type Schema = {
// version
$schema?: string;
Expand Down Expand Up @@ -141,12 +142,5 @@ export type Schema = {
readonly eth?: string;
items?: Schema | Schema[];
};
export interface Validate {
(value: Json): boolean;
errors?: ValidationError[];
}
export type RawValidationError = ValidationError & {
schemaPath: string[];
};

export type JsonSchema = Schema;
Loading

0 comments on commit b93934a

Please sign in to comment.