@aztec/stdlib 2.1.0-rc.2 → 2.1.0-rc.21

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 (62) hide show
  1. package/dest/block/attestation_info.d.ts +30 -0
  2. package/dest/block/attestation_info.d.ts.map +1 -0
  3. package/dest/block/attestation_info.js +39 -0
  4. package/dest/block/index.d.ts +1 -0
  5. package/dest/block/index.d.ts.map +1 -1
  6. package/dest/block/index.js +1 -0
  7. package/dest/block/l2_block_source.d.ts +29 -0
  8. package/dest/block/l2_block_source.d.ts.map +1 -1
  9. package/dest/block/published_l2_block.d.ts +0 -2
  10. package/dest/block/published_l2_block.d.ts.map +1 -1
  11. package/dest/block/published_l2_block.js +0 -6
  12. package/dest/interfaces/archiver.d.ts.map +1 -1
  13. package/dest/interfaces/archiver.js +7 -0
  14. package/dest/interfaces/aztec-node-admin.d.ts +38 -34
  15. package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
  16. package/dest/interfaces/aztec-node-admin.js +2 -2
  17. package/dest/interfaces/aztec-node.d.ts +24 -0
  18. package/dest/interfaces/aztec-node.d.ts.map +1 -1
  19. package/dest/interfaces/aztec-node.js +4 -0
  20. package/dest/interfaces/configs.d.ts +5 -0
  21. package/dest/interfaces/configs.d.ts.map +1 -1
  22. package/dest/interfaces/configs.js +2 -1
  23. package/dest/interfaces/p2p.d.ts +2 -0
  24. package/dest/interfaces/p2p.d.ts.map +1 -1
  25. package/dest/interfaces/p2p.js +2 -1
  26. package/dest/interfaces/tx_provider.d.ts +1 -1
  27. package/dest/interfaces/tx_provider.d.ts.map +1 -1
  28. package/dest/interfaces/validator.d.ts +93 -1
  29. package/dest/interfaces/validator.d.ts.map +1 -1
  30. package/dest/interfaces/validator.js +6 -0
  31. package/dest/p2p/block_attestation.d.ts +44 -9
  32. package/dest/p2p/block_attestation.d.ts.map +1 -1
  33. package/dest/p2p/block_attestation.js +35 -16
  34. package/dest/p2p/block_proposal.d.ts +4 -8
  35. package/dest/p2p/block_proposal.d.ts.map +1 -1
  36. package/dest/p2p/block_proposal.js +10 -13
  37. package/dest/p2p/gossipable.d.ts +2 -4
  38. package/dest/p2p/gossipable.d.ts.map +1 -1
  39. package/dest/p2p/gossipable.js +5 -14
  40. package/dest/tests/mocks.d.ts +3 -1
  41. package/dest/tests/mocks.d.ts.map +1 -1
  42. package/dest/tests/mocks.js +33 -11
  43. package/dest/zkpassport/index.d.ts +15 -9
  44. package/dest/zkpassport/index.d.ts.map +1 -1
  45. package/dest/zkpassport/index.js +17 -11
  46. package/package.json +9 -9
  47. package/src/block/attestation_info.ts +62 -0
  48. package/src/block/index.ts +1 -0
  49. package/src/block/l2_block_source.ts +32 -0
  50. package/src/block/published_l2_block.ts +0 -11
  51. package/src/interfaces/archiver.ts +8 -0
  52. package/src/interfaces/aztec-node-admin.ts +2 -2
  53. package/src/interfaces/aztec-node.ts +36 -0
  54. package/src/interfaces/configs.ts +3 -0
  55. package/src/interfaces/p2p.ts +4 -0
  56. package/src/interfaces/tx_provider.ts +1 -0
  57. package/src/interfaces/validator.ts +14 -1
  58. package/src/p2p/block_attestation.ts +43 -16
  59. package/src/p2p/block_proposal.ts +9 -16
  60. package/src/p2p/gossipable.ts +6 -16
  61. package/src/tests/mocks.ts +53 -17
  62. package/src/zkpassport/index.ts +40 -28
@@ -1,15 +1,21 @@
1
1
  import { Buffer32 } from '@aztec/foundation/buffer';
2
2
  import { Fr } from '@aztec/foundation/fields';
