@aztec/archiver 0.0.0-test.1 → 0.0.1-commit.5476d83

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 (110) hide show
  1. package/README.md +27 -6
  2. package/dest/archiver/archiver.d.ts +147 -57
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +841 -333
  5. package/dest/archiver/archiver_store.d.ts +85 -50
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  8. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  9. package/dest/archiver/archiver_store_test_suite.js +708 -213
  10. package/dest/archiver/config.d.ts +5 -21
  11. package/dest/archiver/config.d.ts.map +1 -1
  12. package/dest/archiver/config.js +21 -12
  13. package/dest/archiver/data_retrieval.d.ts +32 -27
  14. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  15. package/dest/archiver/data_retrieval.js +197 -94
  16. package/dest/archiver/errors.d.ts +9 -1
  17. package/dest/archiver/errors.d.ts.map +1 -1
  18. package/dest/archiver/errors.js +12 -0
  19. package/dest/archiver/index.d.ts +3 -4
  20. package/dest/archiver/index.d.ts.map +1 -1
  21. package/dest/archiver/index.js +1 -2
  22. package/dest/archiver/instrumentation.d.ts +12 -6
  23. package/dest/archiver/instrumentation.d.ts.map +1 -1
  24. package/dest/archiver/instrumentation.js +58 -17
  25. package/dest/archiver/kv_archiver_store/block_store.d.ts +48 -11
  26. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/block_store.js +216 -63
  28. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +3 -3
  29. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  30. package/dest/archiver/kv_archiver_store/contract_class_store.js +12 -18
  31. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +11 -8
  32. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  33. package/dest/archiver/kv_archiver_store/contract_instance_store.js +30 -16
  34. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +50 -35
  35. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  36. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +88 -46
  37. package/dest/archiver/kv_archiver_store/log_store.d.ts +2 -2
  38. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  39. package/dest/archiver/kv_archiver_store/log_store.js +18 -46
  40. package/dest/archiver/kv_archiver_store/message_store.d.ts +23 -17
  41. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  42. package/dest/archiver/kv_archiver_store/message_store.js +150 -48
  43. package/dest/archiver/structs/data_retrieval.d.ts +1 -1
  44. package/dest/archiver/structs/inbox_message.d.ts +15 -0
  45. package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
  46. package/dest/archiver/structs/inbox_message.js +38 -0
  47. package/dest/archiver/structs/published.d.ts +3 -11
  48. package/dest/archiver/structs/published.d.ts.map +1 -1
  49. package/dest/archiver/structs/published.js +1 -1
  50. package/dest/archiver/validation.d.ts +17 -0
  51. package/dest/archiver/validation.d.ts.map +1 -0
  52. package/dest/archiver/validation.js +98 -0
  53. package/dest/factory.d.ts +8 -13
  54. package/dest/factory.d.ts.map +1 -1
  55. package/dest/factory.js +18 -49
  56. package/dest/index.d.ts +2 -2
  57. package/dest/index.d.ts.map +1 -1
  58. package/dest/index.js +1 -1
  59. package/dest/rpc/index.d.ts +2 -3
  60. package/dest/rpc/index.d.ts.map +1 -1
  61. package/dest/rpc/index.js +1 -4
  62. package/dest/test/index.d.ts +1 -1
  63. package/dest/test/mock_archiver.d.ts +2 -2
  64. package/dest/test/mock_archiver.d.ts.map +1 -1
  65. package/dest/test/mock_l1_to_l2_message_source.d.ts +5 -3
  66. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  67. package/dest/test/mock_l1_to_l2_message_source.js +14 -1
  68. package/dest/test/mock_l2_block_source.d.ts +38 -10
  69. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  70. package/dest/test/mock_l2_block_source.js +119 -8
  71. package/dest/test/mock_structs.d.ts +9 -0
  72. package/dest/test/mock_structs.d.ts.map +1 -0
  73. package/dest/test/mock_structs.js +37 -0
  74. package/package.json +28 -30
  75. package/src/archiver/archiver.ts +1087 -410
  76. package/src/archiver/archiver_store.ts +97 -55
  77. package/src/archiver/archiver_store_test_suite.ts +664 -210
  78. package/src/archiver/config.ts +28 -41
  79. package/src/archiver/data_retrieval.ts +279 -125
  80. package/src/archiver/errors.ts +21 -0
  81. package/src/archiver/index.ts +2 -3
  82. package/src/archiver/instrumentation.ts +77 -22
  83. package/src/archiver/kv_archiver_store/block_store.ts +270 -72
  84. package/src/archiver/kv_archiver_store/contract_class_store.ts +13 -23
  85. package/src/archiver/kv_archiver_store/contract_instance_store.ts +35 -27
  86. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +127 -63
  87. package/src/archiver/kv_archiver_store/log_store.ts +24 -62
  88. package/src/archiver/kv_archiver_store/message_store.ts +209 -53
  89. package/src/archiver/structs/inbox_message.ts +41 -0
  90. package/src/archiver/structs/published.ts +2 -11
  91. package/src/archiver/validation.ts +124 -0
  92. package/src/factory.ts +24 -66
  93. package/src/index.ts +1 -1
  94. package/src/rpc/index.ts +1 -5
  95. package/src/test/mock_archiver.ts +1 -1
  96. package/src/test/mock_l1_to_l2_message_source.ts +14 -3
  97. package/src/test/mock_l2_block_source.ts +158 -13
  98. package/src/test/mock_structs.ts +49 -0
  99. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +0 -12
  100. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +0 -1
  101. package/dest/archiver/kv_archiver_store/nullifier_store.js +0 -73
  102. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
  103. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
  104. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
  105. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -175
  106. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
  107. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +0 -636
  108. package/src/archiver/kv_archiver_store/nullifier_store.ts +0 -97
  109. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
  110. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +0 -801
