@lodestar/fork-choice 1.46.0 → 1.47.0-dev.09607ce6d4
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 +6 -1
- package/lib/forkChoice/errors.d.ts.map +1 -1
- package/lib/forkChoice/errors.js +1 -0
- package/lib/forkChoice/errors.js.map +1 -1
- package/lib/forkChoice/fastConfirmation/data.d.ts +1 -1
- package/lib/forkChoice/fastConfirmation/fastConfirmationRule.d.ts +4 -4
- package/lib/forkChoice/fastConfirmation/index.d.ts +3 -3
- package/lib/forkChoice/fastConfirmation/rules.d.ts +1 -1
- package/lib/forkChoice/fastConfirmation/types.d.ts +3 -3
- package/lib/forkChoice/fastConfirmation/types.d.ts.map +1 -1
- package/lib/forkChoice/fastConfirmation/utils.d.ts +3 -3
- package/lib/forkChoice/forkChoice.d.ts +5 -3
- package/lib/forkChoice/forkChoice.d.ts.map +1 -1
- package/lib/forkChoice/forkChoice.js +16 -8
- package/lib/forkChoice/forkChoice.js.map +1 -1
- package/lib/forkChoice/interface.d.ts +8 -8
- package/lib/forkChoice/interface.d.ts.map +1 -1
- package/lib/forkChoice/interface.js +1 -1
- package/lib/forkChoice/interface.js.map +1 -1
- package/lib/forkChoice/safeBlocks.d.ts +3 -11
- package/lib/forkChoice/safeBlocks.d.ts.map +1 -1
- package/lib/forkChoice/safeBlocks.js +21 -30
- package/lib/forkChoice/safeBlocks.js.map +1 -1
- package/lib/forkChoice/store.d.ts +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/metrics.d.ts +2 -2
- package/lib/protoArray/protoArray.d.ts +4 -7
- package/lib/protoArray/protoArray.d.ts.map +1 -1
- package/lib/protoArray/protoArray.js +25 -19
- package/lib/protoArray/protoArray.js.map +1 -1
- package/package.json +7 -7
- package/src/forkChoice/errors.ts +3 -1
- package/src/forkChoice/fastConfirmation/data.ts +2 -2
- package/src/forkChoice/fastConfirmation/fastConfirmationRule.ts +6 -6
- package/src/forkChoice/fastConfirmation/index.ts +3 -3
- package/src/forkChoice/fastConfirmation/rules.ts +3 -3
- package/src/forkChoice/fastConfirmation/types.ts +3 -3
- package/src/forkChoice/fastConfirmation/utils.ts +3 -3
- package/src/forkChoice/forkChoice.ts +19 -9
- package/src/forkChoice/interface.ts +6 -6
- package/src/forkChoice/safeBlocks.ts +25 -33
- package/src/forkChoice/store.ts +1 -1
- package/src/index.ts +1 -1
- package/src/metrics.ts +1 -1
- package/src/protoArray/protoArray.ts +35 -19
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {computeEpochAtSlot, isStartSlotOfEpoch} from "@lodestar/state-transition";
|
|
2
2
|
import {Logger} from "@lodestar/utils";
|
|
3
|
-
import {equalCheckpointWithHex} from "../store.
|
|
3
|
+
import {equalCheckpointWithHex} from "../store.js";
|
|
4
4
|
import {
|
|
5
5
|
FastConfirmationCache,
|
|
6
6
|
FastConfirmationContext,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
FastConfirmationSnapshot,
|
|
12
12
|
IFastConfirmationStore,
|
|
13
13
|
isResetReason,
|
|
14
|
-
} from "./types.
|
|
15
|
-
import {findLatestConfirmedDescendant, getBlock, isAncestor, isConfirmedChainSafe} from "./utils.
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
import {findLatestConfirmedDescendant, getBlock, isAncestor, isConfirmedChainSafe} from "./utils.js";
|
|
16
16
|
|
|
17
17
|
export const resetIfConfirmedUnavailable: FastConfirmationRule = (snapshot, ctx, _store, cache, decision) => {
|
|
18
18
|
const confirmedBlock = getBlock(ctx, cache, decision.confirmedRoot);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {EffectiveBalanceIncrements, IBeaconStateView} from "@lodestar/state-transition";
|
|
2
2
|
import {Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
3
3
|
import {Logger} from "@lodestar/utils";
|
|
4
|
-
import {ProtoBlock} from "../../protoArray/interface.
|
|
5
|
-
import {CheckpointWithHex} from "../store.
|
|
4
|
+
import {ProtoBlock} from "../../protoArray/interface.js";
|
|
5
|
+
import {CheckpointWithHex} from "../store.js";
|
|
6
6
|
|
|
7
7
|
export type FastConfirmationBalanceSource = {
|
|
8
8
|
state: IBeaconStateView | null;
|
|
@@ -15,7 +15,7 @@ export type ForkChoiceStateGetter = (
|
|
|
15
15
|
opts: {stateRoot: RootHex; checkpoint?: never} | {stateRoot?: never; checkpoint: CheckpointWithHex}
|
|
16
16
|
) => IBeaconStateView | null;
|
|
17
17
|
|
|
18
|
-
type IFastConfirmationSpecStore = {
|
|
18
|
+
export type IFastConfirmationSpecStore = {
|
|
19
19
|
confirmedRoot: RootHex;
|
|
20
20
|
previousEpochObservedJustifiedCheckpoint: CheckpointWithHex;
|
|
21
21
|
currentEpochObservedJustifiedCheckpoint: CheckpointWithHex;
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
} from "@lodestar/state-transition";
|
|
10
10
|
import {Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
11
11
|
import {Logger, fromHex} from "@lodestar/utils";
|
|
12
|
-
import {ExecutionStatus, ProtoBlock} from "../../protoArray/interface.
|
|
13
|
-
import {CheckpointWithHex, computeTotalBalance, equalCheckpointWithHex} from "../store.
|
|
12
|
+
import {ExecutionStatus, ProtoBlock} from "../../protoArray/interface.js";
|
|
13
|
+
import {CheckpointWithHex, computeTotalBalance, equalCheckpointWithHex} from "../store.js";
|
|
14
14
|
import {
|
|
15
15
|
type BalanceSourceKey,
|
|
16
16
|
FastConfirmationBalanceSource,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
FastConfirmationSnapshot,
|
|
20
20
|
IFastConfirmationStore,
|
|
21
21
|
type TotalActiveBalanceCacheKey,
|
|
22
|
-
} from "./types.
|
|
22
|
+
} from "./types.js";
|
|
23
23
|
|
|
24
24
|
// Spec: adjust_committee_weight_estimate_to_ensure_safety
|
|
25
25
|
// https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/fast-confirmation.md#adjust_committee_weight_estimate_to_ensure_safety
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
2
|
+
import {MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
DataAvailabilityStatus,
|
|
5
5
|
EffectiveBalanceIncrements,
|
|
@@ -49,7 +49,8 @@ import {
|
|
|
49
49
|
FastConfirmationRule,
|
|
50
50
|
FastConfirmationSteps,
|
|
51
51
|
type IFastConfirmationRule,
|
|
52
|
-
|
|
52
|
+
type IFastConfirmationSpecStore,
|
|
53
|
+
} from "./fastConfirmation/fastConfirmationRule.js";
|
|
53
54
|
import {
|
|
54
55
|
AncestorResult,
|
|
55
56
|
AncestorStatus,
|
|
@@ -228,6 +229,17 @@ export class ForkChoice implements IForkChoice {
|
|
|
228
229
|
return this.fastConfirmationRule?.getConfirmedRoot() ?? this.fcStore.justified.checkpoint.rootHex;
|
|
229
230
|
}
|
|
230
231
|
|
|
232
|
+
getFastConfirmationStore(): IFastConfirmationSpecStore {
|
|
233
|
+
return {
|
|
234
|
+
confirmedRoot: this.getConfirmedRoot(),
|
|
235
|
+
previousEpochObservedJustifiedCheckpoint: this.fcStore.previousEpochObservedJustifiedCheckpoint,
|
|
236
|
+
currentEpochObservedJustifiedCheckpoint: this.fcStore.currentEpochObservedJustifiedCheckpoint,
|
|
237
|
+
previousEpochGreatestUnrealizedCheckpoint: this.fcStore.previousEpochGreatestUnrealizedCheckpoint,
|
|
238
|
+
previousSlotHead: this.fcStore.previousSlotHead,
|
|
239
|
+
currentSlotHead: this.fcStore.currentSlotHead,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
231
243
|
getConfirmedBlock(): ProtoBlock | null {
|
|
232
244
|
return this.getBlockHexDefaultStatus(this.getConfirmedRoot());
|
|
233
245
|
}
|
|
@@ -614,8 +626,8 @@ export class ForkChoice implements IForkChoice {
|
|
|
614
626
|
return this.protoArray.nodes.filter((node) => node.slot > windowStart).length;
|
|
615
627
|
}
|
|
616
628
|
|
|
617
|
-
|
|
618
|
-
return this.protoArray.
|
|
629
|
+
getCanonicalPayloadCounts(fromSlot: Slot, toSlot: Slot, head: ProtoBlock): {full: number; empty: number} {
|
|
630
|
+
return this.protoArray.getCanonicalPayloadCounts(fromSlot, toSlot, head.blockRoot, head.payloadStatus);
|
|
619
631
|
}
|
|
620
632
|
|
|
621
633
|
/** Very expensive function, iterates the entire ProtoArray. Called only in debug API */
|
|
@@ -2074,11 +2086,9 @@ export class ForkChoice implements IForkChoice {
|
|
|
2074
2086
|
return {prelimProposerHead, prelimNotReorgedReason: NotReorgedReason.HeadBlockIsTimely};
|
|
2075
2087
|
}
|
|
2076
2088
|
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
if (isAtEpochBoundary) {
|
|
2081
|
-
return {prelimProposerHead, prelimNotReorgedReason: NotReorgedReason.AtEpochBoundary};
|
|
2089
|
+
const isShufflingStable = isForkPostFulu(this.config.getForkName(slot)) || slot % SLOTS_PER_EPOCH !== 0;
|
|
2090
|
+
if (!isShufflingStable) {
|
|
2091
|
+
return {prelimProposerHead, prelimNotReorgedReason: NotReorgedReason.NotShufflingStable};
|
|
2082
2092
|
}
|
|
2083
2093
|
|
|
2084
2094
|
// No reorg if headBlock and parentBlock are not ffg competitive
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ProtoBlock,
|
|
9
9
|
ProtoNode,
|
|
10
10
|
} from "../protoArray/interface.js";
|
|
11
|
+
import {IFastConfirmationSpecStore} from "./fastConfirmation/types.js";
|
|
11
12
|
import {UpdateAndGetHeadOpt} from "./forkChoice.js";
|
|
12
13
|
import {CheckpointWithHex} from "./store.js";
|
|
13
14
|
|
|
@@ -53,7 +54,7 @@ export enum NotReorgedReason {
|
|
|
53
54
|
HeadBlockIsTimely = "headBlockIsTimely",
|
|
54
55
|
ParentBlockNotAvailable = "parentBlockNotAvailable",
|
|
55
56
|
ProposerBoostReorgDisabled = "proposerBoostReorgDisabled",
|
|
56
|
-
|
|
57
|
+
NotShufflingStable = "notShufflingStable",
|
|
57
58
|
NotFFGCompetitive = "notFFGCompetitive",
|
|
58
59
|
ChainLongUnfinality = "chainLongUnfinality",
|
|
59
60
|
ParentBlockDistanceMoreThanOneSlot = "parentBlockDistanceMoreThanOneSlot",
|
|
@@ -100,6 +101,8 @@ export interface IForkChoice {
|
|
|
100
101
|
getHead(): ProtoBlock;
|
|
101
102
|
getConfirmedRoot(): RootHex;
|
|
102
103
|
getConfirmedBlock(): ProtoBlock | null;
|
|
104
|
+
/** Snapshot of the spec `FastConfirmationStore` fields, mirroring `get_fast_confirmation_store` */
|
|
105
|
+
getFastConfirmationStore(): IFastConfirmationSpecStore;
|
|
103
106
|
/** Resume the fast confirmation rule; restarts from the finalized root on the next slot tick */
|
|
104
107
|
resumeFastConfirmation(): void;
|
|
105
108
|
/** Pause the fast confirmation rule (e.g. while syncing); pins the confirmed root to the finalized root */
|
|
@@ -246,11 +249,8 @@ export interface IForkChoice {
|
|
|
246
249
|
hasPayloadUnsafe(blockRoot: Root): boolean;
|
|
247
250
|
hasPayloadHexUnsafe(blockRoot: RootHex): boolean;
|
|
248
251
|
getSlotsPresent(windowStart: number): number;
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
* payload (FULL variant exists). Used by the builder circuit breaker.
|
|
252
|
-
*/
|
|
253
|
-
getPayloadRevealCounts(fromSlot: Slot, toSlot: Slot): {blocksPresent: number; payloadsRevealed: number};
|
|
252
|
+
/** Count FULL and EMPTY blocks on the supplied head chain in the inclusive slot range. */
|
|
253
|
+
getCanonicalPayloadCounts(fromSlot: Slot, toSlot: Slot, head: ProtoBlock): {full: number; empty: number};
|
|
254
254
|
getPTCVotes(blockRootHex: RootHex): (boolean | null)[] | null;
|
|
255
255
|
/** Raw PTC vote tallies for the debug fork choice endpoint; `null` for pre-Gloas roots. */
|
|
256
256
|
getPTCVoteCounts(blockRootHex: RootHex): {
|
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
import {GENESIS_SLOT
|
|
2
|
-
import {
|
|
3
|
-
import {LogLevel, Logger
|
|
4
|
-
import {HEX_ZERO_HASH, ProtoBlock, isGloasBlock} from "../protoArray/interface.js";
|
|
1
|
+
import {GENESIS_SLOT} from "@lodestar/params";
|
|
2
|
+
import {RootHex} from "@lodestar/types";
|
|
3
|
+
import {LogLevel, Logger} from "@lodestar/utils";
|
|
4
|
+
import {ExecutionStatus, HEX_ZERO_HASH, ProtoBlock, isGloasBlock} from "../protoArray/interface.js";
|
|
5
|
+
import {ForkChoiceError, ForkChoiceErrorCode} from "./errors.js";
|
|
5
6
|
import {IForkChoice} from "./interface.js";
|
|
6
7
|
|
|
7
|
-
/**
|
|
8
|
-
* Under honest majority and certain network synchronicity assumptions there exists a block
|
|
9
|
-
* that is safe from re-orgs. Normally this block is pretty close to the head of canonical
|
|
10
|
-
* chain which makes it valuable to expose a safe block to users.
|
|
11
|
-
*
|
|
12
|
-
* @deprecated The merged fast-confirmation spec only defines `get_safe_execution_block_hash`.
|
|
13
|
-
*/
|
|
14
|
-
export function getSafeBeaconBlockRoot(fc: IForkChoice): Root {
|
|
15
|
-
const confirmedRoot = fc.getConfirmedRoot();
|
|
16
|
-
if (confirmedRoot && fc.hasBlockHex(confirmedRoot)) {
|
|
17
|
-
return fromHex(confirmedRoot);
|
|
18
|
-
}
|
|
19
|
-
return fc.getJustifiedCheckpoint().root;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
8
|
/**
|
|
23
9
|
* Get execution payload hash to report as `safeBlockHash` in `engine_forkchoiceUpdated`.
|
|
24
10
|
*
|
|
@@ -29,16 +15,21 @@ export function getSafeBeaconBlockRoot(fc: IForkChoice): Root {
|
|
|
29
15
|
*
|
|
30
16
|
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.13/specs/bellatrix/fast-confirmation.md#new-get_safe_execution_block_hash
|
|
31
17
|
*/
|
|
32
|
-
export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick<Logger, LogLevel.
|
|
18
|
+
export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick<Logger, LogLevel.debug>): RootHex {
|
|
19
|
+
const confirmedRoot = forkChoice.getConfirmedRoot();
|
|
33
20
|
const confirmedBlock = forkChoice.getConfirmedBlock();
|
|
34
21
|
if (confirmedBlock === null) {
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
throw new ForkChoiceError({code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK, root: confirmedRoot});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (confirmedBlock.blockRoot === forkChoice.getFinalizedBlock().blockRoot) {
|
|
26
|
+
logger?.debug("Confirmed block is the finalized block", {
|
|
27
|
+
blockRoot: confirmedBlock.blockRoot,
|
|
28
|
+
slot: confirmedBlock.slot,
|
|
37
29
|
});
|
|
38
|
-
return ZERO_HASH_HEX;
|
|
39
30
|
}
|
|
40
31
|
|
|
41
|
-
return getExecutionBlockHash(confirmedBlock
|
|
32
|
+
return getExecutionBlockHash(confirmedBlock);
|
|
42
33
|
}
|
|
43
34
|
|
|
44
35
|
/**
|
|
@@ -47,11 +38,11 @@ export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick
|
|
|
47
38
|
*
|
|
48
39
|
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.13/specs/gloas/fork-choice.md#notify_forkchoice_updated
|
|
49
40
|
*/
|
|
50
|
-
export function getFinalizedExecutionBlockHash(forkChoice: IForkChoice
|
|
51
|
-
return getExecutionBlockHash(forkChoice.getFinalizedBlock()
|
|
41
|
+
export function getFinalizedExecutionBlockHash(forkChoice: IForkChoice): RootHex {
|
|
42
|
+
return getExecutionBlockHash(forkChoice.getFinalizedBlock());
|
|
52
43
|
}
|
|
53
44
|
|
|
54
|
-
function getExecutionBlockHash(block: ProtoBlock
|
|
45
|
+
function getExecutionBlockHash(block: ProtoBlock): RootHex {
|
|
55
46
|
if (isGloasBlock(block)) {
|
|
56
47
|
return block.parentBlockHash;
|
|
57
48
|
}
|
|
@@ -63,13 +54,14 @@ function getExecutionBlockHash(block: ProtoBlock, logger?: Pick<Logger, LogLevel
|
|
|
63
54
|
return HEX_ZERO_HASH;
|
|
64
55
|
}
|
|
65
56
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
const {blockRoot, slot} = block;
|
|
58
|
+
if (block.executionPayloadBlockHash === null && block.executionStatus !== ExecutionStatus.PreMerge) {
|
|
59
|
+
throw new ForkChoiceError({
|
|
60
|
+
code: ForkChoiceErrorCode.MISSING_EXECUTION_PAYLOAD_BLOCK_HASH,
|
|
61
|
+
root: blockRoot,
|
|
62
|
+
slot,
|
|
70
63
|
});
|
|
71
|
-
return HEX_ZERO_HASH;
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
return block.executionPayloadBlockHash;
|
|
66
|
+
return block.executionPayloadBlockHash ?? HEX_ZERO_HASH;
|
|
75
67
|
}
|
package/src/forkChoice/store.ts
CHANGED
|
@@ -1,7 +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 {ForkChoiceStateGetter, IFastConfirmationStore} from "./fastConfirmation/types.
|
|
4
|
+
import {ForkChoiceStateGetter, IFastConfirmationStore} from "./fastConfirmation/types.js";
|
|
5
5
|
import {CheckpointWithBalance, CheckpointWithTotalBalance} from "./interface.js";
|
|
6
6
|
|
|
7
7
|
/**
|
package/src/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ export {
|
|
|
16
16
|
type IFastConfirmationRule,
|
|
17
17
|
type IFastConfirmationStore,
|
|
18
18
|
getFastConfirmationMetrics,
|
|
19
|
-
} from "./forkChoice/fastConfirmation/fastConfirmationRule.
|
|
19
|
+
} from "./forkChoice/fastConfirmation/fastConfirmationRule.js";
|
|
20
20
|
export {ForkChoice, type ForkChoiceOpts, UpdateHeadOpt, getCommitteeFraction} from "./forkChoice/forkChoice.js";
|
|
21
21
|
export {
|
|
22
22
|
type AncestorResult,
|
package/src/metrics.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {MetricsRegisterExtra} from "@lodestar/utils";
|
|
2
|
-
import {FastConfirmationMetrics, getFastConfirmationMetrics} from "./forkChoice/fastConfirmation/metrics.
|
|
2
|
+
import {FastConfirmationMetrics, getFastConfirmationMetrics} from "./forkChoice/fastConfirmation/metrics.js";
|
|
3
3
|
import {UpdateHeadOpt} from "./forkChoice/forkChoice.js";
|
|
4
4
|
import {NotReorgedReason} from "./forkChoice/interface.js";
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {BitArray} from "@chainsafe/ssz";
|
|
2
|
-
import {GENESIS_EPOCH, PTC_SIZE} from "@lodestar/params";
|
|
2
|
+
import {GENESIS_EPOCH, GENESIS_SLOT, PTC_SIZE} from "@lodestar/params";
|
|
3
3
|
import {DataAvailabilityStatus, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
4
4
|
import {Epoch, RootHex, Slot} from "@lodestar/types";
|
|
5
5
|
import {bitCount, toRootHex} from "@lodestar/utils";
|
|
@@ -690,26 +690,42 @@ export class ProtoArray {
|
|
|
690
690
|
this.maybeUpdateBestChildAndDescendant(pendingIndex, fullIndex, currentSlot, proposerBoostRoot);
|
|
691
691
|
}
|
|
692
692
|
|
|
693
|
-
/**
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
693
|
+
/** Count blocks selected as FULL or EMPTY by the supplied head chain in the inclusive slot range. */
|
|
694
|
+
getCanonicalPayloadCounts(
|
|
695
|
+
fromSlot: Slot,
|
|
696
|
+
toSlot: Slot,
|
|
697
|
+
headRoot: RootHex,
|
|
698
|
+
headPayloadStatus: PayloadStatus
|
|
699
|
+
): {full: number; empty: number} {
|
|
700
|
+
let full = 0;
|
|
701
|
+
let empty = 0;
|
|
702
|
+
|
|
703
|
+
// Walk the canonical chain newest-first from the head, following ancestors via `getParentNodeIndex`.
|
|
704
|
+
// Ancestors are strictly slot-descending, so we stop as soon as a node falls below `fromSlot`
|
|
705
|
+
// instead of materializing the whole chain back to the anchor as `getAllAncestorNodes` does.
|
|
706
|
+
// This keeps the scan O(window) rather than O(chain-to-anchor), relevant under prolonged non-finality.
|
|
707
|
+
const headIndex = this.getNodeIndexByRootAndStatus(headRoot, headPayloadStatus);
|
|
708
|
+
let node = headIndex !== undefined ? this.nodes[headIndex] : undefined;
|
|
709
|
+
|
|
710
|
+
while (node !== undefined && node.slot >= fromSlot) {
|
|
711
|
+
if (
|
|
712
|
+
node.slot !== GENESIS_SLOT &&
|
|
713
|
+
node.slot <= toSlot &&
|
|
714
|
+
isGloasBlock(node) &&
|
|
715
|
+
node.payloadStatus !== PayloadStatus.PENDING
|
|
716
|
+
) {
|
|
717
|
+
if (node.payloadStatus === PayloadStatus.FULL) {
|
|
718
|
+
full++;
|
|
719
|
+
} else {
|
|
720
|
+
empty++;
|
|
721
|
+
}
|
|
710
722
|
}
|
|
723
|
+
|
|
724
|
+
const parentIndex = this.getParentNodeIndex(node);
|
|
725
|
+
node = parentIndex === undefined ? undefined : this.nodes[parentIndex];
|
|
711
726
|
}
|
|
712
|
-
|
|
727
|
+
|
|
728
|
+
return {full, empty};
|
|
713
729
|
}
|
|
714
730
|
|
|
715
731
|
/**
|