@aztec/stdlib 3.0.0-nightly.20251113 → 3.0.0-nightly.20251115

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 (80) hide show
  1. package/dest/avm/avm.d.ts +102 -8
  2. package/dest/avm/avm.d.ts.map +1 -1
  3. package/dest/avm/avm.js +43 -4
  4. package/dest/avm/public_data_write.d.ts +1 -1
  5. package/dest/avm/public_data_write.d.ts.map +1 -1
  6. package/dest/avm/revert_code.d.ts +2 -1
  7. package/dest/avm/revert_code.d.ts.map +1 -1
  8. package/dest/avm/revert_code.js +8 -8
  9. package/dest/block/body.d.ts +3 -6
  10. package/dest/block/body.d.ts.map +1 -1
  11. package/dest/block/body.js +6 -25
  12. package/dest/block/index.d.ts +1 -0
  13. package/dest/block/index.d.ts.map +1 -1
  14. package/dest/block/index.js +1 -0
  15. package/dest/block/l2_block.d.ts +5 -0
  16. package/dest/block/l2_block.d.ts.map +1 -1
  17. package/dest/block/l2_block.js +34 -4
  18. package/dest/block/l2_block_new.d.ts +97 -0
  19. package/dest/block/l2_block_new.d.ts.map +1 -0
  20. package/dest/block/l2_block_new.js +113 -0
  21. package/dest/checkpoint/checkpoint.d.ts +108 -0
  22. package/dest/checkpoint/checkpoint.d.ts.map +1 -0
  23. package/dest/checkpoint/checkpoint.js +39 -0
  24. package/dest/checkpoint/index.d.ts +1 -1
  25. package/dest/checkpoint/index.d.ts.map +1 -1
  26. package/dest/checkpoint/index.js +1 -1
  27. package/dest/logs/private_log.d.ts +1 -1
  28. package/dest/logs/private_log.d.ts.map +1 -1
  29. package/dest/logs/private_log.js +2 -5
  30. package/dest/messaging/in_hash.d.ts +4 -0
  31. package/dest/messaging/in_hash.d.ts.map +1 -0
  32. package/dest/messaging/in_hash.js +15 -0
  33. package/dest/messaging/index.d.ts +2 -0
  34. package/dest/messaging/index.d.ts.map +1 -1
  35. package/dest/messaging/index.js +2 -0
  36. package/dest/messaging/out_hash.d.ts +5 -0
  37. package/dest/messaging/out_hash.d.ts.map +1 -0
  38. package/dest/messaging/out_hash.js +28 -0
  39. package/dest/rollup/checkpoint_constant_data.d.ts +16 -0
  40. package/dest/rollup/checkpoint_constant_data.d.ts.map +1 -1
  41. package/dest/rollup/checkpoint_constant_data.js +17 -0
  42. package/dest/tests/factories.d.ts +17 -21
  43. package/dest/tests/factories.d.ts.map +1 -1
  44. package/dest/tests/factories.js +14 -111
  45. package/dest/tests/mocks.d.ts +17 -1
  46. package/dest/tests/mocks.d.ts.map +1 -1
  47. package/dest/tests/mocks.js +108 -4
  48. package/dest/tx/partial_state_reference.d.ts +3 -0
  49. package/dest/tx/partial_state_reference.d.ts.map +1 -1
  50. package/dest/tx/partial_state_reference.js +10 -0
  51. package/dest/tx/state_reference.d.ts +3 -0
  52. package/dest/tx/state_reference.d.ts.map +1 -1
  53. package/dest/tx/state_reference.js +9 -0
  54. package/dest/tx/tx_effect.d.ts +9 -6
  55. package/dest/tx/tx_effect.d.ts.map +1 -1
  56. package/dest/tx/tx_effect.js +53 -57
  57. package/package.json +8 -8
  58. package/src/avm/avm.ts +48 -10
  59. package/src/avm/public_data_write.ts +1 -1
  60. package/src/avm/revert_code.ts +9 -8
  61. package/src/block/body.ts +7 -32
  62. package/src/block/index.ts +1 -0
  63. package/src/block/l2_block.ts +33 -2
  64. package/src/block/l2_block_new.ts +143 -0
  65. package/src/checkpoint/checkpoint.ts +46 -0
  66. package/src/checkpoint/index.ts +1 -1
  67. package/src/logs/private_log.ts +2 -3
  68. package/src/messaging/in_hash.ts +15 -0
  69. package/src/messaging/index.ts +2 -0
  70. package/src/messaging/out_hash.ts +36 -0
  71. package/src/rollup/checkpoint_constant_data.ts +20 -0
  72. package/src/tests/factories.ts +91 -193
  73. package/src/tests/mocks.ts +196 -4
  74. package/src/tx/partial_state_reference.ts +9 -0
  75. package/src/tx/state_reference.ts +9 -0
  76. package/src/tx/tx_effect.ts +61 -67
  77. package/dest/checkpoint/checkpoint_body.d.ts +0 -4
  78. package/dest/checkpoint/checkpoint_body.d.ts.map +0 -1
  79. package/dest/checkpoint/checkpoint_body.js +0 -9
  80. package/src/checkpoint/checkpoint_body.ts +0 -10
