@aztec/stdlib 0.82.2 → 0.82.3-nightly.20250403

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 (206) hide show
  1. package/dest/avm/avm.d.ts +4648 -1474
  2. package/dest/avm/avm.d.ts.map +1 -1
  3. package/dest/avm/avm.js +182 -109
  4. package/dest/avm/avm_proving_request.d.ts +1867 -498
  5. package/dest/avm/avm_proving_request.d.ts.map +1 -1
  6. package/dest/block/l2_block_downloader/l2_block_stream.d.ts +10 -12
  7. package/dest/block/l2_block_downloader/l2_block_stream.d.ts.map +1 -1
  8. package/dest/block/l2_block_downloader/l2_block_stream.js +45 -11
  9. package/dest/config/config.d.ts +2 -2
  10. package/dest/config/config.d.ts.map +1 -1
  11. package/dest/config/config.js +4 -5
  12. package/dest/contract/interfaces/node-info.d.ts +2 -2
  13. package/dest/contract/interfaces/node-info.d.ts.map +1 -1
  14. package/dest/contract/interfaces/node-info.js +1 -1
  15. package/dest/database-version/version_manager.d.ts +4 -2
  16. package/dest/database-version/version_manager.d.ts.map +1 -1
  17. package/dest/database-version/version_manager.js +13 -9
  18. package/dest/epoch-helpers/index.d.ts +2 -0
  19. package/dest/epoch-helpers/index.d.ts.map +1 -1
  20. package/dest/epoch-helpers/index.js +3 -0
  21. package/dest/file-store/factory.d.ts +7 -0
  22. package/dest/file-store/factory.d.ts.map +1 -0
  23. package/dest/file-store/factory.js +46 -0
  24. package/dest/file-store/gcs.d.ts +22 -0
  25. package/dest/file-store/gcs.d.ts.map +1 -0
  26. package/dest/file-store/gcs.js +115 -0
  27. package/dest/file-store/http.d.ts +15 -0
  28. package/dest/file-store/http.d.ts.map +1 -0
  29. package/dest/file-store/http.js +53 -0
  30. package/dest/file-store/index.d.ts +3 -0
  31. package/dest/file-store/index.d.ts.map +1 -0
  32. package/dest/file-store/index.js +2 -0
  33. package/dest/file-store/interface.d.ts +24 -0
  34. package/dest/file-store/interface.d.ts.map +1 -0
  35. package/dest/file-store/interface.js +1 -0
  36. package/dest/file-store/local.d.ts +16 -0
  37. package/dest/file-store/local.d.ts.map +1 -0
  38. package/dest/file-store/local.js +40 -0
  39. package/dest/interfaces/aztec-node-admin.d.ts +9 -1
  40. package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
  41. package/dest/interfaces/aztec-node-admin.js +2 -1
  42. package/dest/interfaces/aztec-node.d.ts +3 -0
  43. package/dest/interfaces/aztec-node.d.ts.map +1 -1
  44. package/dest/interfaces/aztec-node.js +2 -0
  45. package/dest/interfaces/p2p.d.ts +2 -0
  46. package/dest/interfaces/p2p.d.ts.map +1 -1
  47. package/dest/interfaces/p2p.js +2 -1
  48. package/dest/interfaces/prover-client.d.ts +3 -3
  49. package/dest/interfaces/prover-client.d.ts.map +1 -1
  50. package/dest/interfaces/prover-client.js +6 -4
  51. package/dest/interfaces/prover-node.d.ts +4 -0
  52. package/dest/interfaces/prover-node.d.ts.map +1 -1
  53. package/dest/interfaces/prover-node.js +5 -1
  54. package/dest/interfaces/proving-job.d.ts +1866 -497
  55. package/dest/interfaces/proving-job.d.ts.map +1 -1
  56. package/dest/interfaces/pxe.d.ts +7 -6
  57. package/dest/interfaces/pxe.d.ts.map +1 -1
  58. package/dest/interfaces/pxe.js +1 -1
  59. package/dest/interfaces/service.d.ts +3 -0
  60. package/dest/interfaces/service.d.ts.map +1 -1
  61. package/dest/interfaces/service.js +7 -0
  62. package/dest/interfaces/world_state.d.ts +13 -15
  63. package/dest/interfaces/world_state.d.ts.map +1 -1
  64. package/dest/keys/derivation.d.ts +1 -1
  65. package/dest/keys/derivation.d.ts.map +1 -1
  66. package/dest/keys/derivation.js +10 -2
  67. package/dest/logs/index.d.ts +2 -1
  68. package/dest/logs/index.d.ts.map +1 -1
  69. package/dest/logs/index.js +2 -1
  70. package/dest/logs/pending_tagged_log.d.ts +17 -0
  71. package/dest/logs/pending_tagged_log.d.ts.map +1 -0
  72. package/dest/logs/pending_tagged_log.js +45 -0
  73. package/dest/logs/{l1_payload/shared_secret_derivation.d.ts → shared_secret_derivation.d.ts} +4 -3
  74. package/dest/logs/shared_secret_derivation.d.ts.map +1 -0
  75. package/dest/logs/{l1_payload/shared_secret_derivation.js → shared_secret_derivation.js} +3 -5
  76. package/dest/logs/tx_scoped_l2_log.d.ts +6 -1
  77. package/dest/logs/tx_scoped_l2_log.d.ts.map +1 -1
  78. package/dest/logs/tx_scoped_l2_log.js +12 -4
  79. package/dest/note/note.d.ts +45 -4
  80. package/dest/note/note.d.ts.map +1 -1
  81. package/dest/note/note.js +51 -4
  82. package/dest/proofs/proof.d.ts.map +1 -1
  83. package/dest/proofs/proof.js +33 -7
  84. package/dest/snapshots/download.d.ts +9 -0
  85. package/dest/snapshots/download.d.ts.map +1 -0
  86. package/dest/snapshots/download.js +37 -0
  87. package/dest/snapshots/index.d.ts +4 -0
  88. package/dest/snapshots/index.d.ts.map +1 -0
  89. package/dest/snapshots/index.js +3 -0
  90. package/dest/snapshots/types.d.ts +97 -0
  91. package/dest/snapshots/types.d.ts.map +1 -0
  92. package/dest/snapshots/types.js +27 -0
  93. package/dest/snapshots/upload.d.ts +5 -0
  94. package/dest/snapshots/upload.d.ts.map +1 -0
  95. package/dest/snapshots/upload.js +37 -0
  96. package/dest/tests/factories.d.ts +21 -7
  97. package/dest/tests/factories.d.ts.map +1 -1
  98. package/dest/tests/factories.js +78 -30
  99. package/dest/tests/mocks.d.ts +2 -1
  100. package/dest/tests/mocks.d.ts.map +1 -1
  101. package/dest/tests/mocks.js +5 -1
  102. package/dest/trees/merkle_tree_id.d.ts +8 -0
  103. package/dest/trees/merkle_tree_id.d.ts.map +1 -1
  104. package/dest/trees/merkle_tree_id.js +10 -0
  105. package/dest/trees/nullifier_leaf.d.ts +49 -15
  106. package/dest/trees/nullifier_leaf.d.ts.map +1 -1
  107. package/dest/trees/nullifier_leaf.js +45 -22
  108. package/dest/trees/nullifier_membership_witness.d.ts +34 -18
  109. package/dest/trees/nullifier_membership_witness.d.ts.map +1 -1
  110. package/dest/trees/protocol_contract_leaf.d.ts +0 -1
  111. package/dest/trees/protocol_contract_leaf.d.ts.map +1 -1
  112. package/dest/trees/protocol_contract_leaf.js +0 -3
  113. package/dest/trees/public_data_leaf.d.ts +59 -25
  114. package/dest/trees/public_data_leaf.d.ts.map +1 -1
  115. package/dest/trees/public_data_leaf.js +41 -30
  116. package/dest/trees/public_data_witness.d.ts +42 -24
  117. package/dest/trees/public_data_witness.d.ts.map +1 -1
  118. package/dest/trees/public_data_witness.js +6 -6
  119. package/dest/validators/index.d.ts +3 -0
  120. package/dest/validators/index.d.ts.map +1 -0
  121. package/dest/validators/index.js +1 -0
  122. package/dest/validators/schemas.d.ts +342 -0
  123. package/dest/validators/schemas.d.ts.map +1 -0
  124. package/dest/validators/schemas.js +40 -0
  125. package/dest/validators/types.d.ts +39 -0
  126. package/dest/validators/types.d.ts.map +1 -0
  127. package/dest/validators/types.js +1 -0
  128. package/dest/versioning/versioning.d.ts +1 -1
  129. package/dest/versioning/versioning.d.ts.map +1 -1
  130. package/dest/versioning/versioning.js +6 -6
  131. package/package.json +11 -8
  132. package/src/avm/avm.ts +183 -104
  133. package/src/block/l2_block_downloader/l2_block_stream.ts +64 -29
  134. package/src/config/config.ts +6 -6
  135. package/src/contract/interfaces/node-info.ts +3 -3
  136. package/src/database-version/version_manager.ts +12 -8
  137. package/src/epoch-helpers/index.ts +8 -0
  138. package/src/file-store/factory.ts +61 -0
  139. package/src/file-store/gcs.ts +121 -0
  140. package/src/file-store/http.ts +58 -0
  141. package/src/file-store/index.ts +2 -0
  142. package/src/file-store/interface.ts +19 -0
  143. package/src/file-store/local.ts +46 -0
  144. package/src/interfaces/aztec-node-admin.ts +11 -1
  145. package/src/interfaces/aztec-node.ts +7 -0
  146. package/src/interfaces/p2p.ts +4 -0
  147. package/src/interfaces/prover-client.ts +9 -7
  148. package/src/interfaces/prover-node.ts +10 -0
  149. package/src/interfaces/pxe.ts +14 -7
  150. package/src/interfaces/service.ts +13 -0
  151. package/src/interfaces/world_state.ts +17 -15
  152. package/src/keys/derivation.ts +12 -6
  153. package/src/logs/index.ts +2 -1
  154. package/src/logs/pending_tagged_log.ts +43 -0
  155. package/src/logs/{l1_payload/shared_secret_derivation.ts → shared_secret_derivation.ts} +4 -11
  156. package/src/logs/tx_scoped_l2_log.ts +13 -4
  157. package/src/note/note.ts +61 -5
  158. package/src/proofs/proof.ts +39 -5
  159. package/src/snapshots/download.ts +60 -0
  160. package/src/snapshots/index.ts +3 -0
  161. package/src/snapshots/types.ts +58 -0
  162. package/src/snapshots/upload.ts +55 -0
  163. package/src/tests/factories.ts +137 -53
  164. package/src/tests/mocks.ts +7 -0
  165. package/src/trees/merkle_tree_id.ts +12 -0
  166. package/src/trees/nullifier_leaf.ts +48 -21
  167. package/src/trees/protocol_contract_leaf.ts +0 -4
  168. package/src/trees/public_data_leaf.ts +40 -29
  169. package/src/trees/public_data_witness.ts +6 -6
  170. package/src/validators/index.ts +3 -0
  171. package/src/validators/schemas.ts +53 -0
  172. package/src/validators/types.ts +37 -0
  173. package/src/versioning/versioning.ts +8 -14
  174. package/dest/event/event.d.ts +0 -24
  175. package/dest/event/event.d.ts.map +0 -1
  176. package/dest/event/event.js +0 -13
  177. package/dest/event/event_metadata.d.ts +0 -38
  178. package/dest/event/event_metadata.d.ts.map +0 -1
  179. package/dest/event/event_metadata.js +0 -45
  180. package/dest/event/index.d.ts +0 -4
  181. package/dest/event/index.d.ts.map +0 -1
  182. package/dest/event/index.js +0 -3
  183. package/dest/event/l1_event_payload.d.ts +0 -52
  184. package/dest/event/l1_event_payload.d.ts.map +0 -1
  185. package/dest/event/l1_event_payload.js +0 -64
  186. package/dest/logs/l1_payload/encrypted_log_payload.d.ts +0 -50
  187. package/dest/logs/l1_payload/encrypted_log_payload.d.ts.map +0 -1
  188. package/dest/logs/l1_payload/encrypted_log_payload.js +0 -140
  189. package/dest/logs/l1_payload/encryption_util.d.ts +0 -24
  190. package/dest/logs/l1_payload/encryption_util.d.ts.map +0 -1
  191. package/dest/logs/l1_payload/encryption_util.js +0 -46
  192. package/dest/logs/l1_payload/index.d.ts +0 -3
  193. package/dest/logs/l1_payload/index.d.ts.map +0 -1
  194. package/dest/logs/l1_payload/index.js +0 -2
  195. package/dest/logs/l1_payload/payload.d.ts +0 -60
  196. package/dest/logs/l1_payload/payload.d.ts.map +0 -1
  197. package/dest/logs/l1_payload/payload.js +0 -61
  198. package/dest/logs/l1_payload/shared_secret_derivation.d.ts.map +0 -1
  199. package/src/event/event.ts +0 -16
  200. package/src/event/event_metadata.ts +0 -56
  201. package/src/event/index.ts +0 -3
  202. package/src/event/l1_event_payload.ts +0 -87
  203. package/src/logs/l1_payload/encrypted_log_payload.ts +0 -202
  204. package/src/logs/l1_payload/encryption_util.ts +0 -54
  205. package/src/logs/l1_payload/index.ts +0 -2
  206. package/src/logs/l1_payload/payload.ts +0 -73
