@aztec/archiver 0.56.0 → 0.58.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.
Files changed (79) hide show
  1. package/README.md +1 -1
  2. package/dest/archiver/archiver.d.ts +27 -22
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +421 -115
  5. package/dest/archiver/archiver_store.d.ts +39 -10
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  8. package/dest/archiver/archiver_store_test_suite.js +84 -31
  9. package/dest/archiver/config.js +6 -6
  10. package/dest/archiver/data_retrieval.d.ts +2 -3
  11. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  12. package/dest/archiver/data_retrieval.js +23 -22
  13. package/dest/archiver/epoch_helpers.d.ts +15 -0
  14. package/dest/archiver/epoch_helpers.d.ts.map +1 -0
  15. package/dest/archiver/epoch_helpers.js +23 -0
  16. package/dest/archiver/kv_archiver_store/block_store.d.ts +20 -1
  17. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  18. package/dest/archiver/kv_archiver_store/block_store.js +62 -5
  19. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +3 -3
  20. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  21. package/dest/archiver/kv_archiver_store/contract_class_store.js +12 -5
  22. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +2 -2
  23. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  24. package/dest/archiver/kv_archiver_store/contract_instance_store.js +5 -2
  25. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +29 -10
  26. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +57 -17
  28. package/dest/archiver/kv_archiver_store/log_store.d.ts +4 -5
  29. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  30. package/dest/archiver/kv_archiver_store/log_store.js +18 -14
  31. package/dest/archiver/kv_archiver_store/message_store.d.ts +2 -1
  32. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  33. package/dest/archiver/kv_archiver_store/message_store.js +17 -13
  34. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +3 -2
  35. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -1
  36. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +12 -14
  37. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +23 -23
  38. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
  39. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +130 -70
  40. package/dest/factory.d.ts.map +1 -1
  41. package/dest/factory.js +17 -1
  42. package/dest/index.js +2 -1
  43. package/dest/test/index.d.ts +4 -0
  44. package/dest/test/index.d.ts.map +1 -0
  45. package/dest/test/index.js +4 -0
  46. package/dest/test/mock_archiver.d.ts +22 -0
  47. package/dest/test/mock_archiver.d.ts.map +1 -0
  48. package/dest/test/mock_archiver.js +44 -0
  49. package/dest/test/mock_l1_to_l2_message_source.d.ts +16 -0
  50. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -0
  51. package/dest/test/mock_l1_to_l2_message_source.js +25 -0
  52. package/dest/test/mock_l2_block_source.d.ts +75 -0
  53. package/dest/test/mock_l2_block_source.d.ts.map +1 -0
  54. package/dest/test/mock_l2_block_source.js +154 -0
  55. package/package.json +15 -11
  56. package/src/archiver/archiver.ts +553 -170
  57. package/src/archiver/archiver_store.ts +48 -19
  58. package/src/archiver/archiver_store_test_suite.ts +111 -73
  59. package/src/archiver/config.ts +5 -5
  60. package/src/archiver/data_retrieval.ts +25 -26
  61. package/src/archiver/epoch_helpers.ts +26 -0
  62. package/src/archiver/kv_archiver_store/block_store.ts +70 -2
  63. package/src/archiver/kv_archiver_store/contract_class_store.ts +24 -9
  64. package/src/archiver/kv_archiver_store/contract_instance_store.ts +5 -2
  65. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +71 -29
  66. package/src/archiver/kv_archiver_store/log_store.ts +18 -18
  67. package/src/archiver/kv_archiver_store/message_store.ts +16 -18
  68. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +13 -19
  69. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +154 -83
  70. package/src/factory.ts +18 -0
  71. package/src/index.ts +1 -0
  72. package/src/test/index.ts +3 -0
  73. package/src/test/mock_archiver.ts +55 -0
  74. package/src/test/mock_l1_to_l2_message_source.ts +31 -0
  75. package/src/test/mock_l2_block_source.ts +190 -0
  76. package/dest/archiver/kv_archiver_store/proven_store.d.ts +0 -14
  77. package/dest/archiver/kv_archiver_store/proven_store.d.ts.map +0 -1
  78. package/dest/archiver/kv_archiver_store/proven_store.js +0 -30
  79. package/src/archiver/kv_archiver_store/proven_store.ts +0 -34
