Skip to content

Commit a61ee80

Browse files
committed
state: fix and test nibble functions
1 parent ba8437d commit a61ee80

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

packages/portalnetwork/src/networks/state/util.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,29 @@ export function calculateAddressRange(
132132
* [1, 2, a, b] -> Nibbles(is_odd_length=false, packed_nibbles=[0x12, 0xab])
133133
* [1, 2, a, b, c] -> Nibbles(is_odd_length=true, packed_nibbles=[0x01, 0x2a, 0xbc])
134134
*/
135-
export const tightlyPackNibbles = (nibbles: TNibble[]): TNibbles => {
136-
if (!nibbles.every((nibble) => Nibble[nibble] !== undefined)) {
137-
throw new Error(`path: [${nibbles}] must be an array of nibbles`)
135+
export const tightlyPackNibbles = (_nibbles: TNibble[]): TNibbles => {
136+
if (!_nibbles.every((nibble) => Nibble[nibble] !== undefined)) {
137+
throw new Error(`path: [${_nibbles}] must be an array of nibbles`)
138138
}
139+
const nibbles: number[] = _nibbles.map((nibble) =>
140+
typeof nibble === 'string' ? parseInt(nibble, 16) : nibble,
141+
)
139142
const isOddLength = nibbles.length % 2 !== 0
140-
const nibbleArray = isOddLength ? ['0', ...nibbles] : nibbles
143+
const nibbleArray = isOddLength ? [0, ...nibbles] : nibbles
141144
const nibblePairs = Array.from({ length: nibbleArray.length / 2 }, (_, idx) => idx).map((i) => {
142145
return nibbleArray.slice(2 * i, 2 * i + 2) as [TNibble, TNibble]
143146
})
144-
const packedBytes = nibblePairs.map((nibbles) => {
145-
return parseInt(nibbles.join(''), 16)
147+
const packedBytes = nibblePairs.map(([a, b]) => {
148+
return parseInt(a.toString(16) + b.toString(16), 16)
146149
})
147150
return { isOddLength, packedNibbles: Uint8Array.from(packedBytes) }
148151
}
152+
153+
export const unpackNibbles = (packedNibbles: Uint8Array, isOddLength: boolean): TNibble[] => {
154+
const unpacked = packedNibbles.reduce((acc, byte, _idx, _array) => {
155+
acc.push((byte >>> 4) as TNibble)
156+
acc.push((byte & 0x0f) as TNibble)
157+
return acc
158+
}, [] as TNibble[])
159+
return isOddLength ? unpacked.slice(1) : unpacked
160+
}

packages/portalnetwork/test/networks/state/utils.spec.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { randomBytes } from '@ethereumjs/util'
2-
import { assert, describe, it } from 'vitest'
2+
import { assert, describe, expect, it } from 'vitest'
33

44
import { StateNetworkContentType } from '../../../src/networks/state/types.js'
55
import {
66
MODULO,
77
calculateAddressRange,
88
distance,
99
keyType,
10+
tightlyPackNibbles,
11+
unpackNibbles,
1012
} from '../../../src/networks/state/util.js'
1113

14+
import type { TNibble } from '../../../src/networks/state/types.js'
15+
1216
describe('distance()', () => {
1317
it('should calculate distance between two values', () => {
1418
assert.ok(distance(10n, 10n) === 0n, 'calculates correct distance')
@@ -197,3 +201,36 @@ describe('calculateAddressRange: ' + address.slice(0, 18) + '...', () => {
197201
})
198202
})
199203
})
204+
205+
describe('Nibbles', () => {
206+
const nibbleArrays: TNibble[][] = [
207+
[0],
208+
[0, 1],
209+
[1, 2, 3],
210+
[1, 2, 3, 4],
211+
['a', 'b', 'c'],
212+
['a', 'b', 'c', 9],
213+
['a', 'b', 'c', 10],
214+
['a', 'b', 'c', 10, 11],
215+
['a', 'b', 'c', 10, 11, 'd'],
216+
]
217+
218+
for (const nibbles of nibbleArrays) {
219+
const packed = tightlyPackNibbles(nibbles)
220+
const unpacked = unpackNibbles(packed.packedNibbles, packed.isOddLength)
221+
it('should calculate packed nibbles', () => {
222+
expect(packed.isOddLength).toEqual(nibbles.length % 2 !== 0)
223+
expect(packed.packedNibbles.length).toEqual(Math.ceil(nibbles.length / 2))
224+
})
225+
it('should unpack packed nibbles', () => {
226+
expect(unpacked.length).toEqual(nibbles.length)
227+
for (const [idx, nibble] of nibbles.entries()) {
228+
if (typeof nibble === 'string') {
229+
expect(parseInt(nibble, 16)).toEqual(unpacked[idx])
230+
} else {
231+
expect(nibble).toEqual(unpacked[idx])
232+
}
233+
}
234+
})
235+
}
236+
})

0 commit comments

Comments
 (0)