@@ -7,71 +7,75 @@ import {
7
7
  SerializableContractInstance,
8
8
  SerializableContractInstanceUpdate,
9
9
  } from '@aztec/stdlib/contract';
10
+ import type { UInt64 } from '@aztec/stdlib/types';
10
11
 
11
- type ContractInstanceUpdateKey = [string, number] | [string, number, number];
12
+ type ContractInstanceUpdateKey = [string, string] | [string, string, number];
12
13
 
13
14
  /**
14
15
  * LMDB implementation of the ArchiverDataStore interface.
15
16
  */
16
17
  export class ContractInstanceStore {
17
18
  #contractInstances: AztecAsyncMap<string, Buffer>;
19
+ #contractInstancePublishedAt: AztecAsyncMap<string, number>;
18
20
  #contractInstanceUpdates: AztecAsyncMap<ContractInstanceUpdateKey, Buffer>;
19
21
 
20
- constructor(db: AztecAsyncKVStore) {
22
+ constructor(private db: AztecAsyncKVStore) {
21
23
  this.#contractInstances = db.openMap('archiver_contract_instances');
24
+ this.#contractInstancePublishedAt = db.openMap('archiver_contract_instances_publication_block_number');
22
25
  this.#contractInstanceUpdates = db.openMap('archiver_contract_instance_updates');
23
26
  }
24
27
 
25
- addContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
26
- return this.#contractInstances.set(
27
- contractInstance.address.toString(),
28
- new SerializableContractInstance(contractInstance).toBuffer(),
29
- );
28
+ addContractInstance(contractInstance: ContractInstanceWithAddress, blockNumber: number): Promise<void> {
29
+ return this.db.transactionAsync(async () => {
30
+ await this.#contractInstances.set(
31
+ contractInstance.address.toString(),
32
+ new SerializableContractInstance(contractInstance).toBuffer(),
33
+ );
34
+ await this.#contractInstancePublishedAt.set(contractInstance.address.toString(), blockNumber);
35
+ });
30
36
  }
31
37
 
32
38
  deleteContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
33
- return this.#contractInstances.delete(contractInstance.address.toString());
39
+ return this.db.transactionAsync(async () => {
40
+ await this.#contractInstances.delete(contractInstance.address.toString());
41
+ await this.#contractInstancePublishedAt.delete(contractInstance.address.toString());
42
+ });
34
43
  }
35
44
 
