@aztec/kv-store 0.71.0 → 0.73.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 (64) hide show
  1. package/dest/config.js +3 -3
  2. package/dest/indexeddb/store.d.ts +4 -7
  3. package/dest/indexeddb/store.d.ts.map +1 -1
  4. package/dest/indexeddb/store.js +5 -2
  5. package/dest/interfaces/common.d.ts +6 -1
  6. package/dest/interfaces/common.d.ts.map +1 -1
  7. package/dest/interfaces/index.d.ts +1 -1
  8. package/dest/interfaces/index.d.ts.map +1 -1
  9. package/dest/interfaces/map.d.ts +0 -6
  10. package/dest/interfaces/map.d.ts.map +1 -1
  11. package/dest/interfaces/map_test_suite.d.ts.map +1 -1
  12. package/dest/interfaces/map_test_suite.js +1 -12
  13. package/dest/interfaces/store.d.ts +11 -11
  14. package/dest/interfaces/store.d.ts.map +1 -1
  15. package/dest/lmdb/store.d.ts +2 -6
  16. package/dest/lmdb/store.d.ts.map +1 -1
  17. package/dest/lmdb/store.js +3 -3
  18. package/dest/lmdb-v2/factory.d.ts +7 -0
  19. package/dest/lmdb-v2/factory.d.ts.map +1 -0
  20. package/dest/lmdb-v2/factory.js +56 -0
  21. package/dest/lmdb-v2/index.d.ts +3 -0
  22. package/dest/lmdb-v2/index.d.ts.map +1 -0
  23. package/dest/lmdb-v2/index.js +3 -0
  24. package/dest/lmdb-v2/map.d.ts +86 -0
  25. package/dest/lmdb-v2/map.d.ts.map +1 -0
  26. package/dest/lmdb-v2/map.js +196 -0
  27. package/dest/lmdb-v2/message.d.ts +112 -0
  28. package/dest/lmdb-v2/message.d.ts.map +1 -0
  29. package/dest/lmdb-v2/message.js +19 -0
  30. package/dest/lmdb-v2/read_transaction.d.ts +14 -0
  31. package/dest/lmdb-v2/read_transaction.d.ts.map +1 -0
  32. package/dest/lmdb-v2/read_transaction.js +89 -0
  33. package/dest/lmdb-v2/singleton.d.ts +12 -0
  34. package/dest/lmdb-v2/singleton.d.ts.map +1 -0
  35. package/dest/lmdb-v2/singleton.js +29 -0
  36. package/dest/lmdb-v2/store.d.ts +41 -0
  37. package/dest/lmdb-v2/store.d.ts.map +1 -0
  38. package/dest/lmdb-v2/store.js +156 -0
  39. package/dest/lmdb-v2/utils.d.ts +19 -0
  40. package/dest/lmdb-v2/utils.d.ts.map +1 -0
  41. package/dest/lmdb-v2/utils.js +126 -0
  42. package/dest/lmdb-v2/write_transaction.d.ts +19 -0
  43. package/dest/lmdb-v2/write_transaction.d.ts.map +1 -0
  44. package/dest/lmdb-v2/write_transaction.js +234 -0
  45. package/dest/stores/l2_tips_store.js +2 -2
  46. package/package.json +14 -6
  47. package/src/config.ts +2 -2
  48. package/src/indexeddb/store.ts +8 -4
  49. package/src/interfaces/common.ts +3 -1
  50. package/src/interfaces/index.ts +1 -1
  51. package/src/interfaces/map.ts +0 -7
  52. package/src/interfaces/map_test_suite.ts +1 -16
  53. package/src/interfaces/store.ts +13 -3
  54. package/src/lmdb/store.ts +4 -4
  55. package/src/lmdb-v2/factory.ts +79 -0
  56. package/src/lmdb-v2/index.ts +2 -0
  57. package/src/lmdb-v2/map.ts +233 -0
  58. package/src/lmdb-v2/message.ts +146 -0
  59. package/src/lmdb-v2/read_transaction.ts +116 -0
  60. package/src/lmdb-v2/singleton.ts +34 -0
  61. package/src/lmdb-v2/store.ts +210 -0
  62. package/src/lmdb-v2/utils.ts +150 -0
  63. package/src/lmdb-v2/write_transaction.ts +314 -0
  64. package/src/stores/l2_tips_store.ts +1 -1
