@aztec/validator-client 1.0.0-nightly.20250708 → 1.0.0-staging.1

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 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAKjB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,oBAAoB,EAAE,WAAW,CAAC,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;IAEnD,+BAA+B;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAE1B,+DAA+D;IAC/D,4BAA4B,EAAE,MAAM,CAAC;IAErC,+CAA+C;IAC/C,kBAAkB,EAAE,OAAO,CAAC;IAE5B,wEAAwE;IACxE,4BAA4B,EAAE,MAAM,CAAC;CACtC;AAED,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,CA6BnF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,qBAAqB,CAExD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAKjB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,oBAAoB,EAAE,WAAW,CAAC,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;IAEnD,+BAA+B;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAE1B,+DAA+D;IAC/D,4BAA4B,EAAE,MAAM,CAAC;IAErC,+CAA+C;IAC/C,kBAAkB,EAAE,OAAO,CAAC;IAE5B,wEAAwE;IACxE,4BAA4B,EAAE,MAAM,CAAC;CACtC;AAED,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,CA4BnF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,qBAAqB,CAExD"}
package/dest/config.js CHANGED
@@ -3,10 +3,7 @@ export const validatorClientConfigMappings = {
3
3
  validatorPrivateKeys: {
4
4
  env: 'VALIDATOR_PRIVATE_KEYS',
5
5
  description: 'List of private keys of the validators participating in attestation duties',
6
- ...secretValueConfigHelper((val)=>val ? val.split(',').map((key)=>`0x${key.replace('0x', '')}`) : []),
7
- fallback: [
8
- 'VALIDATOR_PRIVATE_KEY'
9
- ]
6
+ ...secretValueConfigHelper((val)=>val ? val.split(',').map((key)=>`0x${key.replace('0x', '')}`) : [])
10
7
  },
11
8
  disableValidator: {
12
9
  env: 'VALIDATOR_DISABLED',
@@ -1 +1 @@
1
- {"version":3,"file":"validation_service.d.ts","sourceRoot":"","sources":["../../src/duties/validation_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,iBAAiB;IAE/C;;;;;;;;;OASG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,EAAE,EACX,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,EAAE,EAAE,EACT,uBAAuB,EAAE,UAAU,GAAG,SAAS,EAC/C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC;IAqBzB;;;;;;;;;OASG;IACG,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAUtG"}
1
+ {"version":3,"file":"validation_service.d.ts","sourceRoot":"","sources":["../../src/duties/validation_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,iBAAiB;IAE/C;;;;;;;;;OASG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,EAAE,EACX,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,EAAE,EAAE,EACT,uBAAuB,EAAE,UAAU,GAAG,SAAS,EAC/C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC;IAoBzB;;;;;;;;;OASG;IACG,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAUtG"}
@@ -26,7 +26,7 @@ export class ValidationService {
26
26
  }
27
27
  // TODO: check if this is calculated earlier / can not be recomputed
28
28
  const txHashes = await Promise.all(txs.map((tx)=>tx.getTxHash()));
29
- return BlockProposal.createProposalFromSigner(blockNumber, new ConsensusPayload(header, archive, stateReference), txHashes, options.publishFullTxs ? txs : undefined, payloadSigner);
29
+ return BlockProposal.createProposalFromSigner(blockNumber, new ConsensusPayload(header, archive, stateReference, txHashes), options.publishFullTxs ? txs : undefined, payloadSigner);
30
30
  }
31
31
  /**
32
32
  * Attest with selection of validators to the given block proposal, constructed by the current sequencer
package/dest/factory.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
2
  import type { DateProvider } from '@aztec/foundation/timer';
3
- import type { P2PClient } from '@aztec/p2p';
3
+ import type { P2P } from '@aztec/p2p';
4
4
  import type { SlasherConfig } from '@aztec/slasher/config';
5
5
  import type { L2BlockSource } from '@aztec/stdlib/block';
6
6
  import type { IFullNodeBlockBuilder } from '@aztec/stdlib/interfaces/server';
@@ -10,7 +10,7 @@ import type { ValidatorClientConfig } from './config.js';
10
10
  import { ValidatorClient } from './validator.js';
11
11
  export declare function createValidatorClient(config: ValidatorClientConfig & Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>, deps: {
12
12
  blockBuilder: IFullNodeBlockBuilder;
13
- p2pClient: P2PClient;
13
+ p2pClient: P2P;
14
14
  blockSource: L2BlockSource;
15
15
  l1ToL2MessageSource: L1ToL2MessageSource;
16
16
  telemetry: TelemetryClient;
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC3B,IAAI,CAAC,aAAa,EAAE,0BAA0B,GAAG,0BAA0B,GAAG,6BAA6B,CAAC,EAC9G,IAAI,EAAE;IACJ,YAAY,EAAE,qBAAqB,CAAC;IACpC,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,aAAa,CAAC;IAC3B,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,eAAe,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;CACxB,+BAqBF"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC3B,IAAI,CAAC,aAAa,EAAE,0BAA0B,GAAG,0BAA0B,GAAG,6BAA6B,CAAC,EAC9G,IAAI,EAAE;IACJ,YAAY,EAAE,qBAAqB,CAAC;IACpC,SAAS,EAAE,GAAG,CAAC;IACf,WAAW,EAAE,aAAa,CAAC;IAC3B,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,eAAe,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;CACxB,+BAmBF"}
package/dest/factory.js CHANGED
@@ -10,6 +10,5 @@ export function createValidatorClient(config, deps) {
10
10
  generatePrivateKey()
11
11
  ]);
12
12
  }
13
- const txProvider = deps.p2pClient.getTxProvider();
14
- return ValidatorClient.new(config, deps.blockBuilder, deps.epochCache, deps.p2pClient, deps.blockSource, deps.l1ToL2MessageSource, txProvider, deps.dateProvider, deps.telemetry);
13
+ return ValidatorClient.new(config, deps.blockBuilder, deps.epochCache, deps.p2pClient, deps.blockSource, deps.l1ToL2MessageSource, deps.dateProvider, deps.telemetry);
15
14
  }
@@ -3,7 +3,6 @@ import type { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import { Fr } from '@aztec/foundation/fields';
4
4
  import { DateProvider } from '@aztec/foundation/timer';
5
5
  import type { P2P, PeerId } from '@aztec/p2p';
6
- import { TxProvider } from '@aztec/p2p';
7
6
  import { type SlasherConfig, type WantToSlashArgs, type Watcher, type WatcherEmitter } from '@aztec/slasher/config';
8
7
  import type { L2BlockSource } from '@aztec/stdlib/block';
9
8
  import type { IFullNodeBlockBuilder, SequencerConfig } from '@aztec/stdlib/interfaces/server';
@@ -32,7 +31,6 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
32
31
  private p2pClient;
33
32
  private blockSource;
34
33
  private l1ToL2MessageSource;
35
- private txProvider;
36
34
  private config;
37
35
  private dateProvider;
38
36
  private log;
@@ -41,13 +39,14 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
41
39
  private metrics;
42
40
  private previousProposal?;
43
41
  private myAddresses;
44
- private lastEpochForCommitteeUpdateLoop;
42
+ private lastEpoch;
45
43
  private epochCacheUpdateLoop;
46
44
  private blockProposalValidator;
45
+ private txCollector;
47
46
  private proposersOfInvalidBlocks;
48
- protected constructor(blockBuilder: IFullNodeBlockBuilder, keyStore: ValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, config: ValidatorClientConfig & Pick<SequencerConfig, 'txPublicSetupAllowList'> & Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
47
+ constructor(blockBuilder: IFullNodeBlockBuilder, keyStore: ValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, config: ValidatorClientConfig & Pick<SequencerConfig, 'txPublicSetupAllowList'> & Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
49
48
  private handleEpochCommitteeUpdate;
50
- static new(config: ValidatorClientConfig & Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>, blockBuilder: IFullNodeBlockBuilder, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, dateProvider?: DateProvider, telemetry?: TelemetryClient): ValidatorClient;
49
+ static new(config: ValidatorClientConfig & Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>, blockBuilder: IFullNodeBlockBuilder, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, dateProvider?: DateProvider, telemetry?: TelemetryClient): ValidatorClient;
51
50
  getValidatorAddresses(): EthAddress[];
52
51
  configureSlashing(config: Partial<Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>>): void;
53
52
  start(): Promise<void>;
@@ -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
@@ -6,6 +6,7 @@ import { retryUntil } from '@aztec/foundation/retry';
6
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
7
  import { sleep } from '@aztec/foundation/sleep';
8
8
  import { DateProvider, Timer } from '@aztec/foundation/timer';
9
+ import { TxCollector } from '@aztec/p2p';
9
10
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
10
11
  import { computeInHashFromL1ToL2Messages } from '@aztec/prover-client/helpers';
11
12
  import { Offense, WANT_TO_SLASH_EVENT } from '@aztec/slasher/config';
@@ -29,7 +30,6 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
29
30
  p2pClient;
30
31
  blockSource;
31
32
  l1ToL2MessageSource;
32
- txProvider;
33
33
  config;
34
34
  dateProvider;
35
35
  log;
@@ -39,16 +39,18 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
39
39
  // Used to check if we are sending the same proposal twice
40
40
  previousProposal;
41
41
  myAddresses;
42
- lastEpochForCommitteeUpdateLoop;
42
+ lastEpoch;
43
43
  epochCacheUpdateLoop;
44
44
  blockProposalValidator;
45
+ txCollector;
45
46
  proposersOfInvalidBlocks;
46
- constructor(blockBuilder, keyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, config, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
47
- super(), this.blockBuilder = blockBuilder, this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.blockSource = blockSource, this.l1ToL2MessageSource = l1ToL2MessageSource, this.txProvider = txProvider, this.config = config, this.dateProvider = dateProvider, this.log = log, this.proposersOfInvalidBlocks = new Set();
47
+ constructor(blockBuilder, keyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, config, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
48
+ super(), this.blockBuilder = blockBuilder, this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.blockSource = blockSource, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.dateProvider = dateProvider, this.log = log, this.proposersOfInvalidBlocks = new Set();
48
49
  this.tracer = telemetry.getTracer('Validator');
49
50
  this.metrics = new ValidatorMetrics(telemetry);
50
51
  this.validationService = new ValidationService(keyStore);
51
52
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
53
+ this.txCollector = new TxCollector(p2pClient, this.log);
52
54
  // Refresh epoch cache every second to trigger alert if participation in committee changes
53
55
  this.myAddresses = this.keyStore.getAddresses();
54
56
  this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), log, 1000);
@@ -56,12 +58,12 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
56
58
  }
57
59
  async handleEpochCommitteeUpdate() {
58
60
  try {
59
- const { committee, epoch } = await this.epochCache.getCommittee('next');
61
+ const { committee, epoch } = await this.epochCache.getCommittee('now');
60
62
  if (!committee) {
61
63
  this.log.trace(`No committee found for slot`);
62
64
  return;
63
65
  }
64
- if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
66
+ if (epoch !== this.lastEpoch) {
65
67
  const me = this.myAddresses;
66
68
  const committeeSet = new Set(committee.map((v)=>v.toString()));
67
69
  const inCommittee = me.filter((a)=>committeeSet.has(a.toString()));
@@ -70,19 +72,19 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
70
72
  } else {
71
73
  this.log.verbose(`Validators ${me.map((a)=>a.toString()).join(', ')} are not on the validator committee for epoch ${epoch}`);
72
74
  }
73
- this.lastEpochForCommitteeUpdateLoop = epoch;
75
+ this.lastEpoch = epoch;
74
76
  }
75
77
  } catch (err) {
76
78
  this.log.error(`Error updating epoch committee`, err);
77
79
  }
78
80
  }
79
- static new(config, blockBuilder, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, dateProvider = new DateProvider(), telemetry = getTelemetryClient()) {
81
+ static new(config, blockBuilder, epochCache, p2pClient, blockSource, l1ToL2MessageSource, dateProvider = new DateProvider(), telemetry = getTelemetryClient()) {
80
82
  if (!config.validatorPrivateKeys.getValue().length) {
81
83
  throw new InvalidValidatorPrivateKeyError();
82
84
  }
83
85
  const privateKeys = config.validatorPrivateKeys.getValue().map(validatePrivateKey);
84
86
  const localKeyStore = new LocalKeyStore(privateKeys);
85
- const validator = new ValidatorClient(blockBuilder, localKeyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, config, dateProvider, telemetry);
87
+ const validator = new ValidatorClient(blockBuilder, localKeyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, config, dateProvider, telemetry);
86
88
  validator.registerBlockProposalHandler();
87
89
  return validator;
88
90
  }
@@ -98,7 +100,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
98
100
  // Sync the committee from the smart contract
99
101
  // https://github.com/AztecProtocol/aztec-packages/issues/7962
100
102
  const myAddresses = this.keyStore.getAddresses();
101
- const inCommittee = await this.epochCache.filterInCommittee('now', myAddresses);
103
+ const inCommittee = await this.epochCache.filterInCommittee(myAddresses);
102
104
  if (inCommittee.length > 0) {
103
105
  this.log.info(`Started validator with addresses in current validator committee: ${inCommittee.map((a)=>a.toString()).join(', ')}`);
104
106
  } else {
@@ -111,40 +113,32 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
111
113
  await this.epochCacheUpdateLoop.stop();
112
114
  }
113
115
  registerBlockProposalHandler() {
114
- const handler = (block, proposalSender)=>this.attestToProposal(block, proposalSender);
116
+ const handler = (block, proposalSender)=>{
117
+ return this.attestToProposal(block, proposalSender);
118
+ };
115
119
  this.p2pClient.registerBlockProposalHandler(handler);
116
120
  }
117
121
  async attestToProposal(proposal, proposalSender) {
118
- const slotNumber = proposal.slotNumber.toBigInt();
122
+ const slotNumber = proposal.slotNumber.toNumber();
119
123
  const blockNumber = proposal.blockNumber;
120
124
  const proposer = proposal.getSender();
121
125
  // Check that I have any address in current committee before attesting
122
- const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.keyStore.getAddresses());
126
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
123
127
  const partOfCommittee = inCommittee.length > 0;
124
128
  const proposalInfo = {
125
- ...proposal.toBlockInfo(),
126
- proposer: proposer.toString()
129
+ slotNumber,
130
+ blockNumber,
131
+ proposer: proposer.toString(),
132
+ archive: proposal.payload.archive.toString(),
133
+ txCount: proposal.payload.txHashes.length,
134
+ txHashes: proposal.payload.txHashes.map((txHash)=>txHash.toString())
127
135
  };
128
- this.log.info(`Received proposal for slot ${slotNumber}`, {
129
- ...proposalInfo,
130
- txHashes: proposal.txHashes.map((txHash)=>txHash.toString())
131
- });
132
- // Collect txs from the proposal. Note that we do this before checking if we have an address in the
133
- // current committee, since we want to collect txs anyway to facilitate propagation.
134
- const { txs, missingTxs } = await this.txProvider.getTxsForBlockProposal(proposal, {
135
- pinnedPeer: proposalSender,
136
- deadline: this.getReexecutionDeadline(proposal, this.blockBuilder.getConfig())
137
- });
138
- // Check that I have any address in current committee before attesting
139
- if (!partOfCommittee) {
140
- this.log.verbose(`No validator in the current committee, skipping attestation`, proposalInfo);
141
- return undefined;
142
- }
136
+ this.log.info(`Received request to attest for slot ${slotNumber}`, proposalInfo);
143
137
  // Check that the proposal is from the current proposer, or the next proposer.
144
138
  // Q: Should this be moved to the block proposal validator, so we disregard proposals from anyone?
145
139
  const invalidProposal = await this.blockProposalValidator.validate(proposal);
146
140
  if (invalidProposal) {
147
- this.log.warn(`Proposal is not valid, skipping attestation`, proposalInfo);
141
+ this.log.warn(`Proposal is not valid, skipping attestation`);
148
142
  if (partOfCommittee) {
149
143
  this.metrics.incFailedAttestations(1, 'invalid_proposal');
150
144
  }
@@ -169,7 +163,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
169
163
  return await this.blockSource.getBlock(blockNumber - 1);
170
164
  }, 'Force Archiver Sync', timeoutDurationMs / 1000, 0.5);
171
165
  if (parentBlock === undefined) {
172
- this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`, proposalInfo);
166
+ this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`);
173
167
  if (partOfCommittee) {
174
168
  this.metrics.incFailedAttestations(1, 'parent_block_not_found');
175
169
  }
@@ -187,8 +181,20 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
187
181
  return undefined;
188
182
  }
189
183
  }
184
+ // Collect txs from the proposal
185
+ const { missing, txs } = await this.txCollector.collectForBlockProposal(proposal, proposalSender);
186
+ // Check that all of the transactions in the proposal are available in the tx pool before attesting
187
+ if (missing && missing.length > 0) {
188
+ this.log.warn(`Missing ${missing.length}/${proposal.payload.txHashes.length} txs to attest to proposal`, {
189
+ ...proposalInfo,
190
+ missing
191
+ });
192
+ if (partOfCommittee) {
193
+ this.metrics.incFailedAttestations(1, 'tx_not_available');
194
+ }
195
+ return undefined;
196
+ }
190
197
  // Check that I have the same set of l1ToL2Messages as the proposal
191
- // Q: Same as above, should this be part of p2p validation?
192
198
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
193
199
  const computedInHash = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
194
200
  const proposalInHash = proposal.payload.header.contentCommitment.inHash;
@@ -203,15 +209,8 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
203
209
  }
204
210
  return undefined;
205
211
  }
206
- // Check that all of the transactions in the proposal are available in the tx pool before attesting
207
- if (missingTxs.length > 0) {
208
- this.log.warn(`Missing ${missingTxs.length} txs to attest to proposal`, {
209
- ...proposalInfo,
210
- missingTxs
211
- });
212
- if (partOfCommittee) {
213
- this.metrics.incFailedAttestations(1, 'TransactionsNotAvailableError');
214
- }
212
+ if (!partOfCommittee) {
213
+ this.log.verbose(`No validator in the committee, skipping attestation`);
215
214
  return undefined;
216
215
  }
217
216
  // Try re-executing the transactions in the proposal
@@ -245,8 +244,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
245
244
  * Re-execute the transactions in the proposal and check that the state updates match the header state
246
245
  * @param proposal - The proposal to re-execute
247
246
  */ async reExecuteTransactions(proposal, txs, l1ToL2Messages) {
248
- const { header } = proposal.payload;
249
- const { txHashes } = proposal;
247
+ const { header, txHashes } = proposal.payload;
250
248
  // If we do not have all of the transactions, then we should fail
251
249
  if (txs.length !== txHashes.length) {
252
250
  const foundTxHashes = await Promise.all(txs.map(async (tx)=>await tx.getTxHash()));
@@ -336,7 +334,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
336
334
  }
337
335
  const proposalId = proposal.archive.toString();
338
336
  // adds attestations for all of my addresses locally
339
- const inCommittee = await this.epochCache.filterInCommittee(slot, this.keyStore.getAddresses());
337
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
340
338
  await this.doAttestToProposal(proposal, inCommittee);
341
339
  const myAddresses = this.keyStore.getAddresses();
342
340
  let attestations = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "1.0.0-nightly.20250708",
3
+ "version": "1.0.0-staging.1",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -64,15 +64,15 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/constants": "1.0.0-nightly.20250708",
68
- "@aztec/epoch-cache": "1.0.0-nightly.20250708",
69
- "@aztec/ethereum": "1.0.0-nightly.20250708",
70
- "@aztec/foundation": "1.0.0-nightly.20250708",
71
- "@aztec/p2p": "1.0.0-nightly.20250708",
72
- "@aztec/prover-client": "1.0.0-nightly.20250708",
73
- "@aztec/slasher": "1.0.0-nightly.20250708",
74
- "@aztec/stdlib": "1.0.0-nightly.20250708",
75
- "@aztec/telemetry-client": "1.0.0-nightly.20250708",
67
+ "@aztec/constants": "1.0.0-staging.1",
68
+ "@aztec/epoch-cache": "1.0.0-staging.1",
69
+ "@aztec/ethereum": "1.0.0-staging.1",
70
+ "@aztec/foundation": "1.0.0-staging.1",
71
+ "@aztec/p2p": "1.0.0-staging.1",
72
+ "@aztec/prover-client": "1.0.0-staging.1",
73
+ "@aztec/slasher": "1.0.0-staging.1",
74
+ "@aztec/stdlib": "1.0.0-staging.1",
75
+ "@aztec/telemetry-client": "1.0.0-staging.1",
76
76
  "koa": "^2.16.1",
77
77
  "koa-router": "^12.0.0",
78
78
  "tslib": "^2.4.0",
package/src/config.ts CHANGED
@@ -34,7 +34,6 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
34
34
  ...secretValueConfigHelper<`0x${string}`[]>(val =>
35
35
  val ? val.split(',').map<`0x${string}`>(key => `0x${key.replace('0x', '')}`) : [],
36
36
  ),
37
- fallback: ['VALIDATOR_PRIVATE_KEY'],
38
37
  },
39
38
  disableValidator: {
40
39
  env: 'VALIDATOR_DISABLED',
@@ -49,8 +49,7 @@ export class ValidationService {
49
49
 
50
50
  return BlockProposal.createProposalFromSigner(
51
51
  blockNumber,
52
- new ConsensusPayload(header, archive, stateReference),
53
- txHashes,
52
+ new ConsensusPayload(header, archive, stateReference, txHashes),
54
53
  options.publishFullTxs ? txs : undefined,
55
54
  payloadSigner,
56
55
  );
package/src/factory.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
2
  import { SecretValue } from '@aztec/foundation/config';
3
3
  import type { DateProvider } from '@aztec/foundation/timer';
4
- import type { P2PClient } from '@aztec/p2p';
4
+ import type { P2P } from '@aztec/p2p';
5
5
  import type { SlasherConfig } from '@aztec/slasher/config';
6
6
  import type { L2BlockSource } from '@aztec/stdlib/block';
7
7
  import type { IFullNodeBlockBuilder } from '@aztec/stdlib/interfaces/server';
@@ -18,7 +18,7 @@ export function createValidatorClient(
18
18
  Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>,
19
19
  deps: {
20
20
  blockBuilder: IFullNodeBlockBuilder;
21
- p2pClient: P2PClient;
21
+ p2pClient: P2P;
22
22
  blockSource: L2BlockSource;
23
23
  l1ToL2MessageSource: L1ToL2MessageSource;
24
24
  telemetry: TelemetryClient;
@@ -33,7 +33,6 @@ export function createValidatorClient(
33
33
  config.validatorPrivateKeys = new SecretValue([generatePrivateKey()]);
34
34
  }
35
35
 
36
- const txProvider = deps.p2pClient.getTxProvider();
37
36
  return ValidatorClient.new(
38
37
  config,
39
38
  deps.blockBuilder,
@@ -41,7 +40,6 @@ export function createValidatorClient(
41
40
  deps.p2pClient,
42
41
  deps.blockSource,
43
42
  deps.l1ToL2MessageSource,
44
- txProvider,
45
43
  deps.dateProvider,
46
44
  deps.telemetry,
47
45
  );
package/src/validator.ts CHANGED
@@ -9,7 +9,7 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
9
9
  import { sleep } from '@aztec/foundation/sleep';
10
10
  import { DateProvider, Timer } from '@aztec/foundation/timer';
11
11
  import type { P2P, PeerId } from '@aztec/p2p';
12
- import { TxProvider } from '@aztec/p2p';
12
+ import { TxCollector } from '@aztec/p2p';
13
13
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
14
14
  import { computeInHashFromL1ToL2Messages } from '@aztec/prover-client/helpers';
15
15
  import {
@@ -22,7 +22,7 @@ import {
22
22
  } from '@aztec/slasher/config';
23
23
  import type { L2BlockSource } from '@aztec/stdlib/block';
24
24
  import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
25
- import type { IFullNodeBlockBuilder, SequencerConfig } from '@aztec/stdlib/interfaces/server';
25
+ import type { IFullNodeBlockBuilder, ITxCollector, SequencerConfig } from '@aztec/stdlib/interfaces/server';
26
26
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
27
27
  import type { BlockAttestation, BlockProposal, BlockProposalOptions } from '@aztec/stdlib/p2p';
28
28
  import { GlobalVariables, type ProposedBlockHeader, type StateReference, type Tx } from '@aztec/stdlib/tx';
@@ -80,21 +80,20 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
80
80
  private previousProposal?: BlockProposal;
81
81
 
82
82
  private myAddresses: EthAddress[];
83
- private lastEpochForCommitteeUpdateLoop: bigint | undefined;
83
+ private lastEpoch: bigint | undefined;
84
84
  private epochCacheUpdateLoop: RunningPromise;
85
85
 
86
86
  private blockProposalValidator: BlockProposalValidator;
87
-
87
+ private txCollector: ITxCollector;
88
88
  private proposersOfInvalidBlocks: Set<EthAddress> = new Set();
89
89
 
90
- protected constructor(
90
+ constructor(
91
91
  private blockBuilder: IFullNodeBlockBuilder,
92
92
  private keyStore: ValidatorKeyStore,
93
93
  private epochCache: EpochCache,
94
94
  private p2pClient: P2P,
95
95
  private blockSource: L2BlockSource,
96
96
  private l1ToL2MessageSource: L1ToL2MessageSource,
97
- private txProvider: TxProvider,
98
97
  private config: ValidatorClientConfig &
99
98
  Pick<SequencerConfig, 'txPublicSetupAllowList'> &
100
99
  Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>,
@@ -110,6 +109,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
110
109
 
111
110
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
112
111
 
112
+ this.txCollector = new TxCollector(p2pClient, this.log);
113
+
113
114
  // Refresh epoch cache every second to trigger alert if participation in committee changes
114
115
  this.myAddresses = this.keyStore.getAddresses();
115
116
  this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), log, 1000);
@@ -119,12 +120,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
119
120
 
120
121
  private async handleEpochCommitteeUpdate() {
121
122
  try {
122
- const { committee, epoch } = await this.epochCache.getCommittee('next');
123
+ const { committee, epoch } = await this.epochCache.getCommittee('now');
123
124
  if (!committee) {
124
125
  this.log.trace(`No committee found for slot`);
125
126
  return;
126
127
  }
127
- if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
128
+ if (epoch !== this.lastEpoch) {
128
129
  const me = this.myAddresses;
129
130
  const committeeSet = new Set(committee.map(v => v.toString()));
130
131
  const inCommittee = me.filter(a => committeeSet.has(a.toString()));
@@ -137,7 +138,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
137
138
  `Validators ${me.map(a => a.toString()).join(', ')} are not on the validator committee for epoch ${epoch}`,
138
139
  );
139
140
  }
140
- this.lastEpochForCommitteeUpdateLoop = epoch;
141
+ this.lastEpoch = epoch;
141
142
  }
142
143
  } catch (err) {
143
144
  this.log.error(`Error updating epoch committee`, err);
@@ -152,7 +153,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
152
153
  p2pClient: P2P,
153
154
  blockSource: L2BlockSource,
154
155
  l1ToL2MessageSource: L1ToL2MessageSource,
155
- txProvider: TxProvider,
156
156
  dateProvider: DateProvider = new DateProvider(),
157
157
  telemetry: TelemetryClient = getTelemetryClient(),
158
158
  ) {
@@ -170,7 +170,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
170
170
  p2pClient,
171
171
  blockSource,
172
172
  l1ToL2MessageSource,
173
- txProvider,
174
173
  config,
175
174
  dateProvider,
176
175
  telemetry,
@@ -200,7 +199,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
200
199
 
201
200
  const myAddresses = this.keyStore.getAddresses();
202
201
 
203
- const inCommittee = await this.epochCache.filterInCommittee('now', myAddresses);
202
+ const inCommittee = await this.epochCache.filterInCommittee(myAddresses);
204
203
  if (inCommittee.length > 0) {
205
204
  this.log.info(
206
205
  `Started validator with addresses in current validator committee: ${inCommittee.map(a => a.toString()).join(', ')}`,
@@ -217,48 +216,36 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
217
216
  }
218
217
 
219
218
  public registerBlockProposalHandler() {
220
- const handler = (block: BlockProposal, proposalSender: PeerId): Promise<BlockAttestation[] | undefined> =>
221
- this.attestToProposal(block, proposalSender);
219
+ const handler = (block: BlockProposal, proposalSender: PeerId): Promise<BlockAttestation[] | undefined> => {
220
+ return this.attestToProposal(block, proposalSender);
221
+ };
222
222
  this.p2pClient.registerBlockProposalHandler(handler);
223
223
  }
224
224
 
225
225
  async attestToProposal(proposal: BlockProposal, proposalSender: PeerId): Promise<BlockAttestation[] | undefined> {
226
- const slotNumber = proposal.slotNumber.toBigInt();
226
+ const slotNumber = proposal.slotNumber.toNumber();
227
227
  const blockNumber = proposal.blockNumber;
228
228
  const proposer = proposal.getSender();
229
229
 
230
230
  // Check that I have any address in current committee before attesting
231
- const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.keyStore.getAddresses());
231
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
232
232
  const partOfCommittee = inCommittee.length > 0;
233
233
 
234
234
  const proposalInfo = {
235
- ...proposal.toBlockInfo(),
235
+ slotNumber,
236
+ blockNumber,
236
237
  proposer: proposer.toString(),
238
+ archive: proposal.payload.archive.toString(),
239
+ txCount: proposal.payload.txHashes.length,
240
+ txHashes: proposal.payload.txHashes.map(txHash => txHash.toString()),
237
241
  };
238
-
239
- this.log.info(`Received proposal for slot ${slotNumber}`, {
240
- ...proposalInfo,
241
- txHashes: proposal.txHashes.map(txHash => txHash.toString()),
242
- });
243
-
244
- // Collect txs from the proposal. Note that we do this before checking if we have an address in the
245
- // current committee, since we want to collect txs anyway to facilitate propagation.
246
- const { txs, missingTxs } = await this.txProvider.getTxsForBlockProposal(proposal, {
247
- pinnedPeer: proposalSender,
248
- deadline: this.getReexecutionDeadline(proposal, this.blockBuilder.getConfig()),
249
- });
250
-
251
- // Check that I have any address in current committee before attesting
252
- if (!partOfCommittee) {
253
- this.log.verbose(`No validator in the current committee, skipping attestation`, proposalInfo);
254
- return undefined;
255
- }
242
+ this.log.info(`Received request to attest for slot ${slotNumber}`, proposalInfo);
256
243
 
257
244
  // Check that the proposal is from the current proposer, or the next proposer.
258
245
  // Q: Should this be moved to the block proposal validator, so we disregard proposals from anyone?
259
246
  const invalidProposal = await this.blockProposalValidator.validate(proposal);
260
247
  if (invalidProposal) {
261
- this.log.warn(`Proposal is not valid, skipping attestation`, proposalInfo);
248
+ this.log.warn(`Proposal is not valid, skipping attestation`);
262
249
  if (partOfCommittee) {
263
250
  this.metrics.incFailedAttestations(1, 'invalid_proposal');
264
251
  }
@@ -293,13 +280,14 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
293
280
  );
294
281
 
295
282
  if (parentBlock === undefined) {
296
- this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`, proposalInfo);
283
+ this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`);
284
+
297
285
  if (partOfCommittee) {
298
286
  this.metrics.incFailedAttestations(1, 'parent_block_not_found');
299
287
  }
288
+
300
289
  return undefined;
301
290
  }
302
-
303
291
  if (!proposal.payload.header.lastArchiveRoot.equals(parentBlock.archive.root)) {
304
292
  this.log.warn(`Parent block archive root for proposal does not match, skipping attestation`, {
305
293
  proposalLastArchiveRoot: proposal.payload.header.lastArchiveRoot.toString(),
@@ -313,8 +301,22 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
313
301
  }
314
302
  }
315
303
 
304
+ // Collect txs from the proposal
305
+ const { missing, txs } = await this.txCollector.collectForBlockProposal(proposal, proposalSender);
306
+
307
+ // Check that all of the transactions in the proposal are available in the tx pool before attesting
308
+ if (missing && missing.length > 0) {
309
+ this.log.warn(`Missing ${missing.length}/${proposal.payload.txHashes.length} txs to attest to proposal`, {
310
+ ...proposalInfo,
311
+ missing,
312
+ });
313
+ if (partOfCommittee) {
314
+ this.metrics.incFailedAttestations(1, 'tx_not_available');
315
+ }
316
+ return undefined;
317
+ }
318
+
316
319
  // Check that I have the same set of l1ToL2Messages as the proposal
317
- // Q: Same as above, should this be part of p2p validation?
318
320
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
319
321
  const computedInHash = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
320
322
  const proposalInHash = proposal.payload.header.contentCommitment.inHash;
@@ -330,12 +332,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
330
332
  return undefined;
331
333
  }
332
334
 
333
- // Check that all of the transactions in the proposal are available in the tx pool before attesting
334
- if (missingTxs.length > 0) {
335
- this.log.warn(`Missing ${missingTxs.length} txs to attest to proposal`, { ...proposalInfo, missingTxs });
336
- if (partOfCommittee) {
337
- this.metrics.incFailedAttestations(1, 'TransactionsNotAvailableError');
338
- }
335
+ if (!partOfCommittee) {
336
+ this.log.verbose(`No validator in the committee, skipping attestation`);
339
337
  return undefined;
340
338
  }
341
339
 
@@ -378,8 +376,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
378
376
  * @param proposal - The proposal to re-execute
379
377
  */
380
378
  async reExecuteTransactions(proposal: BlockProposal, txs: Tx[], l1ToL2Messages: Fr[]): Promise<void> {
381
- const { header } = proposal.payload;
382
- const { txHashes } = proposal;
379
+ const { header, txHashes } = proposal.payload;
383
380
 
384
381
  // If we do not have all of the transactions, then we should fail
385
382
  if (txs.length !== txHashes.length) {
@@ -514,7 +511,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
514
511
 
515
512
  const proposalId = proposal.archive.toString();
516
513
  // adds attestations for all of my addresses locally
517
- const inCommittee = await this.epochCache.filterInCommittee(slot, this.keyStore.getAddresses());
514
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
518
515
  await this.doAttestToProposal(proposal, inCommittee);
519
516
 
520
517
  const myAddresses = this.keyStore.getAddresses();