@lodestar/state-transition 1.51.0-dev.4157a0dec4 → 1.51.0-dev.4e12403e39
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/beaconStateView.d.ts +1 -0
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +5 -1
- package/lib/stateView/beaconStateView.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/beaconStateView.ts +5 -1
- 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
package/src/stateTransition.ts
CHANGED
|
@@ -101,7 +101,7 @@ export function stateTransition(
|
|
|
101
101
|
let postState = state.clone(options.dontTransferCache);
|
|
102
102
|
|
|
103
103
|
if (metrics) {
|
|
104
|
-
onStateCloneMetrics(postState, metrics, StateCloneSource.stateTransition);
|
|
104
|
+
onStateCloneMetrics(postState, state.clonedCount, metrics, StateCloneSource.stateTransition);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// State is already a ViewDU, which won't commit changes. Equivalent to .setStateCachesAsTransient()
|
|
@@ -168,7 +168,7 @@ export function processSlots(
|
|
|
168
168
|
let postState = state.clone(opts?.dontTransferCache);
|
|
169
169
|
|
|
170
170
|
if (metrics) {
|
|
171
|
-
onStateCloneMetrics(postState, metrics, StateCloneSource.processSlots);
|
|
171
|
+
onStateCloneMetrics(postState, state.clonedCount, metrics, StateCloneSource.processSlots);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// State is already a ViewDU, which won't commit changes. Equivalent to .setStateCachesAsTransient()
|
|
@@ -84,6 +84,7 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
84
84
|
// phase0
|
|
85
85
|
private cachedFork: Fork | null = null;
|
|
86
86
|
private cachedLatestBlockHeader: phase0.BeaconBlockHeader | null = null;
|
|
87
|
+
private cachedEffectiveBalanceIncrementsZeroInactive: EffectiveBalanceIncrements | null = null;
|
|
87
88
|
// altair
|
|
88
89
|
private cachedCurrentSyncCommittee: SyncCommittee | null = null;
|
|
89
90
|
private cachedNextSyncCommittee: SyncCommittee | null = null;
|
|
@@ -638,7 +639,10 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
638
639
|
}
|
|
639
640
|
|
|
640
641
|
getEffectiveBalanceIncrementsZeroInactive(): EffectiveBalanceIncrements {
|
|
641
|
-
|
|
642
|
+
if (this.cachedEffectiveBalanceIncrementsZeroInactive === null) {
|
|
643
|
+
this.cachedEffectiveBalanceIncrementsZeroInactive = getEffectiveBalanceIncrementsZeroInactive(this.cachedState);
|
|
644
|
+
}
|
|
645
|
+
return this.cachedEffectiveBalanceIncrementsZeroInactive;
|
|
642
646
|
}
|
|
643
647
|
|
|
644
648
|
getBalance(index: number): number {
|
|
@@ -336,8 +336,6 @@ export type IBeaconStateViewLatestFork = Omit<
|
|
|
336
336
|
*/
|
|
337
337
|
export type IBeaconStateViewNative = Omit<
|
|
338
338
|
IBeaconStateViewLatestFork,
|
|
339
|
-
| "builderPendingPayments"
|
|
340
|
-
| "builderPendingWithdrawals"
|
|
341
339
|
| "computeAttestationsRewards"
|
|
342
340
|
| "computeBlockRewards"
|
|
343
341
|
| "computeNewStateRoot"
|
|
@@ -346,8 +344,6 @@ export type IBeaconStateViewNative = Omit<
|
|
|
346
344
|
| "eth1Data"
|
|
347
345
|
| "executionPayloadAvailability"
|
|
348
346
|
| "getBeaconCommittee"
|
|
349
|
-
| "getIndicesInPayloadTimelinessCommittee"
|
|
350
|
-
| "getPayloadTimelinessCommittee"
|
|
351
347
|
| "loadOtherState"
|
|
352
348
|
| "pendingConsolidations"
|
|
353
349
|
| "pendingDeposits"
|
|
@@ -365,7 +361,6 @@ export type IBeaconStateViewNative = Omit<
|
|
|
365
361
|
pendingPartialWithdrawals: Uint8Array;
|
|
366
362
|
pendingConsolidations: Uint8Array;
|
|
367
363
|
proposerLookahead: Uint32Array;
|
|
368
|
-
// UintBn64 lowers to number across the FFI boundary; the wrapper lifts it back to bigint
|
|
369
364
|
eth1Data: phase0.Eth1Data;
|
|
370
365
|
executionPayloadAvailability: {uint8Array: Uint8Array; bitLen: number};
|
|
371
366
|
computeBlockRewards(
|
|
@@ -379,8 +374,6 @@ export type IBeaconStateViewNative = Omit<
|
|
|
379
374
|
validatorIds: (ValidatorIndex | string)[]
|
|
380
375
|
): rewards.SyncCommitteeRewards;
|
|
381
376
|
getBeaconCommittee(slot: Slot, index: CommitteeIndex): Uint32Array;
|
|
382
|
-
getIndexInPayloadTimelinessCommittee?(validatorIndex: ValidatorIndex, slot: Slot): number;
|
|
383
|
-
getIndicesInPayloadTimelinessCommittee?(validatorIndex: ValidatorIndex, slot: Slot): number[];
|
|
384
377
|
loadOtherState(...args: Parameters<IBeaconStateViewLatestFork["loadOtherState"]>): IBeaconStateViewNative;
|
|
385
378
|
stateTransition(
|
|
386
379
|
signedBlockBytes: Uint8Array,
|
|
@@ -388,9 +381,7 @@ export type IBeaconStateViewNative = Omit<
|
|
|
388
381
|
options?: StateTransitionOpts
|
|
389
382
|
): IBeaconStateViewNative;
|
|
390
383
|
processSlots(slot: Slot, opts?: {dontTransferCache?: boolean}): IBeaconStateViewNative;
|
|
391
|
-
withParentPayloadApplied(
|
|
392
|
-
...args: Parameters<IBeaconStateViewLatestFork["withParentPayloadApplied"]>
|
|
393
|
-
): IBeaconStateViewNative;
|
|
384
|
+
withParentPayloadApplied(executionRequestsBytes: Uint8Array): IBeaconStateViewNative;
|
|
394
385
|
};
|
|
395
386
|
|
|
396
387
|
export function isStatePostAltair(state: IBeaconStateView): state is IBeaconStateViewAltair {
|
|
@@ -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
|
*/
|