3
3
  export type ViemZkPassportProofParams = {
4
- vkeyHash: `0x${string}`;
5
- proof: `0x${string}`;
6
- publicInputs: `0x${string}`[];
7
- committedInputs: `0x${string}`;
8
- committedInputCounts: bigint[];
9
- validityPeriodInSeconds: bigint;
10
- domain: string;
11
- scope: string;
12
- devMode: boolean;
4
+ proofVerificationData: {
5
+ vkeyHash: `0x${string}`;
6
+ proof: `0x${string}`;
7
+ publicInputs: `0x${string}`[];
8
+ };
9
+ commitments: {
10
+ committedInputs: `0x${string}`;
11
+ committedInputCounts: bigint[];
12
+ };
13
+ serviceConfig: {
14
+ validityPeriodInSeconds: bigint;
15
+ domain: string;
16
+ scope: string;
17
+ devMode: boolean;
18
+ };
13
19
  };
14
20
  export declare class ZkPassportProofParams {
15
21
  devMode: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/zkpassport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAI9C,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC;IAC9B,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAC/B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAIF,qBAAa,qBAAqB;IAEvB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,MAAM;IACb,YAAY,EAAE,EAAE,EAAE;IAClB,eAAe,EAAE,MAAM;IACvB,oBAAoB,EAAE,MAAM,EAAE;IAC9B,uBAAuB,EAAE,MAAM;IAC/B,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,MAAM;gBARb,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,EAAE,EAAE,EAClB,eAAe,EAAE,MAAM,EACvB,oBAAoB,EAAE,MAAM,EAAE,EAC9B,uBAAuB,EAAE,MAAM,EAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM;IAGtB,QAAQ;IAkBR,MAAM,CAAC,MAAM;IAqBb,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM;IAehC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;IAcjD,MAAM,IAAI,yBAAyB;CAapC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/zkpassport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAI9C,MAAM,MAAM,yBAAyB,GAAG;IACtC,qBAAqB,EAAE;QACrB,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;QACxB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;QACrB,YAAY,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC;KAC/B,CAAC;IACF,WAAW,EAAE;QACX,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;QAC/B,oBAAoB,EAAE,MAAM,EAAE,CAAC;KAChC,CAAC;IACF,aAAa,EAAE;QACb,uBAAuB,EAAE,MAAM,CAAC;QAChC,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH,CAAC;AAIF,qBAAa,qBAAqB;IAEvB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,MAAM;IACb,YAAY,EAAE,EAAE,EAAE;IAClB,eAAe,EAAE,MAAM;IACvB,oBAAoB,EAAE,MAAM,EAAE;IAC9B,uBAAuB,EAAE,MAAM;IAC/B,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,MAAM;gBARb,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,EAAE,EAAE,EAClB,eAAe,EAAE,MAAM,EACvB,oBAAoB,EAAE,MAAM,EAAE,EAC9B,uBAAuB,EAAE,MAAM,EAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM;IAGtB,QAAQ;IAkBR,MAAM,CAAC,MAAM;IAqBb,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM;IAehC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;IAcjD,MAAM,IAAI,yBAAyB;CAmBpC"}
@@ -56,26 +56,32 @@ export class ZkPassportProofParams {
56
56
  const publicInputs = Array.from({
57
57
  length: Number(publicInputsCount)
58
58
  }, ()=>Fr.random());
59
- return new ZkPassportProofParams(false, Buffer32.random(), randomBytes(1024), publicInputs, committedInputs, committedInputCounts, BigInt(100 * 60 * 60 * 24), 'sequencer.alpha-testnet.aztec.network', 'personhood');
59
+ return new ZkPassportProofParams(false, Buffer32.random(), randomBytes(1024), publicInputs, committedInputs, committedInputCounts, BigInt(7 * 24 * 60 * 60), 'sequencer.alpha-testnet.aztec.network', 'personhood');
60
60
  }
61
61
  static fromBuffer(buffer) {
62
62
  const reader = BufferReader.asReader(buffer);
63
63
  return new ZkPassportProofParams(reader.readBoolean(), reader.readObject(Buffer32), reader.readBuffer(), reader.readVector(Fr), reader.readBuffer(), reader.readUint256Vector(), reader.readUInt256(), reader.readString(), reader.readString());
64
64
  }
65
65
  static fromViem(params) {
66
- return new ZkPassportProofParams(params.devMode, Buffer32.fromString(params.vkeyHash), Buffer.from(withoutHexPrefix(params.proof), 'hex'), params.publicInputs.map((input)=>Fr.fromString(input)), Buffer.from(withoutHexPrefix(params.committedInputs), 'hex'), params.committedInputCounts, params.validityPeriodInSeconds, params.domain, params.scope);
66
+ return new ZkPassportProofParams(params.serviceConfig.devMode, Buffer32.fromString(params.proofVerificationData.vkeyHash), Buffer.from(withoutHexPrefix(params.proofVerificationData.proof), 'hex'), params.proofVerificationData.publicInputs.map((input)=>Fr.fromString(input)), Buffer.from(withoutHexPrefix(params.commitments.committedInputs), 'hex'), params.commitments.committedInputCounts, params.serviceConfig.validityPeriodInSeconds, params.serviceConfig.domain, params.serviceConfig.scope);
67
67
  }
68
68
  toViem() {
69
69
  return {
70
- devMode: this.devMode,
71
- vkeyHash: this.vkeyHash.toString(),
72
- proof: `0x${this.proof.toString('hex')}`,
73
- publicInputs: this.publicInputs.map((input)=>input.toString()),
74
- committedInputs: `0x${this.committedInputs.toString('hex')}`,
75
- committedInputCounts: this.committedInputCounts,
76
- validityPeriodInSeconds: this.validityPeriodInSeconds,
77
- domain: this.domain,
78
- scope: this.scope
70
+ serviceConfig: {
71
+ devMode: this.devMode,
72
+ validityPeriodInSeconds: this.validityPeriodInSeconds,
73
+ domain: this.domain,
74
+ scope: this.scope
75
+ },
76
+ proofVerificationData: {
77
+ vkeyHash: this.vkeyHash.toString(),
78
+ proof: `0x${this.proof.toString('hex')}`,
79
+ publicInputs: this.publicInputs.map((input)=>input.toString())
80
+ },
81
+ commitments: {
82
+ committedInputs: `0x${this.committedInputs.toString('hex')}`,
83
+ committedInputCounts: this.committedInputCounts
84
+ }
79
85
  };
80
86
  }
81
87
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/stdlib",
3
- "version": "2.1.0-rc.2",
3
+ "version": "2.1.0-rc.21",
4
4
  "type": "module",
5
5
  "inherits": [
6
6
  "../package.common.json",
@@ -70,13 +70,13 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "@aws-sdk/client-s3": "^3.892.0",
73
- "@aztec/bb.js": "2.1.0-rc.2",
74
- "@aztec/blob-lib": "2.1.0-rc.2",
75
- "@aztec/constants": "2.1.0-rc.2",
76
- "@aztec/ethereum": "2.1.0-rc.2",
77
- "@aztec/foundation": "2.1.0-rc.2",
78
- "@aztec/l1-artifacts": "2.1.0-rc.2",
79
- "@aztec/noir-noirc_abi": "2.1.0-rc.2",
73
+ "@aztec/bb.js": "2.1.0-rc.21",
74
+ "@aztec/blob-lib": "2.1.0-rc.21",
75
+ "@aztec/constants": "2.1.0-rc.21",
76
+ "@aztec/ethereum": "2.1.0-rc.21",
77
+ "@aztec/foundation": "2.1.0-rc.21",
78
+ "@aztec/l1-artifacts": "2.1.0-rc.21",
79
+ "@aztec/noir-noirc_abi": "2.1.0-rc.21",
80
80
  "@google-cloud/storage": "^7.15.0",
81
81
  "axios": "^1.12.0",
82
82
  "json-stringify-deterministic": "1.0.12",
@@ -87,7 +87,7 @@
87
87
  "msgpackr": "^1.11.2",
88
88
  "pako": "^2.1.0",
89
89
  "tslib": "^2.4.0",
90
- "viem": "2.23.7",
90
+ "viem": "npm:@spalladino/viem@2.38.2-eip7594.0",
91
91
  "zod": "^3.23.8"
92
92
  },
93
93
  "devDependencies": {
@@ -0,0 +1,62 @@
1
+ import { recoverAddress } from '@aztec/foundation/crypto';
2
+ import type { EthAddress } from '@aztec/foundation/eth-address';
3
+
4
+ import { ConsensusPayload } from '../p2p/consensus_payload.js';
5
+ import { SignatureDomainSeparator, getHashedSignaturePayloadEthSignedMessage } from '../p2p/signature_utils.js';
6
+ import type { L2Block } from './l2_block.js';
7
+ import type { CommitteeAttestation } from './proposal/committee_attestation.js';
8
+
9
+ /**
10
+ * Status indicating how the attestation address was determined
11
+ */
12
+ export type AttestationStatus = 'recovered-from-signature' | 'provided-as-address' | 'invalid-signature' | 'empty';
13
+
14
+ /**
15
+ * Information about an attestation extracted from a published block
16
+ */
17
+ export type AttestationInfo =
18
+ | {
19
+ /** The validator's address, undefined if signature recovery failed or empty */
20
+ address?: undefined;
21
+ /** How the attestation address was determined */
22
+ status: Extract<AttestationStatus, 'invalid-signature' | 'empty'>;
23
+ }
24
+ | {
25
+ /** The validator's address */
26
+ address: EthAddress;
27
+ /** How the attestation address was determined */
28
+ status: Extract<AttestationStatus, 'provided-as-address' | 'recovered-from-signature'>;
29
+ };
30
+
31
+ /**
32
+ * Extracts attestation information from a published L2 block.
33
+ * Returns info for each attestation, preserving array indices.
34
+ */
35
+ export function getAttestationInfoFromPublishedL2Block(block: {
36
+ attestations: CommitteeAttestation[];
37
+ block: L2Block;
38
+ }): AttestationInfo[] {
39
+ const payload = ConsensusPayload.fromBlock(block.block);
40
+ const hashedPayload = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
41
+
42
+ return block.attestations.map(attestation => {
43
+ // If signature is empty, check if we have an address directly
44
+ if (attestation.signature.isEmpty()) {
45
+ if (attestation.address.isZero()) {
46
+ // No signature and no address - empty
47
+ return { status: 'empty' as const };
48
+ }
49
+ // Address provided without signature
50
+ return { address: attestation.address, status: 'provided-as-address' as const };
51
+ }
52
+
53
+ // Try to recover address from signature
54
+ try {
55
+ const recoveredAddress = recoverAddress(hashedPayload, attestation.signature);
56
+ return { address: recoveredAddress, status: 'recovered-from-signature' as const };
57
+ } catch {
58
+ // Signature present but recovery failed
59
+ return { status: 'invalid-signature' as const };
60
+ }
61
+ });
62
+ }
@@ -9,3 +9,4 @@ export * from './published_l2_block.js';
9
9
  export * from './proposal/index.js';
10
10
  export * from './validate_block_result.js';
11
11
  export * from './l2_block_info.js';
12
+ export * from './attestation_info.js';
@@ -1,4 +1,5 @@
1
1
  import type { EthAddress } from '@aztec/foundation/eth-address';
2
+ import type { Fr } from '@aztec/foundation/fields';
2
3
  import type { TypedEventEmitter } from '@aztec/foundation/types';
3
4
 
4
5
  import { z } from 'zod';
@@ -66,6 +67,34 @@ export interface L2BlockSource {
66
67
  /** Equivalent to getBlocks but includes publish data. */
67
68
  getPublishedBlocks(from: number, limit: number, proven?: boolean): Promise<PublishedL2Block[]>;
68
69
 
70
+ /**
71
+ * Gets a published block by its hash.
72
+ * @param blockHash - The block hash to retrieve.
73
+ * @returns The requested published block (or undefined if not found).
74
+ */
75
+ getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined>;
76
+
77
+ /**
78
+ * Gets a published block by its archive root.
79
+ * @param archive - The archive root to retrieve.
80
+ * @returns The requested published block (or undefined if not found).
81
+ */
82
+ getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined>;
83
+
84
+ /**
85
+ * Gets a block header by its hash.
86
+ * @param blockHash - The block hash to retrieve.
87
+ * @returns The requested block header (or undefined if not found).
88
+ */
89
+ getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined>;
90
+
91
+ /**
92
+ * Gets a block header by its archive root.
93
+ * @param archive - The archive root to retrieve.
94
+ * @returns The requested block header (or undefined if not found).
95
+ */
96
+ getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined>;
97
+
69
98
  /**
70
99
  * Gets a tx effect.
71
100
  * @param txHash - The hash of the tx corresponding to the tx effect.
@@ -120,6 +149,9 @@ export interface L2BlockSource {
120
149
  */
121
150
  getL1Constants(): Promise<L1RollupConstants>;
122
151
 
152
+ /** Returns values for the genesis block */
153
+ getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }>;
154
+
123
155
  /** Latest synced L1 timestamp. */
124
156
  getL1Timestamp(): Promise<bigint>;
125
157
 
@@ -7,8 +7,6 @@ import type { FieldsOf } from '@aztec/foundation/types';
7
7
 
8
8
  import { z } from 'zod';
9
9
 
10
- import { BlockAttestation } from '../p2p/block_attestation.js';
11
- import { ConsensusPayload } from '../p2p/consensus_payload.js';
12
10
  import { L2Block } from './l2_block.js';
13
11
  import { CommitteeAttestation } from './proposal/committee_attestation.js';
14
12
 
@@ -82,12 +80,3 @@ export class PublishedL2Block {
82
80
  );
83
81
  }
84
82
  }
