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

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":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAI9C,OAAO,EAAE,YAAY,EAAS,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAI9C,OAAO,EAEL,KAAK,aAAa,EAElB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,qBAAqB,EAAgB,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAC5G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAmB,KAAK,mBAAmB,EAAE,KAAK,cAAc,EAAE,KAAK,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAS3G,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAsB,MAAM,yBAAyB,CAAC;AAIhG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAQlE,MAAM,WAAW,SAAS;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,4BAA4B,IAAI,IAAI,CAAC;IAGrC,mBAAmB,CACjB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,EAAE,EACX,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,EAAE,EAAE,EACT,eAAe,EAAE,UAAU,GAAG,SAAS,EACvC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IACtC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,GAAG,SAAS,CAAC,CAAC;IAEnG,sBAAsB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;CAC7G;oCAKqD,UAAU,cAAc;AAH9E;;GAEG;AACH,qBAAa,eAAgB,SAAQ,oBAA2C,YAAW,SAAS,EAAE,OAAO;IAiBzG,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,MAAM;IAGd,OAAO,CAAC,YAAY;IAEpB,OAAO,CAAC,GAAG;IA3Bb,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAmB;IAGlC,OAAO,CAAC,gBAAgB,CAAC,CAAgB;IAEzC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,oBAAoB,CAAiB;IAE7C,OAAO,CAAC,sBAAsB,CAAyB;IACvD,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,wBAAwB,CAA8B;gBAGpD,YAAY,EAAE,qBAAqB,EACnC,QAAQ,EAAE,iBAAiB,EAC3B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,GAAG,EACd,WAAW,EAAE,aAAa,EAC1B,mBAAmB,EAAE,mBAAmB,EACxC,MAAM,EAAE,qBAAqB,GACnC,IAAI,CAAC,eAAe,EAAE,wBAAwB,CAAC,GAC/C,IAAI,CAAC,aAAa,EAAE,0BAA0B,GAAG,0BAA0B,GAAG,6BAA6B,CAAC,EACtG,YAAY,GAAE,YAAiC,EACvD,SAAS,GAAE,eAAsC,EACzC,GAAG,yCAA4B;YAmB3B,0BAA0B;IA2BxC,MAAM,CAAC,GAAG,CACR,MAAM,EAAE,qBAAqB,GAC3B,IAAI,CAAC,aAAa,EAAE,0BAA0B,GAAG,0BAA0B,GAAG,6BAA6B,CAAC,EAC9G,YAAY,EAAE,qBAAqB,EACnC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,GAAG,EACd,WAAW,EAAE,aAAa,EAC1B,mBAAmB,EAAE,mBAAmB,EACxC,YAAY,GAAE,YAAiC,EAC/C,SAAS,GAAE,eAAsC;IAwB5C,qBAAqB;IAIrB,iBAAiB,CACtB,MAAM,EAAE,OAAO,CACb,IAAI,CAAC,aAAa,EAAE,0BAA0B,GAAG,0BAA0B,GAAG,6BAA6B,CAAC,CAC7G;IAQU,KAAK;IAkBL,IAAI;IAIV,4BAA4B;IAO7B,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,GAAG,SAAS,CAAC;IA0GhH,OAAO,CAAC,sBAAsB;IAS9B;;;OAGG;IACG,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDpG,OAAO,CAAC,iBAAiB;IAoBzB;;;;;;;;;;;OAWG;IACI,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAOrD,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,EAAE,EACX,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,EAAE,EAAE,EACT,eAAe,EAAE,UAAU,GAAG,SAAS,EACvC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAmB/B,sBAAsB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAiDnG,kBAAkB;CAKjC"}
package/dest/validator.js CHANGED
@@ -2,10 +2,10 @@ import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
2
  import { Buffer32 } from '@aztec/foundation/buffer';
3
3
  import { Fr } from '@aztec/foundation/fields';
4
4
  import { createLogger } from '@aztec/foundation/log';
5
- import { retryUntil } from '@aztec/foundation/retry';
6
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
6
  import { sleep } from '@aztec/foundation/sleep';
