Skip to content

Commit

Permalink
chore: Log when validator enters commitee (#10615)
Browse files Browse the repository at this point in the history
Entering the committee on a new epoch is logged as INFO, new epoch where
validator is not selected is VERBOSE.

```
[10:46:11.603] DEBUG: epoch-cache Initialized EpochCache with constants and validators {"l1constants":{"epochDuration":4,"ethereumSlotDuration":4,"l1GenesisTime":1733923582,"l1StartBlock":33,"slotDuration":8},"initialValidators":["0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc","0x976ea74026e726554db657fa54763abd0c3a0aa9","0x70997970c51812dc3a010c7d01b50e0d17dc79c8"]}
[10:46:11.627] VERBOSE: validator Initialized validator with address 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
[10:46:11.634] INFO: validator Started validator with address 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
[10:46:38.639] DEBUG: epoch-cache Updating validator set for new epoch 38 {"epoch":38,"previousEpoch":37}
[10:46:38.646] DEBUG: epoch-cache Updated validator set for epoch 38 {"commitee":["0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc","0x90f79bf6eb2c4f870365e785982e1f101e93b906","0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc"]}
[10:46:38.646] VERBOSE: validator Validator 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 not on the validator committee for epoch 38
[10:47:10.653] DEBUG: epoch-cache Updating validator set for new epoch 39 {"epoch":39,"previousEpoch":38}
[10:47:10.656] DEBUG: epoch-cache Updated validator set for epoch 39 {"commitee":["0x15d34aaf54267db7d7c367839aaf71a00a2c6a65","0x90f79bf6eb2c4f870365e785982e1f101e93b906","0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc"]}
[10:47:10.656] VERBOSE: validator Validator 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 not on the validator committee for epoch 39
[10:47:42.659] DEBUG: epoch-cache Updating validator set for new epoch 40 {"epoch":40,"previousEpoch":39}
[10:47:42.661] DEBUG: epoch-cache Updated validator set for epoch 40 {"commitee":["0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","0x976ea74026e726554db657fa54763abd0c3a0aa9","0x15d34aaf54267db7d7c367839aaf71a00a2c6a65"]}
[10:47:42.661] INFO: validator Validator 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 is on the validator committee for epoch 40
```

Fixes #10337
  • Loading branch information
spalladino authored Dec 11, 2024
1 parent 98ba747 commit 7746a39
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 8 deletions.
2 changes: 1 addition & 1 deletion yarn-project/epoch-cache/src/epoch_cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('EpochCache', () => {
expect(nextNextProposer).toEqual(testCommittee[0]);
});

it('Should request to update the validator set when on the epoch boundary', async () => {
it('should request to update the validator set when on the epoch boundary', async () => {
// Set initial time to a known slot
const initialTime = Number(l1GenesisTime) * 1000; // Convert to milliseconds
jest.setSystemTime(initialTime);
Expand Down
13 changes: 10 additions & 3 deletions yarn-project/epoch-cache/src/epoch_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { RollupContract, createEthereumChain } from '@aztec/ethereum';
import { EthAddress } from '@aztec/foundation/eth-address';
import { type Logger, createLogger } from '@aztec/foundation/log';

import { EventEmitter } from 'node:events';
import { createPublicClient, encodeAbiParameters, http, keccak256 } from 'viem';

import { type EpochCacheConfig, getEpochCacheConfigEnvVars } from './config.js';
Expand All @@ -28,7 +29,7 @@ type EpochAndSlot = {
*
* Note: This class is very dependent on the system clock being in sync.
*/
export class EpochCache {
export class EpochCache extends EventEmitter<{ committeeChanged: [EthAddress[], bigint] }> {
private committee: EthAddress[];
private cachedEpoch: bigint;
private cachedSampleSeed: bigint;
Expand All @@ -40,6 +41,7 @@ export class EpochCache {
initialSampleSeed: bigint = 0n,
private readonly l1constants: L1RollupConstants = EmptyL1RollupConstants,
) {
super();
this.committee = initialValidators;
this.cachedSampleSeed = initialSampleSeed;

Expand Down Expand Up @@ -111,14 +113,19 @@ export class EpochCache {
const { epoch: calculatedEpoch, ts } = nextSlot ? this.getEpochAndSlotInNextSlot() : this.getEpochAndSlotNow();

if (calculatedEpoch !== this.cachedEpoch) {
this.log.debug(`Epoch changed, updating validator set`, { calculatedEpoch, cachedEpoch: this.cachedEpoch });
this.cachedEpoch = calculatedEpoch;
this.log.debug(`Updating validator set for new epoch ${calculatedEpoch}`, {
epoch: calculatedEpoch,
previousEpoch: this.cachedEpoch,
});
const [committeeAtTs, sampleSeedAtTs] = await Promise.all([
this.rollup.getCommitteeAt(ts),
this.rollup.getSampleSeedAt(ts),
]);
this.committee = committeeAtTs.map((v: `0x${string}`) => EthAddress.fromString(v));
this.cachedEpoch = calculatedEpoch;
this.cachedSampleSeed = sampleSeedAtTs;
this.log.debug(`Updated validator set for epoch ${calculatedEpoch}`, { commitee: this.committee });
this.emit('committeeChanged', this.committee, calculatedEpoch);
}

return this.committee;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class SequencerClient {
telemetryClient,
config,
);

await validatorClient?.start();
await sequencer.start();
return new SequencerClient(sequencer);
}
Expand Down
1 change: 1 addition & 0 deletions yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export class Sequencer {
*/
public async stop(): Promise<void> {
this.log.debug(`Stopping sequencer`);
await this.validatorClient?.stop();
await this.runningPromise?.stop();
this.publisher.interrupt();
this.setState(SequencerState.STOPPED, 0n, true /** force */);
Expand Down
36 changes: 33 additions & 3 deletions yarn-project/validator-client/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { type EpochCache } from '@aztec/epoch-cache';
import { Buffer32 } from '@aztec/foundation/buffer';
import { type Fr } from '@aztec/foundation/fields';
import { createLogger } from '@aztec/foundation/log';
import { RunningPromise } from '@aztec/foundation/running-promise';
import { sleep } from '@aztec/foundation/sleep';
import { type Timer } from '@aztec/foundation/timer';
import { type P2P } from '@aztec/p2p';
Expand Down Expand Up @@ -68,6 +69,8 @@ export class ValidatorClient extends WithTracer implements Validator {
// Callback registered to: sequencer.buildBlock
private blockBuilder?: BlockBuilderCallback = undefined;

private epochCacheUpdateLoop: RunningPromise;

constructor(
private keyStore: ValidatorKeyStore,
private epochCache: EpochCache,
Expand All @@ -81,7 +84,23 @@ export class ValidatorClient extends WithTracer implements Validator {
this.metrics = new ValidatorMetrics(telemetry);

this.validationService = new ValidationService(keyStore);
this.log.verbose('Initialized validator');

// Refresh epoch cache every second to trigger commiteeChanged event
this.epochCacheUpdateLoop = new RunningPromise(async () => {
await this.epochCache.getCommittee().catch(err => log.error('Error updating validator committee', err));
}, 1000);

// Listen to commiteeChanged event to alert operator when their validator has entered the committee
this.epochCache.on('committeeChanged', (newCommittee, epochNumber) => {
const me = this.keyStore.getAddress();
if (newCommittee.some(addr => addr.equals(me))) {
this.log.info(`Validator ${me.toString()} is on the validator committee for epoch ${epochNumber}`);
} else {
this.log.verbose(`Validator ${me.toString()} not on the validator committee for epoch ${epochNumber}`);
}
});

this.log.verbose(`Initialized validator with address ${this.keyStore.getAddress().toString()}`);
}

static new(
Expand All @@ -102,14 +121,25 @@ export class ValidatorClient extends WithTracer implements Validator {
return validator;
}

public start() {
public async start() {
// Sync the committee from the smart contract
// https://github.com/AztecProtocol/aztec-packages/issues/7962

this.log.info('Validator started');
const me = this.keyStore.getAddress();
const inCommittee = await this.epochCache.isInCommittee(me);
if (inCommittee) {
this.log.info(`Started validator with address ${me.toString()} in current validator committee`);
} else {
this.log.info(`Started validator with address ${me.toString()}`);
}
this.epochCacheUpdateLoop.start();
return Promise.resolve();
}

public async stop() {
await this.epochCacheUpdateLoop.stop();
}

public registerBlockProposalHandler() {
const handler = (block: BlockProposal): Promise<BlockAttestation | undefined> => {
return this.attestToProposal(block);
Expand Down

0 comments on commit 7746a39

Please sign in to comment.