@aztec/stdlib 2.0.3 → 2.1.0-rc.2

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 (77) hide show
  1. package/dest/block/in_block.d.ts +5 -5
  2. package/dest/block/in_block.d.ts.map +1 -1
  3. package/dest/block/proposal/attestations_and_signers.d.ts +48 -0
  4. package/dest/block/proposal/attestations_and_signers.d.ts.map +1 -0
  5. package/dest/block/proposal/attestations_and_signers.js +99 -0
  6. package/dest/block/proposal/committee_attestation.d.ts +1 -0
  7. package/dest/block/proposal/committee_attestation.d.ts.map +1 -1
  8. package/dest/block/proposal/committee_attestation.js +3 -0
  9. package/dest/block/proposal/index.d.ts +1 -0
  10. package/dest/block/proposal/index.d.ts.map +1 -1
  11. package/dest/block/proposal/index.js +1 -0
  12. package/dest/contract/interfaces/contract_class.d.ts +3 -3
  13. package/dest/epoch-helpers/index.d.ts +2 -0
  14. package/dest/epoch-helpers/index.d.ts.map +1 -1
  15. package/dest/epoch-helpers/index.js +3 -0
  16. package/dest/file-store/factory.d.ts.map +1 -1
  17. package/dest/file-store/factory.js +18 -0
  18. package/dest/file-store/interface.d.ts +8 -2
  19. package/dest/file-store/interface.d.ts.map +1 -1
  20. package/dest/file-store/s3.d.ts +26 -0
  21. package/dest/file-store/s3.d.ts.map +1 -0
  22. package/dest/file-store/s3.js +252 -0
  23. package/dest/interfaces/aztec-node-admin.d.ts +13 -7
  24. package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
  25. package/dest/interfaces/block-builder.d.ts +1 -0
  26. package/dest/interfaces/block-builder.d.ts.map +1 -1
  27. package/dest/interfaces/proving-job.d.ts +6 -6
  28. package/dest/interfaces/slasher.d.ts +4 -0
  29. package/dest/interfaces/slasher.d.ts.map +1 -1
  30. package/dest/interfaces/slasher.js +1 -0
  31. package/dest/interfaces/validator.d.ts +9 -2
  32. package/dest/interfaces/validator.d.ts.map +1 -1
  33. package/dest/interfaces/validator.js +2 -1
  34. package/dest/p2p/consensus_payload.d.ts +27 -0
  35. package/dest/p2p/consensus_payload.d.ts.map +1 -1
  36. package/dest/p2p/consensus_payload.js +10 -0
  37. package/dest/p2p/signature_utils.d.ts +2 -1
  38. package/dest/p2p/signature_utils.d.ts.map +1 -1
  39. package/dest/p2p/signature_utils.js +1 -0
  40. package/dest/slashing/types.d.ts +1 -0
  41. package/dest/slashing/types.d.ts.map +1 -1
  42. package/dest/slashing/types.js +22 -0
  43. package/dest/snapshots/download.d.ts.map +1 -1
  44. package/dest/snapshots/download.js +58 -2
  45. package/dest/snapshots/upload.d.ts.map +1 -1
  46. package/dest/snapshots/upload.js +1 -0
  47. package/dest/tests/mocks.d.ts +2 -0
  48. package/dest/tests/mocks.d.ts.map +1 -1
  49. package/dest/tests/mocks.js +4 -0
  50. package/dest/tx/indexed_tx_effect.d.ts +3 -3
  51. package/dest/tx/proposed_block_header.d.ts +1 -0
  52. package/dest/tx/proposed_block_header.d.ts.map +1 -1
  53. package/dest/tx/proposed_block_header.js +3 -0
  54. package/dest/tx/state_reference.js +1 -1
  55. package/dest/tx/tx.d.ts +0 -7
  56. package/dest/tx/tx.d.ts.map +1 -1
  57. package/dest/tx/tx.js +0 -8
  58. package/package.json +10 -9
  59. package/src/block/proposal/attestations_and_signers.ts +121 -0
  60. package/src/block/proposal/committee_attestation.ts +4 -0
  61. package/src/block/proposal/index.ts +1 -0
  62. package/src/epoch-helpers/index.ts +8 -0
  63. package/src/file-store/factory.ts +15 -0
  64. package/src/file-store/interface.ts +8 -2
  65. package/src/file-store/s3.ts +254 -0
  66. package/src/interfaces/block-builder.ts +1 -0
  67. package/src/interfaces/slasher.ts +2 -0
  68. package/src/interfaces/validator.ts +12 -2
  69. package/src/p2p/consensus_payload.ts +16 -0
  70. package/src/p2p/signature_utils.ts +1 -0
  71. package/src/slashing/types.ts +23 -0
  72. package/src/snapshots/download.ts +66 -2
  73. package/src/snapshots/upload.ts +1 -0
  74. package/src/tests/mocks.ts +12 -0
  75. package/src/tx/proposed_block_header.ts +13 -0
  76. package/src/tx/state_reference.ts +1 -1
  77. package/src/tx/tx.ts +0 -10
