@lodestar/fork-choice 1.41.0-dev.f2caa915ab → 1.41.0-dev.f7a5f4ddda
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/lib/forkChoice/errors.d.ts +9 -1
- package/lib/forkChoice/errors.d.ts.map +1 -1
- package/lib/forkChoice/errors.js +10 -3
- package/lib/forkChoice/errors.js.map +1 -1
- package/lib/forkChoice/forkChoice.d.ts +75 -19
- package/lib/forkChoice/forkChoice.d.ts.map +1 -1
- package/lib/forkChoice/forkChoice.js +301 -117
- package/lib/forkChoice/forkChoice.js.map +1 -1
- package/lib/forkChoice/interface.d.ts +54 -21
- package/lib/forkChoice/interface.d.ts.map +1 -1
- package/lib/forkChoice/interface.js +6 -3
- package/lib/forkChoice/interface.js.map +1 -1
- package/lib/forkChoice/safeBlocks.js.map +1 -1
- package/lib/forkChoice/store.d.ts +40 -16
- package/lib/forkChoice/store.d.ts.map +1 -1
- package/lib/forkChoice/store.js +22 -4
- package/lib/forkChoice/store.js.map +1 -1
- package/lib/index.d.ts +4 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/metrics.d.ts.map +1 -1
- package/lib/metrics.js.map +1 -1
- package/lib/protoArray/computeDeltas.d.ts.map +1 -1
- package/lib/protoArray/computeDeltas.js +3 -0
- package/lib/protoArray/computeDeltas.js.map +1 -1
- package/lib/protoArray/errors.d.ts +15 -2
- package/lib/protoArray/errors.d.ts.map +1 -1
- package/lib/protoArray/errors.js +7 -2
- package/lib/protoArray/errors.js.map +1 -1
- package/lib/protoArray/interface.d.ts +20 -2
- package/lib/protoArray/interface.d.ts.map +1 -1
- package/lib/protoArray/interface.js +19 -1
- package/lib/protoArray/interface.js.map +1 -1
- package/lib/protoArray/protoArray.d.ts +219 -24
- package/lib/protoArray/protoArray.d.ts.map +1 -1
- package/lib/protoArray/protoArray.js +748 -133
- package/lib/protoArray/protoArray.js.map +1 -1
- package/package.json +9 -9
- package/src/forkChoice/errors.ts +7 -2
- package/src/forkChoice/forkChoice.ts +384 -126
- package/src/forkChoice/interface.ts +72 -20
- package/src/forkChoice/store.ts +52 -20
- package/src/index.ts +10 -2
- package/src/protoArray/computeDeltas.ts +6 -0
- package/src/protoArray/errors.ts +7 -1
- package/src/protoArray/interface.ts +36 -3
- package/src/protoArray/protoArray.ts +880 -134
|
@@ -4,9 +4,15 @@ import {
|
|
|
4
4
|
EffectiveBalanceIncrements,
|
|
5
5
|
} from "@lodestar/state-transition";
|
|
6
6
|
import {AttesterSlashing, BeaconBlock, Epoch, IndexedAttestation, Root, RootHex, Slot} from "@lodestar/types";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
LVHExecResponse,
|
|
9
|
+
MaybeValidExecutionStatus,
|
|
10
|
+
PayloadStatus,
|
|
11
|
+
ProtoBlock,
|
|
12
|
+
ProtoNode,
|
|
13
|
+
} from "../protoArray/interface.js";
|
|
8
14
|
import {UpdateAndGetHeadOpt} from "./forkChoice.js";
|
|
9
|
-
import {CheckpointWithHex} from "./store.js";
|
|
15
|
+
import {CheckpointWithHex, CheckpointWithPayloadStatus} from "./store.js";
|
|
10
16
|
|
|
11
17
|
export type CheckpointHex = {
|
|
12
18
|
epoch: Epoch;
|
|
@@ -18,12 +24,12 @@ export type CheckpointsWithHex = {
|
|
|
18
24
|
finalizedCheckpoint: CheckpointWithHex;
|
|
19
25
|
};
|
|
20
26
|
|
|
21
|
-
export type
|
|
22
|
-
checkpoint:
|
|
27
|
+
export type CheckpointWithPayloadAndBalance = {
|
|
28
|
+
checkpoint: CheckpointWithPayloadStatus;
|
|
23
29
|
balances: EffectiveBalanceIncrements;
|
|
24
30
|
};
|
|
25
31
|
|
|
26
|
-
export type
|
|
32
|
+
export type CheckpointWithPayloadAndTotalBalance = CheckpointWithPayloadAndBalance & {
|
|
27
33
|
totalBalance: number;
|
|
28
34
|
};
|
|
29
35
|
|
|
@@ -72,16 +78,18 @@ export interface IForkChoice {
|
|
|
72
78
|
irrecoverableError?: Error;
|
|
73
79
|
|
|
74
80
|
/**
|
|
75
|
-
* Returns the
|
|
81
|
+
* Returns the ancestor node of `block_root` at the given `slot`. (Note: `slot` refers
|
|
76
82
|
* to the block that is *returned*, not the one that is supplied.)
|
|
77
83
|
*
|
|
78
84
|
* ## Specification
|
|
79
85
|
*
|
|
80
|
-
*
|
|
86
|
+
* Modified for Gloas to return ProtoNode instead of just root:
|
|
87
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.1/specs/gloas/fork-choice.md#modified-get_ancestor
|
|
81
88
|
*
|
|
82
|
-
*
|
|
89
|
+
* Pre-Gloas: Returns (root, PAYLOAD_STATUS_FULL)
|
|
90
|
+
* Gloas: Returns (root, payloadStatus) based on actual node state
|
|
83
91
|
*/
|
|
84
|
-
getAncestor(blockRoot: RootHex, ancestorSlot: Slot):
|
|
92
|
+
getAncestor(blockRoot: RootHex, ancestorSlot: Slot): ProtoNode;
|
|
85
93
|
/**
|
|
86
94
|
* Run the fork choice rule to determine the head.
|
|
87
95
|
*
|
|
@@ -104,7 +112,7 @@ export interface IForkChoice {
|
|
|
104
112
|
* called by `predictProposerHead()` during `prepareNextSlot()`.
|
|
105
113
|
*/
|
|
106
114
|
shouldOverrideForkChoiceUpdate(
|
|
107
|
-
|
|
115
|
+
headBlock: ProtoBlock,
|
|
108
116
|
secFromSlot: number,
|
|
109
117
|
currentSlot: Slot
|
|
110
118
|
): ShouldOverrideForkChoiceUpdateResult;
|
|
@@ -116,8 +124,8 @@ export interface IForkChoice {
|
|
|
116
124
|
* Retrieve all nodes for the debug API.
|
|
117
125
|
*/
|
|
118
126
|
getAllNodes(): ProtoNode[];
|
|
119
|
-
getFinalizedCheckpoint():
|
|
120
|
-
getJustifiedCheckpoint():
|
|
127
|
+
getFinalizedCheckpoint(): CheckpointWithPayloadStatus;
|
|
128
|
+
getJustifiedCheckpoint(): CheckpointWithPayloadStatus;
|
|
121
129
|
/**
|
|
122
130
|
* Add `block` to the fork choice DAG.
|
|
123
131
|
*
|
|
@@ -169,6 +177,38 @@ export interface IForkChoice {
|
|
|
169
177
|
* https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/phase0/fork-choice.md#on_attester_slashing
|
|
170
178
|
*/
|
|
171
179
|
onAttesterSlashing(slashing: AttesterSlashing): void;
|
|
180
|
+
/**
|
|
181
|
+
* Process PTC (Payload Timeliness Committee) messages from a block
|
|
182
|
+
* Updates the PTC votes for the attested beacon block
|
|
183
|
+
*
|
|
184
|
+
* ## Specification
|
|
185
|
+
*
|
|
186
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.0/specs/gloas/fork-choice.md#new-notify_ptc_messages
|
|
187
|
+
*
|
|
188
|
+
* @param blockRoot - The beacon block root being attested
|
|
189
|
+
* @param ptcIndices - Array of PTC committee indices that voted
|
|
190
|
+
* @param payloadPresent - Whether validators attest the payload is present
|
|
191
|
+
*/
|
|
192
|
+
notifyPtcMessages(blockRoot: RootHex, ptcIndices: number[], payloadPresent: boolean): void;
|
|
193
|
+
/**
|
|
194
|
+
* Notify fork choice that an execution payload has arrived (Gloas fork)
|
|
195
|
+
* Creates the FULL variant of a Gloas block when the payload becomes available
|
|
196
|
+
*
|
|
197
|
+
* ## Specification
|
|
198
|
+
*
|
|
199
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.1/specs/gloas/fork-choice.md#new-on_execution_payload
|
|
200
|
+
*
|
|
201
|
+
* @param blockRoot - The beacon block root for which the payload arrived
|
|
202
|
+
* @param executionPayloadBlockHash - The block hash of the execution payload
|
|
203
|
+
* @param executionPayloadNumber - The block number of the execution payload
|
|
204
|
+
* @param executionPayloadStateRoot - The execution payload state root ie. the root of post-state after processExecutionPayloadEnvelope()
|
|
205
|
+
*/
|
|
206
|
+
onExecutionPayload(
|
|
207
|
+
blockRoot: RootHex,
|
|
208
|
+
executionPayloadBlockHash: RootHex,
|
|
209
|
+
executionPayloadNumber: number,
|
|
210
|
+
executionPayloadStateRoot: RootHex
|
|
211
|
+
): void;
|
|
172
212
|
/**
|
|
173
213
|
* Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`.
|
|
174
214
|
*/
|
|
@@ -192,8 +232,11 @@ export interface IForkChoice {
|
|
|
192
232
|
/**
|
|
193
233
|
* Returns a `ProtoBlock` if the block is known **and** a descendant of the finalized root.
|
|
194
234
|
*/
|
|
195
|
-
getBlock(blockRoot: Root): ProtoBlock | null;
|
|
196
|
-
getBlockHex(blockRoot: RootHex): ProtoBlock | null;
|
|
235
|
+
getBlock(blockRoot: Root, payloadStatus: PayloadStatus): ProtoBlock | null;
|
|
236
|
+
getBlockHex(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock | null;
|
|
237
|
+
getBlockDefaultStatus(blockRoot: Root): ProtoBlock | null;
|
|
238
|
+
getBlockHexDefaultStatus(blockRoot: RootHex): ProtoBlock | null;
|
|
239
|
+
getBlockHexAndBlockHash(blockRoot: RootHex, blockHash: RootHex): ProtoBlock | null;
|
|
197
240
|
getFinalizedBlock(): ProtoBlock;
|
|
198
241
|
getJustifiedBlock(): ProtoBlock;
|
|
199
242
|
getFinalizedCheckpointSlot(): Slot;
|
|
@@ -203,7 +246,12 @@ export interface IForkChoice {
|
|
|
203
246
|
* Always returns `false` if either input roots are unknown.
|
|
204
247
|
* Still returns `true` if `ancestorRoot===descendantRoot` (and the roots are known)
|
|
205
248
|
*/
|
|
206
|
-
isDescendant(
|
|
249
|
+
isDescendant(
|
|
250
|
+
ancestorRoot: RootHex,
|
|
251
|
+
ancestorPayloadStatus: PayloadStatus,
|
|
252
|
+
descendantRoot: RootHex,
|
|
253
|
+
descendantPayloadStatus: PayloadStatus
|
|
254
|
+
): boolean;
|
|
207
255
|
/**
|
|
208
256
|
* Prune items up to a finalized root.
|
|
209
257
|
*/
|
|
@@ -212,16 +260,20 @@ export interface IForkChoice {
|
|
|
212
260
|
/**
|
|
213
261
|
* Iterates backwards through ancestor block summaries, starting from a block root
|
|
214
262
|
*/
|
|
215
|
-
iterateAncestorBlocks(blockRoot: RootHex): IterableIterator<ProtoBlock>;
|
|
216
|
-
getAllAncestorBlocks(blockRoot: RootHex): ProtoBlock[];
|
|
263
|
+
iterateAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
|
|
264
|
+
getAllAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
|
|
217
265
|
/**
|
|
218
266
|
* The same to iterateAncestorBlocks but this gets non-ancestor nodes instead of ancestor nodes.
|
|
219
267
|
*/
|
|
220
|
-
getAllNonAncestorBlocks(blockRoot: RootHex): ProtoBlock[];
|
|
268
|
+
getAllNonAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
|
|
221
269
|
/**
|
|
222
270
|
* Returns both ancestor and non-ancestor blocks in a single traversal.
|
|
223
271
|
*/
|
|
224
|
-
getAllAncestorAndNonAncestorBlocks(
|
|
272
|
+
getAllAncestorAndNonAncestorBlocks(
|
|
273
|
+
blockRoot: RootHex,
|
|
274
|
+
payloadStatus: PayloadStatus
|
|
275
|
+
): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]};
|
|
276
|
+
getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null;
|
|
225
277
|
getCanonicalBlockAtSlot(slot: Slot): ProtoBlock | null;
|
|
226
278
|
getCanonicalBlockClosestLteSlot(slot: Slot): ProtoBlock | null;
|
|
227
279
|
/**
|
|
@@ -231,7 +283,7 @@ export interface IForkChoice {
|
|
|
231
283
|
/**
|
|
232
284
|
* Iterates forward descendants of blockRoot. Does not yield blockRoot itself
|
|
233
285
|
*/
|
|
234
|
-
forwardIterateDescendants(blockRoot: RootHex): IterableIterator<ProtoBlock>;
|
|
286
|
+
forwardIterateDescendants(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
|
|
235
287
|
getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[];
|
|
236
288
|
getBlockSummariesAtSlot(slot: Slot): ProtoBlock[];
|
|
237
289
|
/** Returns the distance of common ancestor of nodes to the max of the newNode and the prevNode. */
|
package/src/forkChoice/store.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {CachedBeaconStateAllForks, EffectiveBalanceIncrements} from "@lodestar/state-transition";
|
|
2
2
|
import {RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types";
|
|
3
3
|
import {toRootHex} from "@lodestar/utils";
|
|
4
|
-
import {
|
|
4
|
+
import {PayloadStatus} from "../protoArray/interface.js";
|
|
5
|
+
import {CheckpointWithPayloadAndBalance, CheckpointWithPayloadAndTotalBalance} from "./interface.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Stores checkpoints in a hybrid format:
|
|
@@ -10,6 +11,15 @@ import {CheckpointHexWithBalance, CheckpointHexWithTotalBalance} from "./interfa
|
|
|
10
11
|
*/
|
|
11
12
|
export type CheckpointWithHex = phase0.Checkpoint & {rootHex: RootHex};
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Checkpoint with payload status for Gloas fork choice.
|
|
16
|
+
* Used to track which variant (EMPTY or FULL) of the finalized/justified block to use.
|
|
17
|
+
*
|
|
18
|
+
* Pre-Gloas: payloadStatus is always FULL (payload embedded in block)
|
|
19
|
+
* Gloas: determined by state.execution_payload_availability
|
|
20
|
+
*/
|
|
21
|
+
export type CheckpointWithPayloadStatus = CheckpointWithHex & {payloadStatus: PayloadStatus};
|
|
22
|
+
|
|
13
23
|
export type JustifiedBalances = EffectiveBalanceIncrements;
|
|
14
24
|
|
|
15
25
|
/**
|
|
@@ -19,7 +29,7 @@ export type JustifiedBalances = EffectiveBalanceIncrements;
|
|
|
19
29
|
* @param blockState state that declares justified checkpoint `checkpoint`
|
|
20
30
|
*/
|
|
21
31
|
export type JustifiedBalancesGetter = (
|
|
22
|
-
checkpoint:
|
|
32
|
+
checkpoint: CheckpointWithPayloadStatus,
|
|
23
33
|
blockState: CachedBeaconStateAllForks
|
|
24
34
|
) => JustifiedBalances;
|
|
25
35
|
|
|
@@ -37,11 +47,11 @@ export type JustifiedBalancesGetter = (
|
|
|
37
47
|
*/
|
|
38
48
|
export interface IForkChoiceStore {
|
|
39
49
|
currentSlot: Slot;
|
|
40
|
-
get justified():
|
|
41
|
-
set justified(justified:
|
|
42
|
-
unrealizedJustified:
|
|
43
|
-
finalizedCheckpoint:
|
|
44
|
-
unrealizedFinalizedCheckpoint:
|
|
50
|
+
get justified(): CheckpointWithPayloadAndTotalBalance;
|
|
51
|
+
set justified(justified: CheckpointWithPayloadAndBalance);
|
|
52
|
+
unrealizedJustified: CheckpointWithPayloadAndBalance;
|
|
53
|
+
finalizedCheckpoint: CheckpointWithPayloadStatus;
|
|
54
|
+
unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
|
|
45
55
|
justifiedBalancesGetter: JustifiedBalancesGetter;
|
|
46
56
|
equivocatingIndices: Set<ValidatorIndex>;
|
|
47
57
|
}
|
|
@@ -50,10 +60,10 @@ export interface IForkChoiceStore {
|
|
|
50
60
|
* IForkChoiceStore implementer which emits forkChoice events on updated justified and finalized checkpoints.
|
|
51
61
|
*/
|
|
52
62
|
export class ForkChoiceStore implements IForkChoiceStore {
|
|
53
|
-
private _justified:
|
|
54
|
-
unrealizedJustified:
|
|
55
|
-
private _finalizedCheckpoint:
|
|
56
|
-
unrealizedFinalizedCheckpoint:
|
|
63
|
+
private _justified: CheckpointWithPayloadAndTotalBalance;
|
|
64
|
+
unrealizedJustified: CheckpointWithPayloadAndBalance;
|
|
65
|
+
private _finalizedCheckpoint: CheckpointWithPayloadStatus;
|
|
66
|
+
unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
|
|
57
67
|
equivocatingIndices = new Set<ValidatorIndex>();
|
|
58
68
|
justifiedBalancesGetter: JustifiedBalancesGetter;
|
|
59
69
|
currentSlot: Slot;
|
|
@@ -64,37 +74,49 @@ export class ForkChoiceStore implements IForkChoiceStore {
|
|
|
64
74
|
finalizedCheckpoint: phase0.Checkpoint,
|
|
65
75
|
justifiedBalances: EffectiveBalanceIncrements,
|
|
66
76
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
77
|
+
/**
|
|
78
|
+
* Payload status for justified checkpoint.
|
|
79
|
+
* Pre-Gloas: always FULL
|
|
80
|
+
* Gloas: determined by state.execution_payload_availability
|
|
81
|
+
*/
|
|
82
|
+
justifiedPayloadStatus: PayloadStatus,
|
|
83
|
+
/**
|
|
84
|
+
* Payload status for finalized checkpoint.
|
|
85
|
+
* Pre-Gloas: always FULL
|
|
86
|
+
* Gloas: determined by state.execution_payload_availability
|
|
87
|
+
*/
|
|
88
|
+
finalizedPayloadStatus: PayloadStatus,
|
|
67
89
|
private readonly events?: {
|
|
68
|
-
onJustified: (cp:
|
|
69
|
-
onFinalized: (cp:
|
|
90
|
+
onJustified: (cp: CheckpointWithPayloadStatus) => void;
|
|
91
|
+
onFinalized: (cp: CheckpointWithPayloadStatus) => void;
|
|
70
92
|
}
|
|
71
93
|
) {
|
|
72
94
|
this.justifiedBalancesGetter = justifiedBalancesGetter;
|
|
73
95
|
this.currentSlot = currentSlot;
|
|
74
96
|
const justified = {
|
|
75
|
-
checkpoint:
|
|
97
|
+
checkpoint: toCheckpointWithPayload(justifiedCheckpoint, justifiedPayloadStatus),
|
|
76
98
|
balances: justifiedBalances,
|
|
77
99
|
totalBalance: computeTotalBalance(justifiedBalances),
|
|
78
100
|
};
|
|
79
101
|
this._justified = justified;
|
|
80
102
|
this.unrealizedJustified = justified;
|
|
81
|
-
this._finalizedCheckpoint =
|
|
103
|
+
this._finalizedCheckpoint = toCheckpointWithPayload(finalizedCheckpoint, finalizedPayloadStatus);
|
|
82
104
|
this.unrealizedFinalizedCheckpoint = this._finalizedCheckpoint;
|
|
83
105
|
}
|
|
84
106
|
|
|
85
|
-
get justified():
|
|
107
|
+
get justified(): CheckpointWithPayloadAndTotalBalance {
|
|
86
108
|
return this._justified;
|
|
87
109
|
}
|
|
88
|
-
set justified(justified:
|
|
110
|
+
set justified(justified: CheckpointWithPayloadAndBalance) {
|
|
89
111
|
this._justified = {...justified, totalBalance: computeTotalBalance(justified.balances)};
|
|
90
112
|
this.events?.onJustified(justified.checkpoint);
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
get finalizedCheckpoint():
|
|
115
|
+
get finalizedCheckpoint(): CheckpointWithPayloadStatus {
|
|
94
116
|
return this._finalizedCheckpoint;
|
|
95
117
|
}
|
|
96
|
-
set finalizedCheckpoint(checkpoint:
|
|
97
|
-
const cp =
|
|
118
|
+
set finalizedCheckpoint(checkpoint: CheckpointWithPayloadStatus) {
|
|
119
|
+
const cp = toCheckpointWithPayload(checkpoint, checkpoint.payloadStatus);
|
|
98
120
|
this._finalizedCheckpoint = cp;
|
|
99
121
|
this.events?.onFinalized(cp);
|
|
100
122
|
}
|
|
@@ -111,6 +133,16 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi
|
|
|
111
133
|
};
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
export function toCheckpointWithPayload(
|
|
137
|
+
checkpoint: phase0.Checkpoint,
|
|
138
|
+
payloadStatus: PayloadStatus
|
|
139
|
+
): CheckpointWithPayloadStatus {
|
|
140
|
+
return {
|
|
141
|
+
...toCheckpointWithHex(checkpoint),
|
|
142
|
+
payloadStatus,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
export function equalCheckpointWithHex(a: CheckpointWithHex, b: CheckpointWithHex): boolean {
|
|
115
147
|
return a.epoch === b.epoch && a.rootHex === b.rootHex;
|
|
116
148
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,10 +6,17 @@ export {
|
|
|
6
6
|
type InvalidBlock,
|
|
7
7
|
InvalidBlockCode,
|
|
8
8
|
} from "./forkChoice/errors.js";
|
|
9
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
ForkChoice,
|
|
11
|
+
type ForkChoiceOpts,
|
|
12
|
+
UpdateHeadOpt,
|
|
13
|
+
getCheckpointPayloadStatus,
|
|
14
|
+
} from "./forkChoice/forkChoice.js";
|
|
10
15
|
export {
|
|
11
16
|
type AncestorResult,
|
|
12
17
|
AncestorStatus,
|
|
18
|
+
type CheckpointWithPayloadAndBalance,
|
|
19
|
+
type CheckpointWithPayloadAndTotalBalance,
|
|
13
20
|
EpochDifference,
|
|
14
21
|
type IForkChoice,
|
|
15
22
|
NotReorgedReason,
|
|
@@ -17,6 +24,7 @@ export {
|
|
|
17
24
|
export * from "./forkChoice/safeBlocks.js";
|
|
18
25
|
export {
|
|
19
26
|
type CheckpointWithHex,
|
|
27
|
+
type CheckpointWithPayloadStatus,
|
|
20
28
|
ForkChoiceStore,
|
|
21
29
|
type IForkChoiceStore,
|
|
22
30
|
type JustifiedBalancesGetter,
|
|
@@ -30,5 +38,5 @@ export type {
|
|
|
30
38
|
ProtoBlock,
|
|
31
39
|
ProtoNode,
|
|
32
40
|
} from "./protoArray/interface.js";
|
|
33
|
-
export {ExecutionStatus} from "./protoArray/interface.js";
|
|
41
|
+
export {ExecutionStatus, PayloadStatus} from "./protoArray/interface.js";
|
|
34
42
|
export {ProtoArray} from "./protoArray/protoArray.js";
|
|
@@ -66,6 +66,7 @@ export function computeDeltas(
|
|
|
66
66
|
for (let vIndex = 0; vIndex < voteNextIndices.length; vIndex++) {
|
|
67
67
|
currentIndex = voteCurrentIndices[vIndex];
|
|
68
68
|
nextIndex = voteNextIndices[vIndex];
|
|
69
|
+
|
|
69
70
|
// There is no need to create a score change if the validator has never voted or both of their
|
|
70
71
|
// votes are for the zero hash (genesis block)
|
|
71
72
|
if (currentIndex === NULL_VOTE_INDEX && nextIndex === NULL_VOTE_INDEX) {
|
|
@@ -106,6 +107,9 @@ export function computeDeltas(
|
|
|
106
107
|
continue;
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
// Deduct old balance from current index, add new balance to next index
|
|
111
|
+
// currentIndex and nextIndex already point to the correct node variants
|
|
112
|
+
// Note: If a validator changes from EMPTY to FULL variant of the same block, indexChanged will be true
|
|
109
113
|
if (currentIndex !== nextIndex || oldBalance !== newBalance) {
|
|
110
114
|
// We ignore the vote if it is not known in `indices .
|
|
111
115
|
// We assume that it is outside of our tree (ie: pre-finalization) and therefore not interesting
|
|
@@ -116,6 +120,7 @@ export function computeDeltas(
|
|
|
116
120
|
index: currentIndex,
|
|
117
121
|
});
|
|
118
122
|
}
|
|
123
|
+
|
|
119
124
|
deltas[currentIndex] -= oldBalance;
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -128,6 +133,7 @@ export function computeDeltas(
|
|
|
128
133
|
index: nextIndex,
|
|
129
134
|
});
|
|
130
135
|
}
|
|
136
|
+
|
|
131
137
|
deltas[nextIndex] += newBalance;
|
|
132
138
|
}
|
|
133
139
|
voteCurrentIndices[vIndex] = nextIndex;
|
package/src/protoArray/errors.ts
CHANGED
|
@@ -12,6 +12,8 @@ export type LVHExecError = {lvhCode: LVHExecErrorCode; blockRoot: RootHex; execH
|
|
|
12
12
|
export enum ProtoArrayErrorCode {
|
|
13
13
|
FINALIZED_NODE_UNKNOWN = "PROTO_ARRAY_ERROR_FINALIZED_NODE_UNKNOWN",
|
|
14
14
|
JUSTIFIED_NODE_UNKNOWN = "PROTO_ARRAY_ERROR_JUSTIFIED_NODE_UNKNOWN",
|
|
15
|
+
UNKNOWN_BLOCK = "PROTO_ARRAY_ERROR_UNKNOWN_BLOCK",
|
|
16
|
+
UNKNOWN_PARENT_BLOCK = "PROTO_ARRAY_ERROR_UNKNOWN_PARENT_BLOCK",
|
|
15
17
|
INVALID_FINALIZED_ROOT_CHANGE = "PROTO_ARRAY_ERROR_INVALID_FINALIZED_ROOT_CHANGE",
|
|
16
18
|
INVALID_NODE_INDEX = "PROTO_ARRAY_ERROR_INVALID_NODE_INDEX",
|
|
17
19
|
INVALID_PARENT_INDEX = "PROTO_ARRAY_ERROR_INVALID_PARENT_INDEX",
|
|
@@ -27,11 +29,14 @@ export enum ProtoArrayErrorCode {
|
|
|
27
29
|
INVALID_BLOCK_EXECUTION_STATUS = "PROTO_ARRAY_INVALID_BLOCK_EXECUTION_STATUS",
|
|
28
30
|
INVALID_JUSTIFIED_EXECUTION_STATUS = "PROTO_ARRAY_INVALID_JUSTIFIED_EXECUTION_STATUS",
|
|
29
31
|
INVALID_LVH_EXECUTION_RESPONSE = "PROTO_ARRAY_INVALID_LVH_EXECUTION_RESPONSE",
|
|
32
|
+
PRE_GLOAS_BLOCK = "PROTO_ARRAY_ERROR_PRE_GLOAS_BLOCK",
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export type ProtoArrayErrorType =
|
|
33
36
|
| {code: ProtoArrayErrorCode.FINALIZED_NODE_UNKNOWN; root: RootHex}
|
|
34
37
|
| {code: ProtoArrayErrorCode.JUSTIFIED_NODE_UNKNOWN; root: RootHex}
|
|
38
|
+
| {code: ProtoArrayErrorCode.UNKNOWN_BLOCK; root: RootHex}
|
|
39
|
+
| {code: ProtoArrayErrorCode.UNKNOWN_PARENT_BLOCK; parentRoot: RootHex; parentHash: RootHex | null}
|
|
35
40
|
| {code: ProtoArrayErrorCode.INVALID_FINALIZED_ROOT_CHANGE}
|
|
36
41
|
| {code: ProtoArrayErrorCode.INVALID_NODE_INDEX; index: number}
|
|
37
42
|
| {code: ProtoArrayErrorCode.INVALID_PARENT_INDEX; index: number}
|
|
@@ -54,6 +59,7 @@ export type ProtoArrayErrorType =
|
|
|
54
59
|
}
|
|
55
60
|
| {code: ProtoArrayErrorCode.INVALID_BLOCK_EXECUTION_STATUS; root: RootHex}
|
|
56
61
|
| {code: ProtoArrayErrorCode.INVALID_JUSTIFIED_EXECUTION_STATUS; root: RootHex}
|
|
57
|
-
| ({code: ProtoArrayErrorCode.INVALID_LVH_EXECUTION_RESPONSE} & LVHExecError)
|
|
62
|
+
| ({code: ProtoArrayErrorCode.INVALID_LVH_EXECUTION_RESPONSE} & LVHExecError)
|
|
63
|
+
| {code: ProtoArrayErrorCode.PRE_GLOAS_BLOCK; root: RootHex};
|
|
58
64
|
|
|
59
65
|
export class ProtoArrayError extends LodestarError<ProtoArrayErrorType> {}
|
|
@@ -36,6 +36,23 @@ export enum ExecutionStatus {
|
|
|
36
36
|
PayloadSeparated = "PayloadSeparated",
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Payload status for ePBS (Gloas fork)
|
|
41
|
+
* Spec: gloas/fork-choice.md#constants
|
|
42
|
+
*/
|
|
43
|
+
export enum PayloadStatus {
|
|
44
|
+
PENDING = 0,
|
|
45
|
+
EMPTY = 1,
|
|
46
|
+
FULL = 2,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Check if a block is in the Gloas fork (ePBS enabled)
|
|
51
|
+
*/
|
|
52
|
+
export function isGloasBlock(block: ProtoBlock): boolean {
|
|
53
|
+
return block.parentBlockHash !== null;
|
|
54
|
+
}
|
|
55
|
+
|
|
39
56
|
export type LVHValidResponse = {
|
|
40
57
|
executionStatus: ExecutionStatus.Valid;
|
|
41
58
|
latestValidExecHash: RootHex;
|
|
@@ -51,6 +68,11 @@ export type MaybeValidExecutionStatus = Exclude<ExecutionStatus, ExecutionStatus
|
|
|
51
68
|
|
|
52
69
|
export type BlockExtraMeta =
|
|
53
70
|
| {
|
|
71
|
+
// Pre-gloas:
|
|
72
|
+
// - block hash of payload of the block
|
|
73
|
+
// Post-gloas:
|
|
74
|
+
// - this is parentBlockHash of block bid because payload is only received later
|
|
75
|
+
// - payload block hash for FULL variant
|
|
54
76
|
executionPayloadBlockHash: RootHex;
|
|
55
77
|
executionPayloadNumber: UintNum64;
|
|
56
78
|
executionStatus: Exclude<ExecutionStatus, ExecutionStatus.PreMerge>;
|
|
@@ -102,14 +124,25 @@ export type ProtoBlock = BlockExtraMeta & {
|
|
|
102
124
|
// Indicate whether block arrives in a timely manner ie. before the 4 second mark
|
|
103
125
|
timeliness: boolean;
|
|
104
126
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
/** Payload status for this node (Gloas fork). Always FULL in pre-gloas */
|
|
128
|
+
payloadStatus: PayloadStatus;
|
|
129
|
+
|
|
130
|
+
// GLOAS: The followings are from bids. They are null in pre-gloas
|
|
131
|
+
// Used for execution payload gossip validation
|
|
132
|
+
builderIndex: number | null;
|
|
133
|
+
// Used for execution payload gossip validation. Not to be confused with executionPayloadBlockHash
|
|
134
|
+
blockHashFromBid: RootHex | null;
|
|
135
|
+
|
|
136
|
+
// Used to determine if this block extends EMPTY or FULL parent variant
|
|
137
|
+
// Spec: gloas/fork-choice.md#new-get_parent_payload_status
|
|
138
|
+
parentBlockHash: RootHex | null;
|
|
108
139
|
};
|
|
109
140
|
|
|
110
141
|
/**
|
|
111
142
|
* A block root with additional metadata required to form a DAG
|
|
112
143
|
* with vote weights and best blocks stored as metadata
|
|
144
|
+
*
|
|
145
|
+
* It is also used as ForkChoiceNode in fork choice spec
|
|
113
146
|
*/
|
|
114
147
|
export type ProtoNode = ProtoBlock & {
|
|
115
148
|
parent?: number;
|