@aztec/stdlib 0.77.0-testnet-ignition.30 → 0.77.1

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 (48) hide show
  1. package/dest/contract/interfaces/contract_instance_update.js +1 -1
  2. package/dest/contract/interfaces/node-info.js +2 -2
  3. package/dest/database-version/index.d.ts +2 -0
  4. package/dest/database-version/index.d.ts.map +1 -0
  5. package/dest/database-version/index.js +1 -0
  6. package/dest/database-version/version_manager.d.ts +99 -0
  7. package/dest/database-version/version_manager.d.ts.map +1 -0
  8. package/dest/database-version/version_manager.js +188 -0
  9. package/dest/errors/simulation_error.js +2 -2
  10. package/dest/hash/hash.d.ts +0 -2
  11. package/dest/hash/hash.d.ts.map +1 -1
  12. package/dest/hash/hash.js +0 -11
  13. package/dest/interfaces/world_state.js +3 -3
  14. package/dest/kernel/private_kernel_tail_circuit_public_inputs.d.ts +2 -1
  15. package/dest/kernel/private_kernel_tail_circuit_public_inputs.d.ts.map +1 -1
  16. package/dest/kernel/private_kernel_tail_circuit_public_inputs.js +4 -1
  17. package/dest/logs/contract_class_log.d.ts +4 -0
  18. package/dest/logs/contract_class_log.d.ts.map +1 -1
  19. package/dest/logs/contract_class_log.js +30 -9
  20. package/dest/logs/private_log.d.ts +2 -0
  21. package/dest/logs/private_log.d.ts.map +1 -1
  22. package/dest/logs/private_log.js +9 -0
  23. package/dest/logs/public_log.d.ts +2 -0
  24. package/dest/logs/public_log.d.ts.map +1 -1
  25. package/dest/logs/public_log.js +10 -0
  26. package/dest/messaging/l2_to_l1_message.js +1 -1
  27. package/dest/tx/tx.d.ts.map +1 -1
  28. package/dest/tx/tx.js +4 -6
  29. package/dest/tx/tx_effect.d.ts.map +1 -1
  30. package/dest/tx/tx_effect.js +26 -10
  31. package/dest/tx/tx_receipt.js +1 -1
  32. package/package.json +8 -7
  33. package/src/contract/interfaces/contract_instance_update.ts +1 -1
  34. package/src/contract/interfaces/node-info.ts +2 -2
  35. package/src/database-version/README.md +63 -0
  36. package/src/database-version/index.ts +1 -0
  37. package/src/database-version/version_manager.ts +207 -0
  38. package/src/errors/simulation_error.ts +2 -2
  39. package/src/hash/hash.ts +0 -10
  40. package/src/interfaces/world_state.ts +3 -3
  41. package/src/kernel/private_kernel_tail_circuit_public_inputs.ts +5 -1
  42. package/src/logs/contract_class_log.ts +28 -9
  43. package/src/logs/private_log.ts +11 -0
  44. package/src/logs/public_log.ts +12 -0
  45. package/src/messaging/l2_to_l1_message.ts +1 -1
  46. package/src/tx/tx.ts +7 -7
  47. package/src/tx/tx_effect.ts +29 -9
  48. package/src/tx/tx_receipt.ts +1 -1
package/dest/tx/tx.js CHANGED
@@ -3,10 +3,8 @@ import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection';
3
3
  import { Fr } from '@aztec/foundation/fields';
4
4
  import { BufferReader, serializeArrayOfBufferableToVector, serializeToBuffer } from '@aztec/foundation/serialize';
5
5
  import { z } from 'zod';
6
- import { siloContractClassLog } from '../hash/hash.js';
7
6
  import { PrivateKernelTailCircuitPublicInputs } from '../kernel/private_kernel_tail_circuit_public_inputs.js';
8
7
  import { ContractClassLog } from '../logs/contract_class_log.js';
9
- import { PrivateLog } from '../logs/private_log.js';
10
8
  import { Gossipable } from '../p2p/gossipable.js';
11
9
  import { TopicType, createTopicString } from '../p2p/topic_type.js';
12
10
  import { ClientIvcProof } from '../proofs/client_ivc_proof.js';
@@ -135,9 +133,9 @@ import { TxHash } from './tx_hash.js';
135
133
  const contractClassLogs = [];
