@aztec/archiver 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2 → 0.76.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 (83) hide show
  1. package/dest/archiver/archiver.d.ts +186 -0
  2. package/dest/archiver/archiver.d.ts.map +1 -0
  3. package/dest/archiver/archiver.js +711 -729
  4. package/dest/archiver/archiver_store.d.ts +217 -0
  5. package/dest/archiver/archiver_store.d.ts.map +1 -0
  6. package/dest/archiver/archiver_store.js +2 -4
  7. package/dest/archiver/archiver_store_test_suite.d.ts +8 -0
  8. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -0
  9. package/dest/archiver/archiver_store_test_suite.js +224 -385
  10. package/dest/archiver/config.d.ts +37 -0
  11. package/dest/archiver/config.d.ts.map +1 -0
  12. package/dest/archiver/config.js +15 -9
  13. package/dest/archiver/data_retrieval.d.ts +71 -0
  14. package/dest/archiver/data_retrieval.d.ts.map +1 -0
  15. package/dest/archiver/data_retrieval.js +67 -77
  16. package/dest/archiver/errors.d.ts +4 -0
  17. package/dest/archiver/errors.d.ts.map +1 -0
  18. package/dest/archiver/errors.js +2 -1
  19. package/dest/archiver/index.d.ts +8 -0
  20. package/dest/archiver/index.d.ts.map +1 -0
  21. package/dest/archiver/index.js +1 -0
  22. package/dest/archiver/instrumentation.d.ts +27 -0
  23. package/dest/archiver/instrumentation.d.ts.map +1 -0
  24. package/dest/archiver/instrumentation.js +17 -29
  25. package/dest/archiver/kv_archiver_store/block_store.d.ts +87 -0
  26. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -0
  27. package/dest/archiver/kv_archiver_store/block_store.js +127 -118
  28. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +17 -0
  29. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -0
  30. package/dest/archiver/kv_archiver_store/contract_class_store.js +37 -43
  31. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +13 -0
  32. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -0
  33. package/dest/archiver/kv_archiver_store/contract_instance_store.js +12 -7
  34. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +147 -0
  35. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -0
  36. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +158 -135
  37. package/dest/archiver/kv_archiver_store/log_store.d.ts +47 -0
  38. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -0
  39. package/dest/archiver/kv_archiver_store/log_store.js +256 -271
  40. package/dest/archiver/kv_archiver_store/message_store.d.ts +33 -0
  41. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -0
  42. package/dest/archiver/kv_archiver_store/message_store.js +48 -42
  43. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +12 -0
  44. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +1 -0
  45. package/dest/archiver/kv_archiver_store/nullifier_store.js +42 -35
  46. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +23 -0
  47. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -0
  48. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +24 -15
  49. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +168 -0
  50. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -0
  51. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +231 -227
  52. package/dest/archiver/structs/data_retrieval.d.ts +27 -0
  53. package/dest/archiver/structs/data_retrieval.d.ts.map +1 -0
  54. package/dest/archiver/structs/data_retrieval.js +2 -5
  55. package/dest/archiver/structs/published.d.ts +11 -0
  56. package/dest/archiver/structs/published.d.ts.map +1 -0
  57. package/dest/archiver/structs/published.js +2 -1
  58. package/dest/factory.d.ts +10 -0
  59. package/dest/factory.d.ts.map +1 -0
  60. package/dest/factory.js +24 -32
  61. package/dest/index.d.ts +5 -0
  62. package/dest/index.d.ts.map +1 -0
  63. package/dest/index.js +1 -0
  64. package/dest/rpc/index.d.ts +9 -0
  65. package/dest/rpc/index.d.ts.map +1 -0
  66. package/dest/rpc/index.js +8 -7
  67. package/dest/test/index.d.ts +4 -0
  68. package/dest/test/index.d.ts.map +1 -0
  69. package/dest/test/index.js +1 -0
  70. package/dest/test/mock_archiver.d.ts +22 -0
  71. package/dest/test/mock_archiver.d.ts.map +1 -0
  72. package/dest/test/mock_archiver.js +13 -8
  73. package/dest/test/mock_l1_to_l2_message_source.d.ts +16 -0
  74. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -0
  75. package/dest/test/mock_l1_to_l2_message_source.js +4 -4
  76. package/dest/test/mock_l2_block_source.d.ts +80 -0
  77. package/dest/test/mock_l2_block_source.d.ts.map +1 -0
  78. package/dest/test/mock_l2_block_source.js +67 -68
  79. package/package.json +15 -14
  80. package/src/archiver/config.ts +7 -1
  81. package/src/archiver/index.ts +1 -1
  82. package/src/factory.ts +7 -3
  83. package/src/rpc/index.ts +16 -3