85
-
86
- export function getAttestationsFromPublishedL2Block(
87
- block: Pick<PublishedL2Block, 'attestations' | 'block'>,
88
- ): BlockAttestation[] {
89
- const payload = ConsensusPayload.fromBlock(block.block);
90
- return block.attestations
91
- .filter(attestation => !attestation.signature.isEmpty())
92
- .map(attestation => new BlockAttestation(block.block.number, payload, attestation.signature));
93
- }
@@ -83,6 +83,10 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
83
83
  .function()
84
84
  .args(schemas.Integer, schemas.Integer, optional(z.boolean()))
85
85
  .returns(z.array(PublishedL2Block.schema)),
86
+ getPublishedBlockByHash: z.function().args(schemas.Fr).returns(PublishedL2Block.schema.optional()),
87
+ getPublishedBlockByArchive: z.function().args(schemas.Fr).returns(PublishedL2Block.schema.optional()),
88
+ getBlockHeaderByHash: z.function().args(schemas.Fr).returns(BlockHeader.schema.optional()),
89
+ getBlockHeaderByArchive: z.function().args(schemas.Fr).returns(BlockHeader.schema.optional()),
86
90
  getTxEffect: z.function().args(TxHash.schema).returns(indexedTxSchema().optional()),
87
91
  getSettledTxReceipt: z.function().args(TxHash.schema).returns(TxReceipt.schema.optional()),
