Skip to content

Commit

Permalink
Trie: test to simplify findPath() to the absolute barebone, remove al…
Browse files Browse the repository at this point in the history
…l chained Promise calls (WIP)
  • Loading branch information
holgerd77 committed Aug 15, 2023
1 parent b153bc6 commit 606873c
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 7 deletions.
77 changes: 74 additions & 3 deletions packages/trie/src/trie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,11 @@ export class Trie {
* @returns A Promise that resolves to `Uint8Array` if a value was found or `null` if no value was found.
*/
async get(key: Uint8Array, throwIfMissing = false): Promise<Uint8Array | null> {
const { node, remaining } = await this.findPath(this.appliedKey(key), throwIfMissing)
const { remaining, stack } = await this.findPath2(this.appliedKey(key), throwIfMissing)
let value: Uint8Array | null = null
if (node && remaining.length === 0) {
value = node.value()
if (remaining.length === 0) {
const last = stack.pop()!
value = last.value()
}
return value
}
Expand Down Expand Up @@ -342,6 +343,76 @@ export class Trie {
})
}

async processNode(nodeKey: Uint8Array, stack: TrieNode[], progress: Nibbles, remaining: Nibbles) {
const node = await this.lookupNode(nodeKey)

if (node === null) {
throw new Error('Path not found')
}
stack.push(node)
const current = remaining[0]!
progress.push(current)
remaining = remaining.slice(1)

if (node instanceof BranchNode) {
if (remaining.length === 0) {
// we exhausted the key without finding a node
return
} else {
const branchNode = node.getBranch(current)
if (!branchNode) {
// there are no more nodes to find and we didn't find the key
return
} else {
// node found, continuing search
// this can be optimized as this calls getBranch again.
//walkController.onlyBranchIndex(node, progress, branchIndex)
await this.processNode(branchNode as Uint8Array, stack, progress, remaining)
}
}
} else if (node instanceof LeafNode) {
if (doKeysMatch(remaining, node.key())) {
return
}
} else if (node instanceof ExtensionNode) {
const matchingLen = matchingNibbleLength(remaining, node.key())
if (matchingLen !== node.key().length) {
return
} else {
// keys match, continue search
const children = [[node.key(), node.value()]]
for (const child of children) {
const childRef = child[1] as Uint8Array
//this.pushNodeToQueue(childRef, childKey, priority)
await this.processNode(childRef, stack, progress, remaining)
}
}
}
}

/**
* Tries to find a path to the node for the given key.
* It returns a `stack` of nodes to the closest node.
* @param key - the search key
* @param throwIfMissing - if true, throws if any nodes are missing. Used for verifying proofs. (default: false)
*/
async findPath2(key: Uint8Array, throwIfMissing = false): Promise<Path> {
const stack: TrieNode[] = []
const nodeKey = this.root()
const progress: Nibbles = []
const remaining = bytesToNibbles(key)
try {
await this.processNode(nodeKey, stack, progress, remaining)
} catch (error: any) {
if (error.message === 'Missing node in DB' && !throwIfMissing) {
// pass
} else {
throw error
}
}
return { node: null, stack, remaining }
}

/**
* Walks a trie until finished.
* @param root
Expand Down
8 changes: 4 additions & 4 deletions packages/trie/src/util/walkController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class WalkController {
* @param node - Node to get all children of and call onNode on.
* @param key - The current `key` which would yield the `node` when trying to get this node with a `get` operation.
*/
allChildren(node: TrieNode, key: Nibbles = []) {
allChildren(node: TrieNode, progress: Nibbles = []) {
if (node instanceof LeafNode) {
return
}
Expand All @@ -82,7 +82,7 @@ export class WalkController {
for (const child of children) {
const keyExtension = child[0] as Nibbles
const childRef = child[1] as Uint8Array
const childKey = key.concat(keyExtension)
const childKey = progress.concat(keyExtension)
const priority = childKey.length
this.pushNodeToQueue(childRef, childKey, priority)
}
Expand Down Expand Up @@ -117,15 +117,15 @@ export class WalkController {
* @param childIndex - The child index to add to the event queue.
* @param priority - Optional priority of the event, defaults to the total key length.
*/
onlyBranchIndex(node: BranchNode, key: Nibbles = [], childIndex: number, priority?: number) {
onlyBranchIndex(node: BranchNode, progress: Nibbles = [], childIndex: number, priority?: number) {
if (!(node instanceof BranchNode)) {
throw new Error('Expected branch node')
}
const childRef = node.getBranch(childIndex)
if (!childRef) {
throw new Error('Could not get branch of childIndex')
}
const childKey = key.slice() // This copies the key to a new array.
const childKey = progress.slice() // This copies the key to a new array.
childKey.push(childIndex)
const prio = priority ?? childKey.length
this.pushNodeToQueue(childRef as Uint8Array, childKey, prio)
Expand Down

0 comments on commit 606873c

Please sign in to comment.