@@ -1,338 +1,323 @@
1
- import { ContractClass2BlockL2Logs, ExtendedPublicLog, ExtendedUnencryptedL2Log, LogId, TxScopedL2Log, UnencryptedL2Log } from '@aztec/circuit-types';
1
+ var _LogStore_instances, _LogStore_logsByTag, _LogStore_logTagsByBlock, _LogStore_privateLogsByBlock, _LogStore_publicLogsByBlock, _LogStore_contractClassLogsByBlock, _LogStore_logsMaxPageSize, _LogStore_log, _LogStore_extractTaggedLogsFromPrivate, _LogStore_extractTaggedLogsFromPublic, _LogStore_filterPublicLogsOfTx, _LogStore_filterPublicLogsBetweenBlocks, _LogStore_filterContractClassLogsOfTx, _LogStore_filterContractClassLogsBetweenBlocks, _LogStore_accumulateLogs;
2
+ import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
3
+ import { ContractClass2BlockL2Logs, ExtendedPublicLog, ExtendedUnencryptedL2Log, LogId, TxScopedL2Log, UnencryptedL2Log, } from '@aztec/circuit-types';
2
4
  import { PrivateLog, PublicLog } from '@aztec/circuits.js';
3
- import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/circuits.js/constants';
5
+ import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS, } from '@aztec/circuits.js/constants';
4
6
  import { createLogger } from '@aztec/foundation/log';
5
7
  import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
6
8
  /**
7
9
  * A store for logs
8
- */ export class LogStore {
9
- db;
10
- blockStore;
11
- #logsByTag;
12
- #logTagsByBlock;
13
- #privateLogsByBlock;
14
- #publicLogsByBlock;
15
- #contractClassLogsByBlock;
16
- #logsMaxPageSize;
17
- #log;
18
- constructor(db, blockStore, logsMaxPageSize = 1000){
10
+ */
11
+ export class LogStore {
12
+ constructor(db, blockStore, logsMaxPageSize = 1000) {
13
+ _LogStore_instances.add(this);
19
14
  this.db = db;
20
15
  this.blockStore = blockStore;
21
- this.#log = createLogger('archiver:log_store');
22
- this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
23
- this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
24
- this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
25
- this.#publicLogsByBlock = db.openMap('archiver_public_logs_by_block');
26
- this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
27
- this.#logsMaxPageSize = logsMaxPageSize;
28
- }
29
- #extractTaggedLogsFromPrivate(block) {
30
- const taggedLogs = new Map();
31
- const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
32
- block.body.txEffects.forEach((txEffect, txIndex)=>{
33
- const txHash = txEffect.txHash;
34
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
35
- txEffect.privateLogs.forEach((log)=>{
36
- const tag = log.fields[0];
37
- const currentLogs = taggedLogs.get(tag.toString()) ?? [];
38
- currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer()).toBuffer());
39
- taggedLogs.set(tag.toString(), currentLogs);
40
- });
41
- });
42
- return taggedLogs;
43
- }
44
- #extractTaggedLogsFromPublic(block) {
45
- const taggedLogs = new Map();
46
- const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
47
- block.body.txEffects.forEach((txEffect, txIndex)=>{
48
- const txHash = txEffect.txHash;
49
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
50
- txEffect.publicLogs.forEach((log)=>{
51
- // Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
52
- const firstFieldBuf = log.log[0].toBuffer();
53
- // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
54
- // Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
55
- if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
56
- // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
57
- // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
58
- this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
59
- return;
60
- }
61
- // Check that the length values line up with the log contents
62
- const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
63
- const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
64
- // Add 1 for the first field holding lengths
65
- const totalLogLength = 1 + publicValuesLength + privateValuesLength;
66
- // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
67
- if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find((f)=>!f.isZero())) {
68
- this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
69
- return;
70
- }
71
- // The first elt stores lengths as above => tag is in fields[1]
72
- const tag = log.log[1];
73
- this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
74
- const currentLogs = taggedLogs.get(tag.toString()) ?? [];
75
- currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.toBuffer()).toBuffer());
76
- taggedLogs.set(tag.toString(), currentLogs);
77
- });
78
- });
79
- return taggedLogs;
16
+ _LogStore_logsByTag.set(this, void 0);
17
+ _LogStore_logTagsByBlock.set(this, void 0);
18
+ _LogStore_privateLogsByBlock.set(this, void 0);
19
+ _LogStore_publicLogsByBlock.set(this, void 0);
20
+ _LogStore_contractClassLogsByBlock.set(this, void 0);
21
+ _LogStore_logsMaxPageSize.set(this, void 0);
22
+ _LogStore_log.set(this, createLogger('archiver:log_store'));
23
+ __classPrivateFieldSet(this, _LogStore_logsByTag, db.openMap('archiver_tagged_logs_by_tag'), "f");
24
+ __classPrivateFieldSet(this, _LogStore_logTagsByBlock, db.openMap('archiver_log_tags_by_block'), "f");
25
+ __classPrivateFieldSet(this, _LogStore_privateLogsByBlock, db.openMap('archiver_private_logs_by_block'), "f");
26
+ __classPrivateFieldSet(this, _LogStore_publicLogsByBlock, db.openMap('archiver_public_logs_by_block'), "f");
27
+ __classPrivateFieldSet(this, _LogStore_contractClassLogsByBlock, db.openMap('archiver_contract_class_logs_by_block'), "f");
28
+ __classPrivateFieldSet(this, _LogStore_logsMaxPageSize, logsMaxPageSize, "f");
80
29
  }
