@aztec/archiver 0.80.0 → 0.81.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 (41) hide show
  1. package/dest/archiver/archiver.d.ts +5 -9
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +36 -49
  4. package/dest/archiver/archiver_store.d.ts +5 -4
  5. package/dest/archiver/archiver_store.d.ts.map +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.js +104 -91
  8. package/dest/archiver/data_retrieval.d.ts +3 -4
  9. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  10. package/dest/archiver/data_retrieval.js +8 -3
  11. package/dest/archiver/index.d.ts +1 -1
  12. package/dest/archiver/index.d.ts.map +1 -1
  13. package/dest/archiver/kv_archiver_store/block_store.d.ts +6 -6
  14. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  15. package/dest/archiver/kv_archiver_store/block_store.js +24 -21
  16. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +4 -4
  17. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  18. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +2 -3
  19. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  20. package/dest/archiver/kv_archiver_store/log_store.js +9 -41
  21. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +4 -4
  22. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
  23. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +25 -54
  24. package/dest/archiver/structs/published.d.ts +1 -10
  25. package/dest/archiver/structs/published.d.ts.map +1 -1
  26. package/dest/archiver/structs/published.js +1 -1
  27. package/dest/test/mock_l2_block_source.d.ts +9 -0
  28. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  29. package/dest/test/mock_l2_block_source.js +13 -0
  30. package/package.json +13 -13
  31. package/src/archiver/archiver.ts +44 -60
  32. package/src/archiver/archiver_store.ts +5 -4
  33. package/src/archiver/archiver_store_test_suite.ts +116 -93
  34. package/src/archiver/data_retrieval.ts +11 -10
  35. package/src/archiver/index.ts +1 -1
  36. package/src/archiver/kv_archiver_store/block_store.ts +28 -27
  37. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +5 -6
  38. package/src/archiver/kv_archiver_store/log_store.ts +11 -59
  39. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +35 -66
  40. package/src/archiver/structs/published.ts +1 -11
  41. package/src/test/mock_l2_block_source.ts +14 -0
@@ -1,4 +1,5 @@
1
1
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
+ import { Signature } from '@aztec/foundation/eth-signature';
2
3
  import { toArray } from '@aztec/foundation/iterable';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
5
  import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
