@lodestar/validator 1.35.0-dev.fcf8d024ea → 1.35.0-dev.feed916580

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.
Files changed (131) hide show
  1. package/lib/metrics.js +14 -14
  2. package/lib/metrics.js.map +1 -1
  3. package/lib/services/attestation.js +27 -35
  4. package/lib/services/attestation.js.map +1 -1
  5. package/lib/services/attestationDuties.js +0 -1
  6. package/lib/services/attestationDuties.js.map +1 -1
  7. package/lib/services/blockDuties.d.ts +2 -2
  8. package/lib/services/blockDuties.js +3 -4
  9. package/lib/services/blockDuties.js.map +1 -1
  10. package/lib/services/syncCommittee.js +22 -30
  11. package/lib/services/syncCommittee.js.map +1 -1
  12. package/lib/util/clock.d.ts +0 -3
  13. package/lib/util/clock.js +0 -4
  14. package/lib/util/clock.js.map +1 -1
  15. package/lib/util/params.js +1 -17
  16. package/lib/util/params.js.map +1 -1
  17. package/package.json +16 -19
  18. package/lib/buckets.d.ts.map +0 -1
  19. package/lib/defaults.d.ts.map +0 -1
  20. package/lib/genesis.d.ts.map +0 -1
  21. package/lib/index.d.ts.map +0 -1
  22. package/lib/metrics.d.ts.map +0 -1
  23. package/lib/repositories/index.d.ts.map +0 -1
  24. package/lib/repositories/metaDataRepository.d.ts.map +0 -1
  25. package/lib/services/attestation.d.ts.map +0 -1
  26. package/lib/services/attestationDuties.d.ts.map +0 -1
  27. package/lib/services/block.d.ts.map +0 -1
  28. package/lib/services/blockDuties.d.ts.map +0 -1
  29. package/lib/services/chainHeaderTracker.d.ts.map +0 -1
  30. package/lib/services/doppelgangerService.d.ts.map +0 -1
  31. package/lib/services/emitter.d.ts.map +0 -1
  32. package/lib/services/externalSignerSync.d.ts.map +0 -1
  33. package/lib/services/indices.d.ts.map +0 -1
  34. package/lib/services/prepareBeaconProposer.d.ts.map +0 -1
  35. package/lib/services/syncCommittee.d.ts.map +0 -1
  36. package/lib/services/syncCommitteeDuties.d.ts.map +0 -1
  37. package/lib/services/syncingStatusTracker.d.ts.map +0 -1
  38. package/lib/services/utils.d.ts.map +0 -1
  39. package/lib/services/validatorStore.d.ts.map +0 -1
  40. package/lib/slashingProtection/attestation/attestationByTargetRepository.d.ts.map +0 -1
  41. package/lib/slashingProtection/attestation/attestationLowerBoundRepository.d.ts.map +0 -1
  42. package/lib/slashingProtection/attestation/errors.d.ts.map +0 -1
  43. package/lib/slashingProtection/attestation/index.d.ts.map +0 -1
  44. package/lib/slashingProtection/block/blockBySlotRepository.d.ts.map +0 -1
  45. package/lib/slashingProtection/block/errors.d.ts.map +0 -1
  46. package/lib/slashingProtection/block/index.d.ts.map +0 -1
  47. package/lib/slashingProtection/index.d.ts.map +0 -1
  48. package/lib/slashingProtection/interchange/errors.d.ts.map +0 -1
  49. package/lib/slashingProtection/interchange/formats/completeV4.d.ts.map +0 -1
  50. package/lib/slashingProtection/interchange/formats/index.d.ts.map +0 -1
  51. package/lib/slashingProtection/interchange/formats/v5.d.ts.map +0 -1
  52. package/lib/slashingProtection/interchange/index.d.ts.map +0 -1
  53. package/lib/slashingProtection/interchange/parseInterchange.d.ts.map +0 -1
  54. package/lib/slashingProtection/interchange/serializeInterchange.d.ts.map +0 -1
  55. package/lib/slashingProtection/interchange/types.d.ts.map +0 -1
  56. package/lib/slashingProtection/interface.d.ts.map +0 -1
  57. package/lib/slashingProtection/minMaxSurround/distanceStoreRepository.d.ts.map +0 -1
  58. package/lib/slashingProtection/minMaxSurround/errors.d.ts.map +0 -1
  59. package/lib/slashingProtection/minMaxSurround/index.d.ts.map +0 -1
  60. package/lib/slashingProtection/minMaxSurround/interface.d.ts.map +0 -1
  61. package/lib/slashingProtection/minMaxSurround/minMaxSurround.d.ts.map +0 -1
  62. package/lib/slashingProtection/types.d.ts.map +0 -1
  63. package/lib/slashingProtection/utils.d.ts.map +0 -1
  64. package/lib/types.d.ts.map +0 -1
  65. package/lib/util/batch.d.ts.map +0 -1
  66. package/lib/util/clock.d.ts.map +0 -1
  67. package/lib/util/difference.d.ts.map +0 -1
  68. package/lib/util/externalSignerClient.d.ts.map +0 -1
  69. package/lib/util/format.d.ts.map +0 -1
  70. package/lib/util/index.d.ts.map +0 -1
  71. package/lib/util/logger.d.ts.map +0 -1
  72. package/lib/util/params.d.ts.map +0 -1
  73. package/lib/util/url.d.ts.map +0 -1
  74. package/lib/validator.d.ts.map +0 -1
  75. package/src/buckets.ts +0 -30
  76. package/src/defaults.ts +0 -8
  77. package/src/genesis.ts +0 -19
  78. package/src/index.ts +0 -22
  79. package/src/metrics.ts +0 -417
  80. package/src/repositories/index.ts +0 -1
  81. package/src/repositories/metaDataRepository.ts +0 -42
  82. package/src/services/attestation.ts +0 -362
  83. package/src/services/attestationDuties.ts +0 -406
  84. package/src/services/block.ts +0 -261
  85. package/src/services/blockDuties.ts +0 -217
  86. package/src/services/chainHeaderTracker.ts +0 -89
  87. package/src/services/doppelgangerService.ts +0 -286
  88. package/src/services/emitter.ts +0 -43
  89. package/src/services/externalSignerSync.ts +0 -81
  90. package/src/services/indices.ts +0 -165
  91. package/src/services/prepareBeaconProposer.ts +0 -119
  92. package/src/services/syncCommittee.ts +0 -338
  93. package/src/services/syncCommitteeDuties.ts +0 -337
  94. package/src/services/syncingStatusTracker.ts +0 -74
  95. package/src/services/utils.ts +0 -58
  96. package/src/services/validatorStore.ts +0 -830
  97. package/src/slashingProtection/attestation/attestationByTargetRepository.ts +0 -77
  98. package/src/slashingProtection/attestation/attestationLowerBoundRepository.ts +0 -44
  99. package/src/slashingProtection/attestation/errors.ts +0 -66
  100. package/src/slashingProtection/attestation/index.ts +0 -171
  101. package/src/slashingProtection/block/blockBySlotRepository.ts +0 -78
  102. package/src/slashingProtection/block/errors.ts +0 -28
  103. package/src/slashingProtection/block/index.ts +0 -94
  104. package/src/slashingProtection/index.ts +0 -95
  105. package/src/slashingProtection/interchange/errors.ts +0 -15
  106. package/src/slashingProtection/interchange/formats/completeV4.ts +0 -125
  107. package/src/slashingProtection/interchange/formats/index.ts +0 -7
  108. package/src/slashingProtection/interchange/formats/v5.ts +0 -120
  109. package/src/slashingProtection/interchange/index.ts +0 -5
  110. package/src/slashingProtection/interchange/parseInterchange.ts +0 -55
  111. package/src/slashingProtection/interchange/serializeInterchange.ts +0 -35
  112. package/src/slashingProtection/interchange/types.ts +0 -18
  113. package/src/slashingProtection/interface.ts +0 -28
  114. package/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts +0 -57
  115. package/src/slashingProtection/minMaxSurround/errors.ts +0 -27
  116. package/src/slashingProtection/minMaxSurround/index.ts +0 -4
  117. package/src/slashingProtection/minMaxSurround/interface.ts +0 -23
  118. package/src/slashingProtection/minMaxSurround/minMaxSurround.ts +0 -104
  119. package/src/slashingProtection/types.ts +0 -12
  120. package/src/slashingProtection/utils.ts +0 -42
  121. package/src/types.ts +0 -31
  122. package/src/util/batch.ts +0 -15
  123. package/src/util/clock.ts +0 -170
  124. package/src/util/difference.ts +0 -10
  125. package/src/util/externalSignerClient.ts +0 -277
  126. package/src/util/format.ts +0 -3
  127. package/src/util/index.ts +0 -6
  128. package/src/util/logger.ts +0 -51
  129. package/src/util/params.ts +0 -320
  130. package/src/util/url.ts +0 -16
  131. package/src/validator.ts +0 -418
