@lodestar/state-transition 1.48.0-dev.84285dbabf → 1.48.0-dev.b0ce010779
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/index.d.ts.map +1 -1
- package/lib/block/index.js +3 -2
- package/lib/block/index.js.map +1 -1
- package/lib/block/processExecutionPayloadBid.d.ts +2 -2
- package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadBid.js +3 -2
- package/lib/block/processExecutionPayloadBid.js.map +1 -1
- package/lib/block/processParentExecutionPayload.js +1 -1
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +8 -2
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/epoch/processInactivityUpdates.d.ts.map +1 -1
- package/lib/epoch/processInactivityUpdates.js +7 -1
- package/lib/epoch/processInactivityUpdates.js.map +1 -1
- package/lib/epoch/processPtcWindow.js +1 -1
- package/lib/epoch/processPtcWindow.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts +1 -1
- package/lib/lightClient/spec/index.d.ts.map +1 -1
- package/lib/lightClient/spec/index.js +1 -1
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +13 -3
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +108 -34
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/rewards/blockRewards.d.ts.map +1 -1
- package/lib/rewards/blockRewards.js +1 -3
- package/lib/rewards/blockRewards.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +1 -1
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +2 -1
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +3 -0
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +2 -1
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +3 -1
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js +7 -0
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/package.json +7 -7
- package/src/block/index.ts +5 -2
- package/src/block/processExecutionPayloadBid.ts +6 -5
- package/src/block/processParentExecutionPayload.ts +1 -1
- package/src/block/processWithdrawals.ts +12 -2
- package/src/epoch/processInactivityUpdates.ts +8 -1
- package/src/epoch/processPtcWindow.ts +1 -1
- package/src/lightClient/spec/index.ts +2 -0
- package/src/lightClient/spec/utils.ts +142 -48
- package/src/rewards/blockRewards.ts +1 -3
- package/src/slot/upgradeStateToGloas.ts +1 -1
- package/src/stateView/beaconStateView.ts +4 -0
- package/src/stateView/interface.ts +2 -0
- package/src/stateView/nativeBeaconStateView.ts +9 -1
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ChainSafe/lodestar/issues"
|
|
13
13
|
},
|
|
14
|
-
"version": "1.48.0-dev.
|
|
14
|
+
"version": "1.48.0-dev.b0ce010779",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -70,14 +70,14 @@
|
|
|
70
70
|
"@chainsafe/persistent-merkle-tree": "^1.3.1",
|
|
71
71
|
"@chainsafe/ssz": "^1.6.3",
|
|
72
72
|
"@chainsafe/swap-or-not-shuffle": "^1.2.1",
|
|
73
|
-
"@lodestar/config": "^1.48.0-dev.
|
|
74
|
-
"@lodestar/params": "^1.48.0-dev.
|
|
75
|
-
"@lodestar/types": "^1.48.0-dev.
|
|
76
|
-
"@lodestar/utils": "^1.48.0-dev.
|
|
73
|
+
"@lodestar/config": "^1.48.0-dev.b0ce010779",
|
|
74
|
+
"@lodestar/params": "^1.48.0-dev.b0ce010779",
|
|
75
|
+
"@lodestar/types": "^1.48.0-dev.b0ce010779",
|
|
76
|
+
"@lodestar/utils": "^1.48.0-dev.b0ce010779",
|
|
77
77
|
"@vekexasia/bigint-buffer2": "^1.1.1"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@lodestar/api": "^1.48.0-dev.
|
|
80
|
+
"@lodestar/api": "^1.48.0-dev.b0ce010779"
|
|
81
81
|
},
|
|
82
82
|
"keywords": [
|
|
83
83
|
"ethereum",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"beacon",
|
|
86
86
|
"blockchain"
|
|
87
87
|
],
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "f92bab2a1cac36007e7c63d1504219c92b95407c"
|
|
89
89
|
}
|
package/src/block/index.ts
CHANGED
|
@@ -53,6 +53,10 @@ export function processBlock(
|
|
|
53
53
|
): void {
|
|
54
54
|
const {verifySignatures = true} = opts ?? {};
|
|
55
55
|
|
|
56
|
+
// Capture the parent block's slot before processBlockHeader overwrites latestBlockHeader
|
|
57
|
+
const parentSlot: Slot | null =
|
|
58
|
+
fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).latestBlockHeader.slot : null;
|
|
59
|
+
|
|
56
60
|
// Apply the parent's deferred payload effects before everything else. Must run before
|
|
57
61
|
// processBlockHeader and processExecutionPayloadBid so subsequent steps see the updated state.
|
|
58
62
|
if (fork >= ForkSeq.gloas) {
|
|
@@ -86,9 +90,8 @@ export function processBlock(
|
|
|
86
90
|
processExecutionPayload(fork, state as CachedBeaconStateBellatrix, block.body, externalData);
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
let parentSlot: Slot | null = null;
|
|
90
93
|
if (fork >= ForkSeq.gloas) {
|
|
91
|
-
|
|
94
|
+
processExecutionPayloadBid(
|
|
92
95
|
state as CachedBeaconStateGloas,
|
|
93
96
|
(block as BeaconBlock<ForkPostGloas>).body.signedExecutionPayloadBid
|
|
94
97
|
);
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
PAYLOAD_BUILDER_VERSION,
|
|
6
6
|
SLOTS_PER_EPOCH,
|
|
7
7
|
} from "@lodestar/params";
|
|
8
|
-
import {
|
|
8
|
+
import {gloas, heze, ssz} from "@lodestar/types";
|
|
9
9
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
10
10
|
import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
|
|
11
11
|
import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
export function processExecutionPayloadBid(
|
|
23
23
|
state: CachedBeaconStateGloas | CachedBeaconStateHeze,
|
|
24
24
|
signedBid: gloas.SignedExecutionPayloadBid
|
|
25
|
-
):
|
|
25
|
+
): void {
|
|
26
26
|
const bid = signedBid.message;
|
|
27
27
|
const {builderIndex, value: amount} = bid;
|
|
28
28
|
|
|
@@ -76,6 +76,10 @@ export function processExecutionPayloadBid(
|
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
|
|
80
|
+
throw Error(`Block hash ${toRootHex(bid.blockHash)} of bid must not equal its parent block hash`);
|
|
81
|
+
}
|
|
82
|
+
|
|
79
83
|
const parentBlockRoot = getBlockRootAtSlot(state, state.slot - 1);
|
|
80
84
|
if (!byteArrayEquals(bid.parentBlockRoot, parentBlockRoot)) {
|
|
81
85
|
throw Error(
|
|
@@ -110,14 +114,11 @@ export function processExecutionPayloadBid(
|
|
|
110
114
|
state.builderPendingPayments.set(SLOTS_PER_EPOCH + (bid.slot % SLOTS_PER_EPOCH), pendingPaymentView);
|
|
111
115
|
}
|
|
112
116
|
|
|
113
|
-
const parentSlot = state.latestExecutionPayloadBid.slot;
|
|
114
117
|
if (state.config.getForkSeq(state.slot) >= ForkSeq.heze) {
|
|
115
118
|
state.latestExecutionPayloadBid = ssz.heze.ExecutionPayloadBid.toViewDU(bid as heze.ExecutionPayloadBid);
|
|
116
119
|
} else {
|
|
117
120
|
state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid);
|
|
118
121
|
}
|
|
119
|
-
|
|
120
|
-
return parentSlot;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
function verifyExecutionPayloadBidSignature(
|
|
@@ -59,7 +59,7 @@ export function applyParentExecutionPayload(state: CachedBeaconStateGloas, reque
|
|
|
59
59
|
|
|
60
60
|
const fork = state.config.getForkSeq(state.slot);
|
|
61
61
|
const parentBid = state.latestExecutionPayloadBid;
|
|
62
|
-
const parentSlot =
|
|
62
|
+
const parentSlot = state.latestBlockHeader.slot;
|
|
63
63
|
const parentEpoch = computeEpochAtSlot(parentSlot);
|
|
64
64
|
const currentEpoch = computeEpochAtSlot(state.slot);
|
|
65
65
|
|
|
@@ -212,7 +212,12 @@ function getBuildersSweepWithdrawals(
|
|
|
212
212
|
break;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
// Get next builder in turn
|
|
215
|
+
// Get next builder in turn, the spec does not wrap around an out of bounds start index
|
|
216
|
+
if (n === 0 && state.nextWithdrawalBuilderIndex >= builders.length) {
|
|
217
|
+
throw Error(
|
|
218
|
+
`Next withdrawal builder index ${state.nextWithdrawalBuilderIndex} out of bounds, builders count ${builders.length}`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
216
221
|
const builderIndex = (state.nextWithdrawalBuilderIndex + n) % builders.length;
|
|
217
222
|
const builder = builders.getReadonly(builderIndex);
|
|
218
223
|
|
|
@@ -340,7 +345,12 @@ function getValidatorsSweepWithdrawals(
|
|
|
340
345
|
break;
|
|
341
346
|
}
|
|
342
347
|
|
|
343
|
-
// Get next validator in turn
|
|
348
|
+
// Get next validator in turn, the spec does not wrap around an out of bounds start index
|
|
349
|
+
if (n === 0 && nextWithdrawalValidatorIndex >= validators.length) {
|
|
350
|
+
throw Error(
|
|
351
|
+
`Next withdrawal validator index ${nextWithdrawalValidatorIndex} out of bounds, validators count ${validators.length}`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
344
354
|
const validatorIndex = (nextWithdrawalValidatorIndex + n) % validators.length;
|
|
345
355
|
|
|
346
356
|
const validator = validators.getReadonly(validatorIndex);
|
|
@@ -37,6 +37,7 @@ export function processInactivityUpdates(state: CachedBeaconStateAltair, cache:
|
|
|
37
37
|
|
|
38
38
|
inactivityScoresArr.length = state.validators.length;
|
|
39
39
|
inactivityScores.getAll(inactivityScoresArr);
|
|
40
|
+
let shouldSetInactivityScores = false;
|
|
40
41
|
|
|
41
42
|
for (let i = 0; i < flags.length; i++) {
|
|
42
43
|
const flag = flags[i];
|
|
@@ -53,8 +54,14 @@ export function processInactivityUpdates(state: CachedBeaconStateAltair, cache:
|
|
|
53
54
|
inactivityScore -= Math.min(INACTIVITY_SCORE_RECOVERY_RATE, inactivityScore);
|
|
54
55
|
}
|
|
55
56
|
if (inactivityScore !== prevInactivityScore) {
|
|
56
|
-
|
|
57
|
+
inactivityScoresArr[i] = inactivityScore;
|
|
58
|
+
shouldSetInactivityScores = true;
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
}
|
|
62
|
+
|
|
63
|
+
if (shouldSetInactivityScores) {
|
|
64
|
+
// Rebuilding the full view is slightly slower than individual sets only when very few scores change.
|
|
65
|
+
state.inactivityScores = state.type.fields.inactivityScores.toViewDU(inactivityScoresArr);
|
|
66
|
+
}
|
|
60
67
|
}
|
|
@@ -30,7 +30,7 @@ export function processPtcWindow(state: CachedBeaconStateGloas, cache: EpochTran
|
|
|
30
30
|
|
|
31
31
|
// Write shifted window to state: current(N) + next(N+1) + newlyComputed(N+2)
|
|
32
32
|
// From the perspective of upcoming epoch N+1, this is previous + current + next
|
|
33
|
-
state.ptcWindow = ssz.gloas.
|
|
33
|
+
state.ptcWindow = ssz.gloas.PayloadTimelinessCommitteeWindow.toViewDU([
|
|
34
34
|
...state.epochCtx.payloadTimelinessCommittees,
|
|
35
35
|
...state.epochCtx.nextPayloadTimelinessCommittees,
|
|
36
36
|
...newNextPayloadTimelinessCommittees,
|
|
@@ -32,11 +32,13 @@ export {
|
|
|
32
32
|
type SyncCommitteeFast,
|
|
33
33
|
} from "./store.js";
|
|
34
34
|
export {
|
|
35
|
+
getLightClientExecutionRoot,
|
|
35
36
|
getSafetyThreshold,
|
|
36
37
|
isFinalityUpdate,
|
|
37
38
|
isSyncCommitteeUpdate,
|
|
38
39
|
isValidLightClientHeader,
|
|
39
40
|
normalizeMerkleBranch,
|
|
41
|
+
upgradeLightClientBootstrap,
|
|
40
42
|
upgradeLightClientFinalityUpdate,
|
|
41
43
|
upgradeLightClientHeader,
|
|
42
44
|
upgradeLightClientOptimisticUpdate,
|
|
@@ -23,18 +23,18 @@ import {
|
|
|
23
23
|
} from "@lodestar/params";
|
|
24
24
|
import {
|
|
25
25
|
BeaconBlockHeader,
|
|
26
|
+
LightClientBootstrap,
|
|
26
27
|
LightClientFinalityUpdate,
|
|
27
28
|
LightClientHeader,
|
|
28
29
|
LightClientOptimisticUpdate,
|
|
29
30
|
LightClientUpdate,
|
|
30
|
-
Slot,
|
|
31
31
|
SyncCommittee,
|
|
32
32
|
isElectraLightClientUpdate,
|
|
33
33
|
ssz,
|
|
34
34
|
} from "@lodestar/types";
|
|
35
|
-
import {byteArrayEquals, verifyMerkleBranch} from "@lodestar/utils";
|
|
36
|
-
import {computeEpochAtSlot
|
|
37
|
-
import type {
|
|
35
|
+
import {byteArrayEquals, hash, verifyMerkleBranch} from "@lodestar/utils";
|
|
36
|
+
import {computeEpochAtSlot} from "../../util/epoch.js";
|
|
37
|
+
import type {ILightClientStore, SyncCommitteeFast} from "./store.js";
|
|
38
38
|
|
|
39
39
|
export const GENESIS_SLOT = 0;
|
|
40
40
|
export const ZERO_HASH = new Uint8Array(32);
|
|
@@ -201,6 +201,76 @@ function getGindexIndex(gindex: number): number {
|
|
|
201
201
|
return gindex - 2 ** getGindexDepth(gindex);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Returns the execution root represented by a light-client header.
|
|
206
|
+
*
|
|
207
|
+
* Gloas headers removed `execution` so Pre-Gloas headers upgraded to the Gloas format
|
|
208
|
+
* require reconstruction of the original execution payload header root.
|
|
209
|
+
*
|
|
210
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/light-client/sync-protocol.md#modified-get_lc_execution_root
|
|
211
|
+
*/
|
|
212
|
+
export function getLightClientExecutionRoot(config: ChainForkConfig, header: LightClientHeader): Uint8Array {
|
|
213
|
+
const epoch = computeEpochAtSlot(header.beacon.slot);
|
|
214
|
+
|
|
215
|
+
if (!isGloasLightClientHeader(header)) {
|
|
216
|
+
if (epoch < config.CAPELLA_FORK_EPOCH) {
|
|
217
|
+
return ZERO_HASH;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return config
|
|
221
|
+
.getPostBellatrixForkTypes(header.beacon.slot)
|
|
222
|
+
.ExecutionPayloadHeader.hashTreeRoot((header as LightClientHeader<ForkName.capella>).execution);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (epoch >= config.GLOAS_FORK_EPOCH) {
|
|
226
|
+
return header.executionBlockHash;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Reconstruct the pre-Gloas execution payload root for a header upgraded to the Gloas format
|
|
230
|
+
// because the structure is different, `execution` is removed
|
|
231
|
+
const executionPayloadDepth = getGindexDepth(BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX);
|
|
232
|
+
const innerBranch = header.executionBranch.slice(0, -executionPayloadDepth);
|
|
233
|
+
|
|
234
|
+
if (epoch >= config.DENEB_FORK_EPOCH) {
|
|
235
|
+
if (header.beacon.slot === GENESIS_SLOT) {
|
|
236
|
+
return ssz.deneb.ExecutionPayloadHeader.hashTreeRoot(ssz.deneb.ExecutionPayloadHeader.defaultValue());
|
|
237
|
+
}
|
|
238
|
+
return computeBranchRoot(
|
|
239
|
+
header.executionBlockHash,
|
|
240
|
+
innerBranch,
|
|
241
|
+
ssz.deneb.ExecutionPayloadHeader.getPathInfo(["blockHash"]).gindex
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (epoch >= config.CAPELLA_FORK_EPOCH) {
|
|
246
|
+
if (header.beacon.slot === GENESIS_SLOT) {
|
|
247
|
+
return ssz.capella.ExecutionPayloadHeader.hashTreeRoot(ssz.capella.ExecutionPayloadHeader.defaultValue());
|
|
248
|
+
}
|
|
249
|
+
return computeBranchRoot(
|
|
250
|
+
header.executionBlockHash,
|
|
251
|
+
innerBranch,
|
|
252
|
+
ssz.capella.ExecutionPayloadHeader.getPathInfo(["blockHash"]).gindex
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return ZERO_HASH;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function upgradeLightClientBootstrap(
|
|
260
|
+
config: ChainForkConfig,
|
|
261
|
+
targetFork: ForkName,
|
|
262
|
+
bootstrap: LightClientBootstrap
|
|
263
|
+
): LightClientBootstrap {
|
|
264
|
+
return {
|
|
265
|
+
...bootstrap,
|
|
266
|
+
header: upgradeLightClientHeader(config, targetFork, bootstrap.header),
|
|
267
|
+
currentSyncCommitteeBranch: normalizeMerkleBranch(
|
|
268
|
+
bootstrap.currentSyncCommitteeBranch,
|
|
269
|
+
currentSyncCommitteeGindexAtFork(targetFork)
|
|
270
|
+
),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
204
274
|
export function upgradeLightClientHeader(
|
|
205
275
|
config: ChainForkConfig,
|
|
206
276
|
targetFork: ForkName,
|
|
@@ -211,9 +281,7 @@ export function upgradeLightClientHeader(
|
|
|
211
281
|
throw Error(`Invalid upgrade request from headerFork=${headerFork} to targetFork=${targetFork}`);
|
|
212
282
|
}
|
|
213
283
|
|
|
214
|
-
|
|
215
|
-
// not required as of now
|
|
216
|
-
let upgradedHeader = header;
|
|
284
|
+
let upgradedHeader = {...header} as LightClientHeader;
|
|
217
285
|
const startUpgradeFromFork = Object.values(ForkName)[ForkSeq[headerFork] + 1];
|
|
218
286
|
|
|
219
287
|
switch (startUpgradeFromFork) {
|
|
@@ -231,23 +299,30 @@ export function upgradeLightClientHeader(
|
|
|
231
299
|
|
|
232
300
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
233
301
|
case ForkName.capella:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
ssz.capella.LightClientHeader.fields.executionBranch.defaultValue()
|
|
302
|
+
upgradedHeader = {
|
|
303
|
+
...upgradedHeader,
|
|
304
|
+
execution: ssz.capella.LightClientHeader.fields.execution.defaultValue(),
|
|
305
|
+
executionBranch: ssz.capella.LightClientHeader.fields.executionBranch.defaultValue(),
|
|
306
|
+
} as LightClientHeader<ForkName.capella>;
|
|
238
307
|
|
|
239
308
|
// Break if no further upgradation is required else fall through
|
|
240
309
|
if (ForkSeq[targetFork] <= ForkSeq.capella) break;
|
|
241
310
|
|
|
242
311
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
243
|
-
case ForkName.deneb:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
312
|
+
case ForkName.deneb: {
|
|
313
|
+
const capellaHeader = upgradedHeader as LightClientHeader<ForkName.capella>;
|
|
314
|
+
upgradedHeader = {
|
|
315
|
+
...capellaHeader,
|
|
316
|
+
execution: {
|
|
317
|
+
...capellaHeader.execution,
|
|
318
|
+
blobGasUsed: ssz.deneb.LightClientHeader.fields.execution.fields.blobGasUsed.defaultValue(),
|
|
319
|
+
excessBlobGas: ssz.deneb.LightClientHeader.fields.execution.fields.excessBlobGas.defaultValue(),
|
|
320
|
+
},
|
|
321
|
+
} as LightClientHeader<ForkName.deneb>;
|
|
248
322
|
|
|
249
323
|
// Break if no further upgradation is required else fall through
|
|
250
324
|
if (ForkSeq[targetFork] <= ForkSeq.deneb) break;
|
|
325
|
+
}
|
|
251
326
|
|
|
252
327
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
253
328
|
case ForkName.electra:
|
|
@@ -361,15 +436,16 @@ export function upgradeLightClientUpdate(
|
|
|
361
436
|
targetFork: ForkName,
|
|
362
437
|
update: LightClientUpdate
|
|
363
438
|
): LightClientUpdate {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
update.
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
439
|
+
return {
|
|
440
|
+
...update,
|
|
441
|
+
attestedHeader: upgradeLightClientHeader(config, targetFork, update.attestedHeader),
|
|
442
|
+
finalizedHeader: upgradeLightClientHeader(config, targetFork, update.finalizedHeader),
|
|
443
|
+
nextSyncCommitteeBranch: normalizeMerkleBranch(
|
|
444
|
+
update.nextSyncCommitteeBranch,
|
|
445
|
+
nextSyncCommitteeGindexAtFork(targetFork)
|
|
446
|
+
),
|
|
447
|
+
finalityBranch: normalizeMerkleBranch(update.finalityBranch, finalizedRootGindexAtFork(targetFork)),
|
|
448
|
+
};
|
|
373
449
|
}
|
|
374
450
|
|
|
375
451
|
export function upgradeLightClientFinalityUpdate(
|
|
@@ -377,14 +453,12 @@ export function upgradeLightClientFinalityUpdate(
|
|
|
377
453
|
targetFork: ForkName,
|
|
378
454
|
finalityUpdate: LightClientFinalityUpdate
|
|
379
455
|
): LightClientFinalityUpdate {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
finalityUpdate.
|
|
384
|
-
finalizedRootGindexAtFork(targetFork)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return finalityUpdate;
|
|
456
|
+
return {
|
|
457
|
+
...finalityUpdate,
|
|
458
|
+
attestedHeader: upgradeLightClientHeader(config, targetFork, finalityUpdate.attestedHeader),
|
|
459
|
+
finalizedHeader: upgradeLightClientHeader(config, targetFork, finalityUpdate.finalizedHeader),
|
|
460
|
+
finalityBranch: normalizeMerkleBranch(finalityUpdate.finalityBranch, finalizedRootGindexAtFork(targetFork)),
|
|
461
|
+
};
|
|
388
462
|
}
|
|
389
463
|
|
|
390
464
|
export function upgradeLightClientOptimisticUpdate(
|
|
@@ -392,9 +466,10 @@ export function upgradeLightClientOptimisticUpdate(
|
|
|
392
466
|
targetFork: ForkName,
|
|
393
467
|
optimisticUpdate: LightClientOptimisticUpdate
|
|
394
468
|
): LightClientOptimisticUpdate {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
469
|
+
return {
|
|
470
|
+
...optimisticUpdate,
|
|
471
|
+
attestedHeader: upgradeLightClientHeader(config, targetFork, optimisticUpdate.attestedHeader),
|
|
472
|
+
};
|
|
398
473
|
}
|
|
399
474
|
|
|
400
475
|
/**
|
|
@@ -405,25 +480,44 @@ export function upgradeLightClientOptimisticUpdate(
|
|
|
405
480
|
export function upgradeLightClientStore(
|
|
406
481
|
config: ChainForkConfig,
|
|
407
482
|
targetFork: ForkName,
|
|
408
|
-
store:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
update: upgradeLightClientUpdate(config, targetFork, bestValidUpdate.update),
|
|
417
|
-
summary: bestValidUpdate.summary,
|
|
483
|
+
store: ILightClientStore
|
|
484
|
+
): ILightClientStore {
|
|
485
|
+
const bestValidUpdates = new Map();
|
|
486
|
+
|
|
487
|
+
for (const [period, entry] of store.bestValidUpdates) {
|
|
488
|
+
bestValidUpdates.set(period, {
|
|
489
|
+
...entry,
|
|
490
|
+
update: upgradeLightClientUpdate(config, targetFork, entry.update),
|
|
418
491
|
});
|
|
419
492
|
}
|
|
493
|
+
const finalizedHeader = upgradeLightClientHeader(config, targetFork, store.finalizedHeader);
|
|
494
|
+
const optimisticHeader = upgradeLightClientHeader(config, targetFork, store.optimisticHeader);
|
|
420
495
|
|
|
421
|
-
|
|
422
|
-
|
|
496
|
+
for (const [period, bestValidUpdate] of bestValidUpdates) {
|
|
497
|
+
store.bestValidUpdates.set(period, bestValidUpdate);
|
|
498
|
+
}
|
|
499
|
+
store.finalizedHeader = finalizedHeader;
|
|
500
|
+
store.optimisticHeader = optimisticHeader;
|
|
423
501
|
|
|
424
502
|
return store;
|
|
425
503
|
}
|
|
426
504
|
|
|
505
|
+
function computeBranchRoot(leaf: Uint8Array, branch: Uint8Array[], gindex: bigint): Uint8Array {
|
|
506
|
+
const depth = getGindexDepth(Number(gindex));
|
|
507
|
+
if (branch.length < depth) {
|
|
508
|
+
throw Error(`Invalid Merkle branch length ${branch.length}, expected at least ${depth}`);
|
|
509
|
+
}
|
|
510
|
+
const proof = branch.slice(-depth);
|
|
511
|
+
const index = getGindexIndex(Number(gindex));
|
|
512
|
+
let root = leaf;
|
|
513
|
+
|
|
514
|
+
for (let i = 0; i < depth; i++) {
|
|
515
|
+
root = Math.floor(index / 2 ** i) % 2 === 1 ? hash(proof[i], root) : hash(root, proof[i]);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return root;
|
|
519
|
+
}
|
|
520
|
+
|
|
427
521
|
function isGloasLightClientHeader(header: LightClientHeader): header is LightClientHeader<ForkName.gloas> {
|
|
428
522
|
return (header as LightClientHeader<ForkName.gloas>).executionBlockHash !== undefined;
|
|
429
523
|
}
|
|
@@ -42,9 +42,7 @@ export async function computeBlockRewards(
|
|
|
42
42
|
let syncAggregateReward = cachedSyncAggregateReward;
|
|
43
43
|
|
|
44
44
|
if (blockAttestationReward === 0) {
|
|
45
|
-
const parentSlot = isForkPostGloas(fork)
|
|
46
|
-
? (preState as CachedBeaconStateGloas).latestExecutionPayloadBid.slot
|
|
47
|
-
: null;
|
|
45
|
+
const parentSlot = isForkPostGloas(fork) ? (preState as CachedBeaconStateGloas).latestBlockHeader.slot : null;
|
|
48
46
|
blockAttestationReward =
|
|
49
47
|
fork === ForkName.phase0
|
|
50
48
|
? computeBlockAttestationRewardPhase0(block as phase0.BeaconBlock, preState as CachedBeaconStatePhase0)
|
|
@@ -110,7 +110,7 @@ export function upgradeStateToGloas(
|
|
|
110
110
|
ssz.gloas.PendingConsolidations
|
|
111
111
|
);
|
|
112
112
|
stateGloasView.proposerLookahead = stateGloasCloned.proposerLookahead;
|
|
113
|
-
stateGloasView.ptcWindow = ssz.gloas.
|
|
113
|
+
stateGloasView.ptcWindow = ssz.gloas.PayloadTimelinessCommitteeWindow.toViewDU(initializePtcWindow(stateFulu));
|
|
114
114
|
|
|
115
115
|
for (let i = 0; i < SLOTS_PER_HISTORICAL_ROOT; i++) {
|
|
116
116
|
stateGloasView.executionPayloadAvailability.set(i, true);
|
|
@@ -116,6 +116,10 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
116
116
|
return this.config.getForkName(this.cachedState.slot);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
get forkSeq(): ForkSeq {
|
|
120
|
+
return this.config.getForkSeq(this.cachedState.slot);
|
|
121
|
+
}
|
|
122
|
+
|
|
119
123
|
get slot(): number {
|
|
120
124
|
return this.cachedState.slot;
|
|
121
125
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ForkPostFulu,
|
|
11
11
|
ForkPostGloas,
|
|
12
12
|
ForkPostHeze,
|
|
13
|
+
ForkSeq,
|
|
13
14
|
isForkPostAltair,
|
|
14
15
|
isForkPostBellatrix,
|
|
15
16
|
isForkPostCapella,
|
|
@@ -77,6 +78,7 @@ export interface IBeaconStateView {
|
|
|
77
78
|
|
|
78
79
|
// phase0
|
|
79
80
|
forkName: ForkName;
|
|
81
|
+
forkSeq: ForkSeq;
|
|
80
82
|
slot: Slot;
|
|
81
83
|
fork: Fork;
|
|
82
84
|
epoch: Epoch;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
|
-
import {ForkName} from "@lodestar/params";
|
|
3
|
+
import {ForkName, ForkSeq} from "@lodestar/params";
|
|
4
4
|
import {
|
|
5
5
|
BeaconBlock,
|
|
6
6
|
BeaconState,
|
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
67
67
|
// phase0
|
|
68
68
|
private _forkName: ForkName | null = null;
|
|
69
|
+
private _forkSeq: ForkSeq | null = null;
|
|
69
70
|
private _slot: Slot | null = null;
|
|
70
71
|
private _fork: Fork | null = null;
|
|
71
72
|
private _epoch: Epoch | null = null;
|
|
@@ -194,6 +195,13 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
194
195
|
return this._forkName;
|
|
195
196
|
}
|
|
196
197
|
|
|
198
|
+
get forkSeq(): ForkSeq {
|
|
199
|
+
if (this._forkSeq === null) {
|
|
200
|
+
this._forkSeq = this.binding.forkSeq;
|
|
201
|
+
}
|
|
202
|
+
return this._forkSeq;
|
|
203
|
+
}
|
|
204
|
+
|
|
197
205
|
get slot(): Slot {
|
|
198
206
|
if (this._slot === null) {
|
|
199
207
|
this._slot = this.binding.slot;
|