@aztec/stdlib 3.0.0-nightly.20250926 → 3.0.0-nightly.20250927

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 (71) hide show
  1. package/dest/abi/event_metadata_definition.d.ts +8 -0
  2. package/dest/abi/event_metadata_definition.d.ts.map +1 -0
  3. package/dest/abi/event_metadata_definition.js +1 -0
  4. package/dest/abi/index.d.ts +1 -0
  5. package/dest/abi/index.d.ts.map +1 -1
  6. package/dest/abi/index.js +1 -0
  7. package/dest/block/body.d.ts.map +1 -1
  8. package/dest/block/body.js +0 -5
  9. package/dest/contract/contract_class_metadata.d.ts +8 -0
  10. package/dest/contract/contract_class_metadata.d.ts.map +1 -0
  11. package/dest/contract/contract_class_metadata.js +1 -0
  12. package/dest/contract/contract_metadata.d.ts +7 -0
  13. package/dest/contract/contract_metadata.d.ts.map +1 -0
  14. package/dest/contract/contract_metadata.js +1 -0
  15. package/dest/contract/index.d.ts +2 -0
  16. package/dest/contract/index.d.ts.map +1 -1
  17. package/dest/contract/index.js +2 -0
  18. package/dest/interfaces/client.d.ts +0 -1
  19. package/dest/interfaces/client.d.ts.map +1 -1
  20. package/dest/interfaces/client.js +0 -1
  21. package/dest/interfaces/proving-job.d.ts +5 -5
  22. package/dest/interfaces/proving-job.d.ts.map +1 -1
  23. package/dest/interfaces/proving-job.js +3 -3
  24. package/dest/interfaces/server_circuit_prover.d.ts +2 -2
  25. package/dest/interfaces/server_circuit_prover.d.ts.map +1 -1
  26. package/dest/logs/contract_class_log.d.ts +1 -1
  27. package/dest/logs/contract_class_log.d.ts.map +1 -1
  28. package/dest/logs/contract_class_log.js +1 -3
  29. package/dest/rollup/base_rollup_hints.d.ts +2 -10
  30. package/dest/rollup/base_rollup_hints.d.ts.map +1 -1
  31. package/dest/rollup/base_rollup_hints.js +4 -9
  32. package/dest/rollup/index.d.ts +1 -0
  33. package/dest/rollup/index.d.ts.map +1 -1
  34. package/dest/rollup/index.js +1 -0
  35. package/dest/rollup/public_tube_private_inputs.d.ts +4 -2
  36. package/dest/rollup/public_tube_private_inputs.d.ts.map +1 -1
  37. package/dest/rollup/public_tube_private_inputs.js +7 -3
  38. package/dest/rollup/public_tube_public_inputs.d.ts +20 -0
  39. package/dest/rollup/public_tube_public_inputs.d.ts.map +1 -0
  40. package/dest/rollup/public_tube_public_inputs.js +41 -0
  41. package/dest/rollup/public_tx_base_rollup_private_inputs.d.ts +4 -4
  42. package/dest/rollup/public_tx_base_rollup_private_inputs.d.ts.map +1 -1
  43. package/dest/rollup/public_tx_base_rollup_private_inputs.js +2 -2
  44. package/dest/tests/factories.d.ts +2 -0
  45. package/dest/tests/factories.d.ts.map +1 -1
  46. package/dest/tests/factories.js +6 -3
  47. package/dest/tx/tx_effect.d.ts +3 -33
  48. package/dest/tx/tx_effect.d.ts.map +1 -1
  49. package/dest/tx/tx_effect.js +58 -191
  50. package/package.json +8 -8
  51. package/src/abi/event_metadata_definition.ts +8 -0
  52. package/src/abi/index.ts +1 -0
  53. package/src/block/body.ts +1 -7
  54. package/src/contract/contract_class_metadata.ts +8 -0
  55. package/src/contract/contract_metadata.ts +7 -0
  56. package/src/contract/index.ts +2 -0
  57. package/src/interfaces/client.ts +0 -1
  58. package/src/interfaces/proving-job.ts +4 -4
  59. package/src/interfaces/server_circuit_prover.ts +2 -7
  60. package/src/logs/contract_class_log.ts +2 -3
  61. package/src/rollup/base_rollup_hints.ts +0 -7
  62. package/src/rollup/index.ts +1 -0
  63. package/src/rollup/public_tube_private_inputs.ts +10 -3
  64. package/src/rollup/public_tube_public_inputs.ts +52 -0
  65. package/src/rollup/public_tx_base_rollup_private_inputs.ts +3 -3
  66. package/src/tests/factories.ts +6 -6
  67. package/src/tx/tx_effect.ts +59 -204
  68. package/dest/interfaces/pxe.d.ts +0 -235
  69. package/dest/interfaces/pxe.d.ts.map +0 -1
  70. package/dest/interfaces/pxe.js +0 -13
  71. package/src/interfaces/pxe.ts +0 -284