@@ -26,6 +26,12 @@ export class BlockStore {
26
26
  /** Stores L1 block number in which the last processed L2 block was included */
27
27
  #lastSynchedL1Block: AztecSingleton<bigint>;
28
28
 
29
+ /** Stores l2 block number of the last proven block */
30
+ #lastProvenL2Block: AztecSingleton<number>;
31
+
32
+ /** Stores l2 epoch number of the last proven epoch */
33
+ #lastProvenL2Epoch: AztecSingleton<number>;
34
+
29
35
  /** Index mapping transaction hash (as a string) to its location in a block */
30
36
  #txIndex: AztecMap<string, BlockIndexValue>;
31
37
 
@@ -40,6 +46,8 @@ export class BlockStore {
40
46
  this.#txIndex = db.openMap('archiver_tx_index');
41
47
  this.#contractIndex = db.openMap('archiver_contract_index');
42
48
  this.#lastSynchedL1Block = db.openSingleton('archiver_last_synched_l1_block');
49
+ this.#lastProvenL2Block = db.openSingleton('archiver_last_proven_l2_block');
50
+ this.#lastProvenL2Epoch = db.openSingleton('archiver_last_proven_l2_epoch');
43
51
  }
44
52
 
45
53
  /**
@@ -73,6 +81,38 @@ export class BlockStore {
73
81
  });
74
82
  }
75
83
 
84
+ /**
85
+ * Unwinds blocks from the database
86
+ * @param from - The tip of the chain, passed for verification purposes,
87
+ * ensuring that we don't end up deleting something we did not intend
88
+ * @param blocksToUnwind - The number of blocks we are to unwind
89
+ * @returns True if the operation is successful
90
+ */
91
+ unwindBlocks(from: number, blocksToUnwind: number) {
92
+ return this.db.transaction(() => {
93
+ const last = this.getSynchedL2BlockNumber();
94
+ if (from != last) {
95
+ throw new Error(`Can only remove from the tip`);
96
+ }
97
+
98
+ for (let i = 0; i < blocksToUnwind; i++) {
99
+ const blockNumber = from - i;
100
+ const block = this.getBlock(blockNumber);
101
+
102
+ if (block === undefined) {
103
+ throw new Error(`Cannot remove block ${blockNumber} from the store, we don't have it`);
104
+ }
105
+ void this.#blocks.delete(block.data.number);
106
+ block.data.body.txEffects.forEach(tx => {
107
+ void this.#txIndex.delete(tx.txHash.toString());
108
+ });
109
+ void this.#blockBodies.delete(block.data.body.getTxsEffectsHash().toString('hex'));
110
+ }
111
+
112
+ return true;
113
+ });
114
+ }
115
+
76
116
  /**
77
117
  * Gets up to `limit` amount of L2 blocks starting from `from`.
78
118
  * @param start - Number of the first block to return (inclusive).
@@ -99,6 +139,18 @@ export class BlockStore {
99
139
  return this.getBlockFromBlockStorage(blockStorage);
100
140
  }
101
141
 
142
+ /**
143
+ * Gets the headers for a sequence of L2 blocks.
144
+ * @param start - Number of the first block to return (inclusive).
145
+ * @param limit - The number of blocks to return.
146
+ * @returns The requested L2 block headers
147
+ */
148
+ *getBlockHeaders(start: number, limit: number): IterableIterator<Header> {
149
+ for (const blockStorage of this.#blocks.values(this.#computeBlockRange(start, limit))) {
150
+ yield Header.fromBuffer(blockStorage.header);
151
+ }
152
+ }
153
+
102
154
  private getBlockFromBlockStorage(blockStorage: BlockStorage) {
103
155
  const header = Header.fromBuffer(blockStorage.header);
104
156
  const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
@@ -109,7 +161,7 @@ export class BlockStore {
109
161
  }
110
162
  const body = Body.fromBuffer(blockBodyBuffer);
111
163
 
112
- const l2Block = L2Block.fromFields({ header, archive, body });
164
+ const l2Block = new L2Block(archive, header, body);
113
165
  return { data: l2Block, l1: blockStorage.l1 };
114
166
  }
115
167
 
@@ -191,13 +243,29 @@ export class BlockStore {
191
243
  void this.#lastSynchedL1Block.set(l1BlockNumber);
192
244
  }
193
245
 
246
+ getProvenL2BlockNumber(): number {
247
+ return this.#lastProvenL2Block.get() ?? 0;
248
+ }
249
+
250
+ setProvenL2BlockNumber(blockNumber: number) {
251
+ void this.#lastProvenL2Block.set(blockNumber);
252
+ }
253
+
254
+ getProvenL2EpochNumber(): number | undefined {
255
+ return this.#lastProvenL2Epoch.get();
256
+ }
257
+
258
+ setProvenL2EpochNumber(epochNumber: number) {
259
+ void this.#lastProvenL2Epoch.set(epochNumber);
260
+ }
261
+
194
262
  #computeBlockRange(start: number, limit: number): Required<Pick<Range<number>, 'start' | 'end'>> {
195
263
  if (limit < 1) {
196
264
  throw new Error(`Invalid limit: ${limit}`);
197
265
  }
198
266
 
199
267
  if (start < INITIAL_L2_BLOCK_NUM) {
200
- start = INITIAL_L2_BLOCK_NUM;
268
+ throw new Error(`Invalid start: ${start}`);
201
269
  }
202
270
 
203
271
  const end = start + limit;
@@ -1,11 +1,14 @@
1
- import { Fr, FunctionSelector, Vector } from '@aztec/circuits.js';
2
- import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
3
- import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
4
1
  import {
5
2
  type ContractClassPublic,
3
+ type ContractClassPublicWithBlockNumber,
6
4
  type ExecutablePrivateFunctionWithMembershipProof,
5
+ Fr,
6
+ FunctionSelector,
7
7
  type UnconstrainedFunctionWithMembershipProof,
8
- } from '@aztec/types/contracts';
8
+ Vector,
9
+ } from '@aztec/circuits.js';
10
+ import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
11
+ import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
9
12
 