88
92
  getL2SlotNumber: z.function().args().returns(schemas.BigInt),
@@ -110,6 +114,10 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
110
114
  getL1ToL2MessageIndex: z.function().args(schemas.Fr).returns(schemas.BigInt.optional()),
111
115
  getDebugFunctionName: z.function().args(schemas.AztecAddress, schemas.FunctionSelector).returns(optional(z.string())),
112
116
  getL1Constants: z.function().args().returns(L1RollupConstantsSchema),
117
+ getGenesisValues: z
118
+ .function()
119
+ .args()
120
+ .returns(z.object({ genesisArchiveRoot: schemas.Fr })),
113
121
  getL1Timestamp: z.function().args().returns(schemas.BigInt),
114
122
  syncImmediate: z.function().args().returns(z.void()),
115
123
  isPendingChainInvalid: z.function().args().returns(z.boolean()),
@@ -9,7 +9,7 @@ import { type ArchiverSpecificConfig, ArchiverSpecificConfigSchema } from './arc
9
9
  import { type SequencerConfig, SequencerConfigSchema } from './configs.js';
10
10
  import { type ProverConfig, ProverConfigSchema } from './prover-client.js';
11
11
  import { type SlasherConfig, SlasherConfigSchema } from './slasher.js';
12
- import { ValidatorClientConfigSchema, type ValidatorClientFullConfig } from './validator.js';
12
+ import { type ValidatorClientFullConfig, ValidatorClientFullConfigSchema } from './validator.js';
13
13
 