@@ -10,7 +10,6 @@ import { z } from 'zod';
10
10
 
11
11
  import { AvmCircuitInputs } from '../avm/avm.js';
12
12
  import { AvmProvingRequestSchema } from '../avm/avm_proving_request.js';
13
- import { PrivateToPublicKernelCircuitPublicInputs } from '../kernel/private_to_public_kernel_circuit_public_inputs.js';
14
13
  import { ParityBasePrivateInputs } from '../parity/parity_base_private_inputs.js';
15
14
  import { ParityPublicInputs } from '../parity/parity_public_inputs.js';
16
15
  import { ParityRootPrivateInputs } from '../parity/parity_root_private_inputs.js';
@@ -32,8 +31,9 @@ import {
32
31
  CheckpointRootRollupPrivateInputs,
33
32
  CheckpointRootSingleBlockRollupPrivateInputs,
34
33
  } from '../rollup/checkpoint_root_rollup_private_inputs.js';
35
- import { PublicTubePrivateInputs } from '../rollup/index.js';
36
34
  import { PrivateTxBaseRollupPrivateInputs } from '../rollup/private_tx_base_rollup_private_inputs.js';
35
+ import { PublicTubePrivateInputs } from '../rollup/public_tube_private_inputs.js';
36
+ import { PublicTubePublicInputs } from '../rollup/public_tube_public_inputs.js';
37
37
  import { PublicTxBaseRollupPrivateInputs } from '../rollup/public_tx_base_rollup_private_inputs.js';
38
38
  import { RootRollupPrivateInputs } from '../rollup/root_rollup_private_inputs.js';
39
39
  import { RootRollupPublicInputs } from '../rollup/root_rollup_public_inputs.js';
@@ -214,7 +214,7 @@ export const ProvingJobResult = z.discriminatedUnion('type', [
214
214
  z.object({
215
215
  type: z.literal(ProvingRequestType.PUBLIC_TUBE),
216
216
  result: schemaForPublicInputsAndRecursiveProof(
217
- PrivateToPublicKernelCircuitPublicInputs.schema,
217
+ PublicTubePublicInputs.schema,
218
218
  NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
219
219
  ),
220
220
  }),
@@ -326,7 +326,7 @@ export type ProvingJobResult = z.infer<typeof ProvingJobResult>;
326
326
  export type ProvingJobResultsMap = {
327
327
  [ProvingRequestType.PUBLIC_VM]: ProofAndVerificationKey<typeof AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED>;
328
328
  [ProvingRequestType.PUBLIC_TUBE]: PublicInputsAndRecursiveProof<
329
- PrivateToPublicKernelCircuitPublicInputs,
329
+ PublicTubePublicInputs,
330
330
  typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
331
331
  >;
332
332
  [ProvingRequestType.PRIVATE_TX_BASE_ROLLUP]: PublicInputsAndRecursiveProof<
@@ -6,7 +6,6 @@ import type {
6
6
  } from '@aztec/constants';
7
7
 
8
8
  import type { AvmCircuitInputs } from '../avm/avm.js';
9
- import type { PrivateToPublicKernelCircuitPublicInputs } from '../kernel/private_to_public_kernel_circuit_public_inputs.js';
10
9
  import type { ParityBasePrivateInputs } from '../parity/parity_base_private_inputs.js';
11
10
  import type { ParityPublicInputs } from '../parity/parity_public_inputs.js';
12
11
  import type { ParityRootPrivateInputs } from '../parity/parity_root_private_inputs.js';
@@ -28,6 +27,7 @@ import type {
28
27
  } from '../rollup/checkpoint_root_rollup_private_inputs.js';
29
28
  import type { PrivateTxBaseRollupPrivateInputs } from '../rollup/private_tx_base_rollup_private_inputs.js';
30
29
  import type { PublicTubePrivateInputs } from '../rollup/public_tube_private_inputs.js';
30
+ import type { PublicTubePublicInputs } from '../rollup/public_tube_public_inputs.js';
31
31
  import type { PublicTxBaseRollupPrivateInputs } from '../rollup/public_tx_base_rollup_private_inputs.js';
32
32
  import type { RootRollupPrivateInputs } from '../rollup/root_rollup_private_inputs.js';
33
33
  import type { RootRollupPublicInputs } from '../rollup/root_rollup_public_inputs.js';
@@ -64,12 +64,7 @@ export interface ServerCircuitProver {
64
64
  inputs: PublicTubePrivateInputs,
65
65
  signal?: AbortSignal,
66
66
  epochNumber?: number,
67
- ): Promise<
68
- PublicInputsAndRecursiveProof<
69
- PrivateToPublicKernelCircuitPublicInputs,
70
- typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
71
- >
72
- >;
67
+ ): Promise<PublicInputsAndRecursiveProof<PublicTubePublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>>;
73
68
 
74
69
  /**
75
70
  * Creates a proof for the given input.
@@ -133,12 +133,11 @@ export class ContractClassLog {
133
133
  }
134
134
 
135
135
  toBlobFields(): Fr[] {
136
- return [new Fr(this.emittedLength), this.contractAddress.toField()].concat(this.getEmittedFields());
136
+ return [this.contractAddress.toField()].concat(this.getEmittedFields());
137
137
  }
138
138
 
139
- static fromBlobFields(fields: Fr[] | FieldReader) {
139
+ static fromBlobFields(emittedLength: number, fields: Fr[] | FieldReader) {
140
140
  const reader = FieldReader.asReader(fields);
141
- const emittedLength = reader.readU32();
142
141
  const contractAddress = reader.readObject(AztecAddress);
143
142
  const emittedFields = reader.readFieldArray(emittedLength);
144
143
  return new ContractClassLog(
@@ -127,10 +127,6 @@ export class PublicBaseRollupHints {
127
127
  * Preimages to the kernel's contractClassLogsHashes.
128
128
  */
129
129
  public contractClassLogsFields: Tuple<ContractClassLogFields, typeof MAX_CONTRACT_CLASS_LOGS_PER_TX>,
130
- /**
131
- * Identifier of the prover.
132
- */
133
- public proverId: Fr,
134
130
  ) {}
135
131
 
136
132
  static from(fields: FieldsOf<PublicBaseRollupHints>): PublicBaseRollupHints {
@@ -143,7 +139,6 @@ export class PublicBaseRollupHints {
143
139
  fields.lastArchive,
144
140
  fields.anchorBlockArchiveSiblingPath,
145
141
  fields.contractClassLogsFields,
146
- fields.proverId,
147
142
  ] as const;
148
143
  }
149
144
 
@@ -170,7 +165,6 @@ export class PublicBaseRollupHints {
170
165
  reader.readObject(AppendOnlyTreeSnapshot),
171
166
  reader.readArray(ARCHIVE_HEIGHT, Fr),
172
167
  makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, () => reader.readObject(ContractClassLogFields)),
173
- reader.readObject(Fr),
174
168
  );