8
7
  import { DateProvider, Timer } from '@aztec/foundation/timer';
8
+ import { TxCollector } from '@aztec/p2p';
9
9
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
10
10
  import { computeInHashFromL1ToL2Messages } from '@aztec/prover-client/helpers';
11
11
  import { Offense, WANT_TO_SLASH_EVENT } from '@aztec/slasher/config';
@@ -29,7 +29,6 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
29
29
  p2pClient;
30
30
  blockSource;
31
31
  l1ToL2MessageSource;
32
- txProvider;
33
32
  config;
34
33
  dateProvider;
35
34
  log;
@@ -39,16 +38,18 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
39
38
  // Used to check if we are sending the same proposal twice
40
39
  previousProposal;
41
40
  myAddresses;
42
- lastEpochForCommitteeUpdateLoop;
41
+ lastEpoch;
43
42
  epochCacheUpdateLoop;
44
43
  blockProposalValidator;
44
+ txCollector;
45
45
  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();
46
+ constructor(blockBuilder, keyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, 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.config = config, this.dateProvider = dateProvider, this.log = log, this.proposersOfInvalidBlocks = new Set();
48
48
  this.tracer = telemetry.getTracer('Validator');
49
49
  this.metrics = new ValidatorMetrics(telemetry);
50
50
  this.validationService = new ValidationService(keyStore);
51
51
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
52
+ this.txCollector = new TxCollector(p2pClient, this.log);
52
53
  // Refresh epoch cache every second to trigger alert if participation in committee changes
53
54
  this.myAddresses = this.keyStore.getAddresses();
54
55
  this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), log, 1000);
@@ -56,12 +57,12 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
56
57
  }
57
58
  async handleEpochCommitteeUpdate() {
58
59
  try {
59
- const { committee, epoch } = await this.epochCache.getCommittee('next');
60
+ const { committee, epoch } = await this.epochCache.getCommittee('now');
60
61
  if (!committee) {
61
62
  this.log.trace(`No committee found for slot`);
62
63
  return;
63
64
  }
64
- if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
65
+ if (epoch !== this.lastEpoch) {
65
66
  const me = this.myAddresses;
66
67
  const committeeSet = new Set(committee.map((v)=>v.toString()));
67
68
  const inCommittee = me.filter((a)=>committeeSet.has(a.toString()));
@@ -70,19 +71,19 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
70
71
  } else {
71
72
  this.log.verbose(`Validators ${me.map((a)=>a.toString()).join(', ')} are not on the validator committee for epoch ${epoch}`);
72
73
  }
73
- this.lastEpochForCommitteeUpdateLoop = epoch;
74
+ this.lastEpoch = epoch;
74
75
  }
75
76
  } catch (err) {
76
77
  this.log.error(`Error updating epoch committee`, err);
77
78
  }
78
79
  }
