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

util: revert some PrefixedHexString breaking changes #3427

Merged
merged 8 commits into from
May 14, 2024
4 changes: 2 additions & 2 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
getProvider,
hexToBytes,
intToHex,
isHexPrefixed,
isHexString,
} from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak.js'

Expand Down Expand Up @@ -370,7 +370,7 @@ export class Block {
params: [bigIntToHex(blockTag), true],
})
} else if (
isHexPrefixed(blockTag) ||
isHexString(blockTag) ||
blockTag === 'latest' ||
blockTag === 'earliest' ||
blockTag === 'pending' ||
Expand Down
8 changes: 4 additions & 4 deletions packages/block/test/block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ describe('[Block]: block functions', () => {

it('should test block validation on pow chain', async () => {
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul })
const blockRlp = toBytes(testDataPreLondon.blocks[0].rlp as PrefixedHexString)
const blockRlp = hexToBytes(testDataPreLondon.blocks[0].rlp as PrefixedHexString)
try {
Block.fromRLPSerializedBlock(blockRlp, { common })
assert.ok(true, 'should pass')
Expand All @@ -180,7 +180,7 @@ describe('[Block]: block functions', () => {
}

it('should test transaction validation - invalid tx trie', async () => {
const blockRlp = toBytes(testDataPreLondon.blocks[0].rlp as PrefixedHexString)
const blockRlp = hexToBytes(testDataPreLondon.blocks[0].rlp as PrefixedHexString)
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
const block = Block.fromRLPSerializedBlock(blockRlp, { common, freeze: false })
await testTransactionValidation(block)
Expand Down Expand Up @@ -221,7 +221,7 @@ describe('[Block]: block functions', () => {

it('should test transaction validation with legacy tx in london', async () => {
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
const blockRlp = toBytes(testDataPreLondon.blocks[0].rlp as PrefixedHexString)
const blockRlp = hexToBytes(testDataPreLondon.blocks[0].rlp as PrefixedHexString)
const block = Block.fromRLPSerializedBlock(blockRlp, { common, freeze: false })
await testTransactionValidation(block)
;(block.transactions[0] as any).gasPrice = BigInt(0)
Expand All @@ -234,7 +234,7 @@ describe('[Block]: block functions', () => {

it('should test uncles hash validation', async () => {
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul })
const blockRlp = toBytes(testDataPreLondon2.blocks[2].rlp as PrefixedHexString)
const blockRlp = hexToBytes(testDataPreLondon2.blocks[2].rlp as PrefixedHexString)
const block = Block.fromRLPSerializedBlock(blockRlp, { common, freeze: false })
assert.equal(block.uncleHashIsValid(), true)
;(block.header as any).uncleHash = new Uint8Array(32)
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/rpc/modules/engine/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -927,8 +927,8 @@ export class Engine {
const { headBlockHash, finalizedBlockHash, safeBlockHash } = params[0]
const payloadAttributes = params[1]

const safe = toBytes(safeBlockHash)
const finalized = toBytes(finalizedBlockHash)
const safe = hexToBytes(safeBlockHash)
const finalized = hexToBytes(finalizedBlockHash)

if (!equalsBytes(finalized, zeroBlockHash) && equalsBytes(safe, zeroBlockHash)) {
throw {
Expand Down
6 changes: 3 additions & 3 deletions packages/common/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { intToHex, isHexPrefixed, stripHexPrefix } from '@ethereumjs/util'
import { intToHex, isHexString, stripHexPrefix } from '@ethereumjs/util'

import { Hardfork } from './enums.js'

Expand All @@ -16,7 +16,7 @@ function formatNonce(nonce: string): PrefixedHexString {
if (!nonce || nonce === '0x0') {
return '0x0000000000000000'
}
if (isHexPrefixed(nonce)) {
if (isHexString(nonce)) {
return `0x${stripHexPrefix(nonce).padStart(16, '0')}`
}
return `0x${nonce.padStart(16, '0')}`
Expand Down Expand Up @@ -67,7 +67,7 @@ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) {
unparsedExtraData === '' ? '0x' : (unparsedExtraData as PrefixedHexString)

// geth may use number for timestamp
const timestamp: PrefixedHexString = isHexPrefixed(unparsedTimestamp)
const timestamp: PrefixedHexString = isHexString(unparsedTimestamp)
? unparsedTimestamp
: intToHex(parseInt(unparsedTimestamp))

Expand Down
4 changes: 2 additions & 2 deletions packages/devp2p/src/protocol/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
bytesToUnprefixedHex,
hexToBytes,
intToBytes,
isHexPrefixed,
isHexString,
} from '@ethereumjs/util'
import * as snappy from 'snappyjs'

Expand Down Expand Up @@ -286,7 +286,7 @@ export class ETH extends Protocol {
this._latestBlock = latestBlock
}
const forkHashB = hexToBytes(
isHexPrefixed(this._forkHash) ? this._forkHash : `0x${this._forkHash}`
isHexString(this._forkHash) ? this._forkHash : `0x${this._forkHash}`
)

const nextForkB =
Expand Down
6 changes: 3 additions & 3 deletions packages/rlp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ function padToEven(a: string): string {
}

/** Check if a string is prefixed by 0x */
function isHexPrefixed(str: string): boolean {
function isHexString(str: string): boolean {
return str.length >= 2 && str[0] === '0' && str[1] === 'x'
}

Expand All @@ -262,7 +262,7 @@ function stripHexPrefix(str: string): string {
if (typeof str !== 'string') {
return str
}
return isHexPrefixed(str) ? str.slice(2) : str
return isHexString(str) ? str.slice(2) : str
}

/** Transform anything into a Uint8Array */
Expand All @@ -271,7 +271,7 @@ function toBytes(v: Input): Uint8Array {
return v
}
if (typeof v === 'string') {
if (isHexPrefixed(v)) {
if (isHexString(v)) {
return hexToBytes(padToEven(stripHexPrefix(v)))
}
return utf8ToBytes(v)
Expand Down
11 changes: 5 additions & 6 deletions packages/trie/src/util/genesisState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { RLP } from '@ethereumjs/rlp'
import {
Account,
hexToBytes,
isHexPrefixed,
toBytes,
isHexString,
unpadBytes,
unprefixedHexToBytes,
} from '@ethereumjs/util'
Expand All @@ -19,7 +18,7 @@ import type { AccountState, GenesisState } from '@ethereumjs/util'
export async function genesisStateRoot(genesisState: GenesisState) {
const trie = new Trie({ useKeyHashing: true })
for (const [key, value] of Object.entries(genesisState)) {
const address = isHexPrefixed(key) ? hexToBytes(key) : unprefixedHexToBytes(key)
const address = isHexString(key) ? hexToBytes(key) : unprefixedHexToBytes(key)
const account = new Account()
if (typeof value === 'string') {
account.balance = BigInt(value)
Expand All @@ -29,15 +28,15 @@ export async function genesisStateRoot(genesisState: GenesisState) {
account.balance = BigInt(balance)
}
if (code !== undefined) {
const codeBytes = isHexPrefixed(code) ? toBytes(code) : unprefixedHexToBytes(code)
const codeBytes = isHexString(code) ? hexToBytes(code) : unprefixedHexToBytes(code)
account.codeHash = keccak256(codeBytes)
}
if (storage !== undefined) {
const storageTrie = new Trie({ useKeyHashing: true })
for (const [k, val] of storage) {
const storageKey = isHexPrefixed(k) ? toBytes(k) : unprefixedHexToBytes(k)
const storageKey = isHexString(k) ? hexToBytes(k) : unprefixedHexToBytes(k)
const storageVal = RLP.encode(
unpadBytes(isHexPrefixed(val) ? toBytes(val) : unprefixedHexToBytes(val))
unpadBytes(isHexString(val) ? hexToBytes(val) : unprefixedHexToBytes(val))
)
await storageTrie.put(storageKey, storageVal)
}
Expand Down
6 changes: 3 additions & 3 deletions packages/trie/test/official.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { bytesToHex, hexToBytes, isHexPrefixed, utf8ToBytes } from '@ethereumjs/util'
import { bytesToHex, hexToBytes, isHexString, utf8ToBytes } from '@ethereumjs/util'
import { assert, describe, it } from 'vitest'

import { Trie } from '../src/index.js'
Expand Down Expand Up @@ -41,13 +41,13 @@ describe('official tests any order', async () => {
for (key of keys) {
let val = test.in[key]

if (typeof key === 'string' && isHexPrefixed(key)) {
if (typeof key === 'string' && isHexString(key)) {
key = hexToBytes(key)
} else if (typeof key === 'string') {
key = utf8ToBytes(key)
}

if (typeof val === 'string' && isHexPrefixed(val)) {
if (typeof val === 'string' && isHexString(val)) {
val = hexToBytes(val)
} else if (typeof val === 'string') {
val = utf8ToBytes(val)
Expand Down
4 changes: 2 additions & 2 deletions packages/util/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Genesis related interfaces and helpers.

### Module: [internal](src/internal.ts)

Internalized simple helper methods like `isHexPrefixed`. Note that methods from this module might get deprectared in the future.
Internalized simple helper methods like `isHexString`. Note that methods from this module might get deprecated in the future.

### Module: [kzg](src/kzg.ts)

Expand Down Expand Up @@ -257,7 +257,7 @@ The following methods are available by an internalized version of the [ethjs-uti
- arrayContainsArray
- getBinarySize
- stripHexPrefix
- isHexPrefixed
- isHexString
- isHexString
- padToEven
- fromAscii
Expand Down
19 changes: 11 additions & 8 deletions packages/util/src/bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getRandomBytesSync } from 'ethereum-cryptography/random.js'
import { bytesToHex as _bytesToUnprefixedHex } from 'ethereum-cryptography/utils.js'

import { assertIsArray, assertIsBytes, assertIsHexString } from './helpers.js'
import { isHexPrefixed, isHexString, padToEven, stripHexPrefix } from './internal.js'
import { isHexString, padToEven, stripHexPrefix } from './internal.js'

import type { PrefixedHexString, TransformabletoBytes } from './types.js'

Expand Down Expand Up @@ -107,13 +107,14 @@ export const bytesToInt = (bytes: Uint8Array): number => {
return res
}

// TODO: Restrict the input type to only PrefixedHexString
/**
* Converts a {@link PrefixedHexString} to a {@link Uint8Array}
* @param {PrefixedHexString} hex The 0x-prefixed hex string to convert
* @param {PrefixedHexString | string} hex The 0x-prefixed hex string to convert
* @returns {Uint8Array} The converted bytes
* @throws If the input is not a valid 0x-prefixed hex string
*/
export const hexToBytes = (hex: PrefixedHexString): Uint8Array => {
export const hexToBytes = (hex: PrefixedHexString | string): Uint8Array => {
if (typeof hex !== 'string') {
throw new Error(`hex argument type ${typeof hex} must be of type string`)
}
Expand Down Expand Up @@ -256,12 +257,13 @@ export const unpadArray = (a: number[]): number[] => {
return stripZeros(a)
}

// TODO: Restrict the input type to only PrefixedHexString
/**
* Trims leading zeros from a `PrefixedHexString`.
* @param {PrefixedHexString} a
* @param {PrefixedHexString | string} a
* @return {PrefixedHexString}
*/
export const unpadHex = (a: PrefixedHexString): PrefixedHexString => {
export const unpadHex = (a: PrefixedHexString | string): PrefixedHexString => {
assertIsHexString(a)
return `0x${stripZeros(stripHexPrefix(a))}`
}
Expand Down Expand Up @@ -353,7 +355,7 @@ export const addHexPrefix = (str: string): PrefixedHexString => {
return str
}

return isHexPrefixed(str) ? str : `0x${str}`
return isHexString(str) ? str : `0x${str}`
}

/**
Expand Down Expand Up @@ -540,6 +542,7 @@ export function bigInt64ToBytes(value: bigint, littleEndian: boolean = false): U
// eslint-disable-next-line no-restricted-imports
export { bytesToUtf8, equalsBytes, utf8ToBytes } from 'ethereum-cryptography/utils.js'

export function hexToBigInt(input: PrefixedHexString): bigint {
return bytesToBigInt(hexToBytes(input))
// TODO: Restrict the input type to only PrefixedHexString
export function hexToBigInt(input: PrefixedHexString | string): bigint {
return bytesToBigInt(hexToBytes(isHexString(input) ? input : `0x${input}`))
}
4 changes: 2 additions & 2 deletions packages/util/src/genesis.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { addHexPrefix, bigIntToHex } from './bytes.js'
import { isHexPrefixed } from './internal.js'
import { isHexString } from './internal.js'

import type { PrefixedHexString } from './types.js'

Expand Down Expand Up @@ -50,7 +50,7 @@ export function parseGethGenesisState(json: any) {
let { balance, code, storage, nonce } = json.alloc[address]
// create a map with lowercase for easy lookups
const prefixedAddress = addHexPrefix(address.toLowerCase())
balance = isHexPrefixed(balance) ? balance : bigIntToHex(BigInt(balance))
balance = isHexString(balance) ? balance : bigIntToHex(BigInt(balance))
code = code !== undefined ? addHexPrefix(code) : undefined
storage = storage !== undefined ? Object.entries(storage) : undefined
nonce = nonce !== undefined ? addHexPrefix(nonce) : undefined
Expand Down
1 change: 0 additions & 1 deletion packages/util/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export {
fromUtf8,
getBinarySize,
getKeys,
isHexPrefixed,
isHexString,
padToEven,
stripHexPrefix,
Expand Down
35 changes: 10 additions & 25 deletions packages/util/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ import { bytesToUnprefixedHex, utf8ToBytes } from './bytes.js'
import type { PrefixedHexString } from './types.js'

/**
* Returns a `Boolean` on whether or not the a `String` starts with '0x'
* @param str the string input value
* @return a boolean if it is or is not hex prefixed
* @throws if the str input is not a string
* Returns a boolean on whether or not the the input starts with '0x' and matches the optional length
* @param {string} value the string input value
* @param {number|undefined} length the optional length of the hex string in bytes
* @returns {boolean} Whether or not the string is a valid PrefixedHexString matching the optional length
*/
export function isHexPrefixed(str: string): str is PrefixedHexString {
if (typeof str !== 'string') {
throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`)
}
export function isHexString(value: string, length?: number): value is PrefixedHexString {
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) return false
scorbajio marked this conversation as resolved.
Show resolved Hide resolved

return str[0] === '0' && str[1] === 'x'
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) return false

return true
}

/**
Expand All @@ -49,7 +49,7 @@ export const stripHexPrefix = (str: string): string => {
if (typeof str !== 'string')
throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`)

return isHexPrefixed(str) ? str.slice(2) : str
return isHexString(str) ? str.slice(2) : str
}

/**
Expand Down Expand Up @@ -197,18 +197,3 @@ export function getKeys(params: Record<string, string>[], key: string, allowEmpt

return result
}

/**
* Is the string a hex string.
*
* @param value
* @param length
* @returns output the string is a hex string
*/
export function isHexString(value: string, length?: number): value is PrefixedHexString {
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) return false

if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) return false

return true
}
24 changes: 6 additions & 18 deletions packages/util/test/internal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
fromUtf8,
getBinarySize,
getKeys,
isHexPrefixed,
isHexString,
padToEven,
stripHexPrefix,
Expand All @@ -18,9 +17,12 @@ import {
const buf = utf8ToBytes('hello')

describe('internal', () => {
it('isHexPrefixed', () => {
assert.equal(isHexPrefixed('0xabc'), true)
assert.equal(isHexPrefixed('abc'), false)
it('isHexString', () => {
assert.isTrue(isHexString('0x123'))
assert.isTrue(isHexString('0xabc'))
assert.isFalse(isHexString('abc'))
assert.isFalse(isHexString('123'))
assert.isTrue(isHexString('0x0000000000000000000000000000000000000000'))
})
it('stripHexPrefix', () => {
assert.equal(stripHexPrefix('0xabc'), 'abc')
Expand Down Expand Up @@ -65,20 +67,6 @@ describe('internal', () => {
['', '3']
)
})
it('isHexString', () => {
assert.equal(isHexString('0x0000000000000000000000000000000000000000'), true)
assert.equal(isHexString('123'), false)
})

describe('isHexPrefixed', () => {
it('should return true for hex-prefixed string', () => {
assert.isTrue(isHexPrefixed('0x123'))
})

it('should return false for non-hex-prefixed string', () => {
assert.isFalse(isHexPrefixed('123'))
})
})

describe('padToEven', () => {
it('should pad odd-length string to even', () => {
Expand Down
Loading
Loading