175
169
  }
176
170
 
@@ -184,7 +178,6 @@ export class PublicBaseRollupHints {
184
178
  AppendOnlyTreeSnapshot.empty(),
185
179
  makeTuple(ARCHIVE_HEIGHT, Fr.zero),
186
180
  makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ContractClassLogFields.empty),
187
- Fr.ZERO,
188
181
  );
189
182
  }
190
183
  }
@@ -13,6 +13,7 @@ export * from './epoch_constant_data.js';
13
13
  export * from './private_tx_base_rollup_private_inputs.js';
14
14
  export * from './public_tx_base_rollup_private_inputs.js';
15
15
  export * from './public_tube_private_inputs.js';
16
+ export * from './public_tube_public_inputs.js';
16
17
  export * from './root_rollup_private_inputs.js';
17
18
  export * from './root_rollup_public_inputs.js';
18
19
  export * from './tree_snapshot_diff_hints.js';
@@ -1,3 +1,4 @@
1
+ import { Fr } from '@aztec/foundation/fields';
1
2
  import { bufferSchemaFor } from '@aztec/foundation/schemas';
2
3
  import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
3
4
  import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
@@ -7,19 +8,25 @@ import { PrivateToPublicKernelCircuitPublicInputs } from '../kernel/private_to_p
7
8
  import { type CivcProofData, ProofData } from '../proofs/proof_data.js';
8
9
 