14
14
  /**
15
15
  * Aztec node admin API.
@@ -62,7 +62,7 @@ export type AztecNodeAdminConfig = ValidatorClientFullConfig &
62
62
 
63
63
  export const AztecNodeAdminConfigSchema = SequencerConfigSchema.merge(ProverConfigSchema)
64
64
  .merge(SlasherConfigSchema)
65
- .merge(ValidatorClientConfigSchema)
65
+ .merge(ValidatorClientFullConfigSchema)
66
66
  .merge(
67
67
  ArchiverSpecificConfigSchema.pick({
68
68
  archiverPollingIntervalMS: true,
@@ -224,6 +224,20 @@ export interface AztecNode
224
224
  */
225
225
  getBlock(number: L2BlockNumber): Promise<L2Block | undefined>;
226
226
 
227
+ /**
228
+ * Get a block specified by its hash.
229
+ * @param blockHash - The block hash being requested.
230
+ * @returns The requested block.
231
+ */
232
+ getBlockByHash(blockHash: Fr): Promise<L2Block | undefined>;
233
+
234
+ /**
235
+ * Get a block specified by its archive root.
236
+ * @param archive - The archive root being requested.
237
+ * @returns The requested block.
238
+ */
239
+ getBlockByArchive(archive: Fr): Promise<L2Block | undefined>;
240
+
227
241
  /**
228
242
  * Method to fetch the latest block number synchronized by the node.
229
243
  * @returns The block number.
@@ -399,6 +413,20 @@ export interface AztecNode
399
413
  */