@@ -1,11 +1,10 @@
1
- import { decodeTxStartMarker, encodeTxStartMarker, isValidTxStartMarker } from '@aztec/blob-lib/encoding';
1
+ import { decodeTxBlobData, encodeTxBlobData, getNumTxBlobFields } from '@aztec/blob-lib/encoding';
2
2
  import { MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX } from '@aztec/constants';
3
3
  import { makeTuple, makeTupleAsync } from '@aztec/foundation/array';
4
4
  import { Fr } from '@aztec/foundation/fields';
5
5
  import { schemas } from '@aztec/foundation/schemas';
6
- import { BufferReader, FieldReader, serializeArrayOfBufferableToVector, serializeToBuffer } from '@aztec/foundation/serialize';
6
+ import { BufferReader, serializeArrayOfBufferableToVector, serializeToBuffer } from '@aztec/foundation/serialize';
7
7
  import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
8
- import { computeUnbalancedMerkleTreeRoot } from '@aztec/foundation/trees';
9
8
  import { inspect } from 'util';
10
9
  import { z } from 'zod';
11
10
  import { PublicDataWrite } from '../avm/public_data_write.js';
@@ -13,6 +12,7 @@ import { RevertCode } from '../avm/revert_code.js';
13
12
  import { ContractClassLog } from '../logs/contract_class_log.js';
14
13
  import { PrivateLog } from '../logs/private_log.js';
15
14
  import { FlatPublicLogs, PublicLog } from '../logs/public_log.js';
15
+ import { computeTxOutHash } from '../messaging/out_hash.js';
16
16
  import { TxHash } from './tx_hash.js';