10
13
  /**
11
14
  * LMDB implementation of the ArchiverDataStore interface.
@@ -17,8 +20,18 @@ export class ContractClassStore {
17
20
  this.#contractClasses = db.openMap('archiver_contract_classes');
18
21
  }
19
22
 
20
- addContractClass(contractClass: ContractClassPublic): Promise<void> {
21
- return this.#contractClasses.set(contractClass.id.toString(), serializeContractClassPublic(contractClass));
23
+ async addContractClass(contractClass: ContractClassPublic, blockNumber: number): Promise<void> {
24
+ await this.#contractClasses.setIfNotExists(
25
+ contractClass.id.toString(),
26
+ serializeContractClassPublic({ ...contractClass, l2BlockNumber: blockNumber }),
27
+ );
28
+ }
29
+
30
+ async deleteContractClasses(contractClass: ContractClassPublic, blockNumber: number): Promise<void> {
31
+ const restoredContractClass = this.#contractClasses.get(contractClass.id.toString());
32
+ if (restoredContractClass && deserializeContractClassPublic(restoredContractClass).l2BlockNumber >= blockNumber) {
33
+ await this.#contractClasses.delete(contractClass.id.toString());
34
+ }
22
35
  }
23
36
 
24
37
  getContractClass(id: Fr): ContractClassPublic | undefined {
@@ -44,7 +57,7 @@ export class ContractClassStore {
44
57
  const existingClass = deserializeContractClassPublic(existingClassBuffer);
45
58
  const { privateFunctions: existingPrivateFns, unconstrainedFunctions: existingUnconstrainedFns } = existingClass;
46
59
 
47
- const updatedClass: Omit<ContractClassPublic, 'id'> = {
60
+ const updatedClass: Omit<ContractClassPublicWithBlockNumber, 'id'> = {
48
61
  ...existingClass,
49
62
  privateFunctions: [
50
63
  ...existingPrivateFns,
@@ -63,8 +76,9 @@ export class ContractClassStore {
63
76
  }
64
77
  }
65
78
 
66
- function serializeContractClassPublic(contractClass: Omit<ContractClassPublic, 'id'>): Buffer {
79
+ function serializeContractClassPublic(contractClass: Omit<ContractClassPublicWithBlockNumber, 'id'>): Buffer {
67
80
  return serializeToBuffer(
81
+ contractClass.l2BlockNumber,
68
82
  numToUInt8(contractClass.version),
69
83
  contractClass.artifactHash,
70
84
  contractClass.publicFunctions.length,
@@ -108,9 +122,10 @@ function serializeUnconstrainedFunction(fn: UnconstrainedFunctionWithMembershipP
108
122
  );
109
123
  }
110
124
 
111
- function deserializeContractClassPublic(buffer: Buffer): Omit<ContractClassPublic, 'id'> {
125
+ function deserializeContractClassPublic(buffer: Buffer): Omit<ContractClassPublicWithBlockNumber, 'id'> {
112
126
  const reader = BufferReader.asReader(buffer);
113
127
  return {
128
+ l2BlockNumber: reader.readNumber(),
114
129
  version: reader.readUInt8() as 1,
115
130
  artifactHash: reader.readObject(Fr),
116
131
  publicFunctions: reader.readVector({
@@ -1,6 +1,5 @@
1
- import { type AztecAddress } from '@aztec/circuits.js';
1
+ import { type AztecAddress, type ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/circuits.js';
2
2
  import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
3
- import { type ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts';
4
3
 
5
4
  /**
6
5
  * LMDB implementation of the ArchiverDataStore interface.
@@ -19,6 +18,10 @@ export class ContractInstanceStore {
19
18
  );
20
19
  }
21
20
 
21
+ deleteContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
22
+ return this.#contractInstances.delete(contractInstance.address.toString());
23
+ }
24
+
22
25
  getContractInstance(address: AztecAddress): ContractInstanceWithAddress | undefined {
23
26
  const contractInstance = this.#contractInstances.get(address.toString());
24
27
  return contractInstance && SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
@@ -1,6 +1,4 @@
1
1
  import {
2
- type EncryptedL2BlockL2Logs,
3
- type EncryptedNoteL2BlockL2Logs,
4
2
  type FromLogType,
5
3
  type GetUnencryptedLogsResponse,
6
4
  type InboxLeaf,
@@ -11,22 +9,22 @@ import {
11
9
  type TxEffect,
12
10
  type TxHash,
13
11
  type TxReceipt,
14
- type UnencryptedL2BlockL2Logs,
15
12
  } from '@aztec/circuit-types';
16
- import { type Fr } from '@aztec/circuits.js';
17
- import { type ContractArtifact } from '@aztec/foundation/abi';
18
- import { type AztecAddress } from '@aztec/foundation/aztec-address';
19
- import { createDebugLogger } from '@aztec/foundation/log';
20
- import { type AztecKVStore } from '@aztec/kv-store';
21
13
  import {
22
14
  type ContractClassPublic,
23
15
  type ContractInstanceWithAddress,
24
16
  type ExecutablePrivateFunctionWithMembershipProof,
17
+ type Fr,
18
+ type Header,
25
19
  type UnconstrainedFunctionWithMembershipProof,
26
- } from '@aztec/types/contracts';
20
+ } from '@aztec/circuits.js';
21
+ import { type ContractArtifact } from '@aztec/foundation/abi';
22
+ import { type AztecAddress } from '@aztec/foundation/aztec-address';
23
+ import { createDebugLogger } from '@aztec/foundation/log';
24
+ import { type AztecKVStore } from '@aztec/kv-store';
27
25
 
28
26
  import { type ArchiverDataStore, type ArchiverL1SynchPoint } from '../archiver_store.js';
29
- import { type DataRetrieval, type SingletonDataRetrieval } from '../structs/data_retrieval.js';
27
+ import { type DataRetrieval } from '../structs/data_retrieval.js';
30
28
  import { type L1Published } from '../structs/published.js';
31
29
  import { BlockStore } from './block_store.js';
32
30
  import { ContractArtifactsStore } from './contract_artifacts_store.js';
@@ -34,14 +32,12 @@ import { ContractClassStore } from './contract_class_store.js';
34
32
  import { ContractInstanceStore } from './contract_instance_store.js';
35
33
  import { LogStore } from './log_store.js';
36
34
  import { MessageStore } from './message_store.js';
37
- import { ProvenStore } from './proven_store.js';
38
35
 
39
36
  /**
40
37
  * LMDB implementation of the ArchiverDataStore interface.
41
38
  */
