@lodestar/fork-choice 1.43.0-dev.9fa9f08ef6 → 1.43.0-dev.a142c56215
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/forkChoice.d.ts +20 -18
- package/lib/forkChoice/forkChoice.d.ts.map +1 -1
- package/lib/forkChoice/forkChoice.js +54 -66
- package/lib/forkChoice/forkChoice.js.map +1 -1
- package/lib/forkChoice/interface.d.ts +25 -8
- package/lib/forkChoice/interface.d.ts.map +1 -1
- package/lib/forkChoice/store.d.ts +16 -40
- package/lib/forkChoice/store.d.ts.map +1 -1
- package/lib/forkChoice/store.js +4 -22
- package/lib/forkChoice/store.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/protoArray/protoArray.d.ts +1 -1
- package/lib/protoArray/protoArray.d.ts.map +1 -1
- package/lib/protoArray/protoArray.js +4 -20
- package/lib/protoArray/protoArray.js.map +1 -1
- package/package.json +8 -8
- package/src/forkChoice/forkChoice.ts +65 -108
- package/src/forkChoice/interface.ts +24 -8
- package/src/forkChoice/store.ts +20 -52
- package/src/index.ts +3 -9
- package/src/protoArray/protoArray.ts +3 -30
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ChainSafe/lodestar/issues"
|
|
13
13
|
},
|
|
14
|
-
"version": "1.43.0-dev.
|
|
14
|
+
"version": "1.43.0-dev.a142c56215",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"check-readme": "pnpm exec ts-node ../../scripts/check_readme.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@chainsafe/ssz": "^1.
|
|
43
|
-
"@lodestar/config": "^1.43.0-dev.
|
|
44
|
-
"@lodestar/params": "^1.43.0-dev.
|
|
45
|
-
"@lodestar/state-transition": "^1.43.0-dev.
|
|
46
|
-
"@lodestar/types": "^1.43.0-dev.
|
|
47
|
-
"@lodestar/utils": "^1.43.0-dev.
|
|
42
|
+
"@chainsafe/ssz": "^1.4.0",
|
|
43
|
+
"@lodestar/config": "^1.43.0-dev.a142c56215",
|
|
44
|
+
"@lodestar/params": "^1.43.0-dev.a142c56215",
|
|
45
|
+
"@lodestar/state-transition": "^1.43.0-dev.a142c56215",
|
|
46
|
+
"@lodestar/types": "^1.43.0-dev.a142c56215",
|
|
47
|
+
"@lodestar/utils": "^1.43.0-dev.a142c56215"
|
|
48
48
|
},
|
|
49
49
|
"keywords": [
|
|
50
50
|
"ethereum",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"beacon",
|
|
53
53
|
"blockchain"
|
|
54
54
|
],
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "2dac6aa64eb2ff2b549500b8f6a69706035ce100"
|
|
56
56
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
2
|
+
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
DataAvailabilityStatus,
|
|
5
5
|
EffectiveBalanceIncrements,
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
getAttesterSlashableIndices,
|
|
12
12
|
isExecutionBlockBodyType,
|
|
13
13
|
isStatePostBellatrix,
|
|
14
|
-
isStatePostGloas,
|
|
15
14
|
} from "@lodestar/state-transition";
|
|
16
15
|
import {
|
|
17
16
|
AttesterSlashing,
|
|
@@ -53,7 +52,7 @@ import {
|
|
|
53
52
|
NotReorgedReason,
|
|
54
53
|
ShouldOverrideForkChoiceUpdateResult,
|
|
55
54
|
} from "./interface.js";
|
|
56
|
-
import {
|
|
55
|
+
import {CheckpointWithHex, IForkChoiceStore, JustifiedBalances, toCheckpointWithHex} from "./store.js";
|
|
57
56
|
|
|
58
57
|
export type ForkChoiceOpts = {
|
|
59
58
|
proposerBoost?: boolean;
|
|
@@ -269,6 +268,11 @@ export class ForkChoice implements IForkChoice {
|
|
|
269
268
|
return {shouldOverrideFcu: false, reason: NotReorgedReason.ProposerBoostReorgDisabled};
|
|
270
269
|
}
|
|
271
270
|
|
|
271
|
+
// Gloas genesis anchor has no parent in the proto array. No reorg possible.
|
|
272
|
+
if (headBlock.parentRoot === HEX_ZERO_HASH) {
|
|
273
|
+
return {shouldOverrideFcu: false, reason: NotReorgedReason.ParentBlockNotAvailable};
|
|
274
|
+
}
|
|
275
|
+
|
|
272
276
|
const parentBlock = this.protoArray.getBlock(
|
|
273
277
|
headBlock.parentRoot,
|
|
274
278
|
this.protoArray.getParentPayloadStatus(headBlock)
|
|
@@ -389,6 +393,11 @@ export class ForkChoice implements IForkChoice {
|
|
|
389
393
|
return {proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ProposerBoostReorgDisabled};
|
|
390
394
|
}
|
|
391
395
|
|
|
396
|
+
// Gloas genesis anchor has no parent in the proto array. No reorg possible.
|
|
397
|
+
if (headBlock.parentRoot === HEX_ZERO_HASH) {
|
|
398
|
+
return {proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ParentBlockNotAvailable};
|
|
399
|
+
}
|
|
400
|
+
|
|
392
401
|
const parentBlock = this.protoArray.getBlock(
|
|
393
402
|
headBlock.parentRoot,
|
|
394
403
|
this.protoArray.getParentPayloadStatus(headBlock)
|
|
@@ -564,11 +573,11 @@ export class ForkChoice implements IForkChoice {
|
|
|
564
573
|
return this.protoArray.nodes;
|
|
565
574
|
}
|
|
566
575
|
|
|
567
|
-
getFinalizedCheckpoint():
|
|
576
|
+
getFinalizedCheckpoint(): CheckpointWithHex {
|
|
568
577
|
return this.fcStore.finalizedCheckpoint;
|
|
569
578
|
}
|
|
570
579
|
|
|
571
|
-
getJustifiedCheckpoint():
|
|
580
|
+
getJustifiedCheckpoint(): CheckpointWithHex {
|
|
572
581
|
return this.fcStore.justified.checkpoint;
|
|
573
582
|
}
|
|
574
583
|
|
|
@@ -675,18 +684,10 @@ export class ForkChoice implements IForkChoice {
|
|
|
675
684
|
this.proposerBoostRoot = blockRootHex;
|
|
676
685
|
}
|
|
677
686
|
|
|
678
|
-
|
|
679
|
-
const justifiedPayloadStatus = getCheckpointPayloadStatus(
|
|
680
|
-
this.config,
|
|
681
|
-
state,
|
|
682
|
-
state.currentJustifiedCheckpoint.epoch
|
|
683
|
-
);
|
|
684
|
-
const justifiedCheckpoint = toCheckpointWithPayload(state.currentJustifiedCheckpoint, justifiedPayloadStatus);
|
|
687
|
+
const justifiedCheckpoint = toCheckpointWithHex(state.currentJustifiedCheckpoint);
|
|
685
688
|
const stateJustifiedEpoch = justifiedCheckpoint.epoch;
|
|
686
689
|
|
|
687
|
-
|
|
688
|
-
const finalizedPayloadStatus = getCheckpointPayloadStatus(this.config, state, state.finalizedCheckpoint.epoch);
|
|
689
|
-
const finalizedCheckpoint = toCheckpointWithPayload(state.finalizedCheckpoint, finalizedPayloadStatus);
|
|
690
|
+
const finalizedCheckpoint = toCheckpointWithHex(state.finalizedCheckpoint);
|
|
690
691
|
|
|
691
692
|
// Justified balances for `justifiedCheckpoint` are new to the fork-choice. Compute them on demand only if
|
|
692
693
|
// the justified checkpoint changes
|
|
@@ -708,61 +709,29 @@ export class ForkChoice implements IForkChoice {
|
|
|
708
709
|
// This is an optimization. It should reduce the amount of times we run
|
|
709
710
|
// `process_justification_and_finalization` by approximately 1/3rd when the chain is
|
|
710
711
|
// performing optimally.
|
|
711
|
-
let unrealizedJustifiedCheckpoint:
|
|
712
|
-
let unrealizedFinalizedCheckpoint:
|
|
712
|
+
let unrealizedJustifiedCheckpoint: CheckpointWithHex;
|
|
713
|
+
let unrealizedFinalizedCheckpoint: CheckpointWithHex;
|
|
713
714
|
if (this.opts?.computeUnrealized) {
|
|
714
715
|
if (
|
|
715
716
|
parentBlock.unrealizedJustifiedEpoch === blockEpoch &&
|
|
716
717
|
parentBlock.unrealizedFinalizedEpoch + 1 >= blockEpoch
|
|
717
718
|
) {
|
|
718
719
|
// reuse from parent, happens at 1/3 last blocks of epoch as monitored in mainnet
|
|
719
|
-
// Get payload status for unrealized justified checkpoint
|
|
720
|
-
const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
|
|
721
|
-
this.config,
|
|
722
|
-
state,
|
|
723
|
-
parentBlock.unrealizedJustifiedEpoch
|
|
724
|
-
);
|
|
725
720
|
unrealizedJustifiedCheckpoint = {
|
|
726
721
|
epoch: parentBlock.unrealizedJustifiedEpoch,
|
|
727
722
|
root: fromHex(parentBlock.unrealizedJustifiedRoot),
|
|
728
723
|
rootHex: parentBlock.unrealizedJustifiedRoot,
|
|
729
|
-
payloadStatus: unrealizedJustifiedPayloadStatus,
|
|
730
724
|
};
|
|
731
|
-
// Get payload status for unrealized finalized checkpoint
|
|
732
|
-
const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
|
|
733
|
-
this.config,
|
|
734
|
-
state,
|
|
735
|
-
parentBlock.unrealizedFinalizedEpoch
|
|
736
|
-
);
|
|
737
725
|
unrealizedFinalizedCheckpoint = {
|
|
738
726
|
epoch: parentBlock.unrealizedFinalizedEpoch,
|
|
739
727
|
root: fromHex(parentBlock.unrealizedFinalizedRoot),
|
|
740
728
|
rootHex: parentBlock.unrealizedFinalizedRoot,
|
|
741
|
-
payloadStatus: unrealizedFinalizedPayloadStatus,
|
|
742
729
|
};
|
|
743
730
|
} else {
|
|
744
731
|
// compute new, happens 2/3 first blocks of epoch as monitored in mainnet
|
|
745
732
|
const unrealized = state.computeUnrealizedCheckpoints();
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
this.config,
|
|
749
|
-
state,
|
|
750
|
-
unrealized.justifiedCheckpoint.epoch
|
|
751
|
-
);
|
|
752
|
-
unrealizedJustifiedCheckpoint = toCheckpointWithPayload(
|
|
753
|
-
unrealized.justifiedCheckpoint,
|
|
754
|
-
unrealizedJustifiedPayloadStatus
|
|
755
|
-
);
|
|
756
|
-
// Get payload status for unrealized finalized checkpoint
|
|
757
|
-
const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
|
|
758
|
-
this.config,
|
|
759
|
-
state,
|
|
760
|
-
unrealized.finalizedCheckpoint.epoch
|
|
761
|
-
);
|
|
762
|
-
unrealizedFinalizedCheckpoint = toCheckpointWithPayload(
|
|
763
|
-
unrealized.finalizedCheckpoint,
|
|
764
|
-
unrealizedFinalizedPayloadStatus
|
|
765
|
-
);
|
|
733
|
+
unrealizedJustifiedCheckpoint = toCheckpointWithHex(unrealized.justifiedCheckpoint);
|
|
734
|
+
unrealizedFinalizedCheckpoint = toCheckpointWithHex(unrealized.finalizedCheckpoint);
|
|
766
735
|
}
|
|
767
736
|
} else {
|
|
768
737
|
unrealizedJustifiedCheckpoint = justifiedCheckpoint;
|
|
@@ -988,7 +957,6 @@ export class ForkChoice implements IForkChoice {
|
|
|
988
957
|
blockRoot: RootHex,
|
|
989
958
|
executionPayloadBlockHash: RootHex,
|
|
990
959
|
executionPayloadNumber: number,
|
|
991
|
-
executionPayloadStateRoot: RootHex,
|
|
992
960
|
executionStatus: PayloadExecutionStatus
|
|
993
961
|
): void {
|
|
994
962
|
this.protoArray.onExecutionPayload(
|
|
@@ -996,7 +964,6 @@ export class ForkChoice implements IForkChoice {
|
|
|
996
964
|
this.fcStore.currentSlot,
|
|
997
965
|
executionPayloadBlockHash,
|
|
998
966
|
executionPayloadNumber,
|
|
999
|
-
executionPayloadStateRoot,
|
|
1000
967
|
this.proposerBoostRoot,
|
|
1001
968
|
executionStatus
|
|
1002
969
|
);
|
|
@@ -1127,8 +1094,8 @@ export class ForkChoice implements IForkChoice {
|
|
|
1127
1094
|
}
|
|
1128
1095
|
|
|
1129
1096
|
getJustifiedBlock(): ProtoBlock {
|
|
1130
|
-
const {rootHex
|
|
1131
|
-
const block = this.
|
|
1097
|
+
const {rootHex} = this.fcStore.justified.checkpoint;
|
|
1098
|
+
const block = this.getBlockHexDefaultStatus(rootHex);
|
|
1132
1099
|
if (!block) {
|
|
1133
1100
|
throw new ForkChoiceError({
|
|
1134
1101
|
code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
|
|
@@ -1139,8 +1106,8 @@ export class ForkChoice implements IForkChoice {
|
|
|
1139
1106
|
}
|
|
1140
1107
|
|
|
1141
1108
|
getFinalizedBlock(): ProtoBlock {
|
|
1142
|
-
const {rootHex
|
|
1143
|
-
const block = this.
|
|
1109
|
+
const {rootHex} = this.fcStore.finalizedCheckpoint;
|
|
1110
|
+
const block = this.getBlockHexDefaultStatus(rootHex);
|
|
1144
1111
|
if (!block) {
|
|
1145
1112
|
throw new ForkChoiceError({
|
|
1146
1113
|
code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
|
|
@@ -1215,13 +1182,12 @@ export class ForkChoice implements IForkChoice {
|
|
|
1215
1182
|
}
|
|
1216
1183
|
|
|
1217
1184
|
/**
|
|
1218
|
-
*
|
|
1219
|
-
*
|
|
1185
|
+
* Raw ancestor walk from `blockRoot` back toward the previous finalized block. Includes both
|
|
1186
|
+
* `blockRoot` and the previous-finalized boundary as last element. Mirrors the semantics of
|
|
1187
|
+
* `getAllAncestorAndNonAncestorBlocks.ancestors`
|
|
1220
1188
|
*/
|
|
1221
1189
|
getAllAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[] {
|
|
1222
|
-
|
|
1223
|
-
// the last node is the previous finalized one, it's there to check onBlock finalized checkpoint only.
|
|
1224
|
-
return blocks.slice(0, blocks.length - 1);
|
|
1190
|
+
return this.protoArray.getAllAncestorNodes(blockRoot, payloadStatus);
|
|
1225
1191
|
}
|
|
1226
1192
|
|
|
1227
1193
|
/**
|
|
@@ -1233,18 +1199,33 @@ export class ForkChoice implements IForkChoice {
|
|
|
1233
1199
|
|
|
1234
1200
|
/**
|
|
1235
1201
|
* Returns both ancestor and non-ancestor blocks in a single traversal.
|
|
1202
|
+
*
|
|
1203
|
+
* `ancestors` is the raw walk and includes the previous finalized block as its last element —
|
|
1204
|
+
* callers that don't want the boundary should slice it off themselves.
|
|
1205
|
+
* Post-gloas for each block root, it returns exactly one variant of it.
|
|
1236
1206
|
*/
|
|
1237
1207
|
getAllAncestorAndNonAncestorBlocks(
|
|
1238
1208
|
blockRoot: RootHex,
|
|
1239
1209
|
payloadStatus: PayloadStatus
|
|
1240
1210
|
): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]} {
|
|
1241
|
-
|
|
1211
|
+
return this.protoArray.getAllAncestorAndNonAncestorNodes(blockRoot, payloadStatus);
|
|
1212
|
+
}
|
|
1242
1213
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1214
|
+
/**
|
|
1215
|
+
* Same to getAllAncestorAndNonAncestorBlocks with default variant of ${blockRoot} to start with
|
|
1216
|
+
*/
|
|
1217
|
+
getAllAncestorAndNonAncestorBlocksDefaultStatus(blockRoot: RootHex): {
|
|
1218
|
+
ancestors: ProtoBlock[];
|
|
1219
|
+
nonAncestors: ProtoBlock[];
|
|
1220
|
+
} {
|
|
1221
|
+
const defaultStatus = this.protoArray.getDefaultVariant(blockRoot);
|
|
1222
|
+
if (defaultStatus === undefined) {
|
|
1223
|
+
throw new ForkChoiceError({
|
|
1224
|
+
code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
|
|
1225
|
+
root: blockRoot,
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
return this.getAllAncestorAndNonAncestorBlocks(blockRoot, defaultStatus);
|
|
1248
1229
|
}
|
|
1249
1230
|
|
|
1250
1231
|
getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null {
|
|
@@ -1316,6 +1297,17 @@ export class ForkChoice implements IForkChoice {
|
|
|
1316
1297
|
}
|
|
1317
1298
|
}
|
|
1318
1299
|
|
|
1300
|
+
forwardIterateDescendantsDefaultStatus(blockRoot: RootHex): IterableIterator<ProtoBlock> {
|
|
1301
|
+
const defaultStatus = this.protoArray.getDefaultVariant(blockRoot);
|
|
1302
|
+
if (defaultStatus === undefined) {
|
|
1303
|
+
throw new ForkChoiceError({
|
|
1304
|
+
code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
|
|
1305
|
+
root: blockRoot,
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
return this.forwardIterateDescendants(blockRoot, defaultStatus);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1319
1311
|
/** Very expensive function, iterates the entire ProtoArray. TODO: Is this function even necessary? */
|
|
1320
1312
|
getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[] {
|
|
1321
1313
|
return this.protoArray.nodes.filter((node) => node.parentRoot === parentRoot);
|
|
@@ -1502,12 +1494,12 @@ export class ForkChoice implements IForkChoice {
|
|
|
1502
1494
|
*
|
|
1503
1495
|
* **`on_tick`**
|
|
1504
1496
|
* May need the justified balances of:
|
|
1505
|
-
* - unrealizedJustified: Already available in `
|
|
1497
|
+
* - unrealizedJustified: Already available in `CheckpointWithBalance`
|
|
1506
1498
|
* Since this balances are already available the getter is just `() => balances`, without cache interaction
|
|
1507
1499
|
*/
|
|
1508
1500
|
private updateCheckpoints(
|
|
1509
|
-
justifiedCheckpoint:
|
|
1510
|
-
finalizedCheckpoint:
|
|
1501
|
+
justifiedCheckpoint: CheckpointWithHex,
|
|
1502
|
+
finalizedCheckpoint: CheckpointWithHex,
|
|
1511
1503
|
getJustifiedBalances: () => JustifiedBalances
|
|
1512
1504
|
): void {
|
|
1513
1505
|
// Update justified checkpoint.
|
|
@@ -1527,8 +1519,8 @@ export class ForkChoice implements IForkChoice {
|
|
|
1527
1519
|
* Update unrealized checkpoints in store if necessary
|
|
1528
1520
|
*/
|
|
1529
1521
|
private updateUnrealizedCheckpoints(
|
|
1530
|
-
unrealizedJustifiedCheckpoint:
|
|
1531
|
-
unrealizedFinalizedCheckpoint:
|
|
1522
|
+
unrealizedJustifiedCheckpoint: CheckpointWithHex,
|
|
1523
|
+
unrealizedFinalizedCheckpoint: CheckpointWithHex,
|
|
1532
1524
|
getJustifiedBalances: () => JustifiedBalances
|
|
1533
1525
|
): void {
|
|
1534
1526
|
if (unrealizedJustifiedCheckpoint.epoch > this.fcStore.unrealizedJustified.checkpoint.epoch) {
|
|
@@ -1903,38 +1895,3 @@ export function getCommitteeFraction(
|
|
|
1903
1895
|
const committeeWeight = Math.floor(justifiedTotalActiveBalanceByIncrement / config.slotsPerEpoch);
|
|
1904
1896
|
return Math.floor((committeeWeight * config.committeePercent) / 100);
|
|
1905
1897
|
}
|
|
1906
|
-
|
|
1907
|
-
/**
|
|
1908
|
-
* Get the payload status for a checkpoint.
|
|
1909
|
-
*
|
|
1910
|
-
* Pre-Gloas: always FULL (payload embedded in block)
|
|
1911
|
-
* Gloas: determined by state.execution_payload_availability
|
|
1912
|
-
*
|
|
1913
|
-
* @param config - The chain fork config to determine fork at checkpoint slot
|
|
1914
|
-
* @param state - The state to check execution_payload_availability
|
|
1915
|
-
* @param checkpointEpoch - The epoch of the checkpoint
|
|
1916
|
-
*/
|
|
1917
|
-
export function getCheckpointPayloadStatus(
|
|
1918
|
-
config: ChainForkConfig,
|
|
1919
|
-
state: IBeaconStateView,
|
|
1920
|
-
checkpointEpoch: number
|
|
1921
|
-
): PayloadStatus {
|
|
1922
|
-
// Compute checkpoint slot first to determine the correct fork
|
|
1923
|
-
const checkpointSlot = computeStartSlotAtEpoch(checkpointEpoch);
|
|
1924
|
-
const fork = config.getForkSeq(checkpointSlot);
|
|
1925
|
-
|
|
1926
|
-
// Pre-Gloas: always FULL
|
|
1927
|
-
if (fork < ForkSeq.gloas) {
|
|
1928
|
-
return PayloadStatus.FULL;
|
|
1929
|
-
}
|
|
1930
|
-
if (!isStatePostGloas(state)) {
|
|
1931
|
-
throw new Error(`Expected gloas+ state for checkpoint payload status, got fork=${state.forkName}`);
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
// For Gloas, check state.execution_payload_availability
|
|
1935
|
-
// - For non-skipped slots at checkpoint: returns false (EMPTY) since payload hasn't arrived yet
|
|
1936
|
-
// - For skipped slots at checkpoint: returns the actual availability status from state
|
|
1937
|
-
const payloadAvailable = state.executionPayloadAvailability.get(checkpointSlot % SLOTS_PER_HISTORICAL_ROOT);
|
|
1938
|
-
|
|
1939
|
-
return payloadAvailable ? PayloadStatus.FULL : PayloadStatus.EMPTY;
|
|
1940
|
-
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ProtoNode,
|
|
10
10
|
} from "../protoArray/interface.js";
|
|
11
11
|
import {UpdateAndGetHeadOpt} from "./forkChoice.js";
|
|
12
|
-
import {CheckpointWithHex
|
|
12
|
+
import {CheckpointWithHex} from "./store.js";
|
|
13
13
|
|
|
14
14
|
export type CheckpointHex = {
|
|
15
15
|
epoch: Epoch;
|
|
@@ -21,12 +21,12 @@ export type CheckpointsWithHex = {
|
|
|
21
21
|
finalizedCheckpoint: CheckpointWithHex;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export type
|
|
25
|
-
checkpoint:
|
|
24
|
+
export type CheckpointWithBalance = {
|
|
25
|
+
checkpoint: CheckpointWithHex;
|
|
26
26
|
balances: EffectiveBalanceIncrements;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export type
|
|
29
|
+
export type CheckpointWithTotalBalance = CheckpointWithBalance & {
|
|
30
30
|
totalBalance: number;
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -121,8 +121,8 @@ export interface IForkChoice {
|
|
|
121
121
|
* Retrieve all nodes for the debug API.
|
|
122
122
|
*/
|
|
123
123
|
getAllNodes(): ProtoNode[];
|
|
124
|
-
getFinalizedCheckpoint():
|
|
125
|
-
getJustifiedCheckpoint():
|
|
124
|
+
getFinalizedCheckpoint(): CheckpointWithHex;
|
|
125
|
+
getJustifiedCheckpoint(): CheckpointWithHex;
|
|
126
126
|
/**
|
|
127
127
|
* Add `block` to the fork choice DAG.
|
|
128
128
|
*
|
|
@@ -198,13 +198,11 @@ export interface IForkChoice {
|
|
|
198
198
|
* @param blockRoot - The beacon block root for which the payload arrived
|
|
199
199
|
* @param executionPayloadBlockHash - The block hash of the execution payload
|
|
200
200
|
* @param executionPayloadNumber - The block number of the execution payload
|
|
201
|
-
* @param executionPayloadStateRoot - The execution payload state root ie. the root of post-state after processExecutionPayloadEnvelope()
|
|
202
201
|
*/
|
|
203
202
|
onExecutionPayload(
|
|
204
203
|
blockRoot: RootHex,
|
|
205
204
|
executionPayloadBlockHash: RootHex,
|
|
206
205
|
executionPayloadNumber: number,
|
|
207
|
-
executionPayloadStateRoot: RootHex,
|
|
208
206
|
executionStatus: PayloadExecutionStatus
|
|
209
207
|
): void;
|
|
210
208
|
/**
|
|
@@ -273,11 +271,23 @@ export interface IForkChoice {
|
|
|
273
271
|
getAllNonAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
|
|
274
272
|
/**
|
|
275
273
|
* Returns both ancestor and non-ancestor blocks in a single traversal.
|
|
274
|
+
*
|
|
275
|
+
* `ancestors` is the raw walk and includes the previous finalized block as its last element —
|
|
276
|
+
* callers that don't want the boundary should slice it off themselves.
|
|
276
277
|
*/
|
|
277
278
|
getAllAncestorAndNonAncestorBlocks(
|
|
278
279
|
blockRoot: RootHex,
|
|
279
280
|
payloadStatus: PayloadStatus
|
|
280
281
|
): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]};
|
|
282
|
+
/**
|
|
283
|
+
* Same as `getAllAncestorAndNonAncestorBlocks` but resolves the default payload-status variant
|
|
284
|
+
* (FULL pre-Gloas, PENDING for Gloas) for the given root. Use when the caller holds a
|
|
285
|
+
* `CheckpointWithHex` / finalized root without a specific payload-status variant in mind.
|
|
286
|
+
*/
|
|
287
|
+
getAllAncestorAndNonAncestorBlocksDefaultStatus(blockRoot: RootHex): {
|
|
288
|
+
ancestors: ProtoBlock[];
|
|
289
|
+
nonAncestors: ProtoBlock[];
|
|
290
|
+
};
|
|
281
291
|
getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null;
|
|
282
292
|
getCanonicalBlockAtSlot(slot: Slot): ProtoBlock | null;
|
|
283
293
|
getCanonicalBlockClosestLteSlot(slot: Slot): ProtoBlock | null;
|
|
@@ -289,6 +299,12 @@ export interface IForkChoice {
|
|
|
289
299
|
* Iterates forward descendants of blockRoot. Does not yield blockRoot itself
|
|
290
300
|
*/
|
|
291
301
|
forwardIterateDescendants(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
|
|
302
|
+
/**
|
|
303
|
+
* Same as `forwardIterateDescendants` but resolves the default payload-status variant
|
|
304
|
+
* (FULL pre-Gloas, PENDING for Gloas) for the given root. Use when the caller holds a
|
|
305
|
+
* `CheckpointWithHex` / finalized root without a specific payload-status variant in mind.
|
|
306
|
+
*/
|
|
307
|
+
forwardIterateDescendantsDefaultStatus(blockRoot: RootHex): IterableIterator<ProtoBlock>;
|
|
292
308
|
getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[];
|
|
293
309
|
getBlockSummariesAtSlot(slot: Slot): ProtoBlock[];
|
|
294
310
|
/** Returns the distance of common ancestor of nodes to the max of the newNode and the prevNode. */
|
package/src/forkChoice/store.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {EffectiveBalanceIncrements, IBeaconStateView} from "@lodestar/state-transition";
|
|
2
2
|
import {RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types";
|
|
3
3
|
import {toRootHex} from "@lodestar/utils";
|
|
4
|
-
import {
|
|
5
|
-
import {CheckpointWithPayloadAndBalance, CheckpointWithPayloadAndTotalBalance} from "./interface.js";
|
|
4
|
+
import {CheckpointWithBalance, CheckpointWithTotalBalance} from "./interface.js";
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Stores checkpoints in a hybrid format:
|
|
@@ -11,15 +10,6 @@ import {CheckpointWithPayloadAndBalance, CheckpointWithPayloadAndTotalBalance} f
|
|
|
11
10
|
*/
|
|
12
11
|
export type CheckpointWithHex = phase0.Checkpoint & {rootHex: RootHex};
|
|
13
12
|
|
|
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
|
-
|
|
23
13
|
export type JustifiedBalances = EffectiveBalanceIncrements;
|
|
24
14
|
|
|
25
15
|
/**
|
|
@@ -29,7 +19,7 @@ export type JustifiedBalances = EffectiveBalanceIncrements;
|
|
|
29
19
|
* @param blockState state that declares justified checkpoint `checkpoint`
|
|
30
20
|
*/
|
|
31
21
|
export type JustifiedBalancesGetter = (
|
|
32
|
-
checkpoint:
|
|
22
|
+
checkpoint: CheckpointWithHex,
|
|
33
23
|
blockState: IBeaconStateView
|
|
34
24
|
) => JustifiedBalances;
|
|
35
25
|
|
|
@@ -47,11 +37,11 @@ export type JustifiedBalancesGetter = (
|
|
|
47
37
|
*/
|
|
48
38
|
export interface IForkChoiceStore {
|
|
49
39
|
currentSlot: Slot;
|
|
50
|
-
get justified():
|
|
51
|
-
set justified(justified:
|
|
52
|
-
unrealizedJustified:
|
|
53
|
-
finalizedCheckpoint:
|
|
54
|
-
unrealizedFinalizedCheckpoint:
|
|
40
|
+
get justified(): CheckpointWithTotalBalance;
|
|
41
|
+
set justified(justified: CheckpointWithBalance);
|
|
42
|
+
unrealizedJustified: CheckpointWithBalance;
|
|
43
|
+
finalizedCheckpoint: CheckpointWithHex;
|
|
44
|
+
unrealizedFinalizedCheckpoint: CheckpointWithHex;
|
|
55
45
|
justifiedBalancesGetter: JustifiedBalancesGetter;
|
|
56
46
|
equivocatingIndices: Set<ValidatorIndex>;
|
|
57
47
|
}
|
|
@@ -60,10 +50,10 @@ export interface IForkChoiceStore {
|
|
|
60
50
|
* IForkChoiceStore implementer which emits forkChoice events on updated justified and finalized checkpoints.
|
|
61
51
|
*/
|
|
62
52
|
export class ForkChoiceStore implements IForkChoiceStore {
|
|
63
|
-
private _justified:
|
|
64
|
-
unrealizedJustified:
|
|
65
|
-
private _finalizedCheckpoint:
|
|
66
|
-
unrealizedFinalizedCheckpoint:
|
|
53
|
+
private _justified: CheckpointWithTotalBalance;
|
|
54
|
+
unrealizedJustified: CheckpointWithBalance;
|
|
55
|
+
private _finalizedCheckpoint: CheckpointWithHex;
|
|
56
|
+
unrealizedFinalizedCheckpoint: CheckpointWithHex;
|
|
67
57
|
equivocatingIndices = new Set<ValidatorIndex>();
|
|
68
58
|
justifiedBalancesGetter: JustifiedBalancesGetter;
|
|
69
59
|
currentSlot: Slot;
|
|
@@ -74,49 +64,37 @@ export class ForkChoiceStore implements IForkChoiceStore {
|
|
|
74
64
|
finalizedCheckpoint: phase0.Checkpoint,
|
|
75
65
|
justifiedBalances: EffectiveBalanceIncrements,
|
|
76
66
|
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,
|
|
89
67
|
private readonly events?: {
|
|
90
|
-
onJustified: (cp:
|
|
91
|
-
onFinalized: (cp:
|
|
68
|
+
onJustified: (cp: CheckpointWithHex) => void;
|
|
69
|
+
onFinalized: (cp: CheckpointWithHex) => void;
|
|
92
70
|
}
|
|
93
71
|
) {
|
|
94
72
|
this.justifiedBalancesGetter = justifiedBalancesGetter;
|
|
95
73
|
this.currentSlot = currentSlot;
|
|
96
74
|
const justified = {
|
|
97
|
-
checkpoint:
|
|
75
|
+
checkpoint: toCheckpointWithHex(justifiedCheckpoint),
|
|
98
76
|
balances: justifiedBalances,
|
|
99
77
|
totalBalance: computeTotalBalance(justifiedBalances),
|
|
100
78
|
};
|
|
101
79
|
this._justified = justified;
|
|
102
80
|
this.unrealizedJustified = justified;
|
|
103
|
-
this._finalizedCheckpoint =
|
|
81
|
+
this._finalizedCheckpoint = toCheckpointWithHex(finalizedCheckpoint);
|
|
104
82
|
this.unrealizedFinalizedCheckpoint = this._finalizedCheckpoint;
|
|
105
83
|
}
|
|
106
84
|
|
|
107
|
-
get justified():
|
|
85
|
+
get justified(): CheckpointWithTotalBalance {
|
|
108
86
|
return this._justified;
|
|
109
87
|
}
|
|
110
|
-
set justified(justified:
|
|
88
|
+
set justified(justified: CheckpointWithBalance) {
|
|
111
89
|
this._justified = {...justified, totalBalance: computeTotalBalance(justified.balances)};
|
|
112
90
|
this.events?.onJustified(justified.checkpoint);
|
|
113
91
|
}
|
|
114
92
|
|
|
115
|
-
get finalizedCheckpoint():
|
|
93
|
+
get finalizedCheckpoint(): CheckpointWithHex {
|
|
116
94
|
return this._finalizedCheckpoint;
|
|
117
95
|
}
|
|
118
|
-
set finalizedCheckpoint(checkpoint:
|
|
119
|
-
const cp =
|
|
96
|
+
set finalizedCheckpoint(checkpoint: CheckpointWithHex) {
|
|
97
|
+
const cp = toCheckpointWithHex(checkpoint);
|
|
120
98
|
this._finalizedCheckpoint = cp;
|
|
121
99
|
this.events?.onFinalized(cp);
|
|
122
100
|
}
|
|
@@ -133,16 +111,6 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi
|
|
|
133
111
|
};
|
|
134
112
|
}
|
|
135
113
|
|
|
136
|
-
export function toCheckpointWithPayload(
|
|
137
|
-
checkpoint: phase0.Checkpoint,
|
|
138
|
-
payloadStatus: PayloadStatus
|
|
139
|
-
): CheckpointWithPayloadStatus {
|
|
140
|
-
return {
|
|
141
|
-
...toCheckpointWithHex(checkpoint),
|
|
142
|
-
payloadStatus,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
114
|
export function equalCheckpointWithHex(a: CheckpointWithHex, b: CheckpointWithHex): boolean {
|
|
147
115
|
return a.epoch === b.epoch && a.rootHex === b.rootHex;
|
|
148
116
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,17 +6,12 @@ export {
|
|
|
6
6
|
type InvalidBlock,
|
|
7
7
|
InvalidBlockCode,
|
|
8
8
|
} from "./forkChoice/errors.js";
|
|
9
|
-
export {
|
|
10
|
-
ForkChoice,
|
|
11
|
-
type ForkChoiceOpts,
|
|
12
|
-
UpdateHeadOpt,
|
|
13
|
-
getCheckpointPayloadStatus,
|
|
14
|
-
} from "./forkChoice/forkChoice.js";
|
|
9
|
+
export {ForkChoice, type ForkChoiceOpts, UpdateHeadOpt} from "./forkChoice/forkChoice.js";
|
|
15
10
|
export {
|
|
16
11
|
type AncestorResult,
|
|
17
12
|
AncestorStatus,
|
|
18
|
-
type
|
|
19
|
-
type
|
|
13
|
+
type CheckpointWithBalance,
|
|
14
|
+
type CheckpointWithTotalBalance,
|
|
20
15
|
EpochDifference,
|
|
21
16
|
type IForkChoice,
|
|
22
17
|
NotReorgedReason,
|
|
@@ -24,7 +19,6 @@ export {
|
|
|
24
19
|
export * from "./forkChoice/safeBlocks.js";
|
|
25
20
|
export {
|
|
26
21
|
type CheckpointWithHex,
|
|
27
|
-
type CheckpointWithPayloadStatus,
|
|
28
22
|
ForkChoiceStore,
|
|
29
23
|
type IForkChoiceStore,
|
|
30
24
|
type JustifiedBalancesGetter,
|
|
@@ -109,30 +109,6 @@ export class ProtoArray {
|
|
|
109
109
|
null
|
|
110
110
|
);
|
|
111
111
|
|
|
112
|
-
// Anchor block PTC votes must be all-true per spec get_forkchoice_store:
|
|
113
|
-
// payload_timeliness_vote={anchor_root: Vector[boolean, PTC_SIZE](True for _ in range(PTC_SIZE))}
|
|
114
|
-
// Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.4/specs/gloas/fork-choice.md#modified-get_forkchoice_store
|
|
115
|
-
if (protoArray.ptcVotes.has(block.blockRoot)) {
|
|
116
|
-
protoArray.ptcVotes.set(block.blockRoot, BitArray.fromBoolArray(Array.from({length: PTC_SIZE}, () => true)));
|
|
117
|
-
|
|
118
|
-
// In the spec, we have payload_states = {anchor_root: anchor_state.copy()}
|
|
119
|
-
// which means the anchor's "payload" is considered received
|
|
120
|
-
// Without FULL, blocks extending FULL from the anchor would be orphaned.
|
|
121
|
-
// TODO GLOAS: This is a bug in the spec. Keep this to pass the current spec test
|
|
122
|
-
// for now. Need to remove this when we work on v1.7.0-alpha.5
|
|
123
|
-
if (block.executionPayloadBlockHash !== null) {
|
|
124
|
-
protoArray.onExecutionPayload(
|
|
125
|
-
block.blockRoot,
|
|
126
|
-
currentSlot,
|
|
127
|
-
block.executionPayloadBlockHash,
|
|
128
|
-
(block as {executionPayloadNumber?: number}).executionPayloadNumber ?? 0,
|
|
129
|
-
block.stateRoot,
|
|
130
|
-
null,
|
|
131
|
-
ExecutionStatus.Valid
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
112
|
return protoArray;
|
|
137
113
|
}
|
|
138
114
|
|
|
@@ -572,7 +548,6 @@ export class ProtoArray {
|
|
|
572
548
|
currentSlot: Slot,
|
|
573
549
|
executionPayloadBlockHash: RootHex,
|
|
574
550
|
executionPayloadNumber: number,
|
|
575
|
-
executionPayloadStateRoot: RootHex,
|
|
576
551
|
proposerBoostRoot: RootHex | null,
|
|
577
552
|
executionStatus: PayloadExecutionStatus
|
|
578
553
|
): void {
|
|
@@ -628,7 +603,6 @@ export class ProtoArray {
|
|
|
628
603
|
executionStatus,
|
|
629
604
|
executionPayloadBlockHash,
|
|
630
605
|
executionPayloadNumber,
|
|
631
|
-
stateRoot: executionPayloadStateRoot,
|
|
632
606
|
};
|
|
633
607
|
|
|
634
608
|
const fullIndex = this.nodes.length;
|
|
@@ -1676,10 +1650,9 @@ export class ProtoArray {
|
|
|
1676
1650
|
const ancestors: ProtoNode[] = [];
|
|
1677
1651
|
const nonAncestors: ProtoNode[] = [];
|
|
1678
1652
|
|
|
1679
|
-
//
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
}
|
|
1653
|
+
// caller of this method may pass default status
|
|
1654
|
+
// this is the only node that we accept PENDING
|
|
1655
|
+
ancestors.push(node);
|
|
1683
1656
|
|
|
1684
1657
|
let nodeIndex = startIndex;
|
|
1685
1658
|
while (node.parent !== undefined) {
|