400
414
  getBlockHeader(blockNumber?: L2BlockNumber): Promise<BlockHeader | undefined>;
401
415
 
416
+ /**
417
+ * Get a block header specified by its hash.
418
+ * @param blockHash - The block hash being requested.
419
+ * @returns The requested block header.
420
+ */
421
+ getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined>;
422
+
423
+ /**
424
+ * Get a block header specified by its archive root.
425
+ * @param archive - The archive root being requested.
426
+ * @returns The requested block header.
427
+ */
428
+ getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined>;
429
+
402
430
  /** Returns stats for validators if enabled. */
403
431
  getValidatorsStats(): Promise<ValidatorsStats>;
404
432
 
@@ -516,6 +544,10 @@ export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {
516
544
 
517
545
  getBlock: z.function().args(L2BlockNumberSchema).returns(L2Block.schema.optional()),
518
546
 
547
+ getBlockByHash: z.function().args(schemas.Fr).returns(L2Block.schema.optional()),
548
+
549
+ getBlockByArchive: z.function().args(schemas.Fr).returns(L2Block.schema.optional()),
550
+
519
551
  getBlockNumber: z.function().returns(z.number()),
520
552
 
521
553
  getProvenBlockNumber: z.function().returns(z.number()),
@@ -589,6 +621,10 @@ export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {
589
621
 
590
622
  getBlockHeader: z.function().args(optional(L2BlockNumberSchema)).returns(BlockHeader.schema.optional()),
591
623
 
624
+ getBlockHeaderByHash: z.function().args(schemas.Fr).returns(BlockHeader.schema.optional()),
625
+
626
+ getBlockHeaderByArchive: z.function().args(schemas.Fr).returns(BlockHeader.schema.optional()),
627
+
592
628
  getValidatorsStats: z.function().returns(ValidatorsStatsSchema),
593
629
 
594
630
  getValidatorStats: z
@@ -52,6 +52,8 @@ export interface SequencerConfig {
52
52
  skipCollectingAttestations?: boolean;
53
53
  /** Do not invalidate the previous block if invalid when we are the proposer (for testing only) */
54
54
  skipInvalidateBlockAsProposer?: boolean;
55
+ /** Inject a fake attestation (for testing only) */
56
+ injectFakeAttestation?: boolean;
55
57
  }
56
58
 
57
59
  export const SequencerConfigSchema = z.object({
@@ -75,4 +77,5 @@ export const SequencerConfigSchema = z.object({
75
77
  skipCollectingAttestations: z.boolean().optional(),
76
78
  secondsBeforeInvalidatingBlockAsCommitteeMember: z.number(),
77
79
  secondsBeforeInvalidatingBlockAsNonCommitteeMember: z.number(),
80
+ injectFakeAttestation: z.boolean().optional(),
78
81
  }) satisfies ZodFor<SequencerConfig>;
@@ -57,6 +57,9 @@ export interface P2PApiWithAttestations extends P2PApiWithoutAttestations {
57
57
  * @returns BlockAttestations
58
58
  */
59
59
  getAttestationsForSlot(slot: bigint, proposalId?: string): Promise<BlockAttestation[]>;
60
+
61
+ /** Deletes a given attestation manually from the p2p client attestation pool. */
62
+ deleteAttestation(attestation: BlockAttestation): Promise<void>;
60
63
  }
61
64
 
62
65
  export interface P2PClient extends P2PApiWithAttestations {
@@ -85,4 +88,5 @@ export const P2PApiSchema: ApiSchemaFor<P2PApi> = {
85
88
  getPendingTxCount: z.function().returns(schemas.Integer),
86
89
  getEncodedEnr: z.function().returns(z.string().optional()),
87
90
  getPeers: z.function().args(optional(z.boolean())).returns(z.array(PeerInfoSchema)),
91
+ deleteAttestation: z.function().args(BlockAttestation.schema).returns(z.void()),
88
92
  };
@@ -9,6 +9,7 @@ export interface ITxProvider {
9
9
 
10
10
  getTxsForBlockProposal(
11
11
  blockProposal: BlockProposal,
12
+ blockNumber: number,
12
13
  opts: { pinnedPeer: PeerId | undefined; deadline: Date },
13
14
  ): Promise<{ txs: Tx[]; missingTxs: TxHash[] }>;
14
15
 
@@ -11,6 +11,7 @@ import type { PeerId } from '@libp2p/interface';
11
11
  import { z } from 'zod';
12
12
 
13
13
  import type { CommitteeAttestationsAndSigners } from '../block/index.js';
14
+ import { AllowedElementSchema } from './allowed_element.js';
14
15
 
15
16
  /**
16
17
  * Validator client configuration
@@ -43,7 +44,13 @@ export interface ValidatorClientConfig {
43
44
 
44
45
  export type ValidatorClientFullConfig = ValidatorClientConfig &
45
46
  Pick<SequencerConfig, 'txPublicSetupAllowList'> &
46
- Pick<SlasherConfig, 'slashBroadcastedInvalidBlockPenalty'>;
47
+ Pick<SlasherConfig, 'slashBroadcastedInvalidBlockPenalty'> & {
48
+ /**
49
+ * Whether transactions are disabled for this node
50
+ * @remarks This should match the property in P2PConfig. It's not picked from there to avoid circular dependencies.
51
+ */
52
+ disableTransactions?: boolean;
53
+ };
47
54
 
48
55
  export const ValidatorClientConfigSchema = z.object({
49
56
  validatorAddresses: z.array(schemas.EthAddress).optional(),
@@ -55,6 +62,12 @@ export const ValidatorClientConfigSchema = z.object({
55
62
  alwaysReexecuteBlockProposals: z.boolean().optional(),
56
63
  }) satisfies ZodFor<Omit<ValidatorClientConfig, 'validatorPrivateKeys'>>;
57
64
 
65
+ export const ValidatorClientFullConfigSchema = ValidatorClientConfigSchema.extend({
66
+ txPublicSetupAllowList: z.array(AllowedElementSchema).optional(),
67
+ slashBroadcastedInvalidBlockPenalty: schemas.BigInt,
68
+ disableTransactions: z.boolean().optional(),
69
+ }) satisfies ZodFor<Omit<ValidatorClientFullConfig, 'validatorPrivateKeys'>>;
70
+
58
71
  export interface Validator {
59
72
  start(): Promise<void>;
60
73
  updateConfig(config: Partial<ValidatorClientFullConfig>): void;
@@ -1,5 +1,5 @@
1
1
  import { Buffer32 } from '@aztec/foundation/buffer';
2
- import { keccak256, recoverAddress } from '@aztec/foundation/crypto';
2
+ import { keccak256, tryRecoverAddress } from '@aztec/foundation/crypto';
3
3
  import type { EthAddress } from '@aztec/foundation/eth-address';
4
4
  import { Signature } from '@aztec/foundation/eth-signature';
5
5
  import { Fr } from '@aztec/foundation/fields';
@@ -7,8 +7,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
7
7
 
8
8
  import { z } from 'zod';
9
9
 
10
- import { type ZodFor, schemas } from '../schemas/index.js';
11
- import type { UInt32 } from '../types/index.js';
10
+ import type { ZodFor } from '../schemas/index.js';
12
11
  import { ConsensusPayload } from './consensus_payload.js';
13
12
  import { Gossipable } from './gossipable.js';
14
13
  import { SignatureDomainSeparator, getHashedSignaturePayloadEthSignedMessage } from './signature_utils.js';
@@ -30,16 +29,17 @@ export class BlockAttestation extends Gossipable {
30
29
  static override p2pTopic = TopicType.block_attestation;
31
30
 
32
31
  private sender: EthAddress | undefined;
32
+ private proposer: EthAddress | undefined;
33
33
 
34
34
  constructor(
35
- /** The block number of the attestation. */
36
- public readonly blockNumber: UInt32,
37
-
38
35
  /** The payload of the message, and what the signature is over */
39
36
  public readonly payload: ConsensusPayload,
40
37
 
41
38
  /** The signature of the block attester */
42
39
  public readonly signature: Signature,
40
+
41
+ /** The signature from the block proposer */
42
+ public readonly proposerSignature: Signature,
43
43
  ) {
44
44
  super();
45
45
  }
@@ -47,11 +47,11 @@ export class BlockAttestation extends Gossipable {
47
47
  static get schema(): ZodFor<BlockAttestation> {
48
48
  return z
49
49
  .object({
50
- blockNumber: schemas.UInt32,
51
50
  payload: ConsensusPayload.schema,
52
51
  signature: Signature.schema,
52
+ proposerSignature: Signature.schema,
53
53
  })
54
- .transform(obj => new BlockAttestation(obj.blockNumber, obj.payload, obj.signature));
54
+ .transform(obj => new BlockAttestation(obj.payload, obj.signature, obj.proposerSignature));
55
55
  }
56
56
 
57
57
  override generateP2PMessageIdentifier(): Promise<Buffer32> {
@@ -68,41 +68,68 @@ export class BlockAttestation extends Gossipable {
68
68
 
69
69
  /**
70
70
  * Lazily evaluate and cache the signer of the attestation
71
- * @returns The signer of the attestation
71
+ * @returns The signer of the attestation, or undefined if signature recovery fails
72
72
  */
73
- getSender(): EthAddress {
73
+ getSender(): EthAddress | undefined {
74
74
  if (!this.sender) {
75
75
  // Recover the sender from the attestation
76
76
  const hashed = getHashedSignaturePayloadEthSignedMessage(this.payload, SignatureDomainSeparator.blockAttestation);
77
77
  // Cache the sender for later use
78
- this.sender = recoverAddress(hashed, this.signature);
78
+ this.sender = tryRecoverAddress(hashed, this.signature);
79
79
  }
80
80
 
81
81
  return this.sender;
82
82
  }
83
83
 
84
+ /**
85
+ * Lazily evaluate and cache the proposer of the block
86
+ * @returns The proposer of the block
87
+ */
88
+ getProposer(): EthAddress | undefined {
89
+ if (!this.proposer) {
90
+ // Recover the proposer from the proposal signature
91
+ const hashed = getHashedSignaturePayloadEthSignedMessage(this.payload, SignatureDomainSeparator.blockProposal);
92
+ // Cache the proposer for later use
93
+ this.proposer = tryRecoverAddress(hashed, this.proposerSignature);
94
+ }
95
+
96
+ return this.proposer;
97
+ }
98
+
84
99
  getPayload(): Buffer {
85
100
  return this.payload.getPayloadToSign(SignatureDomainSeparator.blockAttestation);
86
101
  }
87
102
 
88
103
  toBuffer(): Buffer {
89
- return serializeToBuffer([this.blockNumber, this.payload, this.signature]);
104
+ return serializeToBuffer([this.payload, this.signature, this.proposerSignature]);
90
105
  }
91
106
 
92
107
  static fromBuffer(buf: Buffer | BufferReader): BlockAttestation {
93
108
  const reader = BufferReader.asReader(buf);
94
- return new BlockAttestation(reader.readNumber(), reader.readObject(ConsensusPayload), reader.readObject(Signature));
109
+ return new BlockAttestation(
110
+ reader.readObject(ConsensusPayload),
111
+ reader.readObject(Signature),
112
+ reader.readObject(Signature),
113
+ );
95
114
  }
96
115
 
97
116
  static empty(): BlockAttestation {
98
- return new BlockAttestation(0, ConsensusPayload.empty(), Signature.empty());
117
+ return new BlockAttestation(ConsensusPayload.empty(), Signature.empty(), Signature.empty());
99
118
  }
100
119
 
101
120
  static random(): BlockAttestation {
102
- return new BlockAttestation(Math.floor(Math.random() * 1000) + 1, ConsensusPayload.random(), Signature.random());
121
+ return new BlockAttestation(ConsensusPayload.random(), Signature.random(), Signature.random());
103
122
  }
104
123
 
105
124
  getSize(): number {
106
- return 4 /* blockNumber */ + this.payload.getSize() + this.signature.getSize();
125
+ return this.payload.getSize() + this.signature.getSize() + this.proposerSignature.getSize();
126
+ }
127
+
128
+ toInspect() {
129
+ return {
130
+ payload: this.payload.toInspect(),
131
+ signature: this.signature.toString(),
132
+ proposerSignature: this.proposerSignature.toString(),
133
+ };
107
134
  }
108
135
  }