@aztec/archiver 0.0.1-commit.001888fc → 0.0.1-commit.017a351
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 +19 -11
- package/dest/archiver.d.ts +53 -16
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +248 -76
- package/dest/config.d.ts +4 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +21 -14
- package/dest/errors.d.ts +44 -10
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +66 -12
- package/dest/factory.d.ts +13 -7
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +37 -25
- package/dest/index.d.ts +11 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +10 -2
- package/dest/l1/calldata_retriever.d.ts +2 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +15 -5
- package/dest/l1/data_retrieval.d.ts +19 -10
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +25 -32
- package/dest/l1/trace_tx.d.ts +12 -66
- package/dest/l1/trace_tx.d.ts.map +1 -1
- package/dest/l1/validate_historical_logs.d.ts +23 -0
- package/dest/l1/validate_historical_logs.d.ts.map +1 -0
- package/dest/l1/validate_historical_logs.js +108 -0
- package/dest/modules/contract_data_source_adapter.d.ts +25 -0
- package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
- package/dest/modules/contract_data_source_adapter.js +40 -0
- package/dest/modules/data_source_base.d.ts +71 -47
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +269 -137
- package/dest/modules/data_store_updater.d.ts +30 -13
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +166 -116
- package/dest/modules/instrumentation.d.ts +7 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +25 -7
- package/dest/modules/l1_synchronizer.d.ts +11 -6
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +414 -214
- package/dest/modules/outbox_trees_resolver.d.ts +62 -0
- package/dest/modules/outbox_trees_resolver.d.ts.map +1 -0
- package/dest/modules/outbox_trees_resolver.js +162 -0
- package/dest/modules/validation.d.ts +4 -3
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +6 -6
- package/dest/store/block_store.d.ts +165 -66
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +648 -233
- package/dest/store/contract_class_store.d.ts +17 -4
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +24 -68
- package/dest/store/contract_instance_store.d.ts +28 -1
- package/dest/store/contract_instance_store.d.ts.map +1 -1
- package/dest/store/contract_instance_store.js +37 -2
- package/dest/store/data_stores.d.ts +68 -0
- package/dest/store/data_stores.d.ts.map +1 -0
- package/dest/store/data_stores.js +54 -0
- package/dest/store/function_names_cache.d.ts +17 -0
- package/dest/store/function_names_cache.d.ts.map +1 -0
- package/dest/store/function_names_cache.js +30 -0
- package/dest/store/l2_tips_cache.d.ts +13 -7
- package/dest/store/l2_tips_cache.d.ts.map +1 -1
- package/dest/store/l2_tips_cache.js +13 -76
- package/dest/store/log_store.d.ts +42 -40
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +259 -462
- package/dest/store/log_store_codec.d.ts +70 -0
- package/dest/store/log_store_codec.d.ts.map +1 -0
- package/dest/store/log_store_codec.js +101 -0
- package/dest/store/message_store.d.ts +9 -3
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +39 -10
- package/dest/test/fake_l1_state.d.ts +15 -3
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +80 -18
- package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +2 -1
- package/dest/test/mock_l2_block_source.d.ts +51 -50
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +244 -181
- package/dest/test/noop_l1_archiver.d.ts +10 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +22 -9
- package/package.json +14 -14
- package/src/archiver.ts +315 -83
- package/src/config.ts +24 -11
- package/src/errors.ts +103 -18
- package/src/factory.ts +49 -25
- package/src/index.ts +18 -2
- package/src/l1/calldata_retriever.ts +16 -5
- package/src/l1/data_retrieval.ts +36 -45
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/modules/contract_data_source_adapter.ts +55 -0
- package/src/modules/data_source_base.ts +341 -179
- package/src/modules/data_store_updater.ts +201 -147
- package/src/modules/instrumentation.ts +28 -8
- package/src/modules/l1_synchronizer.ts +549 -255
- package/src/modules/outbox_trees_resolver.ts +199 -0
- package/src/modules/validation.ts +10 -9
- package/src/store/block_store.ts +807 -285
- package/src/store/contract_class_store.ts +31 -103
- package/src/store/contract_instance_store.ts +51 -5
- package/src/store/data_stores.ts +104 -0
- package/src/store/function_names_cache.ts +37 -0
- package/src/store/l2_tips_cache.ts +16 -70
- package/src/store/log_store.ts +297 -623
- package/src/store/log_store_codec.ts +132 -0
- package/src/store/message_store.ts +43 -12
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +99 -27
- package/src/test/mock_l1_to_l2_message_source.ts +1 -0
- package/src/test/mock_l2_block_source.ts +299 -232
- package/src/test/noop_l1_archiver.ts +42 -9
- package/dest/store/kv_archiver_store.d.ts +0 -367
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -481
- package/src/store/kv_archiver_store.ts +0 -697
package/dest/store/log_store.js
CHANGED
|
@@ -1,513 +1,310 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { filterAsync } from '@aztec/foundation/collection';
|
|
4
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
|
-
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
7
|
-
import { BlockHash } from '@aztec/stdlib/block';
|
|
8
3
|
import { MAX_LOGS_PER_TAG } from '@aztec/stdlib/interfaces/api-limit';
|
|
9
|
-
import {
|
|
10
|
-
import { TxHash } from '@aztec/stdlib/tx';
|
|
11
|
-
import { OutOfOrderLogInsertionError } from '../errors.js';
|
|
4
|
+
import { decodeKeyTail, decodeValue, encodeKey, encodePublicPrefix, encodeValue, endOfTagRange, endOfTxRange, fieldHex, incKey } from './log_store_codec.js';
|
|
12
5
|
/**
|
|
13
|
-
*
|
|
6
|
+
* Indexes every emitted private and public log under a composite hex-string key
|
|
7
|
+
* `[contractAddress (public only)]-tag-blockNumber-txIndexWithinBlock-logIndexWithinTx`,
|
|
8
|
+
* where each numeric segment is zero-padded to 8 lowercase hex digits (4 bytes BE) and
|
|
9
|
+
* `contractAddress` / `tag` are the bare 64-hex-char field representations (no `0x` prefix). The
|
|
10
|
+
* fixed-width zero-padded hex segments sort lexicographically in the same order as the canonical
|
|
11
|
+
* `(contract, tag, blockNumber, txIndexWithinBlock, logIndexWithinTx)` tuple, so a single ordered
|
|
12
|
+
* range scan answers every {@link PrivateLogsQuery} / {@link PublicLogsQuery}.
|
|
13
|
+
*
|
|
14
|
+
* Per-block secondary indices (`#privateKeysByBlock`, `#publicKeysByBlock`) record the exact primary
|
|
15
|
+
* keys written for each block so {@link deleteLogs} can drop them on reorg without having to range
|
|
16
|
+
* scan by block (block isn't the leading key segment).
|
|
17
|
+
*
|
|
18
|
+
* Contract-class logs are no longer stored or served by the log store.
|
|
14
19
|
*/ export class LogStore {
|
|
15
20
|
db;
|
|
16
21
|
blockStore;
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#publicLogKeysByBlock;
|
|
23
|
-
#publicLogsByBlock;
|
|
24
|
-
#contractClassLogsByBlock;
|
|
25
|
-
#logsMaxPageSize;
|
|
22
|
+
genesisBlockHash;
|
|
23
|
+
/** Primary map: composite private key (tag + tail = 96 hex chars + separators) -> serialized {@link StoredLogValue}. */ #privateLogs;
|
|
24
|
+
/** Primary map: composite public key (contract + tag + tail) -> serialized {@link StoredLogValue}. */ #publicLogs;
|
|
25
|
+
/** Secondary deletion index: blockNumber -> the exact primary keys written for that block. */ #privateKeysByBlock;
|
|
26
|
+
#publicKeysByBlock;
|
|
26
27
|
#log;
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @param genesisBlockHash - Hash of the synthetic genesis block. During early sync the PXE anchors to
|
|
30
|
+
* genesis and passes its hash as a query `referenceBlock`; since the archiver never indexes the
|
|
31
|
+
* genesis block, the store recognizes this hash directly and resolves it to the genesis block number
|
|
32
|
+
* rather than mistaking it for a reorg.
|
|
33
|
+
*/ constructor(db, blockStore, genesisBlockHash){
|
|
28
34
|
this.db = db;
|
|
29
35
|
this.blockStore = blockStore;
|
|
36
|
+
this.genesisBlockHash = genesisBlockHash;
|
|
30
37
|
this.#log = createLogger('archiver:log_store');
|
|
31
|
-
this.#
|
|
32
|
-
this.#
|
|
33
|
-
this.#
|
|
34
|
-
this.#
|
|
35
|
-
this.#publicLogsByBlock = db.openMap('archiver_public_logs_by_block');
|
|
36
|
-
this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
|
|
37
|
-
this.#logsMaxPageSize = logsMaxPageSize;
|
|
38
|
+
this.#privateLogs = db.openMap('archiver_private_logs');
|
|
39
|
+
this.#publicLogs = db.openMap('archiver_public_logs');
|
|
40
|
+
this.#privateKeysByBlock = db.openMap('archiver_private_log_keys_by_block');
|
|
41
|
+
this.#publicKeysByBlock = db.openMap('archiver_public_log_keys_by_block');
|
|
38
42
|
}
|
|
39
43
|
/**
|
|
40
|
-
*
|
|
44
|
+
* Indexes every emitted private and public log from the given blocks. Wraps the write in a single
|
|
45
|
+
* `db.transactionAsync` so the primary entries and the per-block secondary indices stay consistent.
|
|
41
46
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
return acc;
|
|
89
|
-
}, new Map());
|
|
90
|
-
const publicTaggedLogs = taggedLogsInBlocks.reduce((acc, { publicTaggedLogs })=>{
|
|
91
|
-
for (const [key, logs] of publicTaggedLogs.entries()){
|
|
92
|
-
const currentLogs = acc.get(key) ?? [];
|
|
93
|
-
acc.set(key, currentLogs.concat(logs));
|
|
94
|
-
}
|
|
95
|
-
return acc;
|
|
96
|
-
}, new Map());
|
|
97
|
-
return {
|
|
98
|
-
privateTaggedLogs,
|
|
99
|
-
publicTaggedLogs
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
async #addPrivateLogs(blocks) {
|
|
103
|
-
const newBlocks = await filterAsync(blocks, async (block)=>!await this.#privateLogKeysByBlock.hasAsync(block.number));
|
|
104
|
-
const { privateTaggedLogs } = this.#extractTaggedLogs(newBlocks);
|
|
105
|
-
const keysOfPrivateLogsToUpdate = Array.from(privateTaggedLogs.keys());
|
|
106
|
-
const currentPrivateTaggedLogs = await Promise.all(keysOfPrivateLogsToUpdate.map(async (key)=>({
|
|
107
|
-
tag: key,
|
|
108
|
-
logBuffers: await this.#privateLogsByTag.getAsync(key)
|
|
109
|
-
})));
|
|
110
|
-
for (const taggedLogBuffer of currentPrivateTaggedLogs){
|
|
111
|
-
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
112
|
-
const newLogs = privateTaggedLogs.get(taggedLogBuffer.tag);
|
|
113
|
-
if (newLogs.length === 0) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
const lastExisting = TxScopedL2Log.fromBuffer(taggedLogBuffer.logBuffers.at(-1));
|
|
117
|
-
const firstNew = TxScopedL2Log.fromBuffer(newLogs[0]);
|
|
118
|
-
if (lastExisting.blockNumber > firstNew.blockNumber) {
|
|
119
|
-
throw new OutOfOrderLogInsertionError('private', taggedLogBuffer.tag, lastExisting.blockNumber, firstNew.blockNumber);
|
|
47
|
+
* A block is only ever added once; on reorg the archiver calls {@link deleteLogs} first, so we write
|
|
48
|
+
* the secondary index entries with a plain `set` (overwrite) rather than read-modify-append.
|
|
49
|
+
*/ addLogs(blocks) {
|
|
50
|
+
return this.db.transactionAsync(async ()=>{
|
|
51
|
+
for (const block of blocks){
|
|
52
|
+
const blockHash = await block.hash();
|
|
53
|
+
const blockNumber = block.number;
|
|
54
|
+
const blockTimestamp = block.timestamp;
|
|
55
|
+
const privateKeys = [];
|
|
56
|
+
const privateValues = [];
|
|
57
|
+
const publicKeys = [];
|
|
58
|
+
const publicValues = [];
|
|
59
|
+
for(let txIndexWithinBlock = 0; txIndexWithinBlock < block.body.txEffects.length; txIndexWithinBlock++){
|
|
60
|
+
const txEffect = block.body.txEffects[txIndexWithinBlock];
|
|
61
|
+
const txHash = txEffect.txHash;
|
|
62
|
+
// Private and public log indices are counted independently per tx, each starting at 0.
|
|
63
|
+
let privateLogIndexWithinTx = 0;
|
|
64
|
+
let publicLogIndexWithinTx = 0;
|
|
65
|
+
for (const log of txEffect.privateLogs){
|
|
66
|
+
const tagHex = fieldHex(log.fields[0]);
|
|
67
|
+
const key = encodeKey(tagHex, blockNumber, txIndexWithinBlock, privateLogIndexWithinTx);
|
|
68
|
+
const value = encodeValue({
|
|
69
|
+
txHash,
|
|
70
|
+
blockHash,
|
|
71
|
+
blockTimestamp,
|
|
72
|
+
logData: log.getEmittedFields()
|
|
73
|
+
});
|
|
74
|
+
privateKeys.push(key);
|
|
75
|
+
privateValues.push(value);
|
|
76
|
+
privateLogIndexWithinTx++;
|
|
77
|
+
}
|
|
78
|
+
for (const log of txEffect.publicLogs){
|
|
79
|
+
const contractHex = fieldHex(log.contractAddress);
|
|
80
|
+
const tagHex = fieldHex(log.fields[0]);
|
|
81
|
+
const key = encodeKey(encodePublicPrefix(contractHex, tagHex), blockNumber, txIndexWithinBlock, publicLogIndexWithinTx);
|
|
82
|
+
const value = encodeValue({
|
|
83
|
+
txHash,
|
|
84
|
+
blockHash,
|
|
85
|
+
blockTimestamp,
|
|
86
|
+
logData: log.getEmittedFields()
|
|
87
|
+
});
|
|
88
|
+
publicKeys.push(key);
|
|
89
|
+
publicValues.push(value);
|
|
90
|
+
publicLogIndexWithinTx++;
|
|
91
|
+
}
|
|
120
92
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
for (const block of newBlocks){
|
|
125
|
-
const privateTagsInBlock = [];
|
|
126
|
-
for (const [tag, logs] of privateTaggedLogs.entries()){
|
|
127
|
-
await this.#privateLogsByTag.set(tag, logs);
|
|
128
|
-
privateTagsInBlock.push(tag);
|
|
129
|
-
}
|
|
130
|
-
await this.#privateLogKeysByBlock.set(block.number, privateTagsInBlock);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
async #addPublicLogs(blocks) {
|
|
134
|
-
const newBlocks = await filterAsync(blocks, async (block)=>!await this.#publicLogKeysByBlock.hasAsync(block.number));
|
|
135
|
-
const { publicTaggedLogs } = this.#extractTaggedLogs(newBlocks);
|
|
136
|
-
const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys());
|
|
137
|
-
const currentPublicTaggedLogs = await Promise.all(keysOfPublicLogsToUpdate.map(async (key)=>({
|
|
138
|
-
tag: key,
|
|
139
|
-
logBuffers: await this.#publicLogsByContractAndTag.getAsync(key)
|
|
140
|
-
})));
|
|
141
|
-
for (const taggedLogBuffer of currentPublicTaggedLogs){
|
|
142
|
-
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
143
|
-
const newLogs = publicTaggedLogs.get(taggedLogBuffer.tag);
|
|
144
|
-
if (newLogs.length === 0) {
|
|
145
|
-
continue;
|
|
93
|
+
for(let i = 0; i < privateKeys.length; i++){
|
|
94
|
+
await this.#privateLogs.set(privateKeys[i], privateValues[i]);
|
|
146
95
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (lastExisting.blockNumber > firstNew.blockNumber) {
|
|
150
|
-
throw new OutOfOrderLogInsertionError('public', taggedLogBuffer.tag, lastExisting.blockNumber, firstNew.blockNumber);
|
|
96
|
+
for(let i = 0; i < publicKeys.length; i++){
|
|
97
|
+
await this.#publicLogs.set(publicKeys[i], publicValues[i]);
|
|
151
98
|
}
|
|
152
|
-
|
|
99
|
+
await this.#privateKeysByBlock.set(blockNumber, privateKeys);
|
|
100
|
+
await this.#publicKeysByBlock.set(blockNumber, publicKeys);
|
|
101
|
+
this.#log.debug(`Indexed logs for block ${blockNumber}`, {
|
|
102
|
+
blockNumber,
|
|
103
|
+
privateCount: privateKeys.length,
|
|
104
|
+
publicCount: publicKeys.length
|
|
105
|
+
});
|
|
153
106
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const blockHash = await block.hash();
|
|
157
|
-
const publicTagsInBlock = [];
|
|
158
|
-
for (const [tag, logs] of publicTaggedLogs.entries()){
|
|
159
|
-
await this.#publicLogsByContractAndTag.set(tag, logs);
|
|
160
|
-
publicTagsInBlock.push(tag);
|
|
161
|
-
}
|
|
162
|
-
await this.#publicLogKeysByBlock.set(block.number, publicTagsInBlock);
|
|
163
|
-
const publicLogsInBlock = block.body.txEffects.map((txEffect, txIndex)=>[
|
|
164
|
-
numToUInt32BE(txIndex),
|
|
165
|
-
txEffect.txHash.toBuffer(),
|
|
166
|
-
numToUInt32BE(txEffect.publicLogs.length),
|
|
167
|
-
txEffect.publicLogs.map((log)=>log.toBuffer())
|
|
168
|
-
].flat()).flat();
|
|
169
|
-
await this.#publicLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, publicLogsInBlock));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
async #addContractClassLogs(blocks) {
|
|
173
|
-
const newBlocks = await filterAsync(blocks, async (block)=>!await this.#contractClassLogsByBlock.hasAsync(block.number));
|
|
174
|
-
for (const block of newBlocks){
|
|
175
|
-
const blockHash = await block.hash();
|
|
176
|
-
const contractClassLogsInBlock = block.body.txEffects.map((txEffect, txIndex)=>[
|
|
177
|
-
numToUInt32BE(txIndex),
|
|
178
|
-
txEffect.txHash.toBuffer(),
|
|
179
|
-
numToUInt32BE(txEffect.contractClassLogs.length),
|
|
180
|
-
txEffect.contractClassLogs.map((log)=>log.toBuffer())
|
|
181
|
-
].flat()).flat();
|
|
182
|
-
await this.#contractClassLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, contractClassLogsInBlock));
|
|
183
|
-
}
|
|
107
|
+
return true;
|
|
108
|
+
});
|
|
184
109
|
}
|
|
185
110
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
|
|
189
|
-
*/ addLogs(blocks) {
|
|
111
|
+
* Deletes every log indexed under any of the given blocks. Secondary-index driven, so it doesn't
|
|
112
|
+
* have to range-scan the primary maps.
|
|
113
|
+
*/ deleteLogs(blocks) {
|
|
190
114
|
return this.db.transactionAsync(async ()=>{
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
115
|
+
for (const block of blocks){
|
|
116
|
+
const blockNumber = block.number;
|
|
117
|
+
const [privateKeys, publicKeys] = await Promise.all([
|
|
118
|
+
this.#privateKeysByBlock.getAsync(blockNumber),
|
|
119
|
+
this.#publicKeysByBlock.getAsync(blockNumber)
|
|
120
|
+
]);
|
|
121
|
+
if (privateKeys) {
|
|
122
|
+
for (const key of privateKeys){
|
|
123
|
+
await this.#privateLogs.delete(key);
|
|
124
|
+
}
|
|
125
|
+
await this.#privateKeysByBlock.delete(blockNumber);
|
|
126
|
+
}
|
|
127
|
+
if (publicKeys) {
|
|
128
|
+
for (const key of publicKeys){
|
|
129
|
+
await this.#publicLogs.delete(key);
|
|
130
|
+
}
|
|
131
|
+
await this.#publicKeysByBlock.delete(blockNumber);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
196
134
|
return true;
|
|
197
135
|
});
|
|
198
136
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
...data
|
|
203
|
-
]);
|
|
204
|
-
}
|
|
205
|
-
#unpackBlockHash(reader) {
|
|
206
|
-
const blockHash = reader.remainingBytes() > 0 ? reader.readObject(Fr) : undefined;
|
|
207
|
-
if (!blockHash) {
|
|
208
|
-
throw new Error('Failed to read block hash from log entry buffer');
|
|
209
|
-
}
|
|
210
|
-
return new BlockHash(blockHash);
|
|
137
|
+
/** Returns one inner array per element of `query.tags`, in input order. */ getPrivateLogsByTags(query) {
|
|
138
|
+
LogStore.#validateQuery(query);
|
|
139
|
+
return this.db.transactionAsync(()=>this.#runQuery(query, /* contractHex */ undefined));
|
|
211
140
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// Delete private logs
|
|
216
|
-
const privateKeys = await this.#privateLogKeysByBlock.getAsync(block.number) ?? [];
|
|
217
|
-
await Promise.all(privateKeys.map((tag)=>this.#privateLogsByTag.delete(tag)));
|
|
218
|
-
// Delete public logs
|
|
219
|
-
const publicKeys = await this.#publicLogKeysByBlock.getAsync(block.number) ?? [];
|
|
220
|
-
await Promise.all(publicKeys.map((key)=>this.#publicLogsByContractAndTag.delete(key)));
|
|
221
|
-
}));
|
|
222
|
-
await Promise.all(blocks.map((block)=>Promise.all([
|
|
223
|
-
this.#publicLogsByBlock.delete(block.number),
|
|
224
|
-
this.#privateLogKeysByBlock.delete(block.number),
|
|
225
|
-
this.#publicLogKeysByBlock.delete(block.number),
|
|
226
|
-
this.#contractClassLogsByBlock.delete(block.number)
|
|
227
|
-
])));
|
|
228
|
-
return true;
|
|
229
|
-
});
|
|
141
|
+
/** Returns one inner array per element of `query.tags`, in input order. */ getPublicLogsByTags(query) {
|
|
142
|
+
LogStore.#validateQuery(query);
|
|
143
|
+
return this.db.transactionAsync(()=>this.#runQuery(query, fieldHex(query.contractAddress)));
|
|
230
144
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
* @param page - The page number (0-indexed) for pagination.
|
|
236
|
-
* @param upToBlockNumber - If set, only return logs from blocks up to and including this block number.
|
|
237
|
-
* @returns An array of log arrays, one per tag. Returns at most MAX_LOGS_PER_TAG logs per tag per page. If
|
|
238
|
-
* MAX_LOGS_PER_TAG logs are returned for a tag, the caller should fetch the next page to check for more logs.
|
|
239
|
-
*/ async getPrivateLogsByTags(tags, page = 0, upToBlockNumber) {
|
|
240
|
-
const logs = await Promise.all(tags.map((tag)=>this.#privateLogsByTag.getAsync(tag.toString())));
|
|
241
|
-
const start = page * MAX_LOGS_PER_TAG;
|
|
242
|
-
const end = start + MAX_LOGS_PER_TAG;
|
|
243
|
-
return logs.map((logBuffers)=>{
|
|
244
|
-
const deserialized = logBuffers?.slice(start, end).map((buf)=>TxScopedL2Log.fromBuffer(buf)) ?? [];
|
|
245
|
-
if (upToBlockNumber !== undefined) {
|
|
246
|
-
const cutoff = deserialized.findIndex((log)=>log.blockNumber > upToBlockNumber);
|
|
247
|
-
if (cutoff !== -1) {
|
|
248
|
-
return deserialized.slice(0, cutoff);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return deserialized;
|
|
252
|
-
});
|
|
145
|
+
static #validateQuery(query) {
|
|
146
|
+
if (query.txHash !== undefined && (query.fromBlock !== undefined || query.toBlock !== undefined)) {
|
|
147
|
+
throw new Error('`txHash` is mutually exclusive with `fromBlock`/`toBlock`');
|
|
148
|
+
}
|
|
253
149
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const deserialized = logBuffers?.slice(start, end).map((buf)=>TxScopedL2Log.fromBuffer(buf)) ?? [];
|
|
272
|
-
if (upToBlockNumber !== undefined) {
|
|
273
|
-
const cutoff = deserialized.findIndex((log)=>log.blockNumber > upToBlockNumber);
|
|
274
|
-
if (cutoff !== -1) {
|
|
275
|
-
return deserialized.slice(0, cutoff);
|
|
150
|
+
async #runQuery(query, contractHex) {
|
|
151
|
+
const isPublic = contractHex !== undefined;
|
|
152
|
+
const tags = query.tags ?? [];
|
|
153
|
+
const primaryMap = isPublic ? this.#publicLogs : this.#privateLogs;
|
|
154
|
+
// referenceBlock reorg check, in-transaction, against the same db the log primary maps live on. The
|
|
155
|
+
// genesis block is a valid anchor during early sync but is synthetic and never indexed in the block
|
|
156
|
+
// store, so resolve it directly to the genesis block number rather than mistaking it for a reorg.
|
|
157
|
+
let referenceBlockNumber;
|
|
158
|
+
if (query.referenceBlock) {
|
|
159
|
+
if (query.referenceBlock.equals(this.genesisBlockHash)) {
|
|
160
|
+
referenceBlockNumber = INITIAL_L2_BLOCK_NUM - 1;
|
|
161
|
+
} else {
|
|
162
|
+
const refBlk = await this.blockStore.getBlockData({
|
|
163
|
+
hash: query.referenceBlock
|
|
164
|
+
});
|
|
165
|
+
if (!refBlk) {
|
|
166
|
+
throw new Error(`Reference block ${query.referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
276
167
|
}
|
|
168
|
+
referenceBlockNumber = refBlk.header.globalVariables.blockNumber;
|
|
277
169
|
}
|
|
278
|
-
return deserialized;
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Gets public logs based on the provided filter.
|
|
283
|
-
* @param filter - The filter to apply to the logs.
|
|
284
|
-
* @returns The requested logs.
|
|
285
|
-
*/ getPublicLogs(filter) {
|
|
286
|
-
if (filter.afterLog) {
|
|
287
|
-
return this.#filterPublicLogsBetweenBlocks(filter);
|
|
288
|
-
} else if (filter.txHash) {
|
|
289
|
-
return this.#filterPublicLogsOfTx(filter);
|
|
290
|
-
} else {
|
|
291
|
-
return this.#filterPublicLogsBetweenBlocks(filter);
|
|
292
170
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
171
|
+
// Compute the exclusive upper-block bound across `toBlock` and `referenceBlock`.
|
|
172
|
+
// `toBlock` is already exclusive; `referenceBlock` caps inclusively, so its exclusive form is +1.
|
|
173
|
+
let upperExclusive;
|
|
174
|
+
if (query.toBlock !== undefined) {
|
|
175
|
+
upperExclusive = query.toBlock;
|
|
297
176
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
logs: [],
|
|
302
|
-
maxLogsHit: false
|
|
303
|
-
};
|
|
177
|
+
if (referenceBlockNumber !== undefined) {
|
|
178
|
+
const refExclusive = referenceBlockNumber + 1;
|
|
179
|
+
upperExclusive = upperExclusive === undefined ? refExclusive : Math.min(upperExclusive, refExclusive);
|
|
304
180
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
logs: []
|
|
316
|
-
};
|
|
317
|
-
for(let i = 0; i < numLogsInTx; i++){
|
|
318
|
-
publicLogsInBlock[indexOfTx].logs.push(reader.readObject(PublicLog));
|
|
181
|
+
// Resolve txHash -> (blockNumber, txIndexInBlock) once for the whole query.
|
|
182
|
+
let txLocation;
|
|
183
|
+
if (query.txHash) {
|
|
184
|
+
const loc = await this.blockStore.getTxLocation(query.txHash);
|
|
185
|
+
if (!loc) {
|
|
186
|
+
return tags.map(()=>[]);
|
|
187
|
+
}
|
|
188
|
+
txLocation = loc;
|
|
189
|
+
if (upperExclusive !== undefined && txLocation[0] >= upperExclusive) {
|
|
190
|
+
return tags.map(()=>[]);
|
|
319
191
|
}
|
|
320
192
|
}
|
|
321
|
-
const
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
193
|
+
const fromBlock = query.fromBlock ?? INITIAL_L2_BLOCK_NUM;
|
|
194
|
+
const includeEffects = query.includeEffects === true;
|
|
195
|
+
const perTagResults = [];
|
|
196
|
+
for (const tagEntry of tags){
|
|
197
|
+
const { tagHex, afterLog } = normalizeTagEntry(tagEntry);
|
|
198
|
+
const prefix = contractHex !== undefined ? encodePublicPrefix(contractHex, tagHex) : tagHex;
|
|
199
|
+
const end = txLocation ? endOfTxRange(prefix, txLocation[0], txLocation[1]) : endOfTagRange(prefix, upperExclusive);
|
|
200
|
+
let start;
|
|
201
|
+
if (afterLog) {
|
|
202
|
+
// Cursor wins as the start; `fromBlock` is ignored (fine if the cursor sits below it). The cursor
|
|
203
|
+
// carries `(blockNumber, txIndexWithinBlock, logIndexWithinTx)`, which slot directly into the
|
|
204
|
+
// composite key — no tx-hash lookup needed.
|
|
205
|
+
start = incKey(encodeKey(prefix, afterLog.blockNumber, afterLog.txIndexWithinBlock, afterLog.logIndexWithinTx));
|
|
206
|
+
} else if (txLocation) {
|
|
207
|
+
start = encodeKey(prefix, txLocation[0], txLocation[1], 0);
|
|
208
|
+
} else {
|
|
209
|
+
start = encodeKey(prefix, fromBlock, 0, 0);
|
|
210
|
+
}
|
|
211
|
+
const limit = query.limitPerTag ?? MAX_LOGS_PER_TAG;
|
|
212
|
+
const out = [];
|
|
213
|
+
for await (const [rawKey, rawVal] of primaryMap.entriesAsync({
|
|
214
|
+
start,
|
|
215
|
+
end,
|
|
216
|
+
limit
|
|
217
|
+
})){
|
|
218
|
+
const tail = decodeKeyTail(rawKey);
|
|
219
|
+
const value = decodeValue(rawVal);
|
|
220
|
+
out.push({
|
|
221
|
+
logData: value.logData,
|
|
222
|
+
blockNumber: tail.blockNumber,
|
|
223
|
+
blockHash: value.blockHash,
|
|
224
|
+
blockTimestamp: value.blockTimestamp,
|
|
225
|
+
txHash: value.txHash,
|
|
226
|
+
txIndexWithinBlock: tail.txIndexWithinBlock,
|
|
227
|
+
logIndexWithinTx: tail.logIndexWithinTx
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
perTagResults.push(out);
|
|
337
231
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const publicLogsInBlock = [];
|
|
345
|
-
const reader = new BufferReader(logBuffer);
|
|
346
|
-
const blockHash = this.#unpackBlockHash(reader);
|
|
347
|
-
while(reader.remainingBytes() > 0){
|
|
348
|
-
const indexOfTx = reader.readNumber();
|
|
349
|
-
const txHash = reader.readObject(TxHash);
|
|
350
|
-
const numLogsInTx = reader.readNumber();
|
|
351
|
-
publicLogsInBlock[indexOfTx] = {
|
|
352
|
-
txHash,
|
|
353
|
-
logs: []
|
|
354
|
-
};
|
|
355
|
-
for(let i = 0; i < numLogsInTx; i++){
|
|
356
|
-
publicLogsInBlock[indexOfTx].logs.push(reader.readObject(PublicLog));
|
|
232
|
+
if (includeEffects) {
|
|
233
|
+
// Dedupe by txHash across the entire page so a tx with many tagged logs costs one fetch.
|
|
234
|
+
const txHashByKey = new Map();
|
|
235
|
+
for (const arr of perTagResults){
|
|
236
|
+
for (const log of arr){
|
|
237
|
+
txHashByKey.set(log.txHash.toString(), log.txHash);
|
|
357
238
|
}
|
|
358
239
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
240
|
+
const uniqueTxs = Array.from(txHashByKey.values());
|
|
241
|
+
if (uniqueTxs.length > 0) {
|
|
242
|
+
const effects = await this.blockStore.getNoteHashesAndNullifiers(uniqueTxs);
|
|
243
|
+
const byTxHash = new Map();
|
|
244
|
+
uniqueTxs.forEach((tx, i)=>byTxHash.set(tx.toString(), effects[i]));
|
|
245
|
+
for(let i = 0; i < perTagResults.length; i++){
|
|
246
|
+
perTagResults[i] = perTagResults[i].map((log)=>{
|
|
247
|
+
const [noteHashes, nullifiers] = byTxHash.get(log.txHash.toString()) ?? [
|
|
248
|
+
[],
|
|
249
|
+
[]
|
|
250
|
+
];
|
|
251
|
+
return {
|
|
252
|
+
...log,
|
|
253
|
+
noteHashes,
|
|
254
|
+
nullifiers
|
|
255
|
+
};
|
|
256
|
+
});
|
|
365
257
|
}
|
|
366
258
|
}
|
|
367
259
|
}
|
|
368
|
-
return
|
|
369
|
-
logs,
|
|
370
|
-
maxLogsHit
|
|
371
|
-
};
|
|
260
|
+
return perTagResults;
|
|
372
261
|
}
|
|
373
262
|
/**
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
} else if (filter.txHash) {
|
|
381
|
-
return this.#filterContractClassLogsOfTx(filter);
|
|
382
|
-
} else {
|
|
383
|
-
return this.#filterContractClassLogsBetweenBlocks(filter);
|
|
384
|
-
}
|
|
263
|
+
* Reads back every private log indexed for the given block via the per-block secondary index. Order
|
|
264
|
+
* matches the canonical composite-key order (`tag`, `blockNumber`, `txIndexWithinBlock`,
|
|
265
|
+
* `logIndexWithinTx`). Used by the data-store-updater test suite to verify the indexed-vs-block-body
|
|
266
|
+
* counts without depending on the removed `getPublicLogs(LogFilter)` API.
|
|
267
|
+
*/ getPrivateLogsForBlock(blockNumber) {
|
|
268
|
+
return this.db.transactionAsync(()=>this.#readBlockLogs(this.#privateKeysByBlock, this.#privateLogs, blockNumber));
|
|
385
269
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
throw new Error('Missing txHash');
|
|
389
|
-
}
|
|
390
|
-
const [blockNumber, txIndex] = await this.blockStore.getTxLocation(filter.txHash) ?? [];
|
|
391
|
-
if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
|
|
392
|
-
return {
|
|
393
|
-
logs: [],
|
|
394
|
-
maxLogsHit: false
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
const contractClassLogsBuffer = await this.#contractClassLogsByBlock.getAsync(blockNumber) ?? Buffer.alloc(0);
|
|
398
|
-
const contractClassLogsInBlock = [];
|
|
399
|
-
const reader = new BufferReader(contractClassLogsBuffer);
|
|
400
|
-
const blockHash = this.#unpackBlockHash(reader);
|
|
401
|
-
while(reader.remainingBytes() > 0){
|
|
402
|
-
const indexOfTx = reader.readNumber();
|
|
403
|
-
const txHash = reader.readObject(TxHash);
|
|
404
|
-
const numLogsInTx = reader.readNumber();
|
|
405
|
-
contractClassLogsInBlock[indexOfTx] = {
|
|
406
|
-
txHash,
|
|
407
|
-
logs: []
|
|
408
|
-
};
|
|
409
|
-
for(let i = 0; i < numLogsInTx; i++){
|
|
410
|
-
contractClassLogsInBlock[indexOfTx].logs.push(reader.readObject(ContractClassLog));
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
const txData = contractClassLogsInBlock[txIndex];
|
|
414
|
-
const logs = [];
|
|
415
|
-
const maxLogsHit = this.#accumulateContractClassLogs(logs, blockNumber, blockHash, txIndex, txData.txHash, txData.logs, filter);
|
|
416
|
-
return {
|
|
417
|
-
logs,
|
|
418
|
-
maxLogsHit
|
|
419
|
-
};
|
|
270
|
+
/** {@inheritDoc LogStore.getPrivateLogsForBlock} */ getPublicLogsForBlock(blockNumber) {
|
|
271
|
+
return this.db.transactionAsync(()=>this.#readBlockLogs(this.#publicKeysByBlock, this.#publicLogs, blockNumber));
|
|
420
272
|
}
|
|
421
|
-
async #
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return {
|
|
426
|
-
logs: [],
|
|
427
|
-
maxLogsHit: true
|
|
428
|
-
};
|
|
273
|
+
async #readBlockLogs(keysByBlock, primaryMap, blockNumber) {
|
|
274
|
+
const keys = await keysByBlock.getAsync(blockNumber);
|
|
275
|
+
if (!keys || keys.length === 0) {
|
|
276
|
+
return [];
|
|
429
277
|
}
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
})){
|
|
436
|
-
const contractClassLogsInBlock = [];
|
|
437
|
-
const reader = new BufferReader(logBuffer);
|
|
438
|
-
const blockHash = this.#unpackBlockHash(reader);
|
|
439
|
-
while(reader.remainingBytes() > 0){
|
|
440
|
-
const indexOfTx = reader.readNumber();
|
|
441
|
-
const txHash = reader.readObject(TxHash);
|
|
442
|
-
const numLogsInTx = reader.readNumber();
|
|
443
|
-
contractClassLogsInBlock[indexOfTx] = {
|
|
444
|
-
txHash,
|
|
445
|
-
logs: []
|
|
446
|
-
};
|
|
447
|
-
for(let i = 0; i < numLogsInTx; i++){
|
|
448
|
-
contractClassLogsInBlock[indexOfTx].logs.push(reader.readObject(ContractClassLog));
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.length; txIndex++){
|
|
452
|
-
const txData = contractClassLogsInBlock[txIndex];
|
|
453
|
-
maxLogsHit = this.#accumulateContractClassLogs(logs, blockNumber, blockHash, txIndex, txData.txHash, txData.logs, filter);
|
|
454
|
-
if (maxLogsHit) {
|
|
455
|
-
this.#log.debug(`Max logs hit at block ${blockNumber}`);
|
|
456
|
-
break loopOverBlocks;
|
|
457
|
-
}
|
|
278
|
+
const results = [];
|
|
279
|
+
for (const key of keys){
|
|
280
|
+
const raw = await primaryMap.getAsync(key);
|
|
281
|
+
if (!raw) {
|
|
282
|
+
continue;
|
|
458
283
|
}
|
|
284
|
+
const tail = decodeKeyTail(key);
|
|
285
|
+
const value = decodeValue(raw);
|
|
286
|
+
results.push({
|
|
287
|
+
logData: value.logData,
|
|
288
|
+
blockNumber: tail.blockNumber,
|
|
289
|
+
blockHash: value.blockHash,
|
|
290
|
+
blockTimestamp: value.blockTimestamp,
|
|
291
|
+
txHash: value.txHash,
|
|
292
|
+
txIndexWithinBlock: tail.txIndexWithinBlock,
|
|
293
|
+
logIndexWithinTx: tail.logIndexWithinTx
|
|
294
|
+
});
|
|
459
295
|
}
|
|
296
|
+
return results;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** Pulls `{ tagHex, afterLog }` out of a {@link TagQuery}, normalizing the bare-tag form. */ function normalizeTagEntry(entry) {
|
|
300
|
+
if (typeof entry === 'object' && entry !== null && 'tag' in entry) {
|
|
460
301
|
return {
|
|
461
|
-
|
|
462
|
-
|
|
302
|
+
tagHex: fieldHex(entry.tag.value),
|
|
303
|
+
afterLog: entry.afterLog
|
|
463
304
|
};
|
|
464
305
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (filter.toBlock && blockNumber >= filter.toBlock) {
|
|
470
|
-
return false;
|
|
471
|
-
}
|
|
472
|
-
if (filter.txHash && !txHash.equals(filter.txHash)) {
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
let maxLogsHit = false;
|
|
476
|
-
let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
|
|
477
|
-
for(; logIndex < txLogs.length; logIndex++){
|
|
478
|
-
const log = txLogs[logIndex];
|
|
479
|
-
if ((!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) && (!filter.tag || log.fields[0]?.equals(filter.tag))) {
|
|
480
|
-
results.push(new ExtendedPublicLog(new LogId(BlockNumber(blockNumber), blockHash, txHash, txIndex, logIndex), log));
|
|
481
|
-
if (results.length >= this.#logsMaxPageSize) {
|
|
482
|
-
maxLogsHit = true;
|
|
483
|
-
break;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
return maxLogsHit;
|
|
488
|
-
}
|
|
489
|
-
#accumulateContractClassLogs(results, blockNumber, blockHash, txIndex, txHash, txLogs, filter = {}) {
|
|
490
|
-
if (filter.fromBlock && blockNumber < filter.fromBlock) {
|
|
491
|
-
return false;
|
|
492
|
-
}
|
|
493
|
-
if (filter.toBlock && blockNumber >= filter.toBlock) {
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
if (filter.txHash && !txHash.equals(filter.txHash)) {
|
|
497
|
-
return false;
|
|
498
|
-
}
|
|
499
|
-
let maxLogsHit = false;
|
|
500
|
-
let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
|
|
501
|
-
for(; logIndex < txLogs.length; logIndex++){
|
|
502
|
-
const log = txLogs[logIndex];
|
|
503
|
-
if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
|
|
504
|
-
results.push(new ExtendedContractClassLog(new LogId(BlockNumber(blockNumber), blockHash, txHash, txIndex, logIndex), log));
|
|
505
|
-
if (results.length >= this.#logsMaxPageSize) {
|
|
506
|
-
maxLogsHit = true;
|
|
507
|
-
break;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return maxLogsHit;
|
|
512
|
-
}
|
|
306
|
+
return {
|
|
307
|
+
tagHex: fieldHex(entry.value),
|
|
308
|
+
afterLog: undefined
|
|
309
|
+
};
|
|
513
310
|
}
|