@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.
- package/dest/block/attestation_info.d.ts +30 -0
- package/dest/block/attestation_info.d.ts.map +1 -0
- package/dest/block/attestation_info.js +39 -0
- package/dest/block/index.d.ts +1 -0
- package/dest/block/index.d.ts.map +1 -1
- package/dest/block/index.js +1 -0
- package/dest/block/l2_block_source.d.ts +29 -0
- package/dest/block/l2_block_source.d.ts.map +1 -1
- package/dest/block/published_l2_block.d.ts +0 -2
- package/dest/block/published_l2_block.d.ts.map +1 -1
- package/dest/block/published_l2_block.js +0 -6
- package/dest/interfaces/archiver.d.ts.map +1 -1
- package/dest/interfaces/archiver.js +7 -0
- package/dest/interfaces/aztec-node-admin.d.ts +38 -34
- package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
- package/dest/interfaces/aztec-node-admin.js +2 -2
- package/dest/interfaces/aztec-node.d.ts +24 -0
- package/dest/interfaces/aztec-node.d.ts.map +1 -1
- package/dest/interfaces/aztec-node.js +4 -0
- package/dest/interfaces/configs.d.ts +5 -0
- package/dest/interfaces/configs.d.ts.map +1 -1
- package/dest/interfaces/configs.js +2 -1
- package/dest/interfaces/p2p.d.ts +2 -0
- package/dest/interfaces/p2p.d.ts.map +1 -1
- package/dest/interfaces/p2p.js +2 -1
- package/dest/interfaces/tx_provider.d.ts +1 -1
- package/dest/interfaces/tx_provider.d.ts.map +1 -1
- package/dest/interfaces/validator.d.ts +93 -1
- package/dest/interfaces/validator.d.ts.map +1 -1
- package/dest/interfaces/validator.js +6 -0
- package/dest/p2p/block_attestation.d.ts +44 -9
- package/dest/p2p/block_attestation.d.ts.map +1 -1
- package/dest/p2p/block_attestation.js +35 -16
- package/dest/p2p/block_proposal.d.ts +4 -8
- package/dest/p2p/block_proposal.d.ts.map +1 -1
- package/dest/p2p/block_proposal.js +10 -13
- package/dest/p2p/gossipable.d.ts +2 -4
- package/dest/p2p/gossipable.d.ts.map +1 -1
- package/dest/p2p/gossipable.js +5 -14
- package/dest/tests/mocks.d.ts +3 -1
- package/dest/tests/mocks.d.ts.map +1 -1
- package/dest/tests/mocks.js +33 -11
- package/dest/zkpassport/index.d.ts +15 -9
- package/dest/zkpassport/index.d.ts.map +1 -1
- package/dest/zkpassport/index.js +17 -11
- package/package.json +9 -9
- package/src/block/attestation_info.ts +62 -0
- package/src/block/index.ts +1 -0
- package/src/block/l2_block_source.ts +32 -0
- package/src/block/published_l2_block.ts +0 -11
- package/src/interfaces/archiver.ts +8 -0
- package/src/interfaces/aztec-node-admin.ts +2 -2
- package/src/interfaces/aztec-node.ts +36 -0
- package/src/interfaces/configs.ts +3 -0
- package/src/interfaces/p2p.ts +4 -0
- package/src/interfaces/tx_provider.ts +1 -0
- package/src/interfaces/validator.ts +14 -1
- package/src/p2p/block_attestation.ts +43 -16
- package/src/p2p/block_proposal.ts +9 -16
- package/src/p2p/gossipable.ts +6 -16
- package/src/tests/mocks.ts +53 -17
- 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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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;
|
|
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"}
|
package/dest/zkpassport/index.js
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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.
|
|
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.
|
|
74
|
-
"@aztec/blob-lib": "2.1.0-rc.
|
|
75
|
-
"@aztec/constants": "2.1.0-rc.
|
|
76
|
-
"@aztec/ethereum": "2.1.0-rc.
|
|
77
|
-
"@aztec/foundation": "2.1.0-rc.
|
|
78
|
-
"@aztec/l1-artifacts": "2.1.0-rc.
|
|
79
|
-
"@aztec/noir-noirc_abi": "2.1.0-rc.
|
|
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.
|
|
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
|
+
}
|
package/src/block/index.ts
CHANGED
|
@@ -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 {
|
|
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(
|
|
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>;
|
package/src/interfaces/p2p.ts
CHANGED
|
@@ -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
|
};
|
|
@@ -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,
|
|
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 {
|
|
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.
|
|
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 =
|
|
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.
|
|
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(
|
|
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(
|
|
117
|
+
return new BlockAttestation(ConsensusPayload.empty(), Signature.empty(), Signature.empty());
|
|
99
118
|
}
|
|
100
119
|
|
|
101
120
|
static random(): BlockAttestation {
|
|
102
|
-
return new BlockAttestation(
|
|
121
|
+
return new BlockAttestation(ConsensusPayload.random(), Signature.random(), Signature.random());
|
|
103
122
|
}
|
|
104
123
|
|
|
105
124
|
getSize(): number {
|
|
106
|
-
return
|
|
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
|
}
|