@lodestar/state-transition 1.45.0-dev.905415417a → 1.45.0-dev.955b4c884a
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/processAttestationsAltair.d.ts +4 -1
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +7 -5
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processBuilderDepositRequest.d.ts.map +1 -1
- package/lib/block/processBuilderDepositRequest.js +13 -7
- package/lib/block/processBuilderDepositRequest.js.map +1 -1
- package/lib/block/processOperations.d.ts.map +1 -1
- package/lib/block/processOperations.js +17 -1
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
- package/lib/block/processParentExecutionPayload.js +15 -1
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processWithdrawals.js +1 -1
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +2 -4
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.d.ts +2 -2
- package/lib/epoch/processParticipationFlagUpdates.d.ts.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.js +13 -0
- package/lib/epoch/processParticipationFlagUpdates.js.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.d.ts.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.js +1 -2
- package/lib/epoch/processRewardsAndPenalties.js.map +1 -1
- package/lib/lightClient/proofs.d.ts.map +1 -1
- package/lib/lightClient/proofs.js +28 -2
- package/lib/lightClient/proofs.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts.map +1 -1
- package/lib/lightClient/spec/index.js +7 -4
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/processLightClientUpdate.d.ts.map +1 -1
- package/lib/lightClient/spec/processLightClientUpdate.js +8 -2
- package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +7 -2
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +130 -19
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.js +2 -7
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.js +6 -5
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
- package/lib/lightClient/types.d.ts +3 -1
- package/lib/lightClient/types.d.ts.map +1 -1
- package/lib/metrics.js +2 -4
- package/lib/metrics.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.js +1 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +48 -9
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +1 -1
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +6 -8
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +1 -1
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +2 -2
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js +7 -9
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +7 -2
- package/lib/util/execution.js.map +1 -1
- package/lib/util/gloas.d.ts +3 -1
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +8 -11
- package/lib/util/gloas.js.map +1 -1
- 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/ssz.d.ts +9 -0
- package/lib/util/ssz.d.ts.map +1 -0
- package/lib/util/ssz.js +39 -0
- package/lib/util/ssz.js.map +1 -0
- package/package.json +11 -11
- package/src/block/processAttestationsAltair.ts +9 -6
- package/src/block/processBuilderDepositRequest.ts +21 -8
- package/src/block/processOperations.ts +28 -1
- package/src/block/processParentExecutionPayload.ts +26 -1
- package/src/block/processWithdrawals.ts +1 -1
- package/src/cache/stateCache.ts +2 -4
- package/src/epoch/processParticipationFlagUpdates.ts +20 -2
- package/src/epoch/processRewardsAndPenalties.ts +1 -2
- package/src/lightClient/proofs.ts +36 -1
- package/src/lightClient/spec/index.ts +8 -4
- package/src/lightClient/spec/processLightClientUpdate.ts +13 -1
- package/src/lightClient/spec/utils.ts +200 -30
- package/src/lightClient/spec/validateLightClientBootstrap.ts +3 -10
- package/src/lightClient/spec/validateLightClientUpdate.ts +11 -21
- package/src/lightClient/types.ts +3 -1
- package/src/metrics.ts +2 -4
- package/src/slot/upgradeStateToAltair.ts +1 -1
- package/src/slot/upgradeStateToGloas.ts +84 -9
- package/src/stateView/beaconStateView.ts +8 -8
- package/src/stateView/interface.ts +1 -1
- package/src/stateView/nativeBeaconStateView.ts +8 -10
- package/src/util/execution.ts +9 -4
- package/src/util/gloas.ts +9 -14
- package/src/util/index.ts +1 -0
- package/src/util/ssz.ts +42 -0
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import {getNodesAtDepth} from "@chainsafe/persistent-merkle-tree";
|
|
2
|
+
import {
|
|
3
|
+
BasicType,
|
|
4
|
+
CompositeType,
|
|
5
|
+
CompositeView,
|
|
6
|
+
CompositeViewDU,
|
|
7
|
+
ListBasicTreeViewDU,
|
|
8
|
+
ListCompositeTreeViewDU,
|
|
9
|
+
ProgressiveListBasicType,
|
|
10
|
+
ProgressiveListCompositeType,
|
|
11
|
+
ValueOf,
|
|
12
|
+
} from "@chainsafe/ssz";
|
|
1
13
|
import {PAYLOAD_BUILDER_VERSION, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
2
14
|
import {ssz} from "@lodestar/types";
|
|
3
15
|
import {toPubkeyHex} from "@lodestar/utils";
|
|
@@ -7,6 +19,7 @@ import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
|
7
19
|
import {addBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
8
20
|
import {isValidatorKnown} from "../util/index.js";
|
|
9
21
|
import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
|
|
22
|
+
import {progressiveListRootNode} from "../util/ssz.js";
|
|
10
23
|
|
|
11
24
|
/**
|
|
12
25
|
* Upgrade a state from Fulu to Gloas.
|
|
@@ -34,17 +47,26 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
34
47
|
stateGloasView.eth1Data = stateGloasCloned.eth1Data;
|
|
35
48
|
stateGloasView.eth1DataVotes = stateGloasCloned.eth1DataVotes;
|
|
36
49
|
stateGloasView.eth1DepositIndex = stateGloasCloned.eth1DepositIndex;
|
|
37
|
-
stateGloasView.validators = stateGloasCloned.validators;
|
|
38
|
-
stateGloasView.balances = stateGloasCloned.balances;
|
|
50
|
+
stateGloasView.validators = migrateCompositeListToGloas(stateGloasCloned.validators, ssz.gloas.Validators);
|
|
51
|
+
stateGloasView.balances = migrateBasicListToGloas(stateGloasCloned.balances, ssz.gloas.Balances);
|
|
39
52
|
stateGloasView.randaoMixes = stateGloasCloned.randaoMixes;
|
|
40
53
|
stateGloasView.slashings = stateGloasCloned.slashings;
|
|
41
|
-
stateGloasView.previousEpochParticipation =
|
|
42
|
-
|
|
54
|
+
stateGloasView.previousEpochParticipation = migrateBasicListToGloas(
|
|
55
|
+
stateGloasCloned.previousEpochParticipation,
|
|
56
|
+
ssz.gloas.EpochParticipation
|
|
57
|
+
);
|
|
58
|
+
stateGloasView.currentEpochParticipation = migrateBasicListToGloas(
|
|
59
|
+
stateGloasCloned.currentEpochParticipation,
|
|
60
|
+
ssz.gloas.EpochParticipation
|
|
61
|
+
);
|
|
43
62
|
stateGloasView.justificationBits = stateGloasCloned.justificationBits;
|
|
44
63
|
stateGloasView.previousJustifiedCheckpoint = stateGloasCloned.previousJustifiedCheckpoint;
|
|
45
64
|
stateGloasView.currentJustifiedCheckpoint = stateGloasCloned.currentJustifiedCheckpoint;
|
|
46
65
|
stateGloasView.finalizedCheckpoint = stateGloasCloned.finalizedCheckpoint;
|
|
47
|
-
stateGloasView.inactivityScores =
|
|
66
|
+
stateGloasView.inactivityScores = migrateBasicListToGloas(
|
|
67
|
+
stateGloasCloned.inactivityScores,
|
|
68
|
+
ssz.gloas.InactivityScores
|
|
69
|
+
);
|
|
48
70
|
stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
|
|
49
71
|
stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
|
|
50
72
|
stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
|
|
@@ -61,9 +83,18 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
61
83
|
stateGloasView.earliestExitEpoch = stateGloasCloned.earliestExitEpoch;
|
|
62
84
|
stateGloasView.consolidationBalanceToConsume = stateGloasCloned.consolidationBalanceToConsume;
|
|
63
85
|
stateGloasView.earliestConsolidationEpoch = stateGloasCloned.earliestConsolidationEpoch;
|
|
64
|
-
stateGloasView.pendingDeposits =
|
|
65
|
-
|
|
66
|
-
|
|
86
|
+
stateGloasView.pendingDeposits = migrateCompositeListToGloas(
|
|
87
|
+
stateGloasCloned.pendingDeposits,
|
|
88
|
+
ssz.gloas.PendingDeposits
|
|
89
|
+
);
|
|
90
|
+
stateGloasView.pendingPartialWithdrawals = migrateCompositeListToGloas(
|
|
91
|
+
stateGloasCloned.pendingPartialWithdrawals,
|
|
92
|
+
ssz.gloas.PendingPartialWithdrawals
|
|
93
|
+
);
|
|
94
|
+
stateGloasView.pendingConsolidations = migrateCompositeListToGloas(
|
|
95
|
+
stateGloasCloned.pendingConsolidations,
|
|
96
|
+
ssz.gloas.PendingConsolidations
|
|
97
|
+
);
|
|
67
98
|
stateGloasView.proposerLookahead = stateGloasCloned.proposerLookahead;
|
|
68
99
|
stateGloasView.ptcWindow = ssz.gloas.PtcWindow.toViewDU(initializePtcWindow(stateFulu));
|
|
69
100
|
|
|
@@ -85,6 +116,50 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
85
116
|
return stateGloas;
|
|
86
117
|
}
|
|
87
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Migrate a composite list from fulu to its gloas progressive-list equivalent by reusing the fulu
|
|
121
|
+
* list's element nodes.
|
|
122
|
+
*
|
|
123
|
+
* Works whenever the element type is identical across the fork (e.g. validators use ValidatorNodeStruct,
|
|
124
|
+
* the pending* queues use the same electra element types). Each element's cached subtree root is then
|
|
125
|
+
* valid under gloas, so only the progressive list superstructure is rebuilt and a subsequent
|
|
126
|
+
* hashTreeRoot() skips re-hashing every element — the dominant cost for large lists like validators.
|
|
127
|
+
* Much cheaper than `gloasType.toViewDU(fuluList.getAllReadonlyValues())`, which decodes every element
|
|
128
|
+
* to a value and forces a full re-hash.
|
|
129
|
+
*
|
|
130
|
+
* The chunk nodes of a composite list ARE the element root nodes, so they are extracted directly
|
|
131
|
+
* with getNodesAtDepth instead of allocating a temporary ViewDU wrapper per element (getAllReadonly).
|
|
132
|
+
* Requires the fulu view to be committed (done at the top of upgradeStateToGloas).
|
|
133
|
+
*/
|
|
134
|
+
function migrateCompositeListToGloas<
|
|
135
|
+
ElementType extends CompositeType<ValueOf<ElementType>, CompositeView<ElementType>, CompositeViewDU<ElementType>>,
|
|
136
|
+
>(fuluList: ListCompositeTreeViewDU<ElementType>, gloasType: ProgressiveListCompositeType<ElementType>) {
|
|
137
|
+
const {length, type} = fuluList;
|
|
138
|
+
const elementNodes = getNodesAtDepth(fuluList.node.left, type.chunkDepth, 0, length);
|
|
139
|
+
return gloasType.getViewDU(progressiveListRootNode(elementNodes, length));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Migrate a basic list from fulu to its gloas progressive-list equivalent by reusing the fulu
|
|
144
|
+
* list's packed chunk leaf nodes.
|
|
145
|
+
*
|
|
146
|
+
* Packed leaf chunks are bit-identical between List[T, N] and ProgressiveList[T] (same 32-byte
|
|
147
|
+
* LE packing, zero-padded final chunk); only the superstructure above the leaves differs. Reusing
|
|
148
|
+
* the leaves avoids materializing the value array (getAll), re-serializing it, and allocating
|
|
149
|
+
* fresh LeafNodes — the gloas tree shares the leaf nodes with the fulu tree.
|
|
150
|
+
* Requires the fulu view to be committed (done at the top of upgradeStateToGloas).
|
|
151
|
+
*/
|
|
152
|
+
function migrateBasicListToGloas<ElementType extends BasicType<unknown>>(
|
|
153
|
+
fuluList: ListBasicTreeViewDU<ElementType>,
|
|
154
|
+
gloasType: ProgressiveListBasicType<ElementType>
|
|
155
|
+
) {
|
|
156
|
+
const {length, type} = fuluList;
|
|
157
|
+
const chunkCount = Math.ceil(length / type.itemsPerChunk);
|
|
158
|
+
// List root = BranchNode(chunksNode, lengthNode) → chunks tree is the left child
|
|
159
|
+
const chunkLeafNodes = getNodesAtDepth(fuluList.node.left, type.chunkDepth, 0, chunkCount);
|
|
160
|
+
return gloasType.getViewDU(progressiveListRootNode(chunkLeafNodes, length));
|
|
161
|
+
}
|
|
162
|
+
|
|
88
163
|
/**
|
|
89
164
|
* Applies any pending deposits for builders to onboard builders during the fork transition
|
|
90
165
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.8/specs/gloas/fork.md#new-onboard_builders_from_pending_deposits
|
|
@@ -94,7 +169,7 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
|
|
|
94
169
|
// at the fork, so every builder pubkey here is one added in an earlier iteration.
|
|
95
170
|
const builderPubkeys = new Set<string>();
|
|
96
171
|
|
|
97
|
-
const pendingDeposits = ssz.
|
|
172
|
+
const pendingDeposits = ssz.gloas.PendingDeposits.defaultViewDU();
|
|
98
173
|
const pendingDepositsLookup = PendingDepositsLookup.buildEmpty();
|
|
99
174
|
|
|
100
175
|
for (let i = 0; i < state.pendingDeposits.length; i++) {
|
|
@@ -398,6 +398,14 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
398
398
|
return (this.cachedState as CachedBeaconStateGloas).builders.getReadonly(index);
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
+
getBuildersLength(): number {
|
|
402
|
+
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
403
|
+
throw new Error("Builders are not supported before Gloas");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return (this.cachedState as CachedBeaconStateGloas).builders.length;
|
|
407
|
+
}
|
|
408
|
+
|
|
401
409
|
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
|
|
402
410
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
403
411
|
throw new Error("Builders are not supported before Gloas");
|
|
@@ -507,14 +515,6 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
507
515
|
return this.cachedState.epochCtx.getBeaconProposer(slot);
|
|
508
516
|
}
|
|
509
517
|
|
|
510
|
-
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
|
|
511
|
-
try {
|
|
512
|
-
return this.cachedState.epochCtx.getBeaconProposer(slot);
|
|
513
|
-
} catch {
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
518
|
computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} {
|
|
519
519
|
return computeAnchorCheckpoint(this.config, this.cachedState);
|
|
520
520
|
}
|
|
@@ -92,7 +92,6 @@ export interface IBeaconStateView {
|
|
|
92
92
|
currentProposers: ValidatorIndex[];
|
|
93
93
|
nextProposers: ValidatorIndex[];
|
|
94
94
|
getBeaconProposer(slot: Slot): ValidatorIndex;
|
|
95
|
-
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null;
|
|
96
95
|
|
|
97
96
|
// Validators and balances
|
|
98
97
|
effectiveBalanceIncrements: EffectiveBalanceIncrements;
|
|
@@ -255,6 +254,7 @@ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
|
|
|
255
254
|
latestExecutionPayloadBid: ExecutionPayloadBid;
|
|
256
255
|
payloadExpectedWithdrawals: capella.Withdrawal[];
|
|
257
256
|
getBuilder(index: BuilderIndex): gloas.Builder;
|
|
257
|
+
getBuildersLength(): number;
|
|
258
258
|
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
|
|
259
259
|
getEpochPTCs(epoch: Epoch): Uint32Array[];
|
|
260
260
|
getIndicesInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number[];
|
|
@@ -128,8 +128,6 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
128
128
|
private readonly _getBeaconCommitteeCountPerSlot = new Map<Epoch, number>();
|
|
129
129
|
private readonly _getShufflingDecisionRoot = new Map<Epoch, RootHex>();
|
|
130
130
|
private readonly _getBeaconProposer = new Map<Slot, ValidatorIndex>();
|
|
131
|
-
// getBeaconProposerOrNull can return null, so use .has() to distinguish "not cached" from "cached null"
|
|
132
|
-
private readonly _getBeaconProposerOrNull = new Map<Slot, ValidatorIndex | null>();
|
|
133
131
|
private readonly _getValidator = new Map<ValidatorIndex, phase0.Validator>();
|
|
134
132
|
private readonly _getBalance = new Map<number, number>();
|
|
135
133
|
private readonly _getIndexedSyncCommitteeAtEpoch = new Map<Epoch, SyncCommitteeCache>();
|
|
@@ -144,6 +142,7 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
144
142
|
private _getNextShuffling: EpochShuffling | null = null;
|
|
145
143
|
private _getEffectiveBalanceIncrementsZeroInactive: EffectiveBalanceIncrements | null = null;
|
|
146
144
|
private _getAllValidators: phase0.Validator[] | null = null;
|
|
145
|
+
private _getBuildersLength: number | null = null;
|
|
147
146
|
private _getAllBalances: number[] | null = null;
|
|
148
147
|
private _getLatestWeakSubjectivityCheckpointEpoch: Epoch | null = null;
|
|
149
148
|
private _getFinalizedRootProof: Uint8Array[] | null = null;
|
|
@@ -410,14 +409,6 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
410
409
|
return cached;
|
|
411
410
|
}
|
|
412
411
|
|
|
413
|
-
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
|
|
414
|
-
if (!this._getBeaconProposerOrNull.has(slot)) {
|
|
415
|
-
this._getBeaconProposerOrNull.set(slot, this.binding.getBeaconProposerOrNull(slot));
|
|
416
|
-
}
|
|
417
|
-
// biome-ignore lint/style/noNonNullAssertion: has() check guarantees a value
|
|
418
|
-
return this._getBeaconProposerOrNull.get(slot)!;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
412
|
// Validators and balances
|
|
422
413
|
|
|
423
414
|
get effectiveBalanceIncrements(): EffectiveBalanceIncrements {
|
|
@@ -888,6 +879,13 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
888
879
|
return cached;
|
|
889
880
|
}
|
|
890
881
|
|
|
882
|
+
getBuildersLength(): number {
|
|
883
|
+
if (this._getBuildersLength === null) {
|
|
884
|
+
this._getBuildersLength = this.binding.getBuildersLength();
|
|
885
|
+
}
|
|
886
|
+
return this._getBuildersLength;
|
|
887
|
+
}
|
|
888
|
+
|
|
891
889
|
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
|
|
892
890
|
return this.binding.canBuilderCoverBid(builderIndex, bidAmount);
|
|
893
891
|
}
|
package/src/util/execution.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
bellatrix,
|
|
10
10
|
capella,
|
|
11
11
|
deneb,
|
|
12
|
+
gloas,
|
|
12
13
|
isBlindedBeaconBlockBody,
|
|
13
14
|
isExecutionPayload,
|
|
14
15
|
ssz,
|
|
@@ -127,7 +128,10 @@ export function isCapellaPayloadHeader(
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: ExecutionPayload): ExecutionPayloadHeader {
|
|
130
|
-
const transactionsRoot =
|
|
131
|
+
const transactionsRoot =
|
|
132
|
+
fork >= ForkSeq.gloas
|
|
133
|
+
? ssz.gloas.Transactions.hashTreeRoot((payload as gloas.ExecutionPayload).transactions)
|
|
134
|
+
: ssz.bellatrix.Transactions.hashTreeRoot(payload.transactions);
|
|
131
135
|
|
|
132
136
|
const bellatrixPayloadFields: ExecutionPayloadHeader = {
|
|
133
137
|
parentHash: payload.parentHash,
|
|
@@ -147,9 +151,10 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio
|
|
|
147
151
|
};
|
|
148
152
|
|
|
149
153
|
if (fork >= ForkSeq.capella) {
|
|
150
|
-
(bellatrixPayloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot =
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
(bellatrixPayloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot =
|
|
155
|
+
fork >= ForkSeq.gloas
|
|
156
|
+
? ssz.gloas.Withdrawals.hashTreeRoot((payload as gloas.ExecutionPayload).withdrawals)
|
|
157
|
+
: ssz.capella.Withdrawals.hashTreeRoot((payload as capella.ExecutionPayload).withdrawals);
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
if (fork >= ForkSeq.deneb) {
|
package/src/util/gloas.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {AttestationData} from "@lodestar/types/phase0";
|
|
|
18
18
|
import {byteArrayEquals} from "@lodestar/utils";
|
|
19
19
|
import {ZERO_HASH} from "../constants/index.js";
|
|
20
20
|
import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
21
|
-
import {getBlockRootAtSlot} from "./blockRoot.js";
|
|
22
21
|
import {computeDomain} from "./domain.js";
|
|
23
22
|
import {computeEpochAtSlot} from "./epoch.js";
|
|
24
23
|
import {computeEpochShuffling} from "./epochShuffling.js";
|
|
@@ -32,11 +31,13 @@ export function isBuilderWithdrawalCredential(withdrawalCredentials: Uint8Array)
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
export function getBuilderPaymentQuorumThreshold(state: CachedBeaconStateGloas): number {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
// total active balance exceeds Number.MAX_SAFE_INTEGER at mainnet scale, keep the intermediate math in bigint
|
|
35
|
+
const perSlotBalance =
|
|
36
|
+
(BigInt(state.epochCtx.totalActiveBalanceIncrements) * BigInt(EFFECTIVE_BALANCE_INCREMENT)) /
|
|
37
|
+
BigInt(SLOTS_PER_EPOCH);
|
|
38
|
+
const quorum = perSlotBalance * BigInt(BUILDER_PAYMENT_THRESHOLD_NUMERATOR);
|
|
38
39
|
|
|
39
|
-
return
|
|
40
|
+
return Number(quorum / BigInt(BUILDER_PAYMENT_THRESHOLD_DENOMINATOR));
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
function hasBuilderIndexFlag(index: number): boolean {
|
|
@@ -188,15 +189,9 @@ export function findBuilderIndexByPubkey(state: CachedBeaconStateGloas, pubkey:
|
|
|
188
189
|
return null;
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const isMatchingBlockRoot = byteArrayEquals(data.beaconBlockRoot, getBlockRootAtSlot(state, data.slot));
|
|
195
|
-
const isCurrentBlockRoot = !byteArrayEquals(data.beaconBlockRoot, getBlockRootAtSlot(state, data.slot - 1));
|
|
196
|
-
|
|
197
|
-
return isMatchingBlockRoot && isCurrentBlockRoot;
|
|
198
|
-
}
|
|
199
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Use cached block roots to avoid repeated state root lookups while matching the spec's is_attestation_same_slot behavior.
|
|
194
|
+
*/
|
|
200
195
|
export function isAttestationSameSlotRootCache(rootCache: RootCache, data: AttestationData): boolean {
|
|
201
196
|
if (data.slot === 0) return true;
|
|
202
197
|
|
package/src/util/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from "./shuffling.js";
|
|
|
25
25
|
export * from "./signatureSets.js";
|
|
26
26
|
export * from "./signingRoot.js";
|
|
27
27
|
export * from "./slot.js";
|
|
28
|
+
export * from "./ssz.js";
|
|
28
29
|
export * from "./syncCommittee.js";
|
|
29
30
|
export * from "./validator.js";
|
|
30
31
|
export * from "./weakSubjectivity.js";
|
package/src/util/ssz.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {BranchNode, LeafNode, Node, zeroNode} from "@chainsafe/persistent-merkle-tree";
|
|
2
|
+
import {progressiveSubtreeFillToContents} from "@chainsafe/ssz";
|
|
3
|
+
|
|
4
|
+
// TODO: move these utils to @chainsafe/ssz (progressive.ts, next to progressiveSubtreeFillToContents)
|
|
5
|
+
|
|
6
|
+
/** Root node (chunks + length mix-in) of a zero-filled ProgressiveListBasicType of `length` items */
|
|
7
|
+
export function zeroProgressiveListBasicRootNode(itemsPerChunk: number, length: number): Node {
|
|
8
|
+
const chunkCount = Math.ceil(length / itemsPerChunk);
|
|
9
|
+
// mirrors ssz's progressiveSubtreeCount (subtree capacities 1, 4, 16, ...)
|
|
10
|
+
let numSubtrees = 0;
|
|
11
|
+
for (let remaining = chunkCount, subtreeLength = 1; remaining > 0; subtreeLength *= 4) {
|
|
12
|
+
remaining -= Math.min(remaining, subtreeLength);
|
|
13
|
+
numSubtrees++;
|
|
14
|
+
}
|
|
15
|
+
return new BranchNode(zeroProgressiveNode(numSubtrees), LeafNode.fromUint32(length));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Root node of a progressive list from its chunk/element nodes + length mix-in.
|
|
20
|
+
* `nodes` are packed 32-byte chunk leaves for basic lists, or element root nodes for composite lists.
|
|
21
|
+
*/
|
|
22
|
+
export function progressiveListRootNode(nodes: Node[], length: number): Node {
|
|
23
|
+
return new BranchNode(progressiveSubtreeFillToContents(nodes), LeafNode.fromUint32(length));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Return the chunks node of a zero-filled progressive merkle list spanning `numSubtrees`
|
|
28
|
+
* balanced subtrees (chunk capacities 1, 4, 16, ... = 4^i; depths 0, 2, 4, ... = 2i).
|
|
29
|
+
*
|
|
30
|
+
* Not memoized: the zero data is already fully shared via the cached zeroNode(2i) subtrees;
|
|
31
|
+
* only the O(numSubtrees) spine BranchNodes (~10 at 2M validators) are allocated per call.
|
|
32
|
+
*/
|
|
33
|
+
function zeroProgressiveNode(numSubtrees: number): Node {
|
|
34
|
+
// chain(k) = B(zeroNode(0), B(zeroNode(2), ... B(zeroNode(2(k-1)), zeroNode(0))))
|
|
35
|
+
let node: Node = zeroNode(0); // terminator
|
|
36
|
+
for (let i = numSubtrees - 1; i >= 0; i--) {
|
|
37
|
+
// BranchNode(left: balanced subtree i, right: rest of chain) — chain grows to the right,
|
|
38
|
+
// same as ssz progressiveSubtreeFillToContents: `root = new BranchNode(subtreeRoots[i], root)`
|
|
39
|
+
node = new BranchNode(zeroNode(2 * i), node);
|
|
40
|
+
}
|
|
41
|
+
return node;
|
|
42
|
+
}
|