79
- static new(config, blockBuilder, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, dateProvider = new DateProvider(), telemetry = getTelemetryClient()) {
80
+ static new(config, blockBuilder, epochCache, p2pClient, blockSource, l1ToL2MessageSource, dateProvider = new DateProvider(), telemetry = getTelemetryClient()) {
80
81
  if (!config.validatorPrivateKeys.getValue().length) {
81
82
  throw new InvalidValidatorPrivateKeyError();
82
83
  }
83
84
  const privateKeys = config.validatorPrivateKeys.getValue().map(validatePrivateKey);
84
85
  const localKeyStore = new LocalKeyStore(privateKeys);
85
- const validator = new ValidatorClient(blockBuilder, localKeyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, config, dateProvider, telemetry);
86
+ const validator = new ValidatorClient(blockBuilder, localKeyStore, epochCache, p2pClient, blockSource, l1ToL2MessageSource, config, dateProvider, telemetry);
86
87
  validator.registerBlockProposalHandler();
87
88
  return validator;
88
89
  }
@@ -98,7 +99,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
98
99
  // Sync the committee from the smart contract
99
100
  // https://github.com/AztecProtocol/aztec-packages/issues/7962
100
101
  const myAddresses = this.keyStore.getAddresses();
101
- const inCommittee = await this.epochCache.filterInCommittee('now', myAddresses);
102
+ const inCommittee = await this.epochCache.filterInCommittee(myAddresses);
102
103
  if (inCommittee.length > 0) {
103
104
  this.log.info(`Started validator with addresses in current validator committee: ${inCommittee.map((a)=>a.toString()).join(', ')}`);
104
105
  } else {
@@ -111,43 +112,30 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
111
112
  await this.epochCacheUpdateLoop.stop();
112
113
  }
113
114
  registerBlockProposalHandler() {
114
- const handler = (block, proposalSender)=>this.attestToProposal(block, proposalSender);
115
+ const handler = (block, proposalSender)=>{
116
+ return this.attestToProposal(block, proposalSender);
117
+ };
115
118
  this.p2pClient.registerBlockProposalHandler(handler);
116
119
  }
117
120
  async attestToProposal(proposal, proposalSender) {
118
- const slotNumber = proposal.slotNumber.toBigInt();
121
+ const slotNumber = proposal.slotNumber.toNumber();
119
122
  const blockNumber = proposal.blockNumber;
120
123
  const proposer = proposal.getSender();
121
- // Check that I have any address in current committee before attesting
122
- const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.keyStore.getAddresses());
123
- const partOfCommittee = inCommittee.length > 0;
124
124
  const proposalInfo = {
125
- ...proposal.toBlockInfo(),
126
- proposer: proposer.toString()
125
+ slotNumber,
126
+ blockNumber,
127
+ proposer: proposer.toString(),
128
+ archive: proposal.payload.archive.toString(),
129
+ txCount: proposal.payload.txHashes.length,
130
+ txHashes: proposal.payload.txHashes.map((txHash)=>txHash.toString())
127
131
  };
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
- }
132
+ this.log.info(`Received request to attest for slot ${slotNumber}`, proposalInfo);
143
133
  // Check that the proposal is from the current proposer, or the next proposer.
144
134
  // Q: Should this be moved to the block proposal validator, so we disregard proposals from anyone?
145
135
  const invalidProposal = await this.blockProposalValidator.validate(proposal);
146
136
  if (invalidProposal) {
147
- this.log.warn(`Proposal is not valid, skipping attestation`, proposalInfo);
148
- if (partOfCommittee) {
149
- this.metrics.incFailedAttestations(1, 'invalid_proposal');
150
- }
137
+ this.log.warn(`Proposal is not valid, skipping attestation`);
138
+ this.metrics.incFailedAttestations(1, 'invalid_proposal');
151
139
  return undefined;
152
140
  }
153
141
  // Check that the parent proposal is a block we know, otherwise reexecution would fail.
@@ -156,23 +144,10 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
156
144
  // would not be rebroadcasted. But it also means that nodes that have not fully synced would
157
145
  // not rebroadcast the proposal.
158
146
  if (blockNumber > INITIAL_L2_BLOCK_NUM) {
159
- const config = this.blockBuilder.getConfig();
160
- const deadline = this.getReexecutionDeadline(proposal, config);
161
- const currentTime = this.dateProvider.now();
162
- const timeoutDurationMs = deadline.getTime() - currentTime;
163
- const parentBlock = timeoutDurationMs <= 0 ? undefined : await retryUntil(async ()=>{
164
- const block = await this.blockSource.getBlock(blockNumber - 1);
165
- if (block) {
166
- return block;
167
- }
168
- await this.blockSource.syncImmediate();
169
- return await this.blockSource.getBlock(blockNumber - 1);
170
- }, 'Force Archiver Sync', timeoutDurationMs / 1000, 0.5);
147
+ const parentBlock = await this.blockSource.getBlock(blockNumber - 1);
171
148
  if (parentBlock === undefined) {
172
- this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`, proposalInfo);
173
- if (partOfCommittee) {
174
- this.metrics.incFailedAttestations(1, 'parent_block_not_found');
175
- }
149
+ this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`);
150
+ this.metrics.incFailedAttestations(1, 'parent_block_not_found');
176
151
  return undefined;
177
152
  }
