From 657cdad0eb9f52a77fd8b368471a54539adbeb4e Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sat, 28 Sep 2024 17:01:15 -0400 Subject: [PATCH 1/2] monorepo: remove redundant fills and zeros function (#3709) --- packages/block/src/header/header.ts | 17 ++++--- packages/block/test/block.spec.ts | 27 +++++------ packages/block/test/eip4788block.spec.ts | 8 ++-- packages/block/test/eip4895block.spec.ts | 9 ++-- packages/block/test/header.spec.ts | 45 +++++++++---------- packages/block/test/mergeBlock.spec.ts | 9 ++-- packages/client/src/miner/pendingBlock.ts | 9 ++-- .../client/src/rpc/modules/engine/engine.ts | 9 ++-- packages/client/src/service/skeleton.ts | 3 +- packages/common/test/hardforks.spec.ts | 4 +- packages/ethash/examples/example.ts | 2 +- packages/ethash/src/index.ts | 3 +- packages/evm/src/evm.ts | 3 +- packages/evm/src/interpreter.ts | 2 +- packages/evm/src/types.ts | 4 +- packages/evm/test/runCall.spec.ts | 5 ++- packages/statemanager/src/rpcStateManager.ts | 2 +- .../test/proofStateManager.spec.ts | 9 ++-- .../statemanager/test/stateManager.spec.ts | 3 +- .../test/stateManager.storage.spec.ts | 15 +++---- packages/trie/test/index.spec.ts | 8 +--- packages/util/src/account.ts | 7 +-- packages/util/src/address.ts | 5 +-- packages/util/src/blobs.ts | 2 +- packages/util/src/bytes.ts | 13 +----- packages/util/test/bytes.spec.ts | 13 +----- packages/verkle/src/verkleTree.ts | 3 +- packages/verkle/test/proof.spec.ts | 2 +- packages/vm/src/bloom/index.ts | 3 +- packages/vm/src/buildBlock.ts | 5 +-- .../eip-2935-historical-block-hashes.spec.ts | 5 +-- .../test/api/EIPs/eip-4788-beaconroot.spec.ts | 3 +- .../vm/test/api/EIPs/eip-4844-blobs.spec.ts | 3 +- .../api/EIPs/eip-4895-withdrawals.spec.ts | 7 ++- packages/vm/test/api/EIPs/eip-7002.spec.ts | 5 +-- packages/vm/test/api/EIPs/eip-7702.spec.ts | 3 +- packages/vm/test/api/bloom.spec.ts | 5 +-- packages/vm/test/api/runBlock.spec.ts | 3 +- packages/vm/test/api/runTx.spec.ts | 3 +- packages/vm/test/t8n/t8ntool.ts | 13 ++---- 40 files changed, 116 insertions(+), 183 deletions(-) diff --git a/packages/block/src/header/header.ts b/packages/block/src/header/header.ts index 9f24919f56..79675dafed 100644 --- a/packages/block/src/header/header.ts +++ b/packages/block/src/header/header.ts @@ -17,7 +17,6 @@ import { equalsBytes, hexToBytes, toType, - zeros, } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak.js' @@ -106,21 +105,21 @@ export class BlockHeader { const skipValidateConsensusFormat = opts.skipConsensusFormatValidation ?? false const defaults = { - parentHash: zeros(32), + parentHash: new Uint8Array(32), uncleHash: KECCAK256_RLP_ARRAY, coinbase: createZeroAddress(), - stateRoot: zeros(32), + stateRoot: new Uint8Array(32), transactionsTrie: KECCAK256_RLP, receiptTrie: KECCAK256_RLP, - logsBloom: zeros(256), + logsBloom: new Uint8Array(256), difficulty: BIGINT_0, number: BIGINT_0, gasLimit: DEFAULT_GAS_LIMIT, gasUsed: BIGINT_0, timestamp: BIGINT_0, extraData: new Uint8Array(0), - mixHash: zeros(32), - nonce: zeros(8), + mixHash: new Uint8Array(32), + nonce: new Uint8Array(8), } const parentHash = toType(headerData.parentHash, TypeOutput.Uint8Array) ?? defaults.parentHash @@ -161,7 +160,7 @@ export class BlockHeader { withdrawalsRoot: this.common.isActivatedEIP(4895) ? KECCAK256_RLP : undefined, blobGasUsed: this.common.isActivatedEIP(4844) ? BIGINT_0 : undefined, excessBlobGas: this.common.isActivatedEIP(4844) ? BIGINT_0 : undefined, - parentBeaconBlockRoot: this.common.isActivatedEIP(4788) ? zeros(32) : undefined, + parentBeaconBlockRoot: this.common.isActivatedEIP(4788) ? new Uint8Array(32) : undefined, requestsRoot: this.common.isActivatedEIP(7685) ? KECCAK256_RLP : undefined, } @@ -424,8 +423,8 @@ export class BlockHeader { )} (cannot exceed 32 bytes length, received ${extraData.length} bytes)` error = true } - if (!equalsBytes(nonce, zeros(8))) { - errorMsg += `, nonce: ${bytesToHex(nonce)} (expected: ${bytesToHex(zeros(8))})` + if (!equalsBytes(nonce, new Uint8Array(8))) { + errorMsg += `, nonce: ${bytesToHex(nonce)} (expected: ${bytesToHex(new Uint8Array(8))})` error = true } } diff --git a/packages/block/test/block.spec.ts b/packages/block/test/block.spec.ts index 6ad2c932a3..2ae7f1d62a 100644 --- a/packages/block/test/block.spec.ts +++ b/packages/block/test/block.spec.ts @@ -1,14 +1,7 @@ import { Common, Goerli, Hardfork, Mainnet, createCustomCommon } from '@ethereumjs/common' import { RLP } from '@ethereumjs/rlp' import { createLegacyTx } from '@ethereumjs/tx' -import { - KECCAK256_RLP_ARRAY, - bytesToHex, - equalsBytes, - hexToBytes, - toBytes, - zeros, -} from '@ethereumjs/util' +import { KECCAK256_RLP_ARRAY, bytesToHex, equalsBytes, hexToBytes, toBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' import { genTransactionsTrieRoot } from '../src/helpers.js' @@ -76,14 +69,14 @@ describe('[Block]: block functions', () => { headerArray.push(zero) } - // mock header data (if set to zeros(0) header throws) - headerArray[0] = zeros(32) // parentHash - headerArray[2] = zeros(20) // coinbase - headerArray[3] = zeros(32) // stateRoot - headerArray[4] = zeros(32) // transactionsTrie - headerArray[5] = zeros(32) // receiptTrie - headerArray[13] = zeros(32) // mixHash - headerArray[14] = zeros(8) // nonce + // mock header data (if set to new Uint8Array() header throws) + headerArray[0] = new Uint8Array(32) // parentHash + headerArray[2] = new Uint8Array(20) // coinbase + headerArray[3] = new Uint8Array(32) // stateRoot + headerArray[4] = new Uint8Array(32) // transactionsTrie + headerArray[5] = new Uint8Array(32) // receiptTrie + headerArray[13] = new Uint8Array(32) // mixHash + headerArray[14] = new Uint8Array(8) // nonce const valuesArray = [headerArray, [], []] @@ -265,7 +258,7 @@ describe('[Block]: block functions', () => { } } - const zeroRoot = zeros(32) + const zeroRoot = new Uint8Array(32) // Tx root block = createBlock({ diff --git a/packages/block/test/eip4788block.spec.ts b/packages/block/test/eip4788block.spec.ts index 3100c08c76..880066d11e 100644 --- a/packages/block/test/eip4788block.spec.ts +++ b/packages/block/test/eip4788block.spec.ts @@ -1,5 +1,5 @@ import { Common, Hardfork, Mainnet } from '@ethereumjs/common' -import { bytesToHex, zeros } from '@ethereumjs/util' +import { bytesToHex } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' import { createBlock, createBlockHeader } from '../src/index.js' @@ -13,7 +13,7 @@ describe('EIP4788 header tests', () => { () => { createBlockHeader( { - parentBeaconBlockRoot: zeros(32), + parentBeaconBlockRoot: new Uint8Array(32), }, { common: earlyCommon, @@ -45,7 +45,7 @@ describe('EIP4788 header tests', () => { { excessBlobGas: 0n, blobGasUsed: 0n, - parentBeaconBlockRoot: zeros(32), + parentBeaconBlockRoot: new Uint8Array(32), }, { common, @@ -62,7 +62,7 @@ describe('EIP4788 header tests', () => { ) assert.equal( block.toJSON().header?.parentBeaconBlockRoot, - bytesToHex(zeros(32)), + bytesToHex(new Uint8Array(32)), 'JSON output includes excessBlobGas', ) }) diff --git a/packages/block/test/eip4895block.spec.ts b/packages/block/test/eip4895block.spec.ts index 29b8751661..98d2baed05 100644 --- a/packages/block/test/eip4895block.spec.ts +++ b/packages/block/test/eip4895block.spec.ts @@ -6,7 +6,6 @@ import { createWithdrawalFromBytesArray, hexToBytes, randomBytes, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -57,7 +56,7 @@ describe('EIP4895 tests', () => { () => { createBlockHeader( { - withdrawalsRoot: zeros(32), + withdrawalsRoot: new Uint8Array(32), }, { common: earlyCommon, @@ -79,7 +78,7 @@ describe('EIP4895 tests', () => { assert.doesNotThrow(() => { createBlockHeader( { - withdrawalsRoot: zeros(32), + withdrawalsRoot: new Uint8Array(32), }, { common, @@ -116,7 +115,7 @@ describe('EIP4895 tests', () => { createBlock( { header: { - withdrawalsRoot: zeros(32), + withdrawalsRoot: new Uint8Array(32), }, withdrawals: [], }, @@ -128,7 +127,7 @@ describe('EIP4895 tests', () => { const block = createBlock( { header: { - withdrawalsRoot: zeros(32), + withdrawalsRoot: new Uint8Array(32), }, withdrawals: [], }, diff --git a/packages/block/test/header.spec.ts b/packages/block/test/header.spec.ts index 0037e49c9c..dce30df1da 100644 --- a/packages/block/test/header.spec.ts +++ b/packages/block/test/header.spec.ts @@ -8,7 +8,6 @@ import { createZeroAddress, equalsBytes, hexToBytes, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -32,21 +31,21 @@ import type { PrefixedHexString } from '@ethereumjs/util' describe('[Block]: Header functions', () => { it('should create with default constructor', () => { function compareDefaultHeader(header: BlockHeader) { - assert.ok(equalsBytes(header.parentHash, zeros(32))) + assert.ok(equalsBytes(header.parentHash, new Uint8Array(32))) assert.ok(equalsBytes(header.uncleHash, KECCAK256_RLP_ARRAY)) assert.ok(header.coinbase.equals(createZeroAddress())) - assert.ok(equalsBytes(header.stateRoot, zeros(32))) + assert.ok(equalsBytes(header.stateRoot, new Uint8Array(32))) assert.ok(equalsBytes(header.transactionsTrie, KECCAK256_RLP)) assert.ok(equalsBytes(header.receiptTrie, KECCAK256_RLP)) - assert.ok(equalsBytes(header.logsBloom, zeros(256))) + assert.ok(equalsBytes(header.logsBloom, new Uint8Array(256))) assert.equal(header.difficulty, BigInt(0)) assert.equal(header.number, BigInt(0)) assert.equal(header.gasLimit, BigInt('0xffffffffffffff')) assert.equal(header.gasUsed, BigInt(0)) assert.equal(header.timestamp, BigInt(0)) assert.ok(equalsBytes(header.extraData, new Uint8Array(0))) - assert.ok(equalsBytes(header.mixHash, zeros(32))) - assert.ok(equalsBytes(header.nonce, zeros(8))) + assert.ok(equalsBytes(header.mixHash, new Uint8Array(32))) + assert.ok(equalsBytes(header.nonce, new Uint8Array(8))) } const header = createBlockHeader() @@ -137,14 +136,14 @@ describe('[Block]: Header functions', () => { headerArray.push(zero) } - // mock header data (if set to zeros(0) header throws) - headerArray[0] = zeros(32) //parentHash - headerArray[2] = zeros(20) //coinbase - headerArray[3] = zeros(32) //stateRoot - headerArray[4] = zeros(32) //transactionsTrie - headerArray[5] = zeros(32) //receiptTrie - headerArray[13] = zeros(32) // mixHash - headerArray[14] = zeros(8) // nonce + // mock header data (if set to new Uint8Array() header throws) + headerArray[0] = new Uint8Array(32) //parentHash + headerArray[2] = new Uint8Array(20) //coinbase + headerArray[3] = new Uint8Array(32) //stateRoot + headerArray[4] = new Uint8Array(32) //transactionsTrie + headerArray[5] = new Uint8Array(32) //receiptTrie + headerArray[13] = new Uint8Array(32) // mixHash + headerArray[14] = new Uint8Array(8) // nonce let header = createBlockHeaderFromBytesArray(headerArray, { common }) assert.ok(Object.isFrozen(header), 'block should be frozen by default') @@ -159,15 +158,15 @@ describe('[Block]: Header functions', () => { it('Initialization -> createWithdrawalFromBytesArray() -> error cases', () => { const headerArray = Array(22).fill(new Uint8Array(0)) - // mock header data (if set to zeros(0) header throws) - headerArray[0] = zeros(32) //parentHash - headerArray[2] = zeros(20) //coinbase - headerArray[3] = zeros(32) //stateRoot - headerArray[4] = zeros(32) //transactionsTrie - headerArray[5] = zeros(32) //receiptTrie - headerArray[13] = zeros(32) // mixHash - headerArray[14] = zeros(8) // nonce - headerArray[15] = zeros(4) // bad data + // mock header data (if set to new Uint8Array() header throws) + headerArray[0] = new Uint8Array(32) //parentHash + headerArray[2] = new Uint8Array(20) //coinbase + headerArray[3] = new Uint8Array(32) //stateRoot + headerArray[4] = new Uint8Array(32) //transactionsTrie + headerArray[5] = new Uint8Array(32) //receiptTrie + headerArray[13] = new Uint8Array(32) // mixHash + headerArray[14] = new Uint8Array(8) // nonce + headerArray[15] = new Uint8Array(4) // bad data try { createBlockHeaderFromBytesArray(headerArray) } catch (e: any) { diff --git a/packages/block/test/mergeBlock.spec.ts b/packages/block/test/mergeBlock.spec.ts index ccc7a6f8bd..15a4bbd3c4 100644 --- a/packages/block/test/mergeBlock.spec.ts +++ b/packages/block/test/mergeBlock.spec.ts @@ -5,7 +5,6 @@ import { createZeroAddress, equalsBytes, hexToBytes, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -19,13 +18,13 @@ const common = new Common({ }) function validateMergeHeader(header: BlockHeader) { - assert.ok(equalsBytes(header.parentHash, zeros(32)), 'parentHash') + assert.ok(equalsBytes(header.parentHash, new Uint8Array(32)), 'parentHash') assert.ok(equalsBytes(header.uncleHash, KECCAK256_RLP_ARRAY), 'uncleHash') assert.ok(header.coinbase.equals(createZeroAddress()), 'coinbase') - assert.ok(equalsBytes(header.stateRoot, zeros(32)), 'stateRoot') + assert.ok(equalsBytes(header.stateRoot, new Uint8Array(32)), 'stateRoot') assert.ok(equalsBytes(header.transactionsTrie, KECCAK256_RLP), 'transactionsTrie') assert.ok(equalsBytes(header.receiptTrie, KECCAK256_RLP), 'receiptTrie') - assert.ok(equalsBytes(header.logsBloom, zeros(256)), 'logsBloom') + assert.ok(equalsBytes(header.logsBloom, new Uint8Array(256)), 'logsBloom') assert.equal(header.difficulty, BigInt(0), 'difficulty') assert.equal(header.number, BigInt(0), 'number') assert.equal(header.gasLimit, BigInt('0xffffffffffffff'), 'gasLimit') @@ -33,7 +32,7 @@ function validateMergeHeader(header: BlockHeader) { assert.equal(header.timestamp, BigInt(0), 'timestamp') assert.ok(header.extraData.length <= 32, 'extraData') assert.equal(header.mixHash.length, 32, 'mixHash') - assert.ok(equalsBytes(header.nonce, zeros(8)), 'nonce') + assert.ok(equalsBytes(header.nonce, new Uint8Array(8)), 'nonce') } describe('[Header]: Casper PoS / The Merge Functionality', () => { diff --git a/packages/client/src/miner/pendingBlock.ts b/packages/client/src/miner/pendingBlock.ts index 8fdd97c848..cc17cf8316 100644 --- a/packages/client/src/miner/pendingBlock.ts +++ b/packages/client/src/miner/pendingBlock.ts @@ -11,7 +11,6 @@ import { equalsBytes, toBytes, toType, - zeros, } from '@ethereumjs/util' import { BuildStatus, buildBlock } from '@ethereumjs/vm' import { keccak256 } from 'ethereum-cryptography/keccak' @@ -121,12 +120,12 @@ export class PendingBlock { // potentially included in the fcU in future and can be safely added in uniqueness calc const timestampBuf = bigIntToUnpaddedBytes(toType(timestamp ?? 0, TypeOutput.BigInt)) const gasLimitBuf = bigIntToUnpaddedBytes(gasLimit) - const mixHashBuf = toType(mixHash!, TypeOutput.Uint8Array) ?? zeros(32) + const mixHashBuf = toType(mixHash!, TypeOutput.Uint8Array) ?? new Uint8Array(32) const parentBeaconBlockRootBuf = - toType(parentBeaconBlockRoot!, TypeOutput.Uint8Array) ?? zeros(32) - const coinbaseBuf = toType(coinbase ?? zeros(20), TypeOutput.Uint8Array) + toType(parentBeaconBlockRoot!, TypeOutput.Uint8Array) ?? new Uint8Array(32) + const coinbaseBuf = toType(coinbase ?? new Uint8Array(20), TypeOutput.Uint8Array) - let withdrawalsBuf = zeros(0) + let withdrawalsBuf = new Uint8Array() if (withdrawals !== undefined && withdrawals !== null) { const withdrawalsBufTemp: Uint8Array[] = [] diff --git a/packages/client/src/rpc/modules/engine/engine.ts b/packages/client/src/rpc/modules/engine/engine.ts index 47d9abe161..c5e6387ab8 100644 --- a/packages/client/src/rpc/modules/engine/engine.ts +++ b/packages/client/src/rpc/modules/engine/engine.ts @@ -6,7 +6,6 @@ import { equalsBytes, hexToBytes, toBytes, - zeros, } from '@ethereumjs/util' import { ExecStatus } from '../../../execution/index.js' @@ -71,7 +70,7 @@ import type { Block, ExecutionPayload } from '@ethereumjs/block' import type { PrefixedHexString } from '@ethereumjs/util' import type { VM } from '@ethereumjs/vm' -const zeroBlockHash = zeros(32) +const zeroBlockHash = new Uint8Array(32) /** * engine_* RPC module @@ -486,7 +485,7 @@ export class Engine { const latestValidHash = this.chain.blocks.latest !== null ? await validHash(this.chain.blocks.latest.hash(), this.chain, this.chainCache) - : bytesToHex(zeros(32)) + : bytesToHex(new Uint8Array(32)) const response = { status: Status.INVALID, validationError: this.skeleton.fillStatus.validationError ?? '', @@ -555,7 +554,7 @@ export class Engine { const latestValidHash = this.chain.blocks.latest !== null ? await validHash(this.chain.blocks.latest.hash(), this.chain, this.chainCache) - : bytesToHex(zeros(32)) + : bytesToHex(new Uint8Array(32)) const response = { status: Status.INVALID, validationError: this.skeleton.fillStatus.validationError ?? '', @@ -978,7 +977,7 @@ export class Engine { const latestValidHash = this.chain.blocks.latest !== null ? await validHash(this.chain.blocks.latest.hash(), this.chain, this.chainCache) - : bytesToHex(zeros(32)) + : bytesToHex(new Uint8Array(32)) const response = { payloadStatus: { status: Status.INVALID, diff --git a/packages/client/src/service/skeleton.ts b/packages/client/src/service/skeleton.ts index 8401285ea1..4f0da81a90 100644 --- a/packages/client/src/service/skeleton.ts +++ b/packages/client/src/service/skeleton.ts @@ -13,7 +13,6 @@ import { formatBigDecimal, intToBytes, utf8ToBytes, - zeros, } from '@ethereumjs/util' import { short, timeDuration } from '../util/index.js' @@ -89,7 +88,7 @@ export const errReorgDenied = new Error('non-forced head reorg denied') */ export const errSyncMerged = new Error('sync merged') -const zeroBlockHash = zeros(32) +const zeroBlockHash = new Uint8Array(32) /** * The Skeleton chain class helps support beacon sync by accepting head blocks * while backfill syncing the rest of the chain. diff --git a/packages/common/test/hardforks.spec.ts b/packages/common/test/hardforks.spec.ts index 3e37ec5e3c..228e947eab 100644 --- a/packages/common/test/hardforks.spec.ts +++ b/packages/common/test/hardforks.spec.ts @@ -1,4 +1,4 @@ -import { hexToBytes, zeros } from '@ethereumjs/util' +import { hexToBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' import { @@ -312,7 +312,7 @@ describe('[Common]: Hardfork logic', () => { hardfork: Hardfork.Cancun, mergeForkIdPostMerge: true, } - const genesisHash = zeros(32) + const genesisHash = new Uint8Array(32) const zeroCommon = createCommonFromGethGenesis(defaultConfig, gethConfig) const zeroCommonShanghaiFork = zeroCommon.forkHash(Hardfork.Shanghai, genesisHash) diff --git a/packages/ethash/examples/example.ts b/packages/ethash/examples/example.ts index 983a4007bf..ce33dfe98b 100644 --- a/packages/ethash/examples/example.ts +++ b/packages/ethash/examples/example.ts @@ -5,7 +5,7 @@ import { Ethash } from '../dist/cjs/index.js' const ethash = new Ethash() // make the 1000 cache items with a seed of 0 * 32 -ethash.mkcache(1000, new Uint8Array(32).fill(0)) +ethash.mkcache(1000, new Uint8Array(32)) const result = ethash.run(hexToBytes('0xaabb'), Uint8Array.from([0]), 1000) diff --git a/packages/ethash/src/index.ts b/packages/ethash/src/index.ts index 41c3739e70..db4d594c0b 100644 --- a/packages/ethash/src/index.ts +++ b/packages/ethash/src/index.ts @@ -12,7 +12,6 @@ import { equalsBytes, hexToBytes, setLengthLeft, - zeros, } from '@ethereumjs/util' import { keccak256, keccak512 } from 'ethereum-cryptography/keccak.js' @@ -292,7 +291,7 @@ export class Ethash { // gives the seed the first epoc found const findLastSeed = async (epoc: number): Promise<[Uint8Array, number]> => { if (epoc === 0) { - return [zeros(32), 0] + return [new Uint8Array(32), 0] } const dbData = await this.cacheDB!.get(epoc, { diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 16ead4bc27..869b479db7 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -15,7 +15,6 @@ import { generateAddress, generateAddress2, short, - zeros, } from '@ethereumjs/util' import debugDefault from 'debug' @@ -1170,7 +1169,7 @@ export function defaultBlock(): Block { coinbase: createZeroAddress(), timestamp: BIGINT_0, difficulty: BIGINT_0, - prevRandao: zeros(32), + prevRandao: new Uint8Array(32), gasLimit: BIGINT_0, baseFeePerGas: undefined, getBlobGasPrice: () => undefined, diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index 647f6eb6c4..f3619e9648 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -503,7 +503,7 @@ export class Interpreter { // Returns all valid jump and jumpsub destinations. _getValidJumpDestinations(code: Uint8Array) { - const jumps = new Uint8Array(code.length).fill(0) + const jumps = new Uint8Array(code.length) const pushes: { [pc: number]: bigint } = {} const opcodesCached = Array(code.length) diff --git a/packages/evm/src/types.ts b/packages/evm/src/types.ts index ed7a2b5811..1601ab7770 100644 --- a/packages/evm/src/types.ts +++ b/packages/evm/src/types.ts @@ -1,5 +1,3 @@ -import { zeros } from '@ethereumjs/util' - import type { EOFContainer } from './eof/container.js' import type { EvmError } from './exceptions.js' import type { InterpreterStep, RunState } from './interpreter.js' @@ -490,7 +488,7 @@ export class EVMMockBlockchain implements EVMMockBlockchainInterface { async getBlock() { return { hash() { - return zeros(32) + return new Uint8Array(32) }, } } diff --git a/packages/evm/test/runCall.spec.ts b/packages/evm/test/runCall.spec.ts index 8cf1217959..8c3ddc5ad2 100644 --- a/packages/evm/test/runCall.spec.ts +++ b/packages/evm/test/runCall.spec.ts @@ -12,7 +12,6 @@ import { hexToBytes, padToEven, unpadBytes, - zeros, } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak.js' import { assert, describe, it } from 'vitest' @@ -744,7 +743,9 @@ describe('RunCall tests', () => { } await evm.runCall(runCallArgs) - const callResult = bytesToHex(await evm.stateManager.getStorage(callerAddress, zeros(32))) + const callResult = bytesToHex( + await evm.stateManager.getStorage(callerAddress, new Uint8Array(32)), + ) // Expect slot to have value of either: 0 since CALLCODE and CODE did not have enough gas to execute // Or 1, if CALL(CODE) has enough gas to enter the new call frame assert.equal(callResult, expectedOutput, `should have result ${expectedOutput}`) diff --git a/packages/statemanager/src/rpcStateManager.ts b/packages/statemanager/src/rpcStateManager.ts index 2c847ea765..1144cbdf37 100644 --- a/packages/statemanager/src/rpcStateManager.ts +++ b/packages/statemanager/src/rpcStateManager.ts @@ -207,7 +207,7 @@ export class RPCStateManager implements StateManagerInterface { const accountFromProvider = await this.getAccountFromProvider(address) const account = - equalsBytes(accountFromProvider.codeHash, new Uint8Array(32).fill(0)) || + equalsBytes(accountFromProvider.codeHash, new Uint8Array(32)) || equalsBytes(accountFromProvider.serialize(), KECCAK256_RLP_EMPTY_ACCOUNT) ? undefined : createAccountFromRLP(accountFromProvider.serialize()) diff --git a/packages/statemanager/test/proofStateManager.spec.ts b/packages/statemanager/test/proofStateManager.spec.ts index c0bb4442ad..e1550bbfbe 100644 --- a/packages/statemanager/test/proofStateManager.spec.ts +++ b/packages/statemanager/test/proofStateManager.spec.ts @@ -10,7 +10,6 @@ import { equalsBytes, hexToBytes, randomBytes, - zeros, } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak.js' import { assert, describe, it } from 'vitest' @@ -27,7 +26,7 @@ import type { PrefixedHexString } from '@ethereumjs/util' describe('ProofStateManager', () => { it(`should return quantity-encoded RPC representation`, async () => { const address = createZeroAddress() - const key = zeros(32) + const key = new Uint8Array(32) const stateManager = new MerkleStateManager() const proof = await getMerkleStateProof(stateManager, address, [key]) @@ -37,7 +36,7 @@ describe('ProofStateManager', () => { it(`should correctly return the right storage root / account root`, async () => { const address = createZeroAddress() - const key = zeros(32) + const key = new Uint8Array(32) const stateManager = new MerkleStateManager() await stateManager.putAccount(address, new Account(BigInt(100), BigInt(200))) @@ -51,7 +50,7 @@ describe('ProofStateManager', () => { it(`should return quantity-encoded RPC representation for existing accounts`, async () => { const address = createZeroAddress() - const key = zeros(32) + const key = new Uint8Array(32) const stateManager = new MerkleStateManager() const account = new Account() @@ -79,7 +78,7 @@ describe('ProofStateManager', () => { it(`should get and verify EIP 1178 proofs`, async () => { const address = createZeroAddress() - const key = zeros(32) + const key = new Uint8Array(32) const value = hexToBytes('0x0000aabb00') const code = hexToBytes('0x6000') const stateManager = new MerkleStateManager() diff --git a/packages/statemanager/test/stateManager.spec.ts b/packages/statemanager/test/stateManager.spec.ts index c0783792e3..f822b2b13d 100644 --- a/packages/statemanager/test/stateManager.spec.ts +++ b/packages/statemanager/test/stateManager.spec.ts @@ -11,7 +11,6 @@ import { intToBytes, setLengthLeft, utf8ToBytes, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -53,7 +52,7 @@ describe('StateManager -> General', () => { const sm = new MerkleStateManager() try { - const storage = await sm.getStorage(createZeroAddress(), zeros(32)) + const storage = await sm.getStorage(createZeroAddress(), new Uint8Array(32)) assert.ok(equalsBytes(storage, new Uint8Array())) } catch { assert.fail('should not throw') diff --git a/packages/statemanager/test/stateManager.storage.spec.ts b/packages/statemanager/test/stateManager.storage.spec.ts index 1c0ded01f1..a32e995dea 100644 --- a/packages/statemanager/test/stateManager.storage.spec.ts +++ b/packages/statemanager/test/stateManager.storage.spec.ts @@ -6,7 +6,6 @@ import { equalsBytes, hexToBytes, unpadBytes, - zeros, } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak.js' import { assert, describe, it } from 'vitest' @@ -85,7 +84,7 @@ describe('StateManager -> Storage', () => { const account = createAccountWithDefaults() await stateManager.putAccount(address, account) - const key = zeros(32) + const key = new Uint8Array(32) const value = hexToBytes(`0x${'aa'.repeat(33)}`) try { await stateManager.putStorage(address, key, value) @@ -104,14 +103,14 @@ describe('StateManager -> Storage', () => { const account = createAccountWithDefaults() await stateManager.putAccount(address, account) - const key0 = zeros(32) + const key0 = new Uint8Array(32) const value0 = hexToBytes(`0x00${'aa'.repeat(30)}`) // put a value of 31-bytes length with a leading zero byte const expect0 = unpadBytes(value0) await stateManager.putStorage(address, key0, value0) const slot0 = await stateManager.getStorage(address, key0) assert.ok(equalsBytes(slot0, expect0), 'value of 31 bytes padded correctly') - const key1 = concatBytes(zeros(31), hexToBytes('0x01')) + const key1 = concatBytes(new Uint8Array(31), hexToBytes('0x01')) const value1 = hexToBytes(`0x0000${'aa'.repeat(1)}`) // put a value of 1-byte length with two leading zero bytes const expect1 = unpadBytes(value1) await stateManager.putStorage(address, key1, value1) @@ -122,7 +121,7 @@ describe('StateManager -> Storage', () => { it(`should delete storage values which only consist of zero bytes`, async () => { const address = createZeroAddress() - const key = zeros(32) + const key = new Uint8Array(32) const startValue = hexToBytes('0x01') @@ -136,7 +135,7 @@ describe('StateManager -> Storage', () => { const account = createAccountWithDefaults() await stateManager.putAccount(address, account) - const value = zeros(length) + const value = new Uint8Array(length) await stateManager.putStorage(address, key, startValue) const currentValue = await stateManager.getStorage(address, key) if (!equalsBytes(currentValue, startValue)) { @@ -146,7 +145,7 @@ describe('StateManager -> Storage', () => { // delete the value await stateManager.putStorage(address, key, value) const deleted = await stateManager.getStorage(address, key) - assert.ok(equalsBytes(deleted, zeros(0)), 'the storage key should be deleted') + assert.ok(equalsBytes(deleted, new Uint8Array()), 'the storage key should be deleted') } } }) @@ -160,7 +159,7 @@ describe('StateManager -> Storage', () => { const account = createAccountWithDefaults() await stateManager.putAccount(address, account) - const key = zeros(32) + const key = new Uint8Array(32) const value = hexToBytes('0x0000aabb00') const expect = hexToBytes('0xaabb00') diff --git a/packages/trie/test/index.spec.ts b/packages/trie/test/index.spec.ts index 276c51cd0b..f5bb8616d0 100644 --- a/packages/trie/test/index.spec.ts +++ b/packages/trie/test/index.spec.ts @@ -274,10 +274,8 @@ for (const keyPrefix of [undefined, hexToBytes('0x1234')]) { const a = hexToBytes('0x1a26338f0d905e295fccb71fa9ea849ffa12aaf4') const storageRoot = new Uint8Array(32) - storageRoot.fill(0) const startAmount = new Uint8Array(26) - startAmount.fill(0) startAmount[0] = 1 const account = [startAmount, 0, storageRoot, KECCAK256_NULL] @@ -338,11 +336,7 @@ for (const keyPrefix of [undefined, hexToBytes('0x1234')]) { const useKeyHashingFunction: HashKeysFunction = (msg) => { const hashLen = 32 if (msg.length <= hashLen - 5) { - return concatBytes( - utf8ToBytes('hash_'), - new Uint8Array(hashLen - msg.length).fill(0), - msg, - ) + return concatBytes(utf8ToBytes('hash_'), new Uint8Array(hashLen - msg.length), msg) } else { return concatBytes(utf8ToBytes('hash_'), msg.slice(0, hashLen - 5)) } diff --git a/packages/util/src/account.ts b/packages/util/src/account.ts index a62022e959..945beaa2a4 100644 --- a/packages/util/src/account.ts +++ b/packages/util/src/account.ts @@ -13,7 +13,6 @@ import { intToUnpaddedBytes, toBytes, utf8ToBytes, - zeros, } from './bytes.js' import { BIGINT_0, KECCAK256_NULL, KECCAK256_RLP } from './constants.js' import { assertIsBytes, assertIsHexString, assertIsString } from './helpers.js' @@ -612,10 +611,8 @@ export const importPublic = function (publicKey: Uint8Array): Uint8Array { /** * Returns the zero address. */ -export const zeroAddress = function (): string { - const addressLength = 20 - const addr = zeros(addressLength) - return bytesToHex(addr) +export const zeroAddress = function (): PrefixedHexString { + return bytesToHex(new Uint8Array(20)) } /** diff --git a/packages/util/src/address.ts b/packages/util/src/address.ts index 795052e436..83fbdef088 100644 --- a/packages/util/src/address.ts +++ b/packages/util/src/address.ts @@ -12,7 +12,6 @@ import { equalsBytes, hexToBytes, setLengthLeft, - zeros, } from './bytes.js' import { BIGINT_0 } from './constants.js' @@ -42,7 +41,7 @@ export class Address { * Is address zero. */ isZero(): boolean { - return this.equals(new Address(zeros(20))) + return this.equals(new Address(new Uint8Array(20))) } /** @@ -75,7 +74,7 @@ export class Address { * Returns the zero address. */ export function createZeroAddress(): Address { - return new Address(zeros(20)) + return new Address(new Uint8Array(20)) } /** diff --git a/packages/util/src/blobs.ts b/packages/util/src/blobs.ts index 178be0741e..f77dfd719f 100644 --- a/packages/util/src/blobs.ts +++ b/packages/util/src/blobs.ts @@ -16,7 +16,7 @@ const MAX_USEFUL_BYTES_PER_TX = USEFUL_BYTES_PER_BLOB * MAX_BLOBS_PER_TX - 1 const BLOB_SIZE = BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB function get_padded(data: Uint8Array, blobs_len: number): Uint8Array { - const pData = new Uint8Array(blobs_len * USEFUL_BYTES_PER_BLOB).fill(0) + const pData = new Uint8Array(blobs_len * USEFUL_BYTES_PER_BLOB) pData.set(data) pData[data.byteLength] = 0x80 return pData diff --git a/packages/util/src/bytes.ts b/packages/util/src/bytes.ts index 067ce518dc..4fa767f98d 100644 --- a/packages/util/src/bytes.ts +++ b/packages/util/src/bytes.ts @@ -116,15 +116,6 @@ export const bigIntToBytes = (num: bigint, littleEndian = false): Uint8Array => return littleEndian ? bytes.reverse() : bytes } -/** - * Returns a Uint8Array filled with 0s. - * @param {number} bytes the number of bytes of the Uint8Array - * @return {Uint8Array} - */ -export const zeros = (bytes: number): Uint8Array => { - return new Uint8Array(bytes) -} - /** * Pads a `Uint8Array` with zeros till it has `length` bytes. * Truncates the beginning or end of input if its length exceeds `length`. @@ -136,12 +127,12 @@ export const zeros = (bytes: number): Uint8Array => { const setLength = (msg: Uint8Array, length: number, right: boolean): Uint8Array => { if (right) { if (msg.length < length) { - return new Uint8Array([...msg, ...zeros(length - msg.length)]) + return new Uint8Array([...msg, ...new Uint8Array(length - msg.length)]) } return msg.subarray(0, length) } else { if (msg.length < length) { - return new Uint8Array([...zeros(length - msg.length), ...msg]) + return new Uint8Array([...new Uint8Array(length - msg.length), ...msg]) } return msg.subarray(-length) } diff --git a/packages/util/test/bytes.spec.ts b/packages/util/test/bytes.spec.ts index 7f9ece488f..43cd04de3e 100644 --- a/packages/util/test/bytes.spec.ts +++ b/packages/util/test/bytes.spec.ts @@ -29,17 +29,8 @@ import { unprefixedHexToBytes, validateNoLeadingZeroes, zeroAddress, - zeros, } from '../src/index.js' -describe('zeros function', () => { - it('should produce lots of 0s', () => { - const z60 = zeros(30) - const zs60 = '0x000000000000000000000000000000000000000000000000000000000000' - assert.equal(bytesToHex(z60), zs60) - }) -}) - describe('zero address', () => { it('should generate a zero address', () => { assert.equal(zeroAddress(), '0x0000000000000000000000000000000000000000') @@ -164,14 +155,14 @@ describe('bytesToInt', () => { describe('fromSigned', () => { it('should convert an unsigned (negative) Uint8Array to a signed number', () => { const neg = '-452312848583266388373324160190187140051835877600158453279131187530910662656' - const bytes = zeros(32) + const bytes = new Uint8Array(32) bytes[0] = 255 assert.equal(fromSigned(bytes).toString(), neg) }) it('should convert an unsigned (positive) Uint8Array to a signed number', () => { const neg = '452312848583266388373324160190187140051835877600158453279131187530910662656' - const bytes = zeros(32) + const bytes = new Uint8Array(32) bytes[0] = 1 assert.equal(fromSigned(bytes).toString(), neg) diff --git a/packages/verkle/src/verkleTree.ts b/packages/verkle/src/verkleTree.ts index e0294a3580..0b9cf5b466 100644 --- a/packages/verkle/src/verkleTree.ts +++ b/packages/verkle/src/verkleTree.ts @@ -5,7 +5,6 @@ import { equalsBytes, intToHex, matchingBytesLength, - zeros, } from '@ethereumjs/util' import debug from 'debug' @@ -70,7 +69,7 @@ export class VerkleTree { this.database(opts?.db) - this.EMPTY_TREE_ROOT = zeros(32) + this.EMPTY_TREE_ROOT = new Uint8Array(32) this._hashLen = this.EMPTY_TREE_ROOT.length this._root = this.EMPTY_TREE_ROOT diff --git a/packages/verkle/test/proof.spec.ts b/packages/verkle/test/proof.spec.ts index c47e483876..71fd69ea54 100644 --- a/packages/verkle/test/proof.spec.ts +++ b/packages/verkle/test/proof.spec.ts @@ -80,7 +80,7 @@ describe('lets make proofs', () => { serializedCommitment: verkleCrypto.serializeCommitment( (await trie.findPath(new Uint8Array(31))).stack![0][0].commitment, ), - vector: new Array(256).fill(new Uint8Array(32).fill(0)), + vector: new Array(256).fill(new Uint8Array(32)), indices: [0], }, ]) diff --git a/packages/vm/src/bloom/index.ts b/packages/vm/src/bloom/index.ts index f333c2f14b..b328e70b73 100644 --- a/packages/vm/src/bloom/index.ts +++ b/packages/vm/src/bloom/index.ts @@ -1,4 +1,3 @@ -import { zeros } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak.js' import type { Common } from '@ethereumjs/common' @@ -19,7 +18,7 @@ export class Bloom { this.keccakFunction = keccak256 } if (!bitvector) { - this.bitvector = zeros(BYTE_SIZE) + this.bitvector = new Uint8Array(BYTE_SIZE) } else { if (bitvector.length !== BYTE_SIZE) throw new Error('bitvectors must be 2048 bits long') this.bitvector = bitvector diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 119b3b144d..08e904e9c3 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -21,7 +21,6 @@ import { createZeroAddress, toBytes, toType, - zeros, } from '@ethereumjs/util' import { Bloom } from './bloom/index.js' @@ -404,7 +403,7 @@ export class BlockBuilder { // timestamp should already be set in constructor const timestampBigInt = toType(timestamp ?? 0, TypeOutput.BigInt) const parentBeaconBlockRootBuf = - toType(parentBeaconBlockRoot!, TypeOutput.Uint8Array) ?? zeros(32) + toType(parentBeaconBlockRoot!, TypeOutput.Uint8Array) ?? new Uint8Array(32) await accumulateParentBeaconBlockRoot(this.vm, parentBeaconBlockRootBuf, timestampBigInt) } @@ -417,7 +416,7 @@ export class BlockBuilder { const { parentHash, number } = this.headerData // timestamp should already be set in constructor const numberBigInt = toType(number ?? 0, TypeOutput.BigInt) - const parentHashSanitized = toType(parentHash, TypeOutput.Uint8Array) ?? zeros(32) + const parentHashSanitized = toType(parentHash, TypeOutput.Uint8Array) ?? new Uint8Array(32) await accumulateParentBlockHash(this.vm, numberBigInt, parentHashSanitized) } diff --git a/packages/vm/test/api/EIPs/eip-2935-historical-block-hashes.spec.ts b/packages/vm/test/api/EIPs/eip-2935-historical-block-hashes.spec.ts index 7b97d3390f..5708c3be11 100644 --- a/packages/vm/test/api/EIPs/eip-2935-historical-block-hashes.spec.ts +++ b/packages/vm/test/api/EIPs/eip-2935-historical-block-hashes.spec.ts @@ -15,7 +15,6 @@ import { generateAddress, privateToAddress, setLengthLeft, - zeros, } from '@ethereumjs/util' import { hexToBytes } from 'ethereum-cryptography/utils' import { assert, describe, it } from 'vitest' @@ -280,10 +279,10 @@ describe('EIP 2935: historical block hashes', () => { if (i >= blocksToBuild - 256) { assert.ok(equalsBytes(ret.execResult.returnValue, setLengthLeft(block.hash(), 64))) } else { - assert.ok(equalsBytes(ret.execResult.returnValue, zeros(64))) + assert.ok(equalsBytes(ret.execResult.returnValue, new Uint8Array(64))) } } else { - assert.ok(equalsBytes(ret.execResult.returnValue, zeros(64))) + assert.ok(equalsBytes(ret.execResult.returnValue, new Uint8Array(64))) } } diff --git a/packages/vm/test/api/EIPs/eip-4788-beaconroot.spec.ts b/packages/vm/test/api/EIPs/eip-4788-beaconroot.spec.ts index a17fca0560..1913fffd4c 100644 --- a/packages/vm/test/api/EIPs/eip-4788-beaconroot.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4788-beaconroot.spec.ts @@ -19,7 +19,6 @@ import { hexToBytes, setLengthLeft, setLengthRight, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -123,7 +122,7 @@ async function runBlock(block: Block) { * Get call status saved in the contract */ async function getCallStatus(vm: VM) { - const stat = await vm.stateManager.getStorage(contractAddress, zeros(32)) + const stat = await vm.stateManager.getStorage(contractAddress, new Uint8Array(32)) return bytesToBigInt(stat) } diff --git a/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts b/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts index b18176ce80..c9819b62b8 100644 --- a/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts @@ -11,7 +11,6 @@ import { getBlobs, hexToBytes, privateToAddress, - zeros, } from '@ethereumjs/util' import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' import { KZG as microEthKZG } from 'micro-eth-signer/kzg' @@ -33,7 +32,7 @@ describe('EIP4844 tests', () => { customCrypto: { kzg }, }) const genesisBlock = createBlock( - { header: { gasLimit: 50000, parentBeaconBlockRoot: zeros(32) } }, + { header: { gasLimit: 50000, parentBeaconBlockRoot: new Uint8Array(32) } }, { common }, ) const blockchain = await createBlockchain({ diff --git a/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts b/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts index 99b6c1b29f..6686a10350 100644 --- a/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts @@ -12,7 +12,6 @@ import { createWithdrawalFromBytesArray, hexToBytes, parseGethGenesisState, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -122,10 +121,10 @@ describe('EIP4895 tests', () => { assert.equal(BigInt(amount) * GWEI_TO_WEI, balance, 'balance ok') } - assert.deepEqual(zeros(32), result!, 'withdrawals happen after transactions') + assert.deepEqual(new Uint8Array(32), result!, 'withdrawals happen after transactions') - const slotValue = await vm.stateManager.getStorage(withdrawalCheckAddress, zeros(32)) - assert.deepEqual(zeros(0), slotValue, 'withdrawals do not invoke code') + const slotValue = await vm.stateManager.getStorage(withdrawalCheckAddress, new Uint8Array(32)) + assert.deepEqual(new Uint8Array(), slotValue, 'withdrawals do not invoke code') }) it('EIP4895: state update should exclude 0 amount updates', async () => { diff --git a/packages/vm/test/api/EIPs/eip-7002.spec.ts b/packages/vm/test/api/EIPs/eip-7002.spec.ts index 7850812765..f92e8d661a 100644 --- a/packages/vm/test/api/EIPs/eip-7002.spec.ts +++ b/packages/vm/test/api/EIPs/eip-7002.spec.ts @@ -12,7 +12,6 @@ import { equalsBytes, hexToBytes, setLengthLeft, - zeros, } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -100,7 +99,7 @@ describe('EIP-7002 tests', () => { { header: { number: 2, - parentBeaconBlockRoot: zeros(32), + parentBeaconBlockRoot: new Uint8Array(32), }, transactions: [tx], }, @@ -146,7 +145,7 @@ describe('EIP-7002 tests', () => { { header: { number: 3, - parentBeaconBlockRoot: zeros(32), + parentBeaconBlockRoot: new Uint8Array(32), }, transactions: [tx2, tx3], }, diff --git a/packages/vm/test/api/EIPs/eip-7702.spec.ts b/packages/vm/test/api/EIPs/eip-7702.spec.ts index a9239a7820..a1a5c107f5 100644 --- a/packages/vm/test/api/EIPs/eip-7702.spec.ts +++ b/packages/vm/test/api/EIPs/eip-7702.spec.ts @@ -14,7 +14,6 @@ import { privateToAddress, setLengthRight, unpadBytes, - zeros, } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak' import { equalsBytes } from 'ethereum-cryptography/utils' @@ -298,7 +297,7 @@ describe('test EIP-7702 opcodes', () => { // Set authority and immediately call into the contract to get the extcodehash / extcodesize await runTx(vm, { tx: authTx }) - const result = await vm.stateManager.getStorage(deploymentAddress, zeros(32)) + const result = await vm.stateManager.getStorage(deploymentAddress, new Uint8Array(32)) assert.ok(equalsBytes(result, expectedOutput), `FAIL test: ${name}`) } diff --git a/packages/vm/test/api/bloom.spec.ts b/packages/vm/test/api/bloom.spec.ts index a8fb7da60f..c7267b4029 100644 --- a/packages/vm/test/api/bloom.spec.ts +++ b/packages/vm/test/api/bloom.spec.ts @@ -1,4 +1,3 @@ -import * as utils from '@ethereumjs/util' import { bytesToHex, hexToBytes, utf8ToBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' @@ -9,12 +8,12 @@ const byteSize = 256 describe('bloom', () => { it('should initialize without params', () => { const b = new Bloom() - assert.deepEqual(b.bitvector, utils.zeros(byteSize), 'should be empty') + assert.deepEqual(b.bitvector, new Uint8Array(byteSize), 'should be empty') }) it("shouldn't initialize with invalid bitvector", () => { assert.throws( - () => new Bloom(utils.zeros(byteSize / 2)), + () => new Bloom(new Uint8Array(byteSize / 2)), /bitvectors must be 2048 bits long/, undefined, 'should fail for invalid length', diff --git a/packages/vm/test/api/runBlock.spec.ts b/packages/vm/test/api/runBlock.spec.ts index a4df164cb0..a6ce711cb6 100644 --- a/packages/vm/test/api/runBlock.spec.ts +++ b/packages/vm/test/api/runBlock.spec.ts @@ -30,7 +30,6 @@ import { toBytes, unpadBytes, utf8ToBytes, - zeros, } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak' import { assert, describe, it } from 'vitest' @@ -674,7 +673,7 @@ describe('runBlock() -> tx types', async () => { ) await runBlock(vm, { block, skipBlockValidation: true, generate: true }) - const storage = await vm.stateManager.getStorage(defaultAuthAddr, zeros(32)) + const storage = await vm.stateManager.getStorage(defaultAuthAddr, new Uint8Array(32)) assert.ok(equalsBytes(storage, new Uint8Array([2]))) }) }) diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index 15010aeebc..b2d92071f3 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -22,7 +22,6 @@ import { createZeroAddress, equalsBytes, hexToBytes, - zeros, } from '@ethereumjs/util' import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' import { KZG as microEthKZG } from 'micro-eth-signer/kzg' @@ -790,7 +789,7 @@ it('Validate EXTCODEHASH puts KECCAK256_NULL on stack if calling account has no await vm.stateManager.putAccount(addr, acc!) await runTx(vm, { tx, skipHardForkValidation: true }) - const hash = await vm.stateManager.getStorage(codeAddr, zeros(32)) + const hash = await vm.stateManager.getStorage(codeAddr, new Uint8Array(32)) assert.deepEqual(hash, KECCAK256_NULL, 'hash ok') }) diff --git a/packages/vm/test/t8n/t8ntool.ts b/packages/vm/test/t8n/t8ntool.ts index ce5b44f291..6696da5b17 100644 --- a/packages/vm/test/t8n/t8ntool.ts +++ b/packages/vm/test/t8n/t8ntool.ts @@ -2,14 +2,7 @@ import { Block } from '@ethereumjs/block' import { EVMMockBlockchain, NobleBLS } from '@ethereumjs/evm' import { RLP } from '@ethereumjs/rlp' import { createTx } from '@ethereumjs/tx' -import { - CLRequestType, - bigIntToHex, - bytesToHex, - hexToBytes, - toBytes, - zeros, -} from '@ethereumjs/util' +import { CLRequestType, bigIntToHex, bytesToHex, hexToBytes, toBytes } from '@ethereumjs/util' import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' import { keccak256 } from 'ethereum-cryptography/keccak' import { readFileSync, writeFileSync } from 'fs' @@ -180,7 +173,7 @@ export class TransitionTool { blockNumber: bytesToHex(toBytes(builder['headerData'].number)), transactionHash: bytesToHex(event.transaction.hash()), transactionIndex: bigIntToHex(BigInt(txIndex)), - blockHash: bytesToHex(zeros(32)), + blockHash: bytesToHex(new Uint8Array(32)), logIndex: bigIntToHex(BigInt(formattedLogs.length)), removed: 'false', } @@ -294,7 +287,7 @@ function getBlockchain(inputEnv: T8NEnv) { } return { hash() { - return zeros(32) + return new Uint8Array(32) }, } } From f1fda2761c3f506c3cb3a8b69cd8cd583b3051ca Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 29 Sep 2024 17:25:50 -0400 Subject: [PATCH 2/2] trie: improve node typings and class architecture (#3708) * trie: add RawNode types and replace EmbeddedNode type * trie: implement new types in BranchNode class * trie: improve extension and leaf node class architecture * trie: small improvements * trie: improve raw nodes comments * trie: improve comments for raw nodes --- packages/trie/src/node/branch.ts | 16 ++++++------- packages/trie/src/node/extension.ts | 12 ++++------ .../{node.ts => extensionOrLeafNodeBase.ts} | 20 ++++++++-------- packages/trie/src/node/leaf.ts | 12 ++++------ packages/trie/src/trie.ts | 23 +++++++++---------- packages/trie/src/types.ts | 13 +++++++++-- packages/trie/src/util/nibbles.ts | 10 -------- 7 files changed, 50 insertions(+), 56 deletions(-) rename packages/trie/src/node/{node.ts => extensionOrLeafNodeBase.ts} (70%) diff --git a/packages/trie/src/node/branch.ts b/packages/trie/src/node/branch.ts index 8f46befa8b..d13ccdd1ea 100644 --- a/packages/trie/src/node/branch.ts +++ b/packages/trie/src/node/branch.ts @@ -1,9 +1,9 @@ import { RLP } from '@ethereumjs/rlp' -import type { EmbeddedNode } from '../types.js' +import type { BranchNodeBranchValue, NodeReferenceOrRawNode } from '../types.js' export class BranchNode { - _branches: (EmbeddedNode | null)[] + _branches: BranchNodeBranchValue[] _value: Uint8Array | null constructor() { @@ -26,19 +26,19 @@ export class BranchNode { return this._value && this._value.length > 0 ? this._value : null } - setBranch(i: number, v: EmbeddedNode | null) { + setBranch(i: number, v: BranchNodeBranchValue) { this._branches[i] = v } - raw(): (EmbeddedNode | null)[] { + raw(): BranchNodeBranchValue[] { return [...this._branches, this._value] } serialize(): Uint8Array { - return RLP.encode(this.raw() as Uint8Array[]) + return RLP.encode(this.raw()) } - getBranch(i: number) { + getBranch(i: number): BranchNodeBranchValue { const b = this._branches[i] if (b !== null && b.length > 0) { return b @@ -47,8 +47,8 @@ export class BranchNode { } } - getChildren(): [number, EmbeddedNode][] { - const children: [number, EmbeddedNode][] = [] + getChildren(): [number, NodeReferenceOrRawNode][] { + const children: [number, NodeReferenceOrRawNode][] = [] for (let i = 0; i < 16; i++) { const b = this._branches[i] if (b !== null && b.length > 0) { diff --git a/packages/trie/src/node/extension.ts b/packages/trie/src/node/extension.ts index c1d978852c..b8a2797048 100644 --- a/packages/trie/src/node/extension.ts +++ b/packages/trie/src/node/extension.ts @@ -1,15 +1,13 @@ -import { addHexPrefix } from '../util/hex.js' +import { ExtensionOrLeafNodeBase } from './extensionOrLeafNodeBase.js' -import { Node } from './node.js' +import type { Nibbles, RawExtensionNode } from '../types.js' -import type { Nibbles } from '../types.js' - -export class ExtensionNode extends Node { +export class ExtensionNode extends ExtensionOrLeafNodeBase { constructor(nibbles: Nibbles, value: Uint8Array) { super(nibbles, value, false) } - static encodeKey(key: Nibbles): Nibbles { - return addHexPrefix(key, false) + raw(): RawExtensionNode { + return super.raw() } } diff --git a/packages/trie/src/node/node.ts b/packages/trie/src/node/extensionOrLeafNodeBase.ts similarity index 70% rename from packages/trie/src/node/node.ts rename to packages/trie/src/node/extensionOrLeafNodeBase.ts index c4952532ac..3a0f988f75 100644 --- a/packages/trie/src/node/node.ts +++ b/packages/trie/src/node/extensionOrLeafNodeBase.ts @@ -3,23 +3,27 @@ import { RLP } from '@ethereumjs/rlp' import { addHexPrefix, removeHexPrefix } from '../util/hex.js' import { nibblesTypeToPackedBytes } from '../util/nibbles.js' -import type { Nibbles } from '../types.js' +import type { Nibbles, RawExtensionNode, RawLeafNode } from '../types.js' -export class Node { +export abstract class ExtensionOrLeafNodeBase { _nibbles: Nibbles _value: Uint8Array - _terminator: boolean + _isLeaf: boolean - constructor(nibbles: Nibbles, value: Uint8Array, terminator: boolean) { + constructor(nibbles: Nibbles, value: Uint8Array, isLeaf: boolean) { this._nibbles = nibbles this._value = value - this._terminator = terminator + this._isLeaf = isLeaf } static decodeKey(key: Nibbles): Nibbles { return removeHexPrefix(key) } + encodedKey(): Nibbles { + return addHexPrefix(this._nibbles.slice(0), this._isLeaf) + } + key(k?: Nibbles): Nibbles { if (k !== undefined) { this._nibbles = k @@ -40,11 +44,7 @@ export class Node { return this._value } - encodedKey(): Nibbles { - return addHexPrefix(this._nibbles.slice(0), this._terminator) - } - - raw(): [Uint8Array, Uint8Array] { + raw(): RawExtensionNode | RawLeafNode { return [nibblesTypeToPackedBytes(this.encodedKey()), this._value] } diff --git a/packages/trie/src/node/leaf.ts b/packages/trie/src/node/leaf.ts index 766785aebc..7d144d9f99 100644 --- a/packages/trie/src/node/leaf.ts +++ b/packages/trie/src/node/leaf.ts @@ -1,15 +1,13 @@ -import { addHexPrefix } from '../util/hex.js' +import { ExtensionOrLeafNodeBase } from './extensionOrLeafNodeBase.js' -import { Node } from './node.js' +import type { Nibbles, RawLeafNode } from '../types.js' -import type { Nibbles } from '../types.js' - -export class LeafNode extends Node { +export class LeafNode extends ExtensionOrLeafNodeBase { constructor(nibbles: Nibbles, value: Uint8Array) { super(nibbles, value, true) } - static encodeKey(key: Nibbles): Nibbles { - return addHexPrefix(key, true) + raw(): RawLeafNode { + return super.raw() } } diff --git a/packages/trie/src/trie.ts b/packages/trie/src/trie.ts index 15b0a50d10..cfc7a6d358 100644 --- a/packages/trie/src/trie.ts +++ b/packages/trie/src/trie.ts @@ -34,9 +34,10 @@ import { bytesToNibbles, matchingNibbleLength, nibblesTypeToPackedBytes } from ' import { WalkController } from './util/walkController.js' import type { - EmbeddedNode, + BranchNodeBranchValue, FoundNodeFunction, Nibbles, + NodeReferenceOrRawNode, Path, TrieNode, TrieOpts, @@ -357,7 +358,7 @@ export class Trie { debugString += branchNode instanceof Uint8Array ? `NodeHash: ${bytesToHex(branchNode)}` - : `Raw_Node: ${branchNode!.toString()}` + : `Raw_Node: ${branchNode.toString()}` } this.debug(debugString, ['find_path', 'branch_node']) @@ -564,8 +565,8 @@ export class Trie { } if ( - matchingNibbleLength(lastNode.key(), key.slice(l)) === lastNode.key().length && - keyRemainder.length === 0 + keyRemainder.length === 0 && + matchingNibbleLength(lastNode.key(), key.slice(l)) === lastNode.key().length ) { matchLeaf = true } @@ -574,7 +575,7 @@ export class Trie { if (matchLeaf) { // just updating a found value lastNode.value(value) - stack.push(lastNode as TrieNode) + stack.push(lastNode) } else if (lastNode instanceof BranchNode) { stack.push(lastNode) if (keyRemainder.length !== 0) { @@ -609,8 +610,8 @@ export class Trie { if (lastKey.length !== 0 || lastNode instanceof LeafNode) { // shrinking extension or leaf lastNode.key(lastKey) - const formattedNode = this._formatNode(lastNode, false, toSave) - newBranchNode.setBranch(branchKey, formattedNode as EmbeddedNode) + const formattedNode = this._formatNode(lastNode, false, toSave) as NodeReferenceOrRawNode + newBranchNode.setBranch(branchKey, formattedNode) } else { // remove extension or attaching this._formatNode(lastNode, false, toSave, true) @@ -703,7 +704,7 @@ export class Trie { let key = bytesToNibbles(k) - if (!parentNode) { + if (parentNode === undefined) { // the root here has to be a leaf. this.root(this.EMPTY_TRIE_ROOT) return @@ -728,7 +729,7 @@ export class Trie { // nodes on the branch // count the number of nodes on the branch - const branchNodes: [number, EmbeddedNode][] = lastNode.getChildren() + const branchNodes: [number, NodeReferenceOrRawNode][] = lastNode.getChildren() // if there is only one branch node left, collapse the branch node if (branchNodes.length === 1) { @@ -753,10 +754,8 @@ export class Trie { // look up node const foundNode = await this.lookupNode(branchNode) - // if (foundNode) { key = processBranchNode(key, branchNodeKey, foundNode, parentNode as TrieNode, stack) await this.saveStack(key, stack, opStack) - // } } else { // simple removing a leaf and recalculation the stack if (parentNode) { @@ -819,7 +818,7 @@ export class Trie { topLevel: boolean, opStack: BatchDBOp[], remove: boolean = false, - ): Uint8Array | (EmbeddedNode | null)[] { + ): Uint8Array | NodeReferenceOrRawNode | BranchNodeBranchValue[] { const encoded = node.serialize() if (encoded.length >= 32 || topLevel) { diff --git a/packages/trie/src/types.ts b/packages/trie/src/types.ts index f17ecc424c..fd0fc5daf2 100644 --- a/packages/trie/src/types.ts +++ b/packages/trie/src/types.ts @@ -8,9 +8,18 @@ export type TrieNode = BranchNode | ExtensionNode | LeafNode export type Nibbles = number[] +// A raw node refers to the non-serialized, array form of the node +// A raw extension node is a 2-item node, where the first item is the encoded path to the next node, and the second item is the reference to the next node +// A raw leaf node is a 2-item node, where the first item is the remaining path to the leaf node, and the second item is the value +// To learn more: https://ethereum.org/en/developers/docs/data-structures-and-encoding/patricia-merkle-trie/#optimization +export type RawExtensionNode = [Uint8Array, Uint8Array] +export type RawLeafNode = [Uint8Array, Uint8Array] + // Branch and extension nodes might store -// hash to next node, or embed it if its len < 32 -export type EmbeddedNode = Uint8Array | Uint8Array[] +// hash to next node, or a raw node if its length < 32 +export type NodeReferenceOrRawNode = Uint8Array | RawExtensionNode | RawLeafNode + +export type BranchNodeBranchValue = NodeReferenceOrRawNode | null export type Proof = Uint8Array[] diff --git a/packages/trie/src/util/nibbles.ts b/packages/trie/src/util/nibbles.ts index 15ec98bf7e..d3dbe181ce 100644 --- a/packages/trie/src/util/nibbles.ts +++ b/packages/trie/src/util/nibbles.ts @@ -81,13 +81,3 @@ export function matchingNibbleLength(nib1: Nibbles, nib2: Nibbles): number { } return i } - -/** - * Compare two nibble array keys. - * @param keyA - * @param keyB - */ -export function doKeysMatch(keyA: Nibbles, keyB: Nibbles): boolean { - const length = matchingNibbleLength(keyA, keyB) - return length === keyA.length && length === keyB.length -}