@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.
- package/dest/archiver/archiver.d.ts +186 -0
- package/dest/archiver/archiver.d.ts.map +1 -0
- package/dest/archiver/archiver.js +711 -729
- package/dest/archiver/archiver_store.d.ts +217 -0
- package/dest/archiver/archiver_store.d.ts.map +1 -0
- package/dest/archiver/archiver_store.js +2 -4
- package/dest/archiver/archiver_store_test_suite.d.ts +8 -0
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -0
- package/dest/archiver/archiver_store_test_suite.js +224 -385
- package/dest/archiver/config.d.ts +37 -0
- package/dest/archiver/config.d.ts.map +1 -0
- package/dest/archiver/config.js +15 -9
- package/dest/archiver/data_retrieval.d.ts +71 -0
- package/dest/archiver/data_retrieval.d.ts.map +1 -0
- package/dest/archiver/data_retrieval.js +67 -77
- package/dest/archiver/errors.d.ts +4 -0
- package/dest/archiver/errors.d.ts.map +1 -0
- package/dest/archiver/errors.js +2 -1
- package/dest/archiver/index.d.ts +8 -0
- package/dest/archiver/index.d.ts.map +1 -0
- package/dest/archiver/index.js +1 -0
- package/dest/archiver/instrumentation.d.ts +27 -0
- package/dest/archiver/instrumentation.d.ts.map +1 -0
- package/dest/archiver/instrumentation.js +17 -29
- package/dest/archiver/kv_archiver_store/block_store.d.ts +87 -0
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/block_store.js +127 -118
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +17 -0
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/contract_class_store.js +37 -43
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +13 -0
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/contract_instance_store.js +12 -7
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +147 -0
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +158 -135
- package/dest/archiver/kv_archiver_store/log_store.d.ts +47 -0
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/log_store.js +256 -271
- package/dest/archiver/kv_archiver_store/message_store.d.ts +33 -0
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/message_store.js +48 -42
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +12 -0
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/nullifier_store.js +42 -35
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +23 -0
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -0
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +24 -15
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +168 -0
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -0
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +231 -227
- package/dest/archiver/structs/data_retrieval.d.ts +27 -0
- package/dest/archiver/structs/data_retrieval.d.ts.map +1 -0
- package/dest/archiver/structs/data_retrieval.js +2 -5
- package/dest/archiver/structs/published.d.ts +11 -0
- package/dest/archiver/structs/published.d.ts.map +1 -0
- package/dest/archiver/structs/published.js +2 -1
- package/dest/factory.d.ts +10 -0
- package/dest/factory.d.ts.map +1 -0
- package/dest/factory.js +24 -32
- package/dest/index.d.ts +5 -0
- package/dest/index.d.ts.map +1 -0
- package/dest/index.js +1 -0
- package/dest/rpc/index.d.ts +9 -0
- package/dest/rpc/index.d.ts.map +1 -0
- package/dest/rpc/index.js +8 -7
- package/dest/test/index.d.ts +4 -0
- package/dest/test/index.d.ts.map +1 -0
- package/dest/test/index.js +1 -0
- package/dest/test/mock_archiver.d.ts +22 -0
- package/dest/test/mock_archiver.d.ts.map +1 -0
- package/dest/test/mock_archiver.js +13 -8
- package/dest/test/mock_l1_to_l2_message_source.d.ts +16 -0
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -0
- package/dest/test/mock_l1_to_l2_message_source.js +4 -4
- package/dest/test/mock_l2_block_source.d.ts +80 -0
- package/dest/test/mock_l2_block_source.d.ts.map +1 -0
- package/dest/test/mock_l2_block_source.js +67 -68
- package/package.json +15 -14
- package/src/archiver/config.ts +7 -1
- package/src/archiver/index.ts +1 -1
- package/src/factory.ts +7 -3
- package/src/rpc/index.ts +16 -3
|
@@ -1,338 +1,323 @@
|
|
|
1
|
-
|
|
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
|
-
*/
|
|
9
|
-
|
|
10
|
-
blockStore
|
|
11
|
-
|
|
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
|
|
22
|
-
this
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this
|
|
26
|
-
this
|
|
27
|
-
this
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
114
|
-
const privateLogsInBlock = block.body.txEffects
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
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(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
await Promise.all(tagsToDelete.map(
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
187
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
257
|
-
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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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
|