@lodestar/fork-choice 1.42.0-dev.c3829113f4 → 1.42.0-dev.c58e92512e
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 +8 -1
- package/lib/forkChoice/errors.d.ts.map +1 -1
- package/lib/forkChoice/errors.js +4 -0
- package/lib/forkChoice/errors.js.map +1 -1
- package/lib/forkChoice/forkChoice.d.ts +17 -7
- package/lib/forkChoice/forkChoice.d.ts.map +1 -1
- package/lib/forkChoice/forkChoice.js +50 -19
- package/lib/forkChoice/forkChoice.js.map +1 -1
- package/lib/forkChoice/interface.d.ts +10 -4
- package/lib/forkChoice/interface.d.ts.map +1 -1
- package/lib/forkChoice/interface.js.map +1 -1
- package/lib/forkChoice/store.d.ts +2 -2
- package/lib/forkChoice/store.d.ts.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/protoArray/interface.d.ts +11 -1
- package/lib/protoArray/interface.d.ts.map +1 -1
- package/lib/protoArray/protoArray.d.ts +7 -2
- package/lib/protoArray/protoArray.d.ts.map +1 -1
- package/lib/protoArray/protoArray.js +15 -9
- package/lib/protoArray/protoArray.js.map +1 -1
- package/package.json +7 -7
- package/src/forkChoice/errors.ts +6 -1
- package/src/forkChoice/forkChoice.ts +72 -24
- package/src/forkChoice/interface.ts +13 -9
- package/src/forkChoice/store.ts +2 -2
- package/src/index.ts +2 -1
- package/src/protoArray/interface.ts +12 -1
- package/src/protoArray/protoArray.ts +18 -9
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {ForkSeq, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
|
-
CachedBeaconStateAllForks,
|
|
5
|
-
CachedBeaconStateGloas,
|
|
6
4
|
DataAvailabilityStatus,
|
|
7
5
|
EffectiveBalanceIncrements,
|
|
6
|
+
IBeaconStateView,
|
|
8
7
|
ZERO_HASH,
|
|
9
8
|
computeEpochAtSlot,
|
|
10
9
|
computeSlotsSinceEpochStart,
|
|
11
10
|
computeStartSlotAtEpoch,
|
|
12
11
|
getAttesterSlashableIndices,
|
|
13
12
|
isExecutionBlockBodyType,
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
isStatePostBellatrix,
|
|
14
|
+
isStatePostGloas,
|
|
16
15
|
} from "@lodestar/state-transition";
|
|
17
|
-
import {computeUnrealizedCheckpoints} from "@lodestar/state-transition/epoch";
|
|
18
16
|
import {
|
|
19
17
|
AttesterSlashing,
|
|
20
18
|
BeaconBlock,
|
|
@@ -33,11 +31,12 @@ import {ForkChoiceMetrics} from "../metrics.js";
|
|
|
33
31
|
import {computeDeltas} from "../protoArray/computeDeltas.js";
|
|
34
32
|
import {ProtoArrayError, ProtoArrayErrorCode} from "../protoArray/errors.js";
|
|
35
33
|
import {
|
|
34
|
+
BlockExecutionStatus,
|
|
36
35
|
ExecutionStatus,
|
|
37
36
|
HEX_ZERO_HASH,
|
|
38
37
|
LVHExecResponse,
|
|
39
|
-
MaybeValidExecutionStatus,
|
|
40
38
|
NULL_VOTE_INDEX,
|
|
39
|
+
PayloadExecutionStatus,
|
|
41
40
|
PayloadStatus,
|
|
42
41
|
ProtoBlock,
|
|
43
42
|
ProtoNode,
|
|
@@ -586,10 +585,10 @@ export class ForkChoice implements IForkChoice {
|
|
|
586
585
|
*/
|
|
587
586
|
onBlock(
|
|
588
587
|
block: BeaconBlock,
|
|
589
|
-
state:
|
|
588
|
+
state: IBeaconStateView,
|
|
590
589
|
blockDelaySec: number,
|
|
591
590
|
currentSlot: Slot,
|
|
592
|
-
executionStatus:
|
|
591
|
+
executionStatus: BlockExecutionStatus,
|
|
593
592
|
dataAvailabilityStatus: DataAvailabilityStatus
|
|
594
593
|
): ProtoBlock {
|
|
595
594
|
const {parentRoot, slot} = block;
|
|
@@ -672,12 +671,16 @@ export class ForkChoice implements IForkChoice {
|
|
|
672
671
|
}
|
|
673
672
|
|
|
674
673
|
// Get justified checkpoint with payload status for Gloas
|
|
675
|
-
const justifiedPayloadStatus = getCheckpointPayloadStatus(
|
|
674
|
+
const justifiedPayloadStatus = getCheckpointPayloadStatus(
|
|
675
|
+
this.config,
|
|
676
|
+
state,
|
|
677
|
+
state.currentJustifiedCheckpoint.epoch
|
|
678
|
+
);
|
|
676
679
|
const justifiedCheckpoint = toCheckpointWithPayload(state.currentJustifiedCheckpoint, justifiedPayloadStatus);
|
|
677
680
|
const stateJustifiedEpoch = justifiedCheckpoint.epoch;
|
|
678
681
|
|
|
679
682
|
// Get finalized checkpoint with payload status for Gloas
|
|
680
|
-
const finalizedPayloadStatus = getCheckpointPayloadStatus(state, state.finalizedCheckpoint.epoch);
|
|
683
|
+
const finalizedPayloadStatus = getCheckpointPayloadStatus(this.config, state, state.finalizedCheckpoint.epoch);
|
|
681
684
|
const finalizedCheckpoint = toCheckpointWithPayload(state.finalizedCheckpoint, finalizedPayloadStatus);
|
|
682
685
|
|
|
683
686
|
// Justified balances for `justifiedCheckpoint` are new to the fork-choice. Compute them on demand only if
|
|
@@ -710,6 +713,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
710
713
|
// reuse from parent, happens at 1/3 last blocks of epoch as monitored in mainnet
|
|
711
714
|
// Get payload status for unrealized justified checkpoint
|
|
712
715
|
const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
|
|
716
|
+
this.config,
|
|
713
717
|
state,
|
|
714
718
|
parentBlock.unrealizedJustifiedEpoch
|
|
715
719
|
);
|
|
@@ -721,6 +725,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
721
725
|
};
|
|
722
726
|
// Get payload status for unrealized finalized checkpoint
|
|
723
727
|
const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
|
|
728
|
+
this.config,
|
|
724
729
|
state,
|
|
725
730
|
parentBlock.unrealizedFinalizedEpoch
|
|
726
731
|
);
|
|
@@ -732,9 +737,10 @@ export class ForkChoice implements IForkChoice {
|
|
|
732
737
|
};
|
|
733
738
|
} else {
|
|
734
739
|
// compute new, happens 2/3 first blocks of epoch as monitored in mainnet
|
|
735
|
-
const unrealized = computeUnrealizedCheckpoints(
|
|
740
|
+
const unrealized = state.computeUnrealizedCheckpoints();
|
|
736
741
|
// Get payload status for unrealized justified checkpoint
|
|
737
742
|
const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
|
|
743
|
+
this.config,
|
|
738
744
|
state,
|
|
739
745
|
unrealized.justifiedCheckpoint.epoch
|
|
740
746
|
);
|
|
@@ -744,6 +750,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
744
750
|
);
|
|
745
751
|
// Get payload status for unrealized finalized checkpoint
|
|
746
752
|
const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
|
|
753
|
+
this.config,
|
|
747
754
|
state,
|
|
748
755
|
unrealized.finalizedCheckpoint.epoch
|
|
749
756
|
);
|
|
@@ -771,7 +778,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
771
778
|
}
|
|
772
779
|
|
|
773
780
|
const targetSlot = computeStartSlotAtEpoch(blockEpoch);
|
|
774
|
-
const targetRoot = slot === targetSlot ? blockRoot : state.
|
|
781
|
+
const targetRoot = slot === targetSlot ? blockRoot : state.getBlockRootAtSlot(targetSlot);
|
|
775
782
|
|
|
776
783
|
// This does not apply a vote to the block, it just makes fork choice aware of the block so
|
|
777
784
|
// it can still be identified as the head even if it doesn't have any votes.
|
|
@@ -820,7 +827,10 @@ export class ForkChoice implements IForkChoice {
|
|
|
820
827
|
executionStatus: this.getPostGloasExecStatus(executionStatus),
|
|
821
828
|
dataAvailabilityStatus,
|
|
822
829
|
}
|
|
823
|
-
: isExecutionBlockBodyType(block.body) &&
|
|
830
|
+
: isExecutionBlockBodyType(block.body) &&
|
|
831
|
+
isStatePostBellatrix(state) &&
|
|
832
|
+
state.isExecutionStateType &&
|
|
833
|
+
state.isExecutionEnabled(block)
|
|
824
834
|
? {
|
|
825
835
|
executionPayloadBlockHash: toRootHex(block.body.executionPayload.blockHash),
|
|
826
836
|
executionPayloadNumber: block.body.executionPayload.blockNumber,
|
|
@@ -973,7 +983,8 @@ export class ForkChoice implements IForkChoice {
|
|
|
973
983
|
blockRoot: RootHex,
|
|
974
984
|
executionPayloadBlockHash: RootHex,
|
|
975
985
|
executionPayloadNumber: number,
|
|
976
|
-
executionPayloadStateRoot: RootHex
|
|
986
|
+
executionPayloadStateRoot: RootHex,
|
|
987
|
+
executionStatus: PayloadExecutionStatus
|
|
977
988
|
): void {
|
|
978
989
|
this.protoArray.onExecutionPayload(
|
|
979
990
|
blockRoot,
|
|
@@ -981,7 +992,8 @@ export class ForkChoice implements IForkChoice {
|
|
|
981
992
|
executionPayloadBlockHash,
|
|
982
993
|
executionPayloadNumber,
|
|
983
994
|
executionPayloadStateRoot,
|
|
984
|
-
this.proposerBoostRoot
|
|
995
|
+
this.proposerBoostRoot,
|
|
996
|
+
executionStatus
|
|
985
997
|
);
|
|
986
998
|
}
|
|
987
999
|
|
|
@@ -1039,19 +1051,34 @@ export class ForkChoice implements IForkChoice {
|
|
|
1039
1051
|
}
|
|
1040
1052
|
|
|
1041
1053
|
/**
|
|
1042
|
-
* Same
|
|
1054
|
+
* Same as hasBlock but without checking if the block is a descendant of the finalized root.
|
|
1043
1055
|
*/
|
|
1044
1056
|
hasBlockUnsafe(blockRoot: Root): boolean {
|
|
1045
1057
|
return this.hasBlockHexUnsafe(toRootHex(blockRoot));
|
|
1046
1058
|
}
|
|
1047
1059
|
|
|
1048
1060
|
/**
|
|
1049
|
-
* Same
|
|
1061
|
+
* Same as hasBlockHex but without checking if the block is a descendant of the finalized root.
|
|
1050
1062
|
*/
|
|
1051
1063
|
hasBlockHexUnsafe(blockRoot: RootHex): boolean {
|
|
1052
1064
|
return this.protoArray.hasBlock(blockRoot);
|
|
1053
1065
|
}
|
|
1054
1066
|
|
|
1067
|
+
/**
|
|
1068
|
+
* Returns true if the FULL payload variant (execution payload envelope) exists for this block root,
|
|
1069
|
+
* without checking if the block is a descendant of the finalized root.
|
|
1070
|
+
*/
|
|
1071
|
+
hasPayloadUnsafe(blockRoot: Root): boolean {
|
|
1072
|
+
return this.hasPayloadHexUnsafe(toRootHex(blockRoot));
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Same as hasPayloadUnsafe but accepts a hex-encoded block root.
|
|
1077
|
+
*/
|
|
1078
|
+
hasPayloadHexUnsafe(blockRoot: RootHex): boolean {
|
|
1079
|
+
return this.protoArray.hasPayload(blockRoot);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1055
1082
|
/**
|
|
1056
1083
|
* Returns a MUTABLE `ProtoBlock` if the block is known **and** a descendant of the finalized root.
|
|
1057
1084
|
*/
|
|
@@ -1421,7 +1448,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
1421
1448
|
return secFromSlot * 1000 <= proposerReorgCutoff;
|
|
1422
1449
|
}
|
|
1423
1450
|
|
|
1424
|
-
private getPreMergeExecStatus(executionStatus:
|
|
1451
|
+
private getPreMergeExecStatus(executionStatus: BlockExecutionStatus): ExecutionStatus.PreMerge {
|
|
1425
1452
|
if (executionStatus !== ExecutionStatus.PreMerge)
|
|
1426
1453
|
throw Error(`Invalid pre-merge execution status: expected: ${ExecutionStatus.PreMerge}, got ${executionStatus}`);
|
|
1427
1454
|
return executionStatus;
|
|
@@ -1436,7 +1463,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
1436
1463
|
}
|
|
1437
1464
|
|
|
1438
1465
|
private getPreGloasExecStatus(
|
|
1439
|
-
executionStatus:
|
|
1466
|
+
executionStatus: BlockExecutionStatus
|
|
1440
1467
|
): ExecutionStatus.Valid | ExecutionStatus.Syncing {
|
|
1441
1468
|
if (executionStatus === ExecutionStatus.PreMerge || executionStatus === ExecutionStatus.PayloadSeparated)
|
|
1442
1469
|
throw Error(
|
|
@@ -1445,7 +1472,7 @@ export class ForkChoice implements IForkChoice {
|
|
|
1445
1472
|
return executionStatus;
|
|
1446
1473
|
}
|
|
1447
1474
|
|
|
1448
|
-
private getPostGloasExecStatus(executionStatus:
|
|
1475
|
+
private getPostGloasExecStatus(executionStatus: BlockExecutionStatus): ExecutionStatus.PayloadSeparated {
|
|
1449
1476
|
if (executionStatus !== ExecutionStatus.PayloadSeparated)
|
|
1450
1477
|
throw Error(
|
|
1451
1478
|
`Invalid post-gloas execution status: expected: ${ExecutionStatus.PayloadSeparated}, got ${executionStatus}`
|
|
@@ -1669,6 +1696,20 @@ export class ForkChoice implements IForkChoice {
|
|
|
1669
1696
|
});
|
|
1670
1697
|
}
|
|
1671
1698
|
|
|
1699
|
+
// If attesting for a full node, the payload must be known
|
|
1700
|
+
if (isGloasBlock(block) && attestationData.index === 1) {
|
|
1701
|
+
const fullNodeIndex = this.protoArray.getNodeIndexByRootAndStatus(beaconBlockRootHex, PayloadStatus.FULL);
|
|
1702
|
+
if (fullNodeIndex === undefined) {
|
|
1703
|
+
throw new ForkChoiceError({
|
|
1704
|
+
code: ForkChoiceErrorCode.INVALID_ATTESTATION,
|
|
1705
|
+
err: {
|
|
1706
|
+
code: InvalidAttestationCode.UNKNOWN_PAYLOAD_STATUS,
|
|
1707
|
+
beaconBlockRoot: beaconBlockRootHex,
|
|
1708
|
+
},
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1672
1713
|
this.validatedAttestationDatas.add(attDataRoot);
|
|
1673
1714
|
}
|
|
1674
1715
|
|
|
@@ -1851,24 +1892,31 @@ export function getCommitteeFraction(
|
|
|
1851
1892
|
* Pre-Gloas: always FULL (payload embedded in block)
|
|
1852
1893
|
* Gloas: determined by state.execution_payload_availability
|
|
1853
1894
|
*
|
|
1895
|
+
* @param config - The chain fork config to determine fork at checkpoint slot
|
|
1854
1896
|
* @param state - The state to check execution_payload_availability
|
|
1855
1897
|
* @param checkpointEpoch - The epoch of the checkpoint
|
|
1856
1898
|
*/
|
|
1857
|
-
export function getCheckpointPayloadStatus(
|
|
1899
|
+
export function getCheckpointPayloadStatus(
|
|
1900
|
+
config: ChainForkConfig,
|
|
1901
|
+
state: IBeaconStateView,
|
|
1902
|
+
checkpointEpoch: number
|
|
1903
|
+
): PayloadStatus {
|
|
1858
1904
|
// Compute checkpoint slot first to determine the correct fork
|
|
1859
1905
|
const checkpointSlot = computeStartSlotAtEpoch(checkpointEpoch);
|
|
1860
|
-
const fork =
|
|
1906
|
+
const fork = config.getForkSeq(checkpointSlot);
|
|
1861
1907
|
|
|
1862
1908
|
// Pre-Gloas: always FULL
|
|
1863
1909
|
if (fork < ForkSeq.gloas) {
|
|
1864
1910
|
return PayloadStatus.FULL;
|
|
1865
1911
|
}
|
|
1912
|
+
if (!isStatePostGloas(state)) {
|
|
1913
|
+
throw new Error(`Expected gloas+ state for checkpoint payload status, got fork=${state.forkName}`);
|
|
1914
|
+
}
|
|
1866
1915
|
|
|
1867
1916
|
// For Gloas, check state.execution_payload_availability
|
|
1868
1917
|
// - For non-skipped slots at checkpoint: returns false (EMPTY) since payload hasn't arrived yet
|
|
1869
1918
|
// - For skipped slots at checkpoint: returns the actual availability status from state
|
|
1870
|
-
const
|
|
1871
|
-
const payloadAvailable = gloasState.executionPayloadAvailability.get(checkpointSlot % SLOTS_PER_HISTORICAL_ROOT);
|
|
1919
|
+
const payloadAvailable = state.executionPayloadAvailability.get(checkpointSlot % SLOTS_PER_HISTORICAL_ROOT);
|
|
1872
1920
|
|
|
1873
1921
|
return payloadAvailable ? PayloadStatus.FULL : PayloadStatus.EMPTY;
|
|
1874
1922
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CachedBeaconStateAllForks,
|
|
3
|
-
DataAvailabilityStatus,
|
|
4
|
-
EffectiveBalanceIncrements,
|
|
5
|
-
} from "@lodestar/state-transition";
|
|
1
|
+
import {DataAvailabilityStatus, EffectiveBalanceIncrements, IBeaconStateView} from "@lodestar/state-transition";
|
|
6
2
|
import {AttesterSlashing, BeaconBlock, Epoch, IndexedAttestation, Root, RootHex, Slot} from "@lodestar/types";
|
|
7
3
|
import {
|
|
4
|
+
BlockExecutionStatus,
|
|
8
5
|
LVHExecResponse,
|
|
9
|
-
|
|
6
|
+
PayloadExecutionStatus,
|
|
10
7
|
PayloadStatus,
|
|
11
8
|
ProtoBlock,
|
|
12
9
|
ProtoNode,
|
|
@@ -144,10 +141,10 @@ export interface IForkChoice {
|
|
|
144
141
|
*/
|
|
145
142
|
onBlock(
|
|
146
143
|
block: BeaconBlock,
|
|
147
|
-
state:
|
|
144
|
+
state: IBeaconStateView,
|
|
148
145
|
blockDelaySec: number,
|
|
149
146
|
currentSlot: Slot,
|
|
150
|
-
executionStatus:
|
|
147
|
+
executionStatus: BlockExecutionStatus,
|
|
151
148
|
dataAvailabilityStatus: DataAvailabilityStatus
|
|
152
149
|
): ProtoBlock;
|
|
153
150
|
/**
|
|
@@ -207,7 +204,8 @@ export interface IForkChoice {
|
|
|
207
204
|
blockRoot: RootHex,
|
|
208
205
|
executionPayloadBlockHash: RootHex,
|
|
209
206
|
executionPayloadNumber: number,
|
|
210
|
-
executionPayloadStateRoot: RootHex
|
|
207
|
+
executionPayloadStateRoot: RootHex,
|
|
208
|
+
executionStatus: PayloadExecutionStatus
|
|
211
209
|
): void;
|
|
212
210
|
/**
|
|
213
211
|
* Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`.
|
|
@@ -228,6 +226,12 @@ export interface IForkChoice {
|
|
|
228
226
|
*/
|
|
229
227
|
hasBlockUnsafe(blockRoot: Root): boolean;
|
|
230
228
|
hasBlockHexUnsafe(blockRoot: RootHex): boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Returns true if the FULL payload variant (execution payload envelope) exists for this block root,
|
|
231
|
+
* without checking if the block is a descendant of the finalized root.
|
|
232
|
+
*/
|
|
233
|
+
hasPayloadUnsafe(blockRoot: Root): boolean;
|
|
234
|
+
hasPayloadHexUnsafe(blockRoot: RootHex): boolean;
|
|
231
235
|
getSlotsPresent(windowStart: number): number;
|
|
232
236
|
/**
|
|
233
237
|
* Returns a `ProtoBlock` if the block is known **and** a descendant of the finalized root.
|
package/src/forkChoice/store.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
4
|
import {PayloadStatus} from "../protoArray/interface.js";
|
|
@@ -30,7 +30,7 @@ export type JustifiedBalances = EffectiveBalanceIncrements;
|
|
|
30
30
|
*/
|
|
31
31
|
export type JustifiedBalancesGetter = (
|
|
32
32
|
checkpoint: CheckpointWithPayloadStatus,
|
|
33
|
-
blockState:
|
|
33
|
+
blockState: IBeaconStateView
|
|
34
34
|
) => JustifiedBalances;
|
|
35
35
|
|
|
36
36
|
/**
|
package/src/index.ts
CHANGED
|
@@ -31,10 +31,11 @@ export {
|
|
|
31
31
|
} from "./forkChoice/store.js";
|
|
32
32
|
export {type ForkChoiceMetrics, getForkChoiceMetrics} from "./metrics.js";
|
|
33
33
|
export type {
|
|
34
|
+
BlockExecutionStatus,
|
|
34
35
|
BlockExtraMeta,
|
|
35
36
|
LVHInvalidResponse,
|
|
36
37
|
LVHValidResponse,
|
|
37
|
-
|
|
38
|
+
PayloadExecutionStatus,
|
|
38
39
|
ProtoBlock,
|
|
39
40
|
ProtoNode,
|
|
40
41
|
} from "./protoArray/interface.js";
|
|
@@ -64,7 +64,18 @@ export type LVHInvalidResponse = {
|
|
|
64
64
|
};
|
|
65
65
|
export type LVHExecResponse = LVHValidResponse | LVHInvalidResponse;
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Any execution status that is not definitively invalid.
|
|
69
|
+
* Pre-Gloas: Valid | Syncing | PreMerge
|
|
70
|
+
* Post-Gloas: execution status must be PayloadSeparated (beacon block imported before its payload arrives via SignedExecutionPayloadEnvelope)
|
|
71
|
+
*/
|
|
72
|
+
export type BlockExecutionStatus = Exclude<ExecutionStatus, ExecutionStatus.Invalid>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Execution status for a block whose execution payload is present and has been submitted to the EL.
|
|
76
|
+
* Used post-Gloas when transitioning a PayloadSeparated block to FULL via onExecutionPayload().
|
|
77
|
+
*/
|
|
78
|
+
export type PayloadExecutionStatus = ExecutionStatus.Valid | ExecutionStatus.Syncing;
|
|
68
79
|
|
|
69
80
|
export type BlockExtraMeta =
|
|
70
81
|
| {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ExecutionStatus,
|
|
10
10
|
HEX_ZERO_HASH,
|
|
11
11
|
LVHExecResponse,
|
|
12
|
+
PayloadExecutionStatus,
|
|
12
13
|
PayloadStatus,
|
|
13
14
|
ProtoBlock,
|
|
14
15
|
ProtoNode,
|
|
@@ -541,7 +542,8 @@ export class ProtoArray {
|
|
|
541
542
|
executionPayloadBlockHash: RootHex,
|
|
542
543
|
executionPayloadNumber: number,
|
|
543
544
|
executionPayloadStateRoot: RootHex,
|
|
544
|
-
proposerBoostRoot: RootHex | null
|
|
545
|
+
proposerBoostRoot: RootHex | null,
|
|
546
|
+
executionStatus: PayloadExecutionStatus
|
|
545
547
|
): void {
|
|
546
548
|
// First check if block exists
|
|
547
549
|
const variants = this.indices.get(blockRoot);
|
|
@@ -591,7 +593,8 @@ export class ProtoArray {
|
|
|
591
593
|
weight: 0,
|
|
592
594
|
bestChild: undefined,
|
|
593
595
|
bestDescendant: undefined,
|
|
594
|
-
|
|
596
|
+
// TODO GLOAS: handle optimistic sync
|
|
597
|
+
executionStatus,
|
|
595
598
|
executionPayloadBlockHash,
|
|
596
599
|
executionPayloadNumber,
|
|
597
600
|
stateRoot: executionPayloadStateRoot,
|
|
@@ -650,9 +653,7 @@ export class ProtoArray {
|
|
|
650
653
|
}
|
|
651
654
|
|
|
652
655
|
// If payload is not locally available, it's not timely
|
|
653
|
-
|
|
654
|
-
const fullNodeIndex = this.getNodeIndexByRootAndStatus(blockRoot, PayloadStatus.FULL);
|
|
655
|
-
if (fullNodeIndex === undefined) {
|
|
656
|
+
if (!this.hasPayload(blockRoot)) {
|
|
656
657
|
return false;
|
|
657
658
|
}
|
|
658
659
|
|
|
@@ -1059,10 +1060,8 @@ export class ProtoArray {
|
|
|
1059
1060
|
});
|
|
1060
1061
|
}
|
|
1061
1062
|
|
|
1062
|
-
//
|
|
1063
|
-
const finalizedIndex = Array.isArray(variants)
|
|
1064
|
-
? Math.min(...variants.filter((idx) => idx !== undefined))
|
|
1065
|
-
: variants;
|
|
1063
|
+
// For Gloas, PENDING variant (index 0) is always the smallest since it's inserted first
|
|
1064
|
+
const finalizedIndex = Array.isArray(variants) ? variants[PayloadStatus.PENDING] : variants;
|
|
1066
1065
|
|
|
1067
1066
|
if (finalizedIndex < this.pruneThreshold) {
|
|
1068
1067
|
// Pruning at small numbers incurs more cost than benefit
|
|
@@ -1672,6 +1671,16 @@ export class ProtoArray {
|
|
|
1672
1671
|
return this.getDefaultNodeIndex(blockRoot) !== undefined;
|
|
1673
1672
|
}
|
|
1674
1673
|
|
|
1674
|
+
/**
|
|
1675
|
+
* Check if a FULL payload variant (execution payload envelope) exists for this block root.
|
|
1676
|
+
* Returns true once the SignedExecutionPayloadEnvelope for this block has been received and processed.
|
|
1677
|
+
*/
|
|
1678
|
+
hasPayload(blockRoot: RootHex): boolean {
|
|
1679
|
+
// we should also make sure this blockRoot is a gloas block, however we only call this function
|
|
1680
|
+
// starting from GLOAS_FORK_EPOCH, so we can assume the blockRoot is from gloas block
|
|
1681
|
+
return this.getNodeIndexByRootAndStatus(blockRoot, PayloadStatus.FULL) !== undefined;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1675
1684
|
/**
|
|
1676
1685
|
* Return ProtoNode for blockRoot with explicit payload status
|
|
1677
1686
|
*
|