136
134
  for (const log of this.contractClassLogs){
137
135
  const hashedLog = await log.hash();
138
- const logHash = logHashes.find((hash)=>hash.value.equals(hashedLog));
136
+ const logHash = logHashes.find((hash)=>hash.value.equals(hashedLog) && hash.contractAddress.equals(log.contractAddress));
139
137
  if (logHash) {
140
- contractClassLogs.push(silo ? await siloContractClassLog(log, logHash.contractAddress) : log);
138
+ contractClassLogs.push(silo ? await log.silo() : log);
141
139
  }
142
140
  }
143
141
  return contractClassLogs;
@@ -167,7 +165,7 @@ import { TxHash } from './tx_hash.js';
167
165
  nullifierCount: this.data.getNonEmptyNullifiers().length,
168
166
  privateLogCount: this.data.getNonEmptyPrivateLogs().length,
169
167
  classRegisteredCount: this.data.getNonEmptyContractClassLogsHashes().length,
170
- contractClassLogSize: this.data.getNonEmptyContractClassLogsLength(),
168
+ contractClassLogSize: this.data.getEmittedContractClassLogsLength(),
171
169
  proofSize: this.clientIvcProof.clientIvcProofBuffer.length,
172
170
  size: this.toBuffer().length,
173
171
  feePaymentMethod: // needsSetup? then we pay through a fee payment contract
@@ -183,7 +181,7 @@ import { TxHash } from './tx_hash.js';
183
181
  * Estimates the tx size based on its private effects. Note that the actual size of the tx
184
182
  * after processing will probably be larger, as public execution would generate more data.
185
183
  */ getEstimatedPrivateTxEffectsSize() {
186
- return this.data.getNonEmptyNoteHashes().length * Fr.SIZE_IN_BYTES + this.data.getNonEmptyNullifiers().length * Fr.SIZE_IN_BYTES + this.data.getNonEmptyPrivateLogs().length * PrivateLog.SIZE_IN_BYTES + this.data.getNonEmptyContractClassLogsLength() * Fr.SIZE_IN_BYTES;
184
+ return this.data.getNonEmptyNoteHashes().length * Fr.SIZE_IN_BYTES + this.data.getNonEmptyNullifiers().length * Fr.SIZE_IN_BYTES + this.data.getEmittedPrivateLogsLength() * Fr.SIZE_IN_BYTES + this.data.getEmittedContractClassLogsLength() * Fr.SIZE_IN_BYTES;
187
185
  }