36
- getUpdateKey(contractAddress: AztecAddress, blockNumber: number, logIndex?: number): ContractInstanceUpdateKey {
45
+ getUpdateKey(contractAddress: AztecAddress, timestamp: UInt64, logIndex?: number): ContractInstanceUpdateKey {
37
46
  if (logIndex === undefined) {
38
- return [contractAddress.toString(), blockNumber];
47
+ return [contractAddress.toString(), timestamp.toString()];
39
48
  } else {
40
- return [contractAddress.toString(), blockNumber, logIndex];
49
+ return [contractAddress.toString(), timestamp.toString(), logIndex];
41
50
  }
42
51
  }
43
52
 
44
53
  addContractInstanceUpdate(
45
54
  contractInstanceUpdate: ContractInstanceUpdateWithAddress,
46
- blockNumber: number,
55
+ timestamp: UInt64,
47
56
  logIndex: number,
48
57
  ): Promise<void> {
49
58
  return this.#contractInstanceUpdates.set(
50
- this.getUpdateKey(contractInstanceUpdate.address, blockNumber, logIndex),
59
+ this.getUpdateKey(contractInstanceUpdate.address, timestamp, logIndex),
51
60
  new SerializableContractInstanceUpdate(contractInstanceUpdate).toBuffer(),
52
61
  );
53
62
  }
54
63
 
55
64
  deleteContractInstanceUpdate(
56
65
  contractInstanceUpdate: ContractInstanceUpdateWithAddress,
57
- blockNumber: number,
66
+ timestamp: UInt64,
58
67
  logIndex: number,
59
68
  ): Promise<void> {
60
- return this.#contractInstanceUpdates.delete(
61
- this.getUpdateKey(contractInstanceUpdate.address, blockNumber, logIndex),
62
- );
69
+ return this.#contractInstanceUpdates.delete(this.getUpdateKey(contractInstanceUpdate.address, timestamp, logIndex));
63
70
  }
64
71
 