@@ -1,125 +0,0 @@
1
- import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
2
- import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js";
3
- import {InterchangeLodestar} from "../types.js";
4
-
5
- /**
6
- * A complete record of all blocks and attestations signed by a set of validators
7
- * Spec from: https://hackmd.io/@sproul/Bk0Y0qdGD
8
- */
9
- export type InterchangeCompleteV4 = {
10
- metadata: {
11
- interchange_format: "complete";
12
- interchange_format_version: "4";
13
- /**
14
- * ```
15
- * "0x04700007fabc8282644aed6d1c7c9e21d38a03a0c4ba193f3afe428824b3a673"
16
- * ```
17
- */
18
- genesis_validators_root: string;
19
- };
20
- data: {
21
- /**
22
- * pubkey: BLSPubkey is the BLS public key of the validator encoded as 0x-prefixed hex
23
- * ```
24
- * "0xb845089a1457f811bfc000588fbb4e713669be8ce060ea6be3c6ece09afc3794106c91ca73acda5e5457122d58723bed"
25
- * ```
26
- */
27
- pubkey: string;
28
- /**
29
- * signed_blocks is a list of objects with fields
30
- */
31
- signed_blocks: {
32
- /**
33
- * slot: Slot, the slot of the block that was signed
34
- * ```
35
- * "81952"
36
- * ```
37
- */
38
- slot: string;
39
- /**
40
- * signing_root: Root (optional) is compute_signing_root(block, domain), where:
41
- * - block is the block that was signed as type BeaconBlock or equivalently BeaconBlockHeader
42
- * - domain is equal to compute_domain(DOMAIN_BEACON_PROPOSER, fork, metadata.genesis_validators_root), where:
43
- * - metadata.genesis_validators_root is the genesis_validators_root from this interchange file
44
- * - fork: Version is the fork that the block was signed against
45
- * ```
46
- * "0x4ff6f743a43f3b4f95350831aeaf0a122a1a392922c45d804280284a69eb850b"
47
- * ```
48
- */
49
- signing_root?: string;
50
- }[];
51
- /**
52
- * signed_attestations is a list of objects with fields
53
- */
54
- signed_attestations: {
55
- /**
56
- * source_epoch: Epoch, the attestation.data.source.epoch of the signed attestation
57
- * ```
58
- * "2290"
59
- * ```
60
- */
61
- source_epoch: string;
62
- /**
63
- * target_epoch: Epoch, the attestation.data.target.epoch of the signed attestation
64
- * ```
65
- * "3007"
66
- * ```
67
- */
68
- target_epoch: string;
69
- /**
70
- * signing_root: Root (optional) is compute_signing_root(attestation, domain), where:
71
- * - attestation is the attestation that was signed as type AttestationData
72
- * - domain is equal to compute_domain(DOMAIN_BEACON_ATTESTER, fork, metadata.genesis_validators_root), where:
73
- * - metadata.genesis_validators_root is the genesis_validators_root from this interchange file
74
- * - fork: Version is the fork that the attestation was signed against
75
- * ```
76
- * "0x587d6a4f59a58fe24f406e0502413e77fe1babddee641fda30034ed37ecc884d"
77
- * ```
78
- */
79
- signing_root?: string;
80
- }[];
81
- }[];
82
- };
83
-
84
- export function serializeInterchangeCompleteV4({
85
- data,
86
- genesisValidatorsRoot,
87
- }: InterchangeLodestar): InterchangeCompleteV4 {
88
- return {
89
- metadata: {
90
- interchange_format: "complete",
91
- interchange_format_version: "4",
92
- genesis_validators_root: toRootHex(genesisValidatorsRoot),
93
- },
94
- data: data.map((validator) => ({
95
- pubkey: toPubkeyHex(validator.pubkey),
96
- signed_blocks: validator.signedBlocks.map((block) => ({
97
- slot: numToString(block.slot),
98
- signing_root: toOptionalHexString(block.signingRoot),
99
- })),
100
- signed_attestations: validator.signedAttestations.map((att) => ({
101
- source_epoch: numToString(att.sourceEpoch),
102
- target_epoch: numToString(att.targetEpoch),
103
- signing_root: toOptionalHexString(att.signingRoot),
104
- })),
105
- })),
106
- };
107
- }
108
-
109
- export function parseInterchangeCompleteV4(interchange: InterchangeCompleteV4): InterchangeLodestar {
110
- return {
111
- genesisValidatorsRoot: fromHex(interchange.metadata.genesis_validators_root),
112
- data: interchange.data.map((validator) => ({
113
- pubkey: fromHex(validator.pubkey),
114
- signedBlocks: validator.signed_blocks.map((block) => ({
115
- slot: parseInt(block.slot, 10),
116
- signingRoot: fromOptionalHexString(block.signing_root),
117
- })),
118
- signedAttestations: validator.signed_attestations.map((att) => ({
119
- sourceEpoch: parseInt(att.source_epoch, 10),
120
- targetEpoch: parseInt(att.target_epoch, 10),
121
- signingRoot: fromOptionalHexString(att.signing_root),
122
- })),
123
- })),
124
- };
125
- }
@@ -1,7 +0,0 @@
1
- import {InterchangeCompleteV4} from "./completeV4.js";
2
- import {InterchangeV5} from "./v5.js";
3
-
4
- export type InterchangeFormat = {
5
- v4: InterchangeCompleteV4;
6
- v5: InterchangeV5;
7
- };
@@ -1,120 +0,0 @@
1
- import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
2
- import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js";
3
- import {InterchangeLodestar} from "../types.js";
4
-
5
- /**
6
- * A complete record of all blocks and attestations signed by a set of validators
7
- * Spec from: https://eips.ethereum.org/EIPS/eip-3076
8
- */
9
- export type InterchangeV5 = {
10
- metadata: {
11
- interchange_format_version: "5";
12
- /**
13
- * ```
14
- * "0x04700007fabc8282644aed6d1c7c9e21d38a03a0c4ba193f3afe428824b3a673"
15
- * ```
16
- */
17
- genesis_validators_root: string;
18
- };
19
- data: {
20
- /**
21
- * pubkey: BLSPubkey is the BLS public key of the validator encoded as 0x-prefixed hex
22
- * ```
23
- * "0xb845089a1457f811bfc000588fbb4e713669be8ce060ea6be3c6ece09afc3794106c91ca73acda5e5457122d58723bed"
24
- * ```
25
- */
26
- pubkey: string;
27
- /**
28
- * signed_blocks is a list of objects with fields
29
- */
30
- signed_blocks: {
31
- /**
32
- * slot: Slot, the slot of the block that was signed
33
- * ```
34
- * "81952"
35
- * ```
36
- */
37
- slot: string;
38
- /**
39
- * signing_root: Root (optional) is compute_signing_root(block, domain), where:
40
- * - block is the block that was signed as type BeaconBlock or equivalently BeaconBlockHeader
41
- * - domain is equal to compute_domain(DOMAIN_BEACON_PROPOSER, fork, metadata.genesis_validators_root), where:
42
- * - metadata.genesis_validators_root is the genesis_validators_root from this interchange file
43
- * - fork: Version is the fork that the block was signed against
44
- * ```
45
- * "0x4ff6f743a43f3b4f95350831aeaf0a122a1a392922c45d804280284a69eb850b"
46
- * ```
47
- */
48
- signing_root?: string;
49
- }[];
50
- /**
51
- * signed_attestations is a list of objects with fields
52
- */
53
- signed_attestations: {
54
- /**
55
- * source_epoch: Epoch, the attestation.data.source.epoch of the signed attestation
56
- * ```
57
- * "2290"
58
- * ```
59
- */
60
- source_epoch: string;
61
- /**
62
- * target_epoch: Epoch, the attestation.data.target.epoch of the signed attestation
63
- * ```
64
- * "3007"
65
- * ```
66
- */
67
- target_epoch: string;
68
- /**
69
- * signing_root: Root (optional) is compute_signing_root(attestation, domain), where:
70
- * - attestation is the attestation that was signed as type AttestationData
71
- * - domain is equal to compute_domain(DOMAIN_BEACON_ATTESTER, fork, metadata.genesis_validators_root), where:
72
- * - metadata.genesis_validators_root is the genesis_validators_root from this interchange file
73
- * - fork: Version is the fork that the attestation was signed against
74
- * ```
75
- * "0x587d6a4f59a58fe24f406e0502413e77fe1babddee641fda30034ed37ecc884d"
76
- * ```
77
- */
78
- signing_root?: string;
79
- }[];
80
- }[];
81
- };
82
-
83
- export function serializeInterchangeV5({data, genesisValidatorsRoot}: InterchangeLodestar): InterchangeV5 {
84
- return {
85
- metadata: {
86
- interchange_format_version: "5",
87
- genesis_validators_root: toRootHex(genesisValidatorsRoot),
88
- },
89
- data: data.map((validator) => ({
90
- pubkey: toPubkeyHex(validator.pubkey),
91
- signed_blocks: validator.signedBlocks.map((block) => ({
92
- slot: numToString(block.slot),
93
- signing_root: toOptionalHexString(block.signingRoot),
94
- })),
95
- signed_attestations: validator.signedAttestations.map((att) => ({
96
- source_epoch: numToString(att.sourceEpoch),
97
- target_epoch: numToString(att.targetEpoch),
98
- signing_root: toOptionalHexString(att.signingRoot),
99
- })),
100
- })),
101
- };
102
- }
103
-
104
- export function parseInterchangeV5(interchange: InterchangeV5): InterchangeLodestar {
105
- return {
106
- genesisValidatorsRoot: fromHex(interchange.metadata.genesis_validators_root),
107
- data: interchange.data.map((validator) => ({
108
- pubkey: fromHex(validator.pubkey),
109
- signedBlocks: validator.signed_blocks.map((block) => ({
110
- slot: parseInt(block.slot, 10),
111
- signingRoot: fromOptionalHexString(block.signing_root),
112
- })),
113
- signedAttestations: validator.signed_attestations.map((att) => ({
114
- sourceEpoch: parseInt(att.source_epoch, 10),
115
- targetEpoch: parseInt(att.target_epoch, 10),
116
- signingRoot: fromOptionalHexString(att.signing_root),
117
- })),
118
- })),
119
- };
120
- }
@@ -1,5 +0,0 @@
1
- export * from "./errors.js";
2
- export * from "./formats/index.js";
3
- export * from "./parseInterchange.js";
4
- export * from "./serializeInterchange.js";
5
- export * from "./types.js";
@@ -1,55 +0,0 @@
1
- import {Root} from "@lodestar/types";
2
- import {isEqualRoot} from "../utils.js";
3
- import {InterchangeError, InterchangeErrorErrorCode} from "./errors.js";
4
- import {InterchangeCompleteV4, parseInterchangeCompleteV4} from "./formats/completeV4.js";
5
- import {InterchangeV5, parseInterchangeV5} from "./formats/v5.js";
6
- import {Interchange, InterchangeLodestar} from "./types.js";
7
-
8
- export function parseInterchange(interchange: Interchange, expectedGenesisValidatorsRoot: Root): InterchangeLodestar {
9
- const format = (interchange as InterchangeCompleteV4)?.metadata?.interchange_format;
10
- const version = interchange?.metadata?.interchange_format_version;
11
-
12
- if (!format) {
13
- // version >= v5.0.0
14
- switch (version) {
15
- case "5": {
16
- const interchangeLodestar = parseInterchangeV5(interchange as InterchangeV5);
17
- if (!isEqualRoot(interchangeLodestar.genesisValidatorsRoot, expectedGenesisValidatorsRoot)) {
18
- throw new InterchangeError({
19
- code: InterchangeErrorErrorCode.GENESIS_VALIDATOR_MISMATCH,
20
- root: interchangeLodestar.genesisValidatorsRoot,
21
- expectedRoot: expectedGenesisValidatorsRoot,
22
- });
23
- }
24
- return interchangeLodestar;
25
- }
26
-
27
- default:
28
- throw new InterchangeError({code: InterchangeErrorErrorCode.UNSUPPORTED_VERSION, version});
29
- }
30
- }
31
-
32
- // version < v5.0.0 (older version)
33
- switch (format) {
34
- case "complete":
35
- switch (version) {
36
- case "4": {
37
- const interchangeLodestar = parseInterchangeCompleteV4(interchange as InterchangeCompleteV4);
38
- if (!isEqualRoot(interchangeLodestar.genesisValidatorsRoot, expectedGenesisValidatorsRoot)) {
39
- throw new InterchangeError({
40
- code: InterchangeErrorErrorCode.GENESIS_VALIDATOR_MISMATCH,
41
- root: interchangeLodestar.genesisValidatorsRoot,
42
- expectedRoot: expectedGenesisValidatorsRoot,
43
- });
44
- }
45
- return interchangeLodestar;
46
- }
47
-
48
- default:
49
- throw new InterchangeError({code: InterchangeErrorErrorCode.UNSUPPORTED_VERSION, version});
50
- }
51
-
52
- default:
53
- throw new InterchangeError({code: InterchangeErrorErrorCode.UNSUPPORTED_FORMAT, format: format});
54
- }
55
- }
@@ -1,35 +0,0 @@
1
- import {InterchangeError, InterchangeErrorErrorCode} from "./errors.js";
2
- import {serializeInterchangeCompleteV4} from "./formats/completeV4.js";
3
- import {serializeInterchangeV5} from "./formats/v5.js";
4
- import {Interchange, InterchangeFormatVersion, InterchangeLodestar} from "./types.js";
5
-
6
- export function serializeInterchange(
7
- interchangeLodestar: InterchangeLodestar,
8
- {format, version}: InterchangeFormatVersion
9
- ): Interchange {
10
- // version >= v5.0.0
11
- if (!format) {
12
- switch (version) {
13
- case "5":
14
- return serializeInterchangeV5(interchangeLodestar);
15
-
16
- default:
17
- throw new InterchangeError({code: InterchangeErrorErrorCode.UNSUPPORTED_VERSION, version});
18
- }
19
- }
20
-
21
- // version < v5.0.0
22
- switch (format) {
23
- case "complete":
24
- switch (version) {
25
- case "4":
26
- return serializeInterchangeCompleteV4(interchangeLodestar);
27
-
28
- default:
29
- throw new InterchangeError({code: InterchangeErrorErrorCode.UNSUPPORTED_VERSION, version});
30
- }
31
-
32
- default:
33
- throw new InterchangeError({code: InterchangeErrorErrorCode.UNSUPPORTED_FORMAT, format});
34
- }
35
- }
@@ -1,18 +0,0 @@
1
- import {BLSPubkey, Root} from "@lodestar/types";
2
- import {SlashingProtectionAttestation, SlashingProtectionBlock} from "../types.js";
3
- import {InterchangeCompleteV4} from "./formats/completeV4.js";
4
- import {InterchangeV5} from "./formats/v5.js";
5
-
6
- export type Interchange = InterchangeV5 | InterchangeCompleteV4;
7
-
8
- // `format` only for version < v5.0.0
9
- export type InterchangeFormatVersion = {format?: "complete"; version: "4" | "5"};
10
-
11
- export type InterchangeLodestar = {
12
- genesisValidatorsRoot: Root;
13
- data: {
14
- pubkey: BLSPubkey;
15
- signedBlocks: SlashingProtectionBlock[];
16
- signedAttestations: SlashingProtectionAttestation[];
17
- }[];
18
- };
@@ -1,28 +0,0 @@
1
- import {BLSPubkey, Epoch, Root} from "@lodestar/types";
2
- import {Logger} from "@lodestar/utils";
3
- import {Interchange, InterchangeFormatVersion} from "./interchange/types.js";
4
- import {SlashingProtectionAttestation, SlashingProtectionBlock} from "./types.js";
5
-
6
- export interface ISlashingProtection {
7
- /**
8
- * Check a block proposal for slash safety, and if it is safe, record it in the database
9
- */
10
- checkAndInsertBlockProposal(pubKey: BLSPubkey, block: SlashingProtectionBlock): Promise<void>;
11
- /**
12
- * Check an attestation for slash safety, and if it is safe, record it in the database
13
- */
14
- checkAndInsertAttestation(pubKey: BLSPubkey, attestation: SlashingProtectionAttestation): Promise<void>;
15
-
16
- /**
17
- * Check whether a validator as identified by `pubKey` has attested in the specified `epoch`
18
- */
19
- hasAttestedInEpoch(pubKey: BLSPubkey, epoch: Epoch): Promise<boolean>;
20
-
21
- importInterchange(interchange: Interchange, genesisValidatorsRoot: Uint8Array | Root, logger?: Logger): Promise<void>;
22
- exportInterchange(
23
- genesisValidatorsRoot: Uint8Array | Root,
24
- pubkeys: BLSPubkey[],
25
- formatVersion: InterchangeFormatVersion,
26
- logger?: Logger
27
- ): Promise<Interchange>;
28
- }
@@ -1,57 +0,0 @@
1
- import {Type} from "@chainsafe/ssz";
2
- import {DbReqOpts, encodeKey} from "@lodestar/db";
3
- import {BLSPubkey, Epoch, ssz} from "@lodestar/types";
4
- import {intToBytes} from "@lodestar/utils";
5
- import {Bucket, getBucketNameByValue} from "../../buckets.js";
6
- import {LodestarValidatorDatabaseController} from "../../types.js";
7
- import {DistanceEntry, IDistanceStore} from "./interface.js";
8
-
9
- /**
10
- * Manages validator db storage of min/max ranges for min/max surround vote slashing protection.
11
- */
12
- export class DistanceStoreRepository implements IDistanceStore {
13
- minSpan: SpanDistanceRepository;
14
- maxSpan: SpanDistanceRepository;
15
-
16
- constructor(protected db: LodestarValidatorDatabaseController) {
17
- this.minSpan = new SpanDistanceRepository(db, Bucket.slashingProtectionMinSpanDistance);
18
- this.maxSpan = new SpanDistanceRepository(db, Bucket.slashingProtectionMaxSpanDistance);
19
- }
20
- }
21
-
22
- class SpanDistanceRepository {
23
- protected type: Type<Epoch>;
24
- protected bucket: Bucket;
25
-
26
- private readonly bucketId: string;
27
- private readonly dbReqOpts: DbReqOpts;
28
-
29
- constructor(
30
- protected db: LodestarValidatorDatabaseController,
31
- bucket: Bucket
32
- ) {
33
- this.type = ssz.Epoch;
34
- this.bucket = bucket;
35
- this.bucketId = getBucketNameByValue(bucket);
36
- this.dbReqOpts = {bucketId: this.bucketId};
37
- }
38
-
39
- async get(pubkey: BLSPubkey, epoch: Epoch): Promise<Epoch | null> {
40
- const distance = await this.db.get(this.encodeKey(pubkey, epoch), this.dbReqOpts);
41
- return distance && this.type.deserialize(distance);
42
- }
43
-
44
- async setBatch(pubkey: BLSPubkey, values: DistanceEntry[]): Promise<void> {
45
- await this.db.batchPut(
46
- values.map((value) => ({
47
- key: this.encodeKey(pubkey, value.source),
48
- value: this.type.serialize(value.distance),
49
- })),
50
- this.dbReqOpts
51
- );
52
- }
53
-
54
- private encodeKey(pubkey: BLSPubkey, epoch: Epoch): Uint8Array {
55
- return encodeKey(this.bucket, Buffer.concat([pubkey, intToBytes(BigInt(epoch), 8, "be")]));
56
- }
57
- }
@@ -1,27 +0,0 @@
1
- import {LodestarError} from "@lodestar/utils";
2
- import {MinMaxSurroundAttestation} from "./interface.js";
3
-
4
- export enum SurroundAttestationErrorCode {
5
- /**
6
- * The provided attestation is surrounding at least another attestation from the store
7
- */
8
- IS_SURROUNDING = "ERR_SURROUND_ATTESTATION_IS_SURROUNDING",
9
- /**
10
- * The provided attestation is surrounded by at least another attestation from the store
11
- */
12
- IS_SURROUNDED = "ERR_SURROUND_ATTESTATION_IS_SURROUNDED",
13
- }
14
-
15
- type SurroundAttestationErrorType =
16
- | {
17
- code: SurroundAttestationErrorCode.IS_SURROUNDING;
18
- attestation: MinMaxSurroundAttestation;
19
- attestation2Target: number;
20
- }
21
- | {
22
- code: SurroundAttestationErrorCode.IS_SURROUNDED;
23
- attestation: MinMaxSurroundAttestation;
24
- attestation2Target: number;
25
- };
26
-
27
- export class SurroundAttestationError extends LodestarError<SurroundAttestationErrorType> {}
@@ -1,4 +0,0 @@
1
- export * from "./distanceStoreRepository.js";
2
- export * from "./errors.js";
3
- export * from "./interface.js";
4
- export * from "./minMaxSurround.js";
@@ -1,23 +0,0 @@
1
- import {BLSPubkey, Epoch} from "@lodestar/types";
2
-
3
- export type MinMaxSurroundAttestation = {
4
- targetEpoch: number;
5
- sourceEpoch: number;
6
- };
7
-
8
- export interface IMinMaxSurround {
9
- assertNoSurround(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void>;
10
- insertAttestation(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void>;
11
- }
12
-
13
- export type DistanceEntry = {
14
- source: Epoch;
15
- distance: Epoch;
16
- };
17
-
18
- export type IDistanceStore = {
19
- [P in "minSpan" | "maxSpan"]: {
20
- get(pubKey: BLSPubkey, epoch: Epoch): Promise<Epoch | null>;
21
- setBatch(pubKey: BLSPubkey, values: DistanceEntry[]): Promise<void>;
22
- };
23
- };
@@ -1,104 +0,0 @@
1
- import {BLSPubkey} from "@lodestar/types";
2
- import {SurroundAttestationError, SurroundAttestationErrorCode} from "./errors.js";
3
- import {DistanceEntry, IDistanceStore, IMinMaxSurround, MinMaxSurroundAttestation} from "./interface.js";
4
-
5
- // surround vote checking with min-max surround
6
- // https://github.com/protolambda/eth2-surround#min-max-surround
7
-
8
- /**
9
- * Number of epochs in the past to check for surrounding attestations.
10
- *
11
- * This value can be limited to a reasonable high amount as Lodestar does not solely rely on this strategy but also
12
- * implements the minimal strategy which has been formally proven to be safe (https://github.com/michaelsproul/slashing-proofs).
13
- *
14
- * Limiting this value is required due to practical reasons as otherwise there would be a min-span DB read and write
15
- * for each validator from current epoch until genesis which massively increases DB size and causes I/O lag, resulting in
16
- * instability on first startup with an empty DB. See https://github.com/ChainSafe/lodestar/issues/5356 for more details.
17
- *
18
- * The value 4096 has been chosen as it is the default used by slashers (https://lighthouse-book.sigmaprime.io/slasher.html#history-length)
19
- * and is generally higher than the weak subjectivity period. However, it would still be risky if we just relied on min-max surround
20
- * for slashing protection, as slashers can be configured to collect slashable attestations over a longer period.
21
- */
22
- const DEFAULT_MAX_EPOCH_LOOKBACK = 4096;
23
-
24
- export class MinMaxSurround implements IMinMaxSurround {
25
- private store: IDistanceStore;
26
- private maxEpochLookback: number;
27
-
28
- constructor(store: IDistanceStore, options?: {maxEpochLookback?: number}) {
29
- this.store = store;
30
- this.maxEpochLookback = options?.maxEpochLookback ?? DEFAULT_MAX_EPOCH_LOOKBACK;
31
- }
32
-
33
- async assertNoSurround(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
34
- await this.assertNotSurrounding(pubKey, attestation);
35
- await this.assertNotSurrounded(pubKey, attestation);
36
- }
37
-
38
- async insertAttestation(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
39
- await this.updateMinSpan(pubKey, attestation);
40
- await this.updateMaxSpan(pubKey, attestation);
41
- }
42
-
43
- // min span
44
-
45
- private async updateMinSpan(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
46
- await this.assertNotSurrounding(pubKey, attestation);
47
-
48
- const untilEpoch = Math.max(0, attestation.sourceEpoch - 1 - this.maxEpochLookback);
49
-
50
- const values: DistanceEntry[] = [];
51
- for (let epoch = attestation.sourceEpoch - 1; epoch >= untilEpoch; epoch--) {
52
- const minSpan = await this.store.minSpan.get(pubKey, epoch);
53
- const distance = attestation.targetEpoch - epoch;
54
- if (minSpan === null || distance < minSpan) {
55
- values.push({source: epoch, distance});
56
- } else {
57
- break;
58
- }
59
- }
60
- await this.store.minSpan.setBatch(pubKey, values);
61
- }
62
-
63
- private async assertNotSurrounding(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
64
- const minSpan = await this.store.minSpan.get(pubKey, attestation.sourceEpoch);
65
- const distance = attestation.targetEpoch - attestation.sourceEpoch;
66
- if (minSpan != null && minSpan > 0 && minSpan < distance) {
67
- throw new SurroundAttestationError({
68
- code: SurroundAttestationErrorCode.IS_SURROUNDING,
69
- attestation,
70
- attestation2Target: attestation.sourceEpoch + minSpan,
71
- });
72
- }
73
- }
74
-
75
- // max span
76
-
77
- private async updateMaxSpan(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
78
- await this.assertNotSurrounded(pubKey, attestation);
79
-
80
- const values: DistanceEntry[] = [];
81
- for (let epoch = attestation.sourceEpoch + 1; epoch < attestation.targetEpoch; epoch++) {
82
- const maxSpan = await this.store.maxSpan.get(pubKey, epoch);
83
- const distance = attestation.targetEpoch - epoch;
84
- if (maxSpan === null || distance > maxSpan) {
85
- values.push({source: epoch, distance});
86
- } else {
87
- break;
88
- }
89
- }
90
- await this.store.maxSpan.setBatch(pubKey, values);
91
- }
92
-
93
- private async assertNotSurrounded(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
94
- const maxSpan = await this.store.maxSpan.get(pubKey, attestation.sourceEpoch);
95
- const distance = attestation.targetEpoch - attestation.sourceEpoch;
96
- if (maxSpan != null && maxSpan > 0 && maxSpan > distance) {
97
- throw new SurroundAttestationError({
98
- code: SurroundAttestationErrorCode.IS_SURROUNDED,
99
- attestation: attestation,
100
- attestation2Target: attestation.sourceEpoch + maxSpan,
101
- });
102
- }
103
- }
104
- }
@@ -1,12 +0,0 @@
1
- import {Epoch, Root, Slot} from "@lodestar/types";
2
-
3
- export interface SlashingProtectionBlock {
4
- slot: Slot;
5
- signingRoot: Root;
6
- }
7
-
8
- export interface SlashingProtectionAttestation {
9
- sourceEpoch: Epoch;
10
- targetEpoch: Epoch;
11
- signingRoot: Root;
12
- }
@@ -1,42 +0,0 @@
1
- import {Epoch, Root, ssz} from "@lodestar/types";
2
- import {fromHex, toHex, toRootHex} from "@lodestar/utils";
3
-
4
- export const blsPubkeyLen = 48;
5
- export const ZERO_ROOT = ssz.Root.defaultValue();
6
-
7
- export function isEqualRoot(root1: Root, root2: Root): boolean {
8
- return ssz.Root.equals(root1, root2);
9
- }
10
-
11
- export function isEqualNonZeroRoot(root1: Root, root2: Root): boolean {
12
- return !isEqualRoot(root1, ZERO_ROOT) && isEqualRoot(root1, root2);
13
- }
14
-
15
- export function fromOptionalHexString(hex: string | undefined): Root {
16
- return hex ? fromHex(hex) : ZERO_ROOT;
17
- }
18
-
19
- export function toOptionalHexString(root: Root): string | undefined {
20
- return isEqualRoot(root, ZERO_ROOT) ? undefined : toRootHex(root);
21
- }
22
-
23
- /**
24
- * Typesafe wrapper around `String()`. The String constructor accepts any which is dangerous
25
- */
26
- export function numToString(num: number): string {
27
- return String(num);
28
- }
29
-
30
- export function minEpoch(epochs: Epoch[]): Epoch | null {
31
- return epochs.length > 0 ? epochs.reduce((minEpoch, epoch) => (minEpoch < epoch ? minEpoch : epoch)) : null;
32
- }
33
-
34
- export function uniqueVectorArr(buffers: Uint8Array[]): Uint8Array[] {
35
- const bufferStr = new Set<string>();
36
- return buffers.filter((buffer) => {
37
- const str = toHex(buffer);
38
- const seen = bufferStr.has(str);
39
- bufferStr.add(str);
40
- return !seen;
41
- });
42
- }