188
186
  /**
189
187
  * Convenience function to get a hash out of a tx or a tx-like.
@@ -1 +1 @@
1
- {"version":3,"file":"tx_effect.d.ts","sourceRoot":"","sources":["../../src/tx/tx_effect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tx_effect.d.ts","sourceRoot":"","sources":["../../src/tx/tx_effect.ts"],"names":[],"mappings":"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"}
@@ -270,15 +270,26 @@ export class TxEffect {
270
270
  ]).flat());
271
271
  }
272
272
  if (this.privateLogs.length) {
273
- flattened.push(this.toPrefix(PRIVATE_LOGS_PREFIX, this.privateLogs.length * PRIVATE_LOG_SIZE_IN_FIELDS));
274
- flattened.push(...this.privateLogs.map((l)=>l.fields).flat());
273
+ const totalLogLen = this.privateLogs.reduce(// +1 for length prefix
274
+ (total, log)=>total + (log.getEmittedLength() == 0 ? 0 : log.getEmittedLength() + 1), 0);
275
+ flattened.push(this.toPrefix(PRIVATE_LOGS_PREFIX, totalLogLen));
276
+ flattened.push(...this.privateLogs.flatMap((l)=>[
277
+ new Fr(l.getEmittedLength()),
278
+ ...l.getEmittedFields()
279
+ ]));
275
280
  }
276
281
  if (this.publicLogs.length) {
277
- flattened.push(this.toPrefix(PUBLIC_LOGS_PREFIX, this.publicLogs.length * PUBLIC_LOG_SIZE_IN_FIELDS));
278
- flattened.push(...this.publicLogs.map((l)=>l.toFields()).flat());
282
+ const totalLogLen = this.publicLogs.reduce(// +1 for length prefix
283
+ (total, log)=>total + (log.getEmittedLength() == 0 ? 0 : log.getEmittedLength() + 1), 0);
284
+ flattened.push(this.toPrefix(PUBLIC_LOGS_PREFIX, totalLogLen));
285
+ flattened.push(...this.publicLogs.flatMap((l)=>[
286
+ new Fr(l.getEmittedLength()),
287
+ ...l.getEmittedFields()
288
+ ]));
279
289
  }
280
290
  if (this.contractClassLogs.length) {
281
- const totalLogLen = this.contractClassLogs.reduce((total, log)=>total + (log.getEmittedLength() == 0 ? 0 : log.getEmittedLength() + 2), 0);
291
+ const totalLogLen = this.contractClassLogs.reduce(// +2 for length prefix and contract address
292
+ (total, log)=>total + (log.getEmittedLength() == 0 ? 0 : log.getEmittedLength() + 2), 0);
282
293
  flattened.push(this.toPrefix(CONTRACT_CLASS_LOGS_PREFIX, totalLogLen));
283
294
  flattened.push(...this.contractClassLogs.flatMap((l)=>[
284
295
  new Fr(l.getEmittedLength()),
@@ -347,11 +358,13 @@ export class TxEffect {
347
358
  }
348
359
  case PRIVATE_LOGS_PREFIX:
349
360
  {
350
- // TODO(Miranda): squash log 0s in a nested loop and add len prefix?
351
361
  ensureEmpty(effect.privateLogs);
352
362
  const flatPrivateLogs = reader.readFieldArray(length);
353
- for(let i = 0; i < length; i += PRIVATE_LOG_SIZE_IN_FIELDS){
354
- effect.privateLogs.push(PrivateLog.fromFields(flatPrivateLogs.slice(i, i + PRIVATE_LOG_SIZE_IN_FIELDS)));
363
+ let i = 0;
364
+ while(i < length){
365
+ const logLen = flatPrivateLogs[i++].toNumber();
366
+ const logFields = flatPrivateLogs.slice(i, i += logLen);
367
+ effect.privateLogs.push(PrivateLog.fromFields(logFields.concat(new Array(PRIVATE_LOG_SIZE_IN_FIELDS - logLen).fill(Fr.ZERO))));
355
368
  }
356
369
  break;
357
370
  }
@@ -359,8 +372,11 @@ export class TxEffect {
359
372
  {
360
373
  ensureEmpty(effect.publicLogs);
361
374
  const flatPublicLogs = reader.readFieldArray(length);
362
- for(let i = 0; i < length; i += PUBLIC_LOG_SIZE_IN_FIELDS){
363
- effect.publicLogs.push(PublicLog.fromFields(flatPublicLogs.slice(i, i + PUBLIC_LOG_SIZE_IN_FIELDS)));
375
+ let i = 0;
376
+ while(i < length){
377
+ const logLen = flatPublicLogs[i++].toNumber();
378
+ const logFields = flatPublicLogs.slice(i, i += logLen);
379
+ effect.publicLogs.push(PublicLog.fromFields(logFields.concat(new Array(PUBLIC_LOG_SIZE_IN_FIELDS - logLen).fill(Fr.ZERO))));
364
380
  }
365
381
  break;
366
382
  }
@@ -46,7 +46,7 @@ import { TxHash } from './tx_hash.js';
46
46
  status: z.nativeEnum(TxStatus),
47
47
  error: z.string(),
48
48
  blockHash: L2BlockHash.schema.optional(),
49
- blockNumber: z.number().optional(),
49
+ blockNumber: z.number().int().nonnegative().optional(),
50
50
  transactionFee: schemas.BigInt.optional(),
51
51
  debugInfo: DebugInfoSchema.optional()
52
52
  }).transform(TxReceipt.from);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/stdlib",
3
- "version": "0.77.0-testnet-ignition.30",
3
+ "version": "0.77.1",
4
4
  "type": "module",
5
5
  "inherits": [
6
6
  "../package.common.json",
@@ -46,7 +46,8 @@
46
46
  "./interfaces/server": "./dest/interfaces/server.js",
47
47
  "./epoch-helpers": "./dest/epoch-helpers/index.js",
48
48
  "./config": "./dest/config/index.js",
49
- "./testing/jest": "./dest/tests/jest.js"
49
+ "./testing/jest": "./dest/tests/jest.js",
50
+ "./database-version": "./dest/database-version/index.js"
50
51
  },
51
52
  "typedocOptions": {
52
53
  "entryPoints": [
@@ -65,11 +66,11 @@
65
66
  "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
66
67
  },
67
68
  "dependencies": {
68
- "@aztec/bb.js": "0.77.0-testnet-ignition.30",
69
- "@aztec/blob-lib": "0.77.0-testnet-ignition.30",
70
- "@aztec/constants": "0.77.0-testnet-ignition.30",
71
- "@aztec/ethereum": "0.77.0-testnet-ignition.30",
72
- "@aztec/foundation": "0.77.0-testnet-ignition.30",
69
+ "@aztec/bb.js": "0.77.1",
70
+ "@aztec/blob-lib": "0.77.1",
71
+ "@aztec/constants": "0.77.1",
72
+ "@aztec/ethereum": "0.77.1",
73
+ "@aztec/foundation": "0.77.1",
73
74
  "lodash.chunk": "^4.2.0",
74
75
  "lodash.isequal": "^4.5.0",
75
76
  "lodash.omit": "^4.5.0",
@@ -22,7 +22,7 @@ export type ContractInstanceUpdateWithAddress = ContractInstanceUpdate & { addre
22
22
  export const ContractInstanceUpdateSchema = z.object({
23
23
  prevContractClassId: schemas.Fr,
24
24
  newContractClassId: schemas.Fr,
25
- blockOfChange: z.number(),
25
+ blockOfChange: z.number().int().nonnegative(),
26
26
  }) satisfies ZodFor<ContractInstanceUpdate>;
27
27
 
28
28
  export const ContractInstanceUpdateWithAddressSchema = ContractInstanceUpdateSchema.and(
@@ -24,8 +24,8 @@ export interface NodeInfo {
24
24
  export const NodeInfoSchema: ZodFor<NodeInfo> = z
25
25
  .object({
26
26
  nodeVersion: z.string(),
27
- l1ChainId: z.number(),
28
- protocolVersion: z.number(),
27
+ l1ChainId: z.number().int().nonnegative(),
28
+ protocolVersion: z.number().int().nonnegative(),
29
29
  enr: z.string().optional(),
30
30
  l1ContractAddresses: L1ContractAddressesSchema,
31
31
  protocolContractAddresses: ProtocolContractAddressesSchema,
@@ -0,0 +1,63 @@
1
+ # Version Manager
2
+
3
+ The Version Manager helps manage database migrations and version compatibility across different versions of the software.
4
+
5
+ ## Features
6
+
7
+ - Track database schema versions
8
+ - Handle migrations between versions
9
+ - Reset database when necessary (incompatible versions, rollup address change)
10
+ - Simple, clean API for version management
11
+
12
+ ## Usage
13
+
14
+ ```typescript
15
+ import { EthAddress } from '@aztec/foundation/eth-address';
16
+ import { version } from '@aztec/foundation';
17
+
18
+ // Define your current database version
19
+ const DB_VERSION = 3;
20
+ const rollupAddress = EthAddress.fromString('0x1234567890123456789012345678901234567890');
21
+
22
+ // Create version manager for your service
23
+ const versionManager = new version.VersionManager(DB_VERSION, rollupAddress, {
24
+ dataDir: '/path/to/data',
25
+ serviceName: 'my-database',
26
+ });
27
+
28
+ // When initializing your database
29
+ await versionManager.checkVersionAndHandle(
30
+ // Called when a reset is needed
31
+ async () => {
32
+ // Initialize a fresh database
33
+ await initializeFreshDatabase();
34
+ },
35
+ // Called when an upgrade is needed (optional)
36
+ async (oldVersion, newVersion) => {
37
+ if (oldVersion === 1 && newVersion === 2) {
38
+ // Migrate from version 1 to 2
39
+ await migrateV1ToV2();
40
+ } else if (oldVersion === 2 && newVersion === 3) {
41
+ // Migrate from version 2 to 3
42
+ await migrateV2ToV3();
43
+ } else {
44
+ // Unsupported migration path, will fall back to reset
45
+ throw new Error(`Cannot upgrade from ${oldVersion} to ${newVersion}`);
46
+ }
47
+ }
48
+ );
49
+
50
+ // Get the data directory for your service
51
+ const dataDir = versionManager.getDataDirectory();
52
+ ```
53
+
54
+ ## Automatic Reset Conditions
55
+
56
+ The database will be reset in the following conditions:
57
+
58
+ 1. No version information exists (first run)
59
+ 2. Rollup address has changed
60
+ 3. Version has changed and no upgrade callback is provided
61
+ 4. Upgrade callback throws an error
62
+
63
+ When a reset occurs, the data directory is deleted and recreated, and the reset callback is called to initialize a fresh database.
@@ -0,0 +1 @@
1
+ export * from './version_manager.js';
@@ -0,0 +1,207 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { jsonParseWithSchemaSync, jsonStringify } from '@aztec/foundation/json-rpc';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+
5
+ import fs from 'fs/promises';
6
+ import { join } from 'path';
7
+ import { z } from 'zod';
8
+
9
+ /**
10
+ * Represents a version record for storing in a version file.
11
+ */
12
+ export class DatabaseVersion {
13
+ constructor(public readonly schemaVersion: number, public readonly rollupAddress: EthAddress) {}
14
+
15
+ public toBuffer(): Buffer {
16
+ return Buffer.from(jsonStringify(this));
17
+ }
18
+
19
+ public static fromBuffer(buf: Buffer): DatabaseVersion {
20
+ try {
21
+ return jsonParseWithSchemaSync(buf.toString('utf-8'), DatabaseVersion.schema);
22
+ } catch (err) {
23
+ throw new Error(`Failed to deserialize version information: ${err}`, { cause: err });
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Compares two versions. If the rollups addresses are different then it returns undefined
29
+ */
30
+ public cmp(other: DatabaseVersion): undefined | -1 | 0 | 1 {
31
+ if (this.rollupAddress.equals(other.rollupAddress)) {
32
+ if (this.schemaVersion < other.schemaVersion) {
33
+ return -1;
34
+ } else if (this.schemaVersion > other.schemaVersion) {
35
+ return 1;
36
+ } else {
37
+ return 0;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+
43
+ /**
44
+ * Checks if two versions exactly match
45
+ */
46
+ public equals(other: DatabaseVersion): boolean {
47
+ return this.cmp(other) === 0;
48
+ }
49
+
50
+ /**
51
+ * Returns the schema for this class
52
+ */
53
+ static get schema() {
54
+ return z
55
+ .object({
56
+ schemaVersion: z.number(),
57
+ rollupAddress: EthAddress.schema,
58
+ })
59
+ .transform(({ schemaVersion, rollupAddress }) => new DatabaseVersion(schemaVersion, rollupAddress));
60
+ }
61
+
62
+ /**
63
+ * Returns an empty instance
64
+ */
65
+ static empty() {
66
+ return new DatabaseVersion(0, EthAddress.ZERO);
67
+ }
68
+ }
69
+
70
+ export type DatabaseVersionManagerFs = Pick<typeof fs, 'readFile' | 'writeFile' | 'rm' | 'mkdir'>;
71
+
72
+ /**
73
+ * A manager for handling database versioning and migrations.
74
+ * This class will check the version of data in a directory and either
75
+ * reset or upgrade based on version compatibility.
76
+ */
77
+ export class DatabaseVersionManager<T> {
78
+ public static readonly VERSION_FILE = 'db_version';
79
+
80
+ private readonly versionFile: string;
81
+ private readonly currentVersion: DatabaseVersion;
82
+
83
+ /**
84
+ * Create a new version manager
85
+ *
86
+ * @param schemaVersion - The current version of the application
87
+ * @param rollupAddress - The rollup contract address
88
+ * @param dataDirectory - The directory where version information will be stored
89
+ * @param onOpen - A callback to the open the database at the given location
90
+ * @param onUpgrade - An optional callback to upgrade the database before opening. If not provided it will reset the database
91
+ * @param fileSystem - An interface to access the filesystem
92
+ * @param log - Optional custom logger
93
+ * @param options - Configuration options
94
+ */
95
+ constructor(
96
+ schemaVersion: number,
97
+ rollupAddress: EthAddress,
98
+ private dataDirectory: string,
99
+ private onOpen: (dataDir: string) => Promise<T>,
100
+ private onUpgrade?: (dataDir: string, currentVersion: number, latestVersion: number) => Promise<void>,
101
+ private fileSystem: DatabaseVersionManagerFs = fs,
102
+ private log = createLogger(`foundation:version-manager`),
103
+ ) {
104
+ if (schemaVersion < 1) {
105
+ throw new TypeError(`Invalid schema version received: ${schemaVersion}`);
106
+ }
107
+
108
+ this.versionFile = join(this.dataDirectory, DatabaseVersionManager.VERSION_FILE);
109
+ this.currentVersion = new DatabaseVersion(schemaVersion, rollupAddress);
110
+ }
111
+
112
+ /**
113
+ * Checks the stored version against the current version and handles the outcome
114
+ * by either resetting the data directory or calling an upgrade function
115
+ *
116
+ * @param onReset - Function to call when a full reset is needed
117
+ * @param onUpgrade - Function to call when an upgrade is needed
118
+ * @returns True if data was reset, false if upgraded or no change needed
119
+ */
120
+ public async open(): Promise<[T, boolean]> {
121
+ // const storedVersion = await DatabaseVersion.readVersion(this.versionFile);
122
+ let storedVersion: DatabaseVersion;
123
+
124
+ try {
125
+ const versionBuf = await this.fileSystem.readFile(this.versionFile);
126
+ storedVersion = DatabaseVersion.fromBuffer(versionBuf);
127
+ } catch (err) {
128
+ if (err && (err as Error & { code: string }).code === 'ENOENT') {
129
+ storedVersion = DatabaseVersion.empty();
130
+ } else {
131
+ this.log.warn(`Failed to read stored version information: ${err}. Defaulting to empty version`);
132
+ storedVersion = DatabaseVersion.empty();
133
+ }
134
+ }
135
+
136
+ const cmp = storedVersion.cmp(this.currentVersion);
137
+ let needsReset = false;
138
+
139
+ if (typeof cmp === 'number') {
140
+ // only allow forward upgrades
141
+ if (cmp === -1 && this.onUpgrade) {
142
+ this.log.info(`Upgrading from version ${storedVersion.schemaVersion} to ${this.currentVersion.schemaVersion}`);
143
+ try {
144
+ await this.onUpgrade(this.dataDirectory, storedVersion.schemaVersion, this.currentVersion.schemaVersion);
145
+ } catch (error) {
146
+ this.log.error(`Failed to upgrade: ${error}. Falling back to reset.`);
147
+ needsReset = true;
148
+ }
149
+ } else if (cmp !== 0) {
150
+ this.log.info(
151
+ `Can't upgrade from version ${storedVersion.schemaVersion} to ${this.currentVersion}. Resetting database at ${this.dataDirectory}`,
152
+ );
153
+ needsReset = true;
154
+ }
155
+ } else {
156
+ this.log.warn('Rollup address changed, resetting data directory');
157
+ needsReset = true;
158
+ }
159
+
160
+ // Handle reset if needed
161
+ if (needsReset) {
162
+ await this.resetDataDirectory();
163
+ }
164
+
165
+ // Write the current version to disk
166
+ await this.writeVersion();
167
+
168
+ return [await this.onOpen(this.dataDirectory), needsReset];
169
+ }
170
+
171
+ /**
172
+ * Writes the current version to the version file
173
+ */
174
+ private async writeVersion(): Promise<void> {
175
+ // Ensure the directory exists
176
+ await this.fileSystem.mkdir(this.dataDirectory, { recursive: true });
177
+ // Write the version file
178
+ await this.fileSystem.writeFile(this.versionFile, this.currentVersion.toBuffer());
179
+ }
180
+
181
+ /**
182
+ * Resets the data directory by deleting it and recreating it
183
+ */
184
+ private async resetDataDirectory(): Promise<void> {
185
+ try {
186
+ await this.fileSystem.rm(this.dataDirectory, { recursive: true, force: true, maxRetries: 3 });
187
+ await this.fileSystem.mkdir(this.dataDirectory, { recursive: true });
188
+ } catch (err) {
189
+ this.log.error(`Failed to reset data directory: ${err}`);
190
+ throw new Error(`Failed to reset data directory: ${err}`, { cause: err });
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Get the data directory path
196
+ */
197
+ public getDataDirectory(): string {
198
+ return this.dataDirectory;
199
+ }
200
+
201
+ /**
202
+ * Get the current version number
203
+ */
204
+ public getSchemaVersion(): number {
205
+ return this.currentVersion.schemaVersion;
206
+ }
207
+ }
@@ -57,8 +57,8 @@ export interface SourceCodeLocation {
57
57
 
58
58
  const SourceCodeLocationSchema = z.object({
59
59
  filePath: z.string(),
60
- line: z.number(),
61
- column: z.number(),
60
+ line: z.number().int().nonnegative(),
61
+ column: z.number().int().nonnegative(),
62
62
  fileSource: z.string(),
63
63
  locationText: z.string(),
64
64
  });
package/src/hash/hash.ts CHANGED
@@ -3,7 +3,6 @@ import { poseidon2Hash, poseidon2HashWithSeparator, sha256Trunc } from '@aztec/f
3
3
  import { Fr } from '@aztec/foundation/fields';
4
4
 
5
5
  import type { AztecAddress } from '../aztec-address/index.js';
6
- import type { ContractClassLog } from '../logs/index.js';
7
6
  import type { ScopedL2ToL1Message } from '../messaging/l2_to_l1_message.js';
8
7
 
9
8
  /**
@@ -132,12 +131,3 @@ export function siloL2ToL1Message(l2ToL1Message: ScopedL2ToL1Message, version: F
132
131
  ]);
133
132
  return Fr.fromBuffer(sha256Trunc(preimage));
134
133
  }
135
-
136
- export async function siloContractClassLog(log: ContractClassLog, contract: AztecAddress): Promise<ContractClassLog> {
137
- const innerLog = log.clone();
138
- if (contract.isZero()) {
139
- return innerLog;
140
- }
141
- innerLog.fields[0] = await poseidon2Hash([contract, innerLog.fields[0]]);
142
- return innerLog;
143
- }
@@ -76,9 +76,9 @@ export interface WorldStateSynchronizer extends ForkMerkleTreeOperations {
76
76
  }
77
77
 
78
78
  export const WorldStateSyncStatusSchema = z.object({
79
- finalisedBlockNumber: z.number(),
80
- latestBlockNumber: z.number(),
79
+ finalisedBlockNumber: z.number().int().nonnegative(),
80
+ latestBlockNumber: z.number().int().nonnegative(),
81
81
  latestBlockHash: z.string(),
82
- oldestHistoricBlockNumber: z.number(),
82
+ oldestHistoricBlockNumber: z.number().int().nonnegative(),
83
83
  treesAreSynched: z.boolean(),
84
84
  }) satisfies z.ZodType<WorldStateSyncStatus>;
@@ -253,10 +253,14 @@ export class PrivateKernelTailCircuitPublicInputs {
253
253
  return contractClassLogsHashes.filter(h => !h.isEmpty());
254
254
  }
255
255
 
256
- getNonEmptyContractClassLogsLength() {
256
+ getEmittedContractClassLogsLength() {
257
257
  return this.getNonEmptyContractClassLogsHashes().reduce((total, log) => total + log.logHash.length, 0);
258
258
  }
259
259
 
260
+ getEmittedPrivateLogsLength() {
261
+ return this.getNonEmptyPrivateLogs().reduce((total, log) => total + log.getEmittedLength(), 0);
262
+ }
263
+
260
264
  static fromBuffer(buffer: Buffer | BufferReader): PrivateKernelTailCircuitPublicInputs {
261
265
  const reader = BufferReader.asReader(buffer);
262
266
  const isForPublic = reader.readBoolean();
@@ -11,6 +11,8 @@ import { AztecAddress } from '../aztec-address/index.js';
11
11
 
12
12
  export class ContractClassLog {
13
13
  static SIZE_IN_BYTES = Fr.SIZE_IN_BYTES * CONTRACT_CLASS_LOG_SIZE_IN_FIELDS;
14
+ // Keeps original first field pre-siloing. Only set by silo().
15
+ public unsiloedFirstField?: Fr | undefined;
14
16
 
15
17
  // Below line gives error 'Type instantiation is excessively deep and possibly infinite. ts(2589)'
16
18
  // public fields: Tuple<Fr, typeof CONTRACT_CLASS_LOG_DATA_SIZE_IN_FIELDS>
@@ -76,23 +78,40 @@ export class ContractClassLog {
76
78
 
77
79
  getEmittedLength() {
78
80
  // This assumes that we cut trailing zeroes from the end of the log. In ts, these will always be added back.
79
- // Does not include address and length prefix.
81
+ // Does not include address or length prefix.
82
+ // Note: Unlike public logs, address is not included here because it is not included in the log itself.
80
83
  return this.getEmittedFields().length;
81
84
  }
82
85
 
83
86
  getEmittedFields() {
84
- let lastZeroIndex = 0;
85
- for (let i = this.fields.length - 1; i >= 0; i--) {
86
- if (!this.fields[i].isZero() && lastZeroIndex == 0) {
87
- lastZeroIndex = i + 1;
88
- break;
89
- }
87
+ const lastNonZeroIndex = this.fields.findLastIndex(f => !f.isZero());
88
+ return this.fields.slice(0, lastNonZeroIndex + 1);
89
+ }
90
+
91
+ setUnsiloedFirstField(field: Fr) {
92
+ this.unsiloedFirstField = field;
93
+ }
94
+
95
+ toUnsiloed() {
96
+ if (this.unsiloedFirstField) {
97
+ return new ContractClassLog(this.contractAddress, [this.unsiloedFirstField].concat(this.fields.slice(1)));
98
+ } else {
99
+ return this;
100
+ }
101
+ }
102
+
103
+ async silo() {
104
+ const innerLog = this.clone();
105
+ if (innerLog.contractAddress.isZero()) {
106
+ return innerLog;
90
107
  }
91
- return this.fields.slice(0, lastZeroIndex);
108
+ innerLog.setUnsiloedFirstField(innerLog.fields[0]);
109
+ innerLog.fields[0] = await poseidon2Hash([innerLog.contractAddress, innerLog.fields[0]]);
110
+ return innerLog;
92
111
  }
93
112
 
94
113
  async hash() {
95
- return await poseidon2Hash(this.getEmittedFields());
114
+ return await poseidon2Hash(this.fields);
96
115
  }
97
116
 
98
117
  static get schema() {
@@ -42,6 +42,17 @@ export class PrivateLog {
42
42
  return new PrivateLog(makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, Fr.random));
43
43
  }
44
44
 
45
+ getEmittedLength() {
46
+ // This assumes that we cut trailing zeroes from the end of the log. In ts, these will always be added back.
47
+ // Does not include length prefix.
48
+ return this.getEmittedFields().length;
49
+ }
50
+
51
+ getEmittedFields() {
52
+ const lastNonZeroIndex = this.fields.findLastIndex(f => !f.isZero());
53
+ return this.fields.slice(0, lastNonZeroIndex + 1);
54
+ }
55
+
45
56
  static get schema() {
46
57
  return z
47
58
  .object({
@@ -54,6 +54,18 @@ export class PublicLog {
54
54
  return new PublicLog(await AztecAddress.random(), makeTuple(PUBLIC_LOG_DATA_SIZE_IN_FIELDS, Fr.random));
55
55
  }
56
56
 
57
+ getEmittedLength() {
58
+ // This assumes that we cut trailing zeroes from the end of the log. In ts, these will always be added back.
59
+ // Does not include length prefix.
60
+ return this.getEmittedFields().length;
61
+ }
62
+
63
+ getEmittedFields() {
64
+ const fields = this.toFields();
65
+ const lastNonZeroIndex = fields.findLastIndex(f => !f.isZero());
66
+ return fields.slice(0, lastNonZeroIndex + 1);
67
+ }
68
+
57
69
  equals(other: this) {
58
70
  return (
59
71
  this.contractAddress.equals(other.contractAddress) &&
@@ -17,7 +17,7 @@ export class L2ToL1Message {
17
17
  .object({
18
18
  recipient: schemas.EthAddress,
19
19
  content: schemas.Fr,
20
- counter: z.number(),
20
+ counter: z.number().int().nonnegative(),
21
21
  })
22
22
  .transform(({ recipient, content, counter }) => new L2ToL1Message(recipient, content, counter));
23
23
  }