@@ -0,0 +1,314 @@
1
+ import { type Batch, Database, LMDBMessageType } from './message.js';
2
+ import { ReadTransaction } from './read_transaction.js';
3
+ import {
4
+ dedupeSortedArray,
5
+ findInSortedArray,
6
+ findIndexInSortedArray,
7
+ insertIntoSortedArray,
8
+ keyCmp,
9
+ merge,
10
+ removeAnyOf,
11
+ removeFromSortedArray,
12
+ singleKeyCmp,
13
+ } from './utils.js';
14
+
15
+ export class WriteTransaction extends ReadTransaction {
16
+ // exposed for tests
17
+ public readonly dataBatch: Batch = {
18
+ addEntries: [],
19
+ removeEntries: [],
20
+ };
21
+ public readonly indexBatch: Batch = {
22
+ addEntries: [],
23
+ removeEntries: [],
24
+ };
25
+
26
+ set(key: Uint8Array, value: Uint8Array): Promise<void> {
27
+ this.assertIsOpen();
28
+
29
+ const addEntry = findInSortedArray(this.dataBatch.addEntries, key, singleKeyCmp);
30
+ if (!addEntry) {
31
+ insertIntoSortedArray(this.dataBatch.addEntries, [key, [value]], keyCmp);
32
+ } else {
33
+ addEntry[1] = [value];
34
+ }
35
+
36
+ const removeEntryIndex = findIndexInSortedArray(this.dataBatch.removeEntries, key, singleKeyCmp);
37
+ if (removeEntryIndex > -1) {
38
+ this.dataBatch.removeEntries.splice(removeEntryIndex, 1);
39
+ }
40
+
41
+ return Promise.resolve();
42
+ }
43
+
44
+ remove(key: Uint8Array): Promise<void> {
45
+ const removeEntryIndex = findIndexInSortedArray(this.dataBatch.removeEntries, key, singleKeyCmp);
46
+ if (removeEntryIndex === -1) {
47
+ this.dataBatch.removeEntries.push([key, null]);
48
+ }
49
+
50
+ const addEntryIndex = findIndexInSortedArray(this.dataBatch.addEntries, key, singleKeyCmp);
51
+ if (addEntryIndex > -1) {
52
+ this.dataBatch.addEntries.splice(addEntryIndex, 1);
53
+ }
54
+
55
+ return Promise.resolve();
56
+ }
57
+
58
+ public override async get(key: Buffer): Promise<Uint8Array | undefined> {
59
+ this.assertIsOpen();
60
+
61
+ const addEntry = findInSortedArray(this.dataBatch.addEntries, key, singleKeyCmp);
62
+ if (addEntry) {
63
+ return addEntry[1][0];
64
+ }
65
+ const removeEntryIdx = findIndexInSortedArray(this.dataBatch.removeEntries, key, singleKeyCmp);
66
+ if (removeEntryIdx > -1) {
67
+ return undefined;
68
+ }
69
+
70
+ return await super.get(key);
71
+ }
72
+
73
+ setIndex(key: Buffer, ...values: Buffer[]): Promise<void> {
74
+ this.assertIsOpen();
75
+
76
+ const addEntries = findInSortedArray(this.indexBatch.addEntries, key, singleKeyCmp);
77
+ const removeEntries = findInSortedArray(this.indexBatch.removeEntries, key, singleKeyCmp);
78
+
79
+ if (removeEntries) {
80
+ if (removeEntries[1]) {
81
+ // check if we were deleting these values and update
82
+ removeAnyOf(removeEntries[1], values, Buffer.compare);
83
+ }
84
+
85
+ if (!removeEntries[1] || removeEntries[1].length === 0) {
86
+ // either we were deleting the entire key previously
87
+ // or after cleaning up duplicates, we don't have anything else to delete
88
+ removeFromSortedArray(this.indexBatch.removeEntries, removeEntries, keyCmp);
89
+ }
90
+ }
91
+
92
+ if (addEntries) {
93
+ merge(addEntries[1], values, Buffer.compare);
94
+ dedupeSortedArray(addEntries[1], Buffer.compare);
95
+ } else {
96
+ insertIntoSortedArray(this.indexBatch.addEntries, [key, values], keyCmp);
97
+ }
98
+
99
+ return Promise.resolve();
100
+ }
101
+
102
+ removeIndex(key: Buffer, ...values: Buffer[]): Promise<void> {
103
+ this.assertIsOpen();
104
+
105
+ const addEntries = findInSortedArray(this.indexBatch.addEntries, key, singleKeyCmp);
106
+ const removeEntries = findInSortedArray(this.indexBatch.removeEntries, key, singleKeyCmp);
107
+
108
+ if (values.length === 0) {
109
+ // special case, we're deleting the entire key
110
+ if (addEntries) {
111
+ removeFromSortedArray(this.indexBatch.addEntries, addEntries, keyCmp);
112
+ }
113
+
114
+ if (removeEntries) {
115
+ removeEntries[1] = null;
116
+ } else {
117
+ insertIntoSortedArray(this.indexBatch.removeEntries, [key, null], keyCmp);
118
+ }
119
+
120
+ return Promise.resolve();
121
+ }
122
+
123
+ if (addEntries) {
124
+ removeAnyOf(addEntries[1], values, Buffer.compare);
125
+ if (addEntries[1].length === 0) {
126
+ removeFromSortedArray(this.indexBatch.addEntries, addEntries, keyCmp);
127
+ }
128
+ }
129
+
130
+ if (removeEntries) {
131
+ removeEntries[1] ??= [];
132
+ merge(removeEntries[1], values, Buffer.compare);
133
+ dedupeSortedArray(removeEntries[1], Buffer.compare);
134
+ } else {
135
+ insertIntoSortedArray(this.indexBatch.removeEntries, [key, values], keyCmp);
136
+ }
137
+
138
+ return Promise.resolve();
139
+ }
140
+
141
+ public override async getIndex(key: Buffer): Promise<Uint8Array[]> {
142
+ this.assertIsOpen();
143
+
144
+ const removeEntries = findInSortedArray(this.indexBatch.removeEntries, key, singleKeyCmp);
145
+ if (removeEntries && removeEntries[1] === null) {
146
+ return [];
147
+ }
148
+
149
+ const addEntries = findInSortedArray(this.indexBatch.addEntries, key, singleKeyCmp);
150
+ const results = await super.getIndex(key);
151
+
152
+ if (addEntries) {
153
+ merge(results, addEntries[1], Buffer.compare);
154
+ dedupeSortedArray(results, Buffer.compare);
155
+ }
156
+
157
+ if (removeEntries && Array.isArray(removeEntries[1])) {
158
+ removeAnyOf(results, removeEntries[1], Buffer.compare);
159
+ }
160
+
161
+ return results;
162
+ }
163
+
164
+ public override async *iterate(
165
+ startKey: Uint8Array,
166
+ endKey?: Uint8Array | undefined,
167
+ reverse?: boolean,
168
+ limit?: number,
169
+ ): AsyncIterable<[Uint8Array, Uint8Array]> {
170
+ yield* this.#iterate(
171
+ super.iterate(startKey, endKey, reverse),
172
+ this.dataBatch,
173
+ startKey,
174
+ endKey,
175
+ reverse,
176
+ limit,
177
+ (committed, toAdd) => (toAdd.length > 0 ? toAdd[0] : committed),
178
+ vals => vals[0],
179
+ );
180
+ }
181
+
182
+ public override async *iterateIndex(
183
+ startKey: Uint8Array,
184
+ endKey?: Uint8Array | undefined,
185
+ reverse?: boolean,
186
+ limit?: number,
187
+ ): AsyncIterable<[Uint8Array, Uint8Array[]]> {
188
+ yield* this.#iterate(
189
+ super.iterateIndex(startKey, endKey, reverse),
190
+ this.indexBatch,
191
+ startKey,
192
+ endKey,
193
+ reverse,
194
+ limit,
195
+ (committed, toAdd, toRemove) => {
196
+ if (toAdd.length > 0) {
197
+ merge(committed, toAdd, Buffer.compare);
198
+ dedupeSortedArray(committed, Buffer.compare);
199
+ }
200
+ if (toRemove.length > 0) {
201
+ removeAnyOf(committed, toRemove, Buffer.compare);
202
+ }
203
+ return committed;
204
+ },
205
+ vals => vals,
206
+ );
207
+ }
208
+
209
+ async *#iterate<T>(
210
+ iterator: AsyncIterable<[Uint8Array, T]>,
211
+ batch: Batch,
212
+ startKey: Uint8Array,
213
+ endKey: Uint8Array | undefined,
214
+ reverse: boolean = false,
215
+ limit: number | undefined,
216
+ merge: (committed: T, toAdd: Uint8Array[], toRemove: Uint8Array[]) => T,
217
+ map: (vals: Uint8Array[]) => T,
218
+ ): AsyncIterable<[Uint8Array, T]> {
219
+ this.assertIsOpen();
220
+
221
+ // make a copy of this in case we're running in reverse
222
+ const uncommittedEntries = [...batch.addEntries];
223
+ // used to check we're in the right order when comparing between a key and uncommittedEntries
224
+ let cmpDirection = -1;
225
+ if (reverse) {
226
+ cmpDirection = 1;
227
+ uncommittedEntries.reverse();
228
+ }
229
+
230
+ let uncommittedEntriesIdx = 0;
231
+ while (uncommittedEntriesIdx < uncommittedEntries.length) {
232
+ const entry = uncommittedEntries[uncommittedEntriesIdx];
233
+ // go to the first key in our cache that would be captured by the iterator
234
+ if (Buffer.compare(entry[0], startKey) !== cmpDirection) {
235
+ break;
236
+ }
237
+ uncommittedEntriesIdx++;
238
+ }
239
+
240
+ let count = 0;
241
+ // helper to early return if we've reached our limit
242
+ const checkLimit = typeof limit === 'number' ? () => count < limit : () => true;
243
+ for await (const [key, values] of iterator) {
244
+ // yield every key that we have cached that's captured by the iterator
245
+ while (uncommittedEntriesIdx < uncommittedEntries.length && checkLimit()) {
246
+ const entry = uncommittedEntries[uncommittedEntriesIdx];
247
+ if (endKey && Buffer.compare(entry[0], endKey) !== cmpDirection) {
248
+ break;
249
+ }
250
+
251
+ if (Buffer.compare(entry[0], key) === cmpDirection) {
252
+ count++;
253
+ yield [entry[0], map(entry[1])];
254
+ } else {
255
+ break;
256
+ }
257
+ uncommittedEntriesIdx++;
258
+ }
259
+
260
+ if (!checkLimit()) {
261
+ // we reached the imposed `limit`
262
+ break;
263
+ }
264
+
265
+ const toRemove = findInSortedArray(batch.removeEntries, key, singleKeyCmp);
266
+
267
+ // at this point we've either exhausted all uncommitted entries,
268
+ // we reached a key strictly greater/smaller than `key`
269
+ // or we found the key itself
270
+ // check if it's the key and use the uncommitted value
271
+ let toAdd: Uint8Array[] = [];
272
+ if (
273
+ uncommittedEntriesIdx < uncommittedEntries.length &&
274
+ Buffer.compare(uncommittedEntries[uncommittedEntriesIdx][0], key) === 0
275
+ ) {
276
+ toAdd = uncommittedEntries[uncommittedEntriesIdx][1];
277
+ uncommittedEntriesIdx++;
278
+ }
279
+
280
+ if (toRemove && !toRemove[1]) {
281
+ // we were told to delete this key entirely
282
+ continue;
283
+ } else {
284
+ const mergedValues = merge(values, toAdd, toRemove?.[1] ?? []);
285
+ if (mergedValues) {
286
+ count++;
287
+ yield [key, mergedValues];
288
+ }
289
+ }
290
+ }
291
+
292
+ // emit all the uncommitted data that would be captured by this iterator
293
+ while (uncommittedEntriesIdx < uncommittedEntries.length && checkLimit()) {
294
+ const entry = uncommittedEntries[uncommittedEntriesIdx];
295
+ if (endKey && Buffer.compare(entry[0], endKey) !== cmpDirection) {
296
+ break;
297
+ }
298
+ count++;
299
+ yield [entry[0], map(entry[1])];
300
+ uncommittedEntriesIdx++;
301
+ }
302
+ }
303
+
304
+ public async commit() {
305
+ this.assertIsOpen();
306
+ this.close();
307
+ await this.channel.sendMessage(LMDBMessageType.BATCH, {
308
+ batches: new Map([
309
+ [Database.DATA, this.dataBatch],
310
+ [Database.INDEX, this.indexBatch],
311
+ ]),
312
+ });
313
+ }
314
+ }
@@ -48,7 +48,7 @@ export class L2TipsStore implements L2BlockStreamEventHandler, L2BlockStreamLoca
48
48
  switch (event.type) {
49
49
  case 'blocks-added':
50
50
  for (const block of event.blocks) {
51
- await this.l2BlockHashesStore.set(block.number, block.header.hash().toString());
51
+ await this.l2BlockHashesStore.set(block.number, (await block.header.hash()).toString());
52
52
  }
53
53
  await this.l2TipsStore.set('latest', event.blocks.at(-1)!.number);
54
54
  break;