@aztec/stdlib 3.0.0-nightly.20251114 → 3.0.0-nightly.20251118

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 (86) hide show
  1. package/dest/avm/avm.d.ts +139 -45
  2. package/dest/avm/avm.d.ts.map +1 -1
  3. package/dest/avm/avm.js +58 -19
  4. package/dest/avm/avm_proving_request.d.ts +21 -21
  5. package/dest/avm/public_data_write.d.ts +1 -1
  6. package/dest/avm/public_data_write.d.ts.map +1 -1
  7. package/dest/avm/revert_code.d.ts +2 -1
  8. package/dest/avm/revert_code.d.ts.map +1 -1
  9. package/dest/avm/revert_code.js +8 -8
  10. package/dest/block/body.d.ts +3 -6
  11. package/dest/block/body.d.ts.map +1 -1
  12. package/dest/block/body.js +6 -25
  13. package/dest/block/index.d.ts +1 -0
  14. package/dest/block/index.d.ts.map +1 -1
  15. package/dest/block/index.js +1 -0
  16. package/dest/block/l2_block.d.ts +5 -0
  17. package/dest/block/l2_block.d.ts.map +1 -1
  18. package/dest/block/l2_block.js +34 -4
  19. package/dest/block/l2_block_new.d.ts +97 -0
  20. package/dest/block/l2_block_new.d.ts.map +1 -0
  21. package/dest/block/l2_block_new.js +113 -0
  22. package/dest/checkpoint/checkpoint.d.ts +108 -0
  23. package/dest/checkpoint/checkpoint.d.ts.map +1 -0
  24. package/dest/checkpoint/checkpoint.js +39 -0
  25. package/dest/checkpoint/index.d.ts +1 -1
  26. package/dest/checkpoint/index.d.ts.map +1 -1
  27. package/dest/checkpoint/index.js +1 -1
  28. package/dest/interfaces/proving-job.d.ts +21 -21
  29. package/dest/logs/private_log.d.ts +1 -1
  30. package/dest/logs/private_log.d.ts.map +1 -1
  31. package/dest/logs/private_log.js +2 -5
  32. package/dest/messaging/in_hash.d.ts +4 -0
  33. package/dest/messaging/in_hash.d.ts.map +1 -0
  34. package/dest/messaging/in_hash.js +15 -0
  35. package/dest/messaging/index.d.ts +2 -0
  36. package/dest/messaging/index.d.ts.map +1 -1
  37. package/dest/messaging/index.js +2 -0
  38. package/dest/messaging/out_hash.d.ts +5 -0
  39. package/dest/messaging/out_hash.d.ts.map +1 -0
  40. package/dest/messaging/out_hash.js +28 -0
  41. package/dest/rollup/checkpoint_constant_data.d.ts +16 -0
  42. package/dest/rollup/checkpoint_constant_data.d.ts.map +1 -1
  43. package/dest/rollup/checkpoint_constant_data.js +17 -0
  44. package/dest/tests/factories.d.ts +21 -25
  45. package/dest/tests/factories.d.ts.map +1 -1
  46. package/dest/tests/factories.js +24 -121
  47. package/dest/tests/mocks.d.ts +17 -1
  48. package/dest/tests/mocks.d.ts.map +1 -1
  49. package/dest/tests/mocks.js +108 -4
  50. package/dest/tx/partial_state_reference.d.ts +3 -0
  51. package/dest/tx/partial_state_reference.d.ts.map +1 -1
  52. package/dest/tx/partial_state_reference.js +10 -0
  53. package/dest/tx/state_reference.d.ts +3 -0
  54. package/dest/tx/state_reference.d.ts.map +1 -1
  55. package/dest/tx/state_reference.js +9 -0
  56. package/dest/tx/tx_effect.d.ts +9 -6
  57. package/dest/tx/tx_effect.d.ts.map +1 -1
  58. package/dest/tx/tx_effect.js +53 -57
  59. package/dest/vks/verification_key.d.ts +9 -0
  60. package/dest/vks/verification_key.d.ts.map +1 -1
  61. package/dest/vks/verification_key.js +20 -0
  62. package/package.json +8 -8
  63. package/src/avm/avm.ts +66 -28
  64. package/src/avm/public_data_write.ts +1 -1
  65. package/src/avm/revert_code.ts +9 -8
  66. package/src/block/body.ts +7 -32
  67. package/src/block/index.ts +1 -0
  68. package/src/block/l2_block.ts +33 -2
  69. package/src/block/l2_block_new.ts +143 -0
  70. package/src/checkpoint/checkpoint.ts +46 -0
  71. package/src/checkpoint/index.ts +1 -1
  72. package/src/logs/private_log.ts +2 -3
  73. package/src/messaging/in_hash.ts +15 -0
  74. package/src/messaging/index.ts +2 -0
  75. package/src/messaging/out_hash.ts +36 -0
  76. package/src/rollup/checkpoint_constant_data.ts +20 -0
  77. package/src/tests/factories.ts +109 -211
  78. package/src/tests/mocks.ts +196 -4
  79. package/src/tx/partial_state_reference.ts +9 -0
  80. package/src/tx/state_reference.ts +9 -0
  81. package/src/tx/tx_effect.ts +61 -67
  82. package/src/vks/verification_key.ts +25 -0
  83. package/dest/checkpoint/checkpoint_body.d.ts +0 -4
  84. package/dest/checkpoint/checkpoint_body.d.ts.map +0 -1
  85. package/dest/checkpoint/checkpoint_body.js +0 -9
  86. package/src/checkpoint/checkpoint_body.ts +0 -10
