@lodestar/state-transition 1.51.0-dev.fd649df985 → 1.51.0-dev.fe53cec080
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/metrics.d.ts +1 -1
- package/lib/metrics.d.ts.map +1 -1
- package/lib/metrics.js +4 -4
- package/lib/metrics.js.map +1 -1
- package/lib/signatureSets/inclusionList.d.ts +5 -0
- package/lib/signatureSets/inclusionList.d.ts.map +1 -0
- package/lib/signatureSets/inclusionList.js +14 -0
- package/lib/signatureSets/inclusionList.js.map +1 -0
- package/lib/signatureSets/index.d.ts +1 -0
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +1 -0
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/stateTransition.js +2 -2
- package/lib/stateTransition.js.map +1 -1
- package/lib/stateView/interface.d.ts +2 -4
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +14 -6
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js +85 -25
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/lib/stateView/stateViewFactory.js +3 -2
- package/lib/stateView/stateViewFactory.js.map +1 -1
- package/lib/util/inclusionListCommittee.d.ts +9 -0
- package/lib/util/inclusionListCommittee.d.ts.map +1 -0
- package/lib/util/inclusionListCommittee.js +18 -0
- package/lib/util/inclusionListCommittee.js.map +1 -0
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -0
- package/lib/util/index.js.map +1 -1
- package/lib/util/shuffling.d.ts +3 -0
- package/lib/util/shuffling.d.ts.map +1 -1
- package/lib/util/shuffling.js +41 -1
- package/lib/util/shuffling.js.map +1 -1
- package/package.json +8 -8
- package/src/metrics.ts +5 -4
- package/src/signatureSets/inclusionList.ts +20 -0
- package/src/signatureSets/index.ts +1 -0
- package/src/stateTransition.ts +2 -2
- package/src/stateView/interface.ts +1 -10
- package/src/stateView/nativeBeaconStateView.ts +86 -29
- package/src/stateView/stateViewFactory.ts +3 -2
- package/src/util/inclusionListCommittee.ts +17 -0
- package/src/util/index.ts +1 -0
- package/src/util/shuffling.ts +46 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
3
|
import type {BeaconConfig} from "@lodestar/config";
|
|
4
|
-
import {ForkName, ForkSeq} from "@lodestar/params";
|
|
4
|
+
import {ForkName, ForkPostElectra, ForkSeq} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
BeaconBlock,
|
|
7
7
|
BeaconState,
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
phase0,
|
|
29
29
|
rewards,
|
|
30
30
|
ssz,
|
|
31
|
+
sszTypesFor,
|
|
31
32
|
} from "@lodestar/types";
|
|
32
33
|
import {Checkpoint, Fork} from "@lodestar/types/phase0";
|
|
33
34
|
import {VoluntaryExitValidity} from "../block/processVoluntaryExit.js";
|
|
@@ -39,6 +40,7 @@ import {SyncCommitteeWitness} from "../lightClient/types.js";
|
|
|
39
40
|
import {StateTransitionModules, StateTransitionOpts} from "../stateTransition.js";
|
|
40
41
|
import {EpochShuffling} from "../util/epochShuffling.js";
|
|
41
42
|
import {PreVerifyBuilderDepositsResult} from "../util/preVerifyBuilderDeposits.js";
|
|
43
|
+
import {getStateSlotFromBytes} from "../util/sszBytes.js";
|
|
42
44
|
import {computeNewStateRootStateTransitionOpts, getComputeNewStateRootResult} from "./computeNewStateRoot.js";
|
|
43
45
|
import {
|
|
44
46
|
BlockSTFInput,
|
|
@@ -47,8 +49,15 @@ import {
|
|
|
47
49
|
IBeaconStateViewGloas,
|
|
48
50
|
IBeaconStateViewLatestFork,
|
|
49
51
|
IBeaconStateViewNative,
|
|
52
|
+
isStatePostGloas,
|
|
50
53
|
} from "./interface.js";
|
|
51
54
|
|
|
55
|
+
export function assertNativeForkSupported(config: BeaconConfig, slot: Slot): void {
|
|
56
|
+
if (config.getForkSeq(slot) > ForkSeq.gloas) {
|
|
57
|
+
throw Error(`Native state transition does not support ${config.getForkName(slot)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
/**
|
|
53
62
|
* Wraps a native binding (the auto-generated JS interface produced by a `.node`
|
|
54
63
|
* file) and exposes it as a fully-conformant `IBeaconStateViewLatestFork`.
|
|
@@ -115,6 +124,14 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
115
124
|
private cachedPendingConsolidationsCount: number | null = null;
|
|
116
125
|
// fulu
|
|
117
126
|
private cachedProposerLookahead: fulu.ProposerLookahead | null = null;
|
|
127
|
+
// gloas
|
|
128
|
+
private cachedLatestBlockHash: Bytes32 | null = null;
|
|
129
|
+
private cachedExecutionPayloadAvailability: BitArray | null = null;
|
|
130
|
+
private cachedLatestExecutionPayloadBid: ExecutionPayloadBid | null = null;
|
|
131
|
+
private cachedPayloadExpectedWithdrawals: capella.Withdrawal[] | null = null;
|
|
132
|
+
private cachedBuilderPendingPayments: gloas.BuilderPendingPayments | null = null;
|
|
133
|
+
private cachedBuilderPendingWithdrawals: gloas.BuilderPendingWithdrawals | null = null;
|
|
134
|
+
private cachedBuildersLength: number | null = null;
|
|
118
135
|
// Per-argument caches for argument-taking methods. The binding is treated as
|
|
119
136
|
// immutable for the view's lifetime, so a given argument always yields the
|
|
120
137
|
// same result. Maps grow only with touched arguments — typical call patterns
|
|
@@ -174,7 +191,11 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
174
191
|
}
|
|
175
192
|
|
|
176
193
|
get executionPayloadAvailability(): BitArray {
|
|
177
|
-
|
|
194
|
+
if (this.cachedExecutionPayloadAvailability === null) {
|
|
195
|
+
const {uint8Array, bitLen} = this.binding.executionPayloadAvailability;
|
|
196
|
+
this.cachedExecutionPayloadAvailability = new BitArray(uint8Array, bitLen);
|
|
197
|
+
}
|
|
198
|
+
return this.cachedExecutionPayloadAvailability;
|
|
178
199
|
}
|
|
179
200
|
|
|
180
201
|
// ─── phase0 ──────────────────────────────────────────────────────────────
|
|
@@ -598,6 +619,7 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
598
619
|
seedValidatorsBytes?: Uint8Array,
|
|
599
620
|
opts?: {preloadValidatorsAndBalances?: boolean}
|
|
600
621
|
): IBeaconStateView {
|
|
622
|
+
assertNativeForkSupported(this.config, getStateSlotFromBytes(stateBytes));
|
|
601
623
|
return new NativeBeaconStateView(this.config, this.binding.loadOtherState(stateBytes, seedValidatorsBytes, opts));
|
|
602
624
|
}
|
|
603
625
|
|
|
@@ -663,6 +685,7 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
663
685
|
options: StateTransitionOpts,
|
|
664
686
|
_modules: StateTransitionModules
|
|
665
687
|
): IBeaconStateView {
|
|
688
|
+
assertNativeForkSupported(this.config, block.message.slot);
|
|
666
689
|
const isBlinded = isBlindedBeaconBlock(block.message);
|
|
667
690
|
const signedBlockBytes =
|
|
668
691
|
ssz ??
|
|
@@ -675,6 +698,7 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
675
698
|
}
|
|
676
699
|
|
|
677
700
|
processSlots(slot: Slot, opts?: {dontTransferCache?: boolean}, _modules?: StateTransitionModules): IBeaconStateView {
|
|
701
|
+
assertNativeForkSupported(this.config, slot);
|
|
678
702
|
return new NativeBeaconStateView(this.config, this.binding.processSlots(slot, opts));
|
|
679
703
|
}
|
|
680
704
|
|
|
@@ -832,7 +856,8 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
832
856
|
|
|
833
857
|
get pendingDeposits(): electra.PendingDeposits {
|
|
834
858
|
if (this.cachedPendingDeposits === null) {
|
|
835
|
-
|
|
859
|
+
const type = sszTypesFor(this.forkName as ForkPostElectra).PendingDeposits;
|
|
860
|
+
this.cachedPendingDeposits = type.deserialize(this.binding.pendingDeposits);
|
|
836
861
|
}
|
|
837
862
|
return this.cachedPendingDeposits;
|
|
838
863
|
}
|
|
@@ -846,9 +871,8 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
846
871
|
|
|
847
872
|
get pendingPartialWithdrawals(): electra.PendingPartialWithdrawals {
|
|
848
873
|
if (this.cachedPendingPartialWithdrawals === null) {
|
|
849
|
-
this.
|
|
850
|
-
|
|
851
|
-
);
|
|
874
|
+
const type = sszTypesFor(this.forkName as ForkPostElectra).PendingPartialWithdrawals;
|
|
875
|
+
this.cachedPendingPartialWithdrawals = type.deserialize(this.binding.pendingPartialWithdrawals);
|
|
852
876
|
}
|
|
853
877
|
return this.cachedPendingPartialWithdrawals;
|
|
854
878
|
}
|
|
@@ -862,9 +886,8 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
862
886
|
|
|
863
887
|
get pendingConsolidations(): electra.PendingConsolidations {
|
|
864
888
|
if (this.cachedPendingConsolidations === null) {
|
|
865
|
-
this.
|
|
866
|
-
|
|
867
|
-
);
|
|
889
|
+
const type = sszTypesFor(this.forkName as ForkPostElectra).PendingConsolidations;
|
|
890
|
+
this.cachedPendingConsolidations = type.deserialize(this.binding.pendingConsolidations);
|
|
868
891
|
}
|
|
869
892
|
return this.cachedPendingConsolidations;
|
|
870
893
|
}
|
|
@@ -889,60 +912,94 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
889
912
|
_maxBuilderDeposits: number,
|
|
890
913
|
_maxDurationMs: number
|
|
891
914
|
): PreVerifyBuilderDepositsResult {
|
|
892
|
-
|
|
915
|
+
// The native fork upgrade verifies directly; it does not maintain a warm-up cache.
|
|
916
|
+
return {
|
|
917
|
+
validBuilderSignaturesCount: 0,
|
|
918
|
+
invalidBuilderSignaturesCount: 0,
|
|
919
|
+
validValidatorSignaturesCount: 0,
|
|
920
|
+
invalidValidatorSignaturesCount: 0,
|
|
921
|
+
scannedPendingDeposits: 0,
|
|
922
|
+
totalCachedDeposits: 0,
|
|
923
|
+
totalBuilderPubkeys: 0,
|
|
924
|
+
pendingDepositsCount: this.pendingDepositsCount,
|
|
925
|
+
};
|
|
893
926
|
}
|
|
894
927
|
|
|
895
928
|
clearPreGloasBuilderDepositCache(): void {
|
|
896
|
-
|
|
929
|
+
// The native implementation has no pre-Gloas deposit cache to clear.
|
|
897
930
|
}
|
|
898
931
|
|
|
899
932
|
// ─── gloas ───────────────────────────────────────────────────────────────
|
|
900
933
|
|
|
901
934
|
get latestBlockHash(): Bytes32 {
|
|
902
|
-
|
|
935
|
+
if (this.cachedLatestBlockHash === null) {
|
|
936
|
+
this.cachedLatestBlockHash = this.binding.latestBlockHash;
|
|
937
|
+
}
|
|
938
|
+
return this.cachedLatestBlockHash;
|
|
903
939
|
}
|
|
904
940
|
|
|
905
941
|
get latestExecutionPayloadBid(): ExecutionPayloadBid {
|
|
906
|
-
|
|
942
|
+
if (this.cachedLatestExecutionPayloadBid === null) {
|
|
943
|
+
this.cachedLatestExecutionPayloadBid = this.binding.latestExecutionPayloadBid;
|
|
944
|
+
}
|
|
945
|
+
return this.cachedLatestExecutionPayloadBid;
|
|
907
946
|
}
|
|
908
947
|
|
|
909
948
|
get payloadExpectedWithdrawals(): capella.Withdrawal[] {
|
|
910
|
-
|
|
949
|
+
if (this.cachedPayloadExpectedWithdrawals === null) {
|
|
950
|
+
this.cachedPayloadExpectedWithdrawals = this.binding.payloadExpectedWithdrawals;
|
|
951
|
+
}
|
|
952
|
+
return this.cachedPayloadExpectedWithdrawals;
|
|
911
953
|
}
|
|
912
954
|
|
|
913
955
|
get builderPendingPayments(): gloas.BuilderPendingPayments {
|
|
914
|
-
|
|
956
|
+
if (this.cachedBuilderPendingPayments === null) {
|
|
957
|
+
this.cachedBuilderPendingPayments = this.binding.builderPendingPayments;
|
|
958
|
+
}
|
|
959
|
+
return this.cachedBuilderPendingPayments;
|
|
915
960
|
}
|
|
916
961
|
|
|
917
962
|
get builderPendingWithdrawals(): gloas.BuilderPendingWithdrawals {
|
|
918
|
-
|
|
963
|
+
if (this.cachedBuilderPendingWithdrawals === null) {
|
|
964
|
+
this.cachedBuilderPendingWithdrawals = this.binding.builderPendingWithdrawals;
|
|
965
|
+
}
|
|
966
|
+
return this.cachedBuilderPendingWithdrawals;
|
|
919
967
|
}
|
|
920
968
|
|
|
921
|
-
getBuilder(
|
|
922
|
-
|
|
969
|
+
getBuilder(index: BuilderIndex): gloas.Builder {
|
|
970
|
+
return this.binding.getBuilder(index);
|
|
923
971
|
}
|
|
924
972
|
|
|
925
973
|
getBuildersLength(): number {
|
|
926
|
-
|
|
974
|
+
if (this.cachedBuildersLength === null) {
|
|
975
|
+
this.cachedBuildersLength = this.binding.getBuildersLength();
|
|
976
|
+
}
|
|
977
|
+
return this.cachedBuildersLength;
|
|
927
978
|
}
|
|
928
979
|
|
|
929
|
-
canBuilderCoverBid(
|
|
930
|
-
|
|
980
|
+
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
|
|
981
|
+
return this.binding.canBuilderCoverBid(builderIndex, bidAmount);
|
|
931
982
|
}
|
|
932
983
|
|
|
933
|
-
getEpochPTCs(
|
|
934
|
-
|
|
984
|
+
getEpochPTCs(epoch: Epoch): Uint32Array[] {
|
|
985
|
+
return this.binding.getEpochPTCs(epoch);
|
|
935
986
|
}
|
|
936
987
|
|
|
937
|
-
getPayloadTimelinessCommittee(
|
|
938
|
-
|
|
988
|
+
getPayloadTimelinessCommittee(slot: Slot): Uint32Array {
|
|
989
|
+
return this.binding.getPayloadTimelinessCommittee(slot);
|
|
939
990
|
}
|
|
940
991
|
|
|
941
|
-
getIndicesInPayloadTimelinessCommittee(
|
|
942
|
-
|
|
992
|
+
getIndicesInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number[] {
|
|
993
|
+
return this.binding.getIndicesInPayloadTimelinessCommittee(validatorIndex, slot);
|
|
943
994
|
}
|
|
944
995
|
|
|
945
|
-
withParentPayloadApplied(
|
|
946
|
-
|
|
996
|
+
withParentPayloadApplied(executionRequests: gloas.ExecutionRequests): IBeaconStateViewGloas {
|
|
997
|
+
const bytes = ssz.gloas.ExecutionRequests.serialize(executionRequests);
|
|
998
|
+
const state = new NativeBeaconStateView(this.config, this.binding.withParentPayloadApplied(bytes));
|
|
999
|
+
if (!isStatePostGloas(state)) {
|
|
1000
|
+
state.release();
|
|
1001
|
+
throw Error("Expected Gloas state after applying the parent payload");
|
|
1002
|
+
}
|
|
1003
|
+
return state;
|
|
947
1004
|
}
|
|
948
1005
|
}
|
|
@@ -2,10 +2,10 @@ import bindings from "@chainsafe/lodestar-z";
|
|
|
2
2
|
import {pubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
4
|
import {createCachedBeaconState} from "../cache/stateCache.js";
|
|
5
|
-
import {getStateTypeFromBytes} from "../util/sszBytes.js";
|
|
5
|
+
import {getStateSlotFromBytes, getStateTypeFromBytes} from "../util/sszBytes.js";
|
|
6
6
|
import {BeaconStateView} from "./beaconStateView.js";
|
|
7
7
|
import {IBeaconStateView, IBeaconStateViewNative} from "./interface.js";
|
|
8
|
-
import {NativeBeaconStateView} from "./nativeBeaconStateView.js";
|
|
8
|
+
import {NativeBeaconStateView, assertNativeForkSupported} from "./nativeBeaconStateView.js";
|
|
9
9
|
|
|
10
10
|
// ---- createBeaconStateView (startup path) ----
|
|
11
11
|
|
|
@@ -62,6 +62,7 @@ export function createBeaconStateViewForHistoricalRegen(opts: RegenNodeJSOpts |
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function createNativeBeaconStateView(config: BeaconConfig, stateBytes: Uint8Array): IBeaconStateView {
|
|
65
|
+
assertNativeForkSupported(config, getStateSlotFromBytes(stateBytes));
|
|
65
66
|
const nativeConfig = new bindings.BeaconConfig(config, config.genesisValidatorsRoot);
|
|
66
67
|
return new NativeBeaconStateView(
|
|
67
68
|
config,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {ValidatorIndex} from "@lodestar/types";
|
|
2
|
+
|
|
3
|
+
/** Spec `InclusionListCommittee` of one slot */
|
|
4
|
+
export class InclusionListCommittee {
|
|
5
|
+
constructor(readonly validatorIndices: Uint32Array) {}
|
|
6
|
+
|
|
7
|
+
/** Positions of `validatorIndex`, several when the committee cycles over a slot with fewer validators than its size */
|
|
8
|
+
getCommitteeIndices(validatorIndex: ValidatorIndex): number[] {
|
|
9
|
+
const committeeIndices: number[] = [];
|
|
10
|
+
for (let i = 0; i < this.validatorIndices.length; i++) {
|
|
11
|
+
if (this.validatorIndices[i] === validatorIndex) {
|
|
12
|
+
committeeIndices.push(i);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return committeeIndices;
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/util/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from "./execution.js";
|
|
|
17
17
|
export * from "./finality.js";
|
|
18
18
|
export * from "./genesis.js";
|
|
19
19
|
export * from "./gloas.js";
|
|
20
|
+
export * from "./inclusionListCommittee.js";
|
|
20
21
|
export * from "./interop.js";
|
|
21
22
|
export * from "./loadState/index.js";
|
|
22
23
|
export * from "./pendingDepositsLookup.js";
|
package/src/util/shuffling.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {ForkName, ForkSeq, SLOTS_PER_EPOCH, isForkPostFulu} from "@lodestar/params";
|
|
1
|
+
import {ForkName, ForkSeq, INCLUSION_LIST_COMMITTEE_SIZE, SLOTS_PER_EPOCH, isForkPostFulu} from "@lodestar/params";
|
|
2
2
|
import {
|
|
3
3
|
Attestation,
|
|
4
4
|
CommitteeIndex,
|
|
@@ -15,6 +15,7 @@ import {IBeaconStateView} from "../stateView/interface.js";
|
|
|
15
15
|
import {getBlockRootAtSlot} from "./blockRoot.js";
|
|
16
16
|
import {computeStartSlotAtEpoch} from "./epoch.js";
|
|
17
17
|
import {EpochShuffling} from "./epochShuffling.js";
|
|
18
|
+
import {InclusionListCommittee} from "./inclusionListCommittee.js";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Block root that decided the proposer shuffling for `proposalEpoch` (keys that shuffling).
|
|
@@ -196,6 +197,50 @@ export function getBeaconCommittee(epochShuffling: EpochShuffling, slot: Slot, i
|
|
|
196
197
|
return getBeaconCommittees(epochShuffling, slot, [index])[0];
|
|
197
198
|
}
|
|
198
199
|
|
|
200
|
+
/** Inclusion list committees of a shuffling by slot index, computed on first use and freed with the shuffling */
|
|
201
|
+
// TODO HEZE: replace this module-level map with an extended EpochShuffling tracked by the beacon-node ShufflingCache
|
|
202
|
+
const inclusionListCommitteesByShuffling = new WeakMap<EpochShuffling, InclusionListCommittee[]>();
|
|
203
|
+
|
|
204
|
+
/** Spec get_inclusion_list_committee: cycle over the slot's concatenated beacon committees */
|
|
205
|
+
export function getInclusionListCommittee(epochShuffling: EpochShuffling, slot: Slot): InclusionListCommittee {
|
|
206
|
+
let committees = inclusionListCommitteesByShuffling.get(epochShuffling);
|
|
207
|
+
if (committees === undefined) {
|
|
208
|
+
committees = [];
|
|
209
|
+
inclusionListCommitteesByShuffling.set(epochShuffling, committees);
|
|
210
|
+
}
|
|
211
|
+
const slotIndex = slot % SLOTS_PER_EPOCH;
|
|
212
|
+
let committee = committees[slotIndex];
|
|
213
|
+
if (committee === undefined) {
|
|
214
|
+
committee = new InclusionListCommittee(computeInclusionListCommittee(epochShuffling.committees[slotIndex]));
|
|
215
|
+
committees[slotIndex] = committee;
|
|
216
|
+
}
|
|
217
|
+
return committee;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function computeInclusionListCommittee(slotCommittees: Uint32Array[]): Uint32Array {
|
|
221
|
+
let totalLen = 0;
|
|
222
|
+
for (const committee of slotCommittees) {
|
|
223
|
+
totalLen += committee.length;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const result = new Uint32Array(INCLUSION_LIST_COMMITTEE_SIZE);
|
|
227
|
+
if (totalLen === 0) {
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
for (let i = 0; i < INCLUSION_LIST_COMMITTEE_SIZE; i++) {
|
|
232
|
+
let offset = i % totalLen;
|
|
233
|
+
for (const committee of slotCommittees) {
|
|
234
|
+
if (offset < committee.length) {
|
|
235
|
+
result[i] = committee[offset];
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
offset -= committee.length;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
199
244
|
/**
|
|
200
245
|
* Return a Uint32Array[] representing committees validator indices
|
|
201
246
|
*/
|