@aztec/archiver 0.28.1 → 0.30.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 +13 -53
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +60 -199
- package/dest/archiver/archiver_store.d.ts +21 -67
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +60 -199
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +6 -2
- package/dest/archiver/data_retrieval.d.ts +10 -32
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +13 -67
- package/dest/archiver/eth_log_handlers.d.ts +7 -38
- package/dest/archiver/eth_log_handlers.d.ts.map +1 -1
- package/dest/archiver/eth_log_handlers.js +9 -77
- package/dest/archiver/kv_archiver_store/block_store.d.ts +5 -4
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +12 -15
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +15 -56
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +23 -87
- package/dest/archiver/kv_archiver_store/message_store.d.ts +12 -43
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +32 -141
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +8 -41
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +22 -79
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +20 -81
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +30 -143
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +3 -15
- package/dest/rpc/archiver_client.d.ts.map +1 -1
- package/dest/rpc/archiver_client.js +2 -6
- package/dest/rpc/archiver_server.d.ts.map +1 -1
- package/dest/rpc/archiver_server.js +2 -6
- package/package.json +9 -9
- package/src/archiver/archiver.ts +80 -267
- package/src/archiver/archiver_store.ts +22 -76
- package/src/archiver/archiver_store_test_suite.ts +78 -243
- package/src/archiver/config.ts +6 -0
- package/src/archiver/data_retrieval.ts +19 -101
- package/src/archiver/eth_log_handlers.ts +14 -108
- package/src/archiver/kv_archiver_store/block_store.ts +13 -14
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +23 -93
- package/src/archiver/kv_archiver_store/message_store.ts +38 -169
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +21 -90
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +33 -161
- package/src/index.ts +1 -15
- package/src/rpc/archiver_client.ts +0 -8
- package/src/rpc/archiver_server.ts +0 -8
- package/dest/archiver/kv_archiver_store/contract_store.d.ts +0 -26
- package/dest/archiver/kv_archiver_store/contract_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/contract_store.js +0 -49
- package/src/archiver/kv_archiver_store/contract_store.ts +0 -55
|
@@ -1,168 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { InboxLeaf } from '@aztec/circuit-types';
|
|
2
|
+
import {
|
|
3
|
+
Fr,
|
|
4
|
+
INITIAL_L2_BLOCK_NUM,
|
|
5
|
+
L1_TO_L2_MSG_SUBTREE_HEIGHT,
|
|
6
|
+
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
7
|
+
} from '@aztec/circuits.js';
|
|
3
8
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
|
-
import {
|
|
9
|
+
import { AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store';
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
* A message stored in the database
|
|
8
|
-
*/
|
|
9
|
-
type Message = {
|
|
10
|
-
/** The L1ToL2Message */
|
|
11
|
-
message: Buffer;
|
|
12
|
-
/** The message's fee */
|
|
13
|
-
fee: number;
|
|
14
|
-
/** Has it _ever_ been confirmed? */
|
|
15
|
-
confirmed: boolean;
|
|
16
|
-
};
|
|
11
|
+
import { DataRetrieval } from '../data_retrieval.js';
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* LMDB implementation of the ArchiverDataStore interface.
|
|
20
15
|
*/
|
|
21
16
|
export class MessageStore {
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
#pendingMessagesByFee: AztecCounter<[number, string]>;
|
|
26
|
-
#messages: AztecMap<string, Message>;
|
|
27
|
-
#lastL1BlockAddingMessages: AztecSingleton<bigint>;
|
|
28
|
-
#lastL1BlockCancellingMessages: AztecSingleton<bigint>;
|
|
17
|
+
#l1ToL2Messages: AztecMap<string, Buffer>;
|
|
18
|
+
#l1ToL2MessageIndices: AztecMap<string, bigint>;
|
|
19
|
+
#lastL1BlockMessages: AztecSingleton<bigint>;
|
|
29
20
|
|
|
30
21
|
#log = createDebugLogger('aztec:archiver:message_store');
|
|
31
22
|
|
|
32
23
|
#l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
|
|
33
24
|
|
|
34
25
|
constructor(private db: AztecKVStore) {
|
|
35
|
-
this.#
|
|
36
|
-
this.#
|
|
37
|
-
this.#
|
|
38
|
-
this.#lastL1BlockNewMessages = db.openSingleton('archiver_last_l1_block_new_messages');
|
|
39
|
-
this.#lastL1BlockAddingMessages = db.openSingleton('archiver_last_l1_block_adding_messages');
|
|
40
|
-
this.#lastL1BlockCancellingMessages = db.openSingleton('archiver_last_l1_block_cancelling_messages');
|
|
26
|
+
this.#l1ToL2Messages = db.openMap('archiver_l1_to_l2_messages');
|
|
27
|
+
this.#l1ToL2MessageIndices = db.openMap('archiver_l1_to_l2_message_indices');
|
|
28
|
+
this.#lastL1BlockMessages = db.openSingleton('archiver_last_l1_block_new_messages');
|
|
41
29
|
}
|
|
42
30
|
|
|
43
31
|
/**
|
|
44
|
-
* Gets the last L1 block number that emitted new messages
|
|
32
|
+
* Gets the last L1 block number that emitted new messages.
|
|
45
33
|
* @returns The last L1 block number processed
|
|
46
34
|
*/
|
|
47
|
-
|
|
48
|
-
return
|
|
49
|
-
newMessages: this.#lastL1BlockNewMessages.get() ?? 0n,
|
|
50
|
-
// TODO(#4492): Nuke the following when purging the old inbox
|
|
51
|
-
addedMessages: this.#lastL1BlockAddingMessages.get() ?? 0n,
|
|
52
|
-
cancelledMessages: this.#lastL1BlockCancellingMessages.get() ?? 0n,
|
|
53
|
-
};
|
|
35
|
+
getSynchedL1BlockNumber(): bigint {
|
|
36
|
+
return this.#lastL1BlockMessages.get() ?? 0n;
|
|
54
37
|
}
|
|
55
38
|
|
|
56
39
|
/**
|
|
57
|
-
* Append
|
|
58
|
-
* @param messages - The L1 to L2 messages to be added to the store.
|
|
59
|
-
* @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted.
|
|
40
|
+
* Append L1 to L2 messages to the store.
|
|
41
|
+
* @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block.
|
|
60
42
|
* @returns True if the operation is successful.
|
|
61
43
|
*/
|
|
62
|
-
|
|
44
|
+
addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean> {
|
|
63
45
|
return this.db.transaction(() => {
|
|
64
|
-
const lastL1BlockNumber = this.#
|
|
65
|
-
if (lastL1BlockNumber >=
|
|
46
|
+
const lastL1BlockNumber = this.#lastL1BlockMessages.get() ?? 0n;
|
|
47
|
+
if (lastL1BlockNumber >= messages.lastProcessedL1BlockNumber) {
|
|
66
48
|
return false;
|
|
67
49
|
}
|
|
68
50
|
|
|
69
|
-
void this.#
|
|
51
|
+
void this.#lastL1BlockMessages.set(messages.lastProcessedL1BlockNumber);
|
|
70
52
|
|
|
71
|
-
for (const message of messages) {
|
|
53
|
+
for (const message of messages.retrievedData) {
|
|
72
54
|
if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
|
|
73
55
|
throw new Error(`Message index ${message.index} out of subtree range`);
|
|
74
56
|
}
|
|
75
57
|
const key = `${message.blockNumber}-${message.index}`;
|
|
76
|
-
void this.#
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return true;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Append new pending L1 to L2 messages to the store.
|
|
85
|
-
* @param messages - The L1 to L2 messages to be added to the store.
|
|
86
|
-
* @param l1BlockNumber - The L1 block number for which to add the messages.
|
|
87
|
-
* @returns True if the operation is successful.
|
|
88
|
-
*/
|
|
89
|
-
addPendingMessages(messages: L1ToL2Message[], l1BlockNumber: bigint): Promise<boolean> {
|
|
90
|
-
return this.db.transaction(() => {
|
|
91
|
-
const lastL1BlockNumber = this.#lastL1BlockAddingMessages.get() ?? 0n;
|
|
92
|
-
if (lastL1BlockNumber >= l1BlockNumber) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
void this.#lastL1BlockAddingMessages.set(l1BlockNumber);
|
|
97
|
-
|
|
98
|
-
for (const message of messages) {
|
|
99
|
-
const entryKey = message.entryKey?.toString();
|
|
100
|
-
if (!entryKey) {
|
|
101
|
-
throw new Error('Message does not have an entry key');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
void this.#messages.setIfNotExists(entryKey, {
|
|
105
|
-
message: message.toBuffer(),
|
|
106
|
-
fee: message.fee,
|
|
107
|
-
confirmed: false,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
void this.#pendingMessagesByFee.update([message.fee, entryKey], 1);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return true;
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Remove pending L1 to L2 messages from the store (if they were cancelled).
|
|
119
|
-
* @param entryKeys - The entry keys to be removed from the store.
|
|
120
|
-
* @param l1BlockNumber - The L1 block number for which to remove the messages.
|
|
121
|
-
* @returns True if the operation is successful.
|
|
122
|
-
*/
|
|
123
|
-
cancelPendingMessages(entryKeys: Fr[], l1BlockNumber: bigint): Promise<boolean> {
|
|
124
|
-
return this.db.transaction(() => {
|
|
125
|
-
const lastL1BlockNumber = this.#lastL1BlockCancellingMessages.get() ?? 0n;
|
|
126
|
-
if (lastL1BlockNumber >= l1BlockNumber) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
void this.#lastL1BlockCancellingMessages.set(l1BlockNumber);
|
|
131
|
-
|
|
132
|
-
for (const entryKey of entryKeys) {
|
|
133
|
-
const messageCtx = this.#messages.get(entryKey.toString());
|
|
134
|
-
if (!messageCtx) {
|
|
135
|
-
throw new Error(`Message ${entryKey.toString()} not found`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
void this.#pendingMessagesByFee.update([messageCtx.fee, entryKey.toString()], -1);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return true;
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Messages that have been published in an L2 block are confirmed.
|
|
147
|
-
* Add them to the confirmed store, also remove them from the pending store.
|
|
148
|
-
* @param entryKeys - The entry keys to be removed from the store.
|
|
149
|
-
* @returns True if the operation is successful.
|
|
150
|
-
*/
|
|
151
|
-
confirmPendingMessages(entryKeys: Fr[]): Promise<boolean> {
|
|
152
|
-
return this.db.transaction(() => {
|
|
153
|
-
for (const entryKey of entryKeys) {
|
|
154
|
-
if (entryKey.equals(Fr.ZERO)) {
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const messageCtx = this.#messages.get(entryKey.toString());
|
|
159
|
-
if (!messageCtx) {
|
|
160
|
-
throw new Error(`Message ${entryKey.toString()} not found`);
|
|
161
|
-
}
|
|
162
|
-
messageCtx.confirmed = true;
|
|
58
|
+
void this.#l1ToL2Messages.setIfNotExists(key, message.leaf.toBuffer());
|
|
163
59
|
|
|
164
|
-
|
|
165
|
-
|
|
60
|
+
const indexInTheWholeTree =
|
|
61
|
+
(message.blockNumber - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) +
|
|
62
|
+
message.index;
|
|
63
|
+
void this.#l1ToL2MessageIndices.setIfNotExists(message.leaf.toString(), indexInTheWholeTree);
|
|
166
64
|
}
|
|
167
65
|
|
|
168
66
|
return true;
|
|
@@ -170,51 +68,22 @@ export class MessageStore {
|
|
|
170
68
|
}
|
|
171
69
|
|
|
172
70
|
/**
|
|
173
|
-
* Gets the
|
|
174
|
-
* @param
|
|
175
|
-
* @returns The
|
|
71
|
+
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
72
|
+
* @param l1ToL2Message - The L1 to L2 message.
|
|
73
|
+
* @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
|
|
176
74
|
*/
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
throw new Error(`Message ${entryKey.toString()} not found`);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (!messageCtx.confirmed) {
|
|
184
|
-
throw new Error(`Message ${entryKey.toString()} not confirmed`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return L1ToL2Message.fromBuffer(messageCtx.message);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee
|
|
192
|
-
* @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).
|
|
193
|
-
* @returns The requested L1 to L2 entry keys.
|
|
194
|
-
*/
|
|
195
|
-
getPendingEntryKeysByFee(limit: number): Fr[] {
|
|
196
|
-
const entryKeys: Fr[] = [];
|
|
197
|
-
|
|
198
|
-
for (const [[_, entryKey], count] of this.#pendingMessagesByFee.entries({
|
|
199
|
-
reverse: true,
|
|
200
|
-
})) {
|
|
201
|
-
// put `count` copies of this message in the result list
|
|
202
|
-
entryKeys.push(...Array(count).fill(Fr.fromString(entryKey)));
|
|
203
|
-
if (entryKeys.length >= limit) {
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return entryKeys;
|
|
75
|
+
public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
76
|
+
const index = this.#l1ToL2MessageIndices.get(l1ToL2Message.toString());
|
|
77
|
+
return Promise.resolve(index);
|
|
209
78
|
}
|
|
210
79
|
|
|
211
|
-
|
|
80
|
+
getL1ToL2Messages(blockNumber: bigint): Fr[] {
|
|
212
81
|
const messages: Fr[] = [];
|
|
213
82
|
let undefinedMessageFound = false;
|
|
214
83
|
for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
|
|
215
84
|
// This is inefficient but probably fine for now.
|
|
216
85
|
const key = `${blockNumber}-${messageIndex}`;
|
|
217
|
-
const message = this.#
|
|
86
|
+
const message = this.#l1ToL2Messages.get(key);
|
|
218
87
|
if (message) {
|
|
219
88
|
if (undefinedMessageFound) {
|
|
220
89
|
throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { InboxLeaf } from '@aztec/circuit-types';
|
|
2
|
+
import {
|
|
3
|
+
INITIAL_L2_BLOCK_NUM,
|
|
4
|
+
L1_TO_L2_MSG_SUBTREE_HEIGHT,
|
|
5
|
+
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
6
|
+
} from '@aztec/circuits.js/constants';
|
|
3
7
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
|
-
* A simple in-memory implementation of an L1 to L2 message store
|
|
7
|
-
* that handles message duplication.
|
|
8
|
-
* TODO(#4492): Clean this up
|
|
10
|
+
* A simple in-memory implementation of an L1 to L2 message store.
|
|
9
11
|
*/
|
|
10
|
-
export class
|
|
12
|
+
export class L1ToL2MessageStore {
|
|
11
13
|
/**
|
|
12
14
|
* A map containing the entry key to the corresponding L1 to L2
|
|
13
15
|
* messages (and the number of times the message has been seen).
|
|
@@ -18,7 +20,7 @@ export class NewL1ToL2MessageStore {
|
|
|
18
20
|
|
|
19
21
|
constructor() {}
|
|
20
22
|
|
|
21
|
-
addMessage(message:
|
|
23
|
+
addMessage(message: InboxLeaf) {
|
|
22
24
|
if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
|
|
23
25
|
throw new Error(`Message index ${message.index} out of subtree range`);
|
|
24
26
|
}
|
|
@@ -46,93 +48,22 @@ export class NewL1ToL2MessageStore {
|
|
|
46
48
|
}
|
|
47
49
|
return messages;
|
|
48
50
|
}
|
|
49
|
-
}
|
|
50
51
|
|
|
51
|
-
/**
|
|
52
|
-
* A simple in-memory implementation of an L1 to L2 message store
|
|
53
|
-
* that handles message duplication.
|
|
54
|
-
*/
|
|
55
|
-
export class L1ToL2MessageStore {
|
|
56
52
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
53
|
+
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
54
|
+
* @param l1ToL2Message - The L1 to L2 message.
|
|
55
|
+
* @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
|
|
59
56
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
msgAndCount.count++;
|
|
69
|
-
} else {
|
|
70
|
-
this.store.set(entryKeyBigInt, { message, count: 1 });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
getMessage(entryKey: Fr): L1ToL2Message | undefined {
|
|
75
|
-
return this.store.get(entryKey.value)?.message;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
getMessageAndCount(entryKey: Fr): L1ToL2MessageAndCount | undefined {
|
|
79
|
-
return this.store.get(entryKey.value);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Specifically for the store that will hold pending messages
|
|
85
|
-
* for removing messages or fetching multiple messages.
|
|
86
|
-
*/
|
|
87
|
-
export class PendingL1ToL2MessageStore extends L1ToL2MessageStore {
|
|
88
|
-
getEntryKeys(limit: number): Fr[] {
|
|
89
|
-
if (limit < 1) {
|
|
90
|
-
return [];
|
|
91
|
-
}
|
|
92
|
-
// fetch `limit` number of messages from the store with the highest fee.
|
|
93
|
-
// Note the store has multiple of the same message. So if a message has count 2, include both of them in the result:
|
|
94
|
-
const messages: Fr[] = [];
|
|
95
|
-
const sortedMessages = Array.from(this.store.values()).sort((a, b) => b.message.fee - a.message.fee);
|
|
96
|
-
for (const messageAndCount of sortedMessages) {
|
|
97
|
-
for (let i = 0; i < messageAndCount.count; i++) {
|
|
98
|
-
messages.push(messageAndCount.message.entryKey!);
|
|
99
|
-
if (messages.length === limit) {
|
|
100
|
-
return messages;
|
|
101
|
-
}
|
|
57
|
+
getMessageIndex(l1ToL2Message: Fr): bigint | undefined {
|
|
58
|
+
for (const [key, message] of this.store.entries()) {
|
|
59
|
+
if (message.equals(l1ToL2Message)) {
|
|
60
|
+
const [blockNumber, messageIndex] = key.split('-');
|
|
61
|
+
const indexInTheWholeTree =
|
|
62
|
+
(BigInt(blockNumber) - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) +
|
|
63
|
+
BigInt(messageIndex);
|
|
64
|
+
return indexInTheWholeTree;
|
|
102
65
|
}
|
|
103
66
|
}
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
removeMessage(entryKey: Fr) {
|
|
108
|
-
// ignore 0 - entryKey is a hash, so a 0 can probabilistically never occur. It is best to skip it.
|
|
109
|
-
if (entryKey.equals(Fr.ZERO)) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const entryKeyBigInt = entryKey.value;
|
|
114
|
-
const msgAndCount = this.store.get(entryKeyBigInt);
|
|
115
|
-
if (!msgAndCount) {
|
|
116
|
-
throw new Error(`Unable to remove message: L1 to L2 Message with key ${entryKeyBigInt} not found in store`);
|
|
117
|
-
}
|
|
118
|
-
if (msgAndCount.count > 1) {
|
|
119
|
-
msgAndCount.count--;
|
|
120
|
-
} else {
|
|
121
|
-
this.store.delete(entryKeyBigInt);
|
|
122
|
-
}
|
|
67
|
+
return undefined;
|
|
123
68
|
}
|
|
124
69
|
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Useful to keep track of the number of times a message has been seen.
|
|
128
|
-
*/
|
|
129
|
-
type L1ToL2MessageAndCount = {
|
|
130
|
-
/**
|
|
131
|
-
* The message.
|
|
132
|
-
*/
|
|
133
|
-
message: L1ToL2Message;
|
|
134
|
-
/**
|
|
135
|
-
* The number of times the message has been seen.
|
|
136
|
-
*/
|
|
137
|
-
count: number;
|
|
138
|
-
};
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Body,
|
|
3
|
-
ExtendedContractData,
|
|
4
3
|
ExtendedUnencryptedL2Log,
|
|
5
4
|
GetUnencryptedLogsResponse,
|
|
6
|
-
|
|
5
|
+
InboxLeaf,
|
|
7
6
|
L2Block,
|
|
8
7
|
L2BlockContext,
|
|
9
8
|
L2BlockL2Logs,
|
|
10
9
|
LogFilter,
|
|
11
10
|
LogId,
|
|
12
11
|
LogType,
|
|
13
|
-
NewInboxLeaf,
|
|
14
12
|
TxEffect,
|
|
15
13
|
TxHash,
|
|
16
14
|
TxReceipt,
|
|
17
15
|
TxStatus,
|
|
18
16
|
UnencryptedL2Log,
|
|
19
17
|
} from '@aztec/circuit-types';
|
|
20
|
-
import { Fr, INITIAL_L2_BLOCK_NUM
|
|
18
|
+
import { Fr, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js';
|
|
21
19
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
22
20
|
import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts';
|
|
23
21
|
|
|
24
|
-
import { ArchiverDataStore } from '../archiver_store.js';
|
|
25
|
-
import {
|
|
22
|
+
import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
|
|
23
|
+
import { DataRetrieval } from '../data_retrieval.js';
|
|
24
|
+
import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
27
|
* Simple, in-memory implementation of an archiver data store.
|
|
@@ -56,36 +55,16 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
56
55
|
private unencryptedLogsPerBlock: L2BlockL2Logs[] = [];
|
|
57
56
|
|
|
58
57
|
/**
|
|
59
|
-
*
|
|
58
|
+
* Contains all L1 to L2 messages.
|
|
60
59
|
*/
|
|
61
|
-
private
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* A mapping of contract address to extended contract data.
|
|
65
|
-
*/
|
|
66
|
-
private extendedContractData: Map<string, ExtendedContractData> = new Map();
|
|
67
|
-
|
|
68
|
-
// TODO(#4492): Nuke the other message stores
|
|
69
|
-
private newL1ToL2Messages = new NewL1ToL2MessageStore();
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Contains all the confirmed L1 to L2 messages (i.e. messages that were consumed in an L2 block)
|
|
73
|
-
* It is a map of entryKey to the corresponding L1 to L2 message and the number of times it has appeared
|
|
74
|
-
*/
|
|
75
|
-
private confirmedL1ToL2Messages: L1ToL2MessageStore = new L1ToL2MessageStore();
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Contains all the pending L1 to L2 messages (accounts for duplication of messages)
|
|
79
|
-
*/
|
|
80
|
-
private pendingL1ToL2Messages: PendingL1ToL2MessageStore = new PendingL1ToL2MessageStore();
|
|
60
|
+
private l1ToL2Messages = new L1ToL2MessageStore();
|
|
81
61
|
|
|
82
62
|
private contractClasses: Map<string, ContractClassPublic> = new Map();
|
|
83
63
|
|
|
84
64
|
private contractInstances: Map<string, ContractInstanceWithAddress> = new Map();
|
|
85
65
|
|
|
66
|
+
private lastL1BlockNewBlocks: bigint = 0n;
|
|
86
67
|
private lastL1BlockNewMessages: bigint = 0n;
|
|
87
|
-
private lastL1BlockAddedMessages: bigint = 0n;
|
|
88
|
-
private lastL1BlockCancelledMessages: bigint = 0n;
|
|
89
68
|
|
|
90
69
|
constructor(
|
|
91
70
|
/** The max number of logs that can be obtained in 1 "getUnencryptedLogs" call. */
|
|
@@ -120,12 +99,13 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
120
99
|
|
|
121
100
|
/**
|
|
122
101
|
* Append new blocks to the store's list.
|
|
123
|
-
* @param blocks - The L2 blocks to be added to the store.
|
|
124
|
-
* @returns True if the operation is successful
|
|
102
|
+
* @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
|
|
103
|
+
* @returns True if the operation is successful.
|
|
125
104
|
*/
|
|
126
|
-
public addBlocks(blocks: L2Block
|
|
127
|
-
this.
|
|
128
|
-
this.
|
|
105
|
+
public addBlocks(blocks: DataRetrieval<L2Block>): Promise<boolean> {
|
|
106
|
+
this.lastL1BlockNewBlocks = blocks.lastProcessedL1BlockNumber;
|
|
107
|
+
this.l2BlockContexts.push(...blocks.retrievedData.map(block => new L2BlockContext(block)));
|
|
108
|
+
this.txEffects.push(...blocks.retrievedData.flatMap(b => b.getTxs()));
|
|
129
109
|
return Promise.resolve(true);
|
|
130
110
|
}
|
|
131
111
|
|
|
@@ -178,97 +158,29 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
178
158
|
}
|
|
179
159
|
|
|
180
160
|
/**
|
|
181
|
-
* Append
|
|
182
|
-
* @param messages - The L1 to L2 messages to be added to the store.
|
|
183
|
-
* @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted.
|
|
161
|
+
* Append L1 to L2 messages to the store.
|
|
162
|
+
* @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block.
|
|
184
163
|
* @returns True if the operation is successful.
|
|
185
164
|
*/
|
|
186
|
-
public
|
|
187
|
-
if (
|
|
188
|
-
return Promise.resolve(false);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
this.lastL1BlockNewMessages = lastMessageL1BlockNumber;
|
|
192
|
-
for (const message of messages) {
|
|
193
|
-
this.newL1ToL2Messages.addMessage(message);
|
|
194
|
-
}
|
|
195
|
-
return Promise.resolve(true);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Append new pending L1 to L2 messages to the store.
|
|
200
|
-
* @param messages - The L1 to L2 messages to be added to the store.
|
|
201
|
-
* @param l1BlockNumber - The L1 block number for which to add the messages.
|
|
202
|
-
* @returns True if the operation is successful (always in this implementation).
|
|
203
|
-
*/
|
|
204
|
-
public addPendingL1ToL2Messages(messages: L1ToL2Message[], l1BlockNumber: bigint): Promise<boolean> {
|
|
205
|
-
if (l1BlockNumber <= this.lastL1BlockAddedMessages) {
|
|
165
|
+
public addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean> {
|
|
166
|
+
if (messages.lastProcessedL1BlockNumber <= this.lastL1BlockNewMessages) {
|
|
206
167
|
return Promise.resolve(false);
|
|
207
168
|
}
|
|
208
169
|
|
|
209
|
-
this.
|
|
210
|
-
for (const message of messages) {
|
|
211
|
-
this.
|
|
212
|
-
}
|
|
213
|
-
return Promise.resolve(true);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Remove pending L1 to L2 messages from the store (if they were cancelled).
|
|
218
|
-
* @param messages - The entry keys to be removed from the store.
|
|
219
|
-
* @param l1BlockNumber - The L1 block number for which to remove the messages.
|
|
220
|
-
* @returns True if the operation is successful (always in this implementation).
|
|
221
|
-
*/
|
|
222
|
-
public cancelPendingL1ToL2EntryKeys(messages: Fr[], l1BlockNumber: bigint): Promise<boolean> {
|
|
223
|
-
if (l1BlockNumber <= this.lastL1BlockCancelledMessages) {
|
|
224
|
-
return Promise.resolve(false);
|
|
170
|
+
this.lastL1BlockNewMessages = messages.lastProcessedL1BlockNumber;
|
|
171
|
+
for (const message of messages.retrievedData) {
|
|
172
|
+
this.l1ToL2Messages.addMessage(message);
|
|
225
173
|
}
|
|
226
|
-
|
|
227
|
-
this.lastL1BlockCancelledMessages = l1BlockNumber;
|
|
228
|
-
messages.forEach(entryKey => {
|
|
229
|
-
this.pendingL1ToL2Messages.removeMessage(entryKey);
|
|
230
|
-
});
|
|
231
|
-
return Promise.resolve(true);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Messages that have been published in an L2 block are confirmed.
|
|
236
|
-
* Add them to the confirmed store, also remove them from the pending store.
|
|
237
|
-
* @param entryKeys - The entry keys to be removed from the store.
|
|
238
|
-
* @returns True if the operation is successful (always in this implementation).
|
|
239
|
-
*/
|
|
240
|
-
public confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise<boolean> {
|
|
241
|
-
entryKeys.forEach(entryKey => {
|
|
242
|
-
if (entryKey.equals(Fr.ZERO)) {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
this.confirmedL1ToL2Messages.addMessage(entryKey, this.pendingL1ToL2Messages.getMessage(entryKey)!);
|
|
247
|
-
this.pendingL1ToL2Messages.removeMessage(entryKey);
|
|
248
|
-
});
|
|
249
174
|
return Promise.resolve(true);
|
|
250
175
|
}
|
|
251
176
|
|
|
252
177
|
/**
|
|
253
|
-
*
|
|
254
|
-
* @param
|
|
255
|
-
* @
|
|
256
|
-
* @returns True if the operation is successful (always in this implementation).
|
|
178
|
+
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
179
|
+
* @param l1ToL2Message - The L1 to L2 message.
|
|
180
|
+
* @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
|
|
257
181
|
*/
|
|
258
|
-
public
|
|
259
|
-
|
|
260
|
-
for (const contractData of data) {
|
|
261
|
-
const key = contractData.contractData.contractAddress.toString();
|
|
262
|
-
this.extendedContractData.set(key, contractData);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Add the index per block
|
|
266
|
-
if (this.extendedContractDataByBlock[blockNum]?.length) {
|
|
267
|
-
this.extendedContractDataByBlock[blockNum]?.push(...data);
|
|
268
|
-
} else {
|
|
269
|
-
this.extendedContractDataByBlock[blockNum] = [...data];
|
|
270
|
-
}
|
|
271
|
-
return Promise.resolve(true);
|
|
182
|
+
public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
183
|
+
return Promise.resolve(this.l1ToL2Messages.getMessageIndex(l1ToL2Message));
|
|
272
184
|
}
|
|
273
185
|
|
|
274
186
|
/**
|
|
@@ -322,34 +234,12 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
322
234
|
}
|
|
323
235
|
|
|
324
236
|
/**
|
|
325
|
-
* Gets
|
|
326
|
-
* @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).
|
|
327
|
-
* @returns The requested L1 to L2 entry keys.
|
|
328
|
-
*/
|
|
329
|
-
public getPendingL1ToL2EntryKeys(limit: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP): Promise<Fr[]> {
|
|
330
|
-
return Promise.resolve(this.pendingL1ToL2Messages.getEntryKeys(limit));
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Gets the confirmed L1 to L2 message corresponding to the given entry key.
|
|
335
|
-
* @param entryKey - The entry key to look up.
|
|
336
|
-
* @returns The requested L1 to L2 message or throws if not found.
|
|
337
|
-
*/
|
|
338
|
-
public getConfirmedL1ToL2Message(entryKey: Fr): Promise<L1ToL2Message> {
|
|
339
|
-
const message = this.confirmedL1ToL2Messages.getMessage(entryKey);
|
|
340
|
-
if (!message) {
|
|
341
|
-
throw new Error(`L1 to L2 Message with key ${entryKey.toString()} not found in the confirmed messages store`);
|
|
342
|
-
}
|
|
343
|
-
return Promise.resolve(message);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Gets new L1 to L2 message (to be) included in a given block.
|
|
237
|
+
* Gets L1 to L2 message (to be) included in a given block.
|
|
348
238
|
* @param blockNumber - L2 block number to get messages for.
|
|
349
239
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
350
240
|
*/
|
|
351
|
-
|
|
352
|
-
return Promise.resolve(this.
|
|
241
|
+
getL1ToL2Messages(blockNumber: bigint): Promise<Fr[]> {
|
|
242
|
+
return Promise.resolve(this.l1ToL2Messages.getMessages(blockNumber));
|
|
353
243
|
}
|
|
354
244
|
|
|
355
245
|
/**
|
|
@@ -456,39 +346,21 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
456
346
|
});
|
|
457
347
|
}
|
|
458
348
|
|
|
459
|
-
/**
|
|
460
|
-
* Get the extended contract data for this contract.
|
|
461
|
-
* TODO(palla/purge-old-contract-deploy): Delete me?
|
|
462
|
-
* @param contractAddress - The contract data address.
|
|
463
|
-
* @returns The extended contract data or undefined if not found.
|
|
464
|
-
*/
|
|
465
|
-
getExtendedContractData(contractAddress: AztecAddress): Promise<ExtendedContractData | undefined> {
|
|
466
|
-
const result = this.extendedContractData.get(contractAddress.toString());
|
|
467
|
-
return Promise.resolve(result);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
349
|
/**
|
|
471
350
|
* Gets the number of the latest L2 block processed.
|
|
472
351
|
* @returns The number of the latest L2 block processed.
|
|
473
352
|
*/
|
|
474
|
-
public
|
|
353
|
+
public getSynchedL2BlockNumber(): Promise<number> {
|
|
475
354
|
if (this.l2BlockContexts.length === 0) {
|
|
476
355
|
return Promise.resolve(INITIAL_L2_BLOCK_NUM - 1);
|
|
477
356
|
}
|
|
478
357
|
return Promise.resolve(this.l2BlockContexts[this.l2BlockContexts.length - 1].block.number);
|
|
479
358
|
}
|
|
480
359
|
|
|
481
|
-
public
|
|
482
|
-
const addedBlock = this.l2BlockContexts[this.l2BlockContexts.length - 1]?.block?.getL1BlockNumber() ?? 0n;
|
|
483
|
-
const newMessages = this.lastL1BlockNewMessages;
|
|
484
|
-
const addedMessages = this.lastL1BlockAddedMessages;
|
|
485
|
-
const cancelledMessages = this.lastL1BlockCancelledMessages;
|
|
486
|
-
|
|
360
|
+
public getSynchedL1BlockNumbers(): Promise<ArchiverL1SynchPoint> {
|
|
487
361
|
return Promise.resolve({
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
addedMessages,
|
|
491
|
-
cancelledMessages,
|
|
362
|
+
blocks: this.lastL1BlockNewBlocks,
|
|
363
|
+
messages: this.lastL1BlockNewMessages,
|
|
492
364
|
});
|
|
493
365
|
}
|
|
494
366
|
}
|