Skip to content

Commit a8a8973

Browse files
Use node hash as db key (#3472)
* Update findPath to use node hash as db key * update verkle crypto package to latest [no ci] * Update test logic to use findPath result in updating trie * verkle: remove unused imporT --------- Co-authored-by: Gabriel Rocheleau <[email protected]>
1 parent 22612f2 commit a8a8973

File tree

8 files changed

+49
-33
lines changed

8 files changed

+49
-33
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"level": "^8.0.0",
8888
"memory-level": "^1.0.0",
8989
"prom-client": "^15.1.0",
90-
"verkle-cryptography-wasm": "^0.4.2",
90+
"verkle-cryptography-wasm": "^0.4.5",
9191
"winston": "^3.3.3",
9292
"winston-daily-rotate-file": "^4.5.5",
9393
"yargs": "^17.7.1"

packages/statemanager/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,6 @@
6363
"@ethereumjs/genesis": "^0.2.2",
6464
"@types/debug": "^4.1.9",
6565
"rustbn-wasm": "^0.4.0",
66-
"verkle-cryptography-wasm": "^0.4.2"
66+
"verkle-cryptography-wasm": "^0.4.5"
6767
}
6868
}

packages/verkle/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"dependencies": {
5555
"debug": "^4.3.4",
5656
"lru-cache": "10.1.0",
57-
"verkle-cryptography-wasm": "^0.4.4",
57+
"verkle-cryptography-wasm": "^0.4.5",
5858
"@ethereumjs/block": "^5.2.0",
5959
"@ethereumjs/rlp": "^5.0.2",
6060
"@ethereumjs/util": "^9.0.3"

packages/verkle/src/node/baseVerkleNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { RLP } from '@ethereumjs/rlp'
22

33
import { type VerkleNodeInterface, type VerkleNodeOptions, type VerkleNodeType } from './types.js'
44

5-
import type { VerkleCrypto } from 'verkle-cryptography-wasm'
5+
import type { VerkleCrypto } from '@ethereumjs/util'
66

77
export abstract class BaseVerkleNode<T extends VerkleNodeType> implements VerkleNodeInterface {
88
public commitment: Uint8Array

packages/verkle/src/node/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { InternalNode } from './internalNode.js'
22
import type { LeafNode } from './leafNode.js'
3-
import type { VerkleCrypto } from 'verkle-cryptography-wasm'
3+
import type { VerkleCrypto } from '@ethereumjs/util'
44

55
export enum VerkleNodeType {
66
Internal,

packages/verkle/src/verkleTree.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,15 +234,14 @@ export class VerkleTree {
234234
if (equalsBytes(this.root(), this.EMPTY_TREE_ROOT)) return result
235235

236236
// Get root node
237-
let rawNode = await this._db.get(ROOT_DB_KEY)
237+
let rawNode = await this._db.get(this.root())
238238
if (rawNode === undefined)
239239
throw new Error('root node should exist when root not empty tree root')
240240

241241
const rootNode = decodeNode(rawNode, this.verkleCrypto) as InternalNode
242242

243-
this.DEBUG &&
244-
this.debug(`Starting with Root Node: [${bytesToHex(rootNode.hash())}]`, ['FIND_PATH'])
245-
result.stack.push([rootNode, ROOT_DB_KEY])
243+
this.DEBUG && this.debug(`Starting with Root Node: [${bytesToHex(this.root())}]`, ['FIND_PATH'])
244+
result.stack.push([rootNode, this.root()])
246245
let child = rootNode.children[key[0]]
247246

248247
// Root node doesn't contain a child node's commitment on the first byte of the path so we're done
@@ -252,7 +251,8 @@ export class VerkleTree {
252251
}
253252
let finished = false
254253
while (!finished) {
255-
rawNode = await this._db.get(child.path)
254+
// Look up child node by node hash
255+
rawNode = await this._db.get(this.verkleCrypto.hashCommitment(child.commitment))
256256
// We should always find the node if the path is specified in child.path
257257
if (rawNode === undefined) throw new Error(`missing node at ${bytesToHex(child.path)}`)
258258
const decodedNode = decodeNode(rawNode, this.verkleCrypto)
@@ -330,10 +330,9 @@ export class VerkleTree {
330330

331331
// Update the child node's commitment and path
332332
this.DEBUG && this.debug(`No root node. Creating new root node`, ['INITIALIZE'])
333-
334-
await this.saveStack([[ROOT_DB_KEY, rootNode]])
335333
// Set trie root to serialized (aka compressed) commitment for later use in verkle proof
336334
this.root(this.verkleCrypto.serializeCommitment(rootNode.commitment))
335+
await this.saveStack([[this.root(), rootNode]])
337336
return
338337
}
339338

packages/verkle/test/verkle.spec.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { assert, beforeAll, describe, it } from 'vitest'
55
import {
66
InternalNode,
77
LeafNode,
8-
ROOT_DB_KEY,
8+
VerkleNodeType,
99
decodeNode,
1010
matchingBytesLength,
1111
} from '../src/index.js'
@@ -163,16 +163,16 @@ describe('findPath validation', () => {
163163
leafNode1.setValue(hexToBytes(keys[0])[31], hexToBytes(values[0]))
164164
leafNode1.setValue(hexToBytes(keys[1])[31], hexToBytes(values[1]))
165165

166-
putStack.push([stem1, leafNode1])
166+
putStack.push([leafNode1.hash(), leafNode1])
167167

168168
// Pull root node from DB
169-
const rawNode = await trie['_db'].get(ROOT_DB_KEY)
169+
const rawNode = await trie['_db'].get(trie.root())
170170
const rootNode = decodeNode(rawNode!, verkleCrypto) as InternalNode
171171
// Update root node with commitment from leaf node
172172
rootNode.setChild(stem1[0], { commitment: leafNode1.commitment, path: stem1 })
173-
putStack.push([ROOT_DB_KEY, rootNode])
174-
await trie.saveStack(putStack)
175173
trie.root(verkleCrypto.serializeCommitment(rootNode.commitment))
174+
putStack.push([trie.root(), rootNode])
175+
await trie.saveStack(putStack)
176176

177177
// Verify that path to leaf node can be found from stem
178178
const res = await trie.findPath(stem1)
@@ -185,41 +185,58 @@ describe('findPath validation', () => {
185185
// Put a second leaf node in the tree with a partially matching stem
186186
putStack = []
187187
const stem2 = hexToBytes(keys[2]).slice(0, 31)
188+
189+
// Find path to closest node in tree
190+
const foundPath = await trie.findPath(stem2)
191+
192+
// Confirm node with stem2 doesn't exist in trie
193+
assert.equal(foundPath.node, null)
194+
195+
// Create new leaf node
188196
const leafNode2 = await LeafNode.create(
189197
stem2,
190198
new Array(256).fill(new Uint8Array(32)),
191199
verkleCrypto
192200
)
193201
leafNode2.setValue(hexToBytes(keys[2])[31], hexToBytes(values[2]))
194-
putStack.push([stem2, leafNode2])
202+
putStack.push([leafNode2.hash(), leafNode2])
195203

196-
// Create new internal node
197-
const internalNode1 = InternalNode.create(verkleCrypto)
204+
const nearestNode = foundPath.stack.pop()![0]
205+
// Verify that another leaf node is "nearest" node
206+
assert.equal(nearestNode.type, VerkleNodeType.Leaf)
207+
assert.deepEqual(nearestNode, leafNode1)
198208

199-
// Compute the portion of stem1 and stem2 that match
209+
// Compute the portion of stem1 and stem2 that match (i.e. the partial path closest to stem2)
200210
// Note: We subtract 1 since we are using 0-indexed arrays
201211
const partialMatchingStemIndex = matchingBytesLength(stem1, stem2) - 1
202212
// Find the path to the new internal node (the matching portion of stem1 and stem2)
203213
const internalNode1Path = stem1.slice(0, partialMatchingStemIndex)
214+
// Create new internal node
215+
const internalNode1 = InternalNode.create(verkleCrypto)
216+
204217
// Update the child references for leafNode1 and leafNode 2
205218
internalNode1.setChild(stem1[partialMatchingStemIndex], {
206-
commitment: leafNode1.commitment,
207-
path: stem1,
219+
commitment: nearestNode.commitment,
220+
path: (nearestNode as LeafNode).stem,
208221
})
209222
internalNode1.setChild(stem2[partialMatchingStemIndex], {
210223
commitment: leafNode2.commitment,
211224
path: stem2,
212225
})
213226

214-
putStack.push([internalNode1Path, internalNode1])
227+
putStack.push([internalNode1.hash(), internalNode1])
215228
// Update rootNode child reference for internal node 1
216-
rootNode.setChild(internalNode1Path[0], {
229+
230+
const rootNodeFromPath = foundPath.stack.pop()![0] as InternalNode
231+
// Confirm node from findPath matches root
232+
assert.deepEqual(rootNodeFromPath, rootNode)
233+
rootNodeFromPath.setChild(internalNode1Path[0], {
217234
commitment: internalNode1.commitment,
218235
path: internalNode1Path,
219236
})
220-
putStack.push([ROOT_DB_KEY, rootNode])
237+
trie.root(verkleCrypto.serializeCommitment(rootNodeFromPath.commitment))
238+
putStack.push([trie.root(), rootNodeFromPath])
221239
await trie.saveStack(putStack)
222-
trie.root(verkleCrypto.serializeCommitment(rootNode.commitment))
223240
let res2 = await trie.findPath(stem1)
224241

225242
assert.equal(res2.remaining.length, 0, 'confirm full path was found')

0 commit comments

Comments
 (0)