@@ -63,6 +63,14 @@ export class ConsensusPayload implements Signable {
63
63
  return serializeToBuffer([this.header, this.archive, this.stateReference]);
64
64
  }
65
65
 
66
+ public equals(other: ConsensusPayload): boolean {
67
+ return (
68
+ this.header.equals(other.header) &&
69
+ this.archive.equals(other.archive) &&
70
+ this.stateReference.equals(other.stateReference)
71
+ );
72
+ }
73
+
66
74
  static fromBuffer(buf: Buffer | BufferReader): ConsensusPayload {
67
75
  const reader = BufferReader.asReader(buf);
68
76
  const payload = new ConsensusPayload(
@@ -102,6 +110,14 @@ export class ConsensusPayload implements Signable {
102
110
  return this.size;
103
111
  }
104
112
 
113
+ toInspect() {
114
+ return {
115
+ header: this.header.toInspect(),
116
+ archive: this.archive.toString(),
117
+ stateReference: this.stateReference.toInspect(),
118
+ };
119
+ }
120
+
105
121
  toString() {
106
122
  return `header: ${this.header.toString()}, archive: ${this.archive.toString()}, stateReference: ${this.stateReference.l1ToL2MessageTree.root.toString()}`;
107
123
  }
@@ -4,6 +4,7 @@ import { keccak256, makeEthSignDigest } from '@aztec/foundation/crypto';
4
4
  export enum SignatureDomainSeparator {
5
5
  blockProposal = 0,
6
6
  blockAttestation = 1,
7
+ attestationsAndSigners = 2,
7
8
  }
8
9
 
9
10
  export interface Signable {
@@ -22,6 +22,29 @@ export enum OffenseType {
22
22
  ATTESTED_DESCENDANT_OF_INVALID = 7,
23
23
  }
24
24
 
25
+ export function getOffenseTypeName(offense: OffenseType) {
26
+ switch (offense) {
27
+ case OffenseType.UNKNOWN:
28
+ return 'unknown';
29
+ case OffenseType.DATA_WITHHOLDING:
30
+ return 'data_withholding';
31
+ case OffenseType.VALID_EPOCH_PRUNED:
32
+ return 'valid_epoch_pruned';
33
+ case OffenseType.INACTIVITY:
34
+ return 'inactivity';
35
+ case OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL:
36
+ return 'broadcasted_invalid_block_proposal';
37
+ case OffenseType.PROPOSED_INSUFFICIENT_ATTESTATIONS:
38
+ return 'proposed_insufficient_attestations';
39
+ case OffenseType.PROPOSED_INCORRECT_ATTESTATIONS:
40
+ return 'proposed_incorrect_attestations';
41
+ case OffenseType.ATTESTED_DESCENDANT_OF_INVALID:
42
+ return 'attested_descendant_of_invalid';
43
+ default:
44
+ throw new Error(`Unknown offense type: ${offense}`);
45
+ }
46
+ }
47
+
25
48
  export const OffenseTypeSchema = z.nativeEnum(OffenseType);
26
49
 
27
50
  export const OffenseToBigInt: Record<OffenseType, bigint> = {
@@ -2,6 +2,12 @@ import { fromEntries, getEntries, maxBy } from '@aztec/foundation/collection';
2
2
  import { jsonParseWithSchema } from '@aztec/foundation/json-rpc';
3
3
  import type { ReadOnlyFileStore } from '@aztec/stdlib/file-store';
4
4
 
5
+ import { createReadStream, createWriteStream } from 'fs';
6
+ import fs from 'fs/promises';
7
+ import pathMod from 'path';
8
+ import { pipeline } from 'stream/promises';
9
+ import { createGunzip, gunzipSync } from 'zlib';
10
+
5
11
  import {
6
12
  SnapshotDataKeys,
7
13
  type SnapshotDataUrls,
@@ -20,7 +26,8 @@ export async function getSnapshotIndex(
20
26
  try {
21
27
  if (await store.exists(snapshotIndexPath)) {
22
28
  const snapshotIndexData = await store.read(snapshotIndexPath);
23
- return jsonParseWithSchema(snapshotIndexData.toString(), SnapshotsIndexSchema);
29
+ const buf = maybeGunzip(snapshotIndexData);
30
+ return jsonParseWithSchema(buf.toString('utf-8'), SnapshotsIndexSchema);
24
31
  } else {
25
32
  return undefined;
26
33
  }
@@ -50,10 +57,67 @@ export function makeSnapshotPaths(baseDir: string): SnapshotDataUrls {
50
57
  return fromEntries(SnapshotDataKeys.map(key => [key, `${baseDir}/${key}.db`]));
51
58
  }
52
59
 
60
+ function isGzipMagic(data: Buffer): boolean {
61
+ return data.length >= 2 && data[0] === 0x1f && data[1] === 0x8b;
62
+ }
63
+
64
+ function maybeGunzip(data: Buffer): Buffer {
65
+ const magicNumberIndicatesGzip = isGzipMagic(data);
66
+
67
+ if (magicNumberIndicatesGzip) {
68
+ try {
69
+ const out = gunzipSync(data);
70
+ return out;
71
+ } catch (err) {
72
+ throw new Error(`Decompression of gzipped data failed: ${(err as Error).message}`);
73
+ }
74
+ }
75
+ return data;
76
+ }
77
+
78
+ async function detectGzip(localFilePathToPeek: string): Promise<boolean> {
79
+ // Peek the actual bytes we downloaded.
80
+ try {
81
+ const fd = await fs.open(localFilePathToPeek, 'r');
82
+ try {
83
+ const header = Buffer.alloc(2);
84
+ const { bytesRead } = await fd.read(header, 0, 2, 0);
85
+ return bytesRead >= 2 && isGzipMagic(header);
86
+ } finally {
87
+ await fd.close();
88
+ }
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
53
94
  export async function downloadSnapshot(
54
95
  snapshot: Pick<SnapshotMetadata, 'dataUrls'>,
55
96
  localPaths: Record<SnapshotDataKeys, string>,
56
97
  store: ReadOnlyFileStore,
57
98
  ): Promise<void> {
58
- await Promise.all(getEntries(localPaths).map(([key, path]) => store.download(snapshot.dataUrls[key], path)));
99
+ await Promise.all(
100
+ getEntries(localPaths).map(async ([key, path]) => {
101
+ await fs.mkdir(pathMod.dirname(path), { recursive: true });
102
+
103
+ const tmpPath = `${path}.download`;
104
+ try {
105
+ const url = snapshot.dataUrls[key];
106
+ await store.download(url, tmpPath);
107
+
108
+ const isGzip = await detectGzip(tmpPath);
109
+
110
+ const read = createReadStream(tmpPath);
111
+ const write = createWriteStream(path);
112
+ if (isGzip) {
113
+ const gunzip = createGunzip();
114
+ await pipeline(read, gunzip, write);
115
+ } else {
116
+ await pipeline(read, write);
117
+ }
118
+ } finally {
119
+ await fs.unlink(tmpPath).catch(() => undefined);
120
+ }
121
+ }),
122
+ );
59
123
  }
@@ -48,6 +48,7 @@ export async function uploadSnapshotToIndex(
48
48
 
49
49
  await store.save(getSnapshotIndexPath(metadata), Buffer.from(jsonStringify(snapshotsIndex, true)), {
50
50
  public: true, // Make the index publicly accessible
51
+ compress: false, // Ensure index.json is not gzipped
51
52
  metadata: { ['Cache-control']: 'no-store' }, // Do not cache object versions
52
53
  });
53
54
  return newSnapshotMetadata;
@@ -8,6 +8,7 @@ import type { ContractArtifact } from '../abi/abi.js';
8
8
  import { AztecAddress } from '../aztec-address/index.js';
9
9
  import { CommitteeAttestation, L1PublishedData } from '../block/index.js';
10
10
  import { L2Block } from '../block/l2_block.js';
11
+ import type { CommitteeAttestationsAndSigners } from '../block/proposal/attestations_and_signers.js';
11
12
  import { PublishedL2Block } from '../block/published_l2_block.js';
12
13
  import { computeContractAddressFromInstance } from '../contract/contract_address.js';
13
14
  import { getContractClassFromArtifact } from '../contract/contract_class.js';
@@ -273,6 +274,17 @@ const makeAndSignConsensusPayload = (
273
274
  return { blockNumber: header.globalVariables.blockNumber, payload, signature };
274
275
  };
275
276
 
277
+ export const makeAndSignCommitteeAttestationsAndSigners = (
278
+ attestationsAndSigners: CommitteeAttestationsAndSigners,
279
+ signer: Secp256k1Signer = Secp256k1Signer.random(),
280
+ ) => {
281
+ const hash = getHashedSignaturePayloadEthSignedMessage(
282
+ attestationsAndSigners,
283
+ SignatureDomainSeparator.attestationsAndSigners,
284
+ );
285
+ return signer.sign(hash);
286
+ };
287
+
276
288
  export const makeBlockProposal = (options?: MakeConsensusPayloadOptions): BlockProposal => {
277
289
  const { blockNumber, payload, signature } = makeAndSignConsensusPayload(
278
290
  SignatureDomainSeparator.blockProposal,
@@ -84,6 +84,19 @@ export class ProposedBlockHeader {
84
84
  );
85
85
  }
86
86
 
87
+ equals(other: ProposedBlockHeader): boolean {
88
+ return (
89
+ this.lastArchiveRoot.equals(other.lastArchiveRoot) &&
90
+ this.contentCommitment.equals(other.contentCommitment) &&
91
+ this.slotNumber.equals(other.slotNumber) &&
92
+ this.timestamp === other.timestamp &&
93
+ this.coinbase.equals(other.coinbase) &&
94
+ this.feeRecipient.equals(other.feeRecipient) &&
95
+ this.gasFees.equals(other.gasFees) &&
96
+ this.totalManaUsed.equals(other.totalManaUsed)
97
+ );
98
+ }
99
+
87
100
  toBuffer() {
88
101
  // Note: The order here must match the order in the ProposedHeaderLib solidity library.
89
102
  return serializeToBuffer([
@@ -137,6 +137,6 @@ export class StateReference {
137
137
  }
138
138
 
139
139
  public equals(other: this): boolean {
140
- return this.l1ToL2MessageTree.root.equals(other.l1ToL2MessageTree.root) && this.partial.equals(other.partial);
140
+ return this.l1ToL2MessageTree.equals(other.l1ToL2MessageTree) && this.partial.equals(other.partial);
141
141
  }
142
142
  }
package/src/tx/tx.ts CHANGED
@@ -207,16 +207,6 @@ export class Tx extends Gossipable {
207
207
  return this.txHash;
208
208
  }
209
209
 
210
- /**
211
- * Allows setting the hash of the Tx.
212
- * Use this when you want to skip computing it from the original data.
213
- * Don't set a Tx hash received from an untrusted source.
214
- * @param hash - The hash to set.
215
- */
216
- setTxHash(_hash: TxHash) {
217
- return this;
218
- }
219
-
220
210
  getCalldataMap(): Map<string, Fr[]> {
221
211
  if (!this.calldataMap) {
222
212
  const calldataMap = new Map();