package/src/avm/avm.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_MAX_DEBUG_LOG_MEMORY_READS } from '@aztec/constants';
1
2
  import { Fr } from '@aztec/foundation/fields';
2
3
  import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
3
4
 
@@ -666,9 +667,9 @@ export class AvmRevertCheckpointHint {
666
667
  }
667
668
  }
668
669
 
669
- export class AvmContractDBCreateCheckpointHint extends AvmCheckpointActionNoStateChangeHint {}
670
- export class AvmContractDBCommitCheckpointHint extends AvmCheckpointActionNoStateChangeHint {}
671
- export class AvmContractDBRevertCheckpointHint extends AvmCheckpointActionNoStateChangeHint {}
670
+ export class AvmContractDbCreateCheckpointHint extends AvmCheckpointActionNoStateChangeHint {}
671
+ export class AvmContractDbCommitCheckpointHint extends AvmCheckpointActionNoStateChangeHint {}
672
+ export class AvmContractDbRevertCheckpointHint extends AvmCheckpointActionNoStateChangeHint {}
672
673
 
673
674
  ////////////////////////////////////////////////////////////////////////////
674
675
  // Hints (other)
@@ -858,9 +859,9 @@ export class AvmExecutionHints {
858
859
  public readonly contractClasses: AvmContractClassHint[] = [],
859
860
  public readonly bytecodeCommitments: AvmBytecodeCommitmentHint[] = [],
860
861
  public readonly debugFunctionNames: AvmDebugFunctionNameHint[] = [],
861
- public readonly contractDBCreateCheckpointHints: AvmContractDBCreateCheckpointHint[] = [],
862
- public readonly contractDBCommitCheckpointHints: AvmContractDBCommitCheckpointHint[] = [],
863
- public readonly contractDBRevertCheckpointHints: AvmContractDBRevertCheckpointHint[] = [],
862
+ public readonly contractDbCreateCheckpointHints: AvmContractDbCreateCheckpointHint[] = [],
863
+ public readonly contractDbCommitCheckpointHints: AvmContractDbCommitCheckpointHint[] = [],
864
+ public readonly contractDbRevertCheckpointHints: AvmContractDbRevertCheckpointHint[] = [],
864
865
  // Merkle DB hints.
865
866
  public startingTreeRoots: TreeSnapshots = TreeSnapshots.empty(),
866
867
  public readonly getSiblingPathHints: AvmGetSiblingPathHint[] = [],
@@ -895,9 +896,9 @@ export class AvmExecutionHints {
895
896
  obj.contractClasses?.map((c: any) => AvmContractClassHint.fromPlainObject(c)) || [],
896
897
  obj.bytecodeCommitments?.map((b: any) => AvmBytecodeCommitmentHint.fromPlainObject(b)) || [],
897
898
  obj.debugFunctionNames?.map((d: any) => AvmDebugFunctionNameHint.fromPlainObject(d)) || [],
898
- obj.contractDBCreateCheckpointHints?.map((h: any) => AvmContractDBCreateCheckpointHint.fromPlainObject(h)) || [],
899
- obj.contractDBCommitCheckpointHints?.map((h: any) => AvmContractDBCommitCheckpointHint.fromPlainObject(h)) || [],
900
- obj.contractDBRevertCheckpointHints?.map((h: any) => AvmContractDBRevertCheckpointHint.fromPlainObject(h)) || [],
899
+ obj.contractDbCreateCheckpointHints?.map((h: any) => AvmContractDbCreateCheckpointHint.fromPlainObject(h)) || [],
900
+ obj.contractDbCommitCheckpointHints?.map((h: any) => AvmContractDbCommitCheckpointHint.fromPlainObject(h)) || [],
901
+ obj.contractDbRevertCheckpointHints?.map((h: any) => AvmContractDbRevertCheckpointHint.fromPlainObject(h)) || [],
901
902
  obj.startingTreeRoots ? TreeSnapshots.fromPlainObject(obj.startingTreeRoots) : TreeSnapshots.empty(),
902
903
  obj.getSiblingPathHints?.map((h: any) => AvmGetSiblingPathHint.fromPlainObject(h)) || [],
903
904
  obj.getPreviousValueIndexHints?.map((h: any) => AvmGetPreviousValueIndexHint.fromPlainObject(h)) || [],
@@ -934,9 +935,9 @@ export class AvmExecutionHints {
934
935
  contractClasses: AvmContractClassHint.schema.array(),
935
936
  bytecodeCommitments: AvmBytecodeCommitmentHint.schema.array(),
936
937
  debugFunctionNames: AvmDebugFunctionNameHint.schema.array(),
937
- contractDBCreateCheckpointHints: AvmContractDBCreateCheckpointHint.schema.array(),
938
- contractDBCommitCheckpointHints: AvmContractDBCommitCheckpointHint.schema.array(),
939
- contractDBRevertCheckpointHints: AvmContractDBRevertCheckpointHint.schema.array(),
938
+ contractDbCreateCheckpointHints: AvmContractDbCreateCheckpointHint.schema.array(),
939
+ contractDbCommitCheckpointHints: AvmContractDbCommitCheckpointHint.schema.array(),
940
+ contractDbRevertCheckpointHints: AvmContractDbRevertCheckpointHint.schema.array(),
940
941
  startingTreeRoots: TreeSnapshots.schema,
941
942
  getSiblingPathHints: AvmGetSiblingPathHint.schema.array(),
942
943
  getPreviousValueIndexHints: AvmGetPreviousValueIndexHint.schema.array(),
@@ -959,9 +960,9 @@ export class AvmExecutionHints {
959
960
  contractClasses,
960
961
  bytecodeCommitments,
961
962
  debugFunctionNames,
962
- contractDBCreateCheckpointHints,
963
- contractDBCommitCheckpointHints,
964
- contractDBRevertCheckpointHints,
963
+ contractDbCreateCheckpointHints,
964
+ contractDbCommitCheckpointHints,
965
+ contractDbRevertCheckpointHints,
965
966
  startingTreeRoots,
966
967
  getSiblingPathHints,
967
968
  getPreviousValueIndexHints,
@@ -983,9 +984,9 @@ export class AvmExecutionHints {
983
984
  contractClasses,
984
985
  bytecodeCommitments,
985
986
  debugFunctionNames,
986
- contractDBCreateCheckpointHints,
987
- contractDBCommitCheckpointHints,
988
- contractDBRevertCheckpointHints,
987
+ contractDbCreateCheckpointHints,
988
+ contractDbCommitCheckpointHints,
989
+ contractDbRevertCheckpointHints,
989
990
  startingTreeRoots,
990
991
  getSiblingPathHints,
991
992
  getPreviousValueIndexHints,
@@ -1056,7 +1057,7 @@ export class PublicTxResult {
1056
1057
  public gasUsed: GasUsed,
1057
1058
  public revertCode: RevertCode,
1058
1059
  public revertReason: SimulationError | undefined, // Revert reason, if any
1059
- // These are only guaranteed to be present in "client initiated simulation" mode.
1060
+ // These are only guaranteed to be present if the simulator is configured to collect them.
1060
1061
  public processedPhases: ProcessedPhase[] | undefined,
1061
1062
  public logs: DebugLog[] | undefined,
1062
1063
  // For the proving request.
@@ -1121,17 +1122,52 @@ export class PublicTxResult {
1121
1122
  }
1122
1123
  }
1123
1124
 
1124
- export type PublicTxSimulatorConfig = {
1125
- proverId: Fr;
1126
- doMerkleOperations: boolean;
1127
- skipFeeEnforcement: boolean;
1128
- clientInitiatedSimulation: boolean;
1129
- maxDebugLogMemoryReads: number;
1130
- };
1125
+ export class PublicSimulatorConfig {
1126
+ constructor(
1127
+ public readonly proverId: Fr,
1128
+ public readonly skipFeeEnforcement: boolean,
1129
+ public readonly collectCallMetadata: boolean, // processedPhases.
1130
+ public readonly collectHints: boolean, // hints.
1131
+ public readonly collectDebugLogs: boolean, // logs.
1132
+ public readonly maxDebugLogMemoryReads: number,
1133
+ public readonly collectStatistics: boolean, // timings etc.
1134
+ ) {}
1135
+
1136
+ static from(obj: Partial<PublicSimulatorConfig>): PublicSimulatorConfig {
1137
+ return new PublicSimulatorConfig(
1138
+ obj.proverId ?? Fr.ZERO,
1139
+ obj.skipFeeEnforcement ?? false,
1140
+ obj.collectCallMetadata ?? false,
1141
+ obj.collectHints ?? false,
1142
+ obj.collectDebugLogs ?? false,
1143
+ obj.maxDebugLogMemoryReads ?? DEFAULT_MAX_DEBUG_LOG_MEMORY_READS,
1144
+ obj.collectStatistics ?? false,
1145
+ );
1146
+ }
1147
+
1148
+ static empty() {
1149
+ return PublicSimulatorConfig.from({});
1150
+ }
1151
+
1152
+ static get schema() {
1153
+ return z
1154
+ .object({
1155
+ proverId: Fr.schema,
1156
+ skipFeeEnforcement: z.boolean(),
1157
+ collectCallMetadata: z.boolean(),
1158
+ collectHints: z.boolean(),
1159
+ collectDebugLogs: z.boolean(),
1160
+ maxDebugLogMemoryReads: z.number(),
1161
+ collectStatistics: z.boolean(),
1162
+ })
1163
+ .transform(PublicSimulatorConfig.from);
1164
+ }
1165
+ }
1131
1166
 
1132
1167
  export class AvmFastSimulationInputs {
1133
1168
  constructor(
1134
1169
  public readonly wsRevision: WorldStateRevision,
1170
+ public readonly config: PublicSimulatorConfig,
1135
1171
  public tx: AvmTxHint,
1136
1172
  public globalVariables: GlobalVariables,
1137
1173
  public protocolContracts: ProtocolContracts,
@@ -1140,6 +1176,7 @@ export class AvmFastSimulationInputs {
1140
1176
  static empty() {
1141
1177
  return new AvmFastSimulationInputs(
1142
1178
  WorldStateRevision.empty(),
1179
+ PublicSimulatorConfig.empty(),
1143
1180
  AvmTxHint.empty(),
1144
1181
  GlobalVariables.empty(),
1145
1182
  ProtocolContracts.empty(),
@@ -1150,13 +1187,14 @@ export class AvmFastSimulationInputs {
1150
1187
  return z
1151
1188
  .object({
1152
1189
  wsRevision: WorldStateRevision.schema,
1190
+ config: PublicSimulatorConfig.schema,
1153
1191
  tx: AvmTxHint.schema,
1154
1192
  globalVariables: GlobalVariables.schema,
1155
1193
  protocolContracts: ProtocolContracts.schema,
1156
1194
  })
1157
1195
  .transform(
1158
- ({ wsRevision, tx, globalVariables, protocolContracts }) =>
1159
- new AvmFastSimulationInputs(wsRevision, tx, globalVariables, protocolContracts),
1196
+ ({ wsRevision, config, tx, globalVariables, protocolContracts }) =>
1197
+ new AvmFastSimulationInputs(wsRevision, config, tx, globalVariables, protocolContracts),
1160
1198
  );
1161
1199
  }
1162
1200
 
@@ -61,7 +61,7 @@ export class PublicDataWrite {
61
61
  return new PublicDataWrite(reader.readField(), reader.readField());
62
62
  }
63
63
 
64
- toBlobFields(): Fr[] {
64
+ toBlobFields(): [Fr, Fr] {
65
65
  return [this.leafSlot, this.value];
66
66
  }
67
67
 
@@ -115,11 +115,15 @@ export class RevertCode {
115
115
  return this.toBuffer().length;
116
116
  }
117
117
 
118
- public static fromField(fr: Fr): RevertCode {
119
- if (!isRevertCodeEnum(fr.toNumber())) {
120
- throw new Error(`Invalid RevertCode: ${fr.toNumber()}`);
118
+ public static fromNumber(code: number): RevertCode {
119
+ if (!isRevertCodeEnum(code)) {
120
+ throw new Error(`Invalid RevertCode: ${code}`);
121
121
  }
122
- return new RevertCode(fr.toNumber());
122
+ return new RevertCode(code);
123
+ }
124
+
125
+ public static fromField(field: Fr): RevertCode {
126
+ return RevertCode.fromNumber(field.toNumber());
123
127
  }
124
128
 
125
129
  public static fromFields(fields: Fr[] | FieldReader): RevertCode {
@@ -130,10 +134,7 @@ export class RevertCode {
130
134
  public static fromBuffer(buffer: Buffer | BufferReader): RevertCode {
131
135
  const reader = BufferReader.asReader(buffer);
132
136
  const code = reader.readBytes(RevertCode.PACKED_SIZE_IN_BYTES).readUInt8(0);
133
- if (!isRevertCodeEnum(code)) {
134
- throw new Error(`Invalid RevertCode: ${code}`);
135
- }
136
- return new RevertCode(code);
137
+ return RevertCode.fromNumber(code);
137
138
  }
138
139
 
139
140
  private static readonly NUM_OPTIONS = 4;
package/src/block/body.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { createBlockEndMarker, getNumTxsFromBlockEndMarker, isBlockEndMarker } from '@aztec/blob-lib/encoding';
1
+ import type { TxBlobData } from '@aztec/blob-lib/encoding';
2
2
  import { timesParallel } from '@aztec/foundation/collection';
3
- import { Fr } from '@aztec/foundation/fields';
4
- import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize';
3
+ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
5
4
 
6
5
  import { inspect } from 'util';
7
6
  import { z } from 'zod';
@@ -9,14 +8,6 @@ import { z } from 'zod';
9
8
  import type { ZodFor } from '../schemas/index.js';
10
9
  import { TxEffect } from '../tx/tx_effect.js';
11
10
 
12
- export { createBlockEndMarker };
13
-
14
- export function getBlockBlobFields(txEffects: TxEffect[]) {
15
- const blobFields = txEffects.flatMap(txEffect => txEffect.toBlobFields());
16
- blobFields.push(createBlockEndMarker(txEffects.length));
17
- return blobFields;
18
- }
19
-
20
11
  export class Body {
21
12
  constructor(public txEffects: TxEffect[]) {}
22
13
 
@@ -55,32 +46,16 @@ export class Body {
55
46
  /**
56
47
  * Returns a flat packed array of fields of all tx effects - used for blobs.
57
48
  */
58
- toBlobFields() {
59
- return getBlockBlobFields(this.txEffects);
49
+ toTxBlobData(): TxBlobData[] {
50
+ return this.txEffects.map(txEffect => txEffect.toTxBlobData());
60
51
  }
61
52
 
62
53
  /**
63
54
  * Decodes a block from blob fields.
64
55
  */
65
- static fromBlobFields(fields: Fr[]) {
66
- const txEffects: TxEffect[] = [];
67
- const reader = new FieldReader(fields.slice(0, -1));
68
- while (!reader.isFinished()) {
69
- txEffects.push(TxEffect.fromBlobFields(reader));
70
- }
71
-
72
- // If the fields are from a proven block, or are constructed by calling `toBlobFields`, the following errors should never throw.
73
-
74
- if (!isBlockEndMarker(fields[fields.length - 1])) {
75
- throw new Error('Block end marker not found');
76
- }
77
-
78
- const numTxs = getNumTxsFromBlockEndMarker(fields[fields.length - 1]);
79
- if (numTxs !== txEffects.length) {
80
- throw new Error(`Expected ${numTxs} txs, but got ${txEffects.length}`);
81
- }
82
-
83
- return new this(txEffects);
56
+ static fromTxBlobData(txBlobData: TxBlobData[]): Body {
57
+ const txEffects = txBlobData.map(data => TxEffect.fromTxBlobData(data));
58
+ return new Body(txEffects);
84
59
  }
85
60
 
86
61
  [inspect.custom]() {
@@ -1,4 +1,5 @@
1
1
  export * from './l2_block.js';
2
+ export * from './l2_block_new.js';
2
3
  export * from './l2_block_header.js';
3
4
  export * from './l2_block_stream/index.js';
4
5
  export * from './in_block.js';
@@ -1,10 +1,10 @@
1
+ import { type BlockBlobData, encodeBlockBlobData } from '@aztec/blob-lib/encoding';
1
2
  import { Fr } from '@aztec/foundation/fields';
2
3
  import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
3
4
  import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
4
5
 
5
6
  import { z } from 'zod';
6
7
 
7
- import { getCheckpointBlobFields } from '../checkpoint/checkpoint_body.js';
8
8
  import { AppendOnlyTreeSnapshot } from '../trees/append_only_tree_snapshot.js';
9
9
  import type { BlockHeader } from '../tx/block_header.js';
10
10
  import { Body } from './body.js';
@@ -14,6 +14,8 @@ import type { L2BlockInfo } from './l2_block_info.js';
14
14
 
15
15
  /**
16
16
  * The data that makes up the rollup proof, with encoder decoder functions.
17
+ *
18
+ * @deprecated Use `L2BlockNew` instead.
17
19
  */
18
20
  export class L2Block {
19
21
  constructor(
@@ -152,7 +154,36 @@ export class L2Block {
152
154
  * TODO(#17027): Remove this method from L2Block and create a dedicated Checkpoint class.
153
155
  */
154
156
  public getCheckpointBlobFields() {
155
- return getCheckpointBlobFields([this.body.txEffects]);
157
+ const blockBlobData = this.toBlobFields(true);
158
+ return [new Fr(blockBlobData.length + 1)].concat(blockBlobData);
159
+ }
160
+
161
+ public toBlobFields(isFirstBlock: boolean): Fr[] {
162
+ const blockBlobData = this.toBlockBlobData(isFirstBlock);
163
+ return encodeBlockBlobData(blockBlobData);
164
+ }
165
+
166
+ public toBlockBlobData(isFirstBlock: boolean): BlockBlobData {
167
+ return {
168
+ blockEndMarker: {
169
+ numTxs: this.body.txEffects.length,
170
+ timestamp: this.header.globalVariables.timestamp,
171
+ blockNumber: this.number,
172
+ },
173
+ blockEndStateField: {
174
+ l1ToL2MessageNextAvailableLeafIndex: this.header.state.l1ToL2MessageTree.nextAvailableLeafIndex,
175
+ noteHashNextAvailableLeafIndex: this.header.state.partial.noteHashTree.nextAvailableLeafIndex,
176
+ nullifierNextAvailableLeafIndex: this.header.state.partial.nullifierTree.nextAvailableLeafIndex,
177
+ publicDataNextAvailableLeafIndex: this.header.state.partial.publicDataTree.nextAvailableLeafIndex,
178
+ totalManaUsed: this.header.totalManaUsed.toBigInt(),
179
+ },
180
+ lastArchiveRoot: this.header.lastArchive.root,
181
+ noteHashRoot: this.header.state.partial.noteHashTree.root,
182
+ nullifierRoot: this.header.state.partial.nullifierTree.root,
183
+ publicDataRoot: this.header.state.partial.publicDataTree.root,
184
+ l1ToL2MessageRoot: isFirstBlock ? this.header.state.l1ToL2MessageTree.root : undefined,
185
+ txs: this.body.toTxBlobData(),
186
+ };
156
187
  }
157
188
 
158
189
  /**
@@ -0,0 +1,143 @@
1
+ import { type BlockBlobData, encodeBlockBlobData } from '@aztec/blob-lib/encoding';
2
+ import { Fr } from '@aztec/foundation/fields';
3
+ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
4
+
5
+ import { z } from 'zod';
6
+
7
+ import { AppendOnlyTreeSnapshot } from '../trees/append_only_tree_snapshot.js';
8
+ import { BlockHeader } from '../tx/block_header.js';
9
+ import { Body } from './body.js';
10
+ import type { L2BlockInfo } from './l2_block_info.js';
11
+
12
+ /**
13
+ * An L2 block with a header and a body.
14
+ * TODO: Delete the existing `L2Block` class and rename this to `L2Block`.
15
+ */
16
+ export class L2BlockNew {
17
+ constructor(
18
+ /** Snapshot of archive tree after the block is applied. */
19
+ public archive: AppendOnlyTreeSnapshot,
20
+ /** Header of the block. */
21
+ public header: BlockHeader,
22
+ /** L2 block body. */
23
+ public body: Body,
24
+ private blockHash: Fr | undefined = undefined,
25
+ ) {}
26
+
27
+ get number(): number {
28
+ return this.header.globalVariables.blockNumber;
29
+ }
30
+
31
+ get timestamp(): bigint {
32
+ return this.header.globalVariables.timestamp;
33
+ }
34
+
35
+ static get schema() {
36
+ return z
37
+ .object({
38
+ archive: AppendOnlyTreeSnapshot.schema,
39
+ header: BlockHeader.schema,
40
+ body: Body.schema,
41
+ })
42
+ .transform(({ archive, header, body }) => new L2BlockNew(archive, header, body));
43
+ }
44
+
45
+ /**
46
+ * Deserializes a block from a buffer
47
+ * @returns A deserialized L2 block.
48
+ */
49
+ static fromBuffer(buf: Buffer | BufferReader) {
50
+ const reader = BufferReader.asReader(buf);
51
+ const header = reader.readObject(BlockHeader);
52
+ const archive = reader.readObject(AppendOnlyTreeSnapshot);
53
+ const body = reader.readObject(Body);
54
+
55
+ return new L2BlockNew(archive, header, body);
56
+ }
57
+
58
+ /**
59
+ * Serializes a block
60
+ * @returns A serialized L2 block as a Buffer.
61
+ */
62
+ toBuffer() {
63
+ return serializeToBuffer(this.header, this.archive, this.body);
64
+ }
65
+
66
+ /**
67
+ * Returns the block's hash (hash of block header).
68
+ * @returns The block's hash.
69
+ */
70
+ public async hash(): Promise<Fr> {
71
+ if (this.blockHash === undefined) {
72
+ this.blockHash = await this.header.hash();
73
+ }
74
+ return this.blockHash;
75
+ }
76
+
77
+ public toBlobFields(isFirstBlock: boolean): Fr[] {
78
+ const blockBlobData = this.toBlockBlobData(isFirstBlock);
79
+ return encodeBlockBlobData(blockBlobData);
80
+ }
81
+
82
+ public toBlockBlobData(isFirstBlock: boolean): BlockBlobData {
83
+ return {
84
+ blockEndMarker: {
85
+ numTxs: this.body.txEffects.length,
86
+ timestamp: this.header.globalVariables.timestamp,
87
+ blockNumber: this.number,
88
+ },
89
+ blockEndStateField: {
90
+ l1ToL2MessageNextAvailableLeafIndex: this.header.state.l1ToL2MessageTree.nextAvailableLeafIndex,
91
+ noteHashNextAvailableLeafIndex: this.header.state.partial.noteHashTree.nextAvailableLeafIndex,
92
+ nullifierNextAvailableLeafIndex: this.header.state.partial.nullifierTree.nextAvailableLeafIndex,
93
+ publicDataNextAvailableLeafIndex: this.header.state.partial.publicDataTree.nextAvailableLeafIndex,
94
+ totalManaUsed: this.header.totalManaUsed.toBigInt(),
95
+ },
96
+ lastArchiveRoot: this.header.lastArchive.root,
97
+ noteHashRoot: this.header.state.partial.noteHashTree.root,
98
+ nullifierRoot: this.header.state.partial.nullifierTree.root,
99
+ publicDataRoot: this.header.state.partial.publicDataTree.root,
100
+ l1ToL2MessageRoot: isFirstBlock ? this.header.state.l1ToL2MessageTree.root : undefined,
101
+ txs: this.body.toTxBlobData(),
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Returns stats used for logging.
107
+ * @returns Stats on tx count, number, and log size and count.
108
+ */
109
+ getStats() {
110
+ const logsStats = {
111
+ privateLogCount: this.body.txEffects.reduce((logCount, txEffect) => logCount + txEffect.privateLogs.length, 0),
112
+ publicLogCount: this.body.txEffects.reduce((logCount, txEffect) => logCount + txEffect.publicLogs.length, 0),
113
+ contractClassLogCount: this.body.txEffects.reduce(
114
+ (logCount, txEffect) => logCount + txEffect.contractClassLogs.length,
115
+ 0,
116
+ ),
117
+ contractClassLogSize: this.body.txEffects.reduce(
118
+ (totalLogSize, txEffect) =>
119
+ totalLogSize + txEffect.contractClassLogs.reduce((acc, log) => acc + log.emittedLength, 0),
120
+ 0,
121
+ ),
122
+ };
123
+
124
+ return {
125
+ txCount: this.body.txEffects.length,
126
+ blockNumber: this.number,
127
+ blockTimestamp: Number(this.header.globalVariables.timestamp),
128
+ ...logsStats,
129
+ };
130
+ }
131
+
132
+ toBlockInfo(): L2BlockInfo {
133
+ return {
134
+ blockHash: this.blockHash,
135
+ archive: this.archive.root,
136
+ lastArchive: this.header.lastArchive.root,
137
+ blockNumber: this.number,
138
+ slotNumber: Number(this.header.getSlot()),
139
+ txCount: this.body.txEffects.length,
140
+ timestamp: this.header.globalVariables.timestamp,
141
+ };
142
+ }
143
+ }
@@ -0,0 +1,46 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
3
+
4
+ import { z } from 'zod';
5
+
6
+ import { L2BlockNew } from '../block/l2_block_new.js';
7
+ import { CheckpointHeader } from '../rollup/checkpoint_header.js';
8
+ import { AppendOnlyTreeSnapshot } from '../trees/append_only_tree_snapshot.js';
9
+
10
+ export class Checkpoint {
11
+ constructor(
12
+ /** Snapshot of archive tree after the checkpoint is added. */
13
+ public archive: AppendOnlyTreeSnapshot,
14
+ /** Header of the checkpoint. */
15
+ public header: CheckpointHeader,
16
+ /** L2 blocks in the checkpoint. */
17
+ public blocks: L2BlockNew[],
18
+ ) {}
19
+
20
+ static get schema() {
21
+ return z
22
+ .object({
23
+ archive: AppendOnlyTreeSnapshot.schema,
24
+ header: CheckpointHeader.schema,
25
+ blocks: z.array(L2BlockNew.schema),
26
+ })
27
+ .transform(({ archive, header, blocks }) => new Checkpoint(archive, header, blocks));
28
+ }
29
+
30
+ static fromBuffer(buf: Buffer | BufferReader) {
31
+ const reader = BufferReader.asReader(buf);
32
+ const archive = reader.readObject(AppendOnlyTreeSnapshot);
33
+ const header = reader.readObject(CheckpointHeader);
34
+ const blocks = reader.readVector(L2BlockNew);
35
+ return new Checkpoint(archive, header, blocks);
36
+ }
37
+
38
+ toBuffer() {
39
+ return serializeToBuffer(this.archive, this.header, this.blocks.length, this.blocks);
40
+ }
41
+
42
+ public toBlobFields() {
43
+ const blocksBlobFields = this.blocks.flatMap((block, i) => block.toBlobFields(i === 0));
44
+ return [new Fr(blocksBlobFields.length + 1)].concat(blocksBlobFields);
45
+ }
46
+ }
@@ -1 +1 @@
1
- export * from './checkpoint_body.js';
1
+ export * from './checkpoint.js';
@@ -49,12 +49,11 @@ export class PrivateLog {
49
49
  }
50
50
 
51
51
  toBlobFields(): Fr[] {
52
- return [new Fr(this.emittedLength)].concat(this.getEmittedFields());
52
+ return this.getEmittedFields();
53
53
  }
54
54
 
55
- static fromBlobFields(fields: Fr[] | FieldReader) {
55
+ static fromBlobFields(emittedLength: number, fields: Fr[] | FieldReader) {
56
56
  const reader = FieldReader.asReader(fields);
57
- const emittedLength = reader.readU32();
58
57
  const emittedFields = reader.readFieldArray(emittedLength);
59
58
  return new PrivateLog(padArrayEnd(emittedFields, Fr.ZERO, PRIVATE_LOG_SIZE_IN_FIELDS), emittedLength);
60
59
  }
@@ -0,0 +1,15 @@
1
+ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
+ import { padArrayEnd } from '@aztec/foundation/collection';
3
+ import { sha256Trunc } from '@aztec/foundation/crypto';
4
+ import { Fr } from '@aztec/foundation/fields';
5
+ import { MerkleTreeCalculator } from '@aztec/foundation/trees';
6
+
7
+ /** Computes the inHash for a block's ContentCommitment given its l1 to l2 messages. */
8
+ export async function computeInHashFromL1ToL2Messages(unpaddedL1ToL2Messages: Fr[]): Promise<Fr> {
9
+ const l1ToL2Messages = padArrayEnd<Fr, number>(unpaddedL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
10
+ const hasher = (left: Buffer, right: Buffer) =>
11
+ Promise.resolve(sha256Trunc(Buffer.concat([left, right])) as Buffer<ArrayBuffer>);
12
+ const parityHeight = Math.ceil(Math.log2(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP));
13
+ const parityCalculator = await MerkleTreeCalculator.create(parityHeight, Fr.ZERO.toBuffer(), hasher);
14
+ return new Fr(await parityCalculator.computeTreeRoot(l1ToL2Messages.map(msg => msg.toBuffer())));
15
+ }
@@ -1,3 +1,4 @@
1
+ export * from './in_hash.js';
1
2
  export * from './inbox_leaf.js';
2
3
  export * from './l1_to_l2_message.js';
3
4
  export * from './l1_to_l2_message_source.js';
@@ -5,3 +6,4 @@ export * from './l1_actor.js';
5
6
  export * from './l2_actor.js';
6
7
  export * from './l2_to_l1_message.js';
7
8
  export * from './l2_to_l1_membership.js';
9
+ export * from './out_hash.js';
@@ -0,0 +1,36 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import { UnbalancedMerkleTreeCalculator, computeUnbalancedMerkleTreeRoot } from '@aztec/foundation/trees';
3
+
4
+ export function computeTxOutHash(messages: Fr[]): Fr {
5
+ if (!messages.length) {
6
+ return Fr.ZERO;
7
+ }
8
+ // Tx out hash is the root of the unbalanced merkle tree of all the messages.
9
+ // Zero hashes (which should not happen) are not compressed.
10
+ return Fr.fromBuffer(computeUnbalancedMerkleTreeRoot(messages.map(msg => msg.toBuffer())));
11
+ }
12
+
13
+ export function computeBlockOutHash(messagesPerBlock: Fr[][]): Fr {
14
+ const txOutHashes = messagesPerBlock.map(messages => computeTxOutHash(messages));
15
+ return aggregateOutHashes(txOutHashes);
16
+ }
17
+
18
+ export function computeCheckpointOutHash(messagesForAllTxs: Fr[][][]): Fr {
19
+ const blockOutHashes = messagesForAllTxs.map(block => computeBlockOutHash(block));
20
+ return aggregateOutHashes(blockOutHashes);
21
+ }
22
+
23
+ // The root of this tree should match the `out_hash` calculated in the circuits. Zero hashes are compressed to reduce
24
+ // cost if the non-zero leaves result in a shorter path.
25
+ function aggregateOutHashes(outHashes: Fr[]): Fr {
26
+ if (!outHashes.length) {
27
+ return Fr.ZERO;
28
+ }
29
+
30
+ const valueToCompress = Buffer.alloc(32);
31
+ const tree = UnbalancedMerkleTreeCalculator.create(
32
+ outHashes.map(hash => hash.toBuffer()),
33
+ valueToCompress,
34
+ );
35
+ return Fr.fromBuffer(tree.getRoot());
36
+ }
@@ -3,6 +3,8 @@ import { Fr } from '@aztec/foundation/fields';
3
3
  import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
4
4
  import type { FieldsOf } from '@aztec/foundation/types';
5
5
 
6
+ import { inspect } from 'util';
7
+
6
8
  import { AztecAddress } from '../aztec-address/index.js';
7
9
  import { GasFees } from '../gas/gas_fees.js';
8
10
 
@@ -81,4 +83,22 @@ export class CheckpointConstantData {
81
83
  reader.readObject(GasFees),
82
84
  );
83
85
  }
86
+
87
+ toInspect() {
88
+ return {
89
+ chainId: this.chainId.toNumber(),
90
+ version: this.version.toNumber(),
91
+ vkTreeRoot: this.vkTreeRoot.toString(),
92
+ protocolContractsHash: this.protocolContractsHash.toString(),
93
+ proverId: this.proverId.toString(),
94
+ slotNumber: this.slotNumber.toNumber(),
95
+ coinbase: this.coinbase.toString(),
96
+ feeRecipient: this.feeRecipient.toString(),
97
+ gasFees: this.gasFees.toInspect(),
98
+ };
99
+ }
100
+
101
+ [inspect.custom]() {
102
+ return `CheckpointConstantData ${inspect(this.toInspect())}`;
103
+ }
84
104
  }