@lodestar/state-transition 1.42.0 → 1.43.0-dev.0bc48d3b54
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/block/processDepositRequest.d.ts +11 -2
- package/lib/block/processDepositRequest.d.ts.map +1 -1
- package/lib/block/processDepositRequest.js +34 -4
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadEnvelope.js +7 -3
- package/lib/block/processExecutionPayloadEnvelope.js.map +1 -1
- package/lib/cache/epochCache.d.ts +3 -1
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +31 -13
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/epochTransitionCache.d.ts +5 -0
- package/lib/cache/epochTransitionCache.d.ts.map +1 -1
- package/lib/cache/epochTransitionCache.js +1 -0
- package/lib/cache/epochTransitionCache.js.map +1 -1
- package/lib/epoch/index.d.ts +3 -1
- package/lib/epoch/index.d.ts.map +1 -1
- package/lib/epoch/index.js +8 -1
- package/lib/epoch/index.js.map +1 -1
- package/lib/epoch/processPtcWindow.d.ts +11 -0
- package/lib/epoch/processPtcWindow.d.ts.map +1 -0
- package/lib/epoch/processPtcWindow.js +28 -0
- package/lib/epoch/processPtcWindow.js.map +1 -0
- package/lib/index.d.ts +4 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.js +4 -0
- package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
- package/lib/signatureSets/voluntaryExits.d.ts +2 -2
- package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
- package/lib/signatureSets/voluntaryExits.js +4 -0
- package/lib/signatureSets/voluntaryExits.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +2 -1
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateTransition.d.ts +1 -2
- package/lib/stateTransition.d.ts.map +1 -1
- package/lib/stateTransition.js +1 -2
- package/lib/stateTransition.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +10 -10
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +37 -34
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +103 -52
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js +22 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/util/attestation.d.ts +12 -1
- package/lib/util/attestation.d.ts.map +1 -1
- package/lib/util/attestation.js +23 -8
- package/lib/util/attestation.js.map +1 -1
- package/lib/util/execution.d.ts +4 -2
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +7 -0
- package/lib/util/execution.js.map +1 -1
- package/lib/util/gloas.d.ts +7 -1
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +26 -1
- package/lib/util/gloas.js.map +1 -1
- package/package.json +8 -8
- package/src/block/processDepositRequest.ts +50 -5
- package/src/block/processExecutionPayloadEnvelope.ts +8 -3
- package/src/cache/epochCache.ts +32 -30
- package/src/cache/epochTransitionCache.ts +7 -0
- package/src/epoch/index.ts +9 -0
- package/src/epoch/processPtcWindow.ts +38 -0
- package/src/index.ts +20 -2
- package/src/signatureSets/executionPayloadEnvelope.ts +5 -1
- package/src/signatureSets/voluntaryExits.ts +5 -2
- package/src/slot/upgradeStateToGloas.ts +2 -1
- package/src/stateTransition.ts +1 -2
- package/src/stateView/beaconStateView.ts +57 -41
- package/src/stateView/interface.ts +155 -74
- package/src/util/attestation.ts +37 -8
- package/src/util/execution.ts +11 -1
- package/src/util/gloas.ts +48 -1
|
@@ -3,7 +3,7 @@ import {BeaconConfig} from "@lodestar/config";
|
|
|
3
3
|
import {ForkSeq} from "@lodestar/params";
|
|
4
4
|
import {SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types";
|
|
5
5
|
import {PubkeyCache} from "../cache/pubkeyCache.js";
|
|
6
|
-
import {IBeaconStateView} from "../stateView/interface.js";
|
|
6
|
+
import {IBeaconStateView, IBeaconStateViewGloas, isStatePostGloas} from "../stateView/interface.js";
|
|
7
7
|
import {
|
|
8
8
|
ISignatureSet,
|
|
9
9
|
SignatureSetType,
|
|
@@ -34,6 +34,9 @@ export function getVoluntaryExitSignatureSet(
|
|
|
34
34
|
const fork = config.getForkSeq(state.slot);
|
|
35
35
|
|
|
36
36
|
if (fork >= ForkSeq.gloas && isBuilderVoluntaryExit(signedVoluntaryExit)) {
|
|
37
|
+
if (!isStatePostGloas(state)) {
|
|
38
|
+
throw new Error(`Expected gloas+ state for builder voluntary exit signature, got fork=${state.forkName}`);
|
|
39
|
+
}
|
|
37
40
|
return getBuilderVoluntaryExitSignatureSet(config, state, signedVoluntaryExit);
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -68,7 +71,7 @@ export function getValidatorVoluntaryExitSignatureSet(
|
|
|
68
71
|
|
|
69
72
|
export function getBuilderVoluntaryExitSignatureSet(
|
|
70
73
|
config: BeaconConfig,
|
|
71
|
-
state:
|
|
74
|
+
state: IBeaconStateViewGloas,
|
|
72
75
|
signedVoluntaryExit: phase0.SignedVoluntaryExit
|
|
73
76
|
): ISignatureSet {
|
|
74
77
|
const messageSlot = computeStartSlotAtEpoch(signedVoluntaryExit.message.epoch);
|
|
@@ -5,7 +5,7 @@ import {isValidDepositSignature} from "../block/processDeposit.js";
|
|
|
5
5
|
import {applyDepositForBuilder} from "../block/processDepositRequest.js";
|
|
6
6
|
import {getCachedBeaconState} from "../cache/stateCache.js";
|
|
7
7
|
import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
8
|
-
import {isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
8
|
+
import {initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
9
9
|
import {isValidatorKnown} from "../util/index.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -61,6 +61,7 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
61
61
|
stateGloasView.pendingPartialWithdrawals = stateGloasCloned.pendingPartialWithdrawals;
|
|
62
62
|
stateGloasView.pendingConsolidations = stateGloasCloned.pendingConsolidations;
|
|
63
63
|
stateGloasView.proposerLookahead = stateGloasCloned.proposerLookahead;
|
|
64
|
+
stateGloasView.ptcWindow = ssz.gloas.PtcWindow.toViewDU(initializePtcWindow(stateFulu));
|
|
64
65
|
|
|
65
66
|
for (let i = 0; i < SLOTS_PER_HISTORICAL_ROOT; i++) {
|
|
66
67
|
stateGloasView.executionPayloadAvailability.set(i, true);
|
package/src/stateTransition.ts
CHANGED
|
@@ -76,7 +76,6 @@ export enum StateHashTreeRootSource {
|
|
|
76
76
|
prepareNextEpoch = "prepare_next_epoch",
|
|
77
77
|
regenState = "regen_state",
|
|
78
78
|
computeNewStateRoot = "compute_new_state_root",
|
|
79
|
-
computeEnvelopeStateRoot = "compute_envelope_state_root",
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
/**
|
|
@@ -283,7 +282,7 @@ function processSlotsWithTransientCache(
|
|
|
283
282
|
{
|
|
284
283
|
const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.finalProcessEpoch});
|
|
285
284
|
// last step to prepare epoch data that depends on the upgraded state, for example proposerLookahead of BeaconStateFulu
|
|
286
|
-
postState.epochCtx.finalProcessEpoch(postState);
|
|
285
|
+
postState.epochCtx.finalProcessEpoch(postState, epochTransitionCache);
|
|
287
286
|
timer?.();
|
|
288
287
|
}
|
|
289
288
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {CompactMultiProof, ProofType, Tree, createProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
|
-
import {ForkSeq, SLOTS_PER_HISTORICAL_ROOT, isForkPostGloas} from "@lodestar/params";
|
|
4
|
+
import {ForkName, ForkSeq, SLOTS_PER_HISTORICAL_ROOT, isForkPostGloas} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
BeaconBlock,
|
|
7
7
|
BeaconState,
|
|
@@ -59,14 +59,19 @@ import {getBlockRootAtSlot} from "../util/blockRoot.js";
|
|
|
59
59
|
import {computeAnchorCheckpoint} from "../util/computeAnchorCheckpoint.js";
|
|
60
60
|
import {computeEpochAtSlot, computeStartSlotAtEpoch} from "../util/epoch.js";
|
|
61
61
|
import {EpochShuffling} from "../util/epochShuffling.js";
|
|
62
|
-
import {
|
|
62
|
+
import {
|
|
63
|
+
isExecutionEnabled,
|
|
64
|
+
isExecutionStateType,
|
|
65
|
+
isGloasStateType,
|
|
66
|
+
isMergeTransitionComplete,
|
|
67
|
+
} from "../util/execution.js";
|
|
63
68
|
import {canBuilderCoverBid} from "../util/gloas.js";
|
|
64
69
|
import {loadState} from "../util/loadState/loadState.js";
|
|
65
70
|
import {getRandaoMix} from "../util/seed.js";
|
|
66
71
|
import {getLatestWeakSubjectivityCheckpointEpoch} from "../util/weakSubjectivity.js";
|
|
67
|
-
import {IBeaconStateView} from "./interface.js";
|
|
72
|
+
import {IBeaconStateView, IBeaconStateViewLatestFork} from "./interface.js";
|
|
68
73
|
|
|
69
|
-
export class BeaconStateView implements
|
|
74
|
+
export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
70
75
|
private readonly config: BeaconConfig;
|
|
71
76
|
// Cached values extracted from the tree
|
|
72
77
|
// phase0
|
|
@@ -79,8 +84,6 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
79
84
|
private _currentEpochParticipation: Uint8Array | null = null;
|
|
80
85
|
// bellatrix
|
|
81
86
|
private _latestExecutionPayloadHeader: ExecutionPayloadHeader | null = null;
|
|
82
|
-
// Caches the cross-fork latestBlockHash value
|
|
83
|
-
private _latestBlockHash: Bytes32 | null = null;
|
|
84
87
|
// capella
|
|
85
88
|
private _historicalSummaries: capella.HistoricalSummaries | null = null;
|
|
86
89
|
// electra
|
|
@@ -92,6 +95,7 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
92
95
|
// gloas
|
|
93
96
|
private _executionPayloadAvailability: BitArray | null = null;
|
|
94
97
|
private _latestExecutionPayloadBid: ExecutionPayloadBid | null = null;
|
|
98
|
+
private _payloadExpectedWithdrawals: capella.Withdrawal[] | null = null;
|
|
95
99
|
|
|
96
100
|
constructor(readonly cachedState: CachedBeaconStateAllForks) {
|
|
97
101
|
this.config = cachedState.config;
|
|
@@ -99,6 +103,10 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
99
103
|
|
|
100
104
|
// phase0
|
|
101
105
|
|
|
106
|
+
get forkName(): ForkName {
|
|
107
|
+
return this.config.getForkName(this.cachedState.slot);
|
|
108
|
+
}
|
|
109
|
+
|
|
102
110
|
get slot(): number {
|
|
103
111
|
return this.cachedState.slot;
|
|
104
112
|
}
|
|
@@ -208,9 +216,13 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
208
216
|
// bellatrix
|
|
209
217
|
|
|
210
218
|
get latestExecutionPayloadHeader(): ExecutionPayloadHeader {
|
|
211
|
-
|
|
219
|
+
const forkSeq = this.config.getForkSeq(this.cachedState.slot);
|
|
220
|
+
if (forkSeq < ForkSeq.bellatrix) {
|
|
212
221
|
throw new Error("latestExecutionPayloadHeader is not available before Bellatrix");
|
|
213
222
|
}
|
|
223
|
+
if (forkSeq >= ForkSeq.gloas) {
|
|
224
|
+
throw new Error("latestExecutionPayloadHeader is not available after Gloas");
|
|
225
|
+
}
|
|
214
226
|
|
|
215
227
|
if (this._latestExecutionPayloadHeader === null) {
|
|
216
228
|
this._latestExecutionPayloadHeader = (
|
|
@@ -221,30 +233,6 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
221
233
|
return this._latestExecutionPayloadHeader;
|
|
222
234
|
}
|
|
223
235
|
|
|
224
|
-
/**
|
|
225
|
-
* Cross-fork accessor for the execution block hash of the most recently included payload.
|
|
226
|
-
* Pre-gloas: reads from latestExecutionPayloadHeader.blockHash.
|
|
227
|
-
* Gloas+: reads the dedicated latestBlockHash field (EIP-7732).
|
|
228
|
-
*/
|
|
229
|
-
get latestBlockHash(): Bytes32 {
|
|
230
|
-
const forkSeq = this.config.getForkSeq(this.cachedState.slot);
|
|
231
|
-
if (forkSeq < ForkSeq.bellatrix) {
|
|
232
|
-
throw new Error("latestBlockHash is not available before Bellatrix");
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (this._latestBlockHash === null) {
|
|
236
|
-
if (forkSeq >= ForkSeq.gloas) {
|
|
237
|
-
this._latestBlockHash = (this.cachedState as CachedBeaconStateGloas).latestBlockHash;
|
|
238
|
-
} else {
|
|
239
|
-
this._latestBlockHash = (
|
|
240
|
-
this.cachedState as CachedBeaconStateExecutions
|
|
241
|
-
).latestExecutionPayloadHeader.blockHash;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return this._latestBlockHash;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
236
|
/**
|
|
249
237
|
* The execution block number of the most recently included payload.
|
|
250
238
|
* Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
|
|
@@ -355,9 +343,16 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
355
343
|
|
|
356
344
|
// gloas
|
|
357
345
|
|
|
346
|
+
get latestBlockHash(): Bytes32 {
|
|
347
|
+
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
348
|
+
throw new Error("latestBlockHash is not available before Gloas");
|
|
349
|
+
}
|
|
350
|
+
return (this.cachedState as CachedBeaconStateGloas).latestBlockHash;
|
|
351
|
+
}
|
|
352
|
+
|
|
358
353
|
get executionPayloadAvailability(): BitArray {
|
|
359
354
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
360
|
-
throw new Error("executionPayloadAvailability is not available before
|
|
355
|
+
throw new Error("executionPayloadAvailability is not available before Gloas");
|
|
361
356
|
}
|
|
362
357
|
|
|
363
358
|
if (this._executionPayloadAvailability === null) {
|
|
@@ -371,7 +366,7 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
371
366
|
|
|
372
367
|
get latestExecutionPayloadBid(): ExecutionPayloadBid {
|
|
373
368
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
374
|
-
throw new Error("latestExecutionPayloadBid is not available before
|
|
369
|
+
throw new Error("latestExecutionPayloadBid is not available before Gloas");
|
|
375
370
|
}
|
|
376
371
|
|
|
377
372
|
if (this._latestExecutionPayloadBid === null) {
|
|
@@ -382,9 +377,22 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
382
377
|
return this._latestExecutionPayloadBid;
|
|
383
378
|
}
|
|
384
379
|
|
|
380
|
+
get payloadExpectedWithdrawals(): capella.Withdrawal[] {
|
|
381
|
+
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
382
|
+
throw new Error("payloadExpectedWithdrawals is not available before Gloas");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (this._payloadExpectedWithdrawals === null) {
|
|
386
|
+
this._payloadExpectedWithdrawals = (
|
|
387
|
+
this.cachedState as CachedBeaconStateGloas
|
|
388
|
+
).payloadExpectedWithdrawals.toValue();
|
|
389
|
+
}
|
|
390
|
+
return this._payloadExpectedWithdrawals;
|
|
391
|
+
}
|
|
392
|
+
|
|
385
393
|
getBuilder(index: BuilderIndex): gloas.Builder {
|
|
386
394
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
387
|
-
throw new Error("Builders are not supported before
|
|
395
|
+
throw new Error("Builders are not supported before Gloas");
|
|
388
396
|
}
|
|
389
397
|
|
|
390
398
|
return (this.cachedState as CachedBeaconStateGloas).builders.getReadonly(index);
|
|
@@ -392,7 +400,7 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
392
400
|
|
|
393
401
|
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
|
|
394
402
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
395
|
-
throw new Error("Builders are not supported before
|
|
403
|
+
throw new Error("Builders are not supported before Gloas");
|
|
396
404
|
}
|
|
397
405
|
|
|
398
406
|
return canBuilderCoverBid(this.cachedState as CachedBeaconStateGloas, builderIndex, bidAmount);
|
|
@@ -404,7 +412,7 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
404
412
|
*/
|
|
405
413
|
getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number {
|
|
406
414
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
407
|
-
throw new Error("PTC committees are not supported before
|
|
415
|
+
throw new Error("PTC committees are not supported before Gloas");
|
|
408
416
|
}
|
|
409
417
|
|
|
410
418
|
const ptcCommittee = (this.cachedState as CachedBeaconStateGloas).epochCtx.getPayloadTimelinessCommittee(slot);
|
|
@@ -571,7 +579,10 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
571
579
|
}
|
|
572
580
|
|
|
573
581
|
get isMergeTransitionComplete(): boolean {
|
|
574
|
-
return
|
|
582
|
+
return (
|
|
583
|
+
(isExecutionStateType(this.cachedState) || isGloasStateType(this.cachedState)) &&
|
|
584
|
+
isMergeTransitionComplete(this.cachedState)
|
|
585
|
+
);
|
|
575
586
|
}
|
|
576
587
|
|
|
577
588
|
// Block production
|
|
@@ -693,7 +704,11 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
693
704
|
|
|
694
705
|
// Serialization
|
|
695
706
|
|
|
696
|
-
loadOtherState(
|
|
707
|
+
loadOtherState(
|
|
708
|
+
stateBytes: Uint8Array,
|
|
709
|
+
seedValidatorsBytes?: Uint8Array,
|
|
710
|
+
opts?: {preloadValidatorsAndBalances?: boolean}
|
|
711
|
+
): IBeaconStateView {
|
|
697
712
|
const {state} = loadState(this.config, this.cachedState, stateBytes, seedValidatorsBytes);
|
|
698
713
|
|
|
699
714
|
const cachedState = createCachedBeaconState(
|
|
@@ -708,9 +723,10 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
708
723
|
}
|
|
709
724
|
);
|
|
710
725
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
726
|
+
if (opts?.preloadValidatorsAndBalances) {
|
|
727
|
+
cachedState.validators.getAllReadonlyValues();
|
|
728
|
+
cachedState.balances.getAll();
|
|
729
|
+
}
|
|
714
730
|
|
|
715
731
|
return new BeaconStateView(cachedState);
|
|
716
732
|
}
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
|
+
import {
|
|
4
|
+
ForkName,
|
|
5
|
+
ForkPostAltair,
|
|
6
|
+
ForkPostBellatrix,
|
|
7
|
+
ForkPostCapella,
|
|
8
|
+
ForkPostDeneb,
|
|
9
|
+
ForkPostElectra,
|
|
10
|
+
ForkPostFulu,
|
|
11
|
+
ForkPostGloas,
|
|
12
|
+
isForkPostAltair,
|
|
13
|
+
isForkPostBellatrix,
|
|
14
|
+
isForkPostCapella,
|
|
15
|
+
isForkPostDeneb,
|
|
16
|
+
isForkPostElectra,
|
|
17
|
+
isForkPostFulu,
|
|
18
|
+
isForkPostGloas,
|
|
19
|
+
} from "@lodestar/params";
|
|
3
20
|
import {
|
|
4
21
|
BeaconBlock,
|
|
5
22
|
BeaconState,
|
|
@@ -41,6 +58,7 @@ export interface IBeaconStateView {
|
|
|
41
58
|
// State access
|
|
42
59
|
|
|
43
60
|
// phase0
|
|
61
|
+
forkName: ForkName;
|
|
44
62
|
slot: Slot;
|
|
45
63
|
fork: Fork;
|
|
46
64
|
epoch: Epoch;
|
|
@@ -56,50 +74,6 @@ export interface IBeaconStateView {
|
|
|
56
74
|
getStateRootAtSlot(slot: Slot): Root;
|
|
57
75
|
getRandaoMix(epoch: Epoch): Bytes32;
|
|
58
76
|
|
|
59
|
-
// altair
|
|
60
|
-
previousEpochParticipation: Uint8Array;
|
|
61
|
-
currentEpochParticipation: Uint8Array;
|
|
62
|
-
getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number;
|
|
63
|
-
getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number;
|
|
64
|
-
|
|
65
|
-
// bellatrix
|
|
66
|
-
latestExecutionPayloadHeader: ExecutionPayloadHeader;
|
|
67
|
-
/**
|
|
68
|
-
* Cross-fork accessor for the execution block hash of the most recently included payload.
|
|
69
|
-
* Pre-gloas: returns latestExecutionPayloadHeader.blockHash (bellatrix–fulu).
|
|
70
|
-
* Gloas+: returns the dedicated latestBlockHash state field (EIP-7732).
|
|
71
|
-
* Throws before bellatrix.
|
|
72
|
-
*/
|
|
73
|
-
latestBlockHash: Bytes32;
|
|
74
|
-
/**
|
|
75
|
-
* The execution block number of the most recently included payload.
|
|
76
|
-
* Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
|
|
77
|
-
* Only available from bellatrix through fulu — not tracked on BeaconState in gloas+ (EIP-7732).
|
|
78
|
-
* Throws before bellatrix and from gloas onwards.
|
|
79
|
-
*/
|
|
80
|
-
payloadBlockNumber: number;
|
|
81
|
-
|
|
82
|
-
// capella
|
|
83
|
-
historicalSummaries: capella.HistoricalSummaries;
|
|
84
|
-
|
|
85
|
-
// electra
|
|
86
|
-
pendingDeposits: electra.PendingDeposits;
|
|
87
|
-
pendingDepositsCount: number;
|
|
88
|
-
pendingPartialWithdrawals: electra.PendingPartialWithdrawals;
|
|
89
|
-
pendingPartialWithdrawalsCount: number;
|
|
90
|
-
pendingConsolidations: electra.PendingConsolidations;
|
|
91
|
-
pendingConsolidationsCount: number;
|
|
92
|
-
|
|
93
|
-
// fulu
|
|
94
|
-
proposerLookahead: fulu.ProposerLookahead;
|
|
95
|
-
|
|
96
|
-
// gloas
|
|
97
|
-
executionPayloadAvailability: BitArray;
|
|
98
|
-
latestExecutionPayloadBid: ExecutionPayloadBid;
|
|
99
|
-
getBuilder(index: BuilderIndex): gloas.Builder;
|
|
100
|
-
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
|
|
101
|
-
getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number;
|
|
102
|
-
|
|
103
77
|
// Shuffling and committees
|
|
104
78
|
getShufflingAtEpoch(epoch: Epoch): EpochShuffling;
|
|
105
79
|
// Decision roots
|
|
@@ -117,15 +91,6 @@ export interface IBeaconStateView {
|
|
|
117
91
|
nextProposers: ValidatorIndex[];
|
|
118
92
|
getBeaconProposer(slot: Slot): ValidatorIndex;
|
|
119
93
|
|
|
120
|
-
// Sync committees
|
|
121
|
-
currentSyncCommittee: altair.SyncCommittee;
|
|
122
|
-
nextSyncCommittee: altair.SyncCommittee;
|
|
123
|
-
currentSyncCommitteeIndexed: SyncCommitteeCache;
|
|
124
|
-
syncProposerReward: number;
|
|
125
|
-
getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
|
|
126
|
-
/** Get indexed sync committee with slot+1 offset for duty lookups */
|
|
127
|
-
getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache;
|
|
128
|
-
|
|
129
94
|
// Validators and balances
|
|
130
95
|
effectiveBalanceIncrements: EffectiveBalanceIncrements;
|
|
131
96
|
getEffectiveBalanceIncrementsZeroInactive(): EffectiveBalanceIncrements;
|
|
@@ -140,29 +105,10 @@ export interface IBeaconStateView {
|
|
|
140
105
|
getAllValidators(): phase0.Validator[];
|
|
141
106
|
getAllBalances(): number[];
|
|
142
107
|
|
|
143
|
-
// Merge
|
|
144
|
-
isExecutionStateType: boolean;
|
|
145
|
-
isMergeTransitionComplete: boolean;
|
|
146
|
-
// TODO this should go away (or rather only need block)
|
|
147
|
-
isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean;
|
|
148
|
-
|
|
149
|
-
// Block production
|
|
150
|
-
getExpectedWithdrawals(): {
|
|
151
|
-
expectedWithdrawals: capella.Withdrawal[];
|
|
152
|
-
processedBuilderWithdrawalsCount: number;
|
|
153
|
-
processedPartialWithdrawalsCount: number;
|
|
154
|
-
processedBuildersSweepCount: number;
|
|
155
|
-
processedValidatorSweepCount: number;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
108
|
// API
|
|
159
109
|
proposerRewards: RewardCache;
|
|
160
110
|
computeBlockRewards(block: BeaconBlock, proposerRewards?: RewardCache): Promise<rewards.BlockRewards>;
|
|
161
111
|
computeAttestationsRewards(validatorIds?: (ValidatorIndex | string)[]): Promise<rewards.AttestationsRewards>;
|
|
162
|
-
computeSyncCommitteeRewards(
|
|
163
|
-
block: BeaconBlock,
|
|
164
|
-
validatorIds: (ValidatorIndex | string)[]
|
|
165
|
-
): Promise<rewards.SyncCommitteeRewards>;
|
|
166
112
|
getLatestWeakSubjectivityCheckpointEpoch(): Epoch;
|
|
167
113
|
|
|
168
114
|
// Validation
|
|
@@ -174,7 +120,6 @@ export interface IBeaconStateView {
|
|
|
174
120
|
|
|
175
121
|
// Proofs
|
|
176
122
|
getFinalizedRootProof(): Uint8Array[];
|
|
177
|
-
getSyncCommitteesWitness(): SyncCommitteeWitness;
|
|
178
123
|
getSingleProof(gindex: bigint): Uint8Array[];
|
|
179
124
|
createMultiProof(descriptor: Uint8Array): CompactMultiProof;
|
|
180
125
|
|
|
@@ -193,7 +138,13 @@ export interface IBeaconStateView {
|
|
|
193
138
|
isStateValidatorsNodesPopulated(): boolean;
|
|
194
139
|
|
|
195
140
|
// Serialization
|
|
196
|
-
|
|
141
|
+
/** Set `preloadValidatorsAndBalances` only when the whole state will be consumed
|
|
142
|
+
* immediately (e.g. CP reload before block replay). */
|
|
143
|
+
loadOtherState(
|
|
144
|
+
stateBytes: Uint8Array,
|
|
145
|
+
seedValidatorsBytes?: Uint8Array,
|
|
146
|
+
opts?: {preloadValidatorsAndBalances?: boolean}
|
|
147
|
+
): IBeaconStateView;
|
|
197
148
|
toValue(): BeaconState;
|
|
198
149
|
serialize(): Uint8Array;
|
|
199
150
|
serializedSize(): number;
|
|
@@ -215,8 +166,138 @@ export interface IBeaconStateView {
|
|
|
215
166
|
epochTransitionCacheOpts?: EpochTransitionCacheOpts & {dontTransferCache?: boolean},
|
|
216
167
|
modules?: StateTransitionModules
|
|
217
168
|
): IBeaconStateView;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Altair+ state fields — use isStatePostAltair() guard */
|
|
172
|
+
export interface IBeaconStateViewAltair extends IBeaconStateView {
|
|
173
|
+
forkName: ForkPostAltair;
|
|
174
|
+
previousEpochParticipation: Uint8Array;
|
|
175
|
+
currentEpochParticipation: Uint8Array;
|
|
176
|
+
getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number;
|
|
177
|
+
getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number;
|
|
178
|
+
currentSyncCommittee: altair.SyncCommittee;
|
|
179
|
+
nextSyncCommittee: altair.SyncCommittee;
|
|
180
|
+
currentSyncCommitteeIndexed: SyncCommitteeCache;
|
|
181
|
+
syncProposerReward: number;
|
|
182
|
+
getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
|
|
183
|
+
/** Get indexed sync committee with slot+1 offset for duty lookups */
|
|
184
|
+
getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache;
|
|
185
|
+
computeSyncCommitteeRewards(
|
|
186
|
+
block: BeaconBlock,
|
|
187
|
+
validatorIds: (ValidatorIndex | string)[]
|
|
188
|
+
): Promise<rewards.SyncCommitteeRewards>;
|
|
189
|
+
getSyncCommitteesWitness(): SyncCommitteeWitness;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Bellatrix+ state fields — use isStatePostBellatrix() guard */
|
|
193
|
+
export interface IBeaconStateViewBellatrix extends IBeaconStateViewAltair {
|
|
194
|
+
forkName: ForkPostBellatrix;
|
|
195
|
+
latestExecutionPayloadHeader: ExecutionPayloadHeader;
|
|
196
|
+
/**
|
|
197
|
+
* The execution block number of the most recently included payload.
|
|
198
|
+
* Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
|
|
199
|
+
* Only available from bellatrix through fulu — not tracked on BeaconState in gloas+ (EIP-7732).
|
|
200
|
+
* Throws before bellatrix and from gloas onwards.
|
|
201
|
+
*/
|
|
202
|
+
payloadBlockNumber: number;
|
|
203
|
+
isExecutionStateType: boolean;
|
|
204
|
+
isMergeTransitionComplete: boolean;
|
|
205
|
+
isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Capella+ state fields — use isStatePostCapella() guard */
|
|
209
|
+
export interface IBeaconStateViewCapella extends IBeaconStateViewBellatrix {
|
|
210
|
+
forkName: ForkPostCapella;
|
|
211
|
+
historicalSummaries: capella.HistoricalSummaries;
|
|
212
|
+
getExpectedWithdrawals(): {
|
|
213
|
+
expectedWithdrawals: capella.Withdrawal[];
|
|
214
|
+
processedBuilderWithdrawalsCount: number;
|
|
215
|
+
processedPartialWithdrawalsCount: number;
|
|
216
|
+
processedBuildersSweepCount: number;
|
|
217
|
+
processedValidatorSweepCount: number;
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Deneb+ state — no new state-view fields; placeholder for fork completeness and isStatePostDeneb() narrowing */
|
|
222
|
+
export interface IBeaconStateViewDeneb extends IBeaconStateViewCapella {
|
|
223
|
+
forkName: ForkPostDeneb;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Electra+ state fields — use isStatePostElectra() guard */
|
|
227
|
+
export interface IBeaconStateViewElectra extends IBeaconStateViewDeneb {
|
|
228
|
+
forkName: ForkPostElectra;
|
|
229
|
+
pendingDeposits: electra.PendingDeposits;
|
|
230
|
+
pendingDepositsCount: number;
|
|
231
|
+
pendingPartialWithdrawals: electra.PendingPartialWithdrawals;
|
|
232
|
+
pendingPartialWithdrawalsCount: number;
|
|
233
|
+
pendingConsolidations: electra.PendingConsolidations;
|
|
234
|
+
pendingConsolidationsCount: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Fulu+ state fields — use isStatePostFulu() guard */
|
|
238
|
+
export interface IBeaconStateViewFulu extends IBeaconStateViewElectra {
|
|
239
|
+
forkName: ForkPostFulu;
|
|
240
|
+
proposerLookahead: fulu.ProposerLookahead;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Gloas+ state fields — use isStatePostGloas() guard */
|
|
244
|
+
export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
|
|
245
|
+
forkName: ForkPostGloas;
|
|
246
|
+
/** Removed from BeaconState in gloas. Use `latestBlockHash` instead. */
|
|
247
|
+
latestExecutionPayloadHeader: never;
|
|
248
|
+
/** Removed from BeaconState in gloas. */
|
|
249
|
+
payloadBlockNumber: never;
|
|
250
|
+
latestBlockHash: Bytes32;
|
|
251
|
+
executionPayloadAvailability: BitArray;
|
|
252
|
+
latestExecutionPayloadBid: ExecutionPayloadBid;
|
|
253
|
+
payloadExpectedWithdrawals: capella.Withdrawal[];
|
|
254
|
+
getBuilder(index: BuilderIndex): gloas.Builder;
|
|
255
|
+
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
|
|
256
|
+
getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number;
|
|
218
257
|
processExecutionPayloadEnvelope(
|
|
219
258
|
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
220
259
|
opts?: ProcessExecutionPayloadEnvelopeOpts
|
|
221
260
|
): IBeaconStateView;
|
|
222
261
|
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Type constraint for the concrete BeaconStateView class.
|
|
265
|
+
* Requires all fields from the latest fork interface (IBeaconStateViewGloas) but keeps
|
|
266
|
+
* forkName as ForkName since the class wraps any fork's state.
|
|
267
|
+
* Sub-interfaces retain their narrowed forkName discriminants for caller-side type guards.
|
|
268
|
+
*/
|
|
269
|
+
export type IBeaconStateViewLatestFork = Omit<
|
|
270
|
+
IBeaconStateViewGloas,
|
|
271
|
+
"forkName" | "latestExecutionPayloadHeader" | "payloadBlockNumber"
|
|
272
|
+
> & {
|
|
273
|
+
forkName: ForkName;
|
|
274
|
+
latestExecutionPayloadHeader: ExecutionPayloadHeader;
|
|
275
|
+
payloadBlockNumber: number;
|
|
276
|
+
};
|
|
277
|
+
export function isStatePostAltair(state: IBeaconStateView): state is IBeaconStateViewAltair {
|
|
278
|
+
return isForkPostAltair(state.forkName);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function isStatePostBellatrix(state: IBeaconStateView): state is IBeaconStateViewBellatrix {
|
|
282
|
+
return isForkPostBellatrix(state.forkName);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function isStatePostCapella(state: IBeaconStateView): state is IBeaconStateViewCapella {
|
|
286
|
+
return isForkPostCapella(state.forkName);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function isStatePostDeneb(state: IBeaconStateView): state is IBeaconStateViewDeneb {
|
|
290
|
+
return isForkPostDeneb(state.forkName);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function isStatePostElectra(state: IBeaconStateView): state is IBeaconStateViewElectra {
|
|
294
|
+
return isForkPostElectra(state.forkName);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function isStatePostFulu(state: IBeaconStateView): state is IBeaconStateViewFulu {
|
|
298
|
+
return isForkPostFulu(state.forkName);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function isStatePostGloas(state: IBeaconStateView): state is IBeaconStateViewGloas {
|
|
302
|
+
return isForkPostGloas(state.forkName);
|
|
303
|
+
}
|
package/src/util/attestation.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
-
import {
|
|
1
|
+
import {ForkSeq, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {
|
|
3
|
+
AttesterSlashing,
|
|
4
|
+
IndexedAttestation,
|
|
5
|
+
IndexedAttestationBigint,
|
|
6
|
+
Slot,
|
|
7
|
+
ValidatorIndex,
|
|
8
|
+
phase0,
|
|
9
|
+
ssz,
|
|
10
|
+
} from "@lodestar/types";
|
|
3
11
|
|
|
4
12
|
/**
|
|
5
13
|
* Check if [[data1]] and [[data2]] are slashable according to Casper FFG rules.
|
|
@@ -22,15 +30,36 @@ export function isValidAttestationSlot(attestationSlot: Slot, currentSlot: Slot)
|
|
|
22
30
|
);
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Compute the intersection of two sorted validator index lists.
|
|
35
|
+
* Both inputs must be sorted in ascending order (per spec).
|
|
36
|
+
*/
|
|
37
|
+
export function getIntersectingIndices(indices1: ValidatorIndex[], indices2: ValidatorIndex[]): ValidatorIndex[] {
|
|
26
38
|
const indices: ValidatorIndex[] = [];
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (attSet1.has(index)) {
|
|
39
|
+
const alreadyPresent = new Set(indices1);
|
|
40
|
+
for (let i = 0, len = indices2.length; i < len; i++) {
|
|
41
|
+
const index = indices2[i];
|
|
42
|
+
if (alreadyPresent.has(index)) {
|
|
32
43
|
indices.push(index);
|
|
33
44
|
}
|
|
34
45
|
}
|
|
35
46
|
return indices;
|
|
36
47
|
}
|
|
48
|
+
|
|
49
|
+
export function getAttesterSlashableIndices(attesterSlashing: AttesterSlashing): ValidatorIndex[] {
|
|
50
|
+
return getIntersectingIndices(
|
|
51
|
+
attesterSlashing.attestation1.attestingIndices,
|
|
52
|
+
attesterSlashing.attestation2.attestingIndices
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Convert IndexedAttestation to IndexedAttestationBigint via SSZ roundtrip.
|
|
58
|
+
* Both types share the same binary layout — only the JS numeric representation differs.
|
|
59
|
+
*/
|
|
60
|
+
export function toIndexedAttestationBigint(att: IndexedAttestation, fork: ForkSeq): IndexedAttestationBigint {
|
|
61
|
+
const sszType = fork >= ForkSeq.electra ? ssz.electra.IndexedAttestation : ssz.phase0.IndexedAttestation;
|
|
62
|
+
const sszTypeBigint =
|
|
63
|
+
fork >= ForkSeq.electra ? ssz.electra.IndexedAttestationBigint : ssz.phase0.IndexedAttestationBigint;
|
|
64
|
+
return sszTypeBigint.deserialize(sszType.serialize(att));
|
|
65
|
+
}
|
package/src/util/execution.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
BeaconStateBellatrix,
|
|
19
19
|
BeaconStateCapella,
|
|
20
20
|
BeaconStateExecutions,
|
|
21
|
+
BeaconStateGloas,
|
|
21
22
|
CachedBeaconStateAllForks,
|
|
22
23
|
CachedBeaconStateExecutions,
|
|
23
24
|
} from "../types.js";
|
|
@@ -46,7 +47,11 @@ export function isExecutionEnabled(state: BeaconStateExecutions, block: BeaconBl
|
|
|
46
47
|
* Merge is complete when the state includes execution layer data:
|
|
47
48
|
* state.latestExecutionPayloadHeader NOT EMPTY or state is post-capella
|
|
48
49
|
*/
|
|
49
|
-
export function isMergeTransitionComplete(state: BeaconStateExecutions): boolean {
|
|
50
|
+
export function isMergeTransitionComplete(state: BeaconStateExecutions | BeaconStateGloas): boolean {
|
|
51
|
+
if (isGloasStateType(state)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
if (isCapellaStateType(state)) {
|
|
51
56
|
// All networks have completed the merge transition before capella
|
|
52
57
|
return true;
|
|
@@ -71,6 +76,11 @@ export function isCapellaStateType(state: BeaconStateAllForks): state is BeaconS
|
|
|
71
76
|
);
|
|
72
77
|
}
|
|
73
78
|
|
|
79
|
+
/** Type guard for gloas.BeaconState */
|
|
80
|
+
export function isGloasStateType(state: BeaconStateAllForks): state is BeaconStateGloas {
|
|
81
|
+
return (state as BeaconStateGloas).latestBlockHash !== undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
/** Type guard for bellatrix.CachedBeaconState */
|
|
75
85
|
export function isExecutionCachedStateType(state: CachedBeaconStateAllForks): state is CachedBeaconStateExecutions {
|
|
76
86
|
return (state as CachedBeaconStateExecutions).latestExecutionPayloadHeader !== undefined;
|