@@ -0,0 +1,43 @@
1
+ import { MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS } from '@aztec/constants';
2
+ import { Fr } from '@aztec/foundation/fields';
3
+
4
+ import type { AztecAddress } from '../aztec-address/index.js';
5
+
6
+ /**
7
+ * Represents a pending tagged log as it is stored in the pending tagged log array to which the syncNotes oracle
8
+ * inserts found private logs. A TS version of `pending_tagged_log.nr`.
9
+ */
10
+ export class PendingTaggedLog {
11
+ constructor(
12
+ public log: Fr[],
13
+ public txHash: Fr,
14
+ public uniqueNoteHashesInTx: Fr[],
15
+ public firstNullifierInTx: Fr,
16
+ public recipient: AztecAddress,
17
+ public logIndexInTx: number,
18
+ ) {}
19
+
20
+ toFields(): Fr[] {
21
+ return [
22
+ ...serializeBoundedVec(this.log, PRIVATE_LOG_SIZE_IN_FIELDS),
23
+ this.txHash,
24
+ ...serializeBoundedVec(this.uniqueNoteHashesInTx, MAX_NOTE_HASHES_PER_TX),
25
+ this.firstNullifierInTx,
26
+ this.recipient.toField(),
27
+ new Fr(this.logIndexInTx),
28
+ ];
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Helper function to serialize a bounded vector according to Noir's BoundedVec format
34
+ * @param values - The values to serialize
35
+ * @param maxLength - The maximum length of the bounded vector
36
+ * @returns The serialized bounded vector as Fr[]
37
+ */
38
+ function serializeBoundedVec(values: Fr[], maxLength: number): Fr[] {
39
+ const lengthDiff = maxLength - values.length;
40
+ const zeroPaddingArray = Array(lengthDiff).fill(Fr.ZERO);
41
+ const storage = values.concat(zeroPaddingArray);
42
+ return [...storage, new Fr(values.length)];
43
+ }
@@ -1,8 +1,7 @@
1
1
  import { Grumpkin } from '@aztec/foundation/crypto';
2
2
  import type { GrumpkinScalar, Point } from '@aztec/foundation/fields';
3
3
 
4
- import type { AztecAddress } from '../../aztec-address/index.js';
5
- import type { PublicKey } from '../../keys/public_key.js';
4
+ import type { PublicKey } from '../keys/public_key.js';
6
5
 
7
6
  /**
8
7
  * Derive an Elliptic Curve Diffie-Hellman (ECDH) Shared Secret.
@@ -13,6 +12,9 @@ import type { PublicKey } from '../../keys/public_key.js';
13
12
  * @param publicKey - The public key used to derive shared secret.
14
13
  * @returns A derived shared secret.
15
14
  * @throws If the publicKey is zero.
15
+ *
16
+ * TODO(#12656): This function is kept around because of the getSharedSecret oracle. Nuke this once returning
17
+ * the app-siloed secret.
16
18
  */
17
19
  export async function deriveEcdhSharedSecret(secretKey: GrumpkinScalar, publicKey: PublicKey): Promise<Point> {
18
20
  if (publicKey.isZero()) {
@@ -24,12 +26,3 @@ export async function deriveEcdhSharedSecret(secretKey: GrumpkinScalar, publicKe
24
26
  const sharedSecret = await curve.mul(publicKey, secretKey);
25
27
  return sharedSecret;
26
28
  }
27
-
28
- export async function deriveEcdhSharedSecretUsingAztecAddress(
29
- secretKey: GrumpkinScalar,
30
- address: AztecAddress,
31
- ): Promise<Point> {
32
- const addressPoint = await address.toAddressPoint();
33
- const sharedSecret = await deriveEcdhSharedSecret(secretKey, addressPoint);
34
- return sharedSecret;
35
- }
@@ -17,6 +17,11 @@ export class TxScopedL2Log {
17
17
  * with the log so the noteHashIndex can be reconstructed after decryption.
18
18
  */
19
19
  public dataStartIndexForTx: number,
20
+ /*
21
+ * The index of the log in the transaction. Note that public and private logs are in separate arrays in the tx
22
+ * effect and for this reason these indices are independent (a private and public log can have the same index).
23
+ */
24
+ public logIndexInTx: number,
20
25
  /*
21
26
  * The block this log is included in
22
27
  */
@@ -36,12 +41,13 @@ export class TxScopedL2Log {
36
41
  .object({
37
42
  txHash: TxHash.schema,
38
43
  dataStartIndexForTx: z.number(),
44
+ logIndexInTx: z.number(),
39
45
  blockNumber: z.number(),
40
46
  log: z.union([PrivateLog.schema, PublicLog.schema]),
41
47
  })
42
48
  .transform(
43
- ({ txHash, dataStartIndexForTx, blockNumber, log }) =>
44
- new TxScopedL2Log(txHash, dataStartIndexForTx, blockNumber, log),
49
+ ({ txHash, dataStartIndexForTx, logIndexInTx, blockNumber, log }) =>
50
+ new TxScopedL2Log(txHash, dataStartIndexForTx, logIndexInTx, blockNumber, log),
45
51
  );
46
52
  }
47
53
 
@@ -50,6 +56,7 @@ export class TxScopedL2Log {
50
56
  return Buffer.concat([
51
57
  this.txHash.toBuffer(),
52
58
  numToUInt32BE(this.dataStartIndexForTx),
59
+ numToUInt32BE(this.logIndexInTx),
53
60
  numToUInt32BE(this.blockNumber),
54
61
  boolToBuffer(isFromPublic),
55
62
  this.log.toBuffer(),
@@ -60,23 +67,25 @@ export class TxScopedL2Log {
60
67
  const reader = BufferReader.asReader(buffer);
61
68
  const txHash = reader.readObject(TxHash);
62
69
  const dataStartIndexForTx = reader.readNumber();
70
+ const logIndexInTx = reader.readNumber();
63
71
  const blockNumber = reader.readNumber();
64
72
  const isFromPublic = reader.readBoolean();
65
73
  const log = isFromPublic ? PublicLog.fromBuffer(reader) : PrivateLog.fromBuffer(reader);
66
74
 
67
- return new TxScopedL2Log(txHash, dataStartIndexForTx, blockNumber, log);
75
+ return new TxScopedL2Log(txHash, dataStartIndexForTx, logIndexInTx, blockNumber, log);
68
76
  }
69
77
 
70
78
  static async random() {
71
79
  const isFromPublic = Math.random() < 0.5;
72
80
  const log = isFromPublic ? await PublicLog.random() : PrivateLog.random();
73
- return new TxScopedL2Log(TxHash.random(), 1, 1, log);
81
+ return new TxScopedL2Log(TxHash.random(), 1, 1, 1, log);
74
82
  }
75
83
 
76
84
  equals(other: TxScopedL2Log) {
77
85
  return (
78
86
  this.txHash.equals(other.txHash) &&
79
87
  this.dataStartIndexForTx === other.dataStartIndexForTx &&
88
+ this.logIndexInTx === other.logIndexInTx &&
80
89
  this.blockNumber === other.blockNumber &&
81
90
  ((this.log instanceof PublicLog && other.log instanceof PublicLog) ||
82
91
  (this.log instanceof PrivateLog && other.log instanceof PrivateLog)) &&
package/src/note/note.ts CHANGED
@@ -1,16 +1,72 @@
1
+ import { randomInt } from '@aztec/foundation/crypto';
1
2
  import { Fr } from '@aztec/foundation/fields';
2
- import { schemas } from '@aztec/foundation/schemas';
3
3
  import { BufferReader } from '@aztec/foundation/serialize';
4
+ import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
4
5
 
5
- import { Payload } from '../logs/l1_payload/payload.js';
6
+ import { schemas } from '../schemas/index.js';
7
+ import { Vector } from '../types/shared.js';
6
8
 
7
- export class Note extends Payload {
8
- static override get schema() {
9
+ /**
10
+ * The Note class represents a Note emitted from a Noir contract as a vector of Fr (finite field) elements.
11
+ * This data also represents a preimage to a note hash.
12
+ */
13
+ export class Note extends Vector<Fr> {
14
+ toJSON() {
15
+ return this.toBuffer();
16
+ }
17
+
18
+ static get schema() {
9
19
  return schemas.Buffer.transform(Note.fromBuffer);
10
20
  }
11
21
 
12
- static override fromBuffer(buffer: Buffer | BufferReader) {
22
+ /**
23
+ * Create a Note instance from a Buffer or BufferReader.
24
+ * The input 'buffer' can be either a Buffer containing the serialized Fr elements or a BufferReader instance.
25
+ * This function reads the Fr elements in the buffer and constructs a Note with them.
26
+ *
27
+ * @param buffer - The Buffer or BufferReader containing the serialized Fr elements.
28
+ * @returns A Note instance containing the deserialized Fr elements.
29
+ */
30
+ static fromBuffer(buffer: Buffer | BufferReader) {
13
31
  const reader = BufferReader.asReader(buffer);
14
32
  return new Note(reader.readVector(Fr));
15
33
  }
34
+
35
+ /**
36
+ * Generates a random Note instance with a variable number of items.
37
+ * The number of items is determined by a random value between 1 and 10 (inclusive).
38
+ * Each item in the Note is generated using the Fr.random() method.
39
+ *
40
+ * @returns A randomly generated Note instance.
41
+ */
42
+ static random() {
43
+ const numItems = randomInt(10) + 1;
44
+ const items = Array.from({ length: numItems }, () => Fr.random());
45
+ return new Note(items);
46
+ }
47
+
48
+ /**
49
+ * Returns a hex representation of the note.
50
+ * @returns A hex string with the vector length as first element.
51
+ */
52
+ override toString() {
53
+ return bufferToHex(this.toBuffer());
54
+ }
55
+
56
+ /**
57
+ * Creates a new Note instance from a hex string.
58
+ * @param str - Hex representation.
59
+ * @returns A Note instance.
60
+ */
61
+ static fromString(str: string) {
62
+ return Note.fromBuffer(hexToBuffer(str));
63
+ }
64
+
65
+ get length() {
66
+ return this.items.length;
67
+ }
68
+
69
+ equals(other: Note) {
70
+ return this.items.every((item, index) => item.equals(other.items[index]));
71
+ }
16
72
  }
@@ -3,6 +3,8 @@ import { Fr } from '@aztec/foundation/fields';
3
3
  import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
4
4
  import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
5
5
 
6
+ import { strict as assert } from 'assert';
7
+
6
8
  const EMPTY_PROOF_SIZE = 42;
7
9
 
8
10
  /**
@@ -17,6 +19,7 @@ export class Proof {
17
19
 
18
20
  // Honk proofs start with a 4 byte length prefix
19
21
  // the proof metadata starts immediately after
22
+ // TODO(https://github.com/AztecProtocol/barretenberg/issues/1312): Get rid of if possible.
20
23
  private readonly metadataOffset = 4;
21
24
 
22
25
  constructor(
@@ -62,19 +65,50 @@ export class Proof {
62
65
  }
63
66
 
64
67
  public withoutPublicInputs(): Buffer {
65
- return Buffer.concat([this.buffer.subarray(this.metadataOffset + Fr.SIZE_IN_BYTES * this.numPublicInputs)]);
68
+ if (this.isEmpty()) {
69
+ return this.buffer;
70
+ }
71
+ // We are indexing to this particular size because we are assuming the proof buffer looks like:
72
+ // [4 bytes of metadata for public inputs, binary public inputs, 4 bytes of metadata for proof, binary proof]
73
+ const proofStart = this.metadataOffset + Fr.SIZE_IN_BYTES * this.numPublicInputs + this.metadataOffset;
74
+ assert(this.buffer.length >= proofStart, 'Proof buffer is not appropriately sized to call withoutPublicInputs()');
75
+ return this.buffer.subarray(proofStart);
66
76
  }
67
77
 
78
+ // This function assumes that the proof will contain an aggregation object and look something like:
79
+ // [4 bytes of metadata for public inputs, binary public inputs, 4 bytes of metadata for proof, aggregation object, rest of proof]
80
+ // We are extracting the binary public inputs and reading them as Frs, and also extracting the aggregation object.
68
81
  public extractPublicInputs(): Fr[] {
82
+ if (this.isEmpty()) {
83
+ // return array of this.numPublicInputs 0s
84
+ return new Array(this.numPublicInputs).fill(Fr.zero());
85
+ }
86
+ assert(this.numPublicInputs >= AGGREGATION_OBJECT_LENGTH, 'Proof does not contain an aggregation object');
87
+ const numInnerPublicInputs = this.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
69
88
  const reader = BufferReader.asReader(
70
- this.buffer.subarray(this.metadataOffset, this.metadataOffset + Fr.SIZE_IN_BYTES * this.numPublicInputs),
89
+ this.buffer.subarray(this.metadataOffset, this.metadataOffset + Fr.SIZE_IN_BYTES * numInnerPublicInputs),
71
90
  );
72
- return reader.readArray(this.numPublicInputs, Fr);
91
+ let publicInputs = reader.readArray(numInnerPublicInputs, Fr);
92
+ // concatenate Fr[] with aggregation object
93
+ publicInputs = publicInputs.concat(this.extractAggregationObject());
94
+ return publicInputs;
73
95
  }
74
96
 
75
97
  public extractAggregationObject(): Fr[] {
76
- const publicInputs = this.extractPublicInputs();
77
- return publicInputs.slice(-1 * AGGREGATION_OBJECT_LENGTH);
98
+ if (this.isEmpty()) {
99
+ // return array of 16 0s
100
+ return new Array(16).fill(Fr.zero());
101
+ }
102
+ assert(this.numPublicInputs >= AGGREGATION_OBJECT_LENGTH, 'Proof does not contain an aggregation object');
103
+ const numInnerPublicInputs = this.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
104
+ // The aggregation object is currently stored after the initial inner public inputs and after the 4 byte proof metadata.
105
+ const reader = BufferReader.asReader(
106
+ this.buffer.subarray(
107
+ this.metadataOffset + Fr.SIZE_IN_BYTES * numInnerPublicInputs + this.metadataOffset,
108
+ this.metadataOffset + Fr.SIZE_IN_BYTES * this.numPublicInputs + this.metadataOffset,
109
+ ),
110
+ );
111
+ return reader.readArray(AGGREGATION_OBJECT_LENGTH, Fr);
78
112
  }
79
113
 
80
114
  /**
@@ -0,0 +1,60 @@
1
+ import { fromEntries, getEntries, maxBy } from '@aztec/foundation/collection';
2
+ import { jsonParseWithSchemaSync } from '@aztec/foundation/json-rpc';
3
+ import type { ReadOnlyFileStore } from '@aztec/stdlib/file-store';
4
+
5
+ import { join } from 'path';
6
+
7
+ import {
8
+ SnapshotDataKeys,
9
+ type SnapshotDataUrls,
10
+ type SnapshotMetadata,
11
+ type SnapshotsIndex,
12
+ type SnapshotsIndexMetadata,
13
+ SnapshotsIndexSchema,
14
+ } from './types.js';
15
+
16
+ export async function getSnapshotIndex(
17
+ metadata: SnapshotsIndexMetadata,
18
+ store: ReadOnlyFileStore,
19
+ ): Promise<SnapshotsIndex | undefined> {
20
+ const basePath = getBasePath(metadata);
21
+ const snapshotIndexPath = `${basePath}/index.json`;
22
+ try {
23
+ if (await store.exists(snapshotIndexPath)) {
24
+ const snapshotIndexData = await store.read(snapshotIndexPath);
25
+ return jsonParseWithSchemaSync(snapshotIndexData.toString(), SnapshotsIndexSchema);
26
+ } else {
27
+ return undefined;
28
+ }
29
+ } catch (err) {
30
+ throw new Error(`Error reading snapshot index from ${snapshotIndexPath}: ${err}`);
31
+ }
32
+ }
33
+
34
+ export async function getLatestSnapshotMetadata(
35
+ metadata: SnapshotsIndexMetadata,
36
+ store: ReadOnlyFileStore,
37
+ ): Promise<SnapshotMetadata | undefined> {
38
+ const snapshotsIndex = await getSnapshotIndex(metadata, store);
39
+ return snapshotsIndex?.snapshots && maxBy(snapshotsIndex?.snapshots, s => s.l1BlockNumber);
40
+ }
41
+
42
+ export function getBasePath(metadata: SnapshotsIndexMetadata): string {
43
+ return `aztec-${metadata.l1ChainId}-${metadata.rollupVersion}-${metadata.rollupAddress}`;
44
+ }
45
+
46
+ export function getSnapshotIndexPath(metadata: SnapshotsIndexMetadata): string {
47
+ return `${getBasePath(metadata)}/index.json`;
48
+ }
49
+
50
+ export function makeSnapshotLocalPaths(baseDir: string): SnapshotDataUrls {
51
+ return fromEntries(SnapshotDataKeys.map(key => [key, join(baseDir, `${key}.db`)]));
52
+ }
53
+
54
+ export async function downloadSnapshot(
55
+ snapshot: Pick<SnapshotMetadata, 'dataUrls'>,
56
+ localPaths: Record<SnapshotDataKeys, string>,
57
+ store: ReadOnlyFileStore,
58
+ ): Promise<void> {
59
+ await Promise.all(getEntries(localPaths).map(([key, path]) => store.download(snapshot.dataUrls[key], path)));
60
+ }
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './upload.js';
3
+ export { downloadSnapshot, getLatestSnapshotMetadata, makeSnapshotLocalPaths } from './download.js';
@@ -0,0 +1,58 @@
1
+ import type { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { type ZodFor, schemas } from '@aztec/foundation/schemas';
3
+
4
+ import { z } from 'zod';
5
+
6
+ export const SnapshotDataKeys = [
7
+ 'archiver',
8
+ 'nullifier-tree',
9
+ 'public-data-tree',
10
+ 'note-hash-tree',
11
+ 'archive-tree',
12
+ 'l1-to-l2-message-tree',
13
+ ] as const;
14
+
15
+ export type SnapshotDataKeys = (typeof SnapshotDataKeys)[number];
16
+
17
+ export type SnapshotDataUrls = Record<SnapshotDataKeys, string>;
18
+
19
+ export type SnapshotMetadata = {
20
+ l2BlockNumber: number;
21
+ l2BlockHash: string;
22
+ l1BlockNumber: number;
23
+ timestamp: number;
24
+ dataUrls: SnapshotDataUrls;
25
+ schemaVersions: { archiver: number; worldState: number };
26
+ };
27
+
28
+ export type SnapshotsIndexMetadata = {
29
+ l1ChainId: number;
30
+ rollupVersion: number;
31
+ rollupAddress: EthAddress;
32
+ };
33
+
34
+ export type SnapshotsIndex = SnapshotsIndexMetadata & {
35
+ snapshots: SnapshotMetadata[];
36
+ };
37
+
38
+ export const SnapshotsIndexSchema = z.object({
39
+ l1ChainId: z.number(),
40
+ rollupVersion: z.number(),
41
+ rollupAddress: schemas.EthAddress,
42
+ snapshots: z.array(
43
+ z.object({
44
+ l2BlockNumber: z.number(),
45
+ l2BlockHash: z.string(),
46
+ l1BlockNumber: z.number(),
47
+ timestamp: z.number(),
48
+ schemaVersions: z.object({
49
+ archiver: z.number(),
50
+ worldState: z.number(),
51
+ }),
52
+ dataUrls: z
53
+ .record(z.enum(SnapshotDataKeys), z.string())
54
+ // See https://stackoverflow.com/questions/77958464/zod-record-with-required-keys
55
+ .refine((obj): obj is Required<typeof obj> => SnapshotDataKeys.every(key => !!obj[key])),
56
+ }),
57
+ ),
58
+ }) satisfies ZodFor<SnapshotsIndex>;
@@ -0,0 +1,55 @@
1
+ import { fromEntries, getEntries, pick } from '@aztec/foundation/collection';
2
+ import { jsonStringify } from '@aztec/foundation/json-rpc';
3
+ import type { FileStore } from '@aztec/stdlib/file-store';
4
+
5
+ import { getBasePath, getSnapshotIndex, getSnapshotIndexPath } from './download.js';
6
+ import type { SnapshotDataKeys, SnapshotMetadata, SnapshotsIndex } from './types.js';
7
+
8
+ export type UploadSnapshotMetadata = Pick<SnapshotMetadata, 'l2BlockNumber' | 'l2BlockHash' | 'l1BlockNumber'> &
9
+ Pick<SnapshotsIndex, 'l1ChainId' | 'rollupVersion' | 'rollupAddress'>;
10
+
11
+ export async function uploadSnapshot(
12
+ localPaths: Record<SnapshotDataKeys, string>,
13
+ schemaVersions: SnapshotMetadata['schemaVersions'],
14
+ metadata: UploadSnapshotMetadata,
15
+ store: FileStore,
16
+ ): Promise<SnapshotMetadata> {
17
+ const timestamp = Date.now();
18
+ const date = new Date().toISOString().replace(/[-:T]/g, '').replace(/\..+$/, '');
19
+ const basePath = getBasePath(metadata);
20
+ const targetPathFor = (key: SnapshotDataKeys) => `${basePath}/${key}-${date}-${metadata.l2BlockHash}.db`;
21
+
22
+ const dataUrls = fromEntries(
23
+ await Promise.all(
24
+ getEntries(localPaths).map(
25
+ async ([key, path]) =>
26
+ [key, await store.upload(targetPathFor(key), path, { compress: true, public: true })] as const,
27
+ ),
28
+ ),
29
+ );
30
+
31
+ const snapshotsIndex = (await getSnapshotIndex(metadata, store)) ?? createEmptyIndex(metadata);
32
+
33
+ const newSnapshotMetadata: SnapshotMetadata = {
34
+ ...pick(metadata, 'l1BlockNumber', 'l2BlockHash', 'l2BlockNumber'),
35
+ schemaVersions,
36
+ timestamp,
37
+ dataUrls,
38
+ };
39
+ snapshotsIndex.snapshots.unshift(newSnapshotMetadata);
40
+
41
+ await store.save(getSnapshotIndexPath(metadata), Buffer.from(jsonStringify(snapshotsIndex, true)), {
42
+ public: true, // Make the index publicly accessible
43
+ metadata: { ['Cache-control']: 'no-store' }, // Do not cache object versions
44
+ });
45
+ return newSnapshotMetadata;
46
+ }
47
+
48
+ function createEmptyIndex(
49
+ metadata: Pick<SnapshotsIndex, 'l1ChainId' | 'rollupVersion' | 'rollupAddress'>,
50
+ ): SnapshotsIndex {
51
+ return {
52
+ ...pick(metadata, 'l1ChainId', 'rollupVersion', 'rollupAddress'),
53
+ snapshots: [],
54
+ };
55
+ }