forked from NomicFoundation/hardhat
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request NomicFoundation#1366 from nomiclabs/cleanup-jsonrp…
…c-input-types Cleanup JSON-RPC related types
- Loading branch information
Showing
78 changed files
with
3,565 additions
and
2,287 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
packages/hardhat-core/src/internal/core/jsonrpc/types/base-types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { BN, bufferToHex, isValidAddress, toBuffer } from "ethereumjs-util"; | ||
import * as t from "io-ts"; | ||
|
||
import { assertHardhatInvariant, HardhatError } from "../../errors"; | ||
import { ERRORS } from "../../errors-list"; | ||
|
||
const ADDRESS_LENGTH_BYTES = 20; | ||
const HASH_LENGTH_BYTES = 32; | ||
|
||
export const rpcQuantity = new t.Type<BN>( | ||
"QUANTITY", | ||
BN.isBN, | ||
(u, c) => | ||
isRpcQuantityString(u) ? t.success(new BN(toBuffer(u))) : t.failure(u, c), | ||
t.identity | ||
); | ||
|
||
export const rpcData = new t.Type<Buffer>( | ||
"DATA", | ||
Buffer.isBuffer, | ||
(u, c) => (isRpcDataString(u) ? t.success(toBuffer(u)) : t.failure(u, c)), | ||
t.identity | ||
); | ||
|
||
export const rpcHash = new t.Type<Buffer>( | ||
"HASH", | ||
(v): v is Buffer => Buffer.isBuffer(v) && v.length === HASH_LENGTH_BYTES, | ||
(u, c) => (isRpcHashString(u) ? t.success(toBuffer(u)) : t.failure(u, c)), | ||
t.identity | ||
); | ||
|
||
export const rpcAddress = new t.Type<Buffer>( | ||
"ADDRESS", | ||
(v): v is Buffer => Buffer.isBuffer(v) && v.length === ADDRESS_LENGTH_BYTES, | ||
(u, c) => (isRpcAddressString(u) ? t.success(toBuffer(u)) : t.failure(u, c)), | ||
t.identity | ||
); | ||
|
||
export const rpcUnsignedInteger = new t.Type<number>( | ||
"Unsigned integer", | ||
isInteger, | ||
(u, c) => (isInteger(u) && u >= 0 ? t.success(u) : t.failure(u, c)), | ||
t.identity | ||
); | ||
|
||
// Conversion functions | ||
|
||
/** | ||
* Transforms a QUANTITY into a number. It should only be used if you are 100% sure that the value | ||
* fits in a number. | ||
*/ | ||
export function rpcQuantityToNumber(quantity: string): number { | ||
return rpcQuantityToBN(quantity).toNumber(); | ||
} | ||
|
||
export function rpcQuantityToBN(quantity: string): BN { | ||
// We validate it in case a value gets here through a cast or any | ||
if (!isRpcQuantityString(quantity)) { | ||
throw new HardhatError(ERRORS.NETWORK.INVALID_RPC_QUANTITY_VALUE, { | ||
value: quantity, | ||
}); | ||
} | ||
|
||
const buffer = toBuffer(quantity); | ||
return new BN(buffer); | ||
} | ||
|
||
export function numberToRpcQuantity(n: number | BN): string { | ||
assertHardhatInvariant( | ||
typeof n === "number" || BN.isBN(n), | ||
"Expected number" | ||
); | ||
|
||
return `0x${n.toString(16)}`; | ||
} | ||
|
||
/** | ||
* Transforms a DATA into a number. It should only be used if you are 100% sure that the data | ||
* represents a value fits in a number. | ||
*/ | ||
export function rpcDataToNumber(data: string): number { | ||
return rpcDataToBN(data).toNumber(); | ||
} | ||
|
||
export function rpcDataToBN(data: string): BN { | ||
return new BN(rpcDataToBuffer(data)); | ||
} | ||
|
||
export function bufferToRpcData( | ||
buffer: Buffer, | ||
padToBytes: number = 0 | ||
): string { | ||
let s = bufferToHex(buffer); | ||
if (padToBytes > 0 && s.length < padToBytes * 2 + 2) { | ||
s = `0x${"0".repeat(padToBytes * 2 + 2 - s.length)}${s.slice(2)}`; | ||
} | ||
return s; | ||
} | ||
|
||
export function rpcDataToBuffer(data: string): Buffer { | ||
// We validate it in case a value gets here through a cast or any | ||
if (!isRpcDataString(data)) { | ||
throw new HardhatError(ERRORS.NETWORK.INVALID_RPC_DATA_VALUE, { | ||
value: data, | ||
}); | ||
} | ||
|
||
return toBuffer(data); | ||
} | ||
|
||
// Type guards | ||
|
||
function isRpcQuantityString(u: unknown): u is string { | ||
return ( | ||
typeof u === "string" && | ||
u.match(/^0x(?:0|(?:[1-9a-fA-F][0-9a-fA-F]*))$/) !== null | ||
); | ||
} | ||
|
||
function isRpcDataString(u: unknown): u is string { | ||
return typeof u === "string" && u.match(/^0x(?:[0-9a-fA-F]{2})*$/) !== null; | ||
} | ||
|
||
function isRpcHashString(u: unknown): u is string { | ||
return typeof u === "string" && u.length === 66 && isRpcDataString(u); | ||
} | ||
|
||
function isRpcAddressString(u: unknown): u is string { | ||
return typeof u === "string" && isValidAddress(u); | ||
} | ||
|
||
function isInteger(num: unknown): num is number { | ||
return Number.isInteger(num); | ||
} |
42 changes: 42 additions & 0 deletions
42
packages/hardhat-core/src/internal/core/jsonrpc/types/input/blockTag.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import * as t from "io-ts"; | ||
|
||
import { optional } from "../../../../util/io-ts"; | ||
import { rpcData, rpcQuantity } from "../base-types"; | ||
|
||
export const rpcNewBlockTagObjectWithNumber = t.type({ | ||
blockNumber: rpcQuantity, | ||
}); | ||
|
||
export const rpcNewBlockTagObjectWithHash = t.type({ | ||
blockHash: rpcData, | ||
requireCanonical: optional(t.boolean), | ||
}); | ||
|
||
export const rpcBlockTagName = t.keyof({ | ||
earliest: null, | ||
latest: null, | ||
pending: null, | ||
}); | ||
|
||
// This is the new kind of block tag as defined by https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1898.md | ||
export const rpcNewBlockTag = t.union([ | ||
rpcQuantity, | ||
rpcNewBlockTagObjectWithNumber, | ||
rpcNewBlockTagObjectWithHash, | ||
rpcBlockTagName, | ||
]); | ||
|
||
export type RpcNewBlockTag = t.TypeOf<typeof rpcNewBlockTag>; | ||
|
||
export const optionalRpcNewBlockTag = optional(rpcNewBlockTag); | ||
|
||
export type OptionalRpcNewBlockTag = t.TypeOf<typeof optionalRpcNewBlockTag>; | ||
|
||
// This is the old kind of block tag which is described in the ethereum wiki | ||
export const rpcOldBlockTag = t.union([rpcQuantity, rpcBlockTagName]); | ||
|
||
export type RpcOldBlockTag = t.TypeOf<typeof rpcOldBlockTag>; | ||
|
||
export const optionalRpcOldBlockTag = optional(rpcOldBlockTag); | ||
|
||
export type OptionalRpcOldBlockTag = t.TypeOf<typeof optionalRpcOldBlockTag>; |
31 changes: 31 additions & 0 deletions
31
packages/hardhat-core/src/internal/core/jsonrpc/types/input/callRequest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import * as t from "io-ts"; | ||
|
||
import { optional } from "../../../../util/io-ts"; | ||
import { rpcAddress, rpcData, rpcQuantity } from "../base-types"; | ||
|
||
// Type used by eth_call and eth_estimateGas | ||
// TODO: Update to Berlin | ||
export const rpcCallRequest = t.type( | ||
{ | ||
from: optional(rpcAddress), | ||
to: optional(rpcAddress), | ||
gas: optional(rpcQuantity), | ||
gasPrice: optional(rpcQuantity), | ||
value: optional(rpcQuantity), | ||
data: optional(rpcData), | ||
}, | ||
"RpcCallRequest" | ||
); | ||
|
||
// This type represents possibly valid inputs to rpcCallRequest. | ||
// TODO: It can probably be inferred by io-ts. | ||
export interface RpcCallRequestInput { | ||
from?: string; | ||
to: string; | ||
gas?: string; | ||
gasPrice?: string; | ||
value?: string; | ||
data?: string; | ||
} | ||
|
||
export type RpcCallRequest = t.TypeOf<typeof rpcCallRequest>; |
27 changes: 27 additions & 0 deletions
27
packages/hardhat-core/src/internal/core/jsonrpc/types/input/filterRequest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import * as t from "io-ts"; | ||
|
||
import { optional } from "../../../../util/io-ts"; | ||
import { rpcHash } from "../base-types"; | ||
|
||
import { optionalRpcOldBlockTag } from "./blockTag"; | ||
import { optionalRpcLogAddress } from "./logAddress"; | ||
import { optionalRpcLogTopics } from "./logTopics"; | ||
|
||
export const rpcFilterRequest = t.type( | ||
{ | ||
fromBlock: optionalRpcOldBlockTag, | ||
toBlock: optionalRpcOldBlockTag, | ||
address: optionalRpcLogAddress, | ||
topics: optionalRpcLogTopics, | ||
blockHash: optional(rpcHash), | ||
}, | ||
"RpcFilterRequest" | ||
); | ||
|
||
export type RpcFilterRequest = t.TypeOf<typeof rpcFilterRequest>; | ||
|
||
export const optionalRpcFilterRequest = optional(rpcFilterRequest); | ||
|
||
export type OptionalRpcFilterRequest = t.TypeOf< | ||
typeof optionalRpcFilterRequest | ||
>; |
53 changes: 53 additions & 0 deletions
53
packages/hardhat-core/src/internal/core/jsonrpc/types/input/hardhat-network.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import * as t from "io-ts"; | ||
|
||
import { optional } from "../../../../util/io-ts"; | ||
import { rpcUnsignedInteger } from "../base-types"; | ||
|
||
export const rpcForkConfig = optional( | ||
t.type( | ||
{ | ||
jsonRpcUrl: t.string, | ||
blockNumber: optional(t.number), | ||
}, | ||
"RpcForkConfig" | ||
) | ||
); | ||
|
||
export type RpcForkConfig = t.TypeOf<typeof rpcForkConfig>; | ||
|
||
export const rpcHardhatNetworkConfig = t.type( | ||
{ | ||
forking: optional(rpcForkConfig), | ||
}, | ||
"HardhatNetworkConfig" | ||
); | ||
|
||
export type RpcHardhatNetworkConfig = t.TypeOf<typeof rpcHardhatNetworkConfig>; | ||
|
||
export const optionalRpcHardhatNetworkConfig = optional( | ||
rpcHardhatNetworkConfig | ||
); | ||
|
||
const isNumberPair = (x: unknown): x is [number, number] => | ||
Array.isArray(x) && | ||
x.length === 2 && | ||
Number.isInteger(x[0]) && | ||
Number.isInteger(x[1]); | ||
|
||
// TODO: This can be simplified | ||
const rpcIntervalMiningRange = new t.Type<[number, number]>( | ||
"Interval mining range", | ||
isNumberPair, | ||
(u, c) => | ||
isNumberPair(u) && u[0] >= 0 && u[1] >= u[0] | ||
? t.success(u) | ||
: t.failure(u, c), | ||
t.identity | ||
); | ||
|
||
export const rpcIntervalMining = t.union([ | ||
rpcUnsignedInteger, | ||
rpcIntervalMiningRange, | ||
]); | ||
|
||
export type RpcIntervalMining = t.TypeOf<typeof rpcIntervalMining>; |
12 changes: 12 additions & 0 deletions
12
packages/hardhat-core/src/internal/core/jsonrpc/types/input/logAddress.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import * as t from "io-ts"; | ||
|
||
import { optional } from "../../../../util/io-ts"; | ||
import { rpcAddress } from "../base-types"; | ||
|
||
export const rpcLogAddress = t.union([rpcAddress, t.array(rpcAddress)]); | ||
|
||
export type RpcLogAddress = t.TypeOf<typeof rpcLogAddress>; | ||
|
||
export const optionalRpcLogAddress = optional(rpcLogAddress); | ||
|
||
export type OptionalRpcLogAddress = t.TypeOf<typeof optionalRpcLogAddress>; |
14 changes: 14 additions & 0 deletions
14
packages/hardhat-core/src/internal/core/jsonrpc/types/input/logTopics.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import * as t from "io-ts"; | ||
|
||
import { optional } from "../../../../util/io-ts"; | ||
import { rpcHash } from "../base-types"; | ||
|
||
export const rpcLogTopics = t.array( | ||
t.union([t.null, rpcHash, t.array(t.union([t.null, rpcHash]))]) | ||
); | ||
|
||
export type RpcLogTopics = t.TypeOf<typeof rpcLogTopics>; | ||
|
||
export const optionalRpcLogTopics = optional(rpcLogTopics); | ||
|
||
export type OptionalRpcLogTopics = t.TypeOf<typeof optionalRpcLogTopics>; |
Oops, something went wrong.