@aztec/simulator 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/dest/acvm/acvm.d.ts +2 -16
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/acvm.js +2 -70
  4. package/dest/acvm/oracle/oracle.d.ts +4 -3
  5. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/oracle.js +11 -9
  7. package/dest/acvm/oracle/typed_oracle.d.ts +5 -4
  8. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/typed_oracle.js +9 -6
  10. package/dest/avm/avm_gas.d.ts.map +1 -1
  11. package/dest/avm/avm_gas.js +4 -3
  12. package/dest/avm/avm_machine_state.d.ts +27 -8
  13. package/dest/avm/avm_machine_state.d.ts.map +1 -1
  14. package/dest/avm/avm_machine_state.js +6 -10
  15. package/dest/avm/avm_memory_types.d.ts +8 -0
  16. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  17. package/dest/avm/avm_memory_types.js +5 -1
  18. package/dest/avm/avm_simulator.d.ts +2 -19
  19. package/dest/avm/avm_simulator.d.ts.map +1 -1
  20. package/dest/avm/avm_simulator.js +12 -14
  21. package/dest/avm/avm_tree.d.ts +249 -0
  22. package/dest/avm/avm_tree.d.ts.map +1 -0
  23. package/dest/avm/avm_tree.js +637 -0
  24. package/dest/avm/errors.d.ts +4 -17
  25. package/dest/avm/errors.d.ts.map +1 -1
  26. package/dest/avm/errors.js +21 -50
  27. package/dest/avm/fixtures/index.d.ts +7 -2
  28. package/dest/avm/fixtures/index.d.ts.map +1 -1
  29. package/dest/avm/fixtures/index.js +12 -12
  30. package/dest/avm/index.d.ts +1 -0
  31. package/dest/avm/index.d.ts.map +1 -1
  32. package/dest/avm/index.js +2 -1
  33. package/dest/avm/journal/journal.d.ts +43 -24
  34. package/dest/avm/journal/journal.d.ts.map +1 -1
  35. package/dest/avm/journal/journal.js +172 -39
  36. package/dest/avm/journal/nullifiers.d.ts +5 -4
  37. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  38. package/dest/avm/journal/nullifiers.js +2 -3
  39. package/dest/avm/journal/public_storage.d.ts +6 -5
  40. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  41. package/dest/avm/journal/public_storage.js +1 -1
  42. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  43. package/dest/avm/opcodes/accrued_substate.js +4 -10
  44. package/dest/avm/opcodes/arithmetic.d.ts +4 -1
  45. package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
  46. package/dest/avm/opcodes/arithmetic.js +18 -4
  47. package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
  48. package/dest/avm/opcodes/bitwise.js +1 -3
  49. package/dest/avm/opcodes/comparators.d.ts.map +1 -1
  50. package/dest/avm/opcodes/comparators.js +1 -2
  51. package/dest/avm/opcodes/contract.d.ts.map +1 -1
  52. package/dest/avm/opcodes/contract.js +2 -3
  53. package/dest/avm/opcodes/control_flow.d.ts +4 -0
  54. package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
  55. package/dest/avm/opcodes/control_flow.js +26 -11
  56. package/dest/avm/opcodes/conversion.d.ts.map +1 -1
  57. package/dest/avm/opcodes/conversion.js +1 -2
  58. package/dest/avm/opcodes/ec_add.d.ts.map +1 -1
  59. package/dest/avm/opcodes/ec_add.js +5 -11
  60. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  61. package/dest/avm/opcodes/environment_getters.js +1 -2
  62. package/dest/avm/opcodes/external_calls.d.ts +4 -2
  63. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  64. package/dest/avm/opcodes/external_calls.js +38 -22
  65. package/dest/avm/opcodes/hashing.d.ts.map +1 -1
  66. package/dest/avm/opcodes/hashing.js +1 -4
  67. package/dest/avm/opcodes/instruction.d.ts +4 -0
  68. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  69. package/dest/avm/opcodes/instruction.js +7 -1
  70. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  71. package/dest/avm/opcodes/memory.js +1 -7
  72. package/dest/avm/opcodes/misc.js +3 -3
  73. package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
  74. package/dest/avm/opcodes/multi_scalar_mul.js +6 -5
  75. package/dest/avm/opcodes/storage.d.ts.map +1 -1
  76. package/dest/avm/opcodes/storage.js +2 -4
  77. package/dest/avm/serialization/bytecode_serialization.d.ts +1 -6
  78. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  79. package/dest/avm/serialization/bytecode_serialization.js +24 -20
  80. package/dest/avm/serialization/instruction_serialization.d.ts +2 -2
  81. package/dest/avm/serialization/instruction_serialization.js +2 -2
  82. package/dest/client/client_execution_context.d.ts +7 -10
  83. package/dest/client/client_execution_context.d.ts.map +1 -1
  84. package/dest/client/client_execution_context.js +19 -18
  85. package/dest/client/db_oracle.d.ts +22 -8
  86. package/dest/client/db_oracle.d.ts.map +1 -1
  87. package/dest/client/db_oracle.js +1 -1
  88. package/dest/client/private_execution.d.ts.map +1 -1
  89. package/dest/client/private_execution.js +5 -4
  90. package/dest/client/unconstrained_execution.d.ts.map +1 -1
  91. package/dest/client/unconstrained_execution.js +3 -2
  92. package/dest/client/view_data_oracle.d.ts +6 -12
  93. package/dest/client/view_data_oracle.d.ts.map +1 -1
  94. package/dest/client/view_data_oracle.js +10 -12
  95. package/dest/common/errors.d.ts +15 -2
  96. package/dest/common/errors.d.ts.map +1 -1
  97. package/dest/common/errors.js +85 -4
  98. package/dest/mocks/fixtures.d.ts +9 -28
  99. package/dest/mocks/fixtures.d.ts.map +1 -1
  100. package/dest/mocks/fixtures.js +12 -57
  101. package/dest/public/dual_side_effect_trace.d.ts +34 -26
  102. package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
  103. package/dest/public/dual_side_effect_trace.js +48 -36
  104. package/dest/public/enqueued_call_side_effect_trace.d.ts +96 -33
  105. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  106. package/dest/public/enqueued_call_side_effect_trace.js +212 -138
  107. package/dest/public/execution.d.ts +50 -17
  108. package/dest/public/execution.d.ts.map +1 -1
  109. package/dest/public/execution.js +1 -29
  110. package/dest/public/executor.d.ts +28 -11
  111. package/dest/public/executor.d.ts.map +1 -1
  112. package/dest/public/executor.js +33 -33
  113. package/dest/public/index.d.ts +4 -5
  114. package/dest/public/index.d.ts.map +1 -1
  115. package/dest/public/index.js +4 -5
  116. package/dest/public/public_db_sources.d.ts +1 -0
  117. package/dest/public/public_db_sources.d.ts.map +1 -1
  118. package/dest/public/public_db_sources.js +21 -19
  119. package/dest/public/public_processor.d.ts +7 -11
  120. package/dest/public/public_processor.d.ts.map +1 -1
  121. package/dest/public/public_processor.js +60 -42
  122. package/dest/public/public_processor_metrics.d.ts +3 -3
  123. package/dest/public/public_processor_metrics.d.ts.map +1 -1
  124. package/dest/public/public_processor_metrics.js +1 -1
  125. package/dest/public/public_tx_context.d.ts +130 -0
  126. package/dest/public/public_tx_context.d.ts.map +1 -0
  127. package/dest/public/public_tx_context.js +293 -0
  128. package/dest/public/public_tx_simulator.d.ts +36 -0
  129. package/dest/public/public_tx_simulator.d.ts.map +1 -0
  130. package/dest/public/public_tx_simulator.js +148 -0
  131. package/dest/public/side_effect_trace.d.ts +30 -15
  132. package/dest/public/side_effect_trace.d.ts.map +1 -1
  133. package/dest/public/side_effect_trace.js +70 -16
  134. package/dest/public/side_effect_trace_interface.d.ts +43 -12
  135. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  136. package/dest/public/transitional_adapters.d.ts +9 -0
  137. package/dest/public/transitional_adapters.d.ts.map +1 -0
  138. package/dest/public/transitional_adapters.js +127 -0
  139. package/dest/public/utils.d.ts +5 -0
  140. package/dest/public/utils.d.ts.map +1 -0
  141. package/dest/public/utils.js +30 -0
  142. package/dest/test/utils.d.ts +2 -2
  143. package/dest/test/utils.d.ts.map +1 -1
  144. package/dest/test/utils.js +4 -4
  145. package/package.json +12 -9
  146. package/src/acvm/acvm.ts +3 -94
  147. package/src/acvm/oracle/oracle.ts +14 -12
  148. package/src/acvm/oracle/typed_oracle.ts +10 -6
  149. package/src/avm/avm_gas.ts +3 -2
  150. package/src/avm/avm_machine_state.ts +28 -12
  151. package/src/avm/avm_memory_types.ts +5 -0
  152. package/src/avm/avm_simulator.ts +13 -16
  153. package/src/avm/avm_tree.ts +785 -0
  154. package/src/avm/errors.ts +25 -48
  155. package/src/avm/fixtures/index.ts +16 -12
  156. package/src/avm/index.ts +1 -0
  157. package/src/avm/journal/journal.ts +291 -52
  158. package/src/avm/journal/nullifiers.ts +7 -7
  159. package/src/avm/journal/public_storage.ts +5 -5
  160. package/src/avm/opcodes/accrued_substate.ts +3 -9
  161. package/src/avm/opcodes/arithmetic.ts +26 -4
  162. package/src/avm/opcodes/bitwise.ts +0 -2
  163. package/src/avm/opcodes/comparators.ts +0 -1
  164. package/src/avm/opcodes/contract.ts +1 -2
  165. package/src/avm/opcodes/control_flow.ts +29 -10
  166. package/src/avm/opcodes/conversion.ts +0 -1
  167. package/src/avm/opcodes/ec_add.ts +6 -9
  168. package/src/avm/opcodes/environment_getters.ts +0 -1
  169. package/src/avm/opcodes/external_calls.ts +39 -21
  170. package/src/avm/opcodes/hashing.ts +0 -3
  171. package/src/avm/opcodes/instruction.ts +7 -0
  172. package/src/avm/opcodes/memory.ts +0 -6
  173. package/src/avm/opcodes/misc.ts +2 -2
  174. package/src/avm/opcodes/multi_scalar_mul.ts +5 -4
  175. package/src/avm/opcodes/storage.ts +1 -3
  176. package/src/avm/serialization/bytecode_serialization.ts +31 -22
  177. package/src/avm/serialization/instruction_serialization.ts +2 -2
  178. package/src/client/client_execution_context.ts +24 -21
  179. package/src/client/db_oracle.ts +31 -8
  180. package/src/client/private_execution.ts +5 -4
  181. package/src/client/unconstrained_execution.ts +2 -1
  182. package/src/client/view_data_oracle.ts +14 -13
  183. package/src/common/errors.ts +119 -3
  184. package/src/mocks/fixtures.ts +15 -106
  185. package/src/public/dual_side_effect_trace.ts +138 -50
  186. package/src/public/enqueued_call_side_effect_trace.ts +352 -212
  187. package/src/public/execution.ts +58 -42
  188. package/src/public/executor.ts +52 -67
  189. package/src/public/index.ts +7 -5
  190. package/src/public/public_db_sources.ts +22 -19
  191. package/src/public/public_processor.ts +111 -73
  192. package/src/public/public_processor_metrics.ts +3 -3
  193. package/src/public/public_tx_context.ts +411 -0
  194. package/src/public/public_tx_simulator.ts +232 -0
  195. package/src/public/side_effect_trace.ts +154 -28
  196. package/src/public/side_effect_trace_interface.ts +92 -14
  197. package/src/public/transitional_adapters.ts +347 -0
  198. package/src/public/utils.ts +32 -0
  199. package/src/test/utils.ts +9 -2
  200. package/dest/public/enqueued_call_simulator.d.ts +0 -43
  201. package/dest/public/enqueued_call_simulator.d.ts.map +0 -1
  202. package/dest/public/enqueued_call_simulator.js +0 -156
  203. package/dest/public/enqueued_calls_processor.d.ts +0 -43
  204. package/dest/public/enqueued_calls_processor.d.ts.map +0 -1
  205. package/dest/public/enqueued_calls_processor.js +0 -209
  206. package/dest/public/hints_builder.d.ts +0 -29
  207. package/dest/public/hints_builder.d.ts.map +0 -1
  208. package/dest/public/hints_builder.js +0 -75
  209. package/dest/public/public_kernel.d.ts +0 -30
  210. package/dest/public/public_kernel.d.ts.map +0 -1
  211. package/dest/public/public_kernel.js +0 -67
  212. package/dest/public/public_kernel_circuit_simulator.d.ts +0 -25
  213. package/dest/public/public_kernel_circuit_simulator.d.ts.map +0 -1
  214. package/dest/public/public_kernel_circuit_simulator.js +0 -2
  215. package/dest/public/public_kernel_tail_simulator.d.ts +0 -15
  216. package/dest/public/public_kernel_tail_simulator.d.ts.map +0 -1
  217. package/dest/public/public_kernel_tail_simulator.js +0 -39
  218. package/src/public/enqueued_call_simulator.ts +0 -360
  219. package/src/public/enqueued_calls_processor.ts +0 -372
  220. package/src/public/hints_builder.ts +0 -168
  221. package/src/public/public_kernel.ts +0 -100
  222. package/src/public/public_kernel_circuit_simulator.ts +0 -32
  223. package/src/public/public_kernel_tail_simulator.ts +0 -97
