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