@aztec/archiver 0.73.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2

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 (82) hide show
  1. package/dest/archiver/archiver.js +729 -711
  2. package/dest/archiver/archiver_store.js +4 -2
  3. package/dest/archiver/archiver_store_test_suite.js +385 -224
  4. package/dest/archiver/config.js +9 -11
  5. package/dest/archiver/data_retrieval.js +89 -65
  6. package/dest/archiver/errors.js +1 -2
  7. package/dest/archiver/index.js +0 -1
  8. package/dest/archiver/instrumentation.js +29 -17
  9. package/dest/archiver/kv_archiver_store/block_store.js +118 -127
  10. package/dest/archiver/kv_archiver_store/contract_class_store.js +43 -37
  11. package/dest/archiver/kv_archiver_store/contract_instance_store.js +7 -12
  12. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +135 -158
  13. package/dest/archiver/kv_archiver_store/log_store.js +271 -256
  14. package/dest/archiver/kv_archiver_store/message_store.js +42 -48
  15. package/dest/archiver/kv_archiver_store/nullifier_store.js +35 -42
  16. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +15 -24
  17. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +227 -231
  18. package/dest/archiver/structs/data_retrieval.js +5 -2
  19. package/dest/archiver/structs/published.js +1 -2
  20. package/dest/factory.js +30 -20
  21. package/dest/index.js +0 -1
  22. package/dest/rpc/index.js +5 -2
  23. package/dest/test/index.js +0 -1
  24. package/dest/test/mock_archiver.js +8 -13
  25. package/dest/test/mock_l1_to_l2_message_source.js +4 -4
  26. package/dest/test/mock_l2_block_source.js +68 -67
  27. package/package.json +14 -13
  28. package/src/archiver/archiver.ts +1 -1
  29. package/src/archiver/data_retrieval.ts +17 -3
  30. package/src/archiver/index.ts +1 -1
  31. package/dest/archiver/archiver.d.ts +0 -186
  32. package/dest/archiver/archiver.d.ts.map +0 -1
  33. package/dest/archiver/archiver_store.d.ts +0 -217
  34. package/dest/archiver/archiver_store.d.ts.map +0 -1
  35. package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
  36. package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
  37. package/dest/archiver/config.d.ts +0 -35
  38. package/dest/archiver/config.d.ts.map +0 -1
  39. package/dest/archiver/data_retrieval.d.ts +0 -71
  40. package/dest/archiver/data_retrieval.d.ts.map +0 -1
  41. package/dest/archiver/errors.d.ts +0 -4
  42. package/dest/archiver/errors.d.ts.map +0 -1
  43. package/dest/archiver/index.d.ts +0 -8
  44. package/dest/archiver/index.d.ts.map +0 -1
  45. package/dest/archiver/instrumentation.d.ts +0 -27
  46. package/dest/archiver/instrumentation.d.ts.map +0 -1
  47. package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -87
  48. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
  49. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -17
  50. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
  51. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -13
  52. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
  53. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -147
  54. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
  55. package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -47
  56. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
  57. package/dest/archiver/kv_archiver_store/message_store.d.ts +0 -33
  58. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
  59. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +0 -12
  60. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +0 -1
  61. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
  62. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
  63. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -168
  64. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
  65. package/dest/archiver/structs/data_retrieval.d.ts +0 -27
  66. package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
  67. package/dest/archiver/structs/published.d.ts +0 -11
  68. package/dest/archiver/structs/published.d.ts.map +0 -1
  69. package/dest/factory.d.ts +0 -10
  70. package/dest/factory.d.ts.map +0 -1
  71. package/dest/index.d.ts +0 -5
  72. package/dest/index.d.ts.map +0 -1
  73. package/dest/rpc/index.d.ts +0 -4
  74. package/dest/rpc/index.d.ts.map +0 -1
  75. package/dest/test/index.d.ts +0 -4
  76. package/dest/test/index.d.ts.map +0 -1
  77. package/dest/test/mock_archiver.d.ts +0 -22
  78. package/dest/test/mock_archiver.d.ts.map +0 -1
  79. package/dest/test/mock_l1_to_l2_message_source.d.ts +0 -16
  80. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +0 -1
  81. package/dest/test/mock_l2_block_source.d.ts +0 -80
  82. package/dest/test/mock_l2_block_source.d.ts.map +0 -1
@@ -1,323 +1,338 @@
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';
1
+ import { ContractClass2BlockL2Logs, ExtendedPublicLog, ExtendedUnencryptedL2Log, LogId, TxScopedL2Log, UnencryptedL2Log } from '@aztec/circuit-types';
4
2
  import { PrivateLog, PublicLog } from '@aztec/circuits.js';
5
- import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS, } from '@aztec/circuits.js/constants';
3
+ import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/circuits.js/constants';
6
4
  import { createLogger } from '@aztec/foundation/log';
7
5
  import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
