UNPKG

5.33 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.WalkController = void 0;
4const prioritizedTaskExecutor_1 = require("../prioritizedTaskExecutor");
5const trieNode_1 = require("../trieNode");
6/**
7 * WalkController is an interface to control how the trie is being traversed.
8 */
9class WalkController {
10 /**
11 * Creates a new WalkController
12 * @param onNode - The `FoundNodeFunction` to call if a node is found.
13 * @param trie - The `Trie` to walk on.
14 * @param poolSize - The size of the task queue.
15 */
16 constructor(onNode, trie, poolSize) {
17 this.onNode = onNode;
18 this.taskExecutor = new prioritizedTaskExecutor_1.PrioritizedTaskExecutor(poolSize);
19 this.trie = trie;
20 this.resolve = () => { };
21 this.reject = () => { };
22 }
23 /**
24 * Async function to create and start a new walk over a trie.
25 * @param onNode - The `FoundNodeFunction to call if a node is found.
26 * @param trie - The trie to walk on.
27 * @param root - The root key to walk on.
28 * @param poolSize - Task execution pool size to prevent OOM errors. Defaults to 500.
29 */
30 static async newWalk(onNode, trie, root, poolSize) {
31 const strategy = new WalkController(onNode, trie, poolSize !== null && poolSize !== void 0 ? poolSize : 500);
32 await strategy.startWalk(root);
33 }
34 async startWalk(root) {
35 // eslint-disable-next-line no-async-promise-executor
36 return await new Promise(async (resolve, reject) => {
37 this.resolve = resolve;
38 this.reject = reject;
39 let node;
40 try {
41 node = await this.trie._lookupNode(root);
42 }
43 catch (error) {
44 return this.reject(error);
45 }
46 this.processNode(root, node, []);
47 });
48 }
49 /**
50 * Run all children of a node. Priority of these nodes are the key length of the children.
51 * @param node - Node to get all children of and call onNode on.
52 * @param key - The current `key` which would yield the `node` when trying to get this node with a `get` operation.
53 */
54 allChildren(node, key = []) {
55 if (node instanceof trieNode_1.LeafNode) {
56 return;
57 }
58 let children;
59 if (node instanceof trieNode_1.ExtensionNode) {
60 children = [[node.key, node.value]];
61 }
62 else if (node instanceof trieNode_1.BranchNode) {
63 children = node.getChildren().map((b) => [[b[0]], b[1]]);
64 }
65 if (!children) {
66 return;
67 }
68 for (const child of children) {
69 const keyExtension = child[0];
70 const childRef = child[1];
71 const childKey = key.concat(keyExtension);
72 const priority = childKey.length;
73 this.pushNodeToQueue(childRef, childKey, priority);
74 }
75 }
76 /**
77 * Push a node to the queue. If the queue has places left for tasks, the node is executed immediately, otherwise it is queued.
78 * @param nodeRef - Push a node reference to the event queue. This reference is a 32-byte keccak hash of the value corresponding to the `key`.
79 * @param key - The current key.
80 * @param priority - Optional priority, defaults to key length
81 */
82 pushNodeToQueue(nodeRef, key = [], priority) {
83 this.taskExecutor.executeOrQueue(priority !== null && priority !== void 0 ? priority : key.length, async (taskFinishedCallback) => {
84 let childNode;
85 try {
86 childNode = await this.trie._lookupNode(nodeRef);
87 }
88 catch (error) {
89 return this.reject(error);
90 }
91 taskFinishedCallback(); // this marks the current task as finished. If there are any tasks left in the queue, this will immediately execute the first task.
92 this.processNode(nodeRef, childNode, key);
93 });
94 }
95 /**
96 * Push a branch of a certain BranchNode to the event queue.
97 * @param node - The node to select a branch on. Should be a BranchNode.
98 * @param key - The current key which leads to the corresponding node.
99 * @param childIndex - The child index to add to the event queue.
100 * @param priority - Optional priority of the event, defaults to the total key length.
101 */
102 onlyBranchIndex(node, key = [], childIndex, priority) {
103 if (!(node instanceof trieNode_1.BranchNode)) {
104 throw new Error('Expected branch node');
105 }
106 const childRef = node.getBranch(childIndex);
107 if (!childRef) {
108 throw new Error('Could not get branch of childIndex');
109 }
110 const childKey = key.slice(); // This copies the key to a new array.
111 childKey.push(childIndex);
112 const prio = priority !== null && priority !== void 0 ? priority : childKey.length;
113 this.pushNodeToQueue(childRef, childKey, prio);
114 }
115 processNode(nodeRef, node, key = []) {
116 this.onNode(nodeRef, node, key, this);
117 if (this.taskExecutor.finished()) {
118 // onNode should schedule new tasks. If no tasks was added and the queue is empty, then we have finished our walk.
119 this.resolve();
120 }
121 }
122}
123exports.WalkController = WalkController;
124//# sourceMappingURL=walkController.js.map
\No newline at end of file