178
153
  if (!proposal.payload.header.lastArchiveRoot.equals(parentBlock.archive.root)) {
@@ -181,14 +156,28 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
181
156
  parentBlockArchiveRoot: parentBlock.archive.root.toString(),
182
157
  ...proposalInfo
183
158
  });
184
- if (partOfCommittee) {
185
- this.metrics.incFailedAttestations(1, 'parent_block_does_not_match');
186
- }
159
+ this.metrics.incFailedAttestations(1, 'parent_block_does_not_match');
187
160
  return undefined;
188
161
  }
189
162
  }
163
+ // Collect txs from the proposal
164
+ const { missing, txs } = await this.txCollector.collectForBlockProposal(proposal, proposalSender);
165
+ // Check that I have any address in current committee before attesting
166
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
167
+ if (inCommittee.length === 0) {
168
+ this.log.verbose(`No validator in the committee, skipping attestation`);
169
+ return undefined;
170
+ }
171
+ // Check that all of the transactions in the proposal are available in the tx pool before attesting
172
+ if (missing && missing.length > 0) {
173
+ this.log.warn(`Missing ${missing.length}/${proposal.payload.txHashes.length} txs to attest to proposal`, {
174
+ ...proposalInfo,
175
+ missing
176
+ });
177
+ this.metrics.incFailedAttestations(1, 'TransactionsNotAvailableError');
178
+ return undefined;
179
+ }
190
180
  // 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
181
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
193
182
  const computedInHash = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
194
183
  const proposalInHash = proposal.payload.header.contentCommitment.inHash;
@@ -198,20 +187,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
198
187
  computedInHash: computedInHash.toString(),
199
188
  ...proposalInfo
200
189
  });
201
- if (partOfCommittee) {
202
- this.metrics.incFailedAttestations(1, 'in_hash_mismatch');
203
- }
204
- return undefined;
205
- }
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
- }
190
+ this.metrics.incFailedAttestations(1, 'in_hash_mismatch');
215
191
  return undefined;
216
192
  }
217
193
  // Try re-executing the transactions in the proposal
@@ -245,8 +221,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
245
221
  * Re-execute the transactions in the proposal and check that the state updates match the header state
246
222
  * @param proposal - The proposal to re-execute
