@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.
Files changed (45) hide show
  1. package/lib/forkChoice/errors.d.ts +6 -1
  2. package/lib/forkChoice/errors.d.ts.map +1 -1
  3. package/lib/forkChoice/errors.js +1 -0
  4. package/lib/forkChoice/errors.js.map +1 -1
  5. package/lib/forkChoice/fastConfirmation/data.d.ts +1 -1
  6. package/lib/forkChoice/fastConfirmation/fastConfirmationRule.d.ts +4 -4
  7. package/lib/forkChoice/fastConfirmation/index.d.ts +3 -3
  8. package/lib/forkChoice/fastConfirmation/rules.d.ts +1 -1
  9. package/lib/forkChoice/fastConfirmation/types.d.ts +3 -3
  10. package/lib/forkChoice/fastConfirmation/types.d.ts.map +1 -1
  11. package/lib/forkChoice/fastConfirmation/utils.d.ts +3 -3
  12. package/lib/forkChoice/forkChoice.d.ts +5 -3
  13. package/lib/forkChoice/forkChoice.d.ts.map +1 -1
  14. package/lib/forkChoice/forkChoice.js +16 -8
  15. package/lib/forkChoice/forkChoice.js.map +1 -1
  16. package/lib/forkChoice/interface.d.ts +8 -8
  17. package/lib/forkChoice/interface.d.ts.map +1 -1
  18. package/lib/forkChoice/interface.js +1 -1
  19. package/lib/forkChoice/interface.js.map +1 -1
  20. package/lib/forkChoice/safeBlocks.d.ts +3 -11
  21. package/lib/forkChoice/safeBlocks.d.ts.map +1 -1
  22. package/lib/forkChoice/safeBlocks.js +21 -30
  23. package/lib/forkChoice/safeBlocks.js.map +1 -1
  24. package/lib/forkChoice/store.d.ts +1 -1
  25. package/lib/index.d.ts +1 -1
  26. package/lib/metrics.d.ts +2 -2
  27. package/lib/protoArray/protoArray.d.ts +4 -7
  28. package/lib/protoArray/protoArray.d.ts.map +1 -1
  29. package/lib/protoArray/protoArray.js +25 -19
  30. package/lib/protoArray/protoArray.js.map +1 -1
  31. package/package.json +7 -7
  32. package/src/forkChoice/errors.ts +3 -1
  33. package/src/forkChoice/fastConfirmation/data.ts +2 -2
  34. package/src/forkChoice/fastConfirmation/fastConfirmationRule.ts +6 -6
  35. package/src/forkChoice/fastConfirmation/index.ts +3 -3
  36. package/src/forkChoice/fastConfirmation/rules.ts +3 -3
  37. package/src/forkChoice/fastConfirmation/types.ts +3 -3
  38. package/src/forkChoice/fastConfirmation/utils.ts +3 -3
  39. package/src/forkChoice/forkChoice.ts +19 -9
  40. package/src/forkChoice/interface.ts +6 -6
  41. package/src/forkChoice/safeBlocks.ts +25 -33
  42. package/src/forkChoice/store.ts +1 -1
  43. package/src/index.ts +1 -1
  44. package/src/metrics.ts +1 -1
  45. 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.ts";
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.ts";
15
- import {findLatestConfirmedDescendant, getBlock, isAncestor, isConfirmedChainSafe} from "./utils.ts";
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.ts";
5
- import {CheckpointWithHex} from "../store.ts";
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.ts";
13
- import {CheckpointWithHex, computeTotalBalance, equalCheckpointWithHex} from "../store.ts";
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.ts";
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
- } from "./fastConfirmation/fastConfirmationRule.ts";
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
- getPayloadRevealCounts(fromSlot: Slot, toSlot: Slot): {blocksPresent: number; payloadsRevealed: number} {
618
- return this.protoArray.getPayloadRevealCounts(fromSlot, toSlot);
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
- // No reorg if we are at an epoch boundary
2078
- // https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.12/specs/phase0/fork-choice.md#is_not_epoch_boundary
2079
- const isAtEpochBoundary = slot % SLOTS_PER_EPOCH === 0;
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
- AtEpochBoundary = "atEpochBoundary",
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
- * Count gloas blocks with fromSlot <= slot <= toSlot and how many of them have a revealed
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, ZERO_HASH_HEX} from "@lodestar/params";
2
- import {Root, RootHex} from "@lodestar/types";
3
- import {LogLevel, Logger, fromHex} from "@lodestar/utils";
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.warn>): RootHex {
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
- logger?.warn("Confirmed block not found, using zero safe execution block hash", {
36
- confirmedRoot: forkChoice.getConfirmedRoot(),
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, logger);
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, logger?: Pick<Logger, LogLevel.warn>): RootHex {
51
- return getExecutionBlockHash(forkChoice.getFinalizedBlock(), logger);
41
+ export function getFinalizedExecutionBlockHash(forkChoice: IForkChoice): RootHex {
42
+ return getExecutionBlockHash(forkChoice.getFinalizedBlock());
52
43
  }
53
44
 
54
- function getExecutionBlockHash(block: ProtoBlock, logger?: Pick<Logger, LogLevel.warn>): RootHex {
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
- if (block.executionPayloadBlockHash === null) {
67
- logger?.warn("Execution payload block hash not found, using zero hash", {
68
- blockRoot: block.blockRoot,
69
- slot: block.slot,
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
  }
@@ -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.ts";
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.ts";
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.ts";
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
- * Count gloas blocks with fromSlot <= slot <= toSlot and how many of them have a revealed
695
- * payload (FULL variant exists). Used by the builder circuit breaker.
696
- */
697
- getPayloadRevealCounts(fromSlot: Slot, toSlot: Slot): {blocksPresent: number; payloadsRevealed: number} {
698
- let blocksPresent = 0;
699
- let payloadsRevealed = 0;
700
- // Full scan, nodes are in import order not slot order (an old block can be imported after newer
701
- // ones during sync or reorg resolution), so we cannot stop early on an out-of-window slot
702
- for (const node of this.nodes) {
703
- // Count each gloas block once via its PENDING variant, pre-gloas nodes are FULL only
704
- if (node.slot < fromSlot || node.slot > toSlot || node.payloadStatus !== PayloadStatus.PENDING) {
705
- continue;
706
- }
707
- blocksPresent++;
708
- if (this.hasPayload(node.blockRoot)) {
709
- payloadsRevealed++;
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
- return {blocksPresent, payloadsRevealed};
727
+
728
+ return {full, empty};
713
729
  }
714
730
 
715
731
  /**