@aztec/stdlib 0.82.2 → 0.82.3

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 (114) hide show
  1. package/dest/avm/avm.d.ts +919 -1252
  2. package/dest/avm/avm.d.ts.map +1 -1
  3. package/dest/avm/avm.js +138 -111
  4. package/dest/avm/avm_proving_request.d.ts +400 -575
  5. package/dest/avm/avm_proving_request.d.ts.map +1 -1
  6. package/dest/block/l2_block_downloader/l2_block_stream.d.ts +1 -0
  7. package/dest/block/l2_block_downloader/l2_block_stream.d.ts.map +1 -1
  8. package/dest/block/l2_block_downloader/l2_block_stream.js +6 -0
  9. package/dest/database-version/version_manager.d.ts +4 -2
  10. package/dest/database-version/version_manager.d.ts.map +1 -1
  11. package/dest/database-version/version_manager.js +13 -9
  12. package/dest/epoch-helpers/index.d.ts +2 -0
  13. package/dest/epoch-helpers/index.d.ts.map +1 -1
  14. package/dest/epoch-helpers/index.js +3 -0
  15. package/dest/file-store/factory.d.ts +7 -0
  16. package/dest/file-store/factory.d.ts.map +1 -0
  17. package/dest/file-store/factory.js +46 -0
  18. package/dest/file-store/gcs.d.ts +22 -0
  19. package/dest/file-store/gcs.d.ts.map +1 -0
  20. package/dest/file-store/gcs.js +115 -0
  21. package/dest/file-store/http.d.ts +15 -0
  22. package/dest/file-store/http.d.ts.map +1 -0
  23. package/dest/file-store/http.js +53 -0
  24. package/dest/file-store/index.d.ts +3 -0
  25. package/dest/file-store/index.d.ts.map +1 -0
  26. package/dest/file-store/index.js +2 -0
  27. package/dest/file-store/interface.d.ts +24 -0
  28. package/dest/file-store/interface.d.ts.map +1 -0
  29. package/dest/file-store/interface.js +1 -0
  30. package/dest/file-store/local.d.ts +16 -0
  31. package/dest/file-store/local.d.ts.map +1 -0
  32. package/dest/file-store/local.js +40 -0
  33. package/dest/interfaces/aztec-node-admin.d.ts +9 -1
  34. package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
  35. package/dest/interfaces/aztec-node-admin.js +2 -1
  36. package/dest/interfaces/aztec-node.d.ts +3 -0
  37. package/dest/interfaces/aztec-node.d.ts.map +1 -1
  38. package/dest/interfaces/aztec-node.js +2 -0
  39. package/dest/interfaces/p2p.d.ts +2 -0
  40. package/dest/interfaces/p2p.d.ts.map +1 -1
  41. package/dest/interfaces/p2p.js +2 -1
  42. package/dest/interfaces/prover-node.d.ts +4 -0
  43. package/dest/interfaces/prover-node.d.ts.map +1 -1
  44. package/dest/interfaces/prover-node.js +5 -1
  45. package/dest/interfaces/proving-job.d.ts +400 -575
  46. package/dest/interfaces/proving-job.d.ts.map +1 -1
  47. package/dest/interfaces/service.d.ts +3 -0
  48. package/dest/interfaces/service.d.ts.map +1 -1
  49. package/dest/interfaces/service.js +7 -0
  50. package/dest/interfaces/world_state.d.ts +13 -15
  51. package/dest/interfaces/world_state.d.ts.map +1 -1
  52. package/dest/snapshots/download.d.ts +9 -0
  53. package/dest/snapshots/download.d.ts.map +1 -0
  54. package/dest/snapshots/download.js +37 -0
  55. package/dest/snapshots/index.d.ts +4 -0
  56. package/dest/snapshots/index.d.ts.map +1 -0
  57. package/dest/snapshots/index.js +3 -0
  58. package/dest/snapshots/types.d.ts +97 -0
  59. package/dest/snapshots/types.d.ts.map +1 -0
  60. package/dest/snapshots/types.js +27 -0
  61. package/dest/snapshots/upload.d.ts +5 -0
  62. package/dest/snapshots/upload.d.ts.map +1 -0
  63. package/dest/snapshots/upload.js +37 -0
  64. package/dest/tests/factories.d.ts +13 -7
  65. package/dest/tests/factories.d.ts.map +1 -1
  66. package/dest/tests/factories.js +37 -25
  67. package/dest/trees/merkle_tree_id.d.ts +8 -0
  68. package/dest/trees/merkle_tree_id.d.ts.map +1 -1
  69. package/dest/trees/merkle_tree_id.js +10 -0
  70. package/dest/trees/nullifier_leaf.d.ts +11 -2
  71. package/dest/trees/nullifier_leaf.d.ts.map +1 -1
  72. package/dest/trees/nullifier_leaf.js +12 -7
  73. package/dest/trees/nullifier_membership_witness.d.ts +7 -7
  74. package/dest/trees/public_data_leaf.d.ts +13 -0
  75. package/dest/trees/public_data_leaf.d.ts.map +1 -1
  76. package/dest/trees/public_data_leaf.js +6 -0
  77. package/dest/trees/public_data_witness.d.ts +7 -7
  78. package/dest/validators/index.d.ts +3 -0
  79. package/dest/validators/index.d.ts.map +1 -0
  80. package/dest/validators/index.js +1 -0
  81. package/dest/validators/schemas.d.ts +342 -0
  82. package/dest/validators/schemas.d.ts.map +1 -0
  83. package/dest/validators/schemas.js +40 -0
  84. package/dest/validators/types.d.ts +39 -0
  85. package/dest/validators/types.d.ts.map +1 -0
  86. package/dest/validators/types.js +1 -0
  87. package/package.json +11 -7
  88. package/src/avm/avm.ts +131 -106
  89. package/src/block/l2_block_downloader/l2_block_stream.ts +6 -0
  90. package/src/database-version/version_manager.ts +12 -8
  91. package/src/epoch-helpers/index.ts +8 -0
  92. package/src/file-store/factory.ts +61 -0
  93. package/src/file-store/gcs.ts +121 -0
  94. package/src/file-store/http.ts +58 -0
  95. package/src/file-store/index.ts +2 -0
  96. package/src/file-store/interface.ts +19 -0
  97. package/src/file-store/local.ts +46 -0
  98. package/src/interfaces/aztec-node-admin.ts +11 -1
  99. package/src/interfaces/aztec-node.ts +7 -0
  100. package/src/interfaces/p2p.ts +4 -0
  101. package/src/interfaces/prover-node.ts +10 -0
  102. package/src/interfaces/service.ts +13 -0
  103. package/src/interfaces/world_state.ts +17 -15
  104. package/src/snapshots/download.ts +60 -0
  105. package/src/snapshots/index.ts +3 -0
  106. package/src/snapshots/types.ts +58 -0
  107. package/src/snapshots/upload.ts +53 -0
  108. package/src/tests/factories.ts +74 -54
  109. package/src/trees/merkle_tree_id.ts +12 -0
  110. package/src/trees/nullifier_leaf.ts +9 -5
  111. package/src/trees/public_data_leaf.ts +9 -0
  112. package/src/validators/index.ts +3 -0
  113. package/src/validators/schemas.ts +53 -0
  114. package/src/validators/types.ts +37 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/stdlib",