247
223
  */ async reExecuteTransactions(proposal, txs, l1ToL2Messages) {
248
- const { header } = proposal.payload;
249
- const { txHashes } = proposal;
224
+ const { header, txHashes } = proposal.payload;
250
225
  // If we do not have all of the transactions, then we should fail
251
226
  if (txs.length !== txHashes.length) {
252
227
  const foundTxHashes = await Promise.all(txs.map(async (tx)=>await tx.getTxHash()));
@@ -336,7 +311,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
336
311
  }
337
312
  const proposalId = proposal.archive.toString();
338
313
  // adds attestations for all of my addresses locally
339
- const inCommittee = await this.epochCache.filterInCommittee(slot, this.keyStore.getAddresses());
314
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
340
315
  await this.doAttestToProposal(proposal, inCommittee);
341
316
  const myAddresses = this.keyStore.getAddresses();
342
317
  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.0",
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.0",
68
+ "@aztec/epoch-cache": "1.0.0-staging.0",
69
+ "@aztec/ethereum": "1.0.0-staging.0",
70
+ "@aztec/foundation": "1.0.0-staging.0",
71
+ "@aztec/p2p": "1.0.0-staging.0",
72
+ "@aztec/prover-client": "1.0.0-staging.0",
73
+ "@aztec/slasher": "1.0.0-staging.0",
74
+ "@aztec/stdlib": "1.0.0-staging.0",
75
+ "@aztec/telemetry-client": "1.0.0-staging.0",
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
@@ -4,12 +4,11 @@ import { Buffer32 } from '@aztec/foundation/buffer';
4
4
  import type { EthAddress } from '@aztec/foundation/eth-address';
5
5
  import { Fr } from '@aztec/foundation/fields';
6
6
  import { createLogger } from '@aztec/foundation/log';
7
- import { retryUntil } from '@aztec/foundation/retry';
8
7
  import { RunningPromise } from '@aztec/foundation/running-promise';
9
8
  import { sleep } from '@aztec/foundation/sleep';
10
9
  import { DateProvider, Timer } from '@aztec/foundation/timer';
11
10
  import type { P2P, PeerId } from '@aztec/p2p';
12
- import { TxProvider } from '@aztec/p2p';
11
+ import { TxCollector } from '@aztec/p2p';
13
12
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
14
13
  import { computeInHashFromL1ToL2Messages } from '@aztec/prover-client/helpers';
15
14
  import {
@@ -22,7 +21,7 @@ import {
22
21
  } from '@aztec/slasher/config';
23
22
  import type { L2BlockSource } from '@aztec/stdlib/block';
24
23
  import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
25
- import type { IFullNodeBlockBuilder, SequencerConfig } from '@aztec/stdlib/interfaces/server';
24
+ import type { IFullNodeBlockBuilder, ITxCollector, SequencerConfig } from '@aztec/stdlib/interfaces/server';
26
25
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
27
26
  import type { BlockAttestation, BlockProposal, BlockProposalOptions } from '@aztec/stdlib/p2p';
28
27
  import { GlobalVariables, type ProposedBlockHeader, type StateReference, type Tx } from '@aztec/stdlib/tx';
@@ -80,21 +79,20 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
80
79
  private previousProposal?: BlockProposal;
81
80
 
82
81
  private myAddresses: EthAddress[];
83
- private lastEpochForCommitteeUpdateLoop: bigint | undefined;
82
+ private lastEpoch: bigint | undefined;
84
83
  private epochCacheUpdateLoop: RunningPromise;
85
84
 
86
85
  private blockProposalValidator: BlockProposalValidator;
87
-
86
+ private txCollector: ITxCollector;
88
87
  private proposersOfInvalidBlocks: Set<EthAddress> = new Set();
89
88
 
90
- protected constructor(
89
+ constructor(
91
90
  private blockBuilder: IFullNodeBlockBuilder,
92
91
  private keyStore: ValidatorKeyStore,
93
92
  private epochCache: EpochCache,
94
93
  private p2pClient: P2P,
95
94
  private blockSource: L2BlockSource,
96
95
  private l1ToL2MessageSource: L1ToL2MessageSource,
97
- private txProvider: TxProvider,
98
96
  private config: ValidatorClientConfig &
99
97
  Pick<SequencerConfig, 'txPublicSetupAllowList'> &
100
98
  Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>,
@@ -110,6 +108,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
110
108
 
111
109
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
112
110
 
111
+ this.txCollector = new TxCollector(p2pClient, this.log);
112
+
113
113
  // Refresh epoch cache every second to trigger alert if participation in committee changes
114
114
  this.myAddresses = this.keyStore.getAddresses();
115
115
  this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), log, 1000);
@@ -119,12 +119,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
119
119
 
120
120
  private async handleEpochCommitteeUpdate() {
121
121
  try {
122
- const { committee, epoch } = await this.epochCache.getCommittee('next');
122
+ const { committee, epoch } = await this.epochCache.getCommittee('now');
123
123
  if (!committee) {
124
124
  this.log.trace(`No committee found for slot`);
125
125
  return;
126
126
  }
127
- if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
127
+ if (epoch !== this.lastEpoch) {
128
128
  const me = this.myAddresses;
129
129
  const committeeSet = new Set(committee.map(v => v.toString()));
130
130
  const inCommittee = me.filter(a => committeeSet.has(a.toString()));
@@ -137,7 +137,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
137
137
  `Validators ${me.map(a => a.toString()).join(', ')} are not on the validator committee for epoch ${epoch}`,
138
138
  );
139
139
  }
140
- this.lastEpochForCommitteeUpdateLoop = epoch;
140
+ this.lastEpoch = epoch;
141
141
  }
142
142
  } catch (err) {
143
143
  this.log.error(`Error updating epoch committee`, err);
@@ -152,7 +152,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
152
152
  p2pClient: P2P,
153
153
  blockSource: L2BlockSource,
154
154
  l1ToL2MessageSource: L1ToL2MessageSource,
155
- txProvider: TxProvider,
156
155
  dateProvider: DateProvider = new DateProvider(),
157
156
  telemetry: TelemetryClient = getTelemetryClient(),
158
157
  ) {
@@ -170,7 +169,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
170
169
  p2pClient,
171
170
  blockSource,
172
171
  l1ToL2MessageSource,
173
- txProvider,
174
172
  config,
175
173
  dateProvider,
176
174
  telemetry,
@@ -200,7 +198,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
200
198
 
201
199
  const myAddresses = this.keyStore.getAddresses();
202
200
 
203
- const inCommittee = await this.epochCache.filterInCommittee('now', myAddresses);
201
+ const inCommittee = await this.epochCache.filterInCommittee(myAddresses);
204
202
  if (inCommittee.length > 0) {
205
203
  this.log.info(
206
204
  `Started validator with addresses in current validator committee: ${inCommittee.map(a => a.toString()).join(', ')}`,
@@ -217,51 +215,33 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
217
215
  }
218
216
 
219
217
  public registerBlockProposalHandler() {
220
- const handler = (block: BlockProposal, proposalSender: PeerId): Promise<BlockAttestation[] | undefined> =>
221
- this.attestToProposal(block, proposalSender);
218
+ const handler = (block: BlockProposal, proposalSender: PeerId): Promise<BlockAttestation[] | undefined> => {
219
+ return this.attestToProposal(block, proposalSender);
220
+ };
222
221
  this.p2pClient.registerBlockProposalHandler(handler);
223
222
  }
224
223
 
225
224
  async attestToProposal(proposal: BlockProposal, proposalSender: PeerId): Promise<BlockAttestation[] | undefined> {
226
- const slotNumber = proposal.slotNumber.toBigInt();
225
+ const slotNumber = proposal.slotNumber.toNumber();
227
226
  const blockNumber = proposal.blockNumber;
228
227
  const proposer = proposal.getSender();
229
228
 
230
- // Check that I have any address in current committee before attesting
231
- const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.keyStore.getAddresses());
232
- const partOfCommittee = inCommittee.length > 0;
233
-
234
229
  const proposalInfo = {
235
- ...proposal.toBlockInfo(),
230
+ slotNumber,
231
+ blockNumber,
236
232
  proposer: proposer.toString(),
233
+ archive: proposal.payload.archive.toString(),
234
+ txCount: proposal.payload.txHashes.length,
235
+ txHashes: proposal.payload.txHashes.map(txHash => txHash.toString()),
237
236
  };
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
- }
237
+ this.log.info(`Received request to attest for slot ${slotNumber}`, proposalInfo);
256
238
 
257
239
  // Check that the proposal is from the current proposer, or the next proposer.
258
240
  // Q: Should this be moved to the block proposal validator, so we disregard proposals from anyone?
259
241
  const invalidProposal = await this.blockProposalValidator.validate(proposal);
260
242
  if (invalidProposal) {
261
- this.log.warn(`Proposal is not valid, skipping attestation`, proposalInfo);
262
- if (partOfCommittee) {
263
- this.metrics.incFailedAttestations(1, 'invalid_proposal');
264
- }
243
+ this.log.warn(`Proposal is not valid, skipping attestation`);
244
+ this.metrics.incFailedAttestations(1, 'invalid_proposal');
265
245
  return undefined;
266
246
  }
267
247
 
@@ -271,50 +251,44 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
271
251
  // would not be rebroadcasted. But it also means that nodes that have not fully synced would
272
252
  // not rebroadcast the proposal.
273
253
  if (blockNumber > INITIAL_L2_BLOCK_NUM) {
274
- const config = this.blockBuilder.getConfig();
275
- const deadline = this.getReexecutionDeadline(proposal, config);
276
- const currentTime = this.dateProvider.now();
277
- const timeoutDurationMs = deadline.getTime() - currentTime;
278
- const parentBlock =
279
- timeoutDurationMs <= 0
280
- ? undefined
281
- : await retryUntil(
282
- async () => {
283
- const block = await this.blockSource.getBlock(blockNumber - 1);
284
- if (block) {
285
- return block;
286
- }
287
- await this.blockSource.syncImmediate();
288
- return await this.blockSource.getBlock(blockNumber - 1);
289
- },
290
- 'Force Archiver Sync',
291
- timeoutDurationMs / 1000, // Continue retrying until the deadline
292
- 0.5, // Retry every 500ms
293
- );
294
-
254
+ const parentBlock = await this.blockSource.getBlock(blockNumber - 1);
295
255
  if (parentBlock === undefined) {
296
- this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`, proposalInfo);
297
- if (partOfCommittee) {
298
- this.metrics.incFailedAttestations(1, 'parent_block_not_found');
299
- }
256
+ this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`);
257
+ this.metrics.incFailedAttestations(1, 'parent_block_not_found');
300
258
  return undefined;
301
259
  }
302
-
303
260
  if (!proposal.payload.header.lastArchiveRoot.equals(parentBlock.archive.root)) {
304
261
  this.log.warn(`Parent block archive root for proposal does not match, skipping attestation`, {
305
262
  proposalLastArchiveRoot: proposal.payload.header.lastArchiveRoot.toString(),
306
263
  parentBlockArchiveRoot: parentBlock.archive.root.toString(),
307
264
  ...proposalInfo,
308
265
  });
309
- if (partOfCommittee) {
310
- this.metrics.incFailedAttestations(1, 'parent_block_does_not_match');
311
- }
266
+ this.metrics.incFailedAttestations(1, 'parent_block_does_not_match');
312
267
  return undefined;
313
268
  }
314
269
  }
315
270
 
271
+ // Collect txs from the proposal
272
+ const { missing, txs } = await this.txCollector.collectForBlockProposal(proposal, proposalSender);
273
+
274
+ // Check that I have any address in current committee before attesting
275
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
276
+ if (inCommittee.length === 0) {
277
+ this.log.verbose(`No validator in the committee, skipping attestation`);
278
+ return undefined;
279
+ }
280
+
281
+ // Check that all of the transactions in the proposal are available in the tx pool before attesting
282
+ if (missing && missing.length > 0) {
283
+ this.log.warn(`Missing ${missing.length}/${proposal.payload.txHashes.length} txs to attest to proposal`, {
284
+ ...proposalInfo,
285
+ missing,
286
+ });
287
+ this.metrics.incFailedAttestations(1, 'TransactionsNotAvailableError');
288
+ return undefined;
289
+ }
290
+
316
291
  // 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
292
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
319
293
  const computedInHash = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
320
294
  const proposalInHash = proposal.payload.header.contentCommitment.inHash;
@@ -324,18 +298,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
324
298
  computedInHash: computedInHash.toString(),
325
299
  ...proposalInfo,
326
300
  });
