@lodestar/state-transition 1.43.0-dev.433e692fd9 → 1.43.0-dev.4fb05c546d
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/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/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.js +1 -1
- package/lib/stateTransition.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +1 -7
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +11 -23
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +8 -8
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/util/gloas.d.ts +8 -3
- 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/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/slot/upgradeStateToGloas.ts +2 -1
- package/src/stateTransition.ts +1 -1
- package/src/stateView/beaconStateView.ts +12 -27
- package/src/stateView/interface.ts +13 -8
- package/src/util/gloas.ts +49 -3
package/src/epoch/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {processParticipationRecordUpdates} from "./processParticipationRecordUpd
|
|
|
28
28
|
import {processPendingConsolidations} from "./processPendingConsolidations.js";
|
|
29
29
|
import {processPendingDeposits} from "./processPendingDeposits.js";
|
|
30
30
|
import {processProposerLookahead} from "./processProposerLookahead.js";
|
|
31
|
+
import {processPtcWindow} from "./processPtcWindow.js";
|
|
31
32
|
import {processRandaoMixesReset} from "./processRandaoMixesReset.js";
|
|
32
33
|
import {processRegistryUpdates} from "./processRegistryUpdates.js";
|
|
33
34
|
import {processRewardsAndPenalties} from "./processRewardsAndPenalties.js";
|
|
@@ -55,6 +56,7 @@ export {
|
|
|
55
56
|
processPendingDeposits,
|
|
56
57
|
processPendingConsolidations,
|
|
57
58
|
processProposerLookahead,
|
|
59
|
+
processPtcWindow,
|
|
58
60
|
processBuilderPendingPayments,
|
|
59
61
|
};
|
|
60
62
|
|
|
@@ -81,6 +83,7 @@ export enum EpochTransitionStep {
|
|
|
81
83
|
processPendingDeposits = "processPendingDeposits",
|
|
82
84
|
processPendingConsolidations = "processPendingConsolidations",
|
|
83
85
|
processProposerLookahead = "processProposerLookahead",
|
|
86
|
+
processPtcWindow = "processPtcWindow",
|
|
84
87
|
processBuilderPendingPayments = "processBuilderPendingPayments",
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -211,4 +214,10 @@ export function processEpoch(
|
|
|
211
214
|
processProposerLookahead(fork, state as CachedBeaconStateFulu, cache);
|
|
212
215
|
timer?.();
|
|
213
216
|
}
|
|
217
|
+
|
|
218
|
+
if (fork >= ForkSeq.gloas) {
|
|
219
|
+
const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.processPtcWindow});
|
|
220
|
+
processPtcWindow(state as CachedBeaconStateGloas, cache);
|
|
221
|
+
timer?.();
|
|
222
|
+
}
|
|
214
223
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {MIN_SEED_LOOKAHEAD} from "@lodestar/params";
|
|
2
|
+
import {ssz} from "@lodestar/types";
|
|
3
|
+
import {CachedBeaconStateGloas, EpochTransitionCache} from "../types.js";
|
|
4
|
+
import {computeEpochShuffling} from "../util/epochShuffling.js";
|
|
5
|
+
import {computePayloadTimelinessCommitteesForEpoch} from "../util/seed.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Update the `ptc_window` field in the beacon state by shifting out the oldest epoch's
|
|
9
|
+
* PTC entries and appending newly computed entries for the next lookahead epoch.
|
|
10
|
+
* Stashes the computed PTCs in the transition cache for finalProcessEpoch to shift
|
|
11
|
+
* into the epoch cache without reading from state.
|
|
12
|
+
*
|
|
13
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.4/specs/gloas/beacon-chain.md#new-process_ptc_window
|
|
14
|
+
*/
|
|
15
|
+
export function processPtcWindow(state: CachedBeaconStateGloas, cache: EpochTransitionCache): void {
|
|
16
|
+
const nextEpoch = state.epochCtx.epoch + MIN_SEED_LOOKAHEAD + 1;
|
|
17
|
+
const nextEpochShuffling =
|
|
18
|
+
cache.nextShuffling ?? computeEpochShuffling(state, cache.nextShufflingActiveIndices, nextEpoch);
|
|
19
|
+
cache.nextShuffling = nextEpochShuffling;
|
|
20
|
+
|
|
21
|
+
const newNextPayloadTimelinessCommittees = computePayloadTimelinessCommitteesForEpoch(
|
|
22
|
+
state,
|
|
23
|
+
nextEpoch,
|
|
24
|
+
nextEpochShuffling.committees,
|
|
25
|
+
state.epochCtx.effectiveBalanceIncrements
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Stash for finalProcessEpoch to shift into epoch cache
|
|
29
|
+
cache.nextEpochPayloadTimelinessCommittees = newNextPayloadTimelinessCommittees;
|
|
30
|
+
|
|
31
|
+
// Write shifted window to state: current(N) + next(N+1) + newlyComputed(N+2)
|
|
32
|
+
// From the perspective of upcoming epoch N+1, this is previous + current + next
|
|
33
|
+
state.ptcWindow = ssz.gloas.PtcWindow.toViewDU([
|
|
34
|
+
...state.epochCtx.payloadTimelinessCommittees,
|
|
35
|
+
...state.epochCtx.nextPayloadTimelinessCommittees,
|
|
36
|
+
...newNextPayloadTimelinessCommittees,
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
@@ -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
|
@@ -282,7 +282,7 @@ function processSlotsWithTransientCache(
|
|
|
282
282
|
{
|
|
283
283
|
const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.finalProcessEpoch});
|
|
284
284
|
// last step to prepare epoch data that depends on the upgraded state, for example proposerLookahead of BeaconStateFulu
|
|
285
|
-
postState.epochCtx.finalProcessEpoch(postState);
|
|
285
|
+
postState.epochCtx.finalProcessEpoch(postState, epochTransitionCache);
|
|
286
286
|
timer?.();
|
|
287
287
|
}
|
|
288
288
|
|
|
@@ -84,8 +84,6 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
84
84
|
private _currentEpochParticipation: Uint8Array | null = null;
|
|
85
85
|
// bellatrix
|
|
86
86
|
private _latestExecutionPayloadHeader: ExecutionPayloadHeader | null = null;
|
|
87
|
-
// Caches the cross-fork latestBlockHash value
|
|
88
|
-
private _latestBlockHash: Bytes32 | null = null;
|
|
89
87
|
// capella
|
|
90
88
|
private _historicalSummaries: capella.HistoricalSummaries | null = null;
|
|
91
89
|
// electra
|
|
@@ -218,9 +216,13 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
218
216
|
// bellatrix
|
|
219
217
|
|
|
220
218
|
get latestExecutionPayloadHeader(): ExecutionPayloadHeader {
|
|
221
|
-
|
|
219
|
+
const forkSeq = this.config.getForkSeq(this.cachedState.slot);
|
|
220
|
+
if (forkSeq < ForkSeq.bellatrix) {
|
|
222
221
|
throw new Error("latestExecutionPayloadHeader is not available before Bellatrix");
|
|
223
222
|
}
|
|
223
|
+
if (forkSeq >= ForkSeq.gloas) {
|
|
224
|
+
throw new Error("latestExecutionPayloadHeader is not available after Gloas");
|
|
225
|
+
}
|
|
224
226
|
|
|
225
227
|
if (this._latestExecutionPayloadHeader === null) {
|
|
226
228
|
this._latestExecutionPayloadHeader = (
|
|
@@ -231,30 +233,6 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
231
233
|
return this._latestExecutionPayloadHeader;
|
|
232
234
|
}
|
|
233
235
|
|
|
234
|
-
/**
|
|
235
|
-
* Cross-fork accessor for the execution block hash of the most recently included payload.
|
|
236
|
-
* Pre-gloas: reads from latestExecutionPayloadHeader.blockHash.
|
|
237
|
-
* Gloas+: reads the dedicated latestBlockHash field (EIP-7732).
|
|
238
|
-
*/
|
|
239
|
-
get latestBlockHash(): Bytes32 {
|
|
240
|
-
const forkSeq = this.config.getForkSeq(this.cachedState.slot);
|
|
241
|
-
if (forkSeq < ForkSeq.bellatrix) {
|
|
242
|
-
throw new Error("latestBlockHash is not available before Bellatrix");
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (this._latestBlockHash === null) {
|
|
246
|
-
if (forkSeq >= ForkSeq.gloas) {
|
|
247
|
-
this._latestBlockHash = (this.cachedState as CachedBeaconStateGloas).latestBlockHash;
|
|
248
|
-
} else {
|
|
249
|
-
this._latestBlockHash = (
|
|
250
|
-
this.cachedState as CachedBeaconStateExecutions
|
|
251
|
-
).latestExecutionPayloadHeader.blockHash;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return this._latestBlockHash;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
236
|
/**
|
|
259
237
|
* The execution block number of the most recently included payload.
|
|
260
238
|
* Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
|
|
@@ -365,6 +343,13 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
365
343
|
|
|
366
344
|
// gloas
|
|
367
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
|
+
|
|
368
353
|
get executionPayloadAvailability(): BitArray {
|
|
369
354
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
370
355
|
throw new Error("executionPayloadAvailability is not available before Gloas");
|
|
@@ -187,13 +187,6 @@ export interface IBeaconStateViewAltair extends IBeaconStateView {
|
|
|
187
187
|
export interface IBeaconStateViewBellatrix extends IBeaconStateViewAltair {
|
|
188
188
|
forkName: ForkPostBellatrix;
|
|
189
189
|
latestExecutionPayloadHeader: ExecutionPayloadHeader;
|
|
190
|
-
/**
|
|
191
|
-
* Cross-fork accessor for the execution block hash of the most recently included payload.
|
|
192
|
-
* Pre-gloas: returns latestExecutionPayloadHeader.blockHash (bellatrix–fulu).
|
|
193
|
-
* Gloas+: returns the dedicated latestBlockHash state field (EIP-7732).
|
|
194
|
-
* Throws before bellatrix.
|
|
195
|
-
*/
|
|
196
|
-
latestBlockHash: Bytes32;
|
|
197
190
|
/**
|
|
198
191
|
* The execution block number of the most recently included payload.
|
|
199
192
|
* Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
|
|
@@ -244,6 +237,11 @@ export interface IBeaconStateViewFulu extends IBeaconStateViewElectra {
|
|
|
244
237
|
/** Gloas+ state fields — use isStatePostGloas() guard */
|
|
245
238
|
export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
|
|
246
239
|
forkName: ForkPostGloas;
|
|
240
|
+
/** Removed from BeaconState in gloas. Use `latestBlockHash` instead. */
|
|
241
|
+
latestExecutionPayloadHeader: never;
|
|
242
|
+
/** Removed from BeaconState in gloas. */
|
|
243
|
+
payloadBlockNumber: never;
|
|
244
|
+
latestBlockHash: Bytes32;
|
|
247
245
|
executionPayloadAvailability: BitArray;
|
|
248
246
|
latestExecutionPayloadBid: ExecutionPayloadBid;
|
|
249
247
|
payloadExpectedWithdrawals: capella.Withdrawal[];
|
|
@@ -262,7 +260,14 @@ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
|
|
|
262
260
|
* forkName as ForkName since the class wraps any fork's state.
|
|
263
261
|
* Sub-interfaces retain their narrowed forkName discriminants for caller-side type guards.
|
|
264
262
|
*/
|
|
265
|
-
export type IBeaconStateViewLatestFork = Omit<
|
|
263
|
+
export type IBeaconStateViewLatestFork = Omit<
|
|
264
|
+
IBeaconStateViewGloas,
|
|
265
|
+
"forkName" | "latestExecutionPayloadHeader" | "payloadBlockNumber"
|
|
266
|
+
> & {
|
|
267
|
+
forkName: ForkName;
|
|
268
|
+
latestExecutionPayloadHeader: ExecutionPayloadHeader;
|
|
269
|
+
payloadBlockNumber: number;
|
|
270
|
+
};
|
|
266
271
|
export function isStatePostAltair(state: IBeaconStateView): state is IBeaconStateViewAltair {
|
|
267
272
|
return isForkPostAltair(state.forkName);
|
|
268
273
|
}
|
package/src/util/gloas.ts
CHANGED
|
@@ -6,16 +6,20 @@ import {
|
|
|
6
6
|
EFFECTIVE_BALANCE_INCREMENT,
|
|
7
7
|
FAR_FUTURE_EPOCH,
|
|
8
8
|
MIN_DEPOSIT_AMOUNT,
|
|
9
|
+
MIN_SEED_LOOKAHEAD,
|
|
10
|
+
PTC_SIZE,
|
|
9
11
|
SLOTS_PER_EPOCH,
|
|
10
12
|
} from "@lodestar/params";
|
|
11
13
|
import {BuilderIndex, Epoch, ValidatorIndex, gloas} from "@lodestar/types";
|
|
12
14
|
import {AttestationData} from "@lodestar/types/phase0";
|
|
13
15
|
import {byteArrayEquals} from "@lodestar/utils";
|
|
14
|
-
import {
|
|
15
|
-
import {CachedBeaconStateGloas} from "../types.js";
|
|
16
|
+
import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
16
17
|
import {getBlockRootAtSlot} from "./blockRoot.js";
|
|
17
18
|
import {computeEpochAtSlot} from "./epoch.js";
|
|
19
|
+
import {computeEpochShuffling} from "./epochShuffling.js";
|
|
18
20
|
import {RootCache} from "./rootCache.js";
|
|
21
|
+
import {computePayloadTimelinessCommitteesForEpoch} from "./seed.js";
|
|
22
|
+
import {getActiveValidatorIndices} from "./validator.js";
|
|
19
23
|
|
|
20
24
|
export function isBuilderWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean {
|
|
21
25
|
return withdrawalCredentials[0] === BUILDER_WITHDRAWAL_PREFIX;
|
|
@@ -168,6 +172,48 @@ export function isAttestationSameSlotRootCache(rootCache: RootCache, data: Attes
|
|
|
168
172
|
return isMatchingBlockRoot && isCurrentBlockRoot;
|
|
169
173
|
}
|
|
170
174
|
|
|
171
|
-
export function isParentBlockFull(state: CachedBeaconStateGloas
|
|
175
|
+
export function isParentBlockFull(state: CachedBeaconStateGloas): boolean {
|
|
172
176
|
return byteArrayEquals(state.latestExecutionPayloadBid.blockHash, state.latestBlockHash);
|
|
173
177
|
}
|
|
178
|
+
|
|
179
|
+
export function initializePtcWindow(state: CachedBeaconStateFulu): Uint32Array[] {
|
|
180
|
+
const ptcWindow: Uint32Array[] = Array.from({length: SLOTS_PER_EPOCH}, () => new Uint32Array(PTC_SIZE));
|
|
181
|
+
const currentEpoch = state.epochCtx.epoch;
|
|
182
|
+
|
|
183
|
+
for (let epochOffset = 0; epochOffset <= MIN_SEED_LOOKAHEAD; epochOffset++) {
|
|
184
|
+
const epoch = currentEpoch + epochOffset;
|
|
185
|
+
const shuffling =
|
|
186
|
+
state.epochCtx.getShufflingAtEpochOrNull(epoch) ??
|
|
187
|
+
computeEpochShuffling(state, getActiveValidatorIndices(state, epoch), epoch);
|
|
188
|
+
|
|
189
|
+
ptcWindow.push(
|
|
190
|
+
...computePayloadTimelinessCommitteesForEpoch(
|
|
191
|
+
state,
|
|
192
|
+
epoch,
|
|
193
|
+
shuffling.committees,
|
|
194
|
+
state.epochCtx.effectiveBalanceIncrements
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return ptcWindow;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function getPtcWindowEpochCacheData(state: CachedBeaconStateGloas): {
|
|
203
|
+
previousPayloadTimelinessCommittees: Uint32Array[];
|
|
204
|
+
payloadTimelinessCommittees: Uint32Array[];
|
|
205
|
+
nextPayloadTimelinessCommittees: Uint32Array[];
|
|
206
|
+
} {
|
|
207
|
+
const toUint32Arrays = (views: ReturnType<typeof state.ptcWindow.getReadonlyByRange>) =>
|
|
208
|
+
views.map((v) => Uint32Array.from(v.getAll()));
|
|
209
|
+
|
|
210
|
+
const previousPtcWindow = state.ptcWindow.getReadonlyByRange(0, SLOTS_PER_EPOCH);
|
|
211
|
+
const currentPtcWindow = state.ptcWindow.getReadonlyByRange(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH);
|
|
212
|
+
const nextPtcWindow = state.ptcWindow.getReadonlyByRange(2 * SLOTS_PER_EPOCH, SLOTS_PER_EPOCH);
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
previousPayloadTimelinessCommittees: toUint32Arrays(previousPtcWindow),
|
|
216
|
+
payloadTimelinessCommittees: toUint32Arrays(currentPtcWindow),
|
|
217
|
+
nextPayloadTimelinessCommittees: toUint32Arrays(nextPtcWindow),
|
|
218
|
+
};
|
|
219
|
+
}
|