3
- "version": "0.82.2",
3
+ "version": "0.82.3",
4
4
  "type": "module",
5
5
  "inherits": [
6
6
  "../package.common.json",
@@ -46,7 +46,10 @@
46
46
  "./epoch-helpers": "./dest/epoch-helpers/index.js",
47
47
  "./config": "./dest/config/index.js",
48
48
  "./testing/jest": "./dest/tests/jest.js",
49
- "./database-version": "./dest/database-version/index.js"
49
+ "./database-version": "./dest/database-version/index.js",
50
+ "./validators": "./dest/validators/index.js",
51
+ "./file-store": "./dest/file-store/index.js",
52
+ "./snapshots": "./dest/snapshots/index.js"
50
53
  },
51
54
  "typedocOptions": {
52
55
  "entryPoints": [
@@ -65,11 +68,12 @@
65
68
  "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
66
69
  },
67
70
  "dependencies": {
68
- "@aztec/bb.js": "0.82.2",
69
- "@aztec/blob-lib": "0.82.2",
70
- "@aztec/constants": "0.82.2",
71
- "@aztec/ethereum": "0.82.2",
72
- "@aztec/foundation": "0.82.2",
71
+ "@aztec/bb.js": "0.82.3",
72
+ "@aztec/blob-lib": "0.82.3",
73
+ "@aztec/constants": "0.82.3",
74
+ "@aztec/ethereum": "0.82.3",
75
+ "@aztec/foundation": "0.82.3",
76
+ "@google-cloud/storage": "^7.15.0",
73
77
  "lodash.chunk": "^4.2.0",
74
78
  "lodash.isequal": "^4.5.0",
75
79
  "lodash.omit": "^4.5.0",
package/src/avm/avm.ts CHANGED
@@ -1,39 +1,22 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
2
  import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
3
3
  import { schemas } from '@aztec/foundation/schemas';
4
+ import type { IndexedTreeLeaf } from '@aztec/foundation/trees';
4
5
 
5
6
  import { z } from 'zod';
6
7
 
7
8
  import { AztecAddress } from '../aztec-address/index.js';
8
9
  import { PublicKeys } from '../keys/public_keys.js';
9
- import { NullifierLeafPreimage } from '../trees/nullifier_leaf.js';
10
- import { PublicDataTreeLeafPreimage } from '../trees/public_data_leaf.js';
10
+ import { AppendOnlyTreeSnapshot } from '../trees/append_only_tree_snapshot.js';
11
+ import type { MerkleTreeId } from '../trees/merkle_tree_id.js';
12
+ import { NullifierLeaf } from '../trees/nullifier_leaf.js';
13
+ import { PublicDataTreeLeaf } from '../trees/public_data_leaf.js';
11
14
  import { AvmCircuitPublicInputs } from './avm_circuit_public_inputs.js';
12
15
  import { serializeWithMessagePack } from './message_pack.js';
13
16
 
14
- export class AvmEnqueuedCallHint {
15
- constructor(
16
- public readonly msgSender: AztecAddress,
17
- public readonly contractAddress: AztecAddress,
18
- public readonly calldata: Fr[],
19
- public isStaticCall: boolean,
20
- ) {}
21
-
22
- static get schema() {
23
- return z
24
- .object({
25
- msgSender: AztecAddress.schema,
26
- contractAddress: AztecAddress.schema,
27
- calldata: schemas.Fr.array(),
28
- isStaticCall: z.boolean(),
29
- })
30
- .transform(
31
- ({ msgSender, contractAddress, calldata, isStaticCall }) =>
32
- new AvmEnqueuedCallHint(msgSender, contractAddress, calldata, isStaticCall),
33
- );
34
- }
35
- }
36
-
17
+ ////////////////////////////////////////////////////////////////////////////
18
+ // Hints (contracts)
19
+ ////////////////////////////////////////////////////////////////////////////
37
20
  export class AvmContractClassHint {
38
21
  constructor(
39
22
  public readonly classId: Fr,
@@ -115,97 +98,145 @@ export class AvmContractInstanceHint {
115
98
  }
116
99
  }
117
100
 
118
- export class AvmAppendTreeHint {
119
- constructor(public readonly leafIndex: Fr, public readonly value: Fr, public readonly siblingPath: Fr[]) {}
120
-
121
- static get schema() {
122
- return z
123
- .object({
124
- leafIndex: schemas.Fr,
125
- value: schemas.Fr,
126
- siblingPath: schemas.Fr.array(),
127
- })
128
- .transform(({ leafIndex, value, siblingPath }) => new AvmAppendTreeHint(leafIndex, value, siblingPath));
129
- }
130
- }
131
-
132
- export class AvmNullifierWriteTreeHint {
133
- constructor(public lowLeafRead: AvmNullifierReadTreeHint, public readonly insertionPath: Fr[]) {}
101
+ ////////////////////////////////////////////////////////////////////////////
102
+ // Hints (merkle db)
103
+ ////////////////////////////////////////////////////////////////////////////
104
+ // Hint for MerkleTreeDB.getSiblingPath.
105
+ export class AvmGetSiblingPathHint {
106
+ constructor(
107
+ public readonly hintKey: AppendOnlyTreeSnapshot,
108
+ // params
109
+ public readonly treeId: MerkleTreeId,
110
+ public readonly index: bigint,
111
+ // return
112
+ public readonly path: Fr[],
113
+ ) {}
134
114
 
135
115
  static get schema() {
136
116
  return z
137
117
  .object({
138
- lowLeafRead: AvmNullifierReadTreeHint.schema,
139
- insertionPath: schemas.Fr.array(),
118
+ hintKey: AppendOnlyTreeSnapshot.schema,
119
+ treeId: z.number().int().nonnegative(),
120
+ index: schemas.BigInt,
121
+ path: schemas.Fr.array(),
140
122
  })
141
- .transform(({ lowLeafRead, insertionPath }) => new AvmNullifierWriteTreeHint(lowLeafRead, insertionPath));
123
+ .transform(({ hintKey, treeId, index, path }) => new AvmGetSiblingPathHint(hintKey, treeId, index, path));
142
124
  }
143
125
  }
144
126
 
145
- export class AvmNullifierReadTreeHint {
127
+ // Hint for MerkleTreeDB.getPreviousValueIndex.
128
+ export class AvmGetPreviousValueIndexHint {
146
129
  constructor(
147
- public readonly lowLeafPreimage: NullifierLeafPreimage,
148
- public readonly lowLeafIndex: Fr,
149
- public readonly lowLeafSiblingPath: Fr[],
130
+ public readonly hintKey: AppendOnlyTreeSnapshot,
131
+ // params
132
+ public readonly treeId: MerkleTreeId,
133
+ public readonly value: Fr,
134
+ // return
135
+ public readonly index: bigint,
136
+ public readonly alreadyPresent: boolean,
150
137
  ) {}
151
138
 
152
139
  static get schema() {
153
140
  return z
154
141
  .object({
155
- lowLeafPreimage: NullifierLeafPreimage.schema,
156
- lowLeafIndex: schemas.Fr,
157
- lowLeafSiblingPath: schemas.Fr.array(),
142
+ hintKey: AppendOnlyTreeSnapshot.schema,
143
+ treeId: z.number().int().nonnegative(),
144
+ value: schemas.Fr,
145
+ index: schemas.BigInt,
146
+ alreadyPresent: z.boolean(),
158
147
  })
159
148
  .transform(
160
- ({ lowLeafPreimage, lowLeafIndex, lowLeafSiblingPath }) =>
161
- new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafSiblingPath),
149
+ ({ hintKey, treeId, value, index, alreadyPresent }) =>
150
+ new AvmGetPreviousValueIndexHint(hintKey, treeId, value, index, alreadyPresent),
162
151
  );
163
152
  }
164
153
  }
165
154
 
166
- export class AvmPublicDataReadTreeHint {
155
+ // Hint for MerkleTreeDB.getLeafPreimage.
156
+ // NOTE: I need this factory because in order to get hold of the schema, I need an actual instance of the class,
157
+ // having the type doesn't suffice since TS does type erasure in the end.
158
+ function AvmGetLeafPreimageHintFactory<T extends IndexedTreeLeaf>(klass: {
159
+ schema: z.ZodSchema;
160
+ new (...args: any[]): T;
161
+ }) {
162
+ return class AvmGetLeafPreimageHint {
163
+ constructor(
164
+ public readonly hintKey: AppendOnlyTreeSnapshot,
165
+ // params (tree id will be implicit)
166
+ public readonly index: bigint,
167
+ // return
168
+ public readonly leaf: T,
169
+ public readonly nextIndex: bigint,
170
+ public readonly nextValue: Fr,
171
+ ) {}
172
+
173
+ static get schema() {
174
+ return z
175
+ .object({
176
+ hintKey: AppendOnlyTreeSnapshot.schema,
177
+ index: schemas.BigInt,
178
+ leaf: klass.schema,
179
+ nextIndex: schemas.BigInt,
180
+ nextValue: schemas.Fr,
181
+ })
182
+ .transform(
183
+ ({ hintKey, index, leaf, nextIndex, nextValue }) =>
184
+ new AvmGetLeafPreimageHint(hintKey, index, leaf, nextIndex, nextValue),
185
+ );
186
+ }
187
+ };
188
+ }
189
+
190
+ // Note: only supported for PUBLIC_DATA_TREE and NULLIFIER_TREE.
191
+ export class AvmGetLeafPreimageHintPublicDataTree extends AvmGetLeafPreimageHintFactory(PublicDataTreeLeaf) {}
192
+ export class AvmGetLeafPreimageHintNullifierTree extends AvmGetLeafPreimageHintFactory(NullifierLeaf) {}
193
+
194
+ // Hint for MerkleTreeDB.getLeafValue.
195
+ // Note: only supported for NOTE_HASH_TREE and L1_TO_L2_MESSAGE_TREE.
196
+ export class AvmGetLeafValueHint {
167
197
  constructor(
168
- public readonly leafPreimage: PublicDataTreeLeafPreimage,
169
- public readonly leafIndex: Fr,
170
- public readonly siblingPath: Fr[],
198
+ public readonly hintKey: AppendOnlyTreeSnapshot,
199
+ // params
200
+ public readonly treeId: MerkleTreeId,
201
+ public readonly index: bigint,
202
+ // return
203
+ public readonly value: Fr,
171
204
  ) {}
172
205
 
173
- static empty() {
174
- return new AvmPublicDataReadTreeHint(PublicDataTreeLeafPreimage.empty(), Fr.ZERO, []);
175
- }
176
-
177
206
  static get schema() {
178
207
  return z
179
208
  .object({
180
- leafPreimage: PublicDataTreeLeafPreimage.schema,
181
- leafIndex: schemas.Fr,
182
- siblingPath: schemas.Fr.array(),
209
+ hintKey: AppendOnlyTreeSnapshot.schema,
210
+ treeId: z.number().int().nonnegative(),
211
+ index: schemas.BigInt,
212
+ value: schemas.Fr,
183
213
  })
184
- .transform(
185
- ({ leafPreimage, leafIndex, siblingPath }) =>
186
- new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, siblingPath),
187
- );
214
+ .transform(({ hintKey, treeId, index, value }) => new AvmGetLeafValueHint(hintKey, treeId, index, value));
188
215
  }
189
216
  }
190
217
 
191
- export class AvmPublicDataWriteTreeHint {
218
+ ////////////////////////////////////////////////////////////////////////////
219
+ // Hints (other)
220
+ ////////////////////////////////////////////////////////////////////////////
221
+ export class AvmEnqueuedCallHint {
192
222
  constructor(
193
- // To check the current slot has been written to
194
- public readonly lowLeafRead: AvmPublicDataReadTreeHint,
195
- public readonly newLeafPreimage: PublicDataTreeLeafPreimage,
196
- public readonly insertionPath: Fr[],
223
+ public readonly msgSender: AztecAddress,
224
+ public readonly contractAddress: AztecAddress,
225
+ public readonly calldata: Fr[],
226
+ public isStaticCall: boolean,
197
227
  ) {}
198
228
 
199
229
  static get schema() {
200
230
  return z
201
231
  .object({
202
- lowLeafRead: AvmPublicDataReadTreeHint.schema,
203
- newLeafPreimage: PublicDataTreeLeafPreimage.schema,
204
- insertionPath: schemas.Fr.array(),
232
+ msgSender: AztecAddress.schema,
233
+ contractAddress: AztecAddress.schema,
234
+ calldata: schemas.Fr.array(),
235
+ isStaticCall: z.boolean(),
205
236
  })
206
237
  .transform(
207
- ({ lowLeafRead, newLeafPreimage, insertionPath }) =>
208
- new AvmPublicDataWriteTreeHint(lowLeafRead, newLeafPreimage, insertionPath),
238
+ ({ msgSender, contractAddress, calldata, isStaticCall }) =>
239
+ new AvmEnqueuedCallHint(msgSender, contractAddress, calldata, isStaticCall),
209
240
  );
210
241
  }
211
242
  }
@@ -213,16 +244,16 @@ export class AvmPublicDataWriteTreeHint {
213
244
  export class AvmExecutionHints {
214
245
  constructor(
215
246
  public readonly enqueuedCalls: AvmEnqueuedCallHint[] = [],
247
+ // Contract hints.
216
248
  public readonly contractInstances: AvmContractInstanceHint[] = [],
217
249
  public readonly contractClasses: AvmContractClassHint[] = [],
218
250
  public readonly bytecodeCommitments: AvmBytecodeCommitmentHint[] = [],
219
- public readonly publicDataReads: AvmPublicDataReadTreeHint[] = [],
220
- public readonly publicDataWrites: AvmPublicDataWriteTreeHint[] = [],
221
- public readonly nullifierReads: AvmNullifierReadTreeHint[] = [],
222
- public readonly nullifierWrites: AvmNullifierWriteTreeHint[] = [],
223
- public readonly noteHashReads: AvmAppendTreeHint[] = [],
224
- public readonly noteHashWrites: AvmAppendTreeHint[] = [],
225
- public readonly l1ToL2MessageReads: AvmAppendTreeHint[] = [],
251
+ // Merkle DB hints.
252
+ public readonly getSiblingPathHints: AvmGetSiblingPathHint[] = [],
253
+ public readonly getPreviousValueIndexHints: AvmGetPreviousValueIndexHint[] = [],
254
+ public readonly getLeafPreimageHintsPublicDataTree: AvmGetLeafPreimageHintPublicDataTree[] = [],
255
+ public readonly getLeafPreimageHintsNullifierTree: AvmGetLeafPreimageHintNullifierTree[] = [],
256
+ public readonly getLeafValueHints: AvmGetLeafValueHint[] = [],
226
257
  ) {}
227
258
 
228
259
  static empty() {
@@ -236,13 +267,11 @@ export class AvmExecutionHints {
236
267
  contractInstances: AvmContractInstanceHint.schema.array(),
237
268
  contractClasses: AvmContractClassHint.schema.array(),
238
269
  bytecodeCommitments: AvmBytecodeCommitmentHint.schema.array(),
239
- publicDataReads: AvmPublicDataReadTreeHint.schema.array(),
240
- publicDataWrites: AvmPublicDataWriteTreeHint.schema.array(),
241
- nullifierReads: AvmNullifierReadTreeHint.schema.array(),
242
- nullifierWrites: AvmNullifierWriteTreeHint.schema.array(),
243
- noteHashReads: AvmAppendTreeHint.schema.array(),
244
- noteHashWrites: AvmAppendTreeHint.schema.array(),
245
- l1ToL2MessageReads: AvmAppendTreeHint.schema.array(),
270
+ getSiblingPathHints: AvmGetSiblingPathHint.schema.array(),
271
+ getPreviousValueIndexHints: AvmGetPreviousValueIndexHint.schema.array(),
272
+ getLeafPreimageHintsPublicDataTree: AvmGetLeafPreimageHintPublicDataTree.schema.array(),
273
+ getLeafPreimageHintsNullifierTree: AvmGetLeafPreimageHintNullifierTree.schema.array(),
274
+ getLeafValueHints: AvmGetLeafValueHint.schema.array(),
246
275
  })
247
276
  .transform(
248
277
  ({
@@ -250,26 +279,22 @@ export class AvmExecutionHints {
250
279
  contractInstances,
251
280
  contractClasses,
252
281
  bytecodeCommitments,
253
- publicDataReads,
254
- publicDataWrites,
255
- nullifierReads,
256
- nullifierWrites,
257
- noteHashReads,
258
- noteHashWrites,
259
- l1ToL2MessageReads,
282
+ getSiblingPathHints,
283
+ getPreviousValueIndexHints,
284
+ getLeafPreimageHintsPublicDataTree,
285
+ getLeafPreimageHintsNullifierTree,
286
+ getLeafValueHints,
260
287
  }) =>
261
288
  new AvmExecutionHints(
262
289
  enqueuedCalls,
263
290
  contractInstances,
264
291
  contractClasses,
265
292
  bytecodeCommitments,
266
- publicDataReads,
267
- publicDataWrites,
268
- nullifierReads,
269
- nullifierWrites,
270
- noteHashReads,
271
- noteHashWrites,
272
- l1ToL2MessageReads,
293
+ getSiblingPathHints,
294
+ getPreviousValueIndexHints,
295
+ getLeafPreimageHintsPublicDataTree,
296
+ getLeafPreimageHintsNullifierTree,
297
+ getLeafValueHints,
273
298
  ),
274
299
  );
275
300
  }
@@ -9,6 +9,7 @@ import type { PublishedL2Block } from '../published_l2_block.js';
9
9
  export class L2BlockStream {
10
10
  private readonly runningPromise: RunningPromise;
11
11
  private isSyncing = false;
12
+ private hasStarted = false;
12
13
 
13
14
  constructor(
14
15
  private l2BlockSource: Pick<L2BlockSource, 'getPublishedBlocks' | 'getBlockHeader' | 'getL2Tips'>,
@@ -76,7 +77,12 @@ export class L2BlockStream {
76
77
  // If we are just starting, use the starting block number from the options.
77
78
  if (latestBlockNumber === 0 && this.opts.startingBlock !== undefined) {
78
79
  latestBlockNumber = Math.max(this.opts.startingBlock - 1, 0);
80
+ }
81
+
82
+ // Only log this entry once (for sanity)
83
+ if (!this.hasStarted) {
79
84
  this.log.verbose(`Starting sync from block number ${latestBlockNumber}`);
85
+ this.hasStarted = true;
80
86
  }
81
87
 
82
88
  // Request new blocks from the source.
@@ -79,13 +79,15 @@ export class DatabaseVersion {
79
79
 
80
80
  export type DatabaseVersionManagerFs = Pick<typeof fs, 'readFile' | 'writeFile' | 'rm' | 'mkdir'>;
81
81
 
82
+ export const DATABASE_VERSION_FILE_NAME = 'db_version';
83
+
82
84
  /**
83
85
  * A manager for handling database versioning and migrations.
84
86
  * This class will check the version of data in a directory and either
85
87
  * reset or upgrade based on version compatibility.
86
88
  */
87
89
  export class DatabaseVersionManager<T> {
88
- public static readonly VERSION_FILE = 'db_version';
90
+ public static readonly VERSION_FILE = DATABASE_VERSION_FILE_NAME;
89
91
 
90
92
  private readonly versionFile: string;
91
93
  private readonly currentVersion: DatabaseVersion;
@@ -119,6 +121,11 @@ export class DatabaseVersionManager<T> {
119
121
  this.currentVersion = new DatabaseVersion(schemaVersion, rollupAddress);
120
122
  }
121
123
 
124
+ static async writeVersion(version: DatabaseVersion, dataDir: string, fileSystem: DatabaseVersionManagerFs = fs) {
125
+ await fileSystem.mkdir(dataDir, { recursive: true });
126
+ return fileSystem.writeFile(join(dataDir, DatabaseVersionManager.VERSION_FILE), version.toBuffer());
127
+ }
128
+
122
129
  /**
123
130
  * Checks the stored version against the current version and handles the outcome
124
131
  * by either resetting the data directory or calling an upgrade function
@@ -163,7 +170,7 @@ export class DatabaseVersionManager<T> {
163
170
  needsReset = true;
164
171
  }
165
172
  } else {
166
- this.log.warn('Rollup address changed, resetting data directory');
173
+ this.log.warn('Rollup address changed, resetting data directory', { versionFile: this.versionFile });
167
174
  needsReset = true;
168
175
  }
169
176
 
@@ -181,17 +188,14 @@ export class DatabaseVersionManager<T> {
181
188
  /**
182
189
  * Writes the current version to the version file
183
190
  */
184
- private async writeVersion(): Promise<void> {
185
- // Ensure the directory exists
186
- await this.fileSystem.mkdir(this.dataDirectory, { recursive: true });
187
- // Write the version file
188
- await this.fileSystem.writeFile(this.versionFile, this.currentVersion.toBuffer());
191
+ public writeVersion(dir?: string): Promise<void> {
192
+ return DatabaseVersionManager.writeVersion(this.currentVersion, dir ?? this.dataDirectory, this.fileSystem);
189
193
  }
190
194
 
191
195
  /**
192
196
  * Resets the data directory by deleting it and recreating it
193
197
  */
194
- private async resetDataDirectory(): Promise<void> {
198
+ public async resetDataDirectory(): Promise<void> {
195
199
  try {
196
200
  await this.fileSystem.rm(this.dataDirectory, { recursive: true, force: true, maxRetries: 3 });
197
201
  await this.fileSystem.mkdir(this.dataDirectory, { recursive: true });
@@ -26,6 +26,14 @@ export const L1RollupConstantsSchema = z.object({
26
26
  ethereumSlotDuration: z.number(),
27
27
  }) satisfies ZodFor<L1RollupConstants>;
28
28
 
29
+ /** Returns the timestamp for a given L2 slot. */
30
+ export function getTimestampForSlot(
31
+ slot: bigint,
32
+ constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
33
+ ) {
34
+ return constants.l1GenesisTime + slot * BigInt(constants.slotDuration);
35
+ }
36
+
29
37
  /** Returns the slot number for a given timestamp. */
30
38
  export function getSlotAtTimestamp(ts: bigint, constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>) {
31
39
  return ts < constants.l1GenesisTime ? 0n : (ts - constants.l1GenesisTime) / BigInt(constants.slotDuration);
@@ -0,0 +1,61 @@
1
+ import { type Logger, createLogger } from '@aztec/foundation/log';
2
+
3
+ import { GoogleCloudFileStore } from './gcs.js';
4
+ import { HttpFileStore } from './http.js';
5
+ import type { FileStore, ReadOnlyFileStore } from './interface.js';
6
+ import { LocalFileStore } from './local.js';
7
+
8
+ const supportedExamples = [
9
+ `gs://bucket-name/path/to/store`,
10
+ `file:///absolute/local/path/to/store`,
11
+ `https://host/path`,
12
+ ];
13
+
14
+ export async function createFileStore(config: string, logger?: Logger): Promise<FileStore>;
15
+ export async function createFileStore(config: undefined, logger?: Logger): Promise<undefined>;
16
+ export async function createFileStore(
17
+ config: string | undefined,
18
+ logger = createLogger('stdlib:file-store'),
19
+ ): Promise<FileStore | undefined> {
20
+ if (config === undefined) {
21
+ return undefined;
22
+ } else if (config.startsWith('file://')) {
23
+ const url = new URL(config);
24
+ if (url.host) {
25
+ throw new Error(`File store URL only supports local paths (got host ${url.host} from ${config})`);
26
+ }
27
+ const path = url.pathname;
28
+ logger.info(`Creating local file file store at ${path}`);
29
+ return new LocalFileStore(path);
30
+ } else if (config.startsWith('gs://')) {
31
+ try {
32
+ const url = new URL(config);
33
+ const bucket = url.host;
34
+ const path = url.pathname.replace(/^\/+/, '');
35
+ logger.info(`Creating google cloud file store at ${bucket} ${path}`);
36
+ const store = new GoogleCloudFileStore(bucket, path);
37
+ await store.checkCredentials();
38
+ return store;
39
+ } catch (err) {
40
+ throw new Error(`Invalid google cloud store definition: '${config}'.`);
41
+ }
42
+ } else {
43
+ throw new Error(`Unknown file store config: '${config}'. Supported values are ${supportedExamples.join(', ')}.`);
44
+ }
45
+ }
46
+
47
+ export async function createReadOnlyFileStore(config: string, logger?: Logger): Promise<ReadOnlyFileStore>;
48
+ export async function createReadOnlyFileStore(config: undefined, logger?: Logger): Promise<undefined>;
49
+ export async function createReadOnlyFileStore(
50
+ config: string | undefined,
51
+ logger = createLogger('stdlib:file-store'),
52
+ ): Promise<ReadOnlyFileStore | undefined> {
53
+ if (config === undefined) {
54
+ return undefined;
55
+ } else if (config.startsWith('http://') || config.startsWith('https://')) {
56
+ logger.info(`Creating read-only HTTP file store at ${config}`);
57
+ return new HttpFileStore(config, logger);
58
+ } else {
59
+ return await createFileStore(config, logger);
60
+ }
61
+ }
@@ -0,0 +1,121 @@
1
+ import { type Logger, createLogger } from '@aztec/foundation/log';
2
+
3
+ import { File, Storage, type UploadOptions } from '@google-cloud/storage';
4
+ import { join } from 'path';
5
+
6
+ import type { FileStore, FileStoreSaveOptions } from './interface.js';
7
+
8
+ export class GoogleCloudFileStore implements FileStore {
9
+ private readonly storage: Storage;
10
+
11
+ constructor(
12
+ private readonly bucketName: string,
13
+ private readonly basePath: string,
14
+ private readonly log: Logger = createLogger('stdlib:gcs-file-store'),
15
+ ) {
16
+ this.storage = new Storage();
17
+ }
18
+
19
+ public async checkCredentials() {
20
+ await this.storage.getServiceAccount();
21
+ }
22
+
23
+ public async save(
24
+ path: string,
25
+ data: Buffer,
26
+ opts: FileStoreSaveOptions = { public: false, metadata: {}, compress: false },
27
+ ): Promise<string> {
28
+ const fullPath = this.getFullPath(path);
29
+ try {
30
+ const bucket = this.storage.bucket(this.bucketName);
31
+ const file = bucket.file(fullPath);
32
+ await file.save(data, { metadata: opts.metadata, gzip: opts.compress });
33
+ return this.handleUploadedFile(file, opts);
34
+ } catch (err: any) {
35
+ throw new Error(`Error saving file to google cloud storage at ${fullPath}: ${err.message ?? err}`);
36
+ }
37
+ }
38
+
39
+ public async upload(
40
+ destPath: string,
41
+ srcPath: string,
42
+ opts: FileStoreSaveOptions = { compress: true, public: false, metadata: {} },
43
+ ): Promise<string> {
44
+ const fullPath = this.getFullPath(destPath);
45
+ try {
46
+ const bucket = this.storage.bucket(this.bucketName);
47
+ const file = bucket.file(fullPath);
48
+ const uploadOpts: UploadOptions = {
49
+ destination: file,
50
+ gzip: opts.compress,
51
+ metadata: opts.metadata,
52
+ };
53
+ await bucket.upload(srcPath, uploadOpts);
54
+ return this.handleUploadedFile(file, opts);
55
+ } catch (err: any) {
56
+ throw new Error(`Error saving file to google cloud storage at ${fullPath}: ${err.message ?? err}`);
57
+ }
58
+ }
59
+
60
+ private async handleUploadedFile(file: File, opts: { public?: boolean }): Promise<string> {
61
+ if (opts.public) {
62
+ try {
63
+ if (!(await file.isPublic())) {
64
+ await file.makePublic();
65
+ }
66
+ } catch (err: any) {
67
+ this.log.warn(
68
+ `Error making file ${file.name} public: ${
69
+ err.message ?? err
70
+ }. This is expected if we handle public access at the bucket level.`,
71
+ );
72
+ }
73
+ return file.publicUrl().replaceAll('%2F', '/');
74
+ } else {
75
+ return file.cloudStorageURI.toString();
76
+ }
77
+ }
78
+
79
+ public async read(pathOrUrlStr: string): Promise<Buffer> {
80
+ const file = await this.getFileObject(pathOrUrlStr);
81
+ const contents = await file.download();
82
+ return contents[0];
83
+ }
84
+
85
+ public async download(pathOrUrlStr: string, destPath: string): Promise<void> {
86
+ const file = await this.getFileObject(pathOrUrlStr);
87
+ await file.download({ destination: destPath });
88
+ }
89
+
90
+ public async exists(pathOrUrlStr: string): Promise<boolean> {
91
+ const { bucketName, fullPath } = this.getBucketAndFullPath(pathOrUrlStr);
92
+ const bucket = this.storage.bucket(bucketName);
93
+ const file = bucket.file(fullPath);
94
+ const [exists] = await file.exists();
95
+ return exists;
96
+ }
97
+
98
+ private async getFileObject(pathOrUrlStr: string): Promise<File> {
99
+ const { bucketName, fullPath } = this.getBucketAndFullPath(pathOrUrlStr);
100
+ const bucket = this.storage.bucket(bucketName);
101
+ const file = bucket.file(fullPath);
102
+ if (!(await file.exists())) {
103
+ throw new Error(`File at ${fullPath} in gcs bucket ${bucketName} does not exist`);
104
+ }
105
+ return file;
106
+ }
107
+
108
+ private getBucketAndFullPath(pathOrUrlStr: string): { bucketName: string; fullPath: string } {
109
+ if (URL.canParse(pathOrUrlStr)) {
110
+ const url = new URL(pathOrUrlStr);
111
+ // Note that we accept reading from anywhere, not just our bucket
112
+ return { fullPath: url.pathname.replace(/^\/+/, ''), bucketName: url.host };
113
+ } else {
114
+ return { fullPath: this.getFullPath(pathOrUrlStr), bucketName: this.bucketName };
115
+ }
116
+ }
117
+
118
+ private getFullPath(path: string): string {
119
+ return this.basePath && this.basePath.length > 0 ? join(this.basePath, path) : path;
120
+ }
121
+ }