@aztec/aztec-node 0.87.2 → 0.87.3-nightly.20250528

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.
@@ -6,6 +6,7 @@ import { type SharedNodeConfig } from '@aztec/node-lib/config';
6
6
  import { type P2PConfig } from '@aztec/p2p/config';
7
7
  import { type ProverClientUserConfig } from '@aztec/prover-client/config';
8
8
  import { type SequencerClientConfig, sequencerClientConfigMappings } from '@aztec/sequencer-client/config';
9
+ import { type SlasherConfig } from '@aztec/slasher';
9
10
  import { type NodeRPCConfig } from '@aztec/stdlib/config';
10
11
  import { type ValidatorClientConfig } from '@aztec/validator-client/config';
11
12
  import { type WorldStateConfig } from '@aztec/world-state/config';
@@ -14,7 +15,7 @@ export { sequencerClientConfigMappings, type SequencerClientConfig };
14
15
  /**
15
16
  * The configuration the aztec node.
16
17
  */
17
- export type AztecNodeConfig = ArchiverConfig & SequencerClientConfig & ValidatorClientConfig & ProverClientUserConfig & WorldStateConfig & Pick<ProverClientUserConfig, 'bbBinaryPath' | 'bbWorkingDirectory' | 'realProofs'> & P2PConfig & DataStoreConfig & SentinelConfig & SharedNodeConfig & GenesisStateConfig & NodeRPCConfig & {
18
+ export type AztecNodeConfig = ArchiverConfig & SequencerClientConfig & ValidatorClientConfig & ProverClientUserConfig & WorldStateConfig & Pick<ProverClientUserConfig, 'bbBinaryPath' | 'bbWorkingDirectory' | 'realProofs'> & P2PConfig & DataStoreConfig & SentinelConfig & SharedNodeConfig & GenesisStateConfig & NodeRPCConfig & SlasherConfig & {
18
19
  /** L1 contracts addresses */
19
20
  l1Contracts: L1ContractAddresses;
20
21
  /** Whether the validator is disabled for this node */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/aztec-node/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,wBAAwB,CAAC;AACrF,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAGzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,kBAAkB,EAA8C,MAAM,0BAA0B,CAAC;AAC/G,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,KAAK,gBAAgB,EAA4B,MAAM,wBAAwB,CAAC;AACzF,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,KAAK,sBAAsB,EAA8B,MAAM,6BAA6B,CAAC;AACtG,OAAO,EAAE,KAAK,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC3G,OAAO,EAAE,KAAK,aAAa,EAAyB,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,KAAK,qBAAqB,EAAiC,MAAM,gCAAgC,CAAC;AAC3G,OAAO,EAAE,KAAK,gBAAgB,EAA4B,MAAM,2BAA2B,CAAC;AAE5F,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,uBAAuB,CAAC;AAEpF,OAAO,EAAE,6BAA6B,EAAE,KAAK,qBAAqB,EAAE,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,cAAc,GAC1C,qBAAqB,GACrB,qBAAqB,GACrB,sBAAsB,GACtB,gBAAgB,GAChB,IAAI,CAAC,sBAAsB,EAAE,cAAc,GAAG,oBAAoB,GAAG,YAAY,CAAC,GAClF,SAAS,GACT,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,aAAa,GAAG;IACd,6BAA6B;IAC7B,WAAW,EAAE,mBAAmB,CAAC;IACjC,sDAAsD;IACtD,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEJ,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,CAAC,eAAe,CAqBvE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,eAAe,CAElD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/aztec-node/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,wBAAwB,CAAC;AACrF,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAGzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,kBAAkB,EAA8C,MAAM,0BAA0B,CAAC;AAC/G,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,KAAK,gBAAgB,EAA4B,MAAM,wBAAwB,CAAC;AACzF,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,KAAK,sBAAsB,EAA8B,MAAM,6BAA6B,CAAC;AACtG,OAAO,EAAE,KAAK,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC3G,OAAO,EAAE,KAAK,aAAa,EAAyB,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,KAAK,aAAa,EAAyB,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,KAAK,qBAAqB,EAAiC,MAAM,gCAAgC,CAAC;AAC3G,OAAO,EAAE,KAAK,gBAAgB,EAA4B,MAAM,2BAA2B,CAAC;AAE5F,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,uBAAuB,CAAC;AAEpF,OAAO,EAAE,6BAA6B,EAAE,KAAK,qBAAqB,EAAE,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,cAAc,GAC1C,qBAAqB,GACrB,qBAAqB,GACrB,sBAAsB,GACtB,gBAAgB,GAChB,IAAI,CAAC,sBAAsB,EAAE,cAAc,GAAG,oBAAoB,GAAG,YAAY,CAAC,GAClF,SAAS,GACT,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,aAAa,GACb,aAAa,GAAG;IACd,6BAA6B;IAC7B,WAAW,EAAE,mBAAmB,CAAC;IACjC,sDAAsD;IACtD,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEJ,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,CAAC,eAAe,CAsBvE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,eAAe,CAElD"}
@@ -6,6 +6,7 @@ import { sharedNodeConfigMappings } from '@aztec/node-lib/config';
6
6
  import { p2pConfigMappings } from '@aztec/p2p/config';
7
7
  import { proverClientConfigMappings } from '@aztec/prover-client/config';
8
8
  import { sequencerClientConfigMappings } from '@aztec/sequencer-client/config';
9
+ import { slasherConfigMappings } from '@aztec/slasher';
9
10
  import { nodeRpcConfigMappings } from '@aztec/stdlib/config';
10
11
  import { validatorClientConfigMappings } from '@aztec/validator-client/config';
11
12
  import { worldStateConfigMappings } from '@aztec/world-state/config';
@@ -23,6 +24,7 @@ export const aztecNodeConfigMappings = {
23
24
  ...sharedNodeConfigMappings,
24
25
  ...genesisStateConfigMappings,
25
26
  ...nodeRpcConfigMappings,
27
+ ...slasherConfigMappings,
26
28
  l1Contracts: {
27
29
  description: 'The deployed L1 contract addresses',
28
30
  nested: l1ContractAddressesMapping
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/aztec-node/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/aztec-node/server.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,8 @@ import { BBCircuitVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
9
9
  import { createBlobSinkClient } from '@aztec/blob-sink/client';
10
10
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
11
11
  import { EpochCache } from '@aztec/epoch-cache';
12
- import { RegistryContract, createEthereumChain } from '@aztec/ethereum';
12
+ import { RegistryContract, createEthereumChain, createExtendedL1Client } from '@aztec/ethereum';
13
+ import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
13
14
  import { compactArray } from '@aztec/foundation/collection';
14
15
  import { EthAddress } from '@aztec/foundation/eth-address';
15
16
  import { Fr } from '@aztec/foundation/fields';
@@ -25,8 +26,9 @@ import { SHA256Trunc, StandardTree, UnbalancedTree } from '@aztec/merkle-tree';
25
26
  import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
26
27
  import { createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
27
28
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
28
- import { GlobalVariableBuilder, SequencerClient, createSlasherClient, createValidatorForAcceptingTxs } from '@aztec/sequencer-client';
29
+ import { GlobalVariableBuilder, SequencerClient, createValidatorForAcceptingTxs } from '@aztec/sequencer-client';
29
30
  import { PublicProcessorFactory } from '@aztec/simulator/server';
31
+ import { EpochPruneWatcher, SlasherClient } from '@aztec/slasher';
30
32
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
31
33
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
32
34
  import { tryStop } from '@aztec/stdlib/interfaces/server';
@@ -125,6 +127,8 @@ import { NodeMetrics } from './node_metrics.js';
125
127
  ...config.l1Contracts,
126
128
  ...l1ContractsAddresses
127
129
  };
130
+ const l1Client = createExtendedL1Client(config.l1RpcUrls, config.publisherPrivateKey, ethereumChain.chainInfo);
131
+ const l1TxUtils = new L1TxUtilsWithBlobs(l1Client, log, config);
128
132
  const rollup = getContract({
129
133
  address: l1ContractsAddresses.rollupAddress.toString(),
130
134
  abi: RollupAbi,
@@ -155,8 +159,15 @@ import { NodeMetrics } from './node_metrics.js';
155
159
  await worldStateSynchronizer.start();
156
160
  // Start p2p. Note that it depends on world state to be running.
157
161
  await p2pClient.start();
158
- const slasherClient = createSlasherClient(config, archiver, telemetry);
159
- slasherClient.start();
162
+ const watchers = [];
163
+ const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
164
+ if (validatorsSentinel) {
165
+ watchers.push(validatorsSentinel);
166
+ }
167
+ const epochPruneWatcher = new EpochPruneWatcher(archiver, epochCache, config.slashPrunePenalty);
168
+ watchers.push(epochPruneWatcher);
169
+ const slasherClient = await SlasherClient.new(config, config.l1Contracts, l1TxUtils, watchers, dateProvider);
170
+ await slasherClient.start();
160
171
  const validatorClient = createValidatorClient(config, {
161
172
  p2pClient,
162
173
  telemetry,
@@ -164,12 +175,14 @@ import { NodeMetrics } from './node_metrics.js';
164
175
  epochCache,
165
176
  blockSource: archiver
166
177
  });
167
- const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
168
- await validatorsSentinel?.start();
169
178
  log.verbose(`All Aztec Node subsystems synced`);
170
179
  // now create the sequencer
171
180
  const sequencer = config.disableValidator ? undefined : await SequencerClient.new(config, {
181
+ // if deps were provided, they should override the defaults,
182
+ // or things that we created in this function
172
183
  ...deps,
184
+ epochCache,
185
+ l1TxUtils,
173
186
  validatorClient,
174
187
  p2pClient,
175
188
  worldStateSynchronizer,
@@ -365,7 +378,7 @@ import { NodeMetrics } from './node_metrics.js';
365
378
  */ async stop() {
366
379
  this.log.info(`Stopping`);
367
380
  await this.txQueue.end();
368
- await this.validatorsSentinel?.stop();
381
+ // await this.validatorsSentinel?.stop(); <- The slasher client will stop this
369
382
  await this.sequencer?.stop();
370
383
  await this.p2pClient.stop();
371
384
  await this.worldStateSynchronizer.stop();
@@ -1,8 +1,9 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
2
  import type { DataStoreConfig } from '@aztec/kv-store/config';
3
3
  import type { P2PClient } from '@aztec/p2p';
4
+ import type { SlasherConfig } from '@aztec/slasher/config';
4
5
  import type { L2BlockSource } from '@aztec/stdlib/block';
5
6
  import type { SentinelConfig } from './config.js';
6
7
  import { Sentinel } from './sentinel.js';
7
- export declare function createSentinel(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, config: SentinelConfig & DataStoreConfig, logger?: import("@aztec/foundation/log").Logger): Promise<Sentinel | undefined>;
8
+ export declare function createSentinel(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, config: SentinelConfig & DataStoreConfig & SlasherConfig, logger?: import("@aztec/foundation/log").Logger): Promise<Sentinel | undefined>;
8
9
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/sentinel/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,wBAAsB,cAAc,CAClC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,cAAc,GAAG,eAAe,EACxC,MAAM,yCAAgC,GACrC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAa/B"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/sentinel/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,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;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,wBAAsB,cAAc,CAClC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,cAAc,GAAG,eAAe,GAAG,aAAa,EACxD,MAAM,yCAAgC,GACrC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAa/B"}
@@ -11,5 +11,5 @@ export async function createSentinel(epochCache, archiver, p2p, config, logger =
11
11
  const sentinelStore = new SentinelStore(kvStore, {
12
12
  historyLength: storeHistoryLength
13
13
  });
14
- return new Sentinel(epochCache, archiver, p2p, sentinelStore, logger);
14
+ return new Sentinel(epochCache, archiver, p2p, sentinelStore, config, logger);
15
15
  }
@@ -3,14 +3,18 @@ import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import { RunningPromise } from '@aztec/foundation/running-promise';
4
4
  import { type L2TipsStore } from '@aztec/kv-store/stores';
5
5
  import type { P2PClient } from '@aztec/p2p';
6
+ import type { SlasherConfig, Watcher, WatcherEmitter } from '@aztec/slasher/config';
7
+ import { Offence } from '@aztec/slasher/config';
6
8
  import { type L2BlockSource, L2BlockStream, type L2BlockStreamEvent, type L2BlockStreamEventHandler } from '@aztec/stdlib/block';
7
- import type { ValidatorStats, ValidatorStatusHistory, ValidatorStatusInSlot, ValidatorStatusType, ValidatorsStats } from '@aztec/stdlib/validators';
9
+ import type { ValidatorStats, ValidatorStatusHistory, ValidatorStatusInSlot, ValidatorStatusType, ValidatorsEpochPerformance, ValidatorsStats } from '@aztec/stdlib/validators';
8
10
  import { SentinelStore } from './store.js';
9
- export declare class Sentinel implements L2BlockStreamEventHandler {
11
+ declare const Sentinel_base: new () => WatcherEmitter;
12
+ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEventHandler, Watcher {
10
13
  protected epochCache: EpochCache;
11
14
  protected archiver: L2BlockSource;
12
15
  protected p2p: P2PClient;
13
16
  protected store: SentinelStore;
17
+ protected config: Pick<SlasherConfig, 'slashInactivityCreateTargetPercentage' | 'slashInactivityCreatePenalty' | 'slashInactivitySignalTargetPercentage' | 'slashPayloadTtlSeconds'>;
14
18
  protected logger: import("@aztec/foundation/log").Logger;
15
19
  protected runningPromise: RunningPromise;
16
20
  protected blockStream: L2BlockStream;
@@ -22,12 +26,17 @@ export declare class Sentinel implements L2BlockStreamEventHandler {
22
26
  archive: string;
23
27
  attestors: EthAddress[];
24
28
  }>;
25
- constructor(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, store: SentinelStore, logger?: import("@aztec/foundation/log").Logger);
29
+ constructor(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, store: SentinelStore, config: Pick<SlasherConfig, 'slashInactivityCreateTargetPercentage' | 'slashInactivityCreatePenalty' | 'slashInactivitySignalTargetPercentage' | 'slashPayloadTtlSeconds'>, logger?: import("@aztec/foundation/log").Logger);
26
30
  start(): Promise<void>;
27
31
  /** Loads initial slot and initializes blockstream. We will not process anything at or before the initial slot. */
28
32
  protected init(): Promise<void>;
29
33
  stop(): Promise<void>;
30
34
  handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void>;
35
+ protected handleChainProven(event: L2BlockStreamEvent): Promise<void>;
36
+ protected computeProvenPerformance(epoch: bigint): Promise<ValidatorsEpochPerformance>;
37
+ protected updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance): Promise<void>;
38
+ protected handleProvenPerformance(performance: ValidatorsEpochPerformance): void;
39
+ shouldSlash(validator: `0x${string}`, _amount: bigint, _offense: Offence): Promise<boolean>;
31
40
  /**
32
41
  * Process data for two L2 slots ago.
33
42
  * Note that we do not process historical data, since we rely on p2p data for processing,
@@ -52,8 +61,11 @@ export declare class Sentinel implements L2BlockStreamEventHandler {
52
61
  /** Push the status for each slot for each validator. */
53
62
  protected updateValidators(slot: bigint, stats: Record<`0x${string}`, ValidatorStatusInSlot | undefined>): Promise<void>;
54
63
  /** Computes stats to be returned based on stored data. */
55
- computeStats(): Promise<ValidatorsStats>;
56
- protected computeStatsForValidator(address: `0x${string}`, allHistory: ValidatorStatusHistory, fromSlot?: bigint): ValidatorStats;
64
+ computeStats({ fromSlot: _fromSlot, toSlot: _toSlot, }?: {
65
+ fromSlot?: bigint;
66
+ toSlot?: bigint;
67
+ }): Promise<ValidatorsStats>;
68
+ protected computeStatsForValidator(address: `0x${string}`, allHistory: ValidatorStatusHistory, fromSlot?: bigint, toSlot?: bigint): ValidatorStats;
57
69
  protected computeMissed(history: ValidatorStatusHistory, computeOverPrefix: ValidatorStatusType, filter: ValidatorStatusInSlot): {
58
70
  currentStreak: number;
59
71
  rate: number | undefined;
@@ -65,4 +77,5 @@ export declare class Sentinel implements L2BlockStreamEventHandler {
65
77
  date: string;
66
78
  } | undefined;
67
79
  }
80
+ export {};
68
81
  //# sourceMappingURL=sentinel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sentinel.d.ts","sourceRoot":"","sources":["../../src/sentinel/sentinel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAE/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,QAAS,YAAW,yBAAyB;IAWtD,SAAS,CAAC,UAAU,EAAE,UAAU;IAChC,SAAS,CAAC,QAAQ,EAAE,aAAa;IACjC,SAAS,CAAC,GAAG,EAAE,SAAS;IACxB,SAAS,CAAC,KAAK,EAAE,aAAa;IAC9B,SAAS,CAAC,MAAM;IAdlB,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IACzC,SAAS,CAAC,WAAW,EAAG,aAAa,CAAC;IACtC,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IAEnC,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,SAAS,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAC/F;gBAGA,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,aAAa,EACpB,MAAM,yCAAgC;IAOrC,KAAK;IAKlB,kHAAkH;cAClG,IAAI;IAOb,IAAI;IAIE,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB7E;;;;OAIG;IACU,IAAI;IAmBjB;;;;OAIG;cACa,gBAAgB,CAAC,WAAW,EAAE,MAAM;IAkCpD;;;OAGG;cACa,WAAW,CAAC,IAAI,EAAE,MAAM;IAexC,0CAA0C;cAC1B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE;;;IAwD1G,wDAAwD;IACxD,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAIxG,0DAA0D;IAC7C,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC;IAiBrD,SAAS,CAAC,wBAAwB,CAChC,OAAO,EAAE,KAAK,MAAM,EAAE,EACtB,UAAU,EAAE,sBAAsB,EAClC,QAAQ,CAAC,EAAE,MAAM,GAChB,cAAc;IAejB,SAAS,CAAC,aAAa,CACrB,OAAO,EAAE,sBAAsB,EAC/B,iBAAiB,EAAE,mBAAmB,EACtC,MAAM,EAAE,qBAAqB;;;;;IAW/B,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;;;;;CAOnD"}
1
+ {"version":3,"file":"sentinel.d.ts","sourceRoot":"","sources":["../../src/sentinel/sentinel.ts"],"names":[],"mappings":"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"}
@@ -3,13 +3,16 @@ import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { RunningPromise } from '@aztec/foundation/running-promise';
5
5
  import { L2TipsMemoryStore } from '@aztec/kv-store/stores';
6
+ import { Offence, WANT_TO_SLASH_EVENT } from '@aztec/slasher/config';
6
7
  import { L2BlockStream, getAttestationsFromPublishedL2Block } from '@aztec/stdlib/block';
7
- import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
8
- export class Sentinel {
8
+ import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
9
+ import EventEmitter from 'node:events';
10
+ export class Sentinel extends EventEmitter {
9
11
  epochCache;
10
12
  archiver;
11
13
  p2p;
12
14
  store;
15
+ config;
13
16
  logger;
14
17
  runningPromise;
15
18
  blockStream;
@@ -17,13 +20,8 @@ export class Sentinel {
17
20
  initialSlot;
18
21
  lastProcessedSlot;
19
22
  slotNumberToBlock;
20
- constructor(epochCache, archiver, p2p, store, logger = createLogger('node:sentinel')){
21
- this.epochCache = epochCache;
22
- this.archiver = archiver;
23
- this.p2p = p2p;
24
- this.store = store;
25
- this.logger = logger;
26
- this.slotNumberToBlock = new Map();
23
+ constructor(epochCache, archiver, p2p, store, config, logger = createLogger('node:sentinel')){
24
+ super(), this.epochCache = epochCache, this.archiver = archiver, this.p2p = p2p, this.store = store, this.config = config, this.logger = logger, this.slotNumberToBlock = new Map();
27
25
  this.l2TipsStore = new L2TipsMemoryStore();
28
26
  const interval = epochCache.getL1Constants().ethereumSlotDuration * 1000 / 4;
29
27
  this.runningPromise = new RunningPromise(this.work.bind(this), logger, interval);
@@ -62,8 +60,95 @@ export class Sentinel {
62
60
  this.slotNumberToBlock.delete(key);
63
61
  }
64
62
  }
63
+ } else if (event.type === 'chain-proven') {
64
+ await this.handleChainProven(event);
65
65
  }
66
66
  }
67
+ async handleChainProven(event) {
68
+ if (event.type !== 'chain-proven') {
69
+ return;
70
+ }
71
+ const blockNumber = event.block.number;
72
+ const block = await this.archiver.getBlock(blockNumber);
73
+ if (!block) {
74
+ this.logger.error(`Failed to get block ${blockNumber}`, {
75
+ block
76
+ });
77
+ return;
78
+ }
79
+ const epoch = getEpochAtSlot(block.header.getSlot(), await this.archiver.getL1Constants());
80
+ this.logger.info(`Computing proven performance for epoch ${epoch}`);
81
+ const performance = await this.computeProvenPerformance(epoch);
82
+ this.logger.info(`Proven performance for epoch ${epoch}`, performance);
83
+ await this.updateProvenPerformance(epoch, performance);
84
+ this.handleProvenPerformance(performance);
85
+ }
86
+ async computeProvenPerformance(epoch) {
87
+ const headers = await this.archiver.getBlockHeadersForEpoch(epoch);
88
+ const provenSlots = headers.map((h)=>h.getSlot());
89
+ const fromSlot = provenSlots[0];
90
+ const toSlot = provenSlots[provenSlots.length - 1];
91
+ const { committee } = await this.epochCache.getCommittee(fromSlot);
92
+ const stats = await this.computeStats({
93
+ fromSlot,
94
+ toSlot
95
+ });
96
+ this.logger.debug(`Stats for epoch ${epoch}`, stats);
97
+ const performance = {};
98
+ for (const validator of Object.keys(stats.stats)){
99
+ let address;
100
+ try {
101
+ address = EthAddress.fromString(validator);
102
+ } catch (e) {
103
+ this.logger.error(`Invalid validator address ${validator}`, e);
104
+ continue;
105
+ }
106
+ if (!committee.find((v)=>v.equals(address))) {
107
+ continue;
108
+ }
109
+ let missed = 0;
110
+ for (const history of stats.stats[validator].history){
111
+ if (provenSlots.includes(history.slot) && history.status === 'attestation-missed') {
112
+ missed++;
113
+ }
114
+ }
115
+ performance[address.toString()] = {
116
+ missed,
117
+ total: provenSlots.length
118
+ };
119
+ }
120
+ return performance;
121
+ }
122
+ updateProvenPerformance(epoch, performance) {
123
+ return this.store.updateProvenPerformance(epoch, performance);
124
+ }
125
+ handleProvenPerformance(performance) {
126
+ const criminals = Object.entries(performance).filter(([_, { missed, total }])=>{
127
+ return missed / total >= this.config.slashInactivityCreateTargetPercentage;
128
+ }).map(([address])=>address);
129
+ const amounts = Array(criminals.length).fill(this.config.slashInactivityCreatePenalty);
130
+ const offenses = Array(criminals.length).fill(Offence.INACTIVITY);
131
+ this.logger.info(`Criminals: ${criminals.length}`, {
132
+ criminals,
133
+ amounts,
134
+ offenses
135
+ });
136
+ if (criminals.length > 0) {
137
+ this.emit(WANT_TO_SLASH_EVENT, {
138
+ validators: criminals,
139
+ amounts,
140
+ offenses
141
+ });
142
+ }
143
+ }
144
+ async shouldSlash(validator, _amount, _offense) {
145
+ const l1Constants = this.epochCache.getL1Constants();
146
+ const ttlL2Slots = this.config.slashPayloadTtlSeconds / l1Constants.slotDuration;
147
+ const ttlEpochs = BigInt(Math.ceil(ttlL2Slots / l1Constants.epochDuration));
148
+ const currentEpoch = this.epochCache.getEpochAndSlotNow().epoch;
149
+ const performance = await this.store.getProvenPerformance(validator);
150
+ return performance.filter((p)=>p.epoch >= currentEpoch - ttlEpochs).findIndex((p)=>p.missed / p.total >= this.config.slashInactivitySignalTargetPercentage) !== -1;
151
+ }
67
152
  /**
68
153
  * Process data for two L2 slots ago.
69
154
  * Note that we do not process historical data, since we rely on p2p data for processing,
@@ -203,14 +288,15 @@ export class Sentinel {
203
288
  /** Push the status for each slot for each validator. */ updateValidators(slot, stats) {
204
289
  return this.store.updateValidators(slot, stats);
205
290
  }
206
- /** Computes stats to be returned based on stored data. */ async computeStats() {
291
+ /** Computes stats to be returned based on stored data. */ async computeStats({ fromSlot: _fromSlot, toSlot: _toSlot } = {}) {
207
292
  const histories = await this.store.getHistories();
208
293
  const slotNow = this.epochCache.getEpochAndSlotNow().slot;
209
- const fromSlot = (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
294
+ const fromSlot = _fromSlot ?? (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
295
+ const toSlot = _toSlot ?? this.lastProcessedSlot ?? slotNow;
210
296
  const result = {};
211
297
  for (const [address, history] of Object.entries(histories)){
212
298
  const validatorAddress = address;
213
- result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot);
299
+ result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot, toSlot);
214
300
  }
215
301
  return {
216
302
  stats: result,
@@ -219,8 +305,9 @@ export class Sentinel {
219
305
  slotWindow: this.store.getHistoryLength()
220
306
  };
221
307
  }
222
- computeStatsForValidator(address, allHistory, fromSlot) {
223
- const history = fromSlot ? allHistory.filter((h)=>h.slot >= fromSlot) : allHistory;
308
+ computeStatsForValidator(address, allHistory, fromSlot, toSlot) {
309
+ let history = fromSlot ? allHistory.filter((h)=>h.slot >= fromSlot) : allHistory;
310
+ history = toSlot ? history.filter((h)=>h.slot <= toSlot) : history;
224
311
  return {
225
312
  address: EthAddress.fromString(address),
226
313
  lastProposal: this.computeFromSlot(history.filter((h)=>h.status === 'block-proposed' || h.status === 'block-mined').at(-1)?.slot),
@@ -1,18 +1,28 @@
1
1
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
2
- import type { ValidatorStatusHistory, ValidatorStatusInSlot } from '@aztec/stdlib/validators';
2
+ import type { ValidatorStatusHistory, ValidatorStatusInSlot, ValidatorsEpochPerformance } from '@aztec/stdlib/validators';
3
3
  export declare class SentinelStore {
4
4
  private store;
5
5
  private config;
6
- static readonly SCHEMA_VERSION = 1;
7
- private readonly map;
6
+ static readonly SCHEMA_VERSION = 2;
7
+ private readonly historyMap;
8
+ private readonly provenMap;
8
9
  constructor(store: AztecAsyncKVStore, config: {
9
10
  historyLength: number;
10
11
  });
11
12
  getHistoryLength(): number;
13
+ updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance): Promise<void>;
14
+ getProvenPerformance(who: `0x${string}`): Promise<{
15
+ missed: number;
16
+ total: number;
17
+ epoch: bigint;
18
+ }[]>;
19
+ private pushValidatorProvenPerformanceForEpoch;
12
20
  updateValidators(slot: bigint, statuses: Record<`0x${string}`, ValidatorStatusInSlot | undefined>): Promise<void>;
13
21
  private pushValidatorStatusForSlot;
14
22
  getHistories(): Promise<Record<`0x${string}`, ValidatorStatusHistory>>;
15
23
  private getHistory;
24
+ private serializePerformance;
25
+ private deserializePerformance;
16
26
  private serializeHistory;
17
27
  private deserializeHistory;
18
28
  private statusToNumber;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sentinel/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAE9F,qBAAa,aAAa;IAMtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IANhB,gBAAuB,cAAc,KAAK;IAE1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuC;gBAGjD,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;IAKpC,gBAAgB;IAIV,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC;YAUhG,0BAA0B;IAU3B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC;YAQrE,UAAU;IAKxB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,gBAAgB;CAgBzB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sentinel/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAIlC,qBAAa,aAAa;IAWtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IAXhB,gBAAuB,cAAc,KAAK;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAIlE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuC;gBAGvD,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;IAMpC,gBAAgB;IAIV,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,0BAA0B;IAW9E,oBAAoB,CAAC,GAAG,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;YAKpG,sCAAsC;IA6BvC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC;YAUhG,0BAA0B;IAU3B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC;YAQrE,UAAU;IAKxB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,sBAAsB;IAa9B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,gBAAgB;CAgBzB"}
@@ -1,17 +1,65 @@
1
1
  import { BufferReader, numToUInt8, numToUInt32BE, serializeToBuffer } from '@aztec/foundation/serialize';
2
+ import { isAddress } from 'viem';
2
3
  export class SentinelStore {
3
4
  store;
4
5
  config;
5
- static SCHEMA_VERSION = 1;
6
- map;
6
+ static SCHEMA_VERSION = 2;
7
+ // a map from validator address to their ValidatorStatusHistory
8
+ historyMap;
9
+ // a map from validator address to their historical proven epoch performance
10
+ // e.g. { validator: [{ epoch: 1, missed: 1, total: 10 }, { epoch: 2, missed: 3, total: 7 }, ...] }
11
+ provenMap;
7
12
  constructor(store, config){
8
13
  this.store = store;
9
14
  this.config = config;
10
- this.map = store.openMap('sentinel-validator-status');
15
+ this.historyMap = store.openMap('sentinel-validator-status');
16
+ this.provenMap = store.openMap('sentinel-validator-proven');
11
17
  }
12
18
  getHistoryLength() {
13
19
  return this.config.historyLength;
14
20
  }
21
+ async updateProvenPerformance(epoch, performance) {
22
+ await this.store.transactionAsync(async ()=>{
23
+ for (const [who, { missed, total }] of Object.entries(performance)){
24
+ if (!isAddress(who)) {
25
+ continue;
26
+ }
27
+ await this.pushValidatorProvenPerformanceForEpoch({
28
+ who,
29
+ missed,
30
+ total,
31
+ epoch
32
+ });
33
+ }
34
+ });
35
+ }
36
+ async getProvenPerformance(who) {
37
+ const currentPerformanceBuffer = await this.provenMap.getAsync(who);
38
+ return currentPerformanceBuffer ? this.deserializePerformance(currentPerformanceBuffer) : [];
39
+ }
40
+ async pushValidatorProvenPerformanceForEpoch({ who, missed, total, epoch }) {
41
+ const currentPerformance = await this.getProvenPerformance(who);
42
+ const existingIndex = currentPerformance.findIndex((p)=>p.epoch === epoch);
43
+ if (existingIndex !== -1) {
44
+ currentPerformance[existingIndex] = {
45
+ missed,
46
+ total,
47
+ epoch
48
+ };
49
+ } else {
50
+ currentPerformance.push({
51
+ missed,
52
+ total,
53
+ epoch
54
+ });
55
+ }
56
+ // This should be sorted by epoch, but just in case.
57
+ // Since we keep the size small, this is not a big deal.
58
+ currentPerformance.sort((a, b)=>Number(a.epoch - b.epoch));
59
+ // keep the most recent `historyLength` entries.
60
+ const performanceToKeep = currentPerformance.slice(-this.config.historyLength);
61
+ await this.provenMap.set(who, this.serializePerformance(performanceToKeep));
62
+ }
15
63
  async updateValidators(slot, statuses) {
16
64
  await this.store.transactionAsync(async ()=>{
17
65
  for (const [who, status] of Object.entries(statuses)){
@@ -30,19 +78,38 @@ export class SentinelStore {
30
78
  status
31
79
  }
32
80
  ].slice(-this.config.historyLength);
33
- await this.map.set(who, this.serializeHistory(newHistory));
81
+ await this.historyMap.set(who, this.serializeHistory(newHistory));
34
82
  }
35
83
  async getHistories() {
36
84
  const histories = {};
37
- for await (const [address, history] of this.map.entriesAsync()){
85
+ for await (const [address, history] of this.historyMap.entriesAsync()){
38
86
  histories[address] = this.deserializeHistory(history);
39
87
  }
40
88
  return histories;
41
89
  }
42
90
  async getHistory(address) {
43
- const data = await this.map.getAsync(address);
91
+ const data = await this.historyMap.getAsync(address);
44
92
  return data && this.deserializeHistory(data);
45
93
  }
94
+ serializePerformance(performance) {
95
+ return serializeToBuffer(performance.map((p)=>[
96
+ numToUInt32BE(Number(p.epoch)),
97
+ numToUInt32BE(p.missed),
98
+ numToUInt32BE(p.total)
99
+ ]));
100
+ }
101
+ deserializePerformance(buffer) {
102
+ const reader = new BufferReader(buffer);
103
+ const performance = [];
104
+ while(!reader.isEmpty()){
105
+ performance.push({
106
+ epoch: BigInt(reader.readNumber()),
107
+ missed: reader.readNumber(),
108
+ total: reader.readNumber()
109
+ });
110
+ }
111
+ return performance;
112
+ }
46
113
  serializeHistory(history) {
47
114
  return serializeToBuffer(history.map((h)=>[
48
115
  numToUInt32BE(Number(h.slot)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/aztec-node",
3
- "version": "0.87.2",
3
+ "version": "0.87.3-nightly.20250528",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -61,27 +61,28 @@
61
61
  ]
62
62
  },
63
63
  "dependencies": {
64
- "@aztec/archiver": "0.87.2",
65
- "@aztec/bb-prover": "0.87.2",
66
- "@aztec/blob-sink": "0.87.2",
67
- "@aztec/constants": "0.87.2",
68
- "@aztec/epoch-cache": "0.87.2",
69
- "@aztec/ethereum": "0.87.2",
70
- "@aztec/foundation": "0.87.2",
71
- "@aztec/kv-store": "0.87.2",
72
- "@aztec/l1-artifacts": "0.87.2",
73
- "@aztec/merkle-tree": "0.87.2",
74
- "@aztec/node-lib": "0.87.2",
75
- "@aztec/noir-protocol-circuits-types": "0.87.2",
76
- "@aztec/p2p": "0.87.2",
77
- "@aztec/protocol-contracts": "0.87.2",
78
- "@aztec/prover-client": "0.87.2",
79
- "@aztec/sequencer-client": "0.87.2",
80
- "@aztec/simulator": "0.87.2",
81
- "@aztec/stdlib": "0.87.2",
82
- "@aztec/telemetry-client": "0.87.2",
83
- "@aztec/validator-client": "0.87.2",
84
- "@aztec/world-state": "0.87.2",
64
+ "@aztec/archiver": "0.87.3-nightly.20250528",
65
+ "@aztec/bb-prover": "0.87.3-nightly.20250528",
66
+ "@aztec/blob-sink": "0.87.3-nightly.20250528",
67
+ "@aztec/constants": "0.87.3-nightly.20250528",
68
+ "@aztec/epoch-cache": "0.87.3-nightly.20250528",
69
+ "@aztec/ethereum": "0.87.3-nightly.20250528",
70
+ "@aztec/foundation": "0.87.3-nightly.20250528",
71
+ "@aztec/kv-store": "0.87.3-nightly.20250528",
72
+ "@aztec/l1-artifacts": "0.87.3-nightly.20250528",
73
+ "@aztec/merkle-tree": "0.87.3-nightly.20250528",
74
+ "@aztec/node-lib": "0.87.3-nightly.20250528",
75
+ "@aztec/noir-protocol-circuits-types": "0.87.3-nightly.20250528",
76
+ "@aztec/p2p": "0.87.3-nightly.20250528",
77
+ "@aztec/protocol-contracts": "0.87.3-nightly.20250528",
78
+ "@aztec/prover-client": "0.87.3-nightly.20250528",
79
+ "@aztec/sequencer-client": "0.87.3-nightly.20250528",
80
+ "@aztec/simulator": "0.87.3-nightly.20250528",
81
+ "@aztec/slasher": "0.87.3-nightly.20250528",
82
+ "@aztec/stdlib": "0.87.3-nightly.20250528",
83
+ "@aztec/telemetry-client": "0.87.3-nightly.20250528",
84
+ "@aztec/validator-client": "0.87.3-nightly.20250528",
85
+ "@aztec/world-state": "0.87.3-nightly.20250528",
85
86
  "koa": "^2.16.1",
86
87
  "koa-router": "^12.0.0",
87
88
  "tslib": "^2.4.0",
@@ -11,6 +11,7 @@ import { type SharedNodeConfig, sharedNodeConfigMappings } from '@aztec/node-lib
11
11
  import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
12
12
  import { type ProverClientUserConfig, proverClientConfigMappings } from '@aztec/prover-client/config';
13
13
  import { type SequencerClientConfig, sequencerClientConfigMappings } from '@aztec/sequencer-client/config';
14
+ import { type SlasherConfig, slasherConfigMappings } from '@aztec/slasher';
14
15
  import { type NodeRPCConfig, nodeRpcConfigMappings } from '@aztec/stdlib/config';
15
16
  import { type ValidatorClientConfig, validatorClientConfigMappings } from '@aztec/validator-client/config';
16
17
  import { type WorldStateConfig, worldStateConfigMappings } from '@aztec/world-state/config';
@@ -33,7 +34,8 @@ export type AztecNodeConfig = ArchiverConfig &
33
34
  SentinelConfig &
34
35
  SharedNodeConfig &
35
36
  GenesisStateConfig &
36
- NodeRPCConfig & {
37
+ NodeRPCConfig &
38
+ SlasherConfig & {
37
39
  /** L1 contracts addresses */
38
40
  l1Contracts: L1ContractAddresses;
39
41
  /** Whether the validator is disabled for this node */
@@ -52,6 +54,7 @@ export const aztecNodeConfigMappings: ConfigMappingsType<AztecNodeConfig> = {
52
54
  ...sharedNodeConfigMappings,
53
55
  ...genesisStateConfigMappings,
54
56
  ...nodeRpcConfigMappings,
57
+ ...slasherConfigMappings,
55
58
  l1Contracts: {
56
59
  description: 'The deployed L1 contract addresses',
57
60
  nested: l1ContractAddressesMapping,
@@ -10,7 +10,13 @@ import {
10
10
  type PUBLIC_DATA_TREE_HEIGHT,
11
11
  } from '@aztec/constants';
12
12
  import { EpochCache } from '@aztec/epoch-cache';
13
- import { type L1ContractAddresses, RegistryContract, createEthereumChain } from '@aztec/ethereum';
13
+ import {
14
+ type L1ContractAddresses,
15
+ RegistryContract,
16
+ createEthereumChain,
17
+ createExtendedL1Client,
18
+ } from '@aztec/ethereum';
19
+ import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
14
20
  import { compactArray } from '@aztec/foundation/collection';
15
21
  import { EthAddress } from '@aztec/foundation/eth-address';
16
22
  import { Fr } from '@aztec/foundation/fields';
@@ -30,10 +36,10 @@ import {
30
36
  GlobalVariableBuilder,
31
37
  SequencerClient,
32
38
  type SequencerPublisher,
33
- createSlasherClient,
34
39
  createValidatorForAcceptingTxs,
35
40
  } from '@aztec/sequencer-client';
36
41
  import { PublicProcessorFactory } from '@aztec/simulator/server';
42
+ import { EpochPruneWatcher, SlasherClient, type Watcher } from '@aztec/slasher';
37
43
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
38
44
  import type { InBlock, L2Block, L2BlockNumber, L2BlockSource, PublishedL2Block } from '@aztec/stdlib/block';
39
45
  import type {
@@ -181,7 +187,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
181
187
 
182
188
  const publicClient = createPublicClient({
183
189
  chain: ethereumChain.chainInfo,
184
- transport: fallback(config.l1RpcUrls.map(url => http(url))),
190
+ transport: fallback(config.l1RpcUrls.map((url: string) => http(url))),
185
191
  pollingInterval: config.viemPollingIntervalMS,
186
192
  });
187
193
 
@@ -194,6 +200,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
194
200
  // Overwrite the passed in vars.
195
201
  config.l1Contracts = { ...config.l1Contracts, ...l1ContractsAddresses };
196
202
 
203
+ const l1Client = createExtendedL1Client(config.l1RpcUrls, config.publisherPrivateKey, ethereumChain.chainInfo);
204
+ const l1TxUtils = new L1TxUtilsWithBlobs(l1Client, log, config);
205
+
197
206
  const rollup = getContract({
198
207
  address: l1ContractsAddresses.rollupAddress.toString(),
199
208
  abi: RollupAbi,
@@ -247,8 +256,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
247
256
  // Start p2p. Note that it depends on world state to be running.
248
257
  await p2pClient.start();
249
258
 
250
- const slasherClient = createSlasherClient(config, archiver, telemetry);
251
- slasherClient.start();
259
+ const watchers: Watcher[] = [];
260
+
261
+ const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
262
+ if (validatorsSentinel) {
263
+ watchers.push(validatorsSentinel);
264
+ }
265
+ const epochPruneWatcher = new EpochPruneWatcher(archiver, epochCache, config.slashPrunePenalty);
266
+ watchers.push(epochPruneWatcher);
267
+
268
+ const slasherClient = await SlasherClient.new(config, config.l1Contracts, l1TxUtils, watchers, dateProvider);
269
+ await slasherClient.start();
252
270
 
253
271
  const validatorClient = createValidatorClient(config, {
254
272
  p2pClient,
@@ -258,16 +276,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
258
276
  blockSource: archiver,
259
277
  });
260
278
 
261
- const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
262
- await validatorsSentinel?.start();
263
-
264
279
  log.verbose(`All Aztec Node subsystems synced`);
265
280
 
266
281
  // now create the sequencer
267
282
  const sequencer = config.disableValidator
268
283
  ? undefined
269
284
  : await SequencerClient.new(config, {
285
+ // if deps were provided, they should override the defaults,
286
+ // or things that we created in this function
270
287
  ...deps,
288
+ epochCache,
289
+ l1TxUtils,
271
290
  validatorClient,
272
291
  p2pClient,
273
292
  worldStateSynchronizer,
@@ -528,7 +547,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
528
547
  public async stop() {
529
548
  this.log.info(`Stopping`);
530
549
  await this.txQueue.end();
531
- await this.validatorsSentinel?.stop();
550
+ // await this.validatorsSentinel?.stop(); <- The slasher client will stop this
532
551
  await this.sequencer?.stop();
533
552
  await this.p2pClient.stop();
534
553
  await this.worldStateSynchronizer.stop();
@@ -3,6 +3,7 @@ import { createLogger } from '@aztec/foundation/log';
3
3
  import type { DataStoreConfig } from '@aztec/kv-store/config';
4
4
  import { createStore } from '@aztec/kv-store/lmdb-v2';
5
5
  import type { P2PClient } from '@aztec/p2p';
6
+ import type { SlasherConfig } from '@aztec/slasher/config';
6
7
  import type { L2BlockSource } from '@aztec/stdlib/block';
7
8
 
8
9
  import type { SentinelConfig } from './config.js';
@@ -13,7 +14,7 @@ export async function createSentinel(
13
14
  epochCache: EpochCache,
14
15
  archiver: L2BlockSource,
15
16
  p2p: P2PClient,
16
- config: SentinelConfig & DataStoreConfig,
17
+ config: SentinelConfig & DataStoreConfig & SlasherConfig,
17
18
  logger = createLogger('node:sentinel'),
18
19
  ): Promise<Sentinel | undefined> {
19
20
  if (!config.sentinelEnabled) {
@@ -27,5 +28,5 @@ export async function createSentinel(
27
28
  );
28
29
  const storeHistoryLength = config.sentinelHistoryLengthInEpochs * epochCache.getL1Constants().epochDuration;
29
30
  const sentinelStore = new SentinelStore(kvStore, { historyLength: storeHistoryLength });
30
- return new Sentinel(epochCache, archiver, p2p, sentinelStore, logger);
31
+ return new Sentinel(epochCache, archiver, p2p, sentinelStore, config, logger);
31
32
  }
@@ -5,6 +5,8 @@ import { createLogger } from '@aztec/foundation/log';
5
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
6
6
  import { L2TipsMemoryStore, type L2TipsStore } from '@aztec/kv-store/stores';
7
7
  import type { P2PClient } from '@aztec/p2p';
8
+ import type { SlasherConfig, Watcher, WatcherEmitter } from '@aztec/slasher/config';
9
+ import { Offence, WANT_TO_SLASH_EVENT } from '@aztec/slasher/config';
8
10
  import {
9
11
  type L2BlockSource,
10
12
  L2BlockStream,
@@ -12,18 +14,21 @@ import {
12
14
  type L2BlockStreamEventHandler,
13
15
  getAttestationsFromPublishedL2Block,
14
16
  } from '@aztec/stdlib/block';
15
- import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
17
+ import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
16
18
  import type {
17
19
  ValidatorStats,
18
20
  ValidatorStatusHistory,
19
21
  ValidatorStatusInSlot,
20
22
  ValidatorStatusType,
23
+ ValidatorsEpochPerformance,
21
24
  ValidatorsStats,
22
25
  } from '@aztec/stdlib/validators';
23
26
 
27
+ import EventEmitter from 'node:events';
28
+
24
29
  import { SentinelStore } from './store.js';
25
30
 
26
- export class Sentinel implements L2BlockStreamEventHandler {
31
+ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) implements L2BlockStreamEventHandler, Watcher {
27
32
  protected runningPromise: RunningPromise;
28
33
  protected blockStream!: L2BlockStream;
29
34
  protected l2TipsStore: L2TipsStore;
@@ -38,8 +43,16 @@ export class Sentinel implements L2BlockStreamEventHandler {
38
43
  protected archiver: L2BlockSource,
39
44
  protected p2p: P2PClient,
40
45
  protected store: SentinelStore,
46
+ protected config: Pick<
47
+ SlasherConfig,
48
+ | 'slashInactivityCreateTargetPercentage'
49
+ | 'slashInactivityCreatePenalty'
50
+ | 'slashInactivitySignalTargetPercentage'
51
+ | 'slashPayloadTtlSeconds'
52
+ >,
41
53
  protected logger = createLogger('node:sentinel'),
42
54
  ) {
55
+ super();
43
56
  this.l2TipsStore = new L2TipsMemoryStore();
44
57
  const interval = (epochCache.getL1Constants().ethereumSlotDuration * 1000) / 4;
45
58
  this.runningPromise = new RunningPromise(this.work.bind(this), logger, interval);
@@ -84,7 +97,96 @@ export class Sentinel implements L2BlockStreamEventHandler {
84
97
  this.slotNumberToBlock.delete(key);
85
98
  }
86
99
  }
100
+ } else if (event.type === 'chain-proven') {
101
+ await this.handleChainProven(event);
102
+ }
103
+ }
104
+
105
+ protected async handleChainProven(event: L2BlockStreamEvent) {
106
+ if (event.type !== 'chain-proven') {
107
+ return;
108
+ }
109
+ const blockNumber = event.block.number;
110
+ const block = await this.archiver.getBlock(blockNumber);
111
+ if (!block) {
112
+ this.logger.error(`Failed to get block ${blockNumber}`, { block });
113
+ return;
87
114
  }
115
+
116
+ const epoch = getEpochAtSlot(block.header.getSlot(), await this.archiver.getL1Constants());
117
+ this.logger.info(`Computing proven performance for epoch ${epoch}`);
118
+ const performance = await this.computeProvenPerformance(epoch);
119
+ this.logger.info(`Proven performance for epoch ${epoch}`, performance);
120
+
121
+ await this.updateProvenPerformance(epoch, performance);
122
+ this.handleProvenPerformance(performance);
123
+ }
124
+
125
+ protected async computeProvenPerformance(epoch: bigint) {
126
+ const headers = await this.archiver.getBlockHeadersForEpoch(epoch);
127
+ const provenSlots = headers.map(h => h.getSlot());
128
+ const fromSlot = provenSlots[0];
129
+ const toSlot = provenSlots[provenSlots.length - 1];
130
+ const { committee } = await this.epochCache.getCommittee(fromSlot);
131
+ const stats = await this.computeStats({ fromSlot, toSlot });
132
+ this.logger.debug(`Stats for epoch ${epoch}`, stats);
133
+
134
+ const performance: ValidatorsEpochPerformance = {};
135
+ for (const validator of Object.keys(stats.stats)) {
136
+ let address;
137
+ try {
138
+ address = EthAddress.fromString(validator);
139
+ } catch (e) {
140
+ this.logger.error(`Invalid validator address ${validator}`, e);
141
+ continue;
142
+ }
143
+ if (!committee.find(v => v.equals(address))) {
144
+ continue;
145
+ }
146
+ let missed = 0;
147
+ for (const history of stats.stats[validator].history) {
148
+ if (provenSlots.includes(history.slot) && history.status === 'attestation-missed') {
149
+ missed++;
150
+ }
151
+ }
152
+ performance[address.toString()] = { missed, total: provenSlots.length };
153
+ }
154
+ return performance;
155
+ }
156
+
157
+ protected updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance) {
158
+ return this.store.updateProvenPerformance(epoch, performance);
159
+ }
160
+
161
+ protected handleProvenPerformance(performance: ValidatorsEpochPerformance) {
162
+ const criminals = Object.entries(performance)
163
+ .filter(([_, { missed, total }]) => {
164
+ return missed / total >= this.config.slashInactivityCreateTargetPercentage;
165
+ })
166
+ .map(([address]) => address as `0x${string}`);
167
+
168
+ const amounts = Array(criminals.length).fill(this.config.slashInactivityCreatePenalty);
169
+ const offenses = Array(criminals.length).fill(Offence.INACTIVITY);
170
+
171
+ this.logger.info(`Criminals: ${criminals.length}`, { criminals, amounts, offenses });
172
+
173
+ if (criminals.length > 0) {
174
+ this.emit(WANT_TO_SLASH_EVENT, { validators: criminals, amounts, offenses });
175
+ }
176
+ }
177
+
178
+ public async shouldSlash(validator: `0x${string}`, _amount: bigint, _offense: Offence): Promise<boolean> {
179
+ const l1Constants = this.epochCache.getL1Constants();
180
+ const ttlL2Slots = this.config.slashPayloadTtlSeconds / l1Constants.slotDuration;
181
+ const ttlEpochs = BigInt(Math.ceil(ttlL2Slots / l1Constants.epochDuration));
182
+
183
+ const currentEpoch = this.epochCache.getEpochAndSlotNow().epoch;
184
+ const performance = await this.store.getProvenPerformance(validator);
185
+ return (
186
+ performance
187
+ .filter(p => p.epoch >= currentEpoch - ttlEpochs)
188
+ .findIndex(p => p.missed / p.total >= this.config.slashInactivitySignalTargetPercentage) !== -1
189
+ );
88
190
  }
89
191
 
90
192
  /**
@@ -232,14 +334,18 @@ export class Sentinel implements L2BlockStreamEventHandler {
232
334
  }
233
335
 
234
336
  /** Computes stats to be returned based on stored data. */
235
- public async computeStats(): Promise<ValidatorsStats> {
337
+ public async computeStats({
338
+ fromSlot: _fromSlot,
339
+ toSlot: _toSlot,
340
+ }: { fromSlot?: bigint; toSlot?: bigint } = {}): Promise<ValidatorsStats> {
236
341
  const histories = await this.store.getHistories();
237
342
  const slotNow = this.epochCache.getEpochAndSlotNow().slot;
238
- const fromSlot = (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
343
+ const fromSlot = _fromSlot ?? (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
344
+ const toSlot = _toSlot ?? this.lastProcessedSlot ?? slotNow;
239
345
  const result: Record<`0x${string}`, ValidatorStats> = {};
240
346
  for (const [address, history] of Object.entries(histories)) {
241
347
  const validatorAddress = address as `0x${string}`;
242
- result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot);
348
+ result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot, toSlot);
243
349
  }
244
350
  return {
245
351
  stats: result,
@@ -253,8 +359,10 @@ export class Sentinel implements L2BlockStreamEventHandler {
253
359
  address: `0x${string}`,
254
360
  allHistory: ValidatorStatusHistory,
255
361
  fromSlot?: bigint,
362
+ toSlot?: bigint,
256
363
  ): ValidatorStats {
257
- const history = fromSlot ? allHistory.filter(h => h.slot >= fromSlot) : allHistory;
364
+ let history = fromSlot ? allHistory.filter(h => h.slot >= fromSlot) : allHistory;
365
+ history = toSlot ? history.filter(h => h.slot <= toSlot) : history;
258
366
  return {
259
367
  address: EthAddress.fromString(address),
260
368
  lastProposal: this.computeFromSlot(
@@ -1,23 +1,80 @@
1
1
  import { BufferReader, numToUInt8, numToUInt32BE, serializeToBuffer } from '@aztec/foundation/serialize';
2
2
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
3
- import type { ValidatorStatusHistory, ValidatorStatusInSlot } from '@aztec/stdlib/validators';
3
+ import type {
4
+ ValidatorStatusHistory,
5
+ ValidatorStatusInSlot,
6
+ ValidatorsEpochPerformance,
7
+ } from '@aztec/stdlib/validators';
8
+
9
+ import { isAddress } from 'viem';
4
10
 
5
11
  export class SentinelStore {
6
- public static readonly SCHEMA_VERSION = 1;
12
+ public static readonly SCHEMA_VERSION = 2;
13
+
14
+ // a map from validator address to their ValidatorStatusHistory
15
+ private readonly historyMap: AztecAsyncMap<`0x${string}`, Buffer>;
7
16
 
8
- private readonly map: AztecAsyncMap<`0x${string}`, Buffer>;
17
+ // a map from validator address to their historical proven epoch performance
18
+ // e.g. { validator: [{ epoch: 1, missed: 1, total: 10 }, { epoch: 2, missed: 3, total: 7 }, ...] }
19
+ private readonly provenMap: AztecAsyncMap<`0x${string}`, Buffer>;
9
20
 
10
21
  constructor(
11
22
  private store: AztecAsyncKVStore,
12
23
  private config: { historyLength: number },
13
24
  ) {
14
- this.map = store.openMap('sentinel-validator-status');
25
+ this.historyMap = store.openMap('sentinel-validator-status');
26
+ this.provenMap = store.openMap('sentinel-validator-proven');
15
27
  }
16
28
 
17
29
  public getHistoryLength() {
18
30
  return this.config.historyLength;
19
31
  }
20
32
 
33
+ public async updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance) {
34
+ await this.store.transactionAsync(async () => {
35
+ for (const [who, { missed, total }] of Object.entries(performance)) {
36
+ if (!isAddress(who)) {
37
+ continue;
38
+ }
39
+ await this.pushValidatorProvenPerformanceForEpoch({ who, missed, total, epoch });
40
+ }
41
+ });
42
+ }
43
+
44
+ public async getProvenPerformance(who: `0x${string}`): Promise<{ missed: number; total: number; epoch: bigint }[]> {
45
+ const currentPerformanceBuffer = await this.provenMap.getAsync(who);
46
+ return currentPerformanceBuffer ? this.deserializePerformance(currentPerformanceBuffer) : [];
47
+ }
48
+
49
+ private async pushValidatorProvenPerformanceForEpoch({
50
+ who,
51
+ missed,
52
+ total,
53
+ epoch,
54
+ }: {
55
+ who: `0x${string}`;
56
+ missed: number;
57
+ total: number;
58
+ epoch: bigint;
59
+ }) {
60
+ const currentPerformance = await this.getProvenPerformance(who);
61
+ const existingIndex = currentPerformance.findIndex(p => p.epoch === epoch);
62
+ if (existingIndex !== -1) {
63
+ currentPerformance[existingIndex] = { missed, total, epoch };
64
+ } else {
65
+ currentPerformance.push({ missed, total, epoch });
66
+ }
67
+
68
+ // This should be sorted by epoch, but just in case.
69
+ // Since we keep the size small, this is not a big deal.
70
+ currentPerformance.sort((a, b) => Number(a.epoch - b.epoch));
71
+
72
+ // keep the most recent `historyLength` entries.
73
+ const performanceToKeep = currentPerformance.slice(-this.config.historyLength);
74
+
75
+ await this.provenMap.set(who, this.serializePerformance(performanceToKeep));
76
+ }
77
+
21
78
  public async updateValidators(slot: bigint, statuses: Record<`0x${string}`, ValidatorStatusInSlot | undefined>) {
22
79
  await this.store.transactionAsync(async () => {
23
80
  for (const [who, status] of Object.entries(statuses)) {
@@ -35,22 +92,41 @@ export class SentinelStore {
35
92
  ) {
36
93
  const currentHistory = (await this.getHistory(who)) ?? [];
37
94
  const newHistory = [...currentHistory, { slot, status }].slice(-this.config.historyLength);
38
- await this.map.set(who, this.serializeHistory(newHistory));
95
+ await this.historyMap.set(who, this.serializeHistory(newHistory));
39
96
  }
40
97
 
41
98
  public async getHistories(): Promise<Record<`0x${string}`, ValidatorStatusHistory>> {
42
99
  const histories: Record<`0x${string}`, ValidatorStatusHistory> = {};
43
- for await (const [address, history] of this.map.entriesAsync()) {
100
+ for await (const [address, history] of this.historyMap.entriesAsync()) {
44
101
  histories[address] = this.deserializeHistory(history);
45
102
  }
46
103
  return histories;
47
104
  }
48
105
 
49
106
  private async getHistory(address: `0x${string}`): Promise<ValidatorStatusHistory | undefined> {
50
- const data = await this.map.getAsync(address);
107
+ const data = await this.historyMap.getAsync(address);
51
108
  return data && this.deserializeHistory(data);
52
109
  }
53
110
 
111
+ private serializePerformance(performance: { missed: number; total: number; epoch: bigint }[]): Buffer {
112
+ return serializeToBuffer(
113
+ performance.map(p => [numToUInt32BE(Number(p.epoch)), numToUInt32BE(p.missed), numToUInt32BE(p.total)]),
114
+ );
115
+ }
116
+
117
+ private deserializePerformance(buffer: Buffer): { missed: number; total: number; epoch: bigint }[] {
118
+ const reader = new BufferReader(buffer);
119
+ const performance: { missed: number; total: number; epoch: bigint }[] = [];
120
+ while (!reader.isEmpty()) {
121
+ performance.push({
122
+ epoch: BigInt(reader.readNumber()),
123
+ missed: reader.readNumber(),
124
+ total: reader.readNumber(),
125
+ });
126
+ }
127
+ return performance;
128
+ }
129
+
54
130
  private serializeHistory(history: ValidatorStatusHistory): Buffer {
55
131
  return serializeToBuffer(
56
132
  history.map(h => [numToUInt32BE(Number(h.slot)), numToUInt8(this.statusToNumber(h.status))]),