8
6
  /**
9
7
  * A store for logs
10
- */
11
- export class LogStore {
12
- constructor(db, blockStore, logsMaxPageSize = 1000) {
13
- _LogStore_instances.add(this);
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){
14
19
  this.db = db;
15
20
  this.blockStore = blockStore;
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");
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;
29
80
  }
30
81
  /**
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()) {
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()){
40
91
  const currentLogs = acc.get(tag) ?? [];
41
92
  acc.set(tag, currentLogs.concat(logs));
42
93
  }
43
94
  return acc;
44
95
  });
45
96
  const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
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 => {
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)=>{
49
103
  if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
50
104
  taggedLogsToAdd.set(taggedLogBuffer.tag, taggedLogBuffer.logBuffers.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)));
51
105
  }
52
106
  });
53
- for (const block of blocks) {
107
+ for (const block of blocks){
54
108
  const tagsInBlock = [];
55
- for (const [tag, logs] of taggedLogsToAdd.entries()) {
56
- await __classPrivateFieldGet(this, _LogStore_logsByTag, "f").set(tag, logs);
109
+ for (const [tag, logs] of taggedLogsToAdd.entries()){
110
+ await this.#logsByTag.set(tag, logs);
57
111
  tagsInBlock.push(tag);
58
112
  }
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());
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());
74
123
  }
75
124
  return true;
76
125
  });
77
126
  }
78
127
  deleteLogs(blocks) {
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);
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);
82
131
  return tags ?? [];
83
132
  }))).flat();
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())));
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())));
90
139
  return true;
91
140
  });
92
141
  }
93
142
  /**
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) {
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) {
100
148
  const logs = [];
101
- for await (const buffer of __classPrivateFieldGet(this, _LogStore_privateLogsByBlock, "f").valuesAsync({ start, limit })) {
149
+ for await (const buffer of this.#privateLogsByBlock.valuesAsync({
150
+ start,
151
+ limit
152
+ })){
102
153
  const reader = new BufferReader(buffer);
103
- while (reader.remainingBytes() > 0) {
154
+ while(reader.remainingBytes() > 0){
104
155
  logs.push(reader.readObject(PrivateLog));
105
156
  }
106
157
  }
107
158
  return logs;
108
159
  }
109
160
  /**
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)) ?? []);
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)) ?? []);
118
168
  }
119
169
  /**
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) {
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) {
125
174
  if (filter.afterLog) {
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);
175
+ return this.#filterPublicLogsBetweenBlocks(filter);
176
+ } else if (filter.txHash) {
177
+ return this.#filterPublicLogsOfTx(filter);
178
+ } else {
179
+ return this.#filterPublicLogsBetweenBlocks(filter);
133
180
  }
134
181
  }
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);
143
- }
144
- else if (filter.txHash) {
145
- return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterContractClassLogsOfTx).call(this, filter);
182
+ async #filterPublicLogsOfTx(filter) {
183
+ if (!filter.txHash) {
184
+ throw new Error('Missing txHash');
146
185
  }
147
- else {
148
- return __classPrivateFieldGet(this, _LogStore_instances, "m", _LogStore_filterContractClassLogsBetweenBlocks).call(this, filter);
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
+ };
149
192
  }
150
- }
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;
185
- }
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;
195
- }
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');
209
- }
210
- const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
211
- if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
212
- return { logs: [], maxLogsHit: false };
213
- }
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));
223
- }
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) {
233
- return {
234
- logs: [],
235
- maxLogsHit: true,
236
- };
237
- }
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) {
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){
244
199
  const indexOfTx = reader.readNumber();
245
200
  const numLogsInTx = reader.readNumber();
246
201
  publicLogsInBlock[indexOfTx] = [];
247
- for (let i = 0; i < numLogsInTx; i++) {
202
+ for(let i = 0; i < numLogsInTx; i++){
248
203
  publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
249
204
  }
250
205
  }
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;
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
+ }
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
+ }
240
+ }
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
+ }
257
248
  }
258
249
  }
250
+ return {
251
+ logs,
252
+ maxLogsHit
253
+ };
259
254
  }
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 };
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
+ }
268
267
  }
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) {
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
+ };
278
+ }
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);
281
284
  return {
282
- logs: [],
283
- maxLogsHit: true,
285
+ logs,
286
+ maxLogsHit
284
287
  };
285
288
  }
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;
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
+ };
297
+ }
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
+ }
299
312
  }
300
313
  }
314
+ return {
315
+ logs,
316
+ maxLogsHit
317
+ };
301
318
  }
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;
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
+ }
318
334
  }
319
335
  }
336
+ return maxLogsHit;
320
337
  }
321
- return maxLogsHit;
322
- };
323
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nX3N0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FyY2hpdmVyL2t2X2FyY2hpdmVyX3N0b3JlL2xvZ19zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsaUJBQWlCLEVBQ2pCLHdCQUF3QixFQUt4QixLQUFLLEVBQ0wsYUFBYSxFQUNiLGdCQUFnQixHQUNqQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBVyxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEUsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixzQkFBc0IsRUFDdEIsOEJBQThCLEdBQy9CLE1BQU0sOEJBQThCLENBQUM7QUFDdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFLMUU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sUUFBUTtJQVNuQixZQUFvQixFQUFxQixFQUFVLFVBQXNCLEVBQUUsa0JBQTBCLElBQUk7O1FBQXJGLE9BQUUsR0FBRixFQUFFLENBQW1CO1FBQVUsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQVJ6RSxzQ0FBNEM7UUFDNUMsMkNBQWlEO1FBQ2pELCtDQUFtRDtRQUNuRCw4Q0FBa0Q7UUFDbEQscURBQXlEO1FBQ3pELDRDQUF5QjtRQUN6Qix3QkFBTyxZQUFZLENBQUMsb0JBQW9CLENBQUMsRUFBQztRQUd4Qyx1QkFBQSxJQUFJLHVCQUFjLEVBQUUsQ0FBQyxPQUFPLENBQUMsNkJBQTZCLENBQUMsTUFBQSxDQUFDO1FBQzVELHVCQUFBLElBQUksNEJBQW1CLEVBQUUsQ0FBQyxPQUFPLENBQUMsNEJBQTRCLENBQUMsTUFBQSxDQUFDO1FBQ2hFLHVCQUFBLElBQUksZ0NBQXVCLEVBQUUsQ0FBQyxPQUFPLENBQUMsZ0NBQWdDLENB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
338
+ }