@lodestar/fork-choice 1.36.0-dev.c7f3e8d129 → 1.36.0-dev.d690a62b6c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"computeDeltas.d.ts","sourceRoot":"","sources":["../../src/protoArray/computeDeltas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,0BAA0B,EAAC,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAK3C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,WAAW,EAAE,EACpB,WAAW,EAAE,0BAA0B,EACvC,WAAW,EAAE,0BAA0B,EACvC,mBAAmB,EAAE,GAAG,CAAC,cAAc,CAAC,GACvC,MAAM,EAAE,CA+EV"}
1
+ {"version":3,"file":"computeDeltas.d.ts","sourceRoot":"","sources":["../../src/protoArray/computeDeltas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,0BAA0B,EAAC,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAkB,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAK1D,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,sBAAsB,EAAE,MAAM,CAAC;IAE/B,qBAAqB,EAAE,MAAM,CAAC;IAE9B,qBAAqB,EAAE,MAAM,CAAC;IAE9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,SAAS,EAAE,EAC/B,eAAe,EAAE,SAAS,EAAE,EAC5B,WAAW,EAAE,0BAA0B,EACvC,WAAW,EAAE,0BAA0B,EACvC,mBAAmB,EAAE,GAAG,CAAC,cAAc,CAAC,GACvC,YAAY,CAoHd"}
@@ -1,4 +1,5 @@
1
1
  import { ProtoArrayError, ProtoArrayErrorCode } from "./errors.js";
2
+ import { NULL_VOTE_INDEX } from "./interface.js";
2
3
  // reuse arrays to avoid memory reallocation and gc
3
4
  const deltas = new Array();
4
5
  /**
@@ -10,7 +11,14 @@ const deltas = new Array();
10
11
  *
11
12
  * - If a value in `indices` is greater to or equal to `indices.length`.
12
13
  */
13
- export function computeDeltas(numProtoNodes, votes, oldBalances, newBalances, equivocatingIndices) {
14
+ export function computeDeltas(numProtoNodes, voteCurrentIndices, voteNextIndices, oldBalances, newBalances, equivocatingIndices) {
15
+ if (voteCurrentIndices.length !== voteNextIndices.length) {
16
+ throw new Error(`voteCurrentIndices and voteNextIndices must have the same length: ${voteCurrentIndices.length} !== ${voteNextIndices.length}`);
17
+ }
18
+ if (numProtoNodes >= NULL_VOTE_INDEX) {
19
+ // this never happen in practice, but we check to be safe
20
+ throw new Error(`numProtoNodes must be less than NULL_VOTE_INDEX: ${numProtoNodes} >= ${NULL_VOTE_INDEX}`);
21
+ }
14
22
  deltas.length = numProtoNodes;
15
23
  deltas.fill(0);
16
24
  // avoid creating new variables in the loop to potentially reduce GC pressure
@@ -20,15 +28,20 @@ export function computeDeltas(numProtoNodes, votes, oldBalances, newBalances, eq
20
28
  const equivocatingArray = Array.from(equivocatingIndices).sort((a, b) => a - b);
21
29
  let equivocatingIndex = 0;
22
30
  let equivocatingValidatorIndex = equivocatingArray[equivocatingIndex];
23
- for (let vIndex = 0; vIndex < votes.length; vIndex++) {
24
- const vote = votes[vIndex];
31
+ const equivocatingValidators = equivocatingIndices.size;
32
+ let oldInactiveValidators = 0;
33
+ let newInactiveValidators = 0;
34
+ let unchangedVoteValidators = 0;
35
+ let newVoteValidators = 0;
36
+ for (let vIndex = 0; vIndex < voteNextIndices.length; vIndex++) {
37
+ currentIndex = voteCurrentIndices[vIndex];
38
+ nextIndex = voteNextIndices[vIndex];
25
39
  // There is no need to create a score change if the validator has never voted or both of their
26
40
  // votes are for the zero hash (genesis block)
27
- if (vote === undefined) {
41
+ if (currentIndex === NULL_VOTE_INDEX && nextIndex === NULL_VOTE_INDEX) {
42
+ oldInactiveValidators++;
28
43
  continue;
29
44
  }
30
- currentIndex = vote.currentIndex;
31
- nextIndex = vote.nextIndex;
32
45
  // IF the validator was not included in the _old_ balances (i.e. it did not exist yet)
33
46
  // then say its balance was 0
34
47
  oldBalance = oldBalances[vIndex] ?? 0;
@@ -40,7 +53,7 @@ export function computeDeltas(numProtoNodes, votes, oldBalances, newBalances, eq
40
53
  newBalance = newBalances === oldBalances ? oldBalance : (newBalances[vIndex] ?? 0);
41
54
  if (vIndex === equivocatingValidatorIndex) {
42
55
  // this function could be called multiple times but we only want to process slashing validator for 1 time
43
- if (currentIndex !== null) {
56
+ if (currentIndex !== NULL_VOTE_INDEX) {
44
57
  if (currentIndex >= numProtoNodes) {
45
58
  throw new ProtoArrayError({
46
59
  code: ProtoArrayErrorCode.INVALID_NODE_DELTA,
@@ -49,15 +62,19 @@ export function computeDeltas(numProtoNodes, votes, oldBalances, newBalances, eq
49
62
  }
50
63
  deltas[currentIndex] -= oldBalance;
51
64
  }
52
- vote.currentIndex = null;
65
+ voteCurrentIndices[vIndex] = NULL_VOTE_INDEX;
53
66
  equivocatingIndex++;
54
67
  equivocatingValidatorIndex = equivocatingArray[equivocatingIndex];
55
68
  continue;
56
69
  }
70
+ if (oldBalance === 0 && newBalance === 0) {
71
+ newInactiveValidators++;
72
+ continue;
73
+ }
57
74
  if (currentIndex !== nextIndex || oldBalance !== newBalance) {
58
75
  // We ignore the vote if it is not known in `indices .
59
76
  // We assume that it is outside of our tree (ie: pre-finalization) and therefore not interesting
60
- if (currentIndex !== null) {
77
+ if (currentIndex !== NULL_VOTE_INDEX) {
61
78
  if (currentIndex >= numProtoNodes) {
62
79
  throw new ProtoArrayError({
63
80
  code: ProtoArrayErrorCode.INVALID_NODE_DELTA,
@@ -68,7 +85,7 @@ export function computeDeltas(numProtoNodes, votes, oldBalances, newBalances, eq
68
85
  }
69
86
  // We ignore the vote if it is not known in `indices .
70
87
  // We assume that it is outside of our tree (ie: pre-finalization) and therefore not interesting
71
- if (nextIndex !== null) {
88
+ if (nextIndex !== NULL_VOTE_INDEX) {
72
89
  if (nextIndex >= numProtoNodes) {
73
90
  throw new ProtoArrayError({
74
91
  code: ProtoArrayErrorCode.INVALID_NODE_DELTA,
@@ -77,9 +94,24 @@ export function computeDeltas(numProtoNodes, votes, oldBalances, newBalances, eq
77
94
  }
78
95
  deltas[nextIndex] += newBalance;
79
96
  }
97
+ voteCurrentIndices[vIndex] = nextIndex;
98
+ newVoteValidators++;
99
+ }
100
+ else {
101
+ unchangedVoteValidators++;
80
102
  }
81
- vote.currentIndex = nextIndex;
103
+ } // end validator loop
104
+ if (deltas.length !== numProtoNodes) {
105
+ // deltas array could be growed in the loop, especially if we mistakenly set the [NULL_VOTE_INDEX] to it , just to be safe
106
+ throw new Error(`deltas length mismatch: expected ${numProtoNodes}, got ${deltas.length}`);
82
107
  }
83
- return deltas;
108
+ return {
109
+ deltas,
110
+ equivocatingValidators,
111
+ oldInactiveValidators,
112
+ newInactiveValidators,
113
+ unchangedVoteValidators,
114
+ newVoteValidators,
115
+ };
84
116
  }
85
117
  //# sourceMappingURL=computeDeltas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"computeDeltas.js","sourceRoot":"","sources":["../../src/protoArray/computeDeltas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"computeDeltas.js","sourceRoot":"","sources":["../../src/protoArray/computeDeltas.ts"],"names":[],"mappings":"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"}
@@ -2,14 +2,15 @@ import { DataAvailabilityStatus } from "@lodestar/state-transition";
2
2
  import { Epoch, RootHex, Slot, UintNum64 } from "@lodestar/types";
3
3
  export declare const HEX_ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
4
4
  /**
5
- * Simplified 'latest message' with previous message
6
- * The index is relative to ProtoArray indices
5
+ * The null vote index indicates that a validator votes to a non-existent block. This usually happens when
6
+ * we prune the proto array and the validator's latest message is in the pruned part.
7
+ * The number of proto nodes will never exceed this value because it represents (0xffffffff / 365 / 24 / 60 / 5), ie > 1634 years of non-finalized network.
7
8
  */
8
- export type VoteTracker = {
9
- currentIndex: number | null;
10
- nextIndex: number | null;
11
- nextEpoch: Epoch;
12
- };
9
+ export declare const NULL_VOTE_INDEX = 4294967295;
10
+ /**
11
+ * A vote index is a non-negative integer from 0 to NULL_VOTE_INDEX inclusive, and it will never be undefined.
12
+ */
13
+ export type VoteIndex = number;
13
14
  export declare enum ExecutionStatus {
14
15
  Valid = "Valid",
15
16
  Syncing = "Syncing",
@@ -1 +1 @@
1
- {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/protoArray/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAIhE,eAAO,MAAM,aAAa,uEAAuE,CAAC;AAElG;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,KAAK,CAAC;CAClB,CAAC;AAEF,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,eAAe,EAAE,eAAe,CAAC,KAAK,CAAC;IACvC,mBAAmB,EAAE,OAAO,CAAC;CAC9B,CAAC;AACF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC;IACzC,mBAAmB,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,6BAA6B,EAAE,OAAO,CAAC;CACxC,CAAC;AACF,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAEpE,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;AAE1F,MAAM,MAAM,cAAc,GACtB;IACE,yBAAyB,EAAE,OAAO,CAAC;IACnC,sBAAsB,EAAE,SAAS,CAAC;IAClC,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IACpE,sBAAsB,EAAE,sBAAsB,CAAC;CAChD,GACD;IACE,yBAAyB,EAAE,IAAI,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC,QAAQ,CAAC;IAC1C,sBAAsB,EAAE,sBAAsB,CAAC,OAAO,CAAC;CACxD,CAAC;AAEN;;;;GAIG;AAEH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC;;;;OAIG;IACH,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB,cAAc,EAAE,KAAK,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,KAAK,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,wBAAwB,EAAE,KAAK,CAAC;IAChC,uBAAuB,EAAE,OAAO,CAAC;IACjC,wBAAwB,EAAE,KAAK,CAAC;IAChC,uBAAuB,EAAE,OAAO,CAAC;IAGjC,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC"}
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/protoArray/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAIhE,eAAO,MAAM,aAAa,uEAAuE,CAAC;AAElG;;;;GAIG;AACH,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,eAAe,EAAE,eAAe,CAAC,KAAK,CAAC;IACvC,mBAAmB,EAAE,OAAO,CAAC;CAC9B,CAAC;AACF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC;IACzC,mBAAmB,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,6BAA6B,EAAE,OAAO,CAAC;CACxC,CAAC;AACF,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAEpE,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;AAE1F,MAAM,MAAM,cAAc,GACtB;IACE,yBAAyB,EAAE,OAAO,CAAC;IACnC,sBAAsB,EAAE,SAAS,CAAC;IAClC,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IACpE,sBAAsB,EAAE,sBAAsB,CAAC;CAChD,GACD;IACE,yBAAyB,EAAE,IAAI,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC,QAAQ,CAAC;IAC1C,sBAAsB,EAAE,sBAAsB,CAAC,OAAO,CAAC;CACxD,CAAC;AAEN;;;;GAIG;AAEH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC;;;;OAIG;IACH,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB,cAAc,EAAE,KAAK,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,KAAK,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,wBAAwB,EAAE,KAAK,CAAC;IAChC,uBAAuB,EAAE,OAAO,CAAC;IACjC,wBAAwB,EAAE,KAAK,CAAC;IAChC,uBAAuB,EAAE,OAAO,CAAC;IAGjC,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC"}
@@ -1,6 +1,12 @@
1
1
  // RootHex is a root as a hex string
2
2
  // Used for lightweight and easy comparison
3
3
  export const HEX_ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
4
+ /**
5
+ * The null vote index indicates that a validator votes to a non-existent block. This usually happens when
6
+ * we prune the proto array and the validator's latest message is in the pruned part.
7
+ * The number of proto nodes will never exceed this value because it represents (0xffffffff / 365 / 24 / 60 / 5), ie > 1634 years of non-finalized network.
8
+ */
9
+ export const NULL_VOTE_INDEX = 0xffffffff;
4
10
  export var ExecutionStatus;
5
11
  (function (ExecutionStatus) {
6
12
  ExecutionStatus["Valid"] = "Valid";
@@ -1 +1 @@
1
- {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/protoArray/interface.ts"],"names":[],"mappings":"AAGA,oCAAoC;AACpC,2CAA2C;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,oEAAoE,CAAC;AAalG,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,kCAAe,CAAA;IACf,sCAAmB,CAAA;IACnB,wCAAqB,CAAA;IACrB,sCAAmB,CAAA;AACrB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B"}
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/protoArray/interface.ts"],"names":[],"mappings":"AAGA,oCAAoC;AACpC,2CAA2C;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,oEAAoE,CAAC;AAElG;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;AAO1C,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,kCAAe,CAAA;IACf,sCAAmB,CAAA;IACnB,wCAAqB,CAAA;IACrB,sCAAmB,CAAA;AACrB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B"}
package/package.json CHANGED
@@ -11,15 +11,15 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/ChainSafe/lodestar/issues"
13
13
  },
14
- "version": "1.36.0-dev.c7f3e8d129",
14
+ "version": "1.36.0-dev.d690a62b6c",
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
18
18
  "bun": "./src/index.ts",
19
+ "types": "./lib/index.d.ts",
19
20
  "import": "./lib/index.js"
20
21
  }
21
22
  },
22
- "types": "./lib/index.d.ts",
23
23
  "files": [
24
24
  "src",
25
25
  "lib",
@@ -40,11 +40,11 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@chainsafe/ssz": "^1.2.2",
43
- "@lodestar/config": "1.36.0-dev.c7f3e8d129",
44
- "@lodestar/params": "1.36.0-dev.c7f3e8d129",
45
- "@lodestar/state-transition": "1.36.0-dev.c7f3e8d129",
46
- "@lodestar/types": "1.36.0-dev.c7f3e8d129",
47
- "@lodestar/utils": "1.36.0-dev.c7f3e8d129"
43
+ "@lodestar/config": "1.36.0-dev.d690a62b6c",
44
+ "@lodestar/params": "1.36.0-dev.d690a62b6c",
45
+ "@lodestar/state-transition": "1.36.0-dev.d690a62b6c",
46
+ "@lodestar/types": "1.36.0-dev.d690a62b6c",
47
+ "@lodestar/utils": "1.36.0-dev.d690a62b6c"
48
48
  },
49
49
  "keywords": [
50
50
  "ethereum",
@@ -52,5 +52,5 @@
52
52
  "beacon",
53
53
  "blockchain"
54
54
  ],
55
- "gitHead": "ed78bb38a4ebbd6e23b62945055fbfbc9fed0777"
55
+ "gitHead": "cbf80412618dc16aa69cbc4174b4123d0000a998"
56
56
  }
@@ -36,9 +36,10 @@ import {
36
36
  HEX_ZERO_HASH,
37
37
  LVHExecResponse,
38
38
  MaybeValidExecutionStatus,
39
+ NULL_VOTE_INDEX,
39
40
  ProtoBlock,
40
41
  ProtoNode,
41
- VoteTracker,
42
+ VoteIndex,
42
43
  } from "../protoArray/interface.js";
43
44
  import {ProtoArray} from "../protoArray/protoArray.js";
44
45
  import {ForkChoiceError, ForkChoiceErrorCode, InvalidAttestationCode, InvalidBlockCode} from "./errors.js";
@@ -47,7 +48,6 @@ import {
47
48
  AncestorStatus,
48
49
  EpochDifference,
49
50
  IForkChoice,
50
- LatestMessage,
51
51
  NotReorgedReason,
52
52
  PowBlockHex,
53
53
  ShouldOverrideForkChoiceUpdateResult,
@@ -71,6 +71,9 @@ export type UpdateAndGetHeadOpt =
71
71
  | {mode: UpdateHeadOpt.GetProposerHead; secFromSlot: number; slot: Slot}
72
72
  | {mode: UpdateHeadOpt.GetPredictedProposerHead; secFromSlot: number; slot: Slot};
73
73
 
74
+ // the initial vote epoch for all validators
75
+ const INIT_VOTE_EPOCH: Epoch = 0;
76
+
74
77
  /**
75
78
  * Provides an implementation of "Ethereum Consensus -- Beacon Chain Fork Choice":
76
79
  *
@@ -91,11 +94,12 @@ export type UpdateAndGetHeadOpt =
91
94
  export class ForkChoice implements IForkChoice {
92
95
  irrecoverableError?: Error;
93
96
  /**
94
- * Votes currently tracked in the protoArray
95
- * Indexed by validator index
96
- * Each vote contains the latest message and previous message
97
+ * Votes currently tracked in the protoArray. Instead of tracking a VoteTracker of currentIndex, nextIndex and epoch,
98
+ * we decompose the struct and track them in 3 separate arrays for performance reason.
97
99
  */
98
- private readonly votes: VoteTracker[] = [];
100
+ private readonly voteCurrentIndices: VoteIndex[];
101
+ private readonly voteNextIndices: VoteIndex[];
102
+ private readonly voteNextEpochs: Epoch[];
99
103
 
100
104
  /**
101
105
  * Attestations that arrived at the current slot and must be queued for later processing.
@@ -138,15 +142,22 @@ export class ForkChoice implements IForkChoice {
138
142
  private readonly fcStore: IForkChoiceStore,
139
143
  /** The underlying representation of the block DAG. */
140
144
  private readonly protoArray: ProtoArray,
145
+ validatorCount: number,
141
146
  readonly metrics: ForkChoiceMetrics | null,
142
147
  private readonly opts?: ForkChoiceOpts,
143
148
  private readonly logger?: Logger
144
149
  ) {
150
+ // initialize votes, they will grow in addLatestMessage() function below
151
+ this.voteCurrentIndices = new Array(validatorCount).fill(NULL_VOTE_INDEX);
152
+ this.voteNextIndices = new Array(validatorCount).fill(NULL_VOTE_INDEX);
153
+ // when compute deltas, we ignore epoch if voteNextIndex is NULL_VOTE_INDEX anyway
154
+ this.voteNextEpochs = new Array(validatorCount).fill(INIT_VOTE_EPOCH);
155
+
145
156
  this.head = this.updateHead();
146
157
  this.balances = this.fcStore.justified.balances;
147
158
 
148
159
  metrics?.forkChoice.votes.addCollect(() => {
149
- metrics.forkChoice.votes.set(this.votes.length);
160
+ metrics.forkChoice.votes.set(this.voteNextEpochs.length);
150
161
  metrics.forkChoice.queuedAttestations.set(this.queuedAttestationsPreviousSlot);
151
162
  metrics.forkChoice.validatedAttestationDatas.set(this.validatedAttestationDatas.size);
152
163
  metrics.forkChoice.balancesLength.set(this.balances.length);
@@ -443,13 +454,34 @@ export class ForkChoice implements IForkChoice {
443
454
  // Check if scores need to be calculated/updated
444
455
  const oldBalances = this.balances;
445
456
  const newBalances = this.fcStore.justified.balances;
446
- const deltas = computeDeltas(
457
+ const computeDeltasMetrics = this.metrics?.forkChoice.computeDeltas;
458
+
459
+ const timer = computeDeltasMetrics?.duration.startTimer();
460
+ const {
461
+ deltas,
462
+ equivocatingValidators,
463
+ oldInactiveValidators,
464
+ newInactiveValidators,
465
+ unchangedVoteValidators,
466
+ newVoteValidators,
467
+ } = computeDeltas(
447
468
  this.protoArray.nodes.length,
448
- this.votes,
469
+ this.voteCurrentIndices,
470
+ this.voteNextIndices,
449
471
  oldBalances,
450
472
  newBalances,
451
473
  this.fcStore.equivocatingIndices
452
474
  );
475
+ timer?.();
476
+
477
+ computeDeltasMetrics?.deltasCount.set(deltas.length);
478
+ computeDeltasMetrics?.zeroDeltasCount.set(deltas.filter((d) => d === 0).length);
479
+ computeDeltasMetrics?.equivocatingValidators.set(equivocatingValidators);
480
+ computeDeltasMetrics?.oldInactiveValidators.set(oldInactiveValidators);
481
+ computeDeltasMetrics?.newInactiveValidators.set(newInactiveValidators);
482
+ computeDeltasMetrics?.unchangedVoteValidators.set(unchangedVoteValidators);
483
+ computeDeltasMetrics?.newVoteValidators.set(newVoteValidators);
484
+
453
485
  this.balances = newBalances;
454
486
  /**
455
487
  * The structure in line with deltas to propagate boost up the branch
@@ -819,17 +851,6 @@ export class ForkChoice implements IForkChoice {
819
851
  }
820
852
  }
821
853
 
822
- getLatestMessage(validatorIndex: ValidatorIndex): LatestMessage | undefined {
823
- const vote = this.votes[validatorIndex];
824
- if (vote === undefined) {
825
- return undefined;
826
- }
827
- return {
828
- epoch: vote.nextEpoch,
829
- root: vote.nextIndex === null ? HEX_ZERO_HASH : this.protoArray.nodes[vote.nextIndex].blockRoot,
830
- };
831
- }
832
-
833
854
  /**
834
855
  * Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`.
835
856
  * This should only be called once per slot because:
@@ -931,6 +952,11 @@ export class ForkChoice implements IForkChoice {
931
952
  return block;
932
953
  }
933
954
 
955
+ getFinalizedCheckpointSlot(): Slot {
956
+ const finalizedEpoch = this.fcStore.finalizedCheckpoint.epoch;
957
+ return computeStartSlotAtEpoch(finalizedEpoch);
958
+ }
959
+
934
960
  /**
935
961
  * Returns true if the `descendantRoot` has an ancestor with `ancestorRoot`.
936
962
  *
@@ -947,28 +973,26 @@ export class ForkChoice implements IForkChoice {
947
973
  prune(finalizedRoot: RootHex): ProtoBlock[] {
948
974
  const prunedNodes = this.protoArray.maybePrune(finalizedRoot);
949
975
  const prunedCount = prunedNodes.length;
950
- for (let i = 0; i < this.votes.length; i++) {
951
- const vote = this.votes[i];
952
- // validator has never voted
953
- if (vote === undefined) {
954
- continue;
955
- }
976
+ for (let i = 0; i < this.voteNextEpochs.length; i++) {
977
+ const currentIndex = this.voteCurrentIndices[i];
956
978
 
957
- if (vote.currentIndex !== null) {
958
- if (vote.currentIndex >= prunedCount) {
959
- vote.currentIndex -= prunedCount;
979
+ if (currentIndex !== NULL_VOTE_INDEX) {
980
+ if (currentIndex >= prunedCount) {
981
+ this.voteCurrentIndices[i] = currentIndex - prunedCount;
960
982
  } else {
961
983
  // the vote was for a pruned proto node
962
- vote.currentIndex = null;
984
+ this.voteCurrentIndices[i] = NULL_VOTE_INDEX;
963
985
  }
964
986
  }
965
987
 
966
- if (vote.nextIndex !== null) {
967
- if (vote.nextIndex >= prunedCount) {
968
- vote.nextIndex -= prunedCount;
988
+ const nextIndex = this.voteNextIndices[i];
989
+
990
+ if (nextIndex !== NULL_VOTE_INDEX) {
991
+ if (nextIndex >= prunedCount) {
992
+ this.voteNextIndices[i] = nextIndex - prunedCount;
969
993
  } else {
970
994
  // the vote was for a pruned proto node
971
- vote.nextIndex = null;
995
+ this.voteNextIndices[i] = NULL_VOTE_INDEX;
972
996
  }
973
997
  }
974
998
  }
@@ -1435,25 +1459,29 @@ export class ForkChoice implements IForkChoice {
1435
1459
  }
1436
1460
 
1437
1461
  /**
1438
- * Add a validator's latest message to the tracked votes
1462
+ * Add a validator's latest message to the tracked votes.
1463
+ * Always sync voteCurrentIndices and voteNextIndices so that it'll not throw in computeDeltas()
1439
1464
  */
1440
1465
  private addLatestMessage(validatorIndex: ValidatorIndex, nextEpoch: Epoch, nextRoot: RootHex): void {
1441
- const vote = this.votes[validatorIndex];
1442
1466
  // should not happen, attestation is validated before this step
1443
1467
  const nextIndex = this.protoArray.indices.get(nextRoot);
1444
1468
  if (nextIndex === undefined) {
1445
1469
  throw new Error(`Could not find proto index for nextRoot ${nextRoot}`);
1446
1470
  }
1447
1471
 
1448
- if (vote === undefined) {
1449
- this.votes[validatorIndex] = {
1450
- currentIndex: null,
1451
- nextIndex,
1452
- nextEpoch,
1453
- };
1454
- } else if (nextEpoch > vote.nextEpoch) {
1455
- vote.nextIndex = nextIndex;
1456
- vote.nextEpoch = nextEpoch;
1472
+ // ensure there is no undefined entries in Votes arrays
1473
+ if (this.voteNextEpochs.length < validatorIndex + 1) {
1474
+ for (let i = this.voteNextEpochs.length; i < validatorIndex + 1; i++) {
1475
+ this.voteNextEpochs[i] = INIT_VOTE_EPOCH;
1476
+ this.voteCurrentIndices[i] = this.voteNextIndices[i] = NULL_VOTE_INDEX;
1477
+ }
1478
+ }
1479
+
1480
+ const existingNextEpoch = this.voteNextEpochs[validatorIndex];
1481
+ if (existingNextEpoch === INIT_VOTE_EPOCH || nextEpoch > existingNextEpoch) {
1482
+ // nextIndex is transfered to currentIndex in computeDeltas()
1483
+ this.voteNextIndices[validatorIndex] = nextIndex;
1484
+ this.voteNextEpochs[validatorIndex] = nextEpoch;
1457
1485
  }
1458
1486
  // else its an old vote, don't count it
1459
1487
  }
@@ -3,16 +3,7 @@ import {
3
3
  DataAvailabilityStatus,
4
4
  EffectiveBalanceIncrements,
5
5
  } from "@lodestar/state-transition";
6
- import {
7
- AttesterSlashing,
8
- BeaconBlock,
9
- Epoch,
10
- IndexedAttestation,
11
- Root,
12
- RootHex,
13
- Slot,
14
- ValidatorIndex,
15
- } from "@lodestar/types";
6
+ import {AttesterSlashing, BeaconBlock, Epoch, IndexedAttestation, Root, RootHex, Slot} from "@lodestar/types";
16
7
  import {LVHExecResponse, MaybeValidExecutionStatus, ProtoBlock, ProtoNode} from "../protoArray/interface.js";
17
8
  import {UpdateAndGetHeadOpt} from "./forkChoice.js";
18
9
  import {CheckpointWithHex} from "./store.js";
@@ -178,7 +169,6 @@ export interface IForkChoice {
178
169
  * https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/phase0/fork-choice.md#on_attester_slashing
179
170
  */
180
171
  onAttesterSlashing(slashing: AttesterSlashing): void;
181
- getLatestMessage(validatorIndex: ValidatorIndex): LatestMessage | undefined;
182
172
  /**
183
173
  * Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`.
184
174
  */
@@ -206,6 +196,7 @@ export interface IForkChoice {
206
196
  getBlockHex(blockRoot: RootHex): ProtoBlock | null;
207
197
  getFinalizedBlock(): ProtoBlock;
208
198
  getJustifiedBlock(): ProtoBlock;
199
+ getFinalizedCheckpointSlot(): Slot;
209
200
  /**
210
201
  * Returns true if the `descendantRoot` has an ancestor with `ancestorRoot`.
211
202
  *
@@ -262,8 +253,3 @@ export type PowBlockHex = {
262
253
  parentHash: RootHex;
263
254
  totalDifficulty: bigint;
264
255
  };
265
-
266
- export type LatestMessage = {
267
- epoch: Epoch;
268
- root: RootHex;
269
- };
package/src/metrics.ts CHANGED
@@ -66,6 +66,41 @@ export function getForkChoiceMetrics(register: MetricsRegisterExtra) {
66
66
  help: "Reason why the current head is not re-orged out",
67
67
  labelNames: ["reason"],
68
68
  }),
69
+ computeDeltas: {
70
+ duration: register.histogram({
71
+ name: "beacon_fork_choice_compute_deltas_seconds",
72
+ help: "Time taken to compute deltas in seconds",
73
+ buckets: [0.01, 0.05, 0.1, 0.2],
74
+ }),
75
+ deltasCount: register.gauge({
76
+ name: "beacon_fork_choice_compute_deltas_deltas_count",
77
+ help: "Count of deltas computed",
78
+ }),
79
+ zeroDeltasCount: register.gauge({
80
+ name: "beacon_fork_choice_compute_deltas_zero_deltas_count",
81
+ help: "Count of zero deltas processed",
82
+ }),
83
+ equivocatingValidators: register.gauge({
84
+ name: "beacon_fork_choice_compute_deltas_equivocating_validators_count",
85
+ help: "Count of equivocating validators processed",
86
+ }),
87
+ oldInactiveValidators: register.gauge({
88
+ name: "beacon_fork_choice_compute_deltas_old_inactive_validators_count",
89
+ help: "Count of old inactive validators processed",
90
+ }),
91
+ newInactiveValidators: register.gauge({
92
+ name: "beacon_fork_choice_compute_deltas_new_inactive_validators_count",
93
+ help: "Count of new inactive validators processed",
94
+ }),
95
+ unchangedVoteValidators: register.gauge({
96
+ name: "beacon_fork_choice_compute_deltas_unchanged_vote_validators_count",
97
+ help: "Count of unchanged vote validators processed",
98
+ }),
99
+ newVoteValidators: register.gauge({
100
+ name: "beacon_fork_choice_compute_deltas_new_vote_validators_count",
101
+ help: "Count of new vote validators processed",
102
+ }),
103
+ },
69
104
  },
70
105
  };
71
106
  }