@aztec/validator-client 0.0.0-test.0 → 0.0.1-fake-c83136db25

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 (57) hide show
  1. package/dest/block_proposal_handler.d.ts +52 -0
  2. package/dest/block_proposal_handler.d.ts.map +1 -0
  3. package/dest/block_proposal_handler.js +286 -0
  4. package/dest/config.d.ts +2 -13
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +31 -7
  7. package/dest/duties/validation_service.d.ts +16 -8
  8. package/dest/duties/validation_service.d.ts.map +1 -1
  9. package/dest/duties/validation_service.js +35 -11
  10. package/dest/factory.d.ts +21 -4
  11. package/dest/factory.d.ts.map +1 -1
  12. package/dest/factory.js +13 -6
  13. package/dest/index.d.ts +3 -1
  14. package/dest/index.d.ts.map +1 -1
  15. package/dest/index.js +3 -1
  16. package/dest/key_store/index.d.ts +2 -0
  17. package/dest/key_store/index.d.ts.map +1 -1
  18. package/dest/key_store/index.js +2 -0
  19. package/dest/key_store/interface.d.ts +54 -5
  20. package/dest/key_store/interface.d.ts.map +1 -1
  21. package/dest/key_store/interface.js +3 -3
  22. package/dest/key_store/local_key_store.d.ts +40 -10
  23. package/dest/key_store/local_key_store.d.ts.map +1 -1
  24. package/dest/key_store/local_key_store.js +63 -16
  25. package/dest/key_store/node_keystore_adapter.d.ts +138 -0
  26. package/dest/key_store/node_keystore_adapter.d.ts.map +1 -0
  27. package/dest/key_store/node_keystore_adapter.js +316 -0
  28. package/dest/key_store/web3signer_key_store.d.ts +67 -0
  29. package/dest/key_store/web3signer_key_store.d.ts.map +1 -0
  30. package/dest/key_store/web3signer_key_store.js +153 -0
  31. package/dest/metrics.d.ts +11 -4
  32. package/dest/metrics.d.ts.map +1 -1
  33. package/dest/metrics.js +50 -15
  34. package/dest/validator.d.ts +48 -61
  35. package/dest/validator.d.ts.map +1 -1
  36. package/dest/validator.js +265 -165
  37. package/package.json +25 -19
  38. package/src/block_proposal_handler.ts +343 -0
  39. package/src/config.ts +42 -22
  40. package/src/duties/validation_service.ts +69 -14
  41. package/src/factory.ts +56 -11
  42. package/src/index.ts +3 -1
  43. package/src/key_store/index.ts +2 -0
  44. package/src/key_store/interface.ts +61 -5
  45. package/src/key_store/local_key_store.ts +67 -17
  46. package/src/key_store/node_keystore_adapter.ts +375 -0
  47. package/src/key_store/web3signer_key_store.ts +195 -0
  48. package/src/metrics.ts +66 -17
  49. package/src/validator.ts +384 -233
  50. package/dest/errors/index.d.ts +0 -2
  51. package/dest/errors/index.d.ts.map +0 -1
  52. package/dest/errors/index.js +0 -1
  53. package/dest/errors/validator.error.d.ts +0 -29
  54. package/dest/errors/validator.error.d.ts.map +0 -1
  55. package/dest/errors/validator.error.js +0 -45
  56. package/src/errors/index.ts +0 -1
  57. package/src/errors/validator.error.ts +0 -55