42
39
  export class KVArchiverDataStore implements ArchiverDataStore {
43
40
  #blockStore: BlockStore;
44
- #provenStore: ProvenStore;
45
41
  #logStore: LogStore;
46
42
  #messageStore: MessageStore;
47
43
  #contractClassStore: ContractClassStore;
@@ -52,7 +48,6 @@ export class KVArchiverDataStore implements ArchiverDataStore {
52
48
 
53
49
  constructor(db: AztecKVStore, logsMaxPageSize: number = 1000) {
54
50
  this.#blockStore = new BlockStore(db);
55
- this.#provenStore = new ProvenStore(db);
56
51
  this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize);
57
52
  this.#messageStore = new MessageStore(db);
58
53
  this.#contractClassStore = new ContractClassStore(db);
@@ -80,8 +75,14 @@ export class KVArchiverDataStore implements ArchiverDataStore {
80
75
  return Promise.resolve(this.#contractInstanceStore.getContractInstance(address));
81
76
  }
82
77
 
83
- async addContractClasses(data: ContractClassPublic[], _blockNumber: number): Promise<boolean> {
84
- return (await Promise.all(data.map(c => this.#contractClassStore.addContractClass(c)))).every(Boolean);
78
+ async addContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean> {
79
+ return (await Promise.all(data.map(c => this.#contractClassStore.addContractClass(c, blockNumber)))).every(Boolean);
80
+ }
81
+
82
+ async deleteContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean> {
83
+ return (await Promise.all(data.map(c => this.#contractClassStore.deleteContractClasses(c, blockNumber)))).every(
84
+ Boolean,
85
+ );
85
86
  }
86
87
 
87
88
  addFunctions(
@@ -96,6 +97,10 @@ export class KVArchiverDataStore implements ArchiverDataStore {
96
97
  return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c)))).every(Boolean);
97
98
  }
98
99
 
100
+ async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber: number): Promise<boolean> {
101
+ return (await Promise.all(data.map(c => this.#contractInstanceStore.deleteContractInstance(c)))).every(Boolean);
102
+ }
103
+
99
104
  /**
100
105
  * Append new blocks to the store's list.
101
106
  * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
@@ -105,6 +110,17 @@ export class KVArchiverDataStore implements ArchiverDataStore {
105
110
  return this.#blockStore.addBlocks(blocks);
106
111
  }
107
112
 
113
+ /**
114
+ * Unwinds blocks from the database
115
+ * @param from - The tip of the chain, passed for verification purposes,
116
+ * ensuring that we don't end up deleting something we did not intend
117
+ * @param blocksToUnwind - The number of blocks we are to unwind
118
+ * @returns True if the operation is successful
119
+ */
120
+ unwindBlocks(from: number, blocksToUnwind: number): Promise<boolean> {
121
+ return this.#blockStore.unwindBlocks(from, blocksToUnwind);
122
+ }
123
+
108
124
  /**
109
125
  * Gets up to `limit` amount of L2 blocks starting from `from`.
110
126
  *
@@ -121,6 +137,22 @@ export class KVArchiverDataStore implements ArchiverDataStore {
121
137
  }
122
138
  }
123
139
 
140
+ /**
141
+ * Gets up to `limit` amount of L2 blocks headers starting from `from`.
142
+ *
143
+ * @param start - Number of the first block to return (inclusive).
144
+ * @param limit - The number of blocks to return.
145
+ * @returns The requested L2 blocks
146
+ */
147
+ getBlockHeaders(start: number, limit: number): Promise<Header[]> {
148
+ try {
149
+ return Promise.resolve(Array.from(this.#blockStore.getBlockHeaders(start, limit)));
150
+ } catch (err) {
151
+ // this function is sync so if any errors are thrown we need to make sure they're passed on as rejected Promises
152
+ return Promise.reject(err);
153
+ }
154
+ }
155
+
124
156
  /**
125
157
  * Gets a tx effect.
126
158
  * @param txHash - The txHash of the tx corresponding to the tx effect.
@@ -141,18 +173,19 @@ export class KVArchiverDataStore implements ArchiverDataStore {
141
173
 
142
174
  /**
143
175
  * Append new logs to the store's list.
144
- * @param encryptedLogs - The logs to be added to the store.
145
- * @param unencryptedLogs - The type of the logs to be added to the store.
146
- * @param blockNumber - The block for which to add the logs.
176
+ * @param blocks - The blocks for which to add the logs.
147
177
  * @returns True if the operation is successful.
148
178
  */
149
- addLogs(
150
- noteEncryptedLogs: EncryptedNoteL2BlockL2Logs | undefined,
151
- encryptedLogs: EncryptedL2BlockL2Logs | undefined,
152
- unencryptedLogs: UnencryptedL2BlockL2Logs | undefined,
153
- blockNumber: number,
154
- ): Promise<boolean> {
155
- return this.#logStore.addLogs(noteEncryptedLogs, encryptedLogs, unencryptedLogs, blockNumber);
179
+ addLogs(blocks: L2Block[]): Promise<boolean> {
180
+ return this.#logStore.addLogs(blocks);
181
+ }
182
+
183
+ deleteLogs(blocks: L2Block[]): Promise<boolean> {
184
+ return this.#logStore.deleteLogs(blocks);
185
+ }
186
+
187
+ getTotalL1ToL2MessageCount(): Promise<bigint> {
188
+ return Promise.resolve(this.#messageStore.getTotalL1ToL2MessageCount());
156
189
  }
157
190
 
158
191
  /**
@@ -228,11 +261,21 @@ export class KVArchiverDataStore implements ArchiverDataStore {
228
261
  }
229
262
 
230
263
  getProvenL2BlockNumber(): Promise<number> {
231
- return Promise.resolve(this.#provenStore.getProvenL2BlockNumber());
264
+ return Promise.resolve(this.#blockStore.getProvenL2BlockNumber());
265
+ }
266
+
267
+ getProvenL2EpochNumber(): Promise<number | undefined> {
268
+ return Promise.resolve(this.#blockStore.getProvenL2EpochNumber());
232
269
  }
233
270
 
234
- async setProvenL2BlockNumber(blockNumber: SingletonDataRetrieval<number>) {
235
- await this.#provenStore.setProvenL2BlockNumber(blockNumber);
271
+ setProvenL2BlockNumber(blockNumber: number) {
272
+ this.#blockStore.setProvenL2BlockNumber(blockNumber);
273
+ return Promise.resolve();
274
+ }
275
+
276
+ setProvenL2EpochNumber(epochNumber: number) {
277
+ this.#blockStore.setProvenL2EpochNumber(epochNumber);
278
+ return Promise.resolve();
236
279
  }
237
280
 
238
281
  setBlockSynchedL1BlockNumber(l1BlockNumber: bigint) {
@@ -252,7 +295,6 @@ export class KVArchiverDataStore implements ArchiverDataStore {
252
295
  return Promise.resolve({
253
296
  blocksSynchedTo: this.#blockStore.getSynchedL1BlockNumber(),
254
297
  messagesSynchedTo: this.#messageStore.getSynchedL1BlockNumber(),
255
- provenLogsSynchedTo: this.#provenStore.getSynchedL1BlockNumber(),
256
298
  });
257
299
  }
258
300
  }
@@ -4,6 +4,7 @@ import {
4
4
  ExtendedUnencryptedL2Log,
5
5
  type FromLogType,
6
6
  type GetUnencryptedLogsResponse,
7
+ type L2Block,
7
8
  type L2BlockL2Logs,
8
9
  type LogFilter,
9
10
  LogId,
@@ -37,29 +38,28 @@ export class LogStore {
37
38
 
38
39
  /**
39
40
  * Append new logs to the store's list.
40
- * @param encryptedLogs - The logs to be added to the store.
41
- * @param unencryptedLogs - The type of the logs to be added to the store.
42
- * @param blockNumber - The block for which to add the logs.
41
+ * @param blocks - The blocks for which to add the logs.
43
42
  * @returns True if the operation is successful.
44
43
  */
45
- addLogs(
46
- noteEncryptedLogs: EncryptedNoteL2BlockL2Logs | undefined,
47
- encryptedLogs: EncryptedL2BlockL2Logs | undefined,
48
- unencryptedLogs: UnencryptedL2BlockL2Logs | undefined,
49
- blockNumber: number,
50
- ): Promise<boolean> {
44
+ addLogs(blocks: L2Block[]): Promise<boolean> {
51
45
  return this.db.transaction(() => {
52
- if (noteEncryptedLogs) {
53
- void this.#noteEncryptedLogs.set(blockNumber, noteEncryptedLogs.toBuffer());
54
- }
46
+ blocks.forEach(block => {
47
+ void this.#noteEncryptedLogs.set(block.number, block.body.noteEncryptedLogs.toBuffer());
48
+ void this.#encryptedLogs.set(block.number, block.body.encryptedLogs.toBuffer());
49
+ void this.#unencryptedLogs.set(block.number, block.body.unencryptedLogs.toBuffer());
50
+ });
55
51
 
56
- if (encryptedLogs) {
57
- void this.#encryptedLogs.set(blockNumber, encryptedLogs.toBuffer());
58
- }
52
+ return true;
53
+ });
54
+ }
59
55
 
60
- if (unencryptedLogs) {
61
- void this.#unencryptedLogs.set(blockNumber, unencryptedLogs.toBuffer());
62
- }
56
+ deleteLogs(blocks: L2Block[]): Promise<boolean> {
57
+ return this.db.transaction(() => {
58
+ blocks.forEach(block => {
59
+ void this.#noteEncryptedLogs.delete(block.number);
60
+ void this.#encryptedLogs.delete(block.number);
61
+ void this.#unencryptedLogs.delete(block.number);
62
+ });
63
63
 
64
64
  return true;
65
65
  });
@@ -1,10 +1,5 @@
1
- import { type 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';
1
+ import { InboxLeaf } from '@aztec/circuit-types';
2
+ import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
8
3
  import { createDebugLogger } from '@aztec/foundation/log';
9
4
  import { type AztecKVStore, type AztecMap, type AztecSingleton } from '@aztec/kv-store';
10
5
 
@@ -17,6 +12,7 @@ export class MessageStore {
17
12
  #l1ToL2Messages: AztecMap<string, Buffer>;
18
13
  #l1ToL2MessageIndices: AztecMap<string, bigint[]>; // We store array of bigints here because there can be duplicate messages
19
14
  #lastSynchedL1Block: AztecSingleton<bigint>;
15
+ #totalMessageCount: AztecSingleton<bigint>;
20
16
 
21
17
  #log = createDebugLogger('aztec:archiver:message_store');
22
18
 
@@ -26,6 +22,11 @@ export class MessageStore {
26
22
  this.#l1ToL2Messages = db.openMap('archiver_l1_to_l2_messages');
27
23
  this.#l1ToL2MessageIndices = db.openMap('archiver_l1_to_l2_message_indices');
28
24
  this.#lastSynchedL1Block = db.openSingleton('archiver_last_l1_block_new_messages');
25
+ this.#totalMessageCount = db.openSingleton('archiver_l1_to_l2_message_count');
26
+ }
27
+
28
+ getTotalL1ToL2MessageCount(): bigint {
29
+ return this.#totalMessageCount.get() ?? 0n;
29
30
  }
30
31
 
31
32
  /**
@@ -55,21 +56,17 @@ export class MessageStore {
55
56
  void this.#lastSynchedL1Block.set(messages.lastProcessedL1BlockNumber);
56
57
 
57
58
  for (const message of messages.retrievedData) {
58
- if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
59
- throw new Error(`Message index ${message.index} out of subtree range`);
60
- }
61
- const key = `${message.blockNumber}-${message.index}`;
59
+ const key = `${message.index}`;
62
60
  void this.#l1ToL2Messages.setIfNotExists(key, message.leaf.toBuffer());
63
61
 
64
- const indexInTheWholeTree =
65
- (message.blockNumber - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) +
66
- message.index;
67
-
68
62
  const indices = this.#l1ToL2MessageIndices.get(message.leaf.toString()) ?? [];
69
- indices.push(indexInTheWholeTree);
63
+ indices.push(message.index);
70
64
  void this.#l1ToL2MessageIndices.set(message.leaf.toString(), indices);
71
65
  }
72
66
 
67
+ const lastTotalMessageCount = this.getTotalL1ToL2MessageCount();
68
+ void this.#totalMessageCount.set(lastTotalMessageCount + BigInt(messages.retrievedData.length));
69
+
73
70
  return true;
74
71
  });
75
72
  }
@@ -89,9 +86,10 @@ export class MessageStore {
89
86
  getL1ToL2Messages(blockNumber: bigint): Fr[] {
90
87
  const messages: Fr[] = [];
91
88
  let undefinedMessageFound = false;
92
- for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
89
+ const startIndex = Number(InboxLeaf.smallestIndexFromL2Block(blockNumber));
90
+ for (let i = startIndex; i < startIndex + this.#l1ToL2MessagesSubtreeSize; i++) {
93
91
  // This is inefficient but probably fine for now.
94
- const key = `${blockNumber}-${messageIndex}`;
92
+ const key = `${i}`;
95
93
  const message = this.#l1ToL2Messages.get(key);
96
94
  if (message) {
97
95
  if (undefinedMessageFound) {
@@ -1,9 +1,5 @@
1
- import { type 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';
1
+ import { InboxLeaf } from '@aztec/circuit-types';
2
+ import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants';
7
3
  import { type Fr } from '@aztec/foundation/fields';
8
4
 
9
5
  /**
@@ -11,7 +7,7 @@ import { type Fr } from '@aztec/foundation/fields';
11
7
  */
12
8
  export class L1ToL2MessageStore {
13
9
  /**
14
- * A map pointing from a key in a "blockNum-messageIndex" format to the corresponding L1 to L2 message hash.
10
+ * A map pointing from a key in a "messageIndex" format to the corresponding L1 to L2 message hash.
15
11
  */
16
12
  protected store: Map<string, Fr> = new Map();
17
13
 
@@ -19,21 +15,22 @@ export class L1ToL2MessageStore {
19
15
 
20
16
  constructor() {}
21
17
 
18
+ getTotalL1ToL2MessageCount(): bigint {
19
+ return BigInt(this.store.size);
20
+ }
21
+
22
22
  addMessage(message: InboxLeaf) {
23
- if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
24
- throw new Error(`Message index ${message.index} out of subtree range`);
25
- }
26
- const key = `${message.blockNumber}-${message.index}`;
27
- this.store.set(key, message.leaf);
23
+ this.store.set(`${message.index}`, message.leaf);
28
24
  }
29
25
 
30
26
  getMessages(blockNumber: bigint): Fr[] {
31
27
  const messages: Fr[] = [];
32
28
  let undefinedMessageFound = false;
33
- for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
29
+ const startIndex = Number(InboxLeaf.smallestIndexFromL2Block(blockNumber));
30
+
31
+ for (let i = startIndex; i < startIndex + this.#l1ToL2MessagesSubtreeSize; i++) {
34
32
  // This is inefficient but probably fine for now.
35
- const key = `${blockNumber}-${messageIndex}`;
36
- const message = this.store.get(key);
33
+ const message = this.store.get(`${i}`);
37
34
  if (message) {
38
35
  if (undefinedMessageFound) {
39
36
  throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
@@ -57,10 +54,7 @@ export class L1ToL2MessageStore {
57
54
  getMessageIndex(l1ToL2Message: Fr, startIndex: bigint): bigint | undefined {
58
55
  for (const [key, message] of this.store.entries()) {
59
56
  if (message.equals(l1ToL2Message)) {
60
- const keyParts = key.split('-');
61
- const [blockNumber, messageIndex] = [BigInt(keyParts[0]), BigInt(keyParts[1])];
62
- const indexInTheWholeTree =
63
- (blockNumber - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) + messageIndex;
57
+ const indexInTheWholeTree = BigInt(key);
64
58
  if (indexInTheWholeTree < startIndex) {
65
59
  continue;
66
60
  }