From da22a3881cab3baa9c655ffd48273ae9bbd3b028 Mon Sep 17 00:00:00 2001 From: Scorbajio Date: Wed, 24 Jul 2024 04:39:29 -0700 Subject: [PATCH] Refactor trie util helpers (#3534) * Rename nibblestoBytes to nibblesTypeToPackedBytes * Rename function * Fix function name * Make nibblesToBytes return a byte array to conform to how bytesToNibbles returns one * Fix lint issues * Fix function name * Fix lint issue * update import --------- Co-authored-by: acolytec3 <17355484+acolytec3@users.noreply.github.com> --- packages/trie/src/node/node.ts | 4 +-- packages/trie/src/proof/range.ts | 10 +++--- packages/trie/src/trie.ts | 5 ++- packages/trie/src/util/encoding.ts | 35 ++++++------------- packages/trie/src/util/nibbles.ts | 2 +- packages/trie/test/util/encodingUtils.spec.ts | 4 +-- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/packages/trie/src/node/node.ts b/packages/trie/src/node/node.ts index 76b6888811..c4952532ac 100644 --- a/packages/trie/src/node/node.ts +++ b/packages/trie/src/node/node.ts @@ -1,7 +1,7 @@ import { RLP } from '@ethereumjs/rlp' import { addHexPrefix, removeHexPrefix } from '../util/hex.js' -import { nibblestoBytes } from '../util/nibbles.js' +import { nibblesTypeToPackedBytes } from '../util/nibbles.js' import type { Nibbles } from '../types.js' @@ -45,7 +45,7 @@ export class Node { } raw(): [Uint8Array, Uint8Array] { - return [nibblestoBytes(this.encodedKey()), this._value] + return [nibblesTypeToPackedBytes(this.encodedKey()), this._value] } serialize(): Uint8Array { diff --git a/packages/trie/src/proof/range.ts b/packages/trie/src/proof/range.ts index 57aafdbd57..98003d2dc1 100644 --- a/packages/trie/src/proof/range.ts +++ b/packages/trie/src/proof/range.ts @@ -3,7 +3,7 @@ import { equalsBytes } from '@ethereumjs/util' import { createTrieFromProof } from '../index.js' import { BranchNode, ExtensionNode, LeafNode } from '../node/index.js' import { Trie } from '../trie.js' -import { nibblesCompare, nibblestoBytes } from '../util/nibbles.js' +import { nibblesCompare, nibblesTypeToPackedBytes } from '../util/nibbles.js' import type { HashKeysFunction, Nibbles, TrieNode } from '../types.js' @@ -439,7 +439,7 @@ export async function verifyRangeProof( if (proof === null && firstKey === null && lastKey === null) { const trie = new Trie({ useKeyHashingFunction }) for (let i = 0; i < keys.length; i++) { - await trie.put(nibblestoBytes(keys[i]), values[i]) + await trie.put(nibblesTypeToPackedBytes(keys[i]), values[i]) } if (!equalsBytes(rootHash, trie.root())) { throw new Error('invalid all elements proof: root mismatch') @@ -452,7 +452,7 @@ export async function verifyRangeProof( if (keys.length === 0) { const { trie, value } = await verifyProof( rootHash, - nibblestoBytes(firstKey), + nibblesTypeToPackedBytes(firstKey), proof, useKeyHashingFunction ) @@ -475,7 +475,7 @@ export async function verifyRangeProof( if (keys.length === 1 && nibblesCompare(firstKey, lastKey) === 0) { const { trie, value } = await verifyProof( rootHash, - nibblestoBytes(firstKey), + nibblesTypeToPackedBytes(firstKey), proof, useKeyHashingFunction ) @@ -513,7 +513,7 @@ export async function verifyRangeProof( // Put all elements to the trie for (let i = 0; i < keys.length; i++) { - await trie.put(nibblestoBytes(keys[i]), values[i]) + await trie.put(nibblesTypeToPackedBytes(keys[i]), values[i]) } // Compare rootHash diff --git a/packages/trie/src/trie.ts b/packages/trie/src/trie.ts index 703c099519..1792c30b30 100644 --- a/packages/trie/src/trie.ts +++ b/packages/trie/src/trie.ts @@ -31,8 +31,7 @@ import { import { verifyRangeProof } from './proof/range.js' import { ROOT_DB_KEY } from './types.js' import { _walkTrie } from './util/asyncWalk.js' -import { nibbleTypeToPackedBytes } from './util/encoding.js' -import { bytesToNibbles, matchingNibbleLength } from './util/nibbles.js' +import { bytesToNibbles, matchingNibbleLength, nibblesTypeToPackedBytes } from './util/nibbles.js' import { WalkController } from './util/walkController.js' import type { @@ -1239,7 +1238,7 @@ export class Trie { let nextKey: string | null = null await this.walkAllValueNodes(async (node: TrieNode, currentKey: number[]) => { if (node instanceof LeafNode) { - const keyBytes = nibbleTypeToPackedBytes(currentKey.concat(node.key())) + const keyBytes = nibblesTypeToPackedBytes(currentKey.concat(node.key())) if (!inRange) { // Check if the key is already in the correct range. if (bytesToBigInt(keyBytes) >= startKey) { diff --git a/packages/trie/src/util/encoding.ts b/packages/trie/src/util/encoding.ts index 43b1ea10d6..5212d2f708 100644 --- a/packages/trie/src/util/encoding.ts +++ b/packages/trie/src/util/encoding.ts @@ -1,4 +1,6 @@ -import { hexToBytes, toBytes, unprefixedHexToBytes } from '@ethereumjs/util' +import { concatBytes, hexToBytes, toBytes, unprefixedHexToBytes } from '@ethereumjs/util' + +import { nibblesTypeToPackedBytes } from './nibbles.js' import type { Nibbles } from '../types.js' @@ -32,10 +34,13 @@ export const hasTerminator = (nibbles: Uint8Array) => { return nibbles.length > 0 && nibbles[nibbles.length - 1] === 16 } -export const nibblesToBytes = (nibbles: Uint8Array, bytes: Uint8Array) => { +export const nibblesToBytes = (nibbles: Uint8Array) => { + const bytes = new Uint8Array(nibbles.length / 2) for (let bi = 0, ni = 0; ni < nibbles.length; bi += 1, ni += 2) { bytes[bi] = (nibbles[ni] << 4) | nibbles[ni + 1] } + + return bytes } export const hexToKeybytes = (hex: Uint8Array) => { @@ -45,10 +50,8 @@ export const hexToKeybytes = (hex: Uint8Array) => { if (hex.length % 2 === 1) { throw Error("Can't convert hex key of odd length") } - const key = new Uint8Array(hex.length / 2) - nibblesToBytes(hex, key) - return key + return nibblesToBytes(hex) } // hex to compact @@ -69,9 +72,9 @@ export const nibblesToCompactBytes = (nibbles: Uint8Array) => { buf[0] |= nibbles[0] nibbles = nibbles.subarray(1) } + // create bytes out of the rest even nibbles - nibblesToBytes(nibbles, buf.subarray(1)) - return buf + return concatBytes(buf.subarray(0, 1), nibblesToBytes(nibbles)) } export const bytesToNibbles = (str: Uint8Array) => { @@ -103,22 +106,6 @@ export const compactBytesToNibbles = (compact: Uint8Array) => { return base.subarray(chop) } -/** - * Packs every two nibbles into a single byte - * - * @param arr Nibble typed nibble array - * @returns Uint8Array typed byte array - */ -export const nibbleTypeToPackedBytes = (arr: Nibbles): Uint8Array => { - const buf = new Uint8Array(arr.length / 2) - for (let i = 0; i < buf.length; i++) { - let q = i * 2 - buf[i] = (arr[q] << 4) + arr[++q] - } - - return buf -} - /** * Converts each nibble into a single byte * @@ -167,7 +154,7 @@ export const pathToHexKey = (path: string, extension: Nibbles, retType: string): if (retType === 'hex') { return nibbleTypeToByteType(n.concat(extension)) } else if (retType === 'keybyte') { - return nibbleTypeToPackedBytes(n.concat(extension)) + return nibblesTypeToPackedBytes(n.concat(extension)) } throw Error('retType must be either "keybyte" or "hex"') } diff --git a/packages/trie/src/util/nibbles.ts b/packages/trie/src/util/nibbles.ts index 3c5d9c231f..9bc473f310 100644 --- a/packages/trie/src/util/nibbles.ts +++ b/packages/trie/src/util/nibbles.ts @@ -26,7 +26,7 @@ export function bytesToNibbles(key: Uint8Array): Nibbles { * @private * @param arr - Nibble array */ -export function nibblestoBytes(arr: Nibbles): Uint8Array { +export function nibblesTypeToPackedBytes(arr: Nibbles): Uint8Array { const buf = new Uint8Array(arr.length / 2) for (let i = 0; i < buf.length; i++) { let q = i * 2 diff --git a/packages/trie/test/util/encodingUtils.spec.ts b/packages/trie/test/util/encodingUtils.spec.ts index 08152f8406..cf09a89d8d 100644 --- a/packages/trie/test/util/encodingUtils.spec.ts +++ b/packages/trie/test/util/encodingUtils.spec.ts @@ -7,10 +7,10 @@ import { compactBytesToNibbles, mergeAndFormatKeyPaths, nibbleTypeToByteType, - nibbleTypeToPackedBytes, nibblesToCompactBytes, pathToHexKey, } from '../../src/util/encoding.js' +import { nibblesTypeToPackedBytes } from '../../src/util/nibbles.js' import type { Nibbles } from '../../src/types.js' @@ -93,7 +93,7 @@ describe('encoding', () => { // Calculate the expected result manually based on the functions used in the pathToHexKey function const b = hexToBytes(`0x${path}`) const n = byteTypeToNibbleType(b) - const expected = nibbleTypeToPackedBytes(n.concat(extension)) + const expected = nibblesTypeToPackedBytes(n.concat(extension)) assert.deepEqual( result,