17
17
  export class TxEffect {
18
18
  revertCode;
@@ -117,9 +117,6 @@ export class TxEffect {
117
117
  equals(other) {
118
118
  return this.revertCode.equals(other.revertCode) && this.txHash.equals(other.txHash) && this.transactionFee.equals(other.transactionFee) && this.noteHashes.length === other.noteHashes.length && this.noteHashes.every((h, i)=>h.equals(other.noteHashes[i])) && this.nullifiers.length === other.nullifiers.length && this.nullifiers.every((h, i)=>h.equals(other.nullifiers[i])) && this.l2ToL1Msgs.length === other.l2ToL1Msgs.length && this.l2ToL1Msgs.every((h, i)=>h.equals(other.l2ToL1Msgs[i])) && this.publicDataWrites.length === other.publicDataWrites.length && this.publicDataWrites.every((h, i)=>h.equals(other.publicDataWrites[i])) && this.privateLogs.length === other.privateLogs.length && this.privateLogs.every((h, i)=>h.equals(other.privateLogs[i])) && this.publicLogs.length === other.publicLogs.length && this.publicLogs.every((h, i)=>h.equals(other.publicLogs[i])) && this.contractClassLogs.length === other.contractClassLogs.length && this.contractClassLogs.every((h, i)=>h.equals(other.contractClassLogs[i]));
119
119
  }
120
- /** Returns the size of this tx effect in bytes as serialized onto DA. */ getDASize() {
121
- return this.toBlobFields().length * Fr.SIZE_IN_BYTES;
122
- }
123
120
  /**
124
121
  * Deserializes the TxEffect object from a Buffer.
125
122
  * @param buffer - Buffer or BufferReader object to deserialize.
@@ -132,11 +129,7 @@ export class TxEffect {
132
129
  * Computes txOutHash of this tx effect.
133
130
  * @dev Follows new_sha in unbalanced_merkle_tree.nr
134
131
  */ txOutHash() {
135
- const { l2ToL1Msgs } = this;
136
- if (l2ToL1Msgs.length == 0) {
137
- return Buffer.alloc(32);
138
- }
139
- return computeUnbalancedMerkleTreeRoot(l2ToL1Msgs.map((msg)=>msg.toBuffer()));
132
+ return computeTxOutHash(this.l2ToL1Msgs);
140
133
  }
141
134
  static async random(numPublicCallsPerTx = 3, numPublicLogsPerCall = 1, maxEffects = undefined) {
142
135
  return new TxEffect(RevertCode.random(), TxHash.random(), new Fr(Math.floor(Math.random() * 100_000)), makeTuple(maxEffects === undefined ? MAX_NOTE_HASHES_PER_TX : Math.min(maxEffects, MAX_NOTE_HASHES_PER_TX), Fr.random), makeTuple(maxEffects === undefined ? MAX_NULLIFIERS_PER_TX : Math.min(maxEffects, MAX_NULLIFIERS_PER_TX), Fr.random), makeTuple(maxEffects === undefined ? MAX_L2_TO_L1_MSGS_PER_TX : Math.min(maxEffects, MAX_L2_TO_L1_MSGS_PER_TX), Fr.random), makeTuple(maxEffects === undefined ? MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX : Math.min(maxEffects, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX), PublicDataWrite.random), makeTuple(MAX_PRIVATE_LOGS_PER_TX, ()=>PrivateLog.random()), await Promise.all(new Array(numPublicCallsPerTx * numPublicLogsPerCall).fill(null).map(()=>PublicLog.random())), await makeTupleAsync(MAX_CONTRACT_CLASS_LOGS_PER_TX, ContractClassLog.random));
@@ -147,63 +140,66 @@ export class TxEffect {
147
140
  /** Returns a hex representation of the TxEffect object. */ toString() {
148
141
  return bufferToHex(this.toBuffer());
149
142
  }
150
- /**
151
- * Returns a flat packed array of fields of all tx effects, to be appended to blobs.
152
- * Must match the implementation in noir-protocol-circuits/crates/rollup-lib/src/tx_base/components/tx_blob_data.nr
153
- */ toBlobFields() {
154
- const flattened = [];
155
- // We reassign the first field at the end when we know the length of all effects to create the tx start marker.
156
- flattened.push(Fr.ZERO);
157
- flattened.push(this.txHash.hash);
158
- flattened.push(this.transactionFee);
159
- flattened.push(...this.noteHashes);
160
- flattened.push(...this.nullifiers);
161
- flattened.push(...this.l2ToL1Msgs);
162
- flattened.push(...this.publicDataWrites.flatMap((w)=>w.toBlobFields()));
163
- flattened.push(...this.privateLogs.flatMap((l)=>l.toBlobFields()));
164
- const flattenedPublicLogs = FlatPublicLogs.fromLogs(this.publicLogs);
165
- flattened.push(...flattenedPublicLogs.toBlobFields());
166
- flattened.push(...this.contractClassLogs.flatMap((l)=>l.toBlobFields()));
167
- flattened[0] = encodeTxStartMarker({
143
+ getNumBlobFields() {
144
+ return this.getTxStartMarker().numBlobFields;
145
+ }
146
+ toBlobFields() {
147
+ return encodeTxBlobData(this.toTxBlobData());
148
+ }
149
+ static fromBlobFields(fields) {
150
+ return TxEffect.fromTxBlobData(decodeTxBlobData(fields));
151
+ }
152
+ getTxStartMarker() {
153
+ const flatPublicLogs = FlatPublicLogs.fromLogs(this.publicLogs);
154
+ const partialTxStartMarker = {
168
155
  revertCode: this.revertCode.getCode(),
169
- numBlobFields: flattened.length,
170
156
  numNoteHashes: this.noteHashes.length,
171
157
  numNullifiers: this.nullifiers.length,
172
158
  numL2ToL1Msgs: this.l2ToL1Msgs.length,
173
159
  numPublicDataWrites: this.publicDataWrites.length,
174
160
  numPrivateLogs: this.privateLogs.length,
175
- publicLogsLength: flattenedPublicLogs.length,
161
+ privateLogsLength: this.privateLogs.reduce((acc, log)=>acc + log.emittedLength, 0),
162
+ publicLogsLength: flatPublicLogs.length,
176
163
  contractClassLogLength: this.contractClassLogs[0]?.emittedLength ?? 0
177
- });
178
- return flattened;
164
+ };
165
+ const numBlobFields = getNumTxBlobFields(partialTxStartMarker);
166
+ return {
167
+ ...partialTxStartMarker,
168
+ numBlobFields
169
+ };
170
+ }
171
+ /**
172
+ * Returns a flat packed array of fields of all tx effects, to be appended to blobs.
173
+ * Must match the implementation in noir-protocol-circuits/crates/rollup-lib/src/tx_base/components/tx_blob_data.nr
174
+ */ toTxBlobData() {
175
+ return {
176
+ txStartMarker: this.getTxStartMarker(),
177
+ txHash: this.txHash.hash,
178
+ transactionFee: this.transactionFee,
179
+ noteHashes: this.noteHashes,
180
+ nullifiers: this.nullifiers,
181
+ l2ToL1Msgs: this.l2ToL1Msgs,
182
+ publicDataWrites: this.publicDataWrites.map((w)=>w.toBlobFields()),
183
+ privateLogs: this.privateLogs.map((l)=>l.toBlobFields()),
184
+ publicLogs: FlatPublicLogs.fromLogs(this.publicLogs).toBlobFields(),
185
+ contractClassLog: this.contractClassLogs.map((l)=>l.toBlobFields()).flat()
186
+ };
179
187
  }
180
188
  /**
181
189
  * Decodes a flat packed array of fields to TxEffect.
182
- */ static fromBlobFields(fields) {
183
- const reader = FieldReader.asReader(fields);
184
- const totalFields = reader.remainingFields();
185
- if (!totalFields) {
186
- throw new Error('Cannot process empty blob fields.');
187
- }
188
- const txStartMarker = decodeTxStartMarker(reader.readField());
189
- if (!isValidTxStartMarker(txStartMarker)) {
190
- throw new Error('Invalid fields given to TxEffect.fromBlobFields(): invalid TxStartMarker');
191
- }
192
- const revertCode = RevertCode.fromField(new Fr(txStartMarker.revertCode));
193
- const txHash = new TxHash(reader.readField());
194
- const transactionFee = reader.readField();
195
- const noteHashes = reader.readFieldArray(txStartMarker.numNoteHashes);
196
- const nullifiers = reader.readFieldArray(txStartMarker.numNullifiers);
197
- const l2ToL1Msgs = reader.readFieldArray(txStartMarker.numL2ToL1Msgs);
198
- const publicDataWrites = Array.from({
199
- length: txStartMarker.numPublicDataWrites
200
- }, ()=>PublicDataWrite.fromBlobFields(reader));
201
- const privateLogs = Array.from({
202
- length: txStartMarker.numPrivateLogs
203
- }, ()=>PrivateLog.fromBlobFields(reader));
204
- const publicLogs = FlatPublicLogs.fromBlobFields(txStartMarker.publicLogsLength, reader).toLogs();
190
+ */ static fromTxBlobData(txBlobData) {
191
+ const txStartMarker = txBlobData.txStartMarker;
192
+ const revertCode = RevertCode.fromNumber(txStartMarker.revertCode);
193
+ const txHash = new TxHash(txBlobData.txHash);
194
+ const transactionFee = txBlobData.transactionFee;
195
+ const noteHashes = txBlobData.noteHashes;
196
+ const nullifiers = txBlobData.nullifiers;
197
+ const l2ToL1Msgs = txBlobData.l2ToL1Msgs;
198
+ const publicDataWrites = txBlobData.publicDataWrites.map((w)=>PublicDataWrite.fromBlobFields(w));
199
+ const privateLogs = txBlobData.privateLogs.map((l)=>PrivateLog.fromBlobFields(l.length, l));
200
+ const publicLogs = FlatPublicLogs.fromBlobFields(txStartMarker.publicLogsLength, txBlobData.publicLogs).toLogs();
205
201
  const contractClassLogs = txStartMarker.contractClassLogLength > 0 ? [
206
- ContractClassLog.fromBlobFields(txStartMarker.contractClassLogLength, reader)
202
+ ContractClassLog.fromBlobFields(txStartMarker.contractClassLogLength, txBlobData.contractClassLog)
207
203
  ] : [];
208
204
  return TxEffect.from({
209
205
  revertCode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/stdlib",
3
- "version": "3.0.0-nightly.20251113",
3
+ "version": "3.0.0-nightly.20251115",
4
4
  "type": "module",
5
5
  "inherits": [
6
6
  "../package.common.json",
@@ -72,13 +72,13 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@aws-sdk/client-s3": "^3.892.0",
75
- "@aztec/bb.js": "3.0.0-nightly.20251113",
76
- "@aztec/blob-lib": "3.0.0-nightly.20251113",
77
- "@aztec/constants": "3.0.0-nightly.20251113",
78
- "@aztec/ethereum": "3.0.0-nightly.20251113",
79
- "@aztec/foundation": "3.0.0-nightly.20251113",
80
- "@aztec/l1-artifacts": "3.0.0-nightly.20251113",
81
- "@aztec/noir-noirc_abi": "3.0.0-nightly.20251113",
75
+ "@aztec/bb.js": "3.0.0-nightly.20251115",
76
+ "@aztec/blob-lib": "3.0.0-nightly.20251115",
77
+ "@aztec/constants": "3.0.0-nightly.20251115",
78
+ "@aztec/ethereum": "3.0.0-nightly.20251115",
79
+ "@aztec/foundation": "3.0.0-nightly.20251115",
80
+ "@aztec/l1-artifacts": "3.0.0-nightly.20251115",
81
+ "@aztec/noir-noirc_abi": "3.0.0-nightly.20251115",
82
82
  "@google-cloud/storage": "^7.15.0",
83
83
  "axios": "^1.12.0",
84
84
  "json-stringify-deterministic": "1.0.12",
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
 
@@ -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
  }