327
- if (partOfCommittee) {
328
- this.metrics.incFailedAttestations(1, 'in_hash_mismatch');
329
- }
330
- return undefined;
331
- }
332
-
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
- }
301
+ this.metrics.incFailedAttestations(1, 'in_hash_mismatch');
339
302
  return undefined;
340
303
  }
341
304
 
@@ -378,8 +341,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
378
341
  * @param proposal - The proposal to re-execute
379
342
  */
380
343
  async reExecuteTransactions(proposal: BlockProposal, txs: Tx[], l1ToL2Messages: Fr[]): Promise<void> {
381
- const { header } = proposal.payload;
382
- const { txHashes } = proposal;
344
+ const { header, txHashes } = proposal.payload;
383
345
 
384
346
  // If we do not have all of the transactions, then we should fail
385
347
  if (txs.length !== txHashes.length) {
@@ -514,7 +476,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
514
476
 
515
477
  const proposalId = proposal.archive.toString();
516
478
  // adds attestations for all of my addresses locally
517
- const inCommittee = await this.epochCache.filterInCommittee(slot, this.keyStore.getAddresses());
479
+ const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
518
480
  await this.doAttestToProposal(proposal, inCommittee);
519
481
 
520
482
  const myAddresses = this.keyStore.getAddresses();