@@ -0,0 +1,195 @@
1
+ import type { Buffer32 } from '@aztec/foundation/buffer';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { Signature } from '@aztec/foundation/eth-signature';
4
+
5
+ import type { TypedDataDefinition } from 'viem';
6
+
7
+ import type { ValidatorKeyStore } from './interface.js';
8
+
9
+ /**
10
+ * Web3Signer Key Store
11
+ *
12
+ * An implementation of the Key store using Web3Signer remote signing service.
13
+ * This implementation uses the Web3Signer JSON-RPC API for secp256k1 signatures.
14
+ */
15
+ export class Web3SignerKeyStore implements ValidatorKeyStore {
16
+ constructor(
17
+ private addresses: EthAddress[],
18
+ private baseUrl: string,
19
+ ) {}
20
+
21
+ /**
22
+ * Get the address of a signer by index
23
+ *
24
+ * @param index - The index of the signer
25
+ * @returns the address
26
+ */
27
+ public getAddress(index: number): EthAddress {
28
+ if (index >= this.addresses.length) {
29
+ throw new Error(`Index ${index} is out of bounds.`);
30
+ }
31
+ return this.addresses[index];
32
+ }
33
+
34
+ /**
35
+ * Get all addresses
36
+ *
37
+ * @returns all addresses
38
+ */
39
+ public getAddresses(): EthAddress[] {
40
+ return this.addresses;
41
+ }
42
+
43
+ /**
44
+ * Sign EIP-712 typed data with all keystore addresses
45
+ * @param typedData - The complete EIP-712 typed data structure (domain, types, primaryType, message)
46
+ * @return signatures
47
+ */
48
+ public async signTypedData(typedData: TypedDataDefinition): Promise<Signature[]> {
49
+ const signatures = await Promise.all(
50
+ this.addresses.map(address => this.makeJsonRpcSignTypedDataRequest(address, typedData)),
51
+ );
52
+ return signatures;
53
+ }
54
+
55
+ /**
56
+ * Sign EIP-712 typed data with a specific address
57
+ * @param address - The address of the signer to use
58
+ * @param typedData - The complete EIP-712 typed data structure (domain, types, primaryType, message)
59
+ * @returns signature for the specified address
60
+ * @throws Error if the address is not found in the keystore or signing fails
61
+ */
62
+ public async signTypedDataWithAddress(address: EthAddress, typedData: TypedDataDefinition): Promise<Signature> {
63
+ if (!this.addresses.some(addr => addr.equals(address))) {
64
+ throw new Error(`Address ${address.toString()} not found in keystore`);
65
+ }
66
+
67
+ return await this.makeJsonRpcSignTypedDataRequest(address, typedData);
68
+ }
69
+
70
+ /**
71
+ * Sign a message with all keystore addresses using EIP-191 prefix
72
+ *
73
+ * @param message - The message to sign
74
+ * @return signatures
75
+ */
76
+ public async signMessage(message: Buffer32): Promise<Signature[]> {
77
+ const signatures = await Promise.all(this.addresses.map(address => this.makeJsonRpcSignRequest(address, message)));
78
+ return signatures;
79
+ }
80
+
81
+ /**
82
+ * Sign a message with a specific address using EIP-191 prefix
83
+ * @param address - The address of the signer to use
84
+ * @param message - The message to sign
85
+ * @returns signature for the specified address
86
+ * @throws Error if the address is not found in the keystore or signing fails
87
+ */
88
+ public async signMessageWithAddress(address: EthAddress, message: Buffer32): Promise<Signature> {
89
+ if (!this.addresses.some(addr => addr.equals(address))) {
90
+ throw new Error(`Address ${address.toString()} not found in keystore`);
91
+ }
92
+ return await this.makeJsonRpcSignRequest(address, message);
93
+ }
94
+
95
+ /**
96
+ * Make a JSON-RPC sign request to Web3Signer using eth_sign
97
+ * @param address - The Ethereum address to sign with
98
+ * @param data - The data to sign
99
+ * @returns The signature
100
+ */
101
+ private async makeJsonRpcSignRequest(address: EthAddress, data: Buffer32): Promise<Signature> {
102
+ const url = this.baseUrl;
103
+
104
+ // Use JSON-RPC eth_sign method which automatically applies Ethereum message prefixing
105
+ const body = {
106
+ jsonrpc: '2.0',
107
+ method: 'eth_sign',
108
+ params: [
109
+ address.toString(), // Ethereum address as identifier
110
+ data.toString(), // Raw data to sign (eth_sign will apply Ethereum message prefix)
111
+ ],
112
+ id: 1,
113
+ };
114
+
115
+ const response = await fetch(url, {
116
+ method: 'POST',
117
+ headers: {
118
+ 'Content-Type': 'application/json',
119
+ },
120
+ body: JSON.stringify(body),
121
+ });
122
+
123
+ if (!response.ok) {
124
+ const errorText = await response.text();
125
+ throw new Error(`Web3Signer request failed: ${response.status} ${response.statusText} - ${errorText}`);
126
+ }
127
+
128
+ const result = await response.json();
129
+
130
+ // Handle JSON-RPC response format
131
+ if (result.error) {
132
+ throw new Error(`Web3Signer JSON-RPC error: ${result.error.code} - ${result.error.message}`);
133
+ }
134
+
135
+ if (!result.result) {
136
+ throw new Error('Invalid response from Web3Signer: no result found');
137
+ }
138
+
139
+ let signatureHex = result.result;
140
+
141
+ // Ensure the signature has the 0x prefix
142
+ if (!signatureHex.startsWith('0x')) {
143
+ signatureHex = '0x' + signatureHex;
144
+ }
145
+
146
+ // Parse the signature from the hex string
147
+ return Signature.fromString(signatureHex as `0x${string}`);
148
+ }
149
+
150
+ private async makeJsonRpcSignTypedDataRequest(
151
+ address: EthAddress,
152
+ typedData: TypedDataDefinition,
153
+ ): Promise<Signature> {
154
+ const url = this.baseUrl;
155
+
156
+ const body = {
157
+ jsonrpc: '2.0',
158
+ method: 'eth_signTypedData',
159
+ params: [address.toString(), JSON.stringify(typedData)],
160
+ id: 1,
161
+ };
162
+
163
+ const response = await fetch(url, {
164
+ method: 'POST',
165
+ headers: {
166
+ 'Content-Type': 'application/json',
167
+ },
168
+ body: JSON.stringify(body),
169
+ });
170
+
171
+ if (!response.ok) {
172
+ const errorText = await response.text();
173
+ throw new Error(`Web3Signer request failed: ${response.status} ${response.statusText} - ${errorText}`);
174
+ }
175
+
176
+ const result = await response.json();
177
+
178
+ if (result.error) {
179
+ throw new Error(`Web3Signer JSON-RPC error: ${result.error.code} - ${result.error.message}`);
180
+ }
181
+
182
+ if (!result.result) {
183
+ throw new Error('Invalid response from Web3Signer: no result found');
184
+ }
185
+
186
+ let signatureHex = result.result;
187
+
188
+ // Ensure the signature has the 0x prefix
189
+ if (!signatureHex.startsWith('0x')) {
190
+ signatureHex = '0x' + signatureHex;
191
+ }
192
+
193
+ return Signature.fromString(signatureHex as `0x${string}`);
194
+ }
195
+ }
package/src/metrics.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { BlockProposal } from '@aztec/stdlib/p2p';
2
2
  import {
3
3
  Attributes,
4
- type Gauge,
4
+ type Histogram,
5
5
  Metrics,
6
6
  type TelemetryClient,
7
7
  type UpDownCounter,
@@ -9,8 +9,14 @@ import {
9
9
  } from '@aztec/telemetry-client';
10
10
 
11
11
  export class ValidatorMetrics {
12
- private reExecutionTime: Gauge;
13
12
  private failedReexecutionCounter: UpDownCounter;
13
+ private successfulAttestationsCount: UpDownCounter;
14
+ private failedAttestationsBadProposalCount: UpDownCounter;
15
+ private failedAttestationsNodeIssueCount: UpDownCounter;
16
+
17
+ private reexMana: Histogram;
18
+ private reexTx: Histogram;
19
+ private reexDuration: Histogram;
14
20
 
15
21
  constructor(telemetryClient: TelemetryClient) {
16
22
  const meter = telemetryClient.getMeter('Validator');
@@ -21,30 +27,73 @@ export class ValidatorMetrics {
21
27
  valueType: ValueType.INT,
22
28
  });
23
29
 
24
- this.reExecutionTime = meter.createGauge(Metrics.VALIDATOR_RE_EXECUTION_TIME, {
25
- description: 'The time taken to re-execute a transaction',
26
- unit: 'ms',
30
+ this.successfulAttestationsCount = meter.createUpDownCounter(Metrics.VALIDATOR_ATTESTATION_SUCCESS_COUNT, {
31
+ description: 'The number of successful attestations',
32
+ valueType: ValueType.INT,
33
+ });
34
+
35
+ this.failedAttestationsBadProposalCount = meter.createUpDownCounter(
36
+ Metrics.VALIDATOR_ATTESTATION_FAILED_BAD_PROPOSAL_COUNT,
37
+ {
38
+ description: 'The number of failed attestations due to invalid block proposals',
39
+ valueType: ValueType.INT,
40
+ },
41
+ );
42
+
43
+ this.failedAttestationsNodeIssueCount = meter.createUpDownCounter(
44
+ Metrics.VALIDATOR_ATTESTATION_FAILED_NODE_ISSUE_COUNT,
45
+ {
46
+ description: 'The number of failed attestations due to node issues (timeout, missing data, etc.)',
47
+ valueType: ValueType.INT,
48
+ },
49
+ );
50
+
51
+ this.reexMana = meter.createHistogram(Metrics.VALIDATOR_RE_EXECUTION_MANA, {
52
+ description: 'The mana consumed by blocks',
27
53
  valueType: ValueType.DOUBLE,
54
+ unit: 'Mmana',
55
+ });
56
+
57
+ this.reexTx = meter.createHistogram(Metrics.VALIDATOR_RE_EXECUTION_TX_COUNT, {
58
+ description: 'The number of txs in a block proposal',
59
+ valueType: ValueType.INT,
60
+ unit: 'tx',
28
61
  });
29
- }
30
62
 
31
- public reExecutionTimer(): () => void {
32
- const start = performance.now();
33
- return () => {
34
- const end = performance.now();
35
- this.recordReExecutionTime(end - start);
36
- };
63
+ this.reexDuration = meter.createGauge(Metrics.VALIDATOR_RE_EXECUTION_TIME, {
64
+ description: 'The time taken to re-execute a transaction',
65
+ unit: 'ms',
66
+ valueType: ValueType.INT,
67
+ });
37
68
  }
38
69
 
39
- public recordReExecutionTime(time: number) {
40
- this.reExecutionTime.record(time);
70
+ public recordReex(time: number, txs: number, mManaTotal: number) {
71
+ this.reexDuration.record(Math.ceil(time));
72
+ this.reexTx.record(txs);
73
+ this.reexMana.record(mManaTotal);
41
74
  }
42
75
 
43
- public async recordFailedReexecution(proposal: BlockProposal) {
76
+ public recordFailedReexecution(proposal: BlockProposal) {
77
+ const proposer = proposal.getSender();
44
78
  this.failedReexecutionCounter.add(1, {
45
79
  [Attributes.STATUS]: 'failed',
46
- [Attributes.BLOCK_NUMBER]: proposal.payload.header.globalVariables.blockNumber.toString(),
47
- [Attributes.BLOCK_PROPOSER]: (await proposal.getSender())?.toString(),
80
+ [Attributes.BLOCK_PROPOSER]: proposer?.toString() ?? 'unknown',
81
+ });
82
+ }
83
+
84
+ public incSuccessfulAttestations(num: number) {
85
+ this.successfulAttestationsCount.add(num);
86
+ }
87
+
88
+ public incFailedAttestationsBadProposal(num: number, reason: string) {
89
+ this.failedAttestationsBadProposalCount.add(num, {
90
+ [Attributes.ERROR_TYPE]: reason,
91
+ });
92
+ }
93
+
94
+ public incFailedAttestationsNodeIssue(num: number, reason: string) {
95
+ this.failedAttestationsNodeIssueCount.add(num, {
96
+ [Attributes.ERROR_TYPE]: reason,
48
97
  });
49
98
  }
50
99
  }