@@ -7,9 +8,9 @@ import { Body, type InBlock, L2Block, L2BlockHash } from '@aztec/stdlib/block';
7
8
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
8
9
  import { BlockHeader, TxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
9
10
 
10
- import type { L1Published, L1PublishedData } from '../structs/published.js';
11
+ import type { L1PublishedData, PublishedL2Block } from '../structs/published.js';
11
12
 
12
- export { type TxEffect, type TxHash, TxReceipt } from '@aztec/stdlib/tx';
13
+ export { TxReceipt, type TxEffect, type TxHash } from '@aztec/stdlib/tx';
13
14
 
14
15
  type BlockIndexValue = [blockNumber: number, index: number];
15
16
 
@@ -17,6 +18,7 @@ type BlockStorage = {
17
18
  header: Buffer;
18
19
  archive: Buffer;
19
20
  l1: L1PublishedData;
21
+ signatures: Buffer[];
20
22
  };
21
23
 
22
24
  /**
@@ -61,25 +63,26 @@ export class BlockStore {
61
63
  * @param blocks - The L2 blocks to be added to the store.
62
64
  * @returns True if the operation is successful.
63
65
  */
64
- async addBlocks(blocks: L1Published<L2Block>[]): Promise<boolean> {
66
+ async addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
65
67
  if (blocks.length === 0) {
66
68
  return true;
67
69
  }
68
70
 
69
71
  return await this.db.transactionAsync(async () => {
70
72
  for (const block of blocks) {
71
- await this.#blocks.set(block.data.number, {
72
- header: block.data.header.toBuffer(),
73
- archive: block.data.archive.toBuffer(),
73
+ await this.#blocks.set(block.block.number, {
74
+ header: block.block.header.toBuffer(),
75
+ archive: block.block.archive.toBuffer(),
74
76
  l1: block.l1,
77
+ signatures: block.signatures.map(sig => sig.toBuffer()),
75
78
  });
76
79
 
77
- for (let i = 0; i < block.data.body.txEffects.length; i++) {
78
- const txEffect = block.data.body.txEffects[i];
79
- await this.#txIndex.set(txEffect.txHash.toString(), [block.data.number, i]);
80
+ for (let i = 0; i < block.block.body.txEffects.length; i++) {
81
+ const txEffect = block.block.body.txEffects[i];
82
+ await this.#txIndex.set(txEffect.txHash.toString(), [block.block.number, i]);
80
83
  }
81
84
 
82
- await this.#blockBodies.set((await block.data.hash()).toString(), block.data.body.toBuffer());
85
+ await this.#blockBodies.set((await block.block.hash()).toString(), block.block.body.toBuffer());
83
86
  }
84
87
 
85
88
  await this.#lastSynchedL1Block.set(blocks[blocks.length - 1].l1.blockNumber);
@@ -109,9 +112,9 @@ export class BlockStore {
109
112
  this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
110
113
  continue;
111
114
  }
112
- await this.#blocks.delete(block.data.number);
113
- await Promise.all(block.data.body.txEffects.map(tx => this.#txIndex.delete(tx.txHash.toString())));
114
- const blockHash = (await block.data.hash()).toString();
115
+ await this.#blocks.delete(block.block.number);
116
+ await Promise.all(block.block.body.txEffects.map(tx => this.#txIndex.delete(tx.txHash.toString())));
117
+ const blockHash = (await block.block.hash()).toString();
115
118
  await this.#blockBodies.delete(blockHash);
116
119
  this.#log.debug(`Unwound block ${blockNumber} ${blockHash}`);
117
120
  }
@@ -126,10 +129,9 @@ export class BlockStore {
126
129
  * @param limit - The number of blocks to return.
127
130
  * @returns The requested L2 blocks
128
131
  */
129
- async *getBlocks(start: number, limit: number): AsyncIterableIterator<L1Published<L2Block>> {
132
+ async *getBlocks(start: number, limit: number): AsyncIterableIterator<PublishedL2Block> {
130
133
  for await (const blockStorage of this.#blocks.valuesAsync(this.#computeBlockRange(start, limit))) {
131
- const block = await this.getBlockFromBlockStorage(blockStorage);
132
- yield block;
134
+ yield await this.getBlockFromBlockStorage(blockStorage);
133
135
  }
134
136
  }
135
137
 
@@ -138,12 +140,11 @@ export class BlockStore {
138
140
  * @param blockNumber - The number of the block to return.
139
141
  * @returns The requested L2 block.
140
142
  */
141
- async getBlock(blockNumber: number): Promise<L1Published<L2Block> | undefined> {
143
+ async getBlock(blockNumber: number): Promise<PublishedL2Block | undefined> {
142
144
  const blockStorage = await this.#blocks.getAsync(blockNumber);
143
145
  if (!blockStorage || !blockStorage.header) {
144
146
  return Promise.resolve(undefined);
145
147
  }
146
-
147
148
  return this.getBlockFromBlockStorage(blockStorage);
148
149
  }
149
150
 
@@ -170,9 +171,9 @@ export class BlockStore {
170
171
  );
171
172
  }
172
173
  const body = Body.fromBuffer(blockBodyBuffer);
173
-
174
- const l2Block = new L2Block(archive, header, body);
175
- return { data: l2Block, l1: blockStorage.l1 };
174
+ const block = new L2Block(archive, header, body);
175
+ const signatures = blockStorage.signatures.map(Signature.fromBuffer);
176
+ return { block, l1: blockStorage.l1, signatures };
176
177
  }
177
178
 
178
179
  /**
@@ -192,9 +193,9 @@ export class BlockStore {
192
193
  }
193
194
 
194
195
  return {
195
- data: block.data.body.txEffects[txIndex],
196
- l2BlockNumber: block.data.number,
197
- l2BlockHash: (await block.data.hash()).toString(),
196
+ data: block.block.body.txEffects[txIndex],
197
+ l2BlockNumber: block.block.number,
198
+ l2BlockHash: (await block.block.hash()).toString(),
198
199
  };
199
200
  }
200
201
 
@@ -210,15 +211,15 @@ export class BlockStore {
210
211
  }
211
212
 
212
213
  const block = (await this.getBlock(blockNumber))!;
213
- const tx = block.data.body.txEffects[txIndex];
214
+ const tx = block.block.body.txEffects[txIndex];
214
215
 
215
216
  return new TxReceipt(
216
217
  txHash,
217
218
  TxReceipt.statusFromRevertCode(tx.revertCode),
218
219
  '',
219
220
  tx.transactionFee.toBigInt(),
220
- L2BlockHash.fromField(await block.data.hash()),
221
- block.data.number,
221
+ L2BlockHash.fromField(await block.block.hash()),
222
+ block.block.number,
222
223
  );
223
224
  }
224
225
 
@@ -19,7 +19,7 @@ import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
19
19
 
20
20
  import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
21
21
  import type { DataRetrieval } from '../structs/data_retrieval.js';
22
- import type { L1Published } from '../structs/published.js';
22
+ import type { PublishedL2Block } from '../structs/published.js';
23
23
  import { BlockStore } from './block_store.js';
24
24
  import { ContractClassStore } from './contract_class_store.js';
25
25
  import { ContractInstanceStore } from './contract_instance_store.js';
@@ -78,9 +78,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
78
78
  return this.#contractClassStore.getContractClassIds();
79
79
  }
80
80
 
81
- async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
82
- const contract = this.#contractInstanceStore.getContractInstance(address, await this.getSynchedL2BlockNumber());
83
- return contract;
81
+ getContractInstance(address: AztecAddress, blockNumber: number): Promise<ContractInstanceWithAddress | undefined> {
82
+ return this.#contractInstanceStore.getContractInstance(address, blockNumber);
84
83
  }
85
84
 
86
85
  async addContractClasses(
@@ -148,7 +147,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
148
147
  * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
149
148
  * @returns True if the operation is successful.
150
149
  */
151
- addBlocks(blocks: L1Published<L2Block>[]): Promise<boolean> {
150
+ addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
152
151
  return this.#blockStore.addBlocks(blocks);
153
152
  }
154
153
 
@@ -170,7 +169,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
170
169
  * @param limit - The number of blocks to return.
171
170
  * @returns The requested L2 blocks
172
171
  */
173
- getBlocks(start: number, limit: number): Promise<L1Published<L2Block>[]> {
172
+ getBlocks(start: number, limit: number): Promise<PublishedL2Block[]> {
174
173
  return toArray(this.#blockStore.getBlocks(start, limit));
175
174
  }
176
175
 
@@ -1,4 +1,4 @@
1
- import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/constants';
1
+ import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/constants';
2
2
  import type { Fr } from '@aztec/foundation/fields';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
@@ -40,7 +40,7 @@ export class LogStore {
40
40
  this.#logsMaxPageSize = logsMaxPageSize;
41
41
  }
42
42
 
43
- #extractTaggedLogsFromPrivate(block: L2Block) {
43
+ #extractTaggedLogs(block: L2Block) {
44
44
  const taggedLogs = new Map<string, Buffer[]>();
45
45
  const dataStartIndexForBlock =
46
46
  block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
@@ -48,68 +48,22 @@ export class LogStore {
48
48
  block.body.txEffects.forEach((txEffect, txIndex) => {
49
49
  const txHash = txEffect.txHash;
50
50
  const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
51
+
51
52
  txEffect.privateLogs.forEach(log => {
52
53
  const tag = log.fields[0];
54
+ this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
55
+
53
56
  const currentLogs = taggedLogs.get(tag.toString()) ?? [];
54
- currentLogs.push(
55
- new TxScopedL2Log(
56
- txHash,
57
- dataStartIndexForTx,
58
- block.number,
59
- /* isFromPublic */ false,
60
- log.toBuffer(),
61
- ).toBuffer(),
62
- );
57
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log).toBuffer());
63
58
  taggedLogs.set(tag.toString(), currentLogs);
64
59
  });
65
- });
66
- return taggedLogs;
67
- }
68
60
 
69
- #extractTaggedLogsFromPublic(block: L2Block) {
70
- const taggedLogs = new Map<string, Buffer[]>();
71
- const dataStartIndexForBlock =
72
- block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
73
- block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
74
- block.body.txEffects.forEach((txEffect, txIndex) => {
75
- const txHash = txEffect.txHash;
76
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
77
61
  txEffect.publicLogs.forEach(log => {
78
- // Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
79
- const firstFieldBuf = log.log[0].toBuffer();
80
- // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
81
- // 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.
82
- if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
83
- // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
84
- // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
85
- this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
86
- return;
87
- }
88
- // Check that the length values line up with the log contents
89
- const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
90
- const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
91
- // Add 1 for the first field holding lengths
92
- const totalLogLength = 1 + publicValuesLength + privateValuesLength;
93
- // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
94
- if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
95
- this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
96
- return;
97
- }
98
-
99
- // The first elt stores lengths as above => tag is in fields[1]
100
- const tag = log.log[1];
62
+ const tag = log.log[0];
63
+ this.#log.debug(`Found public log with tag ${tag.toString()} in block ${block.number}`);
101
64
 
102
- this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
103
65
  const currentLogs = taggedLogs.get(tag.toString()) ?? [];
104
- currentLogs.push(
105
- new TxScopedL2Log(
106
- txHash,
107
- dataStartIndexForTx,
108
- block.number,
109
- /* isFromPublic */ true,
110
- log.toBuffer(),
111
- ).toBuffer(),
112
- );
66
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log).toBuffer());
113
67
  taggedLogs.set(tag.toString(), currentLogs);
114
68
  });
115
69
  });
@@ -123,7 +77,7 @@ export class LogStore {
123
77
  */
124
78
  addLogs(blocks: L2Block[]): Promise<boolean> {
125
79
  const taggedLogsToAdd = blocks
126
- .flatMap(block => [this.#extractTaggedLogsFromPrivate(block), this.#extractTaggedLogsFromPublic(block)])
80
+ .map(block => this.#extractTaggedLogs(block))
127
81
  .reduce((acc, val) => {
128
82
  for (const [tag, logs] of val.entries()) {
129
83
  const currentLogs = acc.get(tag) ?? [];
@@ -238,9 +192,7 @@ export class LogStore {
238
192
  */
239
193
  async getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
240
194
  const logs = await Promise.all(tags.map(tag => this.#logsByTag.getAsync(tag.toString())));
241
- return logs.map(
242
- noteLogBuffers => noteLogBuffers?.map(noteLogBuffer => TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? [],
243
- );
195
+ return logs.map(logBuffers => logBuffers?.map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
244
196
  }
245
197
 
246
198
  /**
@@ -1,9 +1,4 @@
1
- import {
2
- INITIAL_L2_BLOCK_NUM,
3
- MAX_NOTE_HASHES_PER_TX,
4
- MAX_NULLIFIERS_PER_TX,
5
- PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
6
- } from '@aztec/constants';
1
+ import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX } from '@aztec/constants';
7
2
  import { Fr } from '@aztec/foundation/fields';
8
3
  import { createLogger } from '@aztec/foundation/log';
9
4
  import { FunctionSelector } from '@aztec/stdlib/abi';
@@ -33,7 +28,7 @@ import { type BlockHeader, TxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx'
33
28
 
34
29
  import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
35
30
  import type { DataRetrieval } from '../structs/data_retrieval.js';
36
- import type { L1Published } from '../structs/published.js';
31
+ import type { PublishedL2Block } from '../structs/published.js';
37
32
  import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
38
33
 
39
34
  type StoredContractInstanceUpdate = ContractInstanceUpdateWithAddress & { blockNumber: number; logIndex: number };
@@ -45,7 +40,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
45
40
  /**
46
41
  * An array containing all the L2 blocks that have been fetched so far.
47
42
  */
48
- private l2Blocks: L1Published<L2Block>[] = [];
43
+ private l2Blocks: PublishedL2Block[] = [];
49
44
 
50
45
  /**
51
46
  * An array containing all the tx effects in the L2 blocks that have been fetched so far.
@@ -112,7 +107,10 @@ export class MemoryArchiverStore implements ArchiverDataStore {
112
107
  return Promise.resolve(Array.from(this.contractClasses.keys()).map(key => Fr.fromHexString(key)));
113
108
  }
114
109
 
115
- public getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
110
+ public getContractInstance(
111
+ address: AztecAddress,
112
+ blockNumber: number,
113
+ ): Promise<ContractInstanceWithAddress | undefined> {
116
114
  const instance = this.contractInstances.get(address.toString());
117
115
  if (!instance) {
118
116
  return Promise.resolve(undefined);
@@ -120,8 +118,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
120
118
  const updates = this.contractInstanceUpdates.get(address.toString()) || [];
121
119
  if (updates.length > 0) {
122
120
  const lastUpdate = updates[0];
123
- const currentBlockNumber = this.getLastBlockNumber();
124
- if (currentBlockNumber >= lastUpdate.blockOfChange) {
121
+ if (blockNumber >= lastUpdate.blockOfChange) {
125
122
  instance.currentContractClassId = lastUpdate.newContractClassId;
126
123
  } else if (!lastUpdate.prevContractClassId.isZero()) {
127
124
  instance.currentContractClassId = lastUpdate.prevContractClassId;
@@ -235,16 +232,16 @@ export class MemoryArchiverStore implements ArchiverDataStore {
235
232
  * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
236
233
  * @returns True if the operation is successful.
237
234
  */
238
- public async addBlocks(blocks: L1Published<L2Block>[]): Promise<boolean> {
235
+ public async addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
239
236
  if (blocks.length === 0) {
240
237
  return Promise.resolve(true);
241
238
  }
242
239
 
243
240
  this.lastL1BlockNewBlocks = blocks[blocks.length - 1].l1.blockNumber;
244
241
  this.l2Blocks.push(...blocks);
245
- const flatTxEffects = blocks.flatMap(b => b.data.body.txEffects.map(txEffect => ({ block: b, txEffect })));
242
+ const flatTxEffects = blocks.flatMap(b => b.block.body.txEffects.map(txEffect => ({ block: b, txEffect })));
246
243
  const wrappedTxEffects = await Promise.all(
247
- flatTxEffects.map(flatTxEffect => wrapInBlock(flatTxEffect.txEffect, flatTxEffect.block.data)),
244
+ flatTxEffects.map(flatTxEffect => wrapInBlock(flatTxEffect.txEffect, flatTxEffect.block.block)),
248
245
  );
249
246
  this.txEffects.push(...wrappedTxEffects);
250
247
 
@@ -270,68 +267,41 @@ export class MemoryArchiverStore implements ArchiverDataStore {
270
267
  if (block == undefined) {
271
268
  break;
272
269
  }
273
- block.data.body.txEffects.forEach(() => this.txEffects.pop());
270
+ block.block.body.txEffects.forEach(() => this.txEffects.pop());
274
271
  }
275
272
 
276
273
  return Promise.resolve(true);
277
274
  }
278
275
 
279
- #storeTaggedLogsFromPrivate(block: L2Block): void {
276
+ #storeTaggedLogs(block: L2Block): void {
280
277
  const dataStartIndexForBlock =
281
278
  block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
282
279
  block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
283
280
  block.body.txEffects.forEach((txEffect, txIndex) => {
284
281
  const txHash = txEffect.txHash;
285
282
  const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
283
+
286
284
  txEffect.privateLogs.forEach(log => {
287
285
  const tag = log.fields[0];
286
+ this.#log.verbose(`Storing private log with tag ${tag.toString()} from block ${block.number}`);
287
+
288
288
  const currentLogs = this.taggedLogs.get(tag.toString()) || [];
289
289
  this.taggedLogs.set(tag.toString(), [
290
290
  ...currentLogs,
291
- new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer()),
291
+ new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log),
292
292
  ]);
293
293
  const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
294
294
  this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
295
295
  });
296
- });
297
- }
298
296
 
299
- #storeTaggedLogsFromPublic(block: L2Block): void {
300
- const dataStartIndexForBlock =
301
- block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
302
- block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
303
- block.body.txEffects.forEach((txEffect, txIndex) => {
304
- const txHash = txEffect.txHash;
305
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
306
297
  txEffect.publicLogs.forEach(log => {
307
- // Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
308
- // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
309
- // 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.
310
- const firstFieldBuf = log.log[0].toBuffer();
311
- if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
312
- // See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
313
- // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
314
- this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
315
- return;
316
- }
317
- // Check that the length values line up with the log contents
318
- const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
319
- const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
320
- // Add 1 for the first field holding lengths
321
- const totalLogLength = 1 + publicValuesLength + privateValuesLength;
322
- // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
323
- if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
324
- this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
325
- return;
326
- }
298
+ const tag = log.log[0];
299
+ this.#log.verbose(`Storing public log with tag ${tag.toString()} from block ${block.number}`);
327
300
 
328
- // The first elt stores lengths => tag is in fields[1]
329
- const tag = log.log[1];
330
- this.#log.verbose(`Storing public tagged log with tag ${tag.toString()} in block ${block.number}`);
331
301
  const currentLogs = this.taggedLogs.get(tag.toString()) || [];
332
302
  this.taggedLogs.set(tag.toString(), [
333
303
  ...currentLogs,
334
- new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.toBuffer()),
304
+ new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log),
335
305
  ]);
336
306
  const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
337
307
  this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
@@ -346,8 +316,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
346
316
  */
347
317
  addLogs(blocks: L2Block[]): Promise<boolean> {
348
318
  blocks.forEach(block => {
349
- this.#storeTaggedLogsFromPrivate(block);
350
- this.#storeTaggedLogsFromPublic(block);
319
+ this.#storeTaggedLogs(block);
351
320
  this.privateLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.privateLogs).flat());
352
321
  this.publicLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.publicLogs).flat());
353
322
  this.contractClassLogsPerBlock.set(
@@ -464,7 +433,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
464
433
  * @returns The requested L2 blocks.
465
434
  * @remarks When "from" is smaller than genesis block number, blocks from the beginning are returned.
466
435
  */
467
- public getBlocks(from: number, limit: number): Promise<L1Published<L2Block>[]> {
436
+ public getBlocks(from: number, limit: number): Promise<PublishedL2Block[]> {
468
437
  if (limit < 1) {
469
438
  return Promise.reject(new Error(`Invalid limit: ${limit}`));
470
439
  }
@@ -484,7 +453,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
484
453
 
485
454
  public async getBlockHeaders(from: number, limit: number): Promise<BlockHeader[]> {
486
455
  const blocks = await this.getBlocks(from, limit);
487
- return blocks.map(block => block.data.header);
456
+ return blocks.map(block => block.block.header);
488
457
  }
489
458
 
490
459
  /**
@@ -504,15 +473,15 @@ export class MemoryArchiverStore implements ArchiverDataStore {
504
473
  */
505
474
  public async getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
506
475
  for (const block of this.l2Blocks) {
507
- for (const txEffect of block.data.body.txEffects) {
476
+ for (const txEffect of block.block.body.txEffects) {
508
477
  if (txEffect.txHash.equals(txHash)) {
509
478
  return new TxReceipt(
510
479
  txHash,
511
480
  TxReceipt.statusFromRevertCode(txEffect.revertCode),
512
481
  '',
513
482
  txEffect.transactionFee.toBigInt(),
514
- L2BlockHash.fromField(await block.data.hash()),
515
- block.data.number,
483
+ L2BlockHash.fromField(await block.block.hash()),
484
+ block.block.number,
516
485
  );
517
486
  }
518
487
  }
@@ -566,8 +535,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
566
535
  * that tag.
567
536
  */
568
537
  getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
569
- const noteLogs = tags.map(tag => this.taggedLogs.get(tag.toString()) || []);
570
- return Promise.resolve(noteLogs);
538
+ const logs = tags.map(tag => this.taggedLogs.get(tag.toString()) || []);
539
+ return Promise.resolve(logs);
571
540
  }
572
541
 
573
542
  /**
@@ -626,8 +595,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
626
595
  if (blockLogs) {
627
596
  for (let logIndex = 0; logIndex < blockLogs.length; logIndex++) {
628
597
  const log = blockLogs[logIndex];
629
- const thisTxEffect = block.data.body.txEffects.filter(effect => effect.publicLogs.includes(log))[0];
630
- const thisTxIndexInBlock = block.data.body.txEffects.indexOf(thisTxEffect);
598
+ const thisTxEffect = block.block.body.txEffects.filter(effect => effect.publicLogs.includes(log))[0];
599
+ const thisTxIndexInBlock = block.block.body.txEffects.indexOf(thisTxEffect);
631
600
  const thisLogIndexInTx = thisTxEffect.publicLogs.indexOf(log);
632
601
  if (
633
602
  (!txHash || thisTxEffect.txHash.equals(txHash)) &&
@@ -635,7 +604,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
635
604
  thisTxIndexInBlock >= txIndexInBlock &&
636
605
  thisLogIndexInTx >= logIndexInTx
637
606
  ) {
638
- logs.push(new ExtendedPublicLog(new LogId(block.data.number, thisTxIndexInBlock, thisLogIndexInTx), log));
607
+ logs.push(new ExtendedPublicLog(new LogId(block.block.number, thisTxIndexInBlock, thisLogIndexInTx), log));
639
608
  if (logs.length === this.maxLogs) {
640
609
  return Promise.resolve({
641
610
  logs,
@@ -710,8 +679,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
710
679
  if (blockLogs) {
711
680
  for (let logIndex = 0; logIndex < blockLogs.length; logIndex++) {
712
681
  const log = blockLogs[logIndex];
713
- const thisTxEffect = block.data.body.txEffects.filter(effect => effect.contractClassLogs.includes(log))[0];
714
- const thisTxIndexInBlock = block.data.body.txEffects.indexOf(thisTxEffect);
682
+ const thisTxEffect = block.block.body.txEffects.filter(effect => effect.contractClassLogs.includes(log))[0];
683
+ const thisTxIndexInBlock = block.block.body.txEffects.indexOf(thisTxEffect);
715
684
  const thisLogIndexInTx = thisTxEffect.contractClassLogs.indexOf(log);
716
685
  if (
717
686
  (!txHash || thisTxEffect.txHash.equals(txHash)) &&
@@ -720,7 +689,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
720
689
  thisLogIndexInTx >= logIndexInTx
721
690
  ) {
722
691
  logs.push(
723
- new ExtendedContractClassLog(new LogId(block.data.number, thisTxIndexInBlock, thisLogIndexInTx), log),
692
+ new ExtendedContractClassLog(new LogId(block.block.number, thisTxIndexInBlock, thisLogIndexInTx), log),
724
693
  );
725
694
  if (logs.length === this.maxLogs) {
726
695
  return Promise.resolve({
@@ -743,7 +712,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
743
712
  if (this.l2Blocks.length === 0) {
744
713
  return INITIAL_L2_BLOCK_NUM - 1;
745
714
  }
746
- return this.l2Blocks[this.l2Blocks.length - 1].data.number;
715
+ return this.l2Blocks[this.l2Blocks.length - 1].block.number;
747
716
  }
748
717
 
749
718
  /**
@@ -1,11 +1 @@
1
- /** Extends a type with L1 published info (block number, hash, and timestamp) */
2
- export type L1Published<T> = {
3
- data: T;
4
- l1: L1PublishedData;
5
- };
6
-
7
- export type L1PublishedData = {
8
- blockNumber: bigint;
9
- timestamp: bigint;
10
- blockHash: string;
11
- };
1
+ export type { PublishedL2Block, L1PublishedData } from '@aztec/stdlib/block';
@@ -1,4 +1,5 @@
1
1
  import { DefaultL1ContractsConfig } from '@aztec/ethereum';
2
+ import { Buffer32 } from '@aztec/foundation/buffer';
2
3
  import { EthAddress } from '@aztec/foundation/eth-address';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
5
  import { L2Block, L2BlockHash, type L2BlockSource, type L2Tips } from '@aztec/stdlib/block';
@@ -90,6 +91,19 @@ export class MockL2BlockSource implements L2BlockSource {
90
91
  );
91
92
  }
92
93
 
94
+ public async getPublishedBlocks(from: number, limit: number, proven?: boolean) {
95
+ const blocks = await this.getBlocks(from, limit, proven);
96
+ return blocks.map(block => ({
97
+ block,
98
+ l1: {
99
+ blockNumber: BigInt(block.number),
100
+ blockHash: Buffer32.random().toString(),
101
+ timestamp: BigInt(block.number),
102
+ },
103
+ signatures: [],
104
+ }));
105
+ }
106
+
93
107
  getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
94
108
  return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
95
109
  }