65
- async getCurrentContractInstanceClassId(
66
- address: AztecAddress,
67
- blockNumber: number,
68
- originalClassId: Fr,
69
- ): Promise<Fr> {
70
- // We need to find the last update before the given block number
72
+ async getCurrentContractInstanceClassId(address: AztecAddress, timestamp: UInt64, originalClassId: Fr): Promise<Fr> {
73
+ // We need to find the last update before the given timestamp
71
74
  const queryResult = await this.#contractInstanceUpdates
72
75
  .valuesAsync({
73
76
  reverse: true,
74
- end: this.getUpdateKey(address, blockNumber + 1), // No update can match this key since it doesn't have a log index. We want the highest key <= blockNumber
77
+ start: this.getUpdateKey(address, 0n), // Make sure we only look at updates for this contract
78
+ end: this.getUpdateKey(address, timestamp + 1n), // No update can match this key since it doesn't have a log index. We want the highest key <= timestamp
75
79
  limit: 1,
76
80
  })
77
81
  .next();
@@ -81,7 +85,7 @@ export class ContractInstanceStore {
81
85
 
82
86
  const serializedUpdate = queryResult.value;
83
87
  const update = SerializableContractInstanceUpdate.fromBuffer(serializedUpdate);
84
- if (blockNumber < update.blockOfChange) {
88
+ if (timestamp < update.timestampOfChange) {
85
89
  return update.prevContractClassId.isZero() ? originalClassId : update.prevContractClassId;
86
90
  }
87
91
  return update.newContractClassId;
@@ -89,7 +93,7 @@ export class ContractInstanceStore {
89
93
 
90
94
  async getContractInstance(
91
95
  address: AztecAddress,
92
- blockNumber: number,
96
+ timestamp: UInt64,
93
97
  ): Promise<ContractInstanceWithAddress | undefined> {
94
98
  const contractInstance = await this.#contractInstances.getAsync(address.toString());
95
99
  if (!contractInstance) {
@@ -99,9 +103,13 @@ export class ContractInstanceStore {
99
103
  const instance = SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
100
104
  instance.currentContractClassId = await this.getCurrentContractInstanceClassId(
101
105
  address,
102
- blockNumber,
106
+ timestamp,
103
107
  instance.originalContractClassId,
104
108
  );
105
109
  return instance;
106
110
  }
111
+
112
+ getContractInstanceDeploymentBlockNumber(address: AztecAddress): Promise<number | undefined> {
113
+ return this.#contractInstancePublishedAt.getAsync(address.toString());
114
+ }
107
115
  }
@@ -1,69 +1,104 @@
1
+ import type { L1BlockId } from '@aztec/ethereum';
1
2
  import type { Fr } from '@aztec/foundation/fields';
2
3
  import { toArray } from '@aztec/foundation/iterable';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
- import type { AztecAsyncKVStore, StoreSize } from '@aztec/kv-store';
5
+ import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
5
6
  import { FunctionSelector } from '@aztec/stdlib/abi';
6
7
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
7
- import type { InBlock, L2Block } from '@aztec/stdlib/block';
8
+ import { type L2Block, L2BlockHash, type ValidateBlockResult } from '@aztec/stdlib/block';
8
9
  import type {
9
10
  ContractClassPublic,
11
+ ContractDataSource,
10
12
  ContractInstanceUpdateWithAddress,
11
13
  ContractInstanceWithAddress,
12
14
  ExecutablePrivateFunctionWithMembershipProof,
13
- UnconstrainedFunctionWithMembershipProof,
15
+ UtilityFunctionWithMembershipProof,
14
16
  } from '@aztec/stdlib/contract';
15
17
  import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
16
18
  import { type LogFilter, PrivateLog, type TxScopedL2Log } from '@aztec/stdlib/logs';
17
- import type { InboxLeaf } from '@aztec/stdlib/messaging';
18
19
  import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
20
+ import type { UInt64 } from '@aztec/stdlib/types';
21
+
22
+ import { join } from 'path';
19
23
 
20
24
  import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
21
- import type { DataRetrieval } from '../structs/data_retrieval.js';
22
- import type { L1Published } from '../structs/published.js';
25
+ import type { InboxMessage } from '../structs/inbox_message.js';
26
+ import type { PublishedL2Block } from '../structs/published.js';
23
27
  import { BlockStore } from './block_store.js';
24
28
  import { ContractClassStore } from './contract_class_store.js';
25
29
  import { ContractInstanceStore } from './contract_instance_store.js';
26
30
  import { LogStore } from './log_store.js';
27
31
  import { MessageStore } from './message_store.js';
28
- import { NullifierStore } from './nullifier_store.js';
32
+
33
+ export const ARCHIVER_DB_VERSION = 3;
34
+ export const MAX_FUNCTION_SIGNATURES = 1000;
35
+ export const MAX_FUNCTION_NAME_LEN = 256;
29
36
 
30
37
  /**
31
38
  * LMDB implementation of the ArchiverDataStore interface.
32
39
  */
33
- export class KVArchiverDataStore implements ArchiverDataStore {
34
- public static readonly SCHEMA_VERSION = 1;
40
+ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSource {
41
+ public static readonly SCHEMA_VERSION = ARCHIVER_DB_VERSION;
35
42
 
36
43
  #blockStore: BlockStore;
37
44
  #logStore: LogStore;
38
- #nullifierStore: NullifierStore;
39
45
  #messageStore: MessageStore;
40
46
  #contractClassStore: ContractClassStore;
41
47
  #contractInstanceStore: ContractInstanceStore;
48
+
42
49
  private functionNames = new Map<string, string>();
43
50
 
44
51
  #log = createLogger('archiver:data-store');
45
52
 
46
- constructor(private db: AztecAsyncKVStore, logsMaxPageSize: number = 1000) {
53
+ constructor(
54
+ private db: AztecAsyncKVStore,
55
+ logsMaxPageSize: number = 1000,
56
+ ) {
47
57
  this.#blockStore = new BlockStore(db);
48
58
  this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize);
49
59
  this.#messageStore = new MessageStore(db);
50
60
  this.#contractClassStore = new ContractClassStore(db);
51
61
  this.#contractInstanceStore = new ContractInstanceStore(db);
52
- this.#nullifierStore = new NullifierStore(db);
53
62
  }
54
63
 
55
- // TODO: These function names are in memory only as they are for development/debugging. They require the full contract
56
- // artifact supplied to the node out of band. This should be reviewed and potentially removed as part of
57
- // the node api cleanup process.
58
- getContractFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
64
+ public transactionAsync<T>(callback: () => Promise<T>): Promise<T> {
65
+ return this.db.transactionAsync(callback);
66
+ }
67
+
68
+ public getBlockNumber(): Promise<number> {
69
+ return this.getSynchedL2BlockNumber();
70
+ }
71
+
72
+ public async getContract(
73
+ address: AztecAddress,
74
+ maybeTimestamp?: UInt64,
75
+ ): Promise<ContractInstanceWithAddress | undefined> {
76
+ const [header] = await this.getBlockHeaders(await this.getBlockNumber(), 1);
77
+ const timestamp = maybeTimestamp ?? header!.globalVariables.timestamp;
78
+ return this.getContractInstance(address, timestamp);
79
+ }
80
+
81
+ public async backupTo(path: string, compress = true): Promise<string> {
82
+ await this.db.backupTo(path, compress);
83
+ return join(path, 'data.mdb');
84
+ }
85
+
86
+ public close() {
87
+ return this.db.close();
88
+ }
89
+
90
+ getDebugFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
59
91
  return Promise.resolve(this.functionNames.get(selector.toString()));
60
92
  }
61
93
 
62
- async registerContractFunctionSignatures(_address: AztecAddress, signatures: string[]): Promise<void> {
94
+ async registerContractFunctionSignatures(signatures: string[]): Promise<void> {
63
95
  for (const sig of signatures) {
96
+ if (this.functionNames.size > MAX_FUNCTION_SIGNATURES) {
97
+ return;
98
+ }
64
99
  try {
65
100
  const selector = await FunctionSelector.fromSignature(sig);
66
- this.functionNames.set(selector.toString(), sig.slice(0, sig.indexOf('(')));
101
+ this.functionNames.set(selector.toString(), sig.slice(0, sig.indexOf('(')).slice(0, MAX_FUNCTION_NAME_LEN));
67
102
  } catch {
68
103
  this.#log.warn(`Failed to parse signature: ${sig}. Ignoring`);
69
104
  }
@@ -78,9 +113,12 @@ export class KVArchiverDataStore implements ArchiverDataStore {
78
113
  return this.#contractClassStore.getContractClassIds();
79
114
  }
80
115
 
81
- async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
82
- const contract = this.#contractInstanceStore.getContractInstance(address, await this.getSynchedL2BlockNumber());
83
- return contract;
116
+ getContractInstance(address: AztecAddress, timestamp: UInt64): Promise<ContractInstanceWithAddress | undefined> {
117
+ return this.#contractInstanceStore.getContractInstance(address, timestamp);
118
+ }
119
+
120
+ getContractInstanceDeploymentBlockNumber(address: AztecAddress): Promise<number | undefined> {
121
+ return this.#contractInstanceStore.getContractInstanceDeploymentBlockNumber(address);
84
122
  }
85
123
 
86
124
  async addContractClasses(
@@ -108,36 +146,35 @@ export class KVArchiverDataStore implements ArchiverDataStore {
108
146
  addFunctions(
109
147
  contractClassId: Fr,
110
148
  privateFunctions: ExecutablePrivateFunctionWithMembershipProof[],
111
- unconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[],
149
+ utilityFunctions: UtilityFunctionWithMembershipProof[],
112
150
  ): Promise<boolean> {
113
- return this.#contractClassStore.addFunctions(contractClassId, privateFunctions, unconstrainedFunctions);
151
+ return this.#contractClassStore.addFunctions(contractClassId, privateFunctions, utilityFunctions);
114
152
  }
115
153
 
116
- async addContractInstances(data: ContractInstanceWithAddress[], _blockNumber: number): Promise<boolean> {
117
- return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c)))).every(Boolean);
154
+ async addContractInstances(data: ContractInstanceWithAddress[], blockNumber: number): Promise<boolean> {
155
+ return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c, blockNumber)))).every(
156
+ Boolean,
157
+ );
118
158
  }
119
159
 
120
160
  async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber: number): Promise<boolean> {
121
161
  return (await Promise.all(data.map(c => this.#contractInstanceStore.deleteContractInstance(c)))).every(Boolean);
122
162
  }
123
163
 
124
- async addContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], blockNumber: number): Promise<boolean> {
164
+ async addContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], timestamp: UInt64): Promise<boolean> {
125
165
  return (
126
166
  await Promise.all(
127
167
  data.map((update, logIndex) =>
128
- this.#contractInstanceStore.addContractInstanceUpdate(update, blockNumber, logIndex),
168
+ this.#contractInstanceStore.addContractInstanceUpdate(update, timestamp, logIndex),
129
169
  ),
130
170
  )
131
171
  ).every(Boolean);
132
172
  }
133
- async deleteContractInstanceUpdates(
134
- data: ContractInstanceUpdateWithAddress[],
135
- blockNumber: number,
136
- ): Promise<boolean> {
173
+ async deleteContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], timestamp: UInt64): Promise<boolean> {
137
174
  return (
138
175
  await Promise.all(
139
176
  data.map((update, logIndex) =>
140
- this.#contractInstanceStore.deleteContractInstanceUpdate(update, blockNumber, logIndex),
177
+ this.#contractInstanceStore.deleteContractInstanceUpdate(update, timestamp, logIndex),
141
178
  ),
142
179
  )
143
180
  ).every(Boolean);
@@ -148,8 +185,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
148
185
  * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
149
186
  * @returns True if the operation is successful.
150
187
  */
151
- addBlocks(blocks: L1Published<L2Block>[]): Promise<boolean> {
152
- return this.#blockStore.addBlocks(blocks);
188
+ addBlocks(blocks: PublishedL2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
189
+ return this.#blockStore.addBlocks(blocks, opts);
153
190
  }
154
191
 
155
192
  /**
@@ -163,6 +200,18 @@ export class KVArchiverDataStore implements ArchiverDataStore {
163
200
  return this.#blockStore.unwindBlocks(from, blocksToUnwind);
164
201
  }
165
202
 
203
+ getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
204
+ return this.#blockStore.getBlock(number);
205
+ }
206
+
207
+ getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined> {
208
+ return this.#blockStore.getBlockByHash(L2BlockHash.fromField(blockHash));
209
+ }
210
+
211
+ getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
212
+ return this.#blockStore.getBlockByArchive(archive);
213
+ }
214
+
166
215
  /**
167
216
  * Gets up to `limit` amount of L2 blocks starting from `from`.
168
217
  *
@@ -170,7 +219,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
170
219
  * @param limit - The number of blocks to return.
171
220
  * @returns The requested L2 blocks
172
221
  */
173
- getBlocks(start: number, limit: number): Promise<L1Published<L2Block>[]> {
222
+ getPublishedBlocks(start: number, limit: number): Promise<PublishedL2Block[]> {
174
223
  return toArray(this.#blockStore.getBlocks(start, limit));
175
224
  }
176
225
 
@@ -185,10 +234,18 @@ export class KVArchiverDataStore implements ArchiverDataStore {
185
234
  return toArray(this.#blockStore.getBlockHeaders(start, limit));
186
235
  }
187
236
 
237
+ getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
238
+ return this.#blockStore.getBlockHeaderByHash(L2BlockHash.fromField(blockHash));
239
+ }
240
+
241
+ getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
242
+ return this.#blockStore.getBlockHeaderByArchive(archive);
243
+ }
244
+
188
245
  /**
189
246
  * Gets a tx effect.
190
- * @param txHash - The txHash of the tx corresponding to the tx effect.
191
- * @returns The requested tx effect (or undefined if not found).
247
+ * @param txHash - The hash of the tx corresponding to the tx effect.
248
+ * @returns The requested tx effect with block info (or undefined if not found).
192
249
  */
193
250
  getTxEffect(txHash: TxHash) {
194
251
  return this.#blockStore.getTxEffect(txHash);
@@ -216,33 +273,19 @@ export class KVArchiverDataStore implements ArchiverDataStore {
216
273
  return this.#logStore.deleteLogs(blocks);
217
274
  }
218
275
 
219
- /**
220
- * Append new nullifiers to the store's list.
221
- * @param blocks - The blocks for which to add the nullifiers.
222
- * @returns True if the operation is successful.
223
- */
224
- addNullifiers(blocks: L2Block[]): Promise<boolean> {
225
- return this.#nullifierStore.addNullifiers(blocks);
226
- }
227
-
228
- deleteNullifiers(blocks: L2Block[]): Promise<boolean> {
229
- return this.#nullifierStore.deleteNullifiers(blocks);
230
- }
231
-
232
- findNullifiersIndexesWithBlock(blockNumber: number, nullifiers: Fr[]): Promise<(InBlock<bigint> | undefined)[]> {
233
- return this.#nullifierStore.findNullifiersIndexesWithBlock(blockNumber, nullifiers);
234
- }
235
-
236
276
  getTotalL1ToL2MessageCount(): Promise<bigint> {
237
277
  return this.#messageStore.getTotalL1ToL2MessageCount();
238
278
  }
239
279
 
280
+ getLastL1ToL2Message(): Promise<InboxMessage | undefined> {
281
+ return this.#messageStore.getLastMessage();
282
+ }
283
+
240
284
  /**
241
285
  * Append L1 to L2 messages to the store.
242
- * @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block.
243
- * @returns True if the operation is successful.
286
+ * @param messages - The L1 to L2 messages to be added to the store.
244
287
  */
245
- addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean> {
288
+ addL1ToL2Messages(messages: InboxMessage[]): Promise<void> {
246
289
  return this.#messageStore.addL1ToL2Messages(messages);
247
290
  }
248
291
 
@@ -260,7 +303,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
260
303
  * @param blockNumber - L2 block number to get messages for.
261
304
  * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
262
305
  */
263
- getL1ToL2Messages(blockNumber: bigint): Promise<Fr[]> {
306
+ getL1ToL2Messages(blockNumber: number): Promise<Fr[]> {
264
307
  return this.#messageStore.getL1ToL2Messages(blockNumber);
265
308
  }
266
309
 
@@ -277,12 +320,13 @@ export class KVArchiverDataStore implements ArchiverDataStore {
277
320
  /**
278
321
  * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
279
322
  * @param tags - The tags to filter the logs by.
323
+ * @param logsPerTag - How many logs to return per tag. Default returns everything
280
324
  * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
281
325
  * that tag.
282
326
  */
283
- getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
327
+ getLogsByTags(tags: Fr[], logsPerTag?: number): Promise<TxScopedL2Log[][]> {
284
328
  try {
285
- return this.#logStore.getLogsByTags(tags);
329
+ return this.#logStore.getLogsByTags(tags, logsPerTag);
286
330
  } catch (err) {
287
331
  return Promise.reject(err);
288
332
  }
@@ -334,8 +378,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
334
378
  await this.#blockStore.setSynchedL1BlockNumber(l1BlockNumber);
335
379
  }
336
380
 
337
- async setMessageSynchedL1BlockNumber(l1BlockNumber: bigint) {
338
- await this.#messageStore.setSynchedL1BlockNumber(l1BlockNumber);
381
+ async setMessageSynchedL1Block(l1Block: L1BlockId) {
382
+ await this.#messageStore.setSynchedL1Block(l1Block);
339
383
  }
340
384
 
341
385
  /**
@@ -344,7 +388,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
344
388
  async getSynchPoint(): Promise<ArchiverL1SynchPoint> {
345
389
  const [blocksSynchedTo, messagesSynchedTo] = await Promise.all([
346
390
  this.#blockStore.getSynchedL1BlockNumber(),
347
- this.#messageStore.getSynchedL1BlockNumber(),
391
+ this.#messageStore.getSynchedL1Block(),
348
392
  ]);
349
393
  return {
350
394
  blocksSynchedTo,
@@ -355,4 +399,24 @@ export class KVArchiverDataStore implements ArchiverDataStore {
355
399
  public estimateSize(): Promise<StoreSize> {
356
400
  return this.db.estimateSize();
357
401
  }
402
+
403
+ public rollbackL1ToL2MessagesToL2Block(targetBlockNumber: number): Promise<void> {
404
+ return this.#messageStore.rollbackL1ToL2MessagesToL2Block(targetBlockNumber);
405
+ }
406
+
407
+ public iterateL1ToL2Messages(range: CustomRange<bigint> = {}): AsyncIterableIterator<InboxMessage> {
408
+ return this.#messageStore.iterateL1ToL2Messages(range);
409
+ }
410
+
411
+ public removeL1ToL2Messages(startIndex: bigint): Promise<void> {
412
+ return this.#messageStore.removeL1ToL2Messages(startIndex);
413
+ }
414
+
415
+ public getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
416
+ return this.#blockStore.getPendingChainValidationStatus();
417
+ }
418
+
419
+ public setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
420
+ return this.#blockStore.setPendingChainValidationStatus(status);
421
+ }
358
422
  }
@@ -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';
@@ -30,7 +30,11 @@ export class LogStore {
30
30
  #logsMaxPageSize: number;
31
31
  #log = createLogger('archiver:log_store');
32
32
 
33
- constructor(private db: AztecAsyncKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) {
33
+ constructor(
34
+ private db: AztecAsyncKVStore,
35
+ private blockStore: BlockStore,
36
+ logsMaxPageSize: number = 1000,
37
+ ) {
34
38
  this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
35
39
  this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
36
40
  this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
@@ -40,7 +44,7 @@ export class LogStore {
40
44
  this.#logsMaxPageSize = logsMaxPageSize;
41
45
  }
42
46
 
43
- #extractTaggedLogsFromPrivate(block: L2Block) {
47
+ #extractTaggedLogs(block: L2Block) {
44
48
  const taggedLogs = new Map<string, Buffer[]>();
45
49
  const dataStartIndexForBlock =
46
50
  block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
@@ -48,68 +52,22 @@ export class LogStore {
48
52
  block.body.txEffects.forEach((txEffect, txIndex) => {
49
53
  const txHash = txEffect.txHash;
50
54
  const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
51
- txEffect.privateLogs.forEach(log => {
55
+
56
+ txEffect.privateLogs.forEach((log, logIndex) => {
52
57
  const tag = log.fields[0];
58
+ this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
59
+
53
60
  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
- );
61
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, logIndex, block.number, log).toBuffer());
63
62
  taggedLogs.set(tag.toString(), currentLogs);
64
63
  });
65
- });
66
- return taggedLogs;
67
- }
68
-
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
- 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
64
 
99
- // The first elt stores lengths as above => tag is in fields[1]
100
- const tag = log.log[1];
65
+ txEffect.publicLogs.forEach((log, logIndex) => {
66
+ const tag = log.fields[0];
67
+ this.#log.debug(`Found public log with tag ${tag.toString()} in block ${block.number}`);
101
68
 
102
- this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
103
69
  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
- );
70
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, logIndex, block.number, log).toBuffer());
113
71
  taggedLogs.set(tag.toString(), currentLogs);
114
72
  });
115
73
  });
@@ -123,14 +81,14 @@ export class LogStore {
123
81
  */
124
82
  addLogs(blocks: L2Block[]): Promise<boolean> {
125
83
  const taggedLogsToAdd = blocks
126
- .flatMap(block => [this.#extractTaggedLogsFromPrivate(block), this.#extractTaggedLogsFromPublic(block)])
84
+ .map(block => this.#extractTaggedLogs(block))
127
85
  .reduce((acc, val) => {
128
86
  for (const [tag, logs] of val.entries()) {
129
87
  const currentLogs = acc.get(tag) ?? [];
130
88
  acc.set(tag, currentLogs.concat(logs));
131
89
  }
132
90
  return acc;
133
- });
91
+ }, new Map());
134
92
  const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
135
93
 
136
94
  return this.db.transactionAsync(async () => {
@@ -204,6 +162,7 @@ export class LogStore {
204
162
  this.#privateLogsByBlock.delete(block.number),
205
163
  this.#publicLogsByBlock.delete(block.number),
206
164
  this.#logTagsByBlock.delete(block.number),
165
+ this.#contractClassLogsByBlock.delete(block.number),
207
166
  ]),
208
167
  ),
209
168
  );
@@ -236,10 +195,13 @@ export class LogStore {
236
195
  * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
237
196
  * that tag.
238
197
  */
239
- async getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
198
+ async getLogsByTags(tags: Fr[], limitPerTag?: number): Promise<TxScopedL2Log[][]> {
199
+ if (limitPerTag !== undefined && limitPerTag <= 0) {
200
+ throw new TypeError('limitPerTag needs to be greater than 0');
201
+ }
240
202
  const logs = await Promise.all(tags.map(tag => this.#logsByTag.getAsync(tag.toString())));
241
203
  return logs.map(
242
- noteLogBuffers => noteLogBuffers?.map(noteLogBuffer => TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? [],
204
+ logBuffers => logBuffers?.slice(0, limitPerTag).map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? [],
243
205
  );
244
206
  }
245
207