@aztec/archiver 0.74.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/archiver/archiver.js +729 -711
- package/dest/archiver/archiver_store.js +4 -2
- package/dest/archiver/archiver_store_test_suite.js +385 -224
- package/dest/archiver/config.js +9 -11
- package/dest/archiver/data_retrieval.js +78 -68
- package/dest/archiver/errors.js +1 -2
- package/dest/archiver/index.js +0 -1
- package/dest/archiver/instrumentation.js +29 -17
- package/dest/archiver/kv_archiver_store/block_store.js +118 -127
- package/dest/archiver/kv_archiver_store/contract_class_store.js +43 -37
- package/dest/archiver/kv_archiver_store/contract_instance_store.js +7 -12
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +135 -158
- package/dest/archiver/kv_archiver_store/log_store.js +271 -256
- package/dest/archiver/kv_archiver_store/message_store.js +42 -48
- package/dest/archiver/kv_archiver_store/nullifier_store.js +35 -42
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +15 -24
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +227 -231
- package/dest/archiver/structs/data_retrieval.js +5 -2
- package/dest/archiver/structs/published.js +1 -2
- package/dest/factory.js +30 -20
- package/dest/index.js +0 -1
- package/dest/rpc/index.js +5 -2
- package/dest/test/index.js +0 -1
- package/dest/test/mock_archiver.js +8 -13
- package/dest/test/mock_l1_to_l2_message_source.js +4 -4
- package/dest/test/mock_l2_block_source.js +68 -67
- package/package.json +14 -13
- package/src/archiver/data_retrieval.ts +1 -1
- package/src/archiver/index.ts +1 -1
- package/dest/archiver/archiver.d.ts +0 -186
- package/dest/archiver/archiver.d.ts.map +0 -1
- package/dest/archiver/archiver_store.d.ts +0 -217
- package/dest/archiver/archiver_store.d.ts.map +0 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
- package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
- package/dest/archiver/config.d.ts +0 -35
- package/dest/archiver/config.d.ts.map +0 -1
- package/dest/archiver/data_retrieval.d.ts +0 -71
- package/dest/archiver/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/errors.d.ts +0 -4
- package/dest/archiver/errors.d.ts.map +0 -1
- package/dest/archiver/index.d.ts +0 -8
- package/dest/archiver/index.d.ts.map +0 -1
- package/dest/archiver/instrumentation.d.ts +0 -27
- package/dest/archiver/instrumentation.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -87
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -17
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -13
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -147
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -47
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts +0 -33
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +0 -12
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +0 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -168
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
- package/dest/archiver/structs/data_retrieval.d.ts +0 -27
- package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/structs/published.d.ts +0 -11
- package/dest/archiver/structs/published.d.ts.map +0 -1
- package/dest/factory.d.ts +0 -10
- package/dest/factory.d.ts.map +0 -1
- package/dest/index.d.ts +0 -5
- package/dest/index.d.ts.map +0 -1
- package/dest/rpc/index.d.ts +0 -4
- package/dest/rpc/index.d.ts.map +0 -1
- package/dest/test/index.d.ts +0 -4
- package/dest/test/index.d.ts.map +0 -1
- package/dest/test/mock_archiver.d.ts +0 -22
- package/dest/test/mock_archiver.d.ts.map +0 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts +0 -16
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +0 -1
- package/dest/test/mock_l2_block_source.d.ts +0 -80
- package/dest/test/mock_l2_block_source.d.ts.map +0 -1
|
@@ -1,90 +1,84 @@
|
|
|
1
|
-
var _MessageStore_l1ToL2Messages, _MessageStore_l1ToL2MessageIndices, _MessageStore_lastSynchedL1Block, _MessageStore_totalMessageCount, _MessageStore_log, _MessageStore_l1ToL2MessagesSubtreeSize;
|
|
2
|
-
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
3
1
|
import { InboxLeaf } from '@aztec/circuit-types';
|
|
4
2
|
import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
|
|
5
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
4
|
/**
|
|
7
5
|
* LMDB implementation of the ArchiverDataStore interface.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
*/ export class MessageStore {
|
|
7
|
+
db;
|
|
8
|
+
#l1ToL2Messages;
|
|
9
|
+
#l1ToL2MessageIndices;
|
|
10
|
+
#lastSynchedL1Block;
|
|
11
|
+
#totalMessageCount;
|
|
12
|
+
#log;
|
|
13
|
+
#l1ToL2MessagesSubtreeSize;
|
|
14
|
+
constructor(db){
|
|
11
15
|
this.db = db;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
__classPrivateFieldSet(this, _MessageStore_l1ToL2Messages, db.openMap('archiver_l1_to_l2_messages'), "f");
|
|
19
|
-
__classPrivateFieldSet(this, _MessageStore_l1ToL2MessageIndices, db.openMap('archiver_l1_to_l2_message_indices'), "f");
|
|
20
|
-
__classPrivateFieldSet(this, _MessageStore_lastSynchedL1Block, db.openSingleton('archiver_last_l1_block_new_messages'), "f");
|
|
21
|
-
__classPrivateFieldSet(this, _MessageStore_totalMessageCount, db.openSingleton('archiver_l1_to_l2_message_count'), "f");
|
|
16
|
+
this.#log = createLogger('archiver:message_store');
|
|
17
|
+
this.#l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
|
|
18
|
+
this.#l1ToL2Messages = db.openMap('archiver_l1_to_l2_messages');
|
|
19
|
+
this.#l1ToL2MessageIndices = db.openMap('archiver_l1_to_l2_message_indices');
|
|
20
|
+
this.#lastSynchedL1Block = db.openSingleton('archiver_last_l1_block_new_messages');
|
|
21
|
+
this.#totalMessageCount = db.openSingleton('archiver_l1_to_l2_message_count');
|
|
22
22
|
}
|
|
23
23
|
async getTotalL1ToL2MessageCount() {
|
|
24
|
-
return
|
|
24
|
+
return await this.#totalMessageCount.getAsync() ?? 0n;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return __classPrivateFieldGet(this, _MessageStore_lastSynchedL1Block, "f").getAsync();
|
|
27
|
+
* Gets the last L1 block number that emitted new messages.
|
|
28
|
+
* @returns The last L1 block number processed
|
|
29
|
+
*/ getSynchedL1BlockNumber() {
|
|
30
|
+
return this.#lastSynchedL1Block.getAsync();
|
|
32
31
|
}
|
|
33
32
|
async setSynchedL1BlockNumber(l1BlockNumber) {
|
|
34
|
-
await
|
|
33
|
+
await this.#lastSynchedL1Block.set(l1BlockNumber);
|
|
35
34
|
}
|
|
36
35
|
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const lastL1BlockNumber = (await __classPrivateFieldGet(this, _MessageStore_lastSynchedL1Block, "f").getAsync()) ?? 0n;
|
|
36
|
+
* Append L1 to L2 messages to the store.
|
|
37
|
+
* @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block.
|
|
38
|
+
* @returns True if the operation is successful.
|
|
39
|
+
*/ addL1ToL2Messages(messages) {
|
|
40
|
+
return this.db.transactionAsync(async ()=>{
|
|
41
|
+
const lastL1BlockNumber = await this.#lastSynchedL1Block.getAsync() ?? 0n;
|
|
44
42
|
if (lastL1BlockNumber >= messages.lastProcessedL1BlockNumber) {
|
|
45
43
|
return false;
|
|
46
44
|
}
|
|
47
|
-
await
|
|
48
|
-
for (const message of messages.retrievedData)
|
|
45
|
+
await this.#lastSynchedL1Block.set(messages.lastProcessedL1BlockNumber);
|
|
46
|
+
for (const message of messages.retrievedData){
|
|
49
47
|
const key = `${message.index}`;
|
|
50
|
-
await
|
|
51
|
-
await
|
|
48
|
+
await this.#l1ToL2Messages.set(key, message.leaf.toBuffer());
|
|
49
|
+
await this.#l1ToL2MessageIndices.set(message.leaf.toString(), message.index);
|
|
52
50
|
}
|
|
53
51
|
const lastTotalMessageCount = await this.getTotalL1ToL2MessageCount();
|
|
54
|
-
await
|
|
52
|
+
await this.#totalMessageCount.set(lastTotalMessageCount + BigInt(messages.retrievedData.length));
|
|
55
53
|
return true;
|
|
56
54
|
});
|
|
57
55
|
}
|
|
58
56
|
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return __classPrivateFieldGet(this, _MessageStore_l1ToL2MessageIndices, "f").getAsync(l1ToL2Message.toString());
|
|
57
|
+
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
58
|
+
* @param l1ToL2Message - The L1 to L2 message.
|
|
59
|
+
* @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
|
|
60
|
+
*/ getL1ToL2MessageIndex(l1ToL2Message) {
|
|
61
|
+
return this.#l1ToL2MessageIndices.getAsync(l1ToL2Message.toString());
|
|
65
62
|
}
|
|
66
63
|
async getL1ToL2Messages(blockNumber) {
|
|
67
64
|
const messages = [];
|
|
68
65
|
let undefinedMessageFound = false;
|
|
69
66
|
const startIndex = Number(InboxLeaf.smallestIndexFromL2Block(blockNumber));
|
|
70
|
-
for
|
|
67
|
+
for(let i = startIndex; i < startIndex + this.#l1ToL2MessagesSubtreeSize; i++){
|
|
71
68
|
// This is inefficient but probably fine for now.
|
|
72
69
|
const key = `${i}`;
|
|
73
|
-
const message = await
|
|
70
|
+
const message = await this.#l1ToL2Messages.getAsync(key);
|
|
74
71
|
if (message) {
|
|
75
72
|
if (undefinedMessageFound) {
|
|
76
73
|
throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
|
|
77
74
|
}
|
|
78
75
|
messages.push(Fr.fromBuffer(message));
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
76
|
+
} else {
|
|
81
77
|
undefinedMessageFound = true;
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
// We continue iterating over messages here to verify that there are no more messages after the undefined one.
|
|
79
|
+
// --> If this was the case this would imply there is some issue with log fetching.
|
|
84
80
|
}
|
|
85
81
|
}
|
|
86
82
|
return messages;
|
|
87
83
|
}
|
|
88
84
|
}
|
|
89
|
-
_MessageStore_l1ToL2Messages = new WeakMap(), _MessageStore_l1ToL2MessageIndices = new WeakMap(), _MessageStore_lastSynchedL1Block = new WeakMap(), _MessageStore_totalMessageCount = new WeakMap(), _MessageStore_log = new WeakMap(), _MessageStore_l1ToL2MessagesSubtreeSize = new WeakMap();
|
|
90
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZV9zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcmNoaXZlci9rdl9hcmNoaXZlcl9zdG9yZS9tZXNzYWdlX3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxFQUFFLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFLckQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtJQVV2QixZQUFvQixFQUFxQjtRQUFyQixPQUFFLEdBQUYsRUFBRSxDQUFtQjtRQVR6QywrQ0FBK0M7UUFDL0MscURBQXFEO1FBQ3JELG1EQUFpRDtRQUNqRCxrREFBZ0Q7UUFFaEQsNEJBQU8sWUFBWSxDQUFDLHdCQUF3QixDQUFDLEVBQUM7UUFFOUMsa0RBQTZCLENBQUMsSUFBSSwyQkFBMkIsRUFBQztRQUc1RCx1QkFBQSxJQUFJLGdDQUFtQixFQUFFLENBQUMsT0FBTyxDQUFDLDRCQUE0QixDQUFDLE1BQUEsQ0FBQztRQUNoRSx1QkFBQSxJQUFJLHNDQUF5QixFQUFFLENBQUMsT0FBTyxDQUFDLG1DQUFtQyxDQUFDLE1BQUEsQ0FBQztRQUM3RSx1QkFBQSxJQUFJLG9DQUF1QixFQUFFLENBQUMsYUFBYSxDQUFDLHFDQUFxQyxDQUFDLE1BQUEsQ0FBQztRQUNuRix1QkFBQSxJQUFJLG1DQUFzQixFQUFFLENBQUMsYUFBYSxDQUFDLGlDQUFpQyxDQUFDLE1BQUEsQ0FBQztJQUNoRixDQUFDO0lBRUQsS0FBSyxDQUFDLDBCQUEwQjtRQUM5QixPQUFPLENBQUMsTUFBTSx1QkFBQSxJQUFJLHVDQUFtQixDQUFDLFFBQVEsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzFELENBQUM7SUFFRDs7O09BR0c7SUFDSCx1QkFBdUI7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
|
|
@@ -1,30 +1,29 @@
|
|
|
1
|
-
var _NullifierStore_nullifiersToBlockNumber, _NullifierStore_nullifiersToBlockHash, _NullifierStore_nullifiersToIndex, _NullifierStore_log;
|
|
2
|
-
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
3
1
|
import { MAX_NULLIFIERS_PER_TX } from '@aztec/circuits.js';
|
|
4
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
3
|
export class NullifierStore {
|
|
6
|
-
|
|
4
|
+
db;
|
|
5
|
+
#nullifiersToBlockNumber;
|
|
6
|
+
#nullifiersToBlockHash;
|
|
7
|
+
#nullifiersToIndex;
|
|
8
|
+
#log;
|
|
9
|
+
constructor(db){
|
|
7
10
|
this.db = db;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
__classPrivateFieldSet(this, _NullifierStore_nullifiersToBlockNumber, db.openMap('archiver_nullifiers_to_block_number'), "f");
|
|
13
|
-
__classPrivateFieldSet(this, _NullifierStore_nullifiersToBlockHash, db.openMap('archiver_nullifiers_to_block_hash'), "f");
|
|
14
|
-
__classPrivateFieldSet(this, _NullifierStore_nullifiersToIndex, db.openMap('archiver_nullifiers_to_index'), "f");
|
|
11
|
+
this.#log = createLogger('archiver:log_store');
|
|
12
|
+
this.#nullifiersToBlockNumber = db.openMap('archiver_nullifiers_to_block_number');
|
|
13
|
+
this.#nullifiersToBlockHash = db.openMap('archiver_nullifiers_to_block_hash');
|
|
14
|
+
this.#nullifiersToIndex = db.openMap('archiver_nullifiers_to_index');
|
|
15
15
|
}
|
|
16
16
|
async addNullifiers(blocks) {
|
|
17
|
-
const blockHashes = await Promise.all(blocks.map(block
|
|
18
|
-
await this.db.transactionAsync(async ()
|
|
19
|
-
await Promise.all(blocks.map((block, i)
|
|
20
|
-
const dataStartIndexForBlock = block.header.state.partial.nullifierTree.nextAvailableLeafIndex -
|
|
21
|
-
|
|
22
|
-
return Promise.all(block.body.txEffects.map((txEffects, txIndex) => {
|
|
17
|
+
const blockHashes = await Promise.all(blocks.map((block)=>block.hash()));
|
|
18
|
+
await this.db.transactionAsync(async ()=>{
|
|
19
|
+
await Promise.all(blocks.map((block, i)=>{
|
|
20
|
+
const dataStartIndexForBlock = block.header.state.partial.nullifierTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NULLIFIERS_PER_TX;
|
|
21
|
+
return Promise.all(block.body.txEffects.map((txEffects, txIndex)=>{
|
|
23
22
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NULLIFIERS_PER_TX;
|
|
24
|
-
return Promise.all(txEffects.nullifiers.map(async (nullifier, nullifierIndex)
|
|
25
|
-
await
|
|
26
|
-
await
|
|
27
|
-
await
|
|
23
|
+
return Promise.all(txEffects.nullifiers.map(async (nullifier, nullifierIndex)=>{
|
|
24
|
+
await this.#nullifiersToBlockNumber.set(nullifier.toString(), block.number);
|
|
25
|
+
await this.#nullifiersToBlockHash.set(nullifier.toString(), blockHashes[i].toString());
|
|
26
|
+
await this.#nullifiersToIndex.set(nullifier.toString(), dataStartIndexForTx + nullifierIndex);
|
|
28
27
|
}));
|
|
29
28
|
}));
|
|
30
29
|
}));
|
|
@@ -32,13 +31,13 @@ export class NullifierStore {
|
|
|
32
31
|
return true;
|
|
33
32
|
}
|
|
34
33
|
async deleteNullifiers(blocks) {
|
|
35
|
-
await this.db.transactionAsync(async ()
|
|
36
|
-
for (const block of blocks)
|
|
37
|
-
for (const nullifier of block.body.txEffects.flatMap(tx
|
|
34
|
+
await this.db.transactionAsync(async ()=>{
|
|
35
|
+
for (const block of blocks){
|
|
36
|
+
for (const nullifier of block.body.txEffects.flatMap((tx)=>tx.nullifiers)){
|
|
38
37
|
await Promise.all([
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
this.#nullifiersToBlockNumber.delete(nullifier.toString()),
|
|
39
|
+
this.#nullifiersToBlockHash.delete(nullifier.toString()),
|
|
40
|
+
this.#nullifiersToIndex.delete(nullifier.toString())
|
|
42
41
|
]);
|
|
43
42
|
}
|
|
44
43
|
}
|
|
@@ -46,35 +45,29 @@ export class NullifierStore {
|
|
|
46
45
|
return true;
|
|
47
46
|
}
|
|
48
47
|
async findNullifiersIndexesWithBlock(blockNumber, nullifiers) {
|
|
49
|
-
const asStrings = nullifiers.map(x
|
|
50
|
-
const maybeNullifiers = await Promise.all(asStrings.map(async (nullifier)
|
|
48
|
+
const asStrings = nullifiers.map((x)=>x.toString());
|
|
49
|
+
const maybeNullifiers = await Promise.all(asStrings.map(async (nullifier)=>{
|
|
51
50
|
const [data, l2BlockNumber, l2BlockHash] = await Promise.all([
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
this.#nullifiersToIndex.getAsync(nullifier),
|
|
52
|
+
this.#nullifiersToBlockNumber.getAsync(nullifier),
|
|
53
|
+
this.#nullifiersToBlockHash.getAsync(nullifier)
|
|
55
54
|
]);
|
|
56
55
|
return {
|
|
57
56
|
data,
|
|
58
57
|
l2BlockNumber,
|
|
59
|
-
l2BlockHash
|
|
58
|
+
l2BlockHash
|
|
60
59
|
};
|
|
61
60
|
}));
|
|
62
|
-
return maybeNullifiers.map(({ data, l2BlockNumber, l2BlockHash })
|
|
63
|
-
if (data === undefined ||
|
|
64
|
-
l2BlockNumber === undefined ||
|
|
65
|
-
l2BlockHash === undefined ||
|
|
66
|
-
l2BlockNumber > blockNumber) {
|
|
61
|
+
return maybeNullifiers.map(({ data, l2BlockNumber, l2BlockHash })=>{
|
|
62
|
+
if (data === undefined || l2BlockNumber === undefined || l2BlockHash === undefined || l2BlockNumber > blockNumber) {
|
|
67
63
|
return undefined;
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
64
|
+
} else {
|
|
70
65
|
return {
|
|
71
66
|
data: BigInt(data),
|
|
72
67
|
l2BlockNumber,
|
|
73
|
-
l2BlockHash
|
|
68
|
+
l2BlockHash
|
|
74
69
|
};
|
|
75
70
|
}
|
|
76
71
|
});
|
|
77
72
|
}
|
|
78
73
|
}
|
|
79
|
-
_NullifierStore_nullifiersToBlockNumber = new WeakMap(), _NullifierStore_nullifiersToBlockHash = new WeakMap(), _NullifierStore_nullifiersToIndex = new WeakMap(), _NullifierStore_log = new WeakMap();
|
|
80
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVsbGlmaWVyX3N0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FyY2hpdmVyL2t2X2FyY2hpdmVyX3N0b3JlL251bGxpZmllcl9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLE9BQU8sRUFBVyxxQkFBcUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUdyRCxNQUFNLE9BQU8sY0FBYztJQU16QixZQUFvQixFQUFxQjtRQUFyQixPQUFFLEdBQUYsRUFBRSxDQUFtQjtRQUx6QywwREFBd0Q7UUFDeEQsd0RBQXNEO1FBQ3RELG9EQUFrRDtRQUNsRCw4QkFBTyxZQUFZLENBQUMsb0JBQW9CLENBQUMsRUFBQztRQUd4Qyx1QkFBQSxJQUFJLDJDQUE0QixFQUFFLENBQUMsT0FBTyxDQUFDLHFDQUFxQyxDQUFDLE1BQUEsQ0FBQztRQUNsRix1QkFBQSxJQUFJLHlDQUEwQixFQUFFLENBQUMsT0FBTyxDQUFDLG1DQUFtQyxDQUFDLE1BQUEsQ0FBQztRQUM5RSx1QkFBQSxJQUFJLHFDQUFzQixFQUFFLENBQUMsT0FBTyxDQUFDLDhCQUE4QixDQUFDLE1BQUEsQ0FBQztJQUN2RSxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FBQyxNQUFpQjtRQUNuQyxNQUFNLFdBQVcsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDekUsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLEtBQUssSUFBSSxFQUFFO1lBQ3hDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDZixNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN0QixNQUFNLHNC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
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
var _L1ToL2MessageStore_l1ToL2MessagesSubtreeSize;
|
|
2
|
-
import { __classPrivateFieldGet } from "tslib";
|
|
3
1
|
import { InboxLeaf } from '@aztec/circuit-types';
|
|
4
2
|
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants';
|
|
5
3
|
/**
|
|
6
4
|
* A simple in-memory implementation of an L1 to L2 message store.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.store = new Map();
|
|
14
|
-
_L1ToL2MessageStore_l1ToL2MessagesSubtreeSize.set(this, 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT);
|
|
15
|
-
}
|
|
5
|
+
*/ export class L1ToL2MessageStore {
|
|
6
|
+
/**
|
|
7
|
+
* A map pointing from a key in a "messageIndex" format to the corresponding L1 to L2 message hash.
|
|
8
|
+
*/ store = new Map();
|
|
9
|
+
#l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
|
|
10
|
+
constructor(){}
|
|
16
11
|
getTotalL1ToL2MessageCount() {
|
|
17
12
|
return BigInt(this.store.size);
|
|
18
13
|
}
|
|
@@ -23,7 +18,7 @@ export class L1ToL2MessageStore {
|
|
|
23
18
|
const messages = [];
|
|
24
19
|
let undefinedMessageFound = false;
|
|
25
20
|
const startIndex = Number(InboxLeaf.smallestIndexFromL2Block(blockNumber));
|
|
26
|
-
for
|
|
21
|
+
for(let i = startIndex; i < startIndex + this.#l1ToL2MessagesSubtreeSize; i++){
|
|
27
22
|
// This is inefficient but probably fine for now.
|
|
28
23
|
const message = this.store.get(`${i}`);
|
|
29
24
|
if (message) {
|
|
@@ -31,22 +26,20 @@ export class L1ToL2MessageStore {
|
|
|
31
26
|
throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
|
|
32
27
|
}
|
|
33
28
|
messages.push(message);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
29
|
+
} else {
|
|
36
30
|
undefinedMessageFound = true;
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
// We continue iterating over messages here to verify that there are no more messages after the undefined one.
|
|
32
|
+
// --> If this was the case this would imply there is some issue with log fetching.
|
|
39
33
|
}
|
|
40
34
|
}
|
|
41
35
|
return messages;
|
|
42
36
|
}
|
|
43
37
|
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
for (const [key, message] of this.store.entries()) {
|
|
38
|
+
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
39
|
+
* @param l1ToL2Message - The L1 to L2 message.
|
|
40
|
+
* @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
|
|
41
|
+
*/ getMessageIndex(l1ToL2Message) {
|
|
42
|
+
for (const [key, message] of this.store.entries()){
|
|
50
43
|
if (message.equals(l1ToL2Message)) {
|
|
51
44
|
return BigInt(key);
|
|
52
45
|
}
|
|
@@ -54,5 +47,3 @@ export class L1ToL2MessageStore {
|
|
|
54
47
|
return undefined;
|
|
55
48
|
}
|
|
56
49
|
}
|
|
57
|
-
_L1ToL2MessageStore_l1ToL2MessagesSubtreeSize = new WeakMap();
|
|
58
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibDFfdG9fbDJfbWVzc2FnZV9zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcmNoaXZlci9tZW1vcnlfYXJjaGl2ZXJfc3RvcmUvbDFfdG9fbDJfbWVzc2FnZV9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNqRCxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUczRTs7R0FFRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFRN0I7UUFQQTs7V0FFRztRQUNPLFVBQUssR0FBb0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUU3Qyx3REFBNkIsQ0FBQyxJQUFJLDJCQUEyQixFQUFDO0lBRS9DLENBQUM7SUFFaEIsMEJBQTBCO1FBQ3hCLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVELFVBQVUsQ0FBQyxPQUFrQjtRQUMzQixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVELFdBQVcsQ0FBQyxXQUFtQjtRQUM3QixNQUFNLFFBQVEsR0FBUyxFQUFFLENBQUM7UUFDMUIsSUFBSSxxQkFBcUIsR0FBRyxLQUFLLENBQUM7UUFDbEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBRTNFLEtBQUssSUFBSSxDQUFDLEdBQUcsVUFBVSxFQUFFLENBQUMsR0FBRyxVQUFVLEdBQUcsdUJBQUEsSUFBSSxxREFBMkIsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQy9FLGlEQUFpRDtZQUNqRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDdkMsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixJQUFJLHFCQUFxQixFQUFFLENBQUM7b0JBQzFCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBQ3hFLENBQUM7Z0JBQ0QsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN6QixDQUFDO2lCQUFNLENBQUM7Z0JBQ04scUJBQXFCLEdBQUcsSUFBSSxDQUFDO2dCQUM3Qiw4R0FBOEc7Z0JBQzlHLG1GQUFtRjtZQUNyRixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsZUFBZSxDQUFDLGFBQWlCO1FBQy9CLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDbEQsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7Z0JBQ2xDLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3JCLENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztDQUNGIn0=
|