@@ -0,0 +1,637 @@
1
+ import { MerkleTreeId, getTreeHeight } from '@aztec/circuit-types';
2
+ import { NullifierLeafPreimage, PublicDataTreeLeafPreimage } from '@aztec/circuits.js';
3
+ import { poseidon2Hash } from '@aztec/foundation/crypto';
4
+ import { Fr } from '@aztec/foundation/fields';
5
+ import cloneDeep from 'lodash.clonedeep';
6
+ /****************************************************/
7
+ /****** The AvmEphemeralForest Class ****************/
8
+ /****************************************************/
9
+ /**
10
+ * This provides a forkable abstraction over the EphemeralAvmTree class
11
+ * It contains the logic to look up into a read-only MerkleTreeDb to discover
12
+ * the sibling paths and low witnesses that weren't inserted as part of this tx
13
+ */
14
+ export class AvmEphemeralForest {
15
+ constructor(treeDb, treeMap,
16
+ // This contains the preimage and the leaf index of leaf in the ephemeral tree that contains the lowest key (i.e. nullifier value or public data tree slot)
17
+ indexedTreeMin,
18
+ // This contains the [leaf index,indexed leaf preimages] tuple that were updated or inserted in the ephemeral tree
19
+ // This is needed since we have a sparse collection of keys sorted leaves in the ephemeral tree
20
+ indexedUpdates) {
21
+ this.treeDb = treeDb;
22
+ this.treeMap = treeMap;
23
+ this.indexedTreeMin = indexedTreeMin;
24
+ this.indexedUpdates = indexedUpdates;
25
+ }
26
+ static async create(treeDb) {
27
+ const treeMap = new Map();
28
+ for (const treeType of [MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.PUBLIC_DATA_TREE]) {
29
+ const treeInfo = await treeDb.getTreeInfo(treeType);
30
+ const tree = await EphemeralAvmTree.create(treeInfo.size, treeInfo.depth, treeDb, treeType);
31
+ treeMap.set(treeType, tree);
32
+ }
33
+ return new AvmEphemeralForest(treeDb, treeMap, new Map(), new Map());
34
+ }
35
+ fork() {
36
+ return new AvmEphemeralForest(this.treeDb, cloneDeep(this.treeMap), cloneDeep(this.indexedTreeMin), cloneDeep(this.indexedUpdates));
37
+ }
38
+ /**
39
+ * Gets sibling path for a leaf - if the sibling path is not found in the tree, it is fetched from the DB
40
+ * @param treeId - The tree to be queried for a sibling path.
41
+ * @param index - The index of the leaf for which a sibling path should be returned.
42
+ * @returns The sibling path of the leaf.
43
+ */
44
+ async getSiblingPath(treeId, index) {
45
+ const tree = this.treeMap.get(treeId);
46
+ let path = tree.getSiblingPath(index);
47
+ if (path === undefined) {
48
+ // We dont have the sibling path in our tree - we have to get it from the DB
49
+ path = (await this.treeDb.getSiblingPath(treeId, index)).toFields();
50
+ // Since the sibling path could be outdated, we compare it with nodes in our tree
51
+ // if we encounter a mismatch, we replace it with the node we found in our tree.
52
+ for (let i = 0; i < path.length; i++) {
53
+ const siblingIndex = index ^ 1n;
54
+ const node = tree.getNode(siblingIndex, tree.depth - i);
55
+ if (node !== undefined) {
56
+ const nodeHash = tree.hashTree(node, i + 1);
57
+ if (!nodeHash.equals(path[i])) {
58
+ path[i] = nodeHash;
59
+ }
60
+ }
61
+ index >>= 1n;
62
+ }
63
+ }
64
+ return path;
65
+ }
66
+ /**
67
+ * This does the work of appending the new leaf and updating the low witness
68
+ * @param treeId - The tree to be queried for a sibling path.
69
+ * @param lowWitnessIndex - The index of the low leaf in the tree.
70
+ * @param lowWitness - The preimage of the low leaf.
71
+ * @param newLeafPreimage - The preimage of the new leaf to be inserted.
72
+ * @returns The sibling path of the new leaf (i.e. the insertion path)
73
+ */
74
+ appendIndexedTree(treeId, lowLeafIndex, lowLeafPreimage, newLeafPreimage) {
75
+ const tree = this.treeMap.get(treeId);
76
+ const newLeaf = this.hashPreimage(newLeafPreimage);
77
+ const insertIndex = tree.leafCount;
78
+ const lowLeaf = this.hashPreimage(lowLeafPreimage);
79
+ // Update the low nullifier hash
80
+ this.setIndexedUpdates(treeId, lowLeafIndex, lowLeafPreimage);
81
+ tree.updateLeaf(lowLeaf, lowLeafIndex);
82
+ // Append the new leaf
83
+ tree.appendLeaf(newLeaf);
84
+ this.setIndexedUpdates(treeId, insertIndex, newLeafPreimage);
85
+ return tree.getSiblingPath(insertIndex);
86
+ }
87
+ /**
88
+ * This writes or updates a slot in the public data tree with a value
89
+ * @param slot - The slot to be written to.
90
+ * @param newValue - The value to be written or updated to
91
+ * @returns The insertion result which contains the insertion path, low leaf and the new leaf index
92
+ */
93
+ async writePublicStorage(slot, newValue) {
94
+ // This only works for the public data tree
95
+ const treeId = MerkleTreeId.PUBLIC_DATA_TREE;
96
+ const tree = this.treeMap.get(treeId);
97
+ const { preimage, index, update } = await this.getLeafOrLowLeafInfo(treeId, slot);
98
+ const siblingPath = await this.getSiblingPath(treeId, index);
99
+ if (update) {
100
+ const updatedPreimage = cloneDeep(preimage);
101
+ const existingPublicDataSiblingPath = siblingPath;
102
+ updatedPreimage.value = newValue;
103
+ // It is really unintuitive that by updating, we are also appending a Zero Leaf to the tree
104
+ // Additionally, this leaf preimage does not seem to factor into further appends
105
+ const emptyLeaf = new PublicDataTreeLeafPreimage(Fr.ZERO, Fr.ZERO, Fr.ZERO, 0n);
106
+ const insertionIndex = tree.leafCount;
107
+ tree.updateLeaf(this.hashPreimage(updatedPreimage), index);
108
+ tree.appendLeaf(Fr.ZERO);
109
+ this.setIndexedUpdates(treeId, index, updatedPreimage);
110
+ this.setIndexedUpdates(treeId, insertionIndex, emptyLeaf);
111
+ const insertionPath = tree.getSiblingPath(insertionIndex);
112
+ // Even though we append an empty leaf into the tree as a part of update - it doesnt seem to impact future inserts...
113
+ this._updateMinInfo(MerkleTreeId.PUBLIC_DATA_TREE, [updatedPreimage], [index]);
114
+ return {
115
+ leafIndex: insertionIndex,
116
+ insertionPath,
117
+ newOrElementToUpdate: { update: true, element: updatedPreimage },
118
+ lowWitness: {
119
+ preimage: preimage,
120
+ index: index,
121
+ update: true,
122
+ siblingPath: existingPublicDataSiblingPath,
123
+ },
124
+ };
125
+ }
126
+ // We are writing to a new slot, so our preimage is a lowNullifier
127
+ const insertionIndex = tree.leafCount;
128
+ const updatedLowLeaf = cloneDeep(preimage);
129
+ updatedLowLeaf.nextSlot = slot;
130
+ updatedLowLeaf.nextIndex = insertionIndex;
131
+ const newPublicDataLeaf = new PublicDataTreeLeafPreimage(slot, newValue, new Fr(preimage.getNextKey()), preimage.getNextIndex());
132
+ const insertionPath = this.appendIndexedTree(treeId, index, updatedLowLeaf, newPublicDataLeaf);
133
+ // Since we are appending, we might have a new minimum public data leaf
134
+ this._updateMinInfo(MerkleTreeId.PUBLIC_DATA_TREE, [newPublicDataLeaf, updatedLowLeaf], [insertionIndex, index]);
135
+ return {
136
+ leafIndex: insertionIndex,
137
+ insertionPath: insertionPath,
138
+ newOrElementToUpdate: { update: false, element: newPublicDataLeaf },
139
+ lowWitness: {
140
+ preimage,
141
+ index: index,
142
+ update: false,
143
+ siblingPath,
144
+ },
145
+ };
146
+ }
147
+ /**
148
+ * This is just a helper to compare the preimages and update the minimum public data leaf
149
+ * @param treeId - The tree to be queried for a sibling path.
150
+ * @param T - The type of the preimage (PublicData or Nullifier)
151
+ * @param preimages - The preimages to be compared
152
+ * @param indices - The indices of the preimages
153
+ */
154
+ _updateMinInfo(treeId, preimages, indices) {
155
+ let currentMin = this.getMinInfo(treeId);
156
+ if (currentMin === undefined) {
157
+ currentMin = { preimage: preimages[0], index: indices[0] };
158
+ }
159
+ for (let i = 0; i < preimages.length; i++) {
160
+ if (preimages[i].getKey() <= currentMin.preimage.getKey()) {
161
+ currentMin = { preimage: preimages[i], index: indices[i] };
162
+ }
163
+ }
164
+ this.setMinInfo(treeId, currentMin.preimage, currentMin.index);
165
+ }
166
+ /**
167
+ * This appends a nullifier to the nullifier tree, and throws if the nullifier already exists
168
+ * @param value - The nullifier to be appended
169
+ * @returns The insertion result which contains the insertion path, low leaf and the new leaf index
170
+ */
171
+ async appendNullifier(nullifier) {
172
+ const treeId = MerkleTreeId.NULLIFIER_TREE;
173
+ const tree = this.treeMap.get(treeId);
174
+ const { preimage, index, update } = await this.getLeafOrLowLeafInfo(treeId, nullifier);
175
+ const siblingPath = await this.getSiblingPath(treeId, index);
176
+ if (update) {
177
+ throw new Error('Not allowed to update a nullifier');
178
+ }
179
+ // We are writing a new entry
180
+ const insertionIndex = tree.leafCount;
181
+ const updatedLowNullifier = cloneDeep(preimage);
182
+ updatedLowNullifier.nextNullifier = nullifier;
183
+ updatedLowNullifier.nextIndex = insertionIndex;
184
+ const newNullifierLeaf = new NullifierLeafPreimage(nullifier, preimage.nextNullifier, preimage.nextIndex);
185
+ const insertionPath = this.appendIndexedTree(treeId, index, updatedLowNullifier, newNullifierLeaf);
186
+ // Since we are appending, we might have a new minimum nullifier leaf
187
+ this._updateMinInfo(MerkleTreeId.NULLIFIER_TREE, [newNullifierLeaf, updatedLowNullifier], [insertionIndex, index]);
188
+ return {
189
+ leafIndex: insertionIndex,
190
+ insertionPath: insertionPath,
191
+ newOrElementToUpdate: { update: false, element: newNullifierLeaf },
192
+ lowWitness: {
193
+ preimage,
194
+ index,
195
+ update,
196
+ siblingPath,
197
+ },
198
+ };
199
+ }
200
+ /**
201
+ * This appends a note hash to the note hash tree
202
+ * @param value - The note hash to be appended
203
+ * @returns The insertion result which contains the insertion path
204
+ */
205
+ appendNoteHash(noteHash) {
206
+ const tree = this.treeMap.get(MerkleTreeId.NOTE_HASH_TREE);
207
+ tree.appendLeaf(noteHash);
208
+ // We use leafCount - 1 here because we would have just appended a leaf
209
+ const insertionPath = tree.getSiblingPath(tree.leafCount - 1n);
210
+ return insertionPath;
211
+ }
212
+ /**
213
+ * This is wrapper around treeId to get the correct minimum leaf preimage
214
+ */
215
+ getMinInfo(treeId) {
216
+ const start = this.indexedTreeMin.get(treeId);
217
+ if (start === undefined) {
218
+ return undefined;
219
+ }
220
+ const [preimage, index] = start;
221
+ return { preimage: preimage, index };
222
+ }
223
+ /**
224
+ * This is wrapper around treeId to set the correct minimum leaf preimage
225
+ */
226
+ setMinInfo(treeId, preimage, index) {
227
+ this.indexedTreeMin.set(treeId, [preimage, index]);
228
+ }
229
+ /**
230
+ * This is wrapper around treeId to set values in the indexedUpdates map
231
+ */
232
+ setIndexedUpdates(treeId, index, preimage) {
233
+ let updates = this.indexedUpdates.get(treeId);
234
+ if (updates === undefined) {
235
+ updates = new Map();
236
+ this.indexedUpdates.set(treeId, updates);
237
+ }
238
+ updates.set(index, preimage);
239
+ }
240
+ /**
241
+ * This is wrapper around treeId to get values in the indexedUpdates map
242
+ */
243
+ getIndexedUpdates(treeId, index) {
244
+ const updates = this.indexedUpdates.get(treeId);
245
+ if (updates === undefined) {
246
+ throw new Error('No updates found');
247
+ }
248
+ const preimage = updates.get(index);
249
+ if (preimage === undefined) {
250
+ throw new Error('No updates found');
251
+ }
252
+ return preimage;
253
+ }
254
+ /**
255
+ * This is wrapper around treeId to check membership (i.e. has()) of index in the indexedUpdates map
256
+ */
257
+ hasLocalUpdates(treeId, index) {
258
+ const updates = this.indexedUpdates.get(treeId);
259
+ if (updates === undefined) {
260
+ return false;
261
+ }
262
+ return updates.has(index);
263
+ }
264
+ /**
265
+ * This gets the low leaf preimage and the index of the low leaf in the indexed tree given a value (slot or nullifier value)
266
+ * If the value is not found in the tree, it does an external lookup to the merkleDB
267
+ * @param treeId - The tree we are looking up in
268
+ * @param key - The key for which we are look up the low leaf for.
269
+ * @param T - The type of the preimage (PublicData or Nullifier)
270
+ * @returns The low leaf preimage and the index of the low leaf in the indexed tree
271
+ */
272
+ async getLeafOrLowLeafInfo(treeId, key) {
273
+ // This can probably be done better, we want to say if the minInfo is undefined (because this is our first operation) we do the external lookup
274
+ const minPreimage = this.getMinInfo(treeId);
275
+ const start = minPreimage?.preimage;
276
+ const bigIntKey = key.toBigInt();
277
+ // If the first element we have is already greater than the value, we need to do an external lookup
278
+ if (minPreimage === undefined || (start?.getKey() ?? 0n) >= key.toBigInt()) {
279
+ // The low public data witness is in the previous tree
280
+ const { index, alreadyPresent } = (await this.treeDb.getPreviousValueIndex(treeId, bigIntKey));
281
+ const preimage = await this.treeDb.getLeafPreimage(treeId, index);
282
+ // Since we have never seen this before - we should insert it into our tree
283
+ const siblingPath = (await this.treeDb.getSiblingPath(treeId, index)).toFields();
284
+ // Is it enough to just insert the sibling path without inserting the leaf? - right now probably since we will update this low nullifier index in append
285
+ this.treeMap.get(treeId).insertSiblingPath(index, siblingPath);
286
+ const lowPublicDataPreimage = preimage;
287
+ return { preimage: lowPublicDataPreimage, index: index, update: alreadyPresent };
288
+ }
289
+ // We look for the low element by bouncing between our local indexedUpdates map or the external DB
290
+ // The conditions we are looking for are:
291
+ // (1) Exact Match: curr.nextKey == key (this is only valid for public data tree)
292
+ // (2) Sandwich Match: curr.nextKey > key and curr.key < key
293
+ // (3) Max Condition: curr.next_index == 0 and curr.key < key
294
+ // Note the min condition does not need to be handled since indexed trees are prefilled with at least the 0 element
295
+ let found = false;
296
+ let curr = minPreimage.preimage;
297
+ let result = undefined;
298
+ // Temp to avoid infinite loops - the limit is the number of leaves we may have to read
299
+ const LIMIT = 2n ** BigInt(getTreeHeight(treeId)) - 1n;
300
+ let counter = 0n;
301
+ let lowPublicDataIndex = minPreimage.index;
302
+ while (!found && counter < LIMIT) {
303
+ if (curr.getKey() === bigIntKey) {
304
+ // We found an exact match - therefore this is an update
305
+ found = true;
306
+ result = { preimage: curr, index: lowPublicDataIndex, update: true };
307
+ }
308
+ else if (curr.getKey() < bigIntKey && (curr.getNextKey() === 0n || curr.getNextKey() > bigIntKey)) {
309
+ // We found it via sandwich or max condition, this is a low nullifier
310
+ found = true;
311
+ result = { preimage: curr, index: lowPublicDataIndex, update: false };
312
+ }
313
+ // Update the the values for the next iteration
314
+ else {
315
+ lowPublicDataIndex = curr.getNextIndex();
316
+ if (this.hasLocalUpdates(treeId, lowPublicDataIndex)) {
317
+ curr = this.getIndexedUpdates(treeId, lowPublicDataIndex);
318
+ }
319
+ else {
320
+ const preimage = (await this.treeDb.getLeafPreimage(treeId, lowPublicDataIndex));
321
+ curr = preimage;
322
+ }
323
+ }
324
+ counter++;
325
+ }
326
+ // We did not find it - this is unexpected
327
+ if (result === undefined) {
328
+ throw new Error('No previous value found or ran out of iterations');
329
+ }
330
+ return result;
331
+ }
332
+ /**
333
+ * This hashes the preimage to a field element
334
+ */
335
+ hashPreimage(preimage) {
336
+ // Watch for this edge-case, we are hashing the key=0 leaf to 0.
337
+ // This is for backward compatibility with the world state implementation
338
+ if (preimage.getKey() === 0n) {
339
+ return Fr.zero();
340
+ }
341
+ const input = preimage.toHashInputs().map(x => Fr.fromBuffer(x));
342
+ return poseidon2Hash(input);
343
+ }
344
+ }
345
+ /****************************************************/
346
+ /****** Some useful Structs and Enums **************/
347
+ /****************************************************/
348
+ var TreeType;
349
+ (function (TreeType) {
350
+ TreeType[TreeType["LEAF"] = 0] = "LEAF";
351
+ TreeType[TreeType["NODE"] = 1] = "NODE";
352
+ })(TreeType || (TreeType = {}));
353
+ var SiblingStatus;
354
+ (function (SiblingStatus) {
355
+ SiblingStatus[SiblingStatus["MEMBER"] = 0] = "MEMBER";
356
+ SiblingStatus[SiblingStatus["NONMEMBER"] = 1] = "NONMEMBER";
357
+ SiblingStatus[SiblingStatus["ERROR"] = 2] = "ERROR";
358
+ })(SiblingStatus || (SiblingStatus = {}));
359
+ /****************************************************/
360
+ /****** Some Helpful Constructors for Trees ********/
361
+ /****************************************************/
362
+ const Node = (left, right) => ({
363
+ tag: TreeType.NODE,
364
+ leftTree: left,
365
+ rightTree: right,
366
+ });
367
+ const Leaf = (value) => ({
368
+ tag: TreeType.LEAF,
369
+ value,
370
+ });
371
+ /****************************************************/
372
+ /****** The EphemeralAvmTree Class *****************/
373
+ /****************************************************/
374
+ /**
375
+ * This class contains a recursively defined tree that has leaves at different heights
376
+ * It is seeded by an existing merkle treeDb for which it derives a frontier
377
+ * It is intended to be a lightweight tree that contains only the necessary information to suppport appends or updates
378
+ */
379
+ export class EphemeralAvmTree {
380
+ constructor(leafCount, depth) {
381
+ this.leafCount = leafCount;
382
+ this.depth = depth;
383
+ let zeroHash = Fr.zero();
384
+ // Can probably cache this elsewhere
385
+ const zeroHashes = [];
386
+ for (let i = 0; i < this.depth; i++) {
387
+ zeroHashes.push(zeroHash);
388
+ zeroHash = poseidon2Hash([zeroHash, zeroHash]);
389
+ }
390
+ this.tree = Leaf(zeroHash);
391
+ this.zeroHashes = zeroHashes;
392
+ this.frontier = [];
393
+ }
394
+ static async create(forkedLeafCount, depth, treeDb, merkleId) {
395
+ const tree = new EphemeralAvmTree(forkedLeafCount, depth);
396
+ await tree.initializeFrontier(treeDb, merkleId);
397
+ return tree;
398
+ }
399
+ /**
400
+ * This is a recursive function that inserts a leaf into the tree
401
+ * @param value - The value of the leaf to be inserted
402
+ */
403
+ appendLeaf(value) {
404
+ const insertPath = this._derivePathLE(this.leafCount);
405
+ this.tree = this._insertLeaf(value, insertPath, this.depth, this.tree);
406
+ this.leafCount++;
407
+ }
408
+ /**
409
+ * This is a recursive function that upserts a leaf into the tree at a index and depth
410
+ * @param value - The value of the leaf to be inserted
411
+ * @param index - The index of the leaf to be inserted
412
+ * @param depth - The depth of the leaf to be inserted (defaults to the bottom of the tree)
413
+ */
414
+ updateLeaf(value, index, depth = this.depth) {
415
+ const insertPath = this._derivePathLE(index, depth);
416
+ this.tree = this._insertLeaf(value, insertPath, depth, this.tree);
417
+ }
418
+ /**
419
+ * Get the sibling path of a leaf in the tree
420
+ * @param index - The index of the leaf for which a sibling path should be returned.
421
+ * @returns The sibling path of the leaf, can fail if the path is not found
422
+ */
423
+ getSiblingPath(index) {
424
+ const searchPath = this._derivePathLE(index);
425
+ // Handle cases where we error out
426
+ const { path, status } = this._getSiblingPath(searchPath, this.tree, []);
427
+ if (status === SiblingStatus.ERROR) {
428
+ return undefined;
429
+ }
430
+ return path;
431
+ }
432
+ /**
433
+ * This upserts the nodes of the sibling path into the tree
434
+ * @param index - The index of the leaf that the sibling path is derived from
435
+ * @param siblingPath - The sibling path of the index
436
+ */
437
+ insertSiblingPath(index, siblingPath) {
438
+ for (let i = 0; i < siblingPath.length; i++) {
439
+ // Flip(XOR) the last bit because we are inserting siblings of the leaf
440
+ const sibIndex = index ^ 1n;
441
+ this.updateLeaf(siblingPath[i], sibIndex, this.depth - i);
442
+ index >>= 1n;
443
+ }
444
+ }
445
+ /**
446
+ * This is a helper function that computes the index of the frontier nodes at each depth
447
+ * @param leafCount - The number of leaves in the tree
448
+ * @returns An array of frontier indices at each depth, sorted from leaf to root
449
+ */
450
+ // Do we really need LeafCount to be a bigint - log2 is on numbers only
451
+ static computeFrontierLeafIndices(leafCount) {
452
+ const numFrontierEntries = Math.floor(Math.log2(leafCount)) + 1;
453
+ const frontierIndices = [];
454
+ for (let i = 0; i < numFrontierEntries; i++) {
455
+ if (leafCount === 0) {
456
+ frontierIndices.push(0);
457
+ }
458
+ else if (leafCount % 2 === 0) {
459
+ frontierIndices.push(leafCount - 2);
460
+ }
461
+ else {
462
+ frontierIndices.push(leafCount - 1);
463
+ }
464
+ leafCount >>= 1;
465
+ }
466
+ return frontierIndices;
467
+ }
468
+ /**
469
+ * This derives the frontier and inserts them into the tree
470
+ * @param treeDb - The treeDb to be queried for sibling paths
471
+ * @param merkleId - The treeId of the tree to be queried for sibling paths
472
+ */
473
+ async initializeFrontier(treeDb, merkleId) {
474
+ // The frontier indices are sorted from the leaf to root
475
+ const frontierIndices = EphemeralAvmTree.computeFrontierLeafIndices(Number(this.leafCount));
476
+ // The frontier indices are level-based - i.e. index N at level L.
477
+ // Since we can only ask the DB for paths from the root to the leaf, we do the following complicated calculations
478
+ // 1) The goal is to insert the frontier node N at level L into the tree.
479
+ // 2) We get the path to a leaf that passes through the frontier node we want (there are multiple paths so we just pick one)
480
+ // 3) We can only get sibling paths from the root to the leaf, so we get the sibling path of the leaf from (2)
481
+ // NOTE: This is terribly inefficient and we should probably change the DB API to allow for getting paths to a node
482
+ const frontierValues = [];
483
+ // These are leaf indexes that pass through the frontier nodes
484
+ for (let i = 0; i < frontierIndices.length; i++) {
485
+ // Given the index to a frontier, we first xor it so we can get its sibling index at depth L
486
+ // We then extend the path to that sibling index by shifting left the requisite number of times (for simplicity we just go left down the tree - it doesnt matter)
487
+ // This provides us the leaf index such that if we ask for this leafIndex's sibling path, it will pass through the frontier node
488
+ const index = BigInt(frontierIndices[i] ^ 1) << BigInt(i);
489
+ // This path passes through our frontier node at depth - i
490
+ const path = await treeDb.getSiblingPath(merkleId, index);
491
+ // We derive the path that we can walk and truncate it so that it terminates exactly at the frontier node
492
+ const frontierPath = this._derivePathLE(BigInt(frontierIndices[i]), this.depth - i);
493
+ // The value of the frontier is the at the i-th index of the sibling path
494
+ const frontierValue = path.toFields()[i];
495
+ frontierValues.push(frontierValue);
496
+ // We insert it at depth - i (the truncated position)
497
+ // Note this is a leaf node that wont necessarily be at the bottom of the tree (besides the first frontier)
498
+ this.tree = this._insertLeaf(frontierValue, frontierPath, this.depth - i, this.tree);
499
+ }
500
+ this.frontier = frontierValues;
501
+ }
502
+ /**
503
+ * Computes the root of the tree
504
+ */
505
+ getRoot() {
506
+ return this.hashTree(this.tree, this.depth);
507
+ }
508
+ /**
509
+ * Recursively hashes the subtree
510
+ * @param tree - The tree to be hashed
511
+ * @param depth - The depth of the tree
512
+ */
513
+ hashTree(tree, depth) {
514
+ switch (tree.tag) {
515
+ case TreeType.NODE: {
516
+ return poseidon2Hash([this.hashTree(tree.leftTree, depth - 1), this.hashTree(tree.rightTree, depth - 1)]);
517
+ }
518
+ case TreeType.LEAF: {
519
+ return tree.value;
520
+ }
521
+ }
522
+ }
523
+ /**
524
+ * Extracts the subtree from a given index and depth
525
+ * @param index - The index of the node to be extracted
526
+ * @param depth - The depth of the node to be extracted
527
+ * @returns The subtree rooted at the index and depth
528
+ */
529
+ getNode(index, depth) {
530
+ const path = this._derivePathBE(index, depth);
531
+ const truncatedPath = path.slice(0, depth);
532
+ truncatedPath.reverse();
533
+ try {
534
+ return this._getNode(truncatedPath, this.tree);
535
+ }
536
+ catch (e) {
537
+ return undefined;
538
+ }
539
+ }
540
+ /**
541
+ * This is the recursive helper for getNode
542
+ */
543
+ _getNode(nodePath, tree) {
544
+ if (nodePath.length === 0) {
545
+ return tree;
546
+ }
547
+ switch (tree.tag) {
548
+ case TreeType.NODE:
549
+ return nodePath.pop() === 0 ? this._getNode(nodePath, tree.leftTree) : this._getNode(nodePath, tree.rightTree);
550
+ case TreeType.LEAF:
551
+ throw new Error('Node not found');
552
+ }
553
+ }
554
+ /** Our tree traversal uses an array of 1s and 0s to represent the path to a leaf and expects them to be in LE order
555
+ * This helps with deriving it given an index and (optionally a depth)
556
+ * @param index - The index to derive a path to within the tree, does not have to terminate at a leaf
557
+ * @param depth - The depth to traverse, if not provided it will traverse to the bottom of the tree
558
+ * @returns The path to the leaf in LE order
559
+ */
560
+ _derivePathLE(index, depth = this.depth) {
561
+ return this._derivePathBE(index, depth).reverse();
562
+ }
563
+ /** Sometimes we want it in BE order, to make truncating easier
564
+ * @param index - The index to derive a path to within the tree, does not have to terminate at a leaf
565
+ * @param depth - The depth to traverse, if not provided it will traverse to the bottom of the tree
566
+ * @returns The path to the leaf in LE order
567
+ */
568
+ _derivePathBE(index, depth = this.depth) {
569
+ return index
570
+ .toString(2)
571
+ .padStart(depth, '0')
572
+ .split('')
573
+ .map(x => parseInt(x));
574
+ }
575
+ /**
576
+ * This is a recursive function that upserts a leaf into the tree given a path
577
+ * @param value - The value of the leaf to be upserted
578
+ * @param insertPath - The path to the leaf, this should be ordered from leaf to root (i.e. LE encoded)
579
+ * @param depth - The depth of the tree
580
+ * @param tree - The current tree
581
+ * @param appendMode - If true we append the relevant zeroHashes to the tree as we traverse
582
+ */
583
+ _insertLeaf(value, insertPath, depth, tree) {
584
+ if (insertPath.length > this.depth || depth > this.depth) {
585
+ throw new Error('PATH EXCEEDS DEPTH');
586
+ }
587
+ if (depth === 0 || insertPath.length === 0) {
588
+ return Leaf(value);
589
+ }
590
+ switch (tree.tag) {
591
+ case TreeType.NODE: {
592
+ return insertPath.pop() === 0
593
+ ? Node(this._insertLeaf(value, insertPath, depth - 1, tree.leftTree), tree.rightTree)
594
+ : Node(tree.leftTree, this._insertLeaf(value, insertPath, depth - 1, tree.rightTree));
595
+ }
596
+ case TreeType.LEAF: {
597
+ const zeroLeaf = Leaf(this.zeroHashes[depth - 1]);
598
+ return insertPath.pop() === 0
599
+ ? Node(this._insertLeaf(value, insertPath, depth - 1, zeroLeaf), zeroLeaf)
600
+ : Node(zeroLeaf, this._insertLeaf(value, insertPath, depth - 1, zeroLeaf));
601
+ }
602
+ }
603
+ }
604
+ /* Recursive helper for getSiblingPath, this only looks inside the tree and does not resolve using
605
+ * a DB. If a path is not found, it returns an error status that is expected to be handled by the caller
606
+ * @param searchPath - The path to the leaf for which we would like the sibling pathin LE order
607
+ * @param tree - The current tree
608
+ * @param acc - The accumulated sibling path
609
+ */
610
+ _getSiblingPath(searchPath, tree, acc) {
611
+ // If we have reached the end of the path, we should be at a leaf or empty node
612
+ // If it is a leaf, we check if the value is equal to the leaf value
613
+ // If it is empty we check if the value is equal to zero
614
+ if (searchPath.length === 0) {
615
+ switch (tree.tag) {
616
+ case TreeType.LEAF:
617
+ return { path: acc, status: SiblingStatus.MEMBER };
618
+ case TreeType.NODE:
619
+ return { path: [], status: SiblingStatus.ERROR };
620
+ }
621
+ }
622
+ // Keep exploring here
623
+ switch (tree.tag) {
624
+ case TreeType.NODE: {
625
+ // Look at the next element of the path to decided if we go left or right, note this mutates!
626
+ return searchPath.pop() === 0
627
+ ? this._getSiblingPath(searchPath, tree.leftTree, [this.hashTree(tree.rightTree, searchPath.length)].concat(acc))
628
+ : this._getSiblingPath(searchPath, tree.rightTree, [this.hashTree(tree.leftTree, searchPath.length)].concat(acc));
629
+ }
630
+ // In these two situations we are exploring a subtree we dont have information about
631
+ // We should return an error and look inside the DB
632
+ case TreeType.LEAF:
633
+ return { path: [], status: SiblingStatus.ERROR };
634
+ }
635
+ }
636
+ }
637
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXZtX3RyZWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXZtL2F2bV90cmVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBc0IsWUFBWSxFQUFpQyxhQUFhLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0SCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN2RixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRzlDLE9BQU8sU0FBUyxNQUFNLGtCQUFrQixDQUFDO0FBa0N6QyxzREFBc0Q7QUFDdEQsc0RBQXNEO0FBQ3RELHNEQUFzRDtBQUV0RDs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLGtCQUFrQjtJQUM3QixZQUNTLE1BQWdDLEVBQ2hDLE9BQTRDO0lBQ25ELDJKQUEySjtJQUNwSixjQUFxRTtJQUM1RSxrSEFBa0g7SUFDbEgsK0ZBQStGO0lBQ3hGLGNBQXdFO1FBTnhFLFdBQU0sR0FBTixNQUFNLENBQTBCO1FBQ2hDLFlBQU8sR0FBUCxPQUFPLENBQXFDO1FBRTVDLG1CQUFjLEdBQWQsY0FBYyxDQUF1RDtRQUdyRSxtQkFBYyxHQUFkLGNBQWMsQ0FBMEQ7SUFDOUUsQ0FBQztJQUVKLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQWdDO1FBQ2xELE1BQU0sT0FBTyxHQUFHLElBQUksR0FBRyxFQUFrQyxDQUFDO1FBQzFELEtBQUssTUFBTSxRQUFRLElBQUksQ0FBQyxZQUFZLENBQUMsY0FBYyxFQUFFLFlBQVksQ0FBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztZQUNqSCxNQUFNLFFBQVEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDcEQsTUFBTSxJQUFJLEdBQUcs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