@aztec/aztec-node 0.87.3-nightly.20250529 → 0.87.4
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.
- package/dest/aztec-node/config.d.ts +1 -2
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +0 -2
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +7 -20
- package/dest/sentinel/factory.d.ts +1 -2
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/factory.js +1 -1
- package/dest/sentinel/sentinel.d.ts +5 -18
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +14 -101
- package/dest/sentinel/store.d.ts +3 -13
- package/dest/sentinel/store.d.ts.map +1 -1
- package/dest/sentinel/store.js +6 -73
- package/package.json +22 -23
- package/src/aztec-node/config.ts +1 -4
- package/src/aztec-node/server.ts +9 -28
- package/src/sentinel/factory.ts +2 -3
- package/src/sentinel/sentinel.ts +6 -114
- package/src/sentinel/store.ts +7 -83
|
@@ -6,7 +6,6 @@ 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';
|
|
10
9
|
import { type NodeRPCConfig } from '@aztec/stdlib/config';
|
|
11
10
|
import { type ValidatorClientConfig } from '@aztec/validator-client/config';
|
|
12
11
|
import { type WorldStateConfig } from '@aztec/world-state/config';
|
|
@@ -15,7 +14,7 @@ export { sequencerClientConfigMappings, type SequencerClientConfig };
|
|
|
15
14
|
/**
|
|
16
15
|
* The configuration the aztec node.
|
|
17
16
|
*/
|
|
18
|
-
export type AztecNodeConfig = ArchiverConfig & SequencerClientConfig & ValidatorClientConfig & ProverClientUserConfig & WorldStateConfig & Pick<ProverClientUserConfig, 'bbBinaryPath' | 'bbWorkingDirectory' | 'realProofs'> & P2PConfig & DataStoreConfig & SentinelConfig & SharedNodeConfig & GenesisStateConfig & NodeRPCConfig &
|
|
17
|
+
export type AztecNodeConfig = ArchiverConfig & SequencerClientConfig & ValidatorClientConfig & ProverClientUserConfig & WorldStateConfig & Pick<ProverClientUserConfig, 'bbBinaryPath' | 'bbWorkingDirectory' | 'realProofs'> & P2PConfig & DataStoreConfig & SentinelConfig & SharedNodeConfig & GenesisStateConfig & NodeRPCConfig & {
|
|
19
18
|
/** L1 contracts addresses */
|
|
20
19
|
l1Contracts: L1ContractAddresses;
|
|
21
20
|
/** 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,
|
|
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"}
|
|
@@ -6,7 +6,6 @@ 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';
|
|
10
9
|
import { nodeRpcConfigMappings } from '@aztec/stdlib/config';
|
|
11
10
|
import { validatorClientConfigMappings } from '@aztec/validator-client/config';
|
|
12
11
|
import { worldStateConfigMappings } from '@aztec/world-state/config';
|
|
@@ -24,7 +23,6 @@ export const aztecNodeConfigMappings = {
|
|
|
24
23
|
...sharedNodeConfigMappings,
|
|
25
24
|
...genesisStateConfigMappings,
|
|
26
25
|
...nodeRpcConfigMappings,
|
|
27
|
-
...slasherConfigMappings,
|
|
28
26
|
l1Contracts: {
|
|
29
27
|
description: 'The deployed L1 contract addresses',
|
|
30
28
|
nested: l1ContractAddressesMapping
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/aztec-node/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,uBAAuB,EAAwB,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC7B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/aztec-node/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,uBAAuB,EAAwB,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC7B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,mBAAmB,EAAyC,MAAM,iBAAiB,CAAC;AAGlG,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAS,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAKtD,OAAO,EAAE,KAAK,GAAG,EAAoD,MAAM,YAAY,CAAC;AAExF,OAAO,EAEL,eAAe,EACf,KAAK,kBAAkB,EAGxB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5G,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,2BAA2B,EAC3B,QAAQ,EACR,yBAAyB,EAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAE5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,KAAK,EAAyB,kBAAkB,EAA8B,MAAM,qBAAqB,CAAC;AACjH,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAClG,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,qBAAqB,IAAI,8BAA8B,EAC5D,KAAK,eAAe,EACpB,sBAAsB,EACtB,EAAE,EACF,KAAK,MAAM,EACX,SAAS,EAET,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD;;GAEG;AACH,qBAAa,gBAAiB,YAAW,SAAS,EAAE,cAAc,EAAE,SAAS;;IAYzE,SAAS,CAAC,MAAM,EAAE,eAAe;IACjC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG;IACjC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAChE,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY;IAC3C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB;IACzD,SAAS,CAAC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB;IAC3D,SAAS,CAAC,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB;IACjE,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,eAAe,GAAG,SAAS;IACzD,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,QAAQ,GAAG,SAAS;IAC3D,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM;IACpC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM;IAClC,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,8BAA8B;IACxE,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,GAAG;IA1Bb,OAAO,CAAC,OAAO,CAAc;IAG7B,OAAO,CAAC,mBAAmB,CAAS;IAGpC,OAAO,CAAC,OAAO,CAAkC;IAEjD,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAGnB,MAAM,EAAE,eAAe,EACd,SAAS,EAAE,GAAG,EACd,WAAW,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,EAC7C,UAAU,EAAE,YAAY,EACxB,kBAAkB,EAAE,kBAAkB,EACtC,mBAAmB,EAAE,mBAAmB,EACxC,sBAAsB,EAAE,sBAAsB,EAC9C,SAAS,EAAE,eAAe,GAAG,SAAS,EACtC,kBAAkB,EAAE,QAAQ,GAAG,SAAS,EACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,8BAA8B,EACvD,cAAc,EAAE,MAAM,EAC/B,aAAa,EAAE,6BAA6B,EAC5C,SAAS,GAAE,eAAsC,EACjD,GAAG,SAAuB;IAUvB,uBAAuB,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAK9D,SAAS;IAIhB;;;;OAIG;WACiB,aAAa,CAC/B,MAAM,EAAE,eAAe,EACvB,IAAI,GAAE;QACJ,SAAS,CAAC,EAAE,eAAe,CAAC;QAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,kBAAkB,CAAC;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;QAC5B,cAAc,CAAC,EAAE,uBAAuB,CAAC;KACrC,EACN,OAAO,GAAE;QACP,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;KACvC,GACL,OAAO,CAAC,gBAAgB,CAAC;IAyI5B;;;OAGG;IACI,YAAY,IAAI,eAAe,GAAG,SAAS;IAI3C,cAAc,IAAI,aAAa;IAI/B,qBAAqB,IAAI,kBAAkB;IAI3C,MAAM,IAAI,GAAG;IAIpB;;;OAGG;IACI,sBAAsB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAItD,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAInD;;;OAGG;IACI,OAAO;IAID,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;IAsB7C;;;;OAIG;IACU,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAInE;;;;;OAKG;IACU,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAI1D,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAIzF;;;OAGG;IACU,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAInD;;;OAGG;IACU,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIjC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIpD;;;OAGG;IACI,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxC;;;OAGG;IACI,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAIpC;;;OAGG;IACI,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAIlE,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC;IAI3F;;;;;OAKG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIzE;;;;;OAKG;IACI,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;IAI5D;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAIhE;;;;OAIG;IACH,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,4BAA4B,CAAC;IAI9E;;;OAGG;IACU,MAAM,CAAC,EAAE,EAAE,EAAE;IAqBb,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAkBtD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAIxE;;OAEG;IACU,IAAI;IAYjB;;;OAGG;IACI,aAAa;IAIb,iBAAiB;IAIxB;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM;IAIjC;;;;OAIG;IACU,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE;IAI5C;;;;;;;OAOG;IACU,iBAAiB,CAC5B,WAAW,EAAE,aAAa,EAC1B,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,EAAE,EAAE,GACf,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC;IA2D3C;;;;;OAKG;IACU,uBAAuB,CAClC,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAKrD;;;;;OAKG;IACU,sBAAsB,CACjC,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAKrD;;;;;OAKG;IACU,iCAAiC,CAC5C,WAAW,EAAE,aAAa,EAC1B,aAAa,EAAE,EAAE,GAChB,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAC,GAAG,SAAS,CAAC;IAa9E;;;;OAIG;IACU,qBAAqB,CAAC,aAAa,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAIvE;;;;;;;;;;;;;;;OAeG;IACU,iCAAiC,CAC5C,WAAW,EAAE,aAAa,EAC1B,aAAa,EAAE,EAAE,GAChB,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAkGzC;;;;;OAKG;IACU,qBAAqB,CAChC,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,OAAO,cAAc,CAAC,CAAC;IAK9C;;;;;OAKG;IACU,wBAAwB,CACnC,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAKvD;;;;;OAKG;IACU,6BAA6B,CACxC,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,EAAE,GACZ,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAsBlD;;;;;;;;;;;;;OAaG;IACU,gCAAgC,CAC3C,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,EAAE,GACZ,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAmB5C,oBAAoB,CAAC,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAkB5G;;;;;;;;;;OAUG;IACU,kBAAkB,CAAC,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;IAe1G;;;OAGG;IACU,cAAc,CAAC,WAAW,GAAE,aAAwB,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAMpG;;;QAGI;IAIS,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,kBAAkB,UAAQ,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAqExF,SAAS,CACpB,EAAE,EAAE,EAAE,EACN,EAAE,YAAY,EAAE,kBAAkB,EAAE,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAO,GAClG,OAAO,CAAC,kBAAkB,CAAC;IAgBjB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/E,4BAA4B,IAAI,OAAO,CAAC,yBAAyB,CAAC;IASlE,kCAAkC,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/F,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC;IAIxC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCpD,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC/D,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAMhC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CA6CnC"}
|
|
@@ -9,8 +9,7 @@ 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
|
|
13
|
-
import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
12
|
+
import { RegistryContract, createEthereumChain } from '@aztec/ethereum';
|
|
14
13
|
import { compactArray } from '@aztec/foundation/collection';
|
|
15
14
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
16
15
|
import { Fr } from '@aztec/foundation/fields';
|
|
@@ -26,9 +25,8 @@ import { SHA256Trunc, StandardTree, UnbalancedTree } from '@aztec/merkle-tree';
|
|
|
26
25
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
27
26
|
import { createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
28
27
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
29
|
-
import { GlobalVariableBuilder, SequencerClient, createValidatorForAcceptingTxs } from '@aztec/sequencer-client';
|
|
28
|
+
import { GlobalVariableBuilder, SequencerClient, createSlasherClient, createValidatorForAcceptingTxs } from '@aztec/sequencer-client';
|
|
30
29
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
31
|
-
import { EpochPruneWatcher, SlasherClient } from '@aztec/slasher';
|
|
32
30
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
33
31
|
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
34
32
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
@@ -127,8 +125,6 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
127
125
|
...config.l1Contracts,
|
|
128
126
|
...l1ContractsAddresses
|
|
129
127
|
};
|
|
130
|
-
const l1Client = createExtendedL1Client(config.l1RpcUrls, config.publisherPrivateKey, ethereumChain.chainInfo);
|
|
131
|
-
const l1TxUtils = new L1TxUtilsWithBlobs(l1Client, log, config);
|
|
132
128
|
const rollup = getContract({
|
|
133
129
|
address: l1ContractsAddresses.rollupAddress.toString(),
|
|
134
130
|
abi: RollupAbi,
|
|
@@ -159,15 +155,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
159
155
|
await worldStateSynchronizer.start();
|
|
160
156
|
// Start p2p. Note that it depends on world state to be running.
|
|
161
157
|
await p2pClient.start();
|
|
162
|
-
const
|
|
163
|
-
|
|
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();
|
|
158
|
+
const slasherClient = createSlasherClient(config, archiver, telemetry);
|
|
159
|
+
slasherClient.start();
|
|
171
160
|
const validatorClient = createValidatorClient(config, {
|
|
172
161
|
p2pClient,
|
|
173
162
|
telemetry,
|
|
@@ -175,14 +164,12 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
175
164
|
epochCache,
|
|
176
165
|
blockSource: archiver
|
|
177
166
|
});
|
|
167
|
+
const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
168
|
+
await validatorsSentinel?.start();
|
|
178
169
|
log.verbose(`All Aztec Node subsystems synced`);
|
|
179
170
|
// now create the sequencer
|
|
180
171
|
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
|
|
183
172
|
...deps,
|
|
184
|
-
epochCache,
|
|
185
|
-
l1TxUtils,
|
|
186
173
|
validatorClient,
|
|
187
174
|
p2pClient,
|
|
188
175
|
worldStateSynchronizer,
|
|
@@ -378,7 +365,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
378
365
|
*/ async stop() {
|
|
379
366
|
this.log.info(`Stopping`);
|
|
380
367
|
await this.txQueue.end();
|
|
381
|
-
|
|
368
|
+
await this.validatorsSentinel?.stop();
|
|
382
369
|
await this.sequencer?.stop();
|
|
383
370
|
await this.p2pClient.stop();
|
|
384
371
|
await this.worldStateSynchronizer.stop();
|
|
@@ -1,9 +1,8 @@
|
|
|
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';
|
|
5
4
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
6
5
|
import type { SentinelConfig } from './config.js';
|
|
7
6
|
import { Sentinel } from './sentinel.js';
|
|
8
|
-
export declare function createSentinel(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, config: SentinelConfig & DataStoreConfig
|
|
7
|
+
export declare function createSentinel(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, config: SentinelConfig & DataStoreConfig, logger?: import("@aztec/foundation/log").Logger): Promise<Sentinel | undefined>;
|
|
9
8
|
//# 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,
|
|
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"}
|
package/dest/sentinel/factory.js
CHANGED
|
@@ -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,
|
|
14
|
+
return new Sentinel(epochCache, archiver, p2p, sentinelStore, logger);
|
|
15
15
|
}
|
|
@@ -3,18 +3,14 @@ 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';
|
|
8
6
|
import { type L2BlockSource, L2BlockStream, type L2BlockStreamEvent, type L2BlockStreamEventHandler } from '@aztec/stdlib/block';
|
|
9
|
-
import type { ValidatorStats, ValidatorStatusHistory, ValidatorStatusInSlot, ValidatorStatusType,
|
|
7
|
+
import type { ValidatorStats, ValidatorStatusHistory, ValidatorStatusInSlot, ValidatorStatusType, ValidatorsStats } from '@aztec/stdlib/validators';
|
|
10
8
|
import { SentinelStore } from './store.js';
|
|
11
|
-
declare
|
|
12
|
-
export declare class Sentinel extends Sentinel_base implements L2BlockStreamEventHandler, Watcher {
|
|
9
|
+
export declare class Sentinel implements L2BlockStreamEventHandler {
|
|
13
10
|
protected epochCache: EpochCache;
|
|
14
11
|
protected archiver: L2BlockSource;
|
|
15
12
|
protected p2p: P2PClient;
|
|
16
13
|
protected store: SentinelStore;
|
|
17
|
-
protected config: Pick<SlasherConfig, 'slashInactivityCreateTargetPercentage' | 'slashInactivityCreatePenalty' | 'slashInactivitySignalTargetPercentage' | 'slashPayloadTtlSeconds'>;
|
|
18
14
|
protected logger: import("@aztec/foundation/log").Logger;
|
|
19
15
|
protected runningPromise: RunningPromise;
|
|
20
16
|
protected blockStream: L2BlockStream;
|
|
@@ -26,17 +22,12 @@ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEven
|
|
|
26
22
|
archive: string;
|
|
27
23
|
attestors: EthAddress[];
|
|
28
24
|
}>;
|
|
29
|
-
constructor(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, store: SentinelStore,
|
|
25
|
+
constructor(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, store: SentinelStore, logger?: import("@aztec/foundation/log").Logger);
|
|
30
26
|
start(): Promise<void>;
|
|
31
27
|
/** Loads initial slot and initializes blockstream. We will not process anything at or before the initial slot. */
|
|
32
28
|
protected init(): Promise<void>;
|
|
33
29
|
stop(): Promise<void>;
|
|
34
30
|
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>;
|
|
40
31
|
/**
|
|
41
32
|
* Process data for two L2 slots ago.
|
|
42
33
|
* Note that we do not process historical data, since we rely on p2p data for processing,
|
|
@@ -61,11 +52,8 @@ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEven
|
|
|
61
52
|
/** Push the status for each slot for each validator. */
|
|
62
53
|
protected updateValidators(slot: bigint, stats: Record<`0x${string}`, ValidatorStatusInSlot | undefined>): Promise<void>;
|
|
63
54
|
/** Computes stats to be returned based on stored data. */
|
|
64
|
-
computeStats(
|
|
65
|
-
|
|
66
|
-
toSlot?: bigint;
|
|
67
|
-
}): Promise<ValidatorsStats>;
|
|
68
|
-
protected computeStatsForValidator(address: `0x${string}`, allHistory: ValidatorStatusHistory, fromSlot?: bigint, toSlot?: bigint): ValidatorStats;
|
|
55
|
+
computeStats(): Promise<ValidatorsStats>;
|
|
56
|
+
protected computeStatsForValidator(address: `0x${string}`, allHistory: ValidatorStatusHistory, fromSlot?: bigint): ValidatorStats;
|
|
69
57
|
protected computeMissed(history: ValidatorStatusHistory, computeOverPrefix: ValidatorStatusType, filter: ValidatorStatusInSlot): {
|
|
70
58
|
currentStreak: number;
|
|
71
59
|
rate: number | undefined;
|
|
@@ -77,5 +65,4 @@ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEven
|
|
|
77
65
|
date: string;
|
|
78
66
|
} | undefined;
|
|
79
67
|
}
|
|
80
|
-
export {};
|
|
81
68
|
//# 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,
|
|
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"}
|
|
@@ -3,16 +3,13 @@ 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';
|
|
7
6
|
import { L2BlockStream, getAttestationsFromPublishedL2Block } from '@aztec/stdlib/block';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
export class Sentinel extends EventEmitter {
|
|
7
|
+
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
8
|
+
export class Sentinel {
|
|
11
9
|
epochCache;
|
|
12
10
|
archiver;
|
|
13
11
|
p2p;
|
|
14
12
|
store;
|
|
15
|
-
config;
|
|
16
13
|
logger;
|
|
17
14
|
runningPromise;
|
|
18
15
|
blockStream;
|
|
@@ -20,8 +17,13 @@ export class Sentinel extends EventEmitter {
|
|
|
20
17
|
initialSlot;
|
|
21
18
|
lastProcessedSlot;
|
|
22
19
|
slotNumberToBlock;
|
|
23
|
-
constructor(epochCache, archiver, p2p, store,
|
|
24
|
-
|
|
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();
|
|
25
27
|
this.l2TipsStore = new L2TipsMemoryStore();
|
|
26
28
|
const interval = epochCache.getL1Constants().ethereumSlotDuration * 1000 / 4;
|
|
27
29
|
this.runningPromise = new RunningPromise(this.work.bind(this), logger, interval);
|
|
@@ -60,95 +62,8 @@ export class Sentinel extends EventEmitter {
|
|
|
60
62
|
this.slotNumberToBlock.delete(key);
|
|
61
63
|
}
|
|
62
64
|
}
|
|
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
|
-
}
|
|
152
67
|
/**
|
|
153
68
|
* Process data for two L2 slots ago.
|
|
154
69
|
* Note that we do not process historical data, since we rely on p2p data for processing,
|
|
@@ -288,15 +203,14 @@ export class Sentinel extends EventEmitter {
|
|
|
288
203
|
/** Push the status for each slot for each validator. */ updateValidators(slot, stats) {
|
|
289
204
|
return this.store.updateValidators(slot, stats);
|
|
290
205
|
}
|
|
291
|
-
/** Computes stats to be returned based on stored data. */ async computeStats(
|
|
206
|
+
/** Computes stats to be returned based on stored data. */ async computeStats() {
|
|
292
207
|
const histories = await this.store.getHistories();
|
|
293
208
|
const slotNow = this.epochCache.getEpochAndSlotNow().slot;
|
|
294
|
-
const fromSlot =
|
|
295
|
-
const toSlot = _toSlot ?? this.lastProcessedSlot ?? slotNow;
|
|
209
|
+
const fromSlot = (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
|
|
296
210
|
const result = {};
|
|
297
211
|
for (const [address, history] of Object.entries(histories)){
|
|
298
212
|
const validatorAddress = address;
|
|
299
|
-
result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot
|
|
213
|
+
result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot);
|
|
300
214
|
}
|
|
301
215
|
return {
|
|
302
216
|
stats: result,
|
|
@@ -305,9 +219,8 @@ export class Sentinel extends EventEmitter {
|
|
|
305
219
|
slotWindow: this.store.getHistoryLength()
|
|
306
220
|
};
|
|
307
221
|
}
|
|
308
|
-
computeStatsForValidator(address, allHistory, fromSlot
|
|
309
|
-
|
|
310
|
-
history = toSlot ? history.filter((h)=>h.slot <= toSlot) : history;
|
|
222
|
+
computeStatsForValidator(address, allHistory, fromSlot) {
|
|
223
|
+
const history = fromSlot ? allHistory.filter((h)=>h.slot >= fromSlot) : allHistory;
|
|
311
224
|
return {
|
|
312
225
|
address: EthAddress.fromString(address),
|
|
313
226
|
lastProposal: this.computeFromSlot(history.filter((h)=>h.status === 'block-proposed' || h.status === 'block-mined').at(-1)?.slot),
|
package/dest/sentinel/store.d.ts
CHANGED
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
2
|
-
import type { ValidatorStatusHistory, ValidatorStatusInSlot
|
|
2
|
+
import type { ValidatorStatusHistory, ValidatorStatusInSlot } from '@aztec/stdlib/validators';
|
|
3
3
|
export declare class SentinelStore {
|
|
4
4
|
private store;
|
|
5
5
|
private config;
|
|
6
|
-
static readonly SCHEMA_VERSION =
|
|
7
|
-
private readonly
|
|
8
|
-
private readonly provenMap;
|
|
6
|
+
static readonly SCHEMA_VERSION = 1;
|
|
7
|
+
private readonly map;
|
|
9
8
|
constructor(store: AztecAsyncKVStore, config: {
|
|
10
9
|
historyLength: number;
|
|
11
10
|
});
|
|
12
11
|
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;
|
|
20
12
|
updateValidators(slot: bigint, statuses: Record<`0x${string}`, ValidatorStatusInSlot | undefined>): Promise<void>;
|
|
21
13
|
private pushValidatorStatusForSlot;
|
|
22
14
|
getHistories(): Promise<Record<`0x${string}`, ValidatorStatusHistory>>;
|
|
23
15
|
private getHistory;
|
|
24
|
-
private serializePerformance;
|
|
25
|
-
private deserializePerformance;
|
|
26
16
|
private serializeHistory;
|
|
27
17
|
private deserializeHistory;
|
|
28
18
|
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,
|
|
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"}
|
package/dest/sentinel/store.js
CHANGED
|
@@ -1,65 +1,17 @@
|
|
|
1
1
|
import { BufferReader, numToUInt8, numToUInt32BE, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
2
|
-
import { isAddress } from 'viem';
|
|
3
2
|
export class SentinelStore {
|
|
4
3
|
store;
|
|
5
4
|
config;
|
|
6
|
-
static SCHEMA_VERSION =
|
|
7
|
-
|
|
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;
|
|
5
|
+
static SCHEMA_VERSION = 1;
|
|
6
|
+
map;
|
|
12
7
|
constructor(store, config){
|
|
13
8
|
this.store = store;
|
|
14
9
|
this.config = config;
|
|
15
|
-
this.
|
|
16
|
-
this.provenMap = store.openMap('sentinel-validator-proven');
|
|
10
|
+
this.map = store.openMap('sentinel-validator-status');
|
|
17
11
|
}
|
|
18
12
|
getHistoryLength() {
|
|
19
13
|
return this.config.historyLength;
|
|
20
14
|
}
|
|
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
|
-
}
|
|
63
15
|
async updateValidators(slot, statuses) {
|
|
64
16
|
await this.store.transactionAsync(async ()=>{
|
|
65
17
|
for (const [who, status] of Object.entries(statuses)){
|
|
@@ -78,38 +30,19 @@ export class SentinelStore {
|
|
|
78
30
|
status
|
|
79
31
|
}
|
|
80
32
|
].slice(-this.config.historyLength);
|
|
81
|
-
await this.
|
|
33
|
+
await this.map.set(who, this.serializeHistory(newHistory));
|
|
82
34
|
}
|
|
83
35
|
async getHistories() {
|
|
84
36
|
const histories = {};
|
|
85
|
-
for await (const [address, history] of this.
|
|
37
|
+
for await (const [address, history] of this.map.entriesAsync()){
|
|
86
38
|
histories[address] = this.deserializeHistory(history);
|
|
87
39
|
}
|
|
88
40
|
return histories;
|
|
89
41
|
}
|
|
90
42
|
async getHistory(address) {
|
|
91
|
-
const data = await this.
|
|
43
|
+
const data = await this.map.getAsync(address);
|
|
92
44
|
return data && this.deserializeHistory(data);
|
|
93
45
|
}
|
|
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
|
-
}
|
|
113
46
|
serializeHistory(history) {
|
|
114
47
|
return serializeToBuffer(history.map((h)=>[
|
|
115
48
|
numToUInt32BE(Number(h.slot)),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/aztec-node",
|
|
3
|
-
"version": "0.87.
|
|
3
|
+
"version": "0.87.4",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -61,28 +61,27 @@
|
|
|
61
61
|
]
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@aztec/archiver": "0.87.
|
|
65
|
-
"@aztec/bb-prover": "0.87.
|
|
66
|
-
"@aztec/blob-sink": "0.87.
|
|
67
|
-
"@aztec/constants": "0.87.
|
|
68
|
-
"@aztec/epoch-cache": "0.87.
|
|
69
|
-
"@aztec/ethereum": "0.87.
|
|
70
|
-
"@aztec/foundation": "0.87.
|
|
71
|
-
"@aztec/kv-store": "0.87.
|
|
72
|
-
"@aztec/l1-artifacts": "0.87.
|
|
73
|
-
"@aztec/merkle-tree": "0.87.
|
|
74
|
-
"@aztec/node-lib": "0.87.
|
|
75
|
-
"@aztec/noir-protocol-circuits-types": "0.87.
|
|
76
|
-
"@aztec/p2p": "0.87.
|
|
77
|
-
"@aztec/protocol-contracts": "0.87.
|
|
78
|
-
"@aztec/prover-client": "0.87.
|
|
79
|
-
"@aztec/sequencer-client": "0.87.
|
|
80
|
-
"@aztec/simulator": "0.87.
|
|
81
|
-
"@aztec/
|
|
82
|
-
"@aztec/
|
|
83
|
-
"@aztec/
|
|
84
|
-
"@aztec/
|
|
85
|
-
"@aztec/world-state": "0.87.3-nightly.20250529",
|
|
64
|
+
"@aztec/archiver": "0.87.4",
|
|
65
|
+
"@aztec/bb-prover": "0.87.4",
|
|
66
|
+
"@aztec/blob-sink": "0.87.4",
|
|
67
|
+
"@aztec/constants": "0.87.4",
|
|
68
|
+
"@aztec/epoch-cache": "0.87.4",
|
|
69
|
+
"@aztec/ethereum": "0.87.4",
|
|
70
|
+
"@aztec/foundation": "0.87.4",
|
|
71
|
+
"@aztec/kv-store": "0.87.4",
|
|
72
|
+
"@aztec/l1-artifacts": "0.87.4",
|
|
73
|
+
"@aztec/merkle-tree": "0.87.4",
|
|
74
|
+
"@aztec/node-lib": "0.87.4",
|
|
75
|
+
"@aztec/noir-protocol-circuits-types": "0.87.4",
|
|
76
|
+
"@aztec/p2p": "0.87.4",
|
|
77
|
+
"@aztec/protocol-contracts": "0.87.4",
|
|
78
|
+
"@aztec/prover-client": "0.87.4",
|
|
79
|
+
"@aztec/sequencer-client": "0.87.4",
|
|
80
|
+
"@aztec/simulator": "0.87.4",
|
|
81
|
+
"@aztec/stdlib": "0.87.4",
|
|
82
|
+
"@aztec/telemetry-client": "0.87.4",
|
|
83
|
+
"@aztec/validator-client": "0.87.4",
|
|
84
|
+
"@aztec/world-state": "0.87.4",
|
|
86
85
|
"koa": "^2.16.1",
|
|
87
86
|
"koa-router": "^12.0.0",
|
|
88
87
|
"tslib": "^2.4.0",
|
package/src/aztec-node/config.ts
CHANGED
|
@@ -11,7 +11,6 @@ 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';
|
|
15
14
|
import { type NodeRPCConfig, nodeRpcConfigMappings } from '@aztec/stdlib/config';
|
|
16
15
|
import { type ValidatorClientConfig, validatorClientConfigMappings } from '@aztec/validator-client/config';
|
|
17
16
|
import { type WorldStateConfig, worldStateConfigMappings } from '@aztec/world-state/config';
|
|
@@ -34,8 +33,7 @@ export type AztecNodeConfig = ArchiverConfig &
|
|
|
34
33
|
SentinelConfig &
|
|
35
34
|
SharedNodeConfig &
|
|
36
35
|
GenesisStateConfig &
|
|
37
|
-
NodeRPCConfig &
|
|
38
|
-
SlasherConfig & {
|
|
36
|
+
NodeRPCConfig & {
|
|
39
37
|
/** L1 contracts addresses */
|
|
40
38
|
l1Contracts: L1ContractAddresses;
|
|
41
39
|
/** Whether the validator is disabled for this node */
|
|
@@ -54,7 +52,6 @@ export const aztecNodeConfigMappings: ConfigMappingsType<AztecNodeConfig> = {
|
|
|
54
52
|
...sharedNodeConfigMappings,
|
|
55
53
|
...genesisStateConfigMappings,
|
|
56
54
|
...nodeRpcConfigMappings,
|
|
57
|
-
...slasherConfigMappings,
|
|
58
55
|
l1Contracts: {
|
|
59
56
|
description: 'The deployed L1 contract addresses',
|
|
60
57
|
nested: l1ContractAddressesMapping,
|
package/src/aztec-node/server.ts
CHANGED
|
@@ -10,13 +10,7 @@ import {
|
|
|
10
10
|
type PUBLIC_DATA_TREE_HEIGHT,
|
|
11
11
|
} from '@aztec/constants';
|
|
12
12
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
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';
|
|
13
|
+
import { type L1ContractAddresses, RegistryContract, createEthereumChain } from '@aztec/ethereum';
|
|
20
14
|
import { compactArray } from '@aztec/foundation/collection';
|
|
21
15
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
22
16
|
import { Fr } from '@aztec/foundation/fields';
|
|
@@ -36,10 +30,10 @@ import {
|
|
|
36
30
|
GlobalVariableBuilder,
|
|
37
31
|
SequencerClient,
|
|
38
32
|
type SequencerPublisher,
|
|
33
|
+
createSlasherClient,
|
|
39
34
|
createValidatorForAcceptingTxs,
|
|
40
35
|
} from '@aztec/sequencer-client';
|
|
41
36
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
42
|
-
import { EpochPruneWatcher, SlasherClient, type Watcher } from '@aztec/slasher';
|
|
43
37
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
44
38
|
import type { InBlock, L2Block, L2BlockNumber, L2BlockSource, PublishedL2Block } from '@aztec/stdlib/block';
|
|
45
39
|
import type {
|
|
@@ -187,7 +181,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
187
181
|
|
|
188
182
|
const publicClient = createPublicClient({
|
|
189
183
|
chain: ethereumChain.chainInfo,
|
|
190
|
-
transport: fallback(config.l1RpcUrls.map(
|
|
184
|
+
transport: fallback(config.l1RpcUrls.map(url => http(url))),
|
|
191
185
|
pollingInterval: config.viemPollingIntervalMS,
|
|
192
186
|
});
|
|
193
187
|
|
|
@@ -200,9 +194,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
200
194
|
// Overwrite the passed in vars.
|
|
201
195
|
config.l1Contracts = { ...config.l1Contracts, ...l1ContractsAddresses };
|
|
202
196
|
|
|
203
|
-
const l1Client = createExtendedL1Client(config.l1RpcUrls, config.publisherPrivateKey, ethereumChain.chainInfo);
|
|
204
|
-
const l1TxUtils = new L1TxUtilsWithBlobs(l1Client, log, config);
|
|
205
|
-
|
|
206
197
|
const rollup = getContract({
|
|
207
198
|
address: l1ContractsAddresses.rollupAddress.toString(),
|
|
208
199
|
abi: RollupAbi,
|
|
@@ -256,17 +247,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
256
247
|
// Start p2p. Note that it depends on world state to be running.
|
|
257
248
|
await p2pClient.start();
|
|
258
249
|
|
|
259
|
-
const
|
|
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();
|
|
250
|
+
const slasherClient = createSlasherClient(config, archiver, telemetry);
|
|
251
|
+
slasherClient.start();
|
|
270
252
|
|
|
271
253
|
const validatorClient = createValidatorClient(config, {
|
|
272
254
|
p2pClient,
|
|
@@ -276,17 +258,16 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
276
258
|
blockSource: archiver,
|
|
277
259
|
});
|
|
278
260
|
|
|
261
|
+
const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
262
|
+
await validatorsSentinel?.start();
|
|
263
|
+
|
|
279
264
|
log.verbose(`All Aztec Node subsystems synced`);
|
|
280
265
|
|
|
281
266
|
// now create the sequencer
|
|
282
267
|
const sequencer = config.disableValidator
|
|
283
268
|
? undefined
|
|
284
269
|
: await SequencerClient.new(config, {
|
|
285
|
-
// if deps were provided, they should override the defaults,
|
|
286
|
-
// or things that we created in this function
|
|
287
270
|
...deps,
|
|
288
|
-
epochCache,
|
|
289
|
-
l1TxUtils,
|
|
290
271
|
validatorClient,
|
|
291
272
|
p2pClient,
|
|
292
273
|
worldStateSynchronizer,
|
|
@@ -547,7 +528,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
547
528
|
public async stop() {
|
|
548
529
|
this.log.info(`Stopping`);
|
|
549
530
|
await this.txQueue.end();
|
|
550
|
-
|
|
531
|
+
await this.validatorsSentinel?.stop();
|
|
551
532
|
await this.sequencer?.stop();
|
|
552
533
|
await this.p2pClient.stop();
|
|
553
534
|
await this.worldStateSynchronizer.stop();
|
package/src/sentinel/factory.ts
CHANGED
|
@@ -3,7 +3,6 @@ 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';
|
|
7
6
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
8
7
|
|
|
9
8
|
import type { SentinelConfig } from './config.js';
|
|
@@ -14,7 +13,7 @@ export async function createSentinel(
|
|
|
14
13
|
epochCache: EpochCache,
|
|
15
14
|
archiver: L2BlockSource,
|
|
16
15
|
p2p: P2PClient,
|
|
17
|
-
config: SentinelConfig & DataStoreConfig
|
|
16
|
+
config: SentinelConfig & DataStoreConfig,
|
|
18
17
|
logger = createLogger('node:sentinel'),
|
|
19
18
|
): Promise<Sentinel | undefined> {
|
|
20
19
|
if (!config.sentinelEnabled) {
|
|
@@ -28,5 +27,5 @@ export async function createSentinel(
|
|
|
28
27
|
);
|
|
29
28
|
const storeHistoryLength = config.sentinelHistoryLengthInEpochs * epochCache.getL1Constants().epochDuration;
|
|
30
29
|
const sentinelStore = new SentinelStore(kvStore, { historyLength: storeHistoryLength });
|
|
31
|
-
return new Sentinel(epochCache, archiver, p2p, sentinelStore,
|
|
30
|
+
return new Sentinel(epochCache, archiver, p2p, sentinelStore, logger);
|
|
32
31
|
}
|
package/src/sentinel/sentinel.ts
CHANGED
|
@@ -5,8 +5,6 @@ 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';
|
|
10
8
|
import {
|
|
11
9
|
type L2BlockSource,
|
|
12
10
|
L2BlockStream,
|
|
@@ -14,21 +12,18 @@ import {
|
|
|
14
12
|
type L2BlockStreamEventHandler,
|
|
15
13
|
getAttestationsFromPublishedL2Block,
|
|
16
14
|
} from '@aztec/stdlib/block';
|
|
17
|
-
import {
|
|
15
|
+
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
18
16
|
import type {
|
|
19
17
|
ValidatorStats,
|
|
20
18
|
ValidatorStatusHistory,
|
|
21
19
|
ValidatorStatusInSlot,
|
|
22
20
|
ValidatorStatusType,
|
|
23
|
-
ValidatorsEpochPerformance,
|
|
24
21
|
ValidatorsStats,
|
|
25
22
|
} from '@aztec/stdlib/validators';
|
|
26
23
|
|
|
27
|
-
import EventEmitter from 'node:events';
|
|
28
|
-
|
|
29
24
|
import { SentinelStore } from './store.js';
|
|
30
25
|
|
|
31
|
-
export class Sentinel
|
|
26
|
+
export class Sentinel implements L2BlockStreamEventHandler {
|
|
32
27
|
protected runningPromise: RunningPromise;
|
|
33
28
|
protected blockStream!: L2BlockStream;
|
|
34
29
|
protected l2TipsStore: L2TipsStore;
|
|
@@ -43,16 +38,8 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
|
|
|
43
38
|
protected archiver: L2BlockSource,
|
|
44
39
|
protected p2p: P2PClient,
|
|
45
40
|
protected store: SentinelStore,
|
|
46
|
-
protected config: Pick<
|
|
47
|
-
SlasherConfig,
|
|
48
|
-
| 'slashInactivityCreateTargetPercentage'
|
|
49
|
-
| 'slashInactivityCreatePenalty'
|
|
50
|
-
| 'slashInactivitySignalTargetPercentage'
|
|
51
|
-
| 'slashPayloadTtlSeconds'
|
|
52
|
-
>,
|
|
53
41
|
protected logger = createLogger('node:sentinel'),
|
|
54
42
|
) {
|
|
55
|
-
super();
|
|
56
43
|
this.l2TipsStore = new L2TipsMemoryStore();
|
|
57
44
|
const interval = (epochCache.getL1Constants().ethereumSlotDuration * 1000) / 4;
|
|
58
45
|
this.runningPromise = new RunningPromise(this.work.bind(this), logger, interval);
|
|
@@ -97,96 +84,7 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
|
|
|
97
84
|
this.slotNumberToBlock.delete(key);
|
|
98
85
|
}
|
|
99
86
|
}
|
|
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;
|
|
114
87
|
}
|
|
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
|
-
);
|
|
190
88
|
}
|
|
191
89
|
|
|
192
90
|
/**
|
|
@@ -334,18 +232,14 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
|
|
|
334
232
|
}
|
|
335
233
|
|
|
336
234
|
/** Computes stats to be returned based on stored data. */
|
|
337
|
-
public async computeStats({
|
|
338
|
-
fromSlot: _fromSlot,
|
|
339
|
-
toSlot: _toSlot,
|
|
340
|
-
}: { fromSlot?: bigint; toSlot?: bigint } = {}): Promise<ValidatorsStats> {
|
|
235
|
+
public async computeStats(): Promise<ValidatorsStats> {
|
|
341
236
|
const histories = await this.store.getHistories();
|
|
342
237
|
const slotNow = this.epochCache.getEpochAndSlotNow().slot;
|
|
343
|
-
const fromSlot =
|
|
344
|
-
const toSlot = _toSlot ?? this.lastProcessedSlot ?? slotNow;
|
|
238
|
+
const fromSlot = (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
|
|
345
239
|
const result: Record<`0x${string}`, ValidatorStats> = {};
|
|
346
240
|
for (const [address, history] of Object.entries(histories)) {
|
|
347
241
|
const validatorAddress = address as `0x${string}`;
|
|
348
|
-
result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot
|
|
242
|
+
result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot);
|
|
349
243
|
}
|
|
350
244
|
return {
|
|
351
245
|
stats: result,
|
|
@@ -359,10 +253,8 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
|
|
|
359
253
|
address: `0x${string}`,
|
|
360
254
|
allHistory: ValidatorStatusHistory,
|
|
361
255
|
fromSlot?: bigint,
|
|
362
|
-
toSlot?: bigint,
|
|
363
256
|
): ValidatorStats {
|
|
364
|
-
|
|
365
|
-
history = toSlot ? history.filter(h => h.slot <= toSlot) : history;
|
|
257
|
+
const history = fromSlot ? allHistory.filter(h => h.slot >= fromSlot) : allHistory;
|
|
366
258
|
return {
|
|
367
259
|
address: EthAddress.fromString(address),
|
|
368
260
|
lastProposal: this.computeFromSlot(
|
package/src/sentinel/store.ts
CHANGED
|
@@ -1,80 +1,23 @@
|
|
|
1
1
|
import { BufferReader, numToUInt8, numToUInt32BE, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
2
2
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
3
|
-
import type {
|
|
4
|
-
ValidatorStatusHistory,
|
|
5
|
-
ValidatorStatusInSlot,
|
|
6
|
-
ValidatorsEpochPerformance,
|
|
7
|
-
} from '@aztec/stdlib/validators';
|
|
8
|
-
|
|
9
|
-
import { isAddress } from 'viem';
|
|
3
|
+
import type { ValidatorStatusHistory, ValidatorStatusInSlot } from '@aztec/stdlib/validators';
|
|
10
4
|
|
|
11
5
|
export class SentinelStore {
|
|
12
|
-
public static readonly SCHEMA_VERSION =
|
|
13
|
-
|
|
14
|
-
// a map from validator address to their ValidatorStatusHistory
|
|
15
|
-
private readonly historyMap: AztecAsyncMap<`0x${string}`, Buffer>;
|
|
6
|
+
public static readonly SCHEMA_VERSION = 1;
|
|
16
7
|
|
|
17
|
-
|
|
18
|
-
// e.g. { validator: [{ epoch: 1, missed: 1, total: 10 }, { epoch: 2, missed: 3, total: 7 }, ...] }
|
|
19
|
-
private readonly provenMap: AztecAsyncMap<`0x${string}`, Buffer>;
|
|
8
|
+
private readonly map: AztecAsyncMap<`0x${string}`, Buffer>;
|
|
20
9
|
|
|
21
10
|
constructor(
|
|
22
11
|
private store: AztecAsyncKVStore,
|
|
23
12
|
private config: { historyLength: number },
|
|
24
13
|
) {
|
|
25
|
-
this.
|
|
26
|
-
this.provenMap = store.openMap('sentinel-validator-proven');
|
|
14
|
+
this.map = store.openMap('sentinel-validator-status');
|
|
27
15
|
}
|
|
28
16
|
|
|
29
17
|
public getHistoryLength() {
|
|
30
18
|
return this.config.historyLength;
|
|
31
19
|
}
|
|
32
20
|
|
|
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
|
-
|
|
78
21
|
public async updateValidators(slot: bigint, statuses: Record<`0x${string}`, ValidatorStatusInSlot | undefined>) {
|
|
79
22
|
await this.store.transactionAsync(async () => {
|
|
80
23
|
for (const [who, status] of Object.entries(statuses)) {
|
|
@@ -92,41 +35,22 @@ export class SentinelStore {
|
|
|
92
35
|
) {
|
|
93
36
|
const currentHistory = (await this.getHistory(who)) ?? [];
|
|
94
37
|
const newHistory = [...currentHistory, { slot, status }].slice(-this.config.historyLength);
|
|
95
|
-
await this.
|
|
38
|
+
await this.map.set(who, this.serializeHistory(newHistory));
|
|
96
39
|
}
|
|
97
40
|
|
|
98
41
|
public async getHistories(): Promise<Record<`0x${string}`, ValidatorStatusHistory>> {
|
|
99
42
|
const histories: Record<`0x${string}`, ValidatorStatusHistory> = {};
|
|
100
|
-
for await (const [address, history] of this.
|
|
43
|
+
for await (const [address, history] of this.map.entriesAsync()) {
|
|
101
44
|
histories[address] = this.deserializeHistory(history);
|
|
102
45
|
}
|
|
103
46
|
return histories;
|
|
104
47
|
}
|
|
105
48
|
|
|
106
49
|
private async getHistory(address: `0x${string}`): Promise<ValidatorStatusHistory | undefined> {
|
|
107
|
-
const data = await this.
|
|
50
|
+
const data = await this.map.getAsync(address);
|
|
108
51
|
return data && this.deserializeHistory(data);
|
|
109
52
|
}
|
|
110
53
|
|
|
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
|
-
|
|
130
54
|
private serializeHistory(history: ValidatorStatusHistory): Buffer {
|
|
131
55
|
return serializeToBuffer(
|
|
132
56
|
history.map(h => [numToUInt32BE(Number(h.slot)), numToUInt8(this.statusToNumber(h.status))]),
|