81
30
  /**
82
- * Append new logs to the store's list.
83
- * @param blocks - The blocks for which to add the logs.
84
- * @returns True if the operation is successful.
85
- */ addLogs(blocks) {
86
- const taggedLogsToAdd = blocks.flatMap((block)=>[
87
- this.#extractTaggedLogsFromPrivate(block),
88
- this.#extractTaggedLogsFromPublic(block)
89
- ]).reduce((acc, val)=>{
90
- for (const [tag, logs] of val.entries()){
31
+ * Append new logs to the store's list.
32
+ * @param blocks - The blocks for which to add the logs.
33
+ * @returns True if the operation is successful.
34
+ */
35
+ addLogs(blocks) {
36
+ const taggedLogsToAdd = blocks
37
+ .flatMap(block => [__classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_extractTaggedLogsFromPrivate).call(this, block), __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_extractTaggedLogsFromPublic).call(this, block)])
38
+ .reduce((acc, val) => {
39
+ for (const [tag, logs] of val.entries()) {
91
40
  const currentLogs = acc.get(tag) ?? [];
92
41
  acc.set(tag, currentLogs.concat(logs));
93
42
  }
94
43
  return acc;
95
44
  });
96
45
  const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
97
- return this.db.transactionAsync(async ()=>{
98
- const currentTaggedLogs = await Promise.all(tagsToUpdate.map(async (tag)=>({
99
- tag,
100
- logBuffers: await this.#logsByTag.getAsync(tag)
101
- })));
102
- currentTaggedLogs.forEach((taggedLogBuffer)=>{
46
+ return this.db.transactionAsync(async () => {
47
+ const currentTaggedLogs = await Promise.all(tagsToUpdate.map(async (tag) => ({ tag, logBuffers: await __classPrivateFieldGet(this, _LogStore_logsByTag, "f").getAsync(tag) })));
48
+ currentTaggedLogs.forEach(taggedLogBuffer => {
103
49
  if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
104
50
  taggedLogsToAdd.set(taggedLogBuffer.tag, taggedLogBuffer.logBuffers.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)));
105
51
  }
106
52
  });
107
- for (const block of blocks){
53
+ for (const block of blocks) {
108
54
  const tagsInBlock = [];
109
- for (const [tag, logs] of taggedLogsToAdd.entries()){
110
- await this.#logsByTag.set(tag, logs);
55
+ for (const [tag, logs] of taggedLogsToAdd.entries()) {
56
+ await __classPrivateFieldGet(this, _LogStore_logsByTag, "f").set(tag, logs);
111
57
  tagsInBlock.push(tag);
112
58
  }
113
- await this.#logTagsByBlock.set(block.number, tagsInBlock);
114
- const privateLogsInBlock = block.body.txEffects.map((txEffect)=>txEffect.privateLogs).flat().map((log)=>log.toBuffer());
115
- await this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
116
- const publicLogsInBlock = block.body.txEffects.map((txEffect, txIndex)=>[
117
- numToUInt32BE(txIndex),
118
- numToUInt32BE(txEffect.publicLogs.length),
119
- txEffect.publicLogs.map((log)=>log.toBuffer())
120
- ].flat()).flat();
121
- await this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
122
- await this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
59
+ await __classPrivateFieldGet(this, _LogStore_logTagsByBlock, "f").set(block.number, tagsInBlock);
60
+ const privateLogsInBlock = block.body.txEffects
61
+ .map(txEffect => txEffect.privateLogs)
62
+ .flat()
63
+ .map(log => log.toBuffer());
64
+ await __classPrivateFieldGet(this, _LogStore_privateLogsByBlock, "f").set(block.number, Buffer.concat(privateLogsInBlock));
65
+ const publicLogsInBlock = block.body.txEffects
66
+ .map((txEffect, txIndex) => [
67
+ numToUInt32BE(txIndex),
68
+ numToUInt32BE(txEffect.publicLogs.length),
69
+ txEffect.publicLogs.map(log => log.toBuffer()),
70
+ ].flat())
71
+ .flat();
72
+ await __classPrivateFieldGet(this, _LogStore_publicLogsByBlock, "f").set(block.number, Buffer.concat(publicLogsInBlock));
73
+ await __classPrivateFieldGet(this, _LogStore_contractClassLogsByBlock, "f").set(block.number, block.body.contractClassLogs.toBuffer());
123
74
  }
124
75
  return true;
125
76
  });
126
77
  }
127
78
  deleteLogs(blocks) {
128
- return this.db.transactionAsync(async ()=>{
129
- const tagsToDelete = (await Promise.all(blocks.map(async (block)=>{
130
- const tags = await this.#logTagsByBlock.getAsync(block.number);
79
+ return this.db.transactionAsync(async () => {
80
+ const tagsToDelete = (await Promise.all(blocks.map(async (block) => {
81
+ const tags = await __classPrivateFieldGet(this, _LogStore_logTagsByBlock, "f").getAsync(block.number);
131
82
  return tags ?? [];
132
83
  }))).flat();
133
- await Promise.all(blocks.map((block)=>Promise.all([
134
- this.#privateLogsByBlock.delete(block.number),
135
- this.#publicLogsByBlock.delete(block.number),
136
- this.#logTagsByBlock.delete(block.number)
137
- ])));
138
- await Promise.all(tagsToDelete.map((tag)=>this.#logsByTag.delete(tag.toString())));
84
+ await Promise.all(blocks.map(block => Promise.all([
85
+ __classPrivateFieldGet(this, _LogStore_privateLogsByBlock, "f").delete(block.number),
86
+ __classPrivateFieldGet(this, _LogStore_publicLogsByBlock, "f").delete(block.number),
87
+ __classPrivateFieldGet(this, _LogStore_logTagsByBlock, "f").delete(block.number),
88
+ ])));
89
+ await Promise.all(tagsToDelete.map(tag => __classPrivateFieldGet(this, _LogStore_logsByTag, "f").delete(tag.toString())));
139
90
  return true;
140
91
  });
141
92
  }
142
93
  /**
143
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `start`.
144
- * @param start - The block number from which to begin retrieving logs.
145
- * @param limit - The maximum number of blocks to retrieve logs from.
146
- * @returns An array of private logs from the specified range of blocks.
147
- */ async getPrivateLogs(start, limit) {
94
+ * Retrieves all private logs from up to `limit` blocks, starting from the block number `start`.
95
+ * @param start - The block number from which to begin retrieving logs.
96
+ * @param limit - The maximum number of blocks to retrieve logs from.
97
+ * @returns An array of private logs from the specified range of blocks.
98
+ */
99
+ async getPrivateLogs(start, limit) {
148
100
  const logs = [];
149
- for await (const buffer of this.#privateLogsByBlock.valuesAsync({
150
- start,
151
- limit
152
- })){
101
+ for await (const buffer of __classPrivateFieldGet(this, _LogStore_privateLogsByBlock, "f").valuesAsync({ start, limit })) {
153
102
  const reader = new BufferReader(buffer);
154
- while(reader.remainingBytes() > 0){
103
+ while (reader.remainingBytes() > 0) {
155
104
  logs.push(reader.readObject(PrivateLog));
156
105
  }
157
106
  }
158
107
  return logs;
159
108
  }
160
109
  /**
161
- * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
162
- * @param tags - The tags to filter the logs by.
163
- * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
164
- * that tag.
165
- */ async getLogsByTags(tags) {
166
- const logs = await Promise.all(tags.map((tag)=>this.#logsByTag.getAsync(tag.toString())));
167
- return logs.map((noteLogBuffers)=>noteLogBuffers?.map((noteLogBuffer)=>TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? []);
110
+ * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
111
+ * @param tags - The tags to filter the logs by.
112
+ * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
113
+ * that tag.
114
+ */
115
+ async getLogsByTags(tags) {
116
+ const logs = await Promise.all(tags.map(tag => __classPrivateFieldGet(this, _LogStore_logsByTag, "f").getAsync(tag.toString())));
117
+ return logs.map(noteLogBuffers => noteLogBuffers?.map(noteLogBuffer => TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? []);
168
118
  }
169
119
  /**
170
- * Gets public logs based on the provided filter.
171
- * @param filter - The filter to apply to the logs.
172
- * @returns The requested logs.
173
- */ getPublicLogs(filter) {
120
+ * Gets public logs based on the provided filter.
121
+ * @param filter - The filter to apply to the logs.
122
+ * @returns The requested logs.
123
+ */
124
+ getPublicLogs(filter) {
174
125
  if (filter.afterLog) {
175
- return this.#filterPublicLogsBetweenBlocks(filter);
176
- } else if (filter.txHash) {
177
- return this.#filterPublicLogsOfTx(filter);
178
- } else {
179
- return this.#filterPublicLogsBetweenBlocks(filter);
126
+ return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterPublicLogsBetweenBlocks).call(this, filter);
127
+ }
128
+ else if (filter.txHash) {
129
+ return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterPublicLogsOfTx).call(this, filter);
130
+ }
131
+ else {
132
+ return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterPublicLogsBetweenBlocks).call(this, filter);
180
133
  }
181
134
  }
182
- async #filterPublicLogsOfTx(filter) {
183
- if (!filter.txHash) {
184
- throw new Error('Missing txHash');
135
+ /**
136
+ * Gets contract class logs based on the provided filter.
137
+ * @param filter - The filter to apply to the logs.
138
+ * @returns The requested logs.
139
+ */
140
+ getContractClassLogs(filter) {
141
+ if (filter.afterLog) {
142
+ return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterContractClassLogsBetweenBlocks).call(this, filter);
185
143
  }
186
- const [blockNumber, txIndex] = await this.blockStore.getTxLocation(filter.txHash) ?? [];
187
- if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
188
- return {
189
- logs: [],
190
- maxLogsHit: false
191
- };
144
+ else if (filter.txHash) {
145
+ return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterContractClassLogsOfTx).call(this, filter);
192
146
  }
193
- const buffer = await this.#publicLogsByBlock.getAsync(blockNumber) ?? Buffer.alloc(0);
194
- const publicLogsInBlock = [
195
- []
196
- ];
197
- const reader = new BufferReader(buffer);
198
- while(reader.remainingBytes() > 0){
199
- const indexOfTx = reader.readNumber();
200
- const numLogsInTx = reader.readNumber();
201
- publicLogsInBlock[indexOfTx] = [];
202
- for(let i = 0; i < numLogsInTx; i++){
203
- publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
204
- }
147
+ else {
148
+ return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterContractClassLogsBetweenBlocks).call(this, filter);
205
149
  }
206
- const txLogs = publicLogsInBlock[txIndex];
207
- const logs = [];
208
- const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
209
- return {
210
- logs,
211
- maxLogsHit
212
- };
213
150
  }
214
- async #filterPublicLogsBetweenBlocks(filter) {
215
- const start = filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
216
- const end = filter.toBlock;
217
- if (typeof end === 'number' && end < start) {
218
- return {
219
- logs: [],
220
- maxLogsHit: true
221
- };
222
- }
223
- const logs = [];
224
- let maxLogsHit = false;
225
- loopOverBlocks: for await (const [blockNumber, logBuffer] of this.#publicLogsByBlock.entriesAsync({
226
- start,
227
- end
228
- })){
229
- const publicLogsInBlock = [
230
- []
231
- ];
232
- const reader = new BufferReader(logBuffer);
233
- while(reader.remainingBytes() > 0){
234
- const indexOfTx = reader.readNumber();
235
- const numLogsInTx = reader.readNumber();
236
- publicLogsInBlock[indexOfTx] = [];
237
- for(let i = 0; i < numLogsInTx; i++){
238
- publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
239
- }
151
+ }
152
+ _LogStore_logsByTag = new WeakMap(), _LogStore_logTagsByBlock = new WeakMap(), _LogStore_privateLogsByBlock = new WeakMap(), _LogStore_publicLogsByBlock = new WeakMap(), _LogStore_contractClassLogsByBlock = new WeakMap(), _LogStore_logsMaxPageSize = new WeakMap(), _LogStore_log = new WeakMap(), _LogStore_instances = new WeakSet(), _LogStore_extractTaggedLogsFromPrivate = function _LogStore_extractTaggedLogsFromPrivate(block) {
153
+ const taggedLogs = new Map();
154
+ const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
155
+ block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
156
+ block.body.txEffects.forEach((txEffect, txIndex) => {
157
+ const txHash = txEffect.txHash;
158
+ const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
159
+ txEffect.privateLogs.forEach(log => {
160
+ const tag = log.fields[0];
161
+ const currentLogs = taggedLogs.get(tag.toString()) ?? [];
162
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number,
163
+ /* isFromPublic */ false, log.toBuffer()).toBuffer());
164
+ taggedLogs.set(tag.toString(), currentLogs);
165
+ });
166
+ });
167
+ return taggedLogs;
168
+ }, _LogStore_extractTaggedLogsFromPublic = function _LogStore_extractTaggedLogsFromPublic(block) {
169
+ const taggedLogs = new Map();
170
+ const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
171
+ block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
172
+ block.body.txEffects.forEach((txEffect, txIndex) => {
173
+ const txHash = txEffect.txHash;
174
+ const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
175
+ txEffect.publicLogs.forEach(log => {
176
+ // Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
177
+ const firstFieldBuf = log.log[0].toBuffer();
178
+ // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
179
+ // Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
180
+ if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
181
+ // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
182
+ // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
183
+ __classPrivateFieldGet(this, _LogStore_log, "f").warn(`Skipping public log with invalid first field: ${log.log[0]}`);
184
+ return;
240
185
  }
241
- for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < publicLogsInBlock.length; txIndex++){
242
- const txLogs = publicLogsInBlock[txIndex];
243
- maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
244
- if (maxLogsHit) {
245
- this.#log.debug(`Max logs hit at block ${blockNumber}`);
246
- break loopOverBlocks;
247
- }
186
+ // Check that the length values line up with the log contents
187
+ const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
188
+ const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
189
+ // Add 1 for the first field holding lengths
190
+ const totalLogLength = 1 + publicValuesLength + privateValuesLength;
191
+ // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
192
+ if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
193
+ __classPrivateFieldGet(this, _LogStore_log, "f").warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
194
+ return;
248
195
  }
249
- }
250
- return {
251
- logs,
252
- maxLogsHit
253
- };
196
+ // The first elt stores lengths as above => tag is in fields[1]
197
+ const tag = log.log[1];
198
+ __classPrivateFieldGet(this, _LogStore_log, "f").debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
199
+ const currentLogs = taggedLogs.get(tag.toString()) ?? [];
200
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number,
201
+ /* isFromPublic */ true, log.toBuffer()).toBuffer());
202
+ taggedLogs.set(tag.toString(), currentLogs);
203
+ });
204
+ });
205
+ return taggedLogs;
206
+ }, _LogStore_filterPublicLogsOfTx = async function _LogStore_filterPublicLogsOfTx(filter) {
207
+ if (!filter.txHash) {
208
+ throw new Error('Missing txHash');
254
209
  }
255
- /**
256
- * Gets contract class logs based on the provided filter.
257
- * @param filter - The filter to apply to the logs.
258
- * @returns The requested logs.
259
- */ getContractClassLogs(filter) {
260
- if (filter.afterLog) {
261
- return this.#filterContractClassLogsBetweenBlocks(filter);
262
- } else if (filter.txHash) {
263
- return this.#filterContractClassLogsOfTx(filter);
264
- } else {
265
- return this.#filterContractClassLogsBetweenBlocks(filter);
266
- }
210
+ const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
211
+ if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
212
+ return { logs: [], maxLogsHit: false };
267
213
  }
268
- async #filterContractClassLogsOfTx(filter) {
269
- if (!filter.txHash) {
270
- throw new Error('Missing txHash');
271
- }
272
- const [blockNumber, txIndex] = await this.blockStore.getTxLocation(filter.txHash) ?? [];
273
- if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
274
- return {
275
- logs: [],
276
- maxLogsHit: false
277
- };
214
+ const buffer = (await __classPrivateFieldGet(this, _LogStore_publicLogsByBlock, "f").getAsync(blockNumber)) ?? Buffer.alloc(0);
215
+ const publicLogsInBlock = [[]];
216
+ const reader = new BufferReader(buffer);
217
+ while (reader.remainingBytes() > 0) {
218
+ const indexOfTx = reader.readNumber();
219
+ const numLogsInTx = reader.readNumber();
220
+ publicLogsInBlock[indexOfTx] = [];
221
+ for (let i = 0; i < numLogsInTx; i++) {
222
+ publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
278
223
  }
279
- const contractClassLogsBuffer = await this.#contractClassLogsByBlock.getAsync(blockNumber);
280
- const contractClassLogsInBlock = contractClassLogsBuffer ? ContractClass2BlockL2Logs.fromBuffer(contractClassLogsBuffer) : new ContractClass2BlockL2Logs([]);
281
- const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
282
- const logs = [];
283
- const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
224
+ }
225
+ const txLogs = publicLogsInBlock[txIndex];
226
+ const logs = [];
227
+ const maxLogsHit = __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_accumulateLogs).call(this, logs, blockNumber, txIndex, txLogs, filter);
228
+ return { logs, maxLogsHit };
229
+ }, _LogStore_filterPublicLogsBetweenBlocks = async function _LogStore_filterPublicLogsBetweenBlocks(filter) {
230
+ const start = filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
231
+ const end = filter.toBlock;
232
+ if (typeof end === 'number' && end < start) {
284
233
  return {
285
- logs,
286
- maxLogsHit
234
+ logs: [],
235
+ maxLogsHit: true,
287
236
  };
288
237
  }
289
- async #filterContractClassLogsBetweenBlocks(filter) {
290
- const start = filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
291
- const end = filter.toBlock;
292
- if (typeof end === 'number' && end < start) {
293
- return {
294
- logs: [],
295
- maxLogsHit: true
296
- };
238
+ const logs = [];
239
+ let maxLogsHit = false;
240
+ loopOverBlocks: for await (const [blockNumber, logBuffer] of __classPrivateFieldGet(this, _LogStore_publicLogsByBlock, "f").entriesAsync({ start, end })) {
241
+ const publicLogsInBlock = [[]];
242
+ const reader = new BufferReader(logBuffer);
243
+ while (reader.remainingBytes() > 0) {
244
+ const indexOfTx = reader.readNumber();
245
+ const numLogsInTx = reader.readNumber();
246
+ publicLogsInBlock[indexOfTx] = [];
247
+ for (let i = 0; i < numLogsInTx; i++) {
248
+ publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
249
+ }
297
250
  }
298
- const logs = [];
299
- let maxLogsHit = false;
300
- loopOverBlocks: for await (const [blockNumber, logBuffer] of this.#contractClassLogsByBlock.entriesAsync({
301
- start,
302
- end
303
- })){
304
- const contractClassLogsInBlock = ContractClass2BlockL2Logs.fromBuffer(logBuffer);
305
- for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.txLogs.length; txIndex++){
306
- const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
307
- maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
308
- if (maxLogsHit) {
309
- this.#log.debug(`Max logs hit at block ${blockNumber}`);
310
- break loopOverBlocks;
311
- }
251
+ for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < publicLogsInBlock.length; txIndex++) {
252
+ const txLogs = publicLogsInBlock[txIndex];
253
+ maxLogsHit = __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_accumulateLogs).call(this, logs, blockNumber, txIndex, txLogs, filter);
254
+ if (maxLogsHit) {
255
+ __classPrivateFieldGet(this, _LogStore_log, "f").debug(`Max logs hit at block ${blockNumber}`);
256
+ break loopOverBlocks;
312
257
  }
313
258
  }
259
+ }
260
+ return { logs, maxLogsHit };
261
+ }, _LogStore_filterContractClassLogsOfTx = async function _LogStore_filterContractClassLogsOfTx(filter) {
262
+ if (!filter.txHash) {
263
+ throw new Error('Missing txHash');
264
+ }
265
+ const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
266
+ if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
267
+ return { logs: [], maxLogsHit: false };
268
+ }
269
+ const contractClassLogsBuffer = await __classPrivateFieldGet(this, _LogStore_contractClassLogsByBlock, "f").getAsync(blockNumber);
270
+ const contractClassLogsInBlock = contractClassLogsBuffer
271
+ ? ContractClass2BlockL2Logs.fromBuffer(contractClassLogsBuffer)
272
+ : new ContractClass2BlockL2Logs([]);
273
+ const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
274
+ const logs = [];
275
+ const maxLogsHit = __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_accumulateLogs).call(this, logs, blockNumber, txIndex, txLogs, filter);
276
+ return { logs, maxLogsHit };
277
+ }, _LogStore_filterContractClassLogsBetweenBlocks = async function _LogStore_filterContractClassLogsBetweenBlocks(filter) {
278
+ const start = filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
279
+ const end = filter.toBlock;
280
+ if (typeof end === 'number' && end < start) {
314
281
  return {
315
- logs,
316
- maxLogsHit
282
+ logs: [],
283
+ maxLogsHit: true,
317
284
  };
318
285
  }
319
- #accumulateLogs(results, blockNumber, txIndex, txLogs, filter) {
320
- let maxLogsHit = false;
321
- let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
322
- for(; logIndex < txLogs.length; logIndex++){
323
- const log = txLogs[logIndex];
324
- if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
325
- if (log instanceof UnencryptedL2Log) {
326
- results.push(new ExtendedUnencryptedL2Log(new LogId(blockNumber, txIndex, logIndex), log));
327
- } else {
328
- results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
329
- }
330
- if (results.length >= this.#logsMaxPageSize) {
331
- maxLogsHit = true;
332
- break;
333
- }
286
+ const logs = [];
287
+ let maxLogsHit = false;
288
+ loopOverBlocks: for await (const [blockNumber, logBuffer] of __classPrivateFieldGet(this, _LogStore_contractClassLogsByBlock, "f").entriesAsync({
289
+ start,
290
+ end,
291
+ })) {
292
+ const contractClassLogsInBlock = ContractClass2BlockL2Logs.fromBuffer(logBuffer);
293
+ for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.txLogs.length; txIndex++) {
294
+ const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
295
+ maxLogsHit = __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_accumulateLogs).call(this, logs, blockNumber, txIndex, txLogs, filter);
296
+ if (maxLogsHit) {
297
+ __classPrivateFieldGet(this, _LogStore_log, "f").debug(`Max logs hit at block ${blockNumber}`);
298
+ break loopOverBlocks;
334
299
  }
335
300
  }
336
- return maxLogsHit;
337
301
  }
338
- }
302
+ return { logs, maxLogsHit };
303
+ }, _LogStore_accumulateLogs = function _LogStore_accumulateLogs(results, blockNumber, txIndex, txLogs, filter) {
304
+ let maxLogsHit = false;
305
+ let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
306
+ for (; logIndex < txLogs.length; logIndex++) {
307
+ const log = txLogs[logIndex];
308
+ if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
309
+ if (log instanceof UnencryptedL2Log) {
310
+ results.push(new ExtendedUnencryptedL2Log(new LogId(blockNumber, txIndex, logIndex), log));
311
+ }
312
+ else {
313
+ results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
314
+ }
315
+ if (results.length >= __classPrivateFieldGet(this, _LogStore_logsMaxPageSize, "f")) {
316
+ maxLogsHit = true;
317
+ break;
318
+ }
319
+ }
320
+ }
321
+ return maxLogsHit;
322
+ };
323
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nX3N0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FyY2hpdmVyL2t2X2FyY2hpdmVyX3N0b3JlL2xvZ19zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsaUJBQWlCLEVBQ2pCLHdCQUF3QixFQUt4QixLQUFLLEVBQ0wsYUFBYSxFQUNiLGdCQUFnQixHQUNqQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBVyxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEUsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixzQkFBc0IsRUFDdEIsOEJBQThCLEdBQy9CLE1BQU0sOEJBQThCLENBQUM7QUFDdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFLMUU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sUUFBUTtJQVNuQixZQUFvQixFQUFxQixFQUFVLFVBQXNCLEVBQUUsa0JBQTBCLElBQUk7O1FBQXJGLE9BQUUsR0FBRixFQUFFLENBQW1CO1FBQVUsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQVJ6RSxzQ0FBNEM7UUFDNUMsMkNBQWlEO1FBQ2pELCtDQUFtRDtRQUNuRCw4Q0FBa0Q7UUFDbEQscURBQXlEO1FBQ3pELDRDQUF5QjtRQUN6Qix3QkFBTyxZQUFZLENBQUMsb0JBQW9CLENBQUMsRUFBQztRQUd4Qyx1QkFBQSxJQUFJLHVCQUFjLEVBQUUsQ0FBQyxPQUFPLENBQUMsNkJBQTZCLENBQUMsTUFBQSxDQUFDO1FBQzVELHVCQUFBLElBQUksNEJBQW1CLEVBQUUsQ0FBQyxPQUFPLENBQUMsNEJBQTRCLENBQUMsTUFBQSxDQUFDO1FBQ2hFLHVCQUFBLElBQUksZ0NBQXVCLEVBQUUsQ0FBQyxPQUFPLENBQUMsZ0NBQWdDLENB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