@aztec/validator-client 0.82.2 → 0.82.3

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.
@@ -1,4 +1,5 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
+ import type { EthAddress } from '@aztec/foundation/eth-address';
2
3
  import type { Fr } from '@aztec/foundation/fields';
3
4
  import { DateProvider, type Timer } from '@aztec/foundation/timer';
4
5
  import type { P2P } from '@aztec/p2p';
@@ -45,11 +46,14 @@ export declare class ValidatorClient extends WithTracer implements Validator {
45
46
  private metrics;
46
47
  private previousProposal?;
47
48
  private blockBuilder?;
49
+ private myAddress;
50
+ private lastEpoch;
48
51
  private epochCacheUpdateLoop;
49
52
  private blockProposalValidator;
50
53
  constructor(keyStore: ValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P, config: ValidatorClientConfig, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
54
+ private handleEpochCommiteeUpdate;
51
55
  static new(config: ValidatorClientConfig, epochCache: EpochCache, p2pClient: P2P, dateProvider?: DateProvider, telemetry?: TelemetryClient): ValidatorClient;
52
- getValidatorAddress(): import("@aztec/foundation/schemas").EthAddress;
56
+ getValidatorAddress(): EthAddress;
53
57
  start(): Promise<void>;
54
58
  stop(): Promise<void>;
55
59
  registerBlockProposalHandler(): void;
@@ -77,6 +81,7 @@ export declare class ValidatorClient extends WithTracer implements Validator {
77
81
  createBlockProposal(header: BlockHeader, archive: Fr, txs: TxHash[]): Promise<BlockProposal | undefined>;
78
82
  broadcastBlockProposal(proposal: BlockProposal): void;
79
83
  collectAttestations(proposal: BlockProposal, required: number, deadline: Date): Promise<BlockAttestation[]>;
84
+ private doAttestToProposal;
80
85
  }
81
86
  export {};
82
87
  //# sourceMappingURL=validator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
package/dest/validator.js CHANGED
@@ -24,6 +24,8 @@ import { ValidatorMetrics } from './metrics.js';
24
24
  previousProposal;
25
25
  // Callback registered to: sequencer.buildBlock
26
26
  blockBuilder;
27
+ myAddress;
28
+ lastEpoch;
27
29
  epochCacheUpdateLoop;
28
30
  blockProposalValidator;
29
31
  constructor(keyStore, epochCache, p2pClient, config, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
@@ -32,19 +34,27 @@ import { ValidatorMetrics } from './metrics.js';
32
34
  this.metrics = new ValidatorMetrics(telemetry);
33
35
  this.validationService = new ValidationService(keyStore);
34
36
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
35
- // Refresh epoch cache every second to trigger commiteeChanged event
36
- this.epochCacheUpdateLoop = new RunningPromise(()=>this.epochCache.getCommittee().then(()=>{}).catch((err)=>log.error('Error updating validator committee', err)), log, 1000);
37
- // Listen to commiteeChanged event to alert operator when their validator has entered the committee
38
- this.epochCache.on('committeeChanged', (newCommittee, epochNumber)=>{
39
- const me = this.keyStore.getAddress();
40
- if (newCommittee.some((addr)=>addr.equals(me))) {
41
- this.log.info(`Validator ${me.toString()} is on the validator committee for epoch ${epochNumber}`);
42
- } else {
43
- this.log.verbose(`Validator ${me.toString()} not on the validator committee for epoch ${epochNumber}`);
44
- }
45
- });
37
+ // Refresh epoch cache every second to trigger alert if participation in commitee changes
38
+ this.myAddress = this.keyStore.getAddress();
39
+ this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommiteeUpdate.bind(this), log, 1000);
46
40
  this.log.verbose(`Initialized validator with address ${this.keyStore.getAddress().toString()}`);
47
41
  }
42
+ async handleEpochCommiteeUpdate() {
43
+ try {
44
+ const { committee, epoch } = await this.epochCache.getCommittee('now');
45
+ if (epoch !== this.lastEpoch) {
46
+ const me = this.myAddress;
47
+ if (committee.some((addr)=>addr.equals(me))) {
48
+ this.log.info(`Validator ${me.toString()} is on the validator committee for epoch ${epoch}`);
49
+ } else {
50
+ this.log.verbose(`Validator ${me.toString()} not on the validator committee for epoch ${epoch}`);
51
+ }
52
+ this.lastEpoch = epoch;
53
+ }
54
+ } catch (err) {
55
+ this.log.error(`Error updating epoch committee`, err);
56
+ }
57
+ }
48
58
  static new(config, epochCache, p2pClient, dateProvider = new DateProvider(), telemetry = getTelemetryClient()) {
49
59
  if (!config.validatorPrivateKey) {
50
60
  throw new InvalidValidatorPrivateKeyError();
@@ -130,7 +140,7 @@ import { ValidatorMetrics } from './metrics.js';
130
140
  // Provided all of the above checks pass, we can attest to the proposal
131
141
  this.log.info(`Attesting to proposal for slot ${slotNumber}`, proposalInfo);
132
142
  // If the above function does not throw an error, then we can attest to the proposal
133
- return this.validationService.attestToProposal(proposal);
143
+ return this.doAttestToProposal(proposal);
134
144
  }
135
145
  /**
136
146
  * Re-execute the transactions in the proposal and check that the state updates match the header state
@@ -212,17 +222,15 @@ import { ValidatorMetrics } from './metrics.js';
212
222
  throw new AttestationTimeoutError(required, slot);
213
223
  }
214
224
  const proposalId = proposal.archive.toString();
215
- const myAttestation = await this.validationService.attestToProposal(proposal);
225
+ await this.doAttestToProposal(proposal);
226
+ const me = this.keyStore.getAddress();
216
227
  let attestations = [];
217
228
  while(true){
218
- const collectedAttestations = [
219
- myAttestation,
220
- ...await this.p2pClient.getAttestationsForSlot(slot, proposalId)
221
- ];
229
+ const collectedAttestations = await this.p2pClient.getAttestationsForSlot(slot, proposalId);
222
230
  const oldSenders = await Promise.all(attestations.map((attestation)=>attestation.getSender()));
223
231
  for (const collected of collectedAttestations){
224
232
  const collectedSender = await collected.getSender();
225
- if (!oldSenders.some((sender)=>sender.equals(collectedSender))) {
233
+ if (!collectedSender.equals(me) && !oldSenders.some((sender)=>sender.equals(collectedSender))) {
226
234
  this.log.debug(`Received attestation for slot ${slot} from ${collectedSender.toString()}`);
227
235
  }
228
236
  }
@@ -239,6 +247,11 @@ import { ValidatorMetrics } from './metrics.js';
239
247
  await sleep(this.config.attestationPollingIntervalMs);
240
248
  }
241
249
  }
250
+ async doAttestToProposal(proposal) {
251
+ const attestation = await this.validationService.attestToProposal(proposal);
252
+ await this.p2pClient.addAttestation(attestation);
253
+ return attestation;
254
+ }
242
255
  }
243
256
  function validatePrivateKey(privateKey) {
244
257
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.82.2",
3
+ "version": "0.82.3",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -62,12 +62,12 @@
62
62
  ]
63
63
  },
64
64
  "dependencies": {
65
- "@aztec/epoch-cache": "0.82.2",
66
- "@aztec/ethereum": "0.82.2",
67
- "@aztec/foundation": "0.82.2",
68
- "@aztec/p2p": "0.82.2",
69
- "@aztec/stdlib": "0.82.2",
70
- "@aztec/telemetry-client": "0.82.2",
65
+ "@aztec/epoch-cache": "0.82.3",
66
+ "@aztec/ethereum": "0.82.3",
67
+ "@aztec/foundation": "0.82.3",
68
+ "@aztec/p2p": "0.82.3",
69
+ "@aztec/stdlib": "0.82.3",
70
+ "@aztec/telemetry-client": "0.82.3",
71
71
  "koa": "^2.14.2",
72
72
  "koa-router": "^12.0.0",
73
73
  "tslib": "^2.4.0",
package/src/validator.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
2
  import { Buffer32 } from '@aztec/foundation/buffer';
3
+ import type { EthAddress } from '@aztec/foundation/eth-address';
3
4
  import type { Fr } from '@aztec/foundation/fields';
4
5
  import { createLogger } from '@aztec/foundation/log';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -70,6 +71,8 @@ export class ValidatorClient extends WithTracer implements Validator {
70
71
  // Callback registered to: sequencer.buildBlock
71
72
  private blockBuilder?: BlockBuilderCallback = undefined;
72
73
 
74
+ private myAddress: EthAddress;
75
+ private lastEpoch: bigint | undefined;
73
76
  private epochCacheUpdateLoop: RunningPromise;
74
77
 
75
78
  private blockProposalValidator: BlockProposalValidator;
@@ -91,30 +94,30 @@ export class ValidatorClient extends WithTracer implements Validator {
91
94
 
92
95
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
93
96
 
94
- // Refresh epoch cache every second to trigger commiteeChanged event
95
- this.epochCacheUpdateLoop = new RunningPromise(
96
- () =>
97
- this.epochCache
98
- .getCommittee()
99
- .then(() => {})
100
- .catch(err => log.error('Error updating validator committee', err)),
101
- log,
102
- 1000,
103
- );
104
-
105
- // Listen to commiteeChanged event to alert operator when their validator has entered the committee
106
- this.epochCache.on('committeeChanged', (newCommittee, epochNumber) => {
107
- const me = this.keyStore.getAddress();
108
- if (newCommittee.some(addr => addr.equals(me))) {
109
- this.log.info(`Validator ${me.toString()} is on the validator committee for epoch ${epochNumber}`);
110
- } else {
111
- this.log.verbose(`Validator ${me.toString()} not on the validator committee for epoch ${epochNumber}`);
112
- }
113
- });
97
+ // Refresh epoch cache every second to trigger alert if participation in commitee changes
98
+ this.myAddress = this.keyStore.getAddress();
99
+ this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommiteeUpdate.bind(this), log, 1000);
114
100
 
115
101
  this.log.verbose(`Initialized validator with address ${this.keyStore.getAddress().toString()}`);
116
102
  }
117
103
 
104
+ private async handleEpochCommiteeUpdate() {
105
+ try {
106
+ const { committee, epoch } = await this.epochCache.getCommittee('now');
107
+ if (epoch !== this.lastEpoch) {
108
+ const me = this.myAddress;
109
+ if (committee.some(addr => addr.equals(me))) {
110
+ this.log.info(`Validator ${me.toString()} is on the validator committee for epoch ${epoch}`);
111
+ } else {
112
+ this.log.verbose(`Validator ${me.toString()} not on the validator committee for epoch ${epoch}`);
113
+ }
114
+ this.lastEpoch = epoch;
115
+ }
116
+ } catch (err) {
117
+ this.log.error(`Error updating epoch committee`, err);
118
+ }
119
+ }
120
+
118
121
  static new(
119
122
  config: ValidatorClientConfig,
120
123
  epochCache: EpochCache,
@@ -222,7 +225,7 @@ export class ValidatorClient extends WithTracer implements Validator {
222
225
  this.log.info(`Attesting to proposal for slot ${slotNumber}`, proposalInfo);
223
226
 
224
227
  // If the above function does not throw an error, then we can attest to the proposal
225
- return this.validationService.attestToProposal(proposal);
228
+ return this.doAttestToProposal(proposal);
226
229
  }
227
230
 
228
231
  /**
@@ -327,15 +330,16 @@ export class ValidatorClient extends WithTracer implements Validator {
327
330
  }
328
331
 
329
332
  const proposalId = proposal.archive.toString();
330
- const myAttestation = await this.validationService.attestToProposal(proposal);
333
+ await this.doAttestToProposal(proposal);
334
+ const me = this.keyStore.getAddress();
331
335
 
332
336
  let attestations: BlockAttestation[] = [];
333
337
  while (true) {
334
- const collectedAttestations = [myAttestation, ...(await this.p2pClient.getAttestationsForSlot(slot, proposalId))];
338
+ const collectedAttestations = await this.p2pClient.getAttestationsForSlot(slot, proposalId);
335
339
  const oldSenders = await Promise.all(attestations.map(attestation => attestation.getSender()));
336
340
  for (const collected of collectedAttestations) {
337
341
  const collectedSender = await collected.getSender();
338
- if (!oldSenders.some(sender => sender.equals(collectedSender))) {
342
+ if (!collectedSender.equals(me) && !oldSenders.some(sender => sender.equals(collectedSender))) {
339
343
  this.log.debug(`Received attestation for slot ${slot} from ${collectedSender.toString()}`);
340
344
  }
341
345
  }
@@ -355,6 +359,12 @@ export class ValidatorClient extends WithTracer implements Validator {
355
359
  await sleep(this.config.attestationPollingIntervalMs);
356
360
  }
357
361
  }
362
+
363
+ private async doAttestToProposal(proposal: BlockProposal): Promise<BlockAttestation> {
364
+ const attestation = await this.validationService.attestToProposal(proposal);
365
+ await this.p2pClient.addAttestation(attestation);
366
+ return attestation;
367
+ }
358
368
  }
359
369
 
360
370
  function validatePrivateKey(privateKey: string): Buffer32 {