@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,41 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
var _MemoryArchiverStore_instances, _MemoryArchiverStore_log, _MemoryArchiverStore_storeTaggedLogsFromPrivate, _MemoryArchiverStore_storeTaggedLogsFromPublic;
|
|
2
|
+
import { __classPrivateFieldGet } from "tslib";
|
|
3
|
+
import { ExtendedPublicLog, ExtendedUnencryptedL2Log, L2BlockHash, LogId, TxReceipt, TxScopedL2Log, wrapInBlock, } from '@aztec/circuit-types';
|
|
4
|
+
import { Fr, INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS, } from '@aztec/circuits.js';
|
|
3
5
|
import { FunctionSelector } from '@aztec/foundation/abi';
|
|
4
6
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
7
|
import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
6
8
|
/**
|
|
7
9
|
* Simple, in-memory implementation of an archiver data store.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* An array containing all the tx effects in the L2 blocks that have been fetched so far.
|
|
15
|
-
*/ txEffects;
|
|
16
|
-
taggedLogs;
|
|
17
|
-
logTagsPerBlock;
|
|
18
|
-
privateLogsPerBlock;
|
|
19
|
-
publicLogsPerBlock;
|
|
20
|
-
contractClassLogsPerBlock;
|
|
21
|
-
blockScopedNullifiers;
|
|
22
|
-
/**
|
|
23
|
-
* Contains all L1 to L2 messages.
|
|
24
|
-
*/ l1ToL2Messages;
|
|
25
|
-
contractClasses;
|
|
26
|
-
bytecodeCommitments;
|
|
27
|
-
privateFunctions;
|
|
28
|
-
unconstrainedFunctions;
|
|
29
|
-
contractInstances;
|
|
30
|
-
lastL1BlockNewBlocks;
|
|
31
|
-
lastL1BlockNewMessages;
|
|
32
|
-
lastProvenL2BlockNumber;
|
|
33
|
-
lastProvenL2EpochNumber;
|
|
34
|
-
functionNames;
|
|
35
|
-
#log;
|
|
36
|
-
constructor(/** The max number of logs that can be obtained in 1 "getPublicLogs" call. */ maxLogs){
|
|
10
|
+
*/
|
|
11
|
+
export class MemoryArchiverStore {
|
|
12
|
+
constructor(
|
|
13
|
+
/** The max number of logs that can be obtained in 1 "getPublicLogs" call. */
|
|
14
|
+
maxLogs) {
|
|
15
|
+
_MemoryArchiverStore_instances.add(this);
|
|
37
16
|
this.maxLogs = maxLogs;
|
|
17
|
+
/**
|
|
18
|
+
* An array containing all the L2 blocks that have been fetched so far.
|
|
19
|
+
*/
|
|
38
20
|
this.l2Blocks = [];
|
|
21
|
+
/**
|
|
22
|
+
* An array containing all the tx effects in the L2 blocks that have been fetched so far.
|
|
23
|
+
*/
|
|
39
24
|
this.txEffects = [];
|
|
40
25
|
this.taggedLogs = new Map();
|
|
41
26
|
this.logTagsPerBlock = new Map();
|
|
@@ -43,6 +28,9 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
43
28
|
this.publicLogsPerBlock = new Map();
|
|
44
29
|
this.contractClassLogsPerBlock = new Map();
|
|
45
30
|
this.blockScopedNullifiers = new Map();
|
|
31
|
+
/**
|
|
32
|
+
* Contains all L1 to L2 messages.
|
|
33
|
+
*/
|
|
46
34
|
this.l1ToL2Messages = new L1ToL2MessageStore();
|
|
47
35
|
this.contractClasses = new Map();
|
|
48
36
|
this.bytecodeCommitments = new Map();
|
|
@@ -54,18 +42,18 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
54
42
|
this.lastProvenL2BlockNumber = 0;
|
|
55
43
|
this.lastProvenL2EpochNumber = 0;
|
|
56
44
|
this.functionNames = new Map();
|
|
57
|
-
this
|
|
45
|
+
_MemoryArchiverStore_log.set(this, createLogger('archiver:data-store'));
|
|
58
46
|
}
|
|
59
47
|
getContractClass(id) {
|
|
60
48
|
const contractClass = this.contractClasses.get(id.toString());
|
|
61
49
|
return Promise.resolve(contractClass && {
|
|
62
50
|
...contractClass,
|
|
63
51
|
privateFunctions: this.privateFunctions.get(id.toString()) ?? [],
|
|
64
|
-
unconstrainedFunctions: this.unconstrainedFunctions.get(id.toString()) ?? []
|
|
52
|
+
unconstrainedFunctions: this.unconstrainedFunctions.get(id.toString()) ?? [],
|
|
65
53
|
});
|
|
66
54
|
}
|
|
67
55
|
getContractClassIds() {
|
|
68
|
-
return Promise.resolve(Array.from(this.contractClasses.keys()).map(
|
|
56
|
+
return Promise.resolve(Array.from(this.contractClasses.keys()).map(key => Fr.fromHexString(key)));
|
|
69
57
|
}
|
|
70
58
|
getContractInstance(address) {
|
|
71
59
|
return Promise.resolve(this.contractInstances.get(address.toString()));
|
|
@@ -78,23 +66,23 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
78
66
|
const unconstrainedFunctions = this.unconstrainedFunctions.get(contractClassId.toString()) ?? [];
|
|
79
67
|
const updatedPrivateFunctions = [
|
|
80
68
|
...privateFunctions,
|
|
81
|
-
...newPrivateFunctions.filter(
|
|
69
|
+
...newPrivateFunctions.filter(newFn => !privateFunctions.find(f => f.selector.equals(newFn.selector))),
|
|
82
70
|
];
|
|
83
71
|
const updatedUnconstrainedFunctions = [
|
|
84
72
|
...unconstrainedFunctions,
|
|
85
|
-
...newUnconstrainedFunctions.filter(
|
|
73
|
+
...newUnconstrainedFunctions.filter(newFn => !unconstrainedFunctions.find(f => f.selector.equals(newFn.selector))),
|
|
86
74
|
];
|
|
87
75
|
this.privateFunctions.set(contractClassId.toString(), updatedPrivateFunctions);
|
|
88
76
|
this.unconstrainedFunctions.set(contractClassId.toString(), updatedUnconstrainedFunctions);
|
|
89
77
|
return Promise.resolve(true);
|
|
90
78
|
}
|
|
91
79
|
addContractClasses(data, bytecodeCommitments, blockNumber) {
|
|
92
|
-
for(let i = 0; i < data.length; i++){
|
|
80
|
+
for (let i = 0; i < data.length; i++) {
|
|
93
81
|
const contractClass = data[i];
|
|
94
82
|
if (!this.contractClasses.has(contractClass.id.toString())) {
|
|
95
83
|
this.contractClasses.set(contractClass.id.toString(), {
|
|
96
84
|
...contractClass,
|
|
97
|
-
l2BlockNumber: blockNumber
|
|
85
|
+
l2BlockNumber: blockNumber,
|
|
98
86
|
});
|
|
99
87
|
}
|
|
100
88
|
if (!this.bytecodeCommitments.has(contractClass.id.toString())) {
|
|
@@ -104,7 +92,7 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
104
92
|
return Promise.resolve(true);
|
|
105
93
|
}
|
|
106
94
|
deleteContractClasses(data, blockNumber) {
|
|
107
|
-
for (const contractClass of data){
|
|
95
|
+
for (const contractClass of data) {
|
|
108
96
|
const restored = this.contractClasses.get(contractClass.id.toString());
|
|
109
97
|
if (restored && restored.l2BlockNumber >= blockNumber) {
|
|
110
98
|
this.contractClasses.delete(contractClass.id.toString());
|
|
@@ -114,138 +102,78 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
114
102
|
return Promise.resolve(true);
|
|
115
103
|
}
|
|
116
104
|
addContractInstances(data, _blockNumber) {
|
|
117
|
-
for (const contractInstance of data){
|
|
105
|
+
for (const contractInstance of data) {
|
|
118
106
|
this.contractInstances.set(contractInstance.address.toString(), contractInstance);
|
|
119
107
|
}
|
|
120
108
|
return Promise.resolve(true);
|
|
121
109
|
}
|
|
122
110
|
deleteContractInstances(data, _blockNumber) {
|
|
123
|
-
for (const contractInstance of data){
|
|
111
|
+
for (const contractInstance of data) {
|
|
124
112
|
this.contractInstances.delete(contractInstance.address.toString());
|
|
125
113
|
}
|
|
126
114
|
return Promise.resolve(true);
|
|
127
115
|
}
|
|
128
116
|
/**
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
117
|
+
* Append new blocks to the store's list.
|
|
118
|
+
* @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
|
|
119
|
+
* @returns True if the operation is successful.
|
|
120
|
+
*/
|
|
121
|
+
async addBlocks(blocks) {
|
|
133
122
|
if (blocks.length === 0) {
|
|
134
123
|
return Promise.resolve(true);
|
|
135
124
|
}
|
|
136
125
|
this.lastL1BlockNewBlocks = blocks[blocks.length - 1].l1.blockNumber;
|
|
137
126
|
this.l2Blocks.push(...blocks);
|
|
138
|
-
const flatTxEffects = blocks.flatMap(
|
|
139
|
-
|
|
140
|
-
txEffect
|
|
141
|
-
})));
|
|
142
|
-
const wrappedTxEffects = await Promise.all(flatTxEffects.map((flatTxEffect)=>wrapInBlock(flatTxEffect.txEffect, flatTxEffect.block.data)));
|
|
127
|
+
const flatTxEffects = blocks.flatMap(b => b.data.body.txEffects.map(txEffect => ({ block: b, txEffect })));
|
|
128
|
+
const wrappedTxEffects = await Promise.all(flatTxEffects.map(flatTxEffect => wrapInBlock(flatTxEffect.txEffect, flatTxEffect.block.data)));
|
|
143
129
|
this.txEffects.push(...wrappedTxEffects);
|
|
144
130
|
return Promise.resolve(true);
|
|
145
131
|
}
|
|
146
132
|
/**
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
133
|
+
* Unwinds blocks from the database
|
|
134
|
+
* @param from - The tip of the chain, passed for verification purposes,
|
|
135
|
+
* ensuring that we don't end up deleting something we did not intend
|
|
136
|
+
* @param blocksToUnwind - The number of blocks we are to unwind
|
|
137
|
+
* @returns True if the operation is successful
|
|
138
|
+
*/
|
|
139
|
+
async unwindBlocks(from, blocksToUnwind) {
|
|
153
140
|
const last = await this.getSynchedL2BlockNumber();
|
|
154
141
|
if (from != last) {
|
|
155
142
|
throw new Error(`Can only unwind blocks from the tip (requested ${from} but current tip is ${last})`);
|
|
156
143
|
}
|
|
157
144
|
const stopAt = from - blocksToUnwind;
|
|
158
|
-
while(await this.getSynchedL2BlockNumber() > stopAt){
|
|
145
|
+
while ((await this.getSynchedL2BlockNumber()) > stopAt) {
|
|
159
146
|
const block = this.l2Blocks.pop();
|
|
160
147
|
if (block == undefined) {
|
|
161
148
|
break;
|
|
162
149
|
}
|
|
163
|
-
block.data.body.txEffects.forEach(()=>this.txEffects.pop());
|
|
150
|
+
block.data.body.txEffects.forEach(() => this.txEffects.pop());
|
|
164
151
|
}
|
|
165
152
|
return Promise.resolve(true);
|
|
166
153
|
}
|
|
167
|
-
#storeTaggedLogsFromPrivate(block) {
|
|
168
|
-
const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
169
|
-
block.body.txEffects.forEach((txEffect, txIndex)=>{
|
|
170
|
-
const txHash = txEffect.txHash;
|
|
171
|
-
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
172
|
-
txEffect.privateLogs.forEach((log)=>{
|
|
173
|
-
const tag = log.fields[0];
|
|
174
|
-
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
175
|
-
this.taggedLogs.set(tag.toString(), [
|
|
176
|
-
...currentLogs,
|
|
177
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer())
|
|
178
|
-
]);
|
|
179
|
-
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
180
|
-
this.logTagsPerBlock.set(block.number, [
|
|
181
|
-
...currentTagsInBlock,
|
|
182
|
-
tag
|
|
183
|
-
]);
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
#storeTaggedLogsFromPublic(block) {
|
|
188
|
-
const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
189
|
-
block.body.txEffects.forEach((txEffect, txIndex)=>{
|
|
190
|
-
const txHash = txEffect.txHash;
|
|
191
|
-
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
192
|
-
txEffect.publicLogs.forEach((log)=>{
|
|
193
|
-
// Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
|
|
194
|
-
// See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
|
|
195
|
-
// 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.
|
|
196
|
-
const firstFieldBuf = log.log[0].toBuffer();
|
|
197
|
-
if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
|
|
198
|
-
// See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
|
|
199
|
-
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
|
|
200
|
-
this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
// Check that the length values line up with the log contents
|
|
204
|
-
const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
|
|
205
|
-
const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
|
|
206
|
-
// Add 1 for the first field holding lengths
|
|
207
|
-
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
208
|
-
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
209
|
-
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find((f)=>!f.isZero())) {
|
|
210
|
-
this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
// The first elt stores lengths => tag is in fields[1]
|
|
214
|
-
const tag = log.log[1];
|
|
215
|
-
this.#log.verbose(`Storing public tagged log with tag ${tag.toString()} in block ${block.number}`);
|
|
216
|
-
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
217
|
-
this.taggedLogs.set(tag.toString(), [
|
|
218
|
-
...currentLogs,
|
|
219
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.toBuffer())
|
|
220
|
-
]);
|
|
221
|
-
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
222
|
-
this.logTagsPerBlock.set(block.number, [
|
|
223
|
-
...currentTagsInBlock,
|
|
224
|
-
tag
|
|
225
|
-
]);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
154
|
/**
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this
|
|
237
|
-
this.
|
|
238
|
-
this.
|
|
155
|
+
* Append new logs to the store's list.
|
|
156
|
+
* @param block - The block for which to add the logs.
|
|
157
|
+
* @returns True if the operation is successful.
|
|
158
|
+
*/
|
|
159
|
+
addLogs(blocks) {
|
|
160
|
+
blocks.forEach(block => {
|
|
161
|
+
__classPrivateFieldGet(this, _MemoryArchiverStore_instances, "m", _MemoryArchiverStore_storeTaggedLogsFromPrivate).call(this, block);
|
|
162
|
+
__classPrivateFieldGet(this, _MemoryArchiverStore_instances, "m", _MemoryArchiverStore_storeTaggedLogsFromPublic).call(this, block);
|
|
163
|
+
this.privateLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.privateLogs).flat());
|
|
164
|
+
this.publicLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.publicLogs).flat());
|
|
239
165
|
this.contractClassLogsPerBlock.set(block.number, block.body.contractClassLogs);
|
|
240
166
|
});
|
|
241
167
|
return Promise.resolve(true);
|
|
242
168
|
}
|
|
243
169
|
deleteLogs(blocks) {
|
|
244
|
-
const tagsToDelete = blocks.flatMap(
|
|
245
|
-
tagsToDelete
|
|
170
|
+
const tagsToDelete = blocks.flatMap(block => this.logTagsPerBlock.get(block.number));
|
|
171
|
+
tagsToDelete
|
|
172
|
+
.filter(tag => tag != undefined)
|
|
173
|
+
.forEach(tag => {
|
|
246
174
|
this.taggedLogs.delete(tag.toString());
|
|
247
175
|
});
|
|
248
|
-
blocks.forEach(
|
|
176
|
+
blocks.forEach(block => {
|
|
249
177
|
this.privateLogsPerBlock.delete(block.number);
|
|
250
178
|
this.publicLogsPerBlock.delete(block.number);
|
|
251
179
|
this.logTagsPerBlock.delete(block.number);
|
|
@@ -254,16 +182,17 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
254
182
|
return Promise.resolve(true);
|
|
255
183
|
}
|
|
256
184
|
async addNullifiers(blocks) {
|
|
257
|
-
await Promise.all(blocks.map(async (block)=>{
|
|
258
|
-
const dataStartIndexForBlock = block.header.state.partial.nullifierTree.nextAvailableLeafIndex -
|
|
185
|
+
await Promise.all(blocks.map(async (block) => {
|
|
186
|
+
const dataStartIndexForBlock = block.header.state.partial.nullifierTree.nextAvailableLeafIndex -
|
|
187
|
+
block.body.txEffects.length * MAX_NULLIFIERS_PER_TX;
|
|
259
188
|
const blockHash = await block.hash();
|
|
260
|
-
block.body.txEffects.forEach((txEffects, txIndex)=>{
|
|
189
|
+
block.body.txEffects.forEach((txEffects, txIndex) => {
|
|
261
190
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NULLIFIERS_PER_TX;
|
|
262
|
-
txEffects.nullifiers.forEach((nullifier, nullifierIndex)=>{
|
|
191
|
+
txEffects.nullifiers.forEach((nullifier, nullifierIndex) => {
|
|
263
192
|
this.blockScopedNullifiers.set(nullifier.toString(), {
|
|
264
193
|
index: BigInt(dataStartIndexForTx + nullifierIndex),
|
|
265
194
|
blockNumber: block.number,
|
|
266
|
-
blockHash: blockHash.toString()
|
|
195
|
+
blockHash: blockHash.toString(),
|
|
267
196
|
});
|
|
268
197
|
});
|
|
269
198
|
});
|
|
@@ -271,9 +200,9 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
271
200
|
return Promise.resolve(true);
|
|
272
201
|
}
|
|
273
202
|
deleteNullifiers(blocks) {
|
|
274
|
-
blocks.forEach(
|
|
275
|
-
block.body.txEffects.forEach(
|
|
276
|
-
txEffect.nullifiers.forEach(
|
|
203
|
+
blocks.forEach(block => {
|
|
204
|
+
block.body.txEffects.forEach(txEffect => {
|
|
205
|
+
txEffect.nullifiers.forEach(nullifier => {
|
|
277
206
|
this.blockScopedNullifiers.delete(nullifier.toString());
|
|
278
207
|
});
|
|
279
208
|
});
|
|
@@ -281,13 +210,13 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
281
210
|
return Promise.resolve(true);
|
|
282
211
|
}
|
|
283
212
|
findNullifiersIndexesWithBlock(blockNumber, nullifiers) {
|
|
284
|
-
const blockScopedNullifiers = nullifiers.map(
|
|
213
|
+
const blockScopedNullifiers = nullifiers.map(nullifier => {
|
|
285
214
|
const nullifierData = this.blockScopedNullifiers.get(nullifier.toString());
|
|
286
215
|
if (nullifierData !== undefined && nullifierData.blockNumber <= blockNumber) {
|
|
287
216
|
return {
|
|
288
217
|
data: nullifierData.index,
|
|
289
218
|
l2BlockHash: nullifierData.blockHash,
|
|
290
|
-
l2BlockNumber: nullifierData.blockNumber
|
|
219
|
+
l2BlockNumber: nullifierData.blockNumber,
|
|
291
220
|
};
|
|
292
221
|
}
|
|
293
222
|
return undefined;
|
|
@@ -298,33 +227,37 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
298
227
|
return Promise.resolve(this.l1ToL2Messages.getTotalL1ToL2MessageCount());
|
|
299
228
|
}
|
|
300
229
|
/**
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
230
|
+
* Append L1 to L2 messages to the store.
|
|
231
|
+
* @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block.
|
|
232
|
+
* @returns True if the operation is successful.
|
|
233
|
+
*/
|
|
234
|
+
addL1ToL2Messages(messages) {
|
|
235
|
+
if (typeof this.lastL1BlockNewMessages === 'bigint' &&
|
|
236
|
+
messages.lastProcessedL1BlockNumber <= this.lastL1BlockNewMessages) {
|
|
306
237
|
return Promise.resolve(false);
|
|
307
238
|
}
|
|
308
239
|
this.lastL1BlockNewMessages = messages.lastProcessedL1BlockNumber;
|
|
309
|
-
for (const message of messages.retrievedData){
|
|
240
|
+
for (const message of messages.retrievedData) {
|
|
310
241
|
this.l1ToL2Messages.addMessage(message);
|
|
311
242
|
}
|
|
312
243
|
return Promise.resolve(true);
|
|
313
244
|
}
|
|
314
245
|
/**
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
246
|
+
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
247
|
+
* @param l1ToL2Message - The L1 to L2 message.
|
|
248
|
+
* @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
|
|
249
|
+
*/
|
|
250
|
+
getL1ToL2MessageIndex(l1ToL2Message) {
|
|
319
251
|
return Promise.resolve(this.l1ToL2Messages.getMessageIndex(l1ToL2Message));
|
|
320
252
|
}
|
|
321
253
|
/**
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
254
|
+
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
255
|
+
* @param from - Number of the first block to return (inclusive).
|
|
256
|
+
* @param limit - The number of blocks to return.
|
|
257
|
+
* @returns The requested L2 blocks.
|
|
258
|
+
* @remarks When "from" is smaller than genesis block number, blocks from the beginning are returned.
|
|
259
|
+
*/
|
|
260
|
+
getBlocks(from, limit) {
|
|
328
261
|
if (limit < 1) {
|
|
329
262
|
return Promise.reject(new Error(`Invalid limit: ${limit}`));
|
|
330
263
|
}
|
|
@@ -340,23 +273,25 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
340
273
|
}
|
|
341
274
|
async getBlockHeaders(from, limit) {
|
|
342
275
|
const blocks = await this.getBlocks(from, limit);
|
|
343
|
-
return blocks.map(
|
|
276
|
+
return blocks.map(block => block.data.header);
|
|
344
277
|
}
|
|
345
278
|
/**
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
279
|
+
* Gets a tx effect.
|
|
280
|
+
* @param txHash - The txHash of the tx effect.
|
|
281
|
+
* @returns The requested tx effect.
|
|
282
|
+
*/
|
|
283
|
+
getTxEffect(txHash) {
|
|
284
|
+
const txEffect = this.txEffects.find(tx => tx.data.txHash.equals(txHash));
|
|
351
285
|
return Promise.resolve(txEffect);
|
|
352
286
|
}
|
|
353
287
|
/**
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
288
|
+
* Gets a receipt of a settled tx.
|
|
289
|
+
* @param txHash - The hash of a tx we try to get the receipt for.
|
|
290
|
+
* @returns The requested tx receipt (or undefined if not found).
|
|
291
|
+
*/
|
|
292
|
+
async getSettledTxReceipt(txHash) {
|
|
293
|
+
for (const block of this.l2Blocks) {
|
|
294
|
+
for (const txEffect of block.data.body.txEffects) {
|
|
360
295
|
if (txEffect.txHash.equals(txHash)) {
|
|
361
296
|
return new TxReceipt(txHash, TxReceipt.statusFromRevertCode(txEffect.revertCode), '', txEffect.transactionFee.toBigInt(), L2BlockHash.fromField(await block.data.hash()), block.data.number);
|
|
362
297
|
}
|
|
@@ -365,18 +300,20 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
365
300
|
return undefined;
|
|
366
301
|
}
|
|
367
302
|
/**
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
303
|
+
* Gets L1 to L2 message (to be) included in a given block.
|
|
304
|
+
* @param blockNumber - L2 block number to get messages for.
|
|
305
|
+
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
306
|
+
*/
|
|
307
|
+
getL1ToL2Messages(blockNumber) {
|
|
372
308
|
return Promise.resolve(this.l1ToL2Messages.getMessages(blockNumber));
|
|
373
309
|
}
|
|
374
310
|
/**
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
311
|
+
* Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
|
|
312
|
+
* @param from - The block number from which to begin retrieving logs.
|
|
313
|
+
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
314
|
+
* @returns An array of private logs from the specified range of blocks.
|
|
315
|
+
*/
|
|
316
|
+
getPrivateLogs(from, limit) {
|
|
380
317
|
if (from < INITIAL_L2_BLOCK_NUM || limit < 1) {
|
|
381
318
|
return Promise.resolve([]);
|
|
382
319
|
}
|
|
@@ -387,7 +324,7 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
387
324
|
const endIndex = startIndex + limit;
|
|
388
325
|
const upper = Math.min(endIndex, this.l2Blocks.length + INITIAL_L2_BLOCK_NUM);
|
|
389
326
|
const logsInBlocks = [];
|
|
390
|
-
for(let i = startIndex; i < upper; i++){
|
|
327
|
+
for (let i = startIndex; i < upper; i++) {
|
|
391
328
|
const logs = this.privateLogsPerBlock.get(i);
|
|
392
329
|
if (logs) {
|
|
393
330
|
logsInBlocks.push(logs);
|
|
@@ -396,20 +333,22 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
396
333
|
return Promise.resolve(logsInBlocks.flat());
|
|
397
334
|
}
|
|
398
335
|
/**
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
336
|
+
* Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
|
|
337
|
+
* @param tags - The tags to filter the logs by.
|
|
338
|
+
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
339
|
+
* that tag.
|
|
340
|
+
*/
|
|
341
|
+
getLogsByTags(tags) {
|
|
342
|
+
const noteLogs = tags.map(tag => this.taggedLogs.get(tag.toString()) || []);
|
|
405
343
|
return Promise.resolve(noteLogs);
|
|
406
344
|
}
|
|
407
345
|
/**
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
346
|
+
* Gets public logs based on the provided filter.
|
|
347
|
+
* @param filter - The filter to apply to the logs.
|
|
348
|
+
* @returns The requested logs.
|
|
349
|
+
* @remarks Works by doing an intersection of all params in the filter.
|
|
350
|
+
*/
|
|
351
|
+
getPublicLogs(filter) {
|
|
413
352
|
let txHash;
|
|
414
353
|
let fromBlock = 0;
|
|
415
354
|
let toBlock = this.l2Blocks.length + INITIAL_L2_BLOCK_NUM;
|
|
@@ -421,10 +360,12 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
421
360
|
fromBlock = filter.afterLog.blockNumber;
|
|
422
361
|
txIndexInBlock = filter.afterLog.txIndex;
|
|
423
362
|
logIndexInTx = filter.afterLog.logIndex + 1; // We want to start from the next log
|
|
424
|
-
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
425
365
|
fromBlock = filter.fromBlock;
|
|
426
366
|
}
|
|
427
|
-
}
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
428
369
|
txHash = filter.txHash;
|
|
429
370
|
if (filter.fromBlock !== undefined) {
|
|
430
371
|
fromBlock = filter.fromBlock;
|
|
@@ -439,26 +380,29 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
439
380
|
if (fromBlock > this.l2Blocks.length || toBlock < fromBlock || toBlock <= 0) {
|
|
440
381
|
return Promise.resolve({
|
|
441
382
|
logs: [],
|
|
442
|
-
maxLogsHit: false
|
|
383
|
+
maxLogsHit: false,
|
|
443
384
|
});
|
|
444
385
|
}
|
|
445
386
|
const contractAddress = filter.contractAddress;
|
|
446
387
|
const logs = [];
|
|
447
|
-
for(; fromBlock < toBlock; fromBlock++){
|
|
388
|
+
for (; fromBlock < toBlock; fromBlock++) {
|
|
448
389
|
const block = this.l2Blocks[fromBlock - INITIAL_L2_BLOCK_NUM];
|
|
449
390
|
const blockLogs = this.publicLogsPerBlock.get(fromBlock);
|
|
450
391
|
if (blockLogs) {
|
|
451
|
-
for(let logIndex = 0; logIndex < blockLogs.length; logIndex++){
|
|
392
|
+
for (let logIndex = 0; logIndex < blockLogs.length; logIndex++) {
|
|
452
393
|
const log = blockLogs[logIndex];
|
|
453
|
-
const thisTxEffect = block.data.body.txEffects.filter(
|
|
394
|
+
const thisTxEffect = block.data.body.txEffects.filter(effect => effect.publicLogs.includes(log))[0];
|
|
454
395
|
const thisTxIndexInBlock = block.data.body.txEffects.indexOf(thisTxEffect);
|
|
455
396
|
const thisLogIndexInTx = thisTxEffect.publicLogs.indexOf(log);
|
|
456
|
-
if ((!txHash || thisTxEffect.txHash.equals(txHash)) &&
|
|
397
|
+
if ((!txHash || thisTxEffect.txHash.equals(txHash)) &&
|
|
398
|
+
(!contractAddress || log.contractAddress.equals(contractAddress)) &&
|
|
399
|
+
thisTxIndexInBlock >= txIndexInBlock &&
|
|
400
|
+
thisLogIndexInTx >= logIndexInTx) {
|
|
457
401
|
logs.push(new ExtendedPublicLog(new LogId(block.data.number, thisTxIndexInBlock, thisLogIndexInTx), log));
|
|
458
402
|
if (logs.length === this.maxLogs) {
|
|
459
403
|
return Promise.resolve({
|
|
460
404
|
logs,
|
|
461
|
-
maxLogsHit: true
|
|
405
|
+
maxLogsHit: true,
|
|
462
406
|
});
|
|
463
407
|
}
|
|
464
408
|
}
|
|
@@ -467,16 +411,17 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
467
411
|
}
|
|
468
412
|
return Promise.resolve({
|
|
469
413
|
logs,
|
|
470
|
-
maxLogsHit: false
|
|
414
|
+
maxLogsHit: false,
|
|
471
415
|
});
|
|
472
416
|
}
|
|
473
417
|
/**
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
418
|
+
* Gets contract class logs based on the provided filter.
|
|
419
|
+
* NB: clone of the above fn, but for contract class logs
|
|
420
|
+
* @param filter - The filter to apply to the logs.
|
|
421
|
+
* @returns The requested logs.
|
|
422
|
+
* @remarks Works by doing an intersection of all params in the filter.
|
|
423
|
+
*/
|
|
424
|
+
getContractClassLogs(filter) {
|
|
480
425
|
let txHash;
|
|
481
426
|
let fromBlock = 0;
|
|
482
427
|
let toBlock = this.l2Blocks.length + INITIAL_L2_BLOCK_NUM;
|
|
@@ -488,10 +433,12 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
488
433
|
fromBlock = filter.afterLog.blockNumber;
|
|
489
434
|
txIndexInBlock = filter.afterLog.txIndex;
|
|
490
435
|
logIndexInTx = filter.afterLog.logIndex + 1; // We want to start from the next log
|
|
491
|
-
}
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
492
438
|
fromBlock = filter.fromBlock;
|
|
493
439
|
}
|
|
494
|
-
}
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
495
442
|
txHash = filter.txHash;
|
|
496
443
|
if (filter.fromBlock !== undefined) {
|
|
497
444
|
fromBlock = filter.fromBlock;
|
|
@@ -506,25 +453,26 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
506
453
|
if (fromBlock > this.l2Blocks.length || toBlock < fromBlock || toBlock <= 0) {
|
|
507
454
|
return Promise.resolve({
|
|
508
455
|
logs: [],
|
|
509
|
-
maxLogsHit: false
|
|
456
|
+
maxLogsHit: false,
|
|
510
457
|
});
|
|
511
458
|
}
|
|
512
459
|
const contractAddress = filter.contractAddress;
|
|
513
460
|
const logs = [];
|
|
514
|
-
for(; fromBlock < toBlock; fromBlock++){
|
|
461
|
+
for (; fromBlock < toBlock; fromBlock++) {
|
|
515
462
|
const block = this.l2Blocks[fromBlock - INITIAL_L2_BLOCK_NUM];
|
|
516
463
|
const blockLogs = this.contractClassLogsPerBlock.get(fromBlock);
|
|
517
464
|
if (blockLogs) {
|
|
518
|
-
for(; txIndexInBlock < blockLogs.txLogs.length; txIndexInBlock++){
|
|
465
|
+
for (; txIndexInBlock < blockLogs.txLogs.length; txIndexInBlock++) {
|
|
519
466
|
const txLogs = blockLogs.txLogs[txIndexInBlock].unrollLogs();
|
|
520
|
-
for(; logIndexInTx < txLogs.length; logIndexInTx++){
|
|
467
|
+
for (; logIndexInTx < txLogs.length; logIndexInTx++) {
|
|
521
468
|
const log = txLogs[logIndexInTx];
|
|
522
|
-
if ((!txHash || block.data.body.txEffects[txIndexInBlock].txHash.equals(txHash)) &&
|
|
469
|
+
if ((!txHash || block.data.body.txEffects[txIndexInBlock].txHash.equals(txHash)) &&
|
|
470
|
+
(!contractAddress || log.contractAddress.equals(contractAddress))) {
|
|
523
471
|
logs.push(new ExtendedUnencryptedL2Log(new LogId(block.data.number, txIndexInBlock, logIndexInTx), log));
|
|
524
472
|
if (logs.length === this.maxLogs) {
|
|
525
473
|
return Promise.resolve({
|
|
526
474
|
logs,
|
|
527
|
-
maxLogsHit: true
|
|
475
|
+
maxLogsHit: true,
|
|
528
476
|
});
|
|
529
477
|
}
|
|
530
478
|
}
|
|
@@ -536,13 +484,14 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
536
484
|
}
|
|
537
485
|
return Promise.resolve({
|
|
538
486
|
logs,
|
|
539
|
-
maxLogsHit: false
|
|
487
|
+
maxLogsHit: false,
|
|
540
488
|
});
|
|
541
489
|
}
|
|
542
490
|
/**
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
491
|
+
* Gets the number of the latest L2 block processed.
|
|
492
|
+
* @returns The number of the latest L2 block processed.
|
|
493
|
+
*/
|
|
494
|
+
getSynchedL2BlockNumber() {
|
|
546
495
|
if (this.l2Blocks.length === 0) {
|
|
547
496
|
return Promise.resolve(INITIAL_L2_BLOCK_NUM - 1);
|
|
548
497
|
}
|
|
@@ -573,27 +522,82 @@ import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
|
573
522
|
getSynchPoint() {
|
|
574
523
|
return Promise.resolve({
|
|
575
524
|
blocksSynchedTo: this.lastL1BlockNewBlocks,
|
|
576
|
-
messagesSynchedTo: this.lastL1BlockNewMessages
|
|
525
|
+
messagesSynchedTo: this.lastL1BlockNewMessages,
|
|
577
526
|
});
|
|
578
527
|
}
|
|
579
528
|
getContractFunctionName(_address, selector) {
|
|
580
529
|
return Promise.resolve(this.functionNames.get(selector.toString()));
|
|
581
530
|
}
|
|
582
531
|
async registerContractFunctionSignatures(_address, signatures) {
|
|
583
|
-
for (const sig of signatures){
|
|
532
|
+
for (const sig of signatures) {
|
|
584
533
|
try {
|
|
585
534
|
const selector = await FunctionSelector.fromSignature(sig);
|
|
586
535
|
this.functionNames.set(selector.toString(), sig.slice(0, sig.indexOf('(')));
|
|
587
|
-
}
|
|
588
|
-
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
__classPrivateFieldGet(this, _MemoryArchiverStore_log, "f").warn(`Failed to parse signature: ${sig}. Ignoring`);
|
|
589
539
|
}
|
|
590
540
|
}
|
|
591
541
|
}
|
|
592
542
|
estimateSize() {
|
|
593
|
-
return Promise.resolve({
|
|
594
|
-
mappingSize: 0,
|
|
595
|
-
actualSize: 0,
|
|
596
|
-
numItems: 0
|
|
597
|
-
});
|
|
543
|
+
return Promise.resolve({ mappingSize: 0, actualSize: 0, numItems: 0 });
|
|
598
544
|
}
|
|
599
545
|
}
|
|
546
|
+
_MemoryArchiverStore_log = new WeakMap(), _MemoryArchiverStore_instances = new WeakSet(), _MemoryArchiverStore_storeTaggedLogsFromPrivate = function _MemoryArchiverStore_storeTaggedLogsFromPrivate(block) {
|
|
547
|
+
const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
548
|
+
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
549
|
+
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
550
|
+
const txHash = txEffect.txHash;
|
|
551
|
+
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
552
|
+
txEffect.privateLogs.forEach(log => {
|
|
553
|
+
const tag = log.fields[0];
|
|
554
|
+
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
555
|
+
this.taggedLogs.set(tag.toString(), [
|
|
556
|
+
...currentLogs,
|
|
557
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer()),
|
|
558
|
+
]);
|
|
559
|
+
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
560
|
+
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
}, _MemoryArchiverStore_storeTaggedLogsFromPublic = function _MemoryArchiverStore_storeTaggedLogsFromPublic(block) {
|
|
564
|
+
const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
565
|
+
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
566
|
+
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
567
|
+
const txHash = txEffect.txHash;
|
|
568
|
+
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
569
|
+
txEffect.publicLogs.forEach(log => {
|
|
570
|
+
// Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
|
|
571
|
+
// See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
|
|
572
|
+
// 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.
|
|
573
|
+
const firstFieldBuf = log.log[0].toBuffer();
|
|
574
|
+
if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
|
|
575
|
+
// See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
|
|
576
|
+
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
|
|
577
|
+
__classPrivateFieldGet(this, _MemoryArchiverStore_log, "f").warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
// Check that the length values line up with the log contents
|
|
581
|
+
const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
|
|
582
|
+
const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
|
|
583
|
+
// Add 1 for the first field holding lengths
|
|
584
|
+
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
585
|
+
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
586
|
+
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
587
|
+
__classPrivateFieldGet(this, _MemoryArchiverStore_log, "f").warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
// The first elt stores lengths => tag is in fields[1]
|
|
591
|
+
const tag = log.log[1];
|
|
592
|
+
__classPrivateFieldGet(this, _MemoryArchiverStore_log, "f").verbose(`Storing public tagged log with tag ${tag.toString()} in block ${block.number}`);
|
|
593
|
+
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
594
|
+
this.taggedLogs.set(tag.toString(), [
|
|
595
|
+
...currentLogs,
|
|
596
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.toBuffer()),
|
|
597
|
+
]);
|
|
598
|
+
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
599
|
+
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
};
|
|
603
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5X2FyY2hpdmVyX3N0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FyY2hpdmVyL21lbW9yeV9hcmNoaXZlcl9zdG9yZS9tZW1vcnlfYXJjaGl2ZXJfc3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxPQUFPLEVBRUwsaUJBQWlCLEVBQ2pCLHdCQUF3QixFQU14QixXQUFXLEVBRVgsS0FBSyxFQUdMLFNBQVMsRUFDVCxhQUFhLEVBQ2IsV0FBVyxHQUNaLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQU1MLEVBQUUsRUFDRixvQkFBb0IsRUFDcEIsc0JBQXNCLEVBQ3RCLHFCQUFxQixFQUNyQiw4QkFBOEIsR0FJL0IsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFLckQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFakU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sbUJBQW1CO0lBZ0Q5QjtJQUNFLDZFQUE2RTtJQUM3RCxPQUFlOztRQUFmLFlBQU8sR0FBUCxPQUFPLENBQVE7UUFqRGpDOztXQUVHO1FBQ0ssYUFBUSxHQUEyQixFQUFFLENBQUM7UUFFOUM7O1dBRUc7UUFDSyxjQUFTLEdBQXdCLEVBQUUsQ0FBQztRQUVwQyxlQUFVLEdBQWlDLElBQUksR0FBRyxFQUFFLENBQUM7UUFFckQsb0JBQWUsR0FBc0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUUvQyx3QkFBbUIsR0FBOEIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUUzRCx1QkFBa0IsR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUV6RCw4QkFBeUIsR0FBMkMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUU5RSwwQkFBcUIsR0FBMkUsSUFBSSxHQUFHLEVBQUUs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
|