9
10
  export class PublicTubePrivateInputs {
10
- constructor(public hidingKernelProofData: CivcProofData<PrivateToPublicKernelCircuitPublicInputs>) {}
11
+ constructor(
12
+ public hidingKernelProofData: CivcProofData<PrivateToPublicKernelCircuitPublicInputs>,
13
+ public proverId: Fr,
14
+ ) {}
11
15
 
12
16
  static from(fields: FieldsOf<PublicTubePrivateInputs>) {
13
17
  return new PublicTubePrivateInputs(...PublicTubePrivateInputs.getFields(fields));
14
18
  }
15
19
 
16
20
  static getFields(fields: FieldsOf<PublicTubePrivateInputs>) {
17
- return [fields.hidingKernelProofData] as const;
21
+ return [fields.hidingKernelProofData, fields.proverId] as const;
18
22
  }
19
23
 
20
24
  static fromBuffer(buffer: Buffer | BufferReader) {
21
25
  const reader = BufferReader.asReader(buffer);
22
- return new PublicTubePrivateInputs(ProofData.fromBuffer(reader, PrivateToPublicKernelCircuitPublicInputs));
26
+ return new PublicTubePrivateInputs(
27
+ ProofData.fromBuffer(reader, PrivateToPublicKernelCircuitPublicInputs),
28
+ Fr.fromBuffer(reader),
29
+ );
23
30
  }
24
31
 
25
32
  toBuffer() {
@@ -0,0 +1,52 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import { bufferSchemaFor } from '@aztec/foundation/schemas';
3
+ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
4
+ import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
5
+ import type { FieldsOf } from '@aztec/foundation/types';
6
+
7
+ import { PrivateToPublicKernelCircuitPublicInputs } from '../kernel/private_to_public_kernel_circuit_public_inputs.js';
8
+
9
+ export class PublicTubePublicInputs {
10
+ constructor(
11
+ public privateTail: PrivateToPublicKernelCircuitPublicInputs,
12
+ public proverId: Fr,
13
+ ) {}
14
+
15
+ static from(fields: FieldsOf<PublicTubePublicInputs>) {
16
+ return new PublicTubePublicInputs(...PublicTubePublicInputs.getFields(fields));
17
+ }
18
+
19
+ static getFields(fields: FieldsOf<PublicTubePublicInputs>) {
20
+ return [fields.privateTail, fields.proverId] as const;
21
+ }
22
+
23
+ static fromBuffer(buffer: Buffer | BufferReader) {
24
+ const reader = BufferReader.asReader(buffer);
25
+ return new PublicTubePublicInputs(
26
+ reader.readObject(PrivateToPublicKernelCircuitPublicInputs),
27
+ reader.readObject(Fr),
28
+ );
29
+ }
30
+
31
+ toBuffer() {
32
+ return serializeToBuffer(...PublicTubePublicInputs.getFields(this));
33
+ }
34
+
35
+ static fromString(str: string) {
36
+ return PublicTubePublicInputs.fromBuffer(hexToBuffer(str));
37
+ }
38
+
39
+ toString() {
40
+ return bufferToHex(this.toBuffer());
41
+ }
42
+
43
+ /** Returns a representation for JSON serialization. */
44
+ toJSON() {
45
+ return this.toBuffer();
46
+ }
47
+
48
+ /** Creates an instance from a string. */
49
+ static get schema() {
50
+ return bufferSchemaFor(PublicTubePublicInputs);
51
+ }
52
+ }
@@ -4,14 +4,14 @@ import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
4
4
  import type { FieldsOf } from '@aztec/foundation/types';
5
5
 
6
6
  import { AvmCircuitPublicInputs } from '../avm/avm_circuit_public_inputs.js';
7
- import { PrivateToPublicKernelCircuitPublicInputs } from '../kernel/private_to_public_kernel_circuit_public_inputs.js';
8
7
  import { ProofData, type RollupHonkProofData } from '../proofs/proof_data.js';
9
8
  import type { AvmProofData } from './avm_proof_data.js';
10
9
  import { PublicBaseRollupHints } from './base_rollup_hints.js';
10
+ import { PublicTubePublicInputs } from './public_tube_public_inputs.js';
11
11
 
12
12
  export class PublicTxBaseRollupPrivateInputs {
13
13
  constructor(
14
- public publicTubeProofData: RollupHonkProofData<PrivateToPublicKernelCircuitPublicInputs>,
14
+ public publicTubeProofData: RollupHonkProofData<PublicTubePublicInputs>,
15
15
  public avmProofData: AvmProofData,
16
16
  public hints: PublicBaseRollupHints,
17
17
  ) {}
@@ -27,7 +27,7 @@ export class PublicTxBaseRollupPrivateInputs {
27
27
  static fromBuffer(buffer: Buffer | BufferReader): PublicTxBaseRollupPrivateInputs {
28
28
  const reader = BufferReader.asReader(buffer);
29
29
  return new PublicTxBaseRollupPrivateInputs(
30
- ProofData.fromBuffer(reader, PrivateToPublicKernelCircuitPublicInputs),
30
+ ProofData.fromBuffer(reader, PublicTubePublicInputs),
31
31
  ProofData.fromBuffer(reader, AvmCircuitPublicInputs),
32
32
  reader.readObject(PublicBaseRollupHints),
33
33
  );
@@ -143,6 +143,7 @@ import { CheckpointHeader } from '../rollup/checkpoint_header.js';
143
143
  import { CheckpointRollupPublicInputs, FeeRecipient } from '../rollup/checkpoint_rollup_public_inputs.js';
144
144
  import { EpochConstantData } from '../rollup/epoch_constant_data.js';
145
145
  import { PrivateTxBaseRollupPrivateInputs } from '../rollup/private_tx_base_rollup_private_inputs.js';
146
+ import { PublicTubePublicInputs } from '../rollup/public_tube_public_inputs.js';
146
147
  import { PublicTxBaseRollupPrivateInputs } from '../rollup/public_tx_base_rollup_private_inputs.js';
147
148
  import { RootRollupPublicInputs } from '../rollup/root_rollup_public_inputs.js';
148
149
  import { TreeSnapshotDiffHints } from '../rollup/tree_snapshot_diff_hints.js';
@@ -415,6 +416,10 @@ export function makePrivateToPublicKernelCircuitPublicInputs(seed = 1) {
415
416
  );
416
417
  }
417
418
 
419
+ export function makePublicTubePublicInputs(seed = 1) {
420
+ return new PublicTubePublicInputs(makePrivateToPublicKernelCircuitPublicInputs(seed), fr(seed + 0x1000));
421
+ }
422
+
418
423
  /**
419
424
  * Creates arbitrary public kernel circuit public inputs.
420
425
  * @param seed - The seed to use for generating the kernel circuit public inputs.
@@ -1068,7 +1073,6 @@ function makePublicBaseRollupHints(seed = 1) {
1068
1073
  lastArchive: makeAppendOnlyTreeSnapshot(seed + 0x1000),
1069
1074
  anchorBlockArchiveSiblingPath: makeSiblingPath(seed + 0x2000, ARCHIVE_HEIGHT),
1070
1075
  contractClassLogsFields: makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, makeContractClassLogFields, seed + 0x3000),
1071
- proverId: fr(seed + 0x4000),
1072
1076
  });
1073
1077
  }
1074
1078
 
@@ -1080,11 +1084,7 @@ export function makePrivateTxBaseRollupPrivateInputs(seed = 0) {
1080
1084
  }
1081
1085
 
1082
1086
  export function makePublicTxBaseRollupPrivateInputs(seed = 0) {
1083
- const publicTubeProofData = makeProofData(
1084
- seed,
1085
- makePrivateToPublicKernelCircuitPublicInputs,
1086
- RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
1087
- );
1087
+ const publicTubeProofData = makeProofData(seed, makePublicTubePublicInputs, RECURSIVE_ROLLUP_HONK_PROOF_LENGTH);
1088
1088
  const avmProofData = makeProofData(seed + 0x100, makeAvmCircuitPublicInputs, AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED);
1089
1089
  const hints = makePublicBaseRollupHints(seed + 0x200);
1090
1090
 
@@ -1,24 +1,13 @@
1
- import { TX_EFFECT_PREFIX_BYTE_LENGTH, TX_START_PREFIX_BYTES_LENGTH } from '@aztec/blob-lib/encoding';
1
+ import { decodeTxStartMarker, encodeTxStartMarker, isValidTxStartMarker } from '@aztec/blob-lib/encoding';
2
2
  import {
3
- CONTRACT_CLASS_LOGS_PREFIX,
4
- L2_L1_MSGS_PREFIX,
5
3
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
6
4
  MAX_L2_TO_L1_MSGS_PER_TX,
7
5
  MAX_NOTE_HASHES_PER_TX,
8
6
  MAX_NULLIFIERS_PER_TX,
9
7
  MAX_PRIVATE_LOGS_PER_TX,
10
8
  MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
11
- NOTES_PREFIX,
12
- NULLIFIERS_PREFIX,
13
- PRIVATE_LOGS_PREFIX,
14
- PUBLIC_DATA_UPDATE_REQUESTS_PREFIX,
15
- PUBLIC_LOGS_PREFIX,
16
- REVERT_CODE_PREFIX,
17
- TX_FEE_PREFIX,
18
- TX_START_PREFIX,
19
9
  } from '@aztec/constants';
20
10
  import { type FieldsOf, makeTuple, makeTupleAsync } from '@aztec/foundation/array';
21
- import { toBufferBE } from '@aztec/foundation/bigint-buffer';
22
11
  import { Fr } from '@aztec/foundation/fields';
23
12
  import { type ZodFor, schemas } from '@aztec/foundation/schemas';
24
13
  import {
@@ -248,224 +237,90 @@ export class TxEffect {
248
237
  return new TxEffect(RevertCode.OK, TxHash.zero(), Fr.ZERO, [], [], [], [], [], [], []);
249
238
  }
250
239
 
251
- isEmpty(): boolean {
252
- return this.nullifiers.length === 0;
253
- }
254
-
255
240
  /** Returns a hex representation of the TxEffect object. */
256
241
  toString() {
257
242
  return bufferToHex(this.toBuffer());
258
243
  }
259
244
 
260
245
  /**
261
- * Returns the prefix as used in a blob.
262
- * Used to prefix a 'block' of tx effects with its type and length.
263
- */
264
- private toPrefix(type: number, length: number): Fr {
265
- const buf = Buffer.alloc(4);
266
- buf.writeUint8(type);
267
- buf.writeUInt16BE(length, 2);
268
- return new Fr(buf);
269
- }
270
-
271
- /**
272
- * Decodes the prefix as used in a blob to tx effect type and length.
273
- */
274
- static fromPrefix(prefix: Fr) {
275
- const buf = prefix.toBuffer().subarray(-4);
276
- return { type: buf[0], length: new Fr(buf.subarray(-2)).toNumber() };
277
- }
278
-
279
- /**
280
- * Encodes the first field of a tx effect as used in a blob:
281
- * TX_START_PREFIX | 0 | txlen[0] txlen[1] | 0 | REVERT_CODE_PREFIX | 0 | revert_code
282
- */
283
- private encodeFirstField(length: number, revertCode: RevertCode) {
284
- const lengthBuf = Buffer.alloc(2);
285
- lengthBuf.writeUInt16BE(length, 0);
286
- return new Fr(
287
- Buffer.concat([
288
- toBufferBE(TX_START_PREFIX, TX_START_PREFIX_BYTES_LENGTH),
289
- Buffer.alloc(1),
290
- lengthBuf,
291
- Buffer.alloc(1),
292
- Buffer.from([REVERT_CODE_PREFIX]),
293
- Buffer.alloc(1),
294
- revertCode.toBuffer(),
295
- ]),
296
- );
297
- }
298
-
299
- /**
300
- * Decodes the first field of a tx effect as used in a blob:
301
- * TX_START_PREFIX | 0 | txlen[0] txlen[1] | 0 | REVERT_CODE_PREFIX | 0 | revert_code
302
- * Assumes that isFirstField has been called already.
303
- */
304
- static decodeFirstField(field: Fr) {
305
- const buf = field.toBuffer().subarray(-TX_EFFECT_PREFIX_BYTE_LENGTH);
306
- return {
307
- length: new Fr(buf.subarray(TX_START_PREFIX_BYTES_LENGTH + 1, TX_START_PREFIX_BYTES_LENGTH + 3)).toNumber(),
308
- revertCode: buf[buf.length - 1],
309
- };
310
- }
311
-
312
- /**
313
- * Determines whether a field is the first field of a tx effect
314
- */
315
- static isFirstField(field: Fr) {
316
- const buf = field.toBuffer();
317
- if (
318
- !buf
319
- .subarray(0, field.size - TX_EFFECT_PREFIX_BYTE_LENGTH)
320
- .equals(Buffer.alloc(field.size - TX_EFFECT_PREFIX_BYTE_LENGTH))
321
- ) {
322
- return false;
323
- }
324
- const sliced = buf.subarray(-TX_EFFECT_PREFIX_BYTE_LENGTH);
325
- if (
326
- // Checking we start with the correct prefix...
327
- !new Fr(sliced.subarray(0, TX_START_PREFIX_BYTES_LENGTH)).equals(new Fr(TX_START_PREFIX)) ||
328
- // ...and include the revert code prefix..
329
- sliced[sliced.length - 3] !== REVERT_CODE_PREFIX ||
330
- // ...and the following revert code is valid.
331
- sliced[sliced.length - 1] > 4
332
- ) {
333
- return false;
334
- }
335
- return true;
336
- }
337
-
338
- /**
339
- * Returns a flat packed array of prefixed fields of all tx effects, used for blobs.
246
+ * Returns a flat packed array of fields of all tx effects, to be appended to blobs.
247
+ * Must match the implementation in noir-protocol-circuits/crates/rollup-lib/src/tx_base/components/tx_blob_data.nr
340
248
  */
341
249
  toBlobFields(): Fr[] {
342
- if (this.isEmpty()) {
343
- return [];
344
- }
345
250
  const flattened: Fr[] = [];
346
- // We reassign the first field when we know the length of all effects - see below
251
+
252
+ // We reassign the first field at the end when we know the length of all effects to create the tx start marker.
347
253
  flattened.push(Fr.ZERO);
348
254
 
349
255
  flattened.push(this.txHash.hash);
350
- // TODO: how long should tx fee be? For now, not using toPrefix()
351
- flattened.push(
352
- new Fr(
353
- Buffer.concat([Buffer.from([TX_FEE_PREFIX]), Buffer.alloc(1), this.transactionFee.toBuffer().subarray(3)]),
354
- ),
355
- );
356
- if (this.noteHashes.length) {
357
- flattened.push(this.toPrefix(NOTES_PREFIX, this.noteHashes.length));
358
- flattened.push(...this.noteHashes);
359
- }
360
- if (this.nullifiers.length) {
361
- flattened.push(this.toPrefix(NULLIFIERS_PREFIX, this.nullifiers.length));
362
- flattened.push(...this.nullifiers);
363
- }
364
- if (this.l2ToL1Msgs.length) {
365
- flattened.push(this.toPrefix(L2_L1_MSGS_PREFIX, this.l2ToL1Msgs.length));
366
- flattened.push(...this.l2ToL1Msgs);
367
- }
368
- if (this.publicDataWrites.length) {
369
- flattened.push(this.toPrefix(PUBLIC_DATA_UPDATE_REQUESTS_PREFIX, this.publicDataWrites.length));
370
- flattened.push(...this.publicDataWrites.flatMap(w => w.toBlobFields()));
371
- }
372
- if (this.privateLogs.length) {
373
- flattened.push(this.toPrefix(PRIVATE_LOGS_PREFIX, this.privateLogs.length));
374
- flattened.push(...this.privateLogs.flatMap(l => l.toBlobFields()));
375
- }
376
- if (this.publicLogs.length) {
377
- const flattenedPublicLogs = FlatPublicLogs.fromLogs(this.publicLogs);
378
- flattened.push(this.toPrefix(PUBLIC_LOGS_PREFIX, flattenedPublicLogs.length));
379
- flattened.push(...flattenedPublicLogs.toBlobFields());
380
- }
381
- if (this.contractClassLogs.length) {
382
- flattened.push(this.toPrefix(CONTRACT_CLASS_LOGS_PREFIX, this.contractClassLogs.length));
383
- flattened.push(...this.contractClassLogs.flatMap(l => l.toBlobFields()));
384
- }
256
+ flattened.push(this.transactionFee);
257
+ flattened.push(...this.noteHashes);
258
+ flattened.push(...this.nullifiers);
259
+ flattened.push(...this.l2ToL1Msgs);
260
+ flattened.push(...this.publicDataWrites.flatMap(w => w.toBlobFields()));
261
+ flattened.push(...this.privateLogs.flatMap(l => l.toBlobFields()));
262
+ const flattenedPublicLogs = FlatPublicLogs.fromLogs(this.publicLogs);
263
+ flattened.push(...flattenedPublicLogs.toBlobFields());
264
+ flattened.push(...this.contractClassLogs.flatMap(l => l.toBlobFields()));
265
+
266
+ flattened[0] = encodeTxStartMarker({
267
+ revertCode: this.revertCode.getCode(),
268
+ numBlobFields: flattened.length,
269
+ numNoteHashes: this.noteHashes.length,
270
+ numNullifiers: this.nullifiers.length,
271
+ numL2ToL1Msgs: this.l2ToL1Msgs.length,
272
+ numPublicDataWrites: this.publicDataWrites.length,
273
+ numPrivateLogs: this.privateLogs.length,
274
+ publicLogsLength: flattenedPublicLogs.length,
275
+ contractClassLogLength: this.contractClassLogs[0]?.emittedLength ?? 0,
276
+ });
385
277
 
386
- // The first value appended to each list of fields representing a tx effect is:
387
- // TX_START_PREFIX | 0 | txlen[0] txlen[1] | 0 | REVERT_CODE_PREFIX | 0 | revert_code
388
- // Tx start and len are to aid decomposing/ identifying when we reach a new tx effect
389
- // The remaining bytes are used for revert code, since that only requires 3 bytes
390
- flattened[0] = this.encodeFirstField(flattened.length, this.revertCode);
391
278
  return flattened;
392
279
  }
393
280
 
394
281
  /**
395
- * Decodes a flat packed array of prefixed fields to TxEffect
282
+ * Decodes a flat packed array of fields to TxEffect.
396
283
  */
397
284
  static fromBlobFields(fields: Fr[] | FieldReader) {
398
- const ensureEmpty = <T>(arr: Array<T>) => {
399
- if (arr.length) {
400
- throw new Error('Invalid fields given to TxEffect.fromBlobFields(): Attempted to assign property twice.');
401
- }
402
- };
403
-
404
- const effect = this.empty();
405
285
  const reader = FieldReader.asReader(fields);
406
286
  const totalFields = reader.remainingFields();
407
287
  if (!totalFields) {
408
- return effect;
288
+ throw new Error('Cannot process empty blob fields.');
409
289
  }
410
290
 
411
- const firstField = reader.readField();
412
- if (!this.isFirstField(firstField)) {
413
- throw new Error('Invalid fields given to TxEffect.fromBlobFields(): First field invalid.');
291
+ const txStartMarker = decodeTxStartMarker(reader.readField());
292
+ if (!isValidTxStartMarker(txStartMarker)) {
293
+ throw new Error('Invalid fields given to TxEffect.fromBlobFields(): invalid TxStartMarker');
414
294
  }
415
295
 
416
- const { length: fieldsToProcess, revertCode } = this.decodeFirstField(firstField);
417
- effect.revertCode = RevertCode.fromField(new Fr(revertCode));
418
-
419
- effect.txHash = new TxHash(reader.readField());
420
- // TODO: how long should tx fee be? For now, not using fromPrefix()
421
- const prefixedFee = reader.readField();
422
- // NB: Fr.fromBuffer hangs here if you provide a buffer less than 32 in len
423
- // todo: try new Fr(prefixedFee.toBuffer().subarray(3))
424
- effect.transactionFee = Fr.fromBuffer(Buffer.concat([Buffer.alloc(3), prefixedFee.toBuffer().subarray(3)]));
425
-
426
- let fieldsProcessed = totalFields - reader.remainingFields();
427
- while (fieldsProcessed < fieldsToProcess) {
428
- const { type, length } = this.fromPrefix(reader.readField());
429
- switch (type) {
430
- case NOTES_PREFIX:
431
- ensureEmpty(effect.noteHashes);
432
- effect.noteHashes = reader.readFieldArray(length);
433
- break;
434
- case NULLIFIERS_PREFIX:
435
- ensureEmpty(effect.nullifiers);
436
- effect.nullifiers = reader.readFieldArray(length);
437
- break;
438
- case L2_L1_MSGS_PREFIX:
439
- ensureEmpty(effect.l2ToL1Msgs);
440
- effect.l2ToL1Msgs = reader.readFieldArray(length);
441
- break;
442
- case PUBLIC_DATA_UPDATE_REQUESTS_PREFIX: {
443
- ensureEmpty(effect.publicDataWrites);
444
- effect.publicDataWrites = Array.from({ length }, () => PublicDataWrite.fromBlobFields(reader));
445
- break;
446
- }
447
- case PRIVATE_LOGS_PREFIX: {
448
- ensureEmpty(effect.privateLogs);
449
- effect.privateLogs = Array.from({ length }, () => PrivateLog.fromBlobFields(reader));
450
- break;
451
- }
452
- case PUBLIC_LOGS_PREFIX: {
453
- ensureEmpty(effect.publicLogs);
454
- effect.publicLogs = FlatPublicLogs.fromBlobFields(length, reader).toLogs();
455
- break;
456
- }
457
- case CONTRACT_CLASS_LOGS_PREFIX: {
458
- ensureEmpty(effect.contractClassLogs);
459
- effect.contractClassLogs = Array.from({ length }, () => ContractClassLog.fromBlobFields(reader));
460
- break;
461
- }
462
- case REVERT_CODE_PREFIX:
463
- default:
464
- throw new Error(`Too many fields to decode given to TxEffect.fromBlobFields()`);
465
- }
466
- fieldsProcessed = totalFields - reader.remainingFields();
467
- }
468
- return effect;
296
+ const revertCode = RevertCode.fromField(new Fr(txStartMarker.revertCode));
297
+ const txHash = new TxHash(reader.readField());
298
+ const transactionFee = reader.readField();
299
+ const noteHashes = reader.readFieldArray(txStartMarker.numNoteHashes);
300
+ const nullifiers = reader.readFieldArray(txStartMarker.numNullifiers);
301
+ const l2ToL1Msgs = reader.readFieldArray(txStartMarker.numL2ToL1Msgs);
302
+ const publicDataWrites = Array.from({ length: txStartMarker.numPublicDataWrites }, () =>
303
+ PublicDataWrite.fromBlobFields(reader),
304
+ );
305
+ const privateLogs = Array.from({ length: txStartMarker.numPrivateLogs }, () => PrivateLog.fromBlobFields(reader));
306
+ const publicLogs = FlatPublicLogs.fromBlobFields(txStartMarker.publicLogsLength, reader).toLogs();
307
+ const contractClassLogs =
308
+ txStartMarker.contractClassLogLength > 0
309
+ ? [ContractClassLog.fromBlobFields(txStartMarker.contractClassLogLength, reader)]
310
+ : [];
311
+
312
+ return TxEffect.from({
313
+ revertCode,
314
+ txHash,
315
+ transactionFee,
316
+ noteHashes,
317
+ nullifiers,
318
+ l2ToL1Msgs,
319
+ publicDataWrites,
320
+ privateLogs,
321
+ publicLogs,
322
+ contractClassLogs,
323
+ });
469
324
  }
470
325
 
471
326
  static from(fields: FieldsOf<TxEffect>) {