@lodestar/state-transition 1.46.0-dev.2063820a22 → 1.46.0-dev.20c6ad786e
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/externalData.js +2 -4
- package/lib/block/externalData.js.map +1 -1
- package/lib/block/index.js.map +1 -1
- package/lib/block/initiateValidatorExit.js.map +1 -1
- package/lib/block/isValidIndexedAttestation.js.map +1 -1
- package/lib/block/isValidIndexedPayloadAttestation.js.map +1 -1
- package/lib/block/processAttestationPhase0.js.map +1 -1
- package/lib/block/processAttestations.js.map +1 -1
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processAttesterSlashing.js.map +1 -1
- package/lib/block/processBlobKzgCommitments.js.map +1 -1
- package/lib/block/processBlockHeader.js.map +1 -1
- package/lib/block/processBlsToExecutionChange.js.map +1 -1
- package/lib/block/processBuilderDepositRequest.js.map +1 -1
- package/lib/block/processBuilderExitRequest.js.map +1 -1
- package/lib/block/processConsolidationRequest.js.map +1 -1
- package/lib/block/processDeposit.d.ts +15 -0
- package/lib/block/processDeposit.d.ts.map +1 -1
- package/lib/block/processDeposit.js +73 -1
- package/lib/block/processDeposit.js.map +1 -1
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processEth1Data.js.map +1 -1
- package/lib/block/processExecutionPayload.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 +8 -3
- package/lib/block/processExecutionPayloadBid.js.map +1 -1
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processPayloadAttestation.js.map +1 -1
- package/lib/block/processProposerSlashing.js.map +1 -1
- package/lib/block/processRandao.js.map +1 -1
- package/lib/block/processSyncCommittee.js.map +1 -1
- package/lib/block/processVoluntaryExit.js +1 -2
- package/lib/block/processVoluntaryExit.js.map +1 -1
- package/lib/block/processWithdrawalRequest.js.map +1 -1
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/block/slashValidator.js.map +1 -1
- package/lib/block/types.js +1 -2
- package/lib/block/types.js.map +1 -1
- package/lib/cache/builderDepositSignatureCache.d.ts +48 -0
- package/lib/cache/builderDepositSignatureCache.d.ts.map +1 -0
- package/lib/cache/builderDepositSignatureCache.js +70 -0
- package/lib/cache/builderDepositSignatureCache.js.map +1 -0
- package/lib/cache/effectiveBalanceIncrements.js.map +1 -1
- package/lib/cache/epochCache.d.ts +9 -0
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +14 -2
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/epochTransitionCache.js.map +1 -1
- package/lib/cache/pubkeyCache.js.map +1 -1
- package/lib/cache/rewardCache.js.map +1 -1
- package/lib/cache/stateCache.d.ts +2 -1
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +3 -2
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/cache/syncCommitteeCache.js.map +1 -1
- package/lib/cache/types.d.ts +1 -0
- package/lib/cache/types.d.ts.map +1 -1
- package/lib/epoch/computeUnrealizedCheckpoints.js.map +1 -1
- package/lib/epoch/getAttestationDeltas.js.map +1 -1
- package/lib/epoch/getRewardsAndPenalties.js.map +1 -1
- package/lib/epoch/index.js +1 -2
- package/lib/epoch/index.js.map +1 -1
- package/lib/epoch/processBuilderPendingPayments.js.map +1 -1
- package/lib/epoch/processEffectiveBalanceUpdates.js.map +1 -1
- package/lib/epoch/processEth1DataReset.js.map +1 -1
- package/lib/epoch/processHistoricalRootsUpdate.js.map +1 -1
- package/lib/epoch/processHistoricalSummariesUpdate.js.map +1 -1
- package/lib/epoch/processInactivityUpdates.js.map +1 -1
- package/lib/epoch/processJustificationAndFinalization.js.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.js.map +1 -1
- package/lib/epoch/processParticipationRecordUpdates.js.map +1 -1
- package/lib/epoch/processPendingAttestations.js.map +1 -1
- package/lib/epoch/processPendingConsolidations.js.map +1 -1
- package/lib/epoch/processPendingDeposits.js.map +1 -1
- package/lib/epoch/processProposerLookahead.js.map +1 -1
- package/lib/epoch/processPtcWindow.js.map +1 -1
- package/lib/epoch/processRandaoMixesReset.js.map +1 -1
- package/lib/epoch/processRegistryUpdates.js.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.js.map +1 -1
- package/lib/epoch/processSlashings.js.map +1 -1
- package/lib/epoch/processSlashingsReset.js.map +1 -1
- package/lib/epoch/processSyncCommitteeUpdates.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/lightClient/proofs.js.map +1 -1
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/isBetterUpdate.js.map +1 -1
- package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -1
- package/lib/lightClient/spec/store.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +0 -2
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +8 -2
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
- package/lib/metrics.d.ts.map +1 -1
- package/lib/metrics.js +3 -2
- package/lib/metrics.js.map +1 -1
- package/lib/rewards/attestationsRewards.js.map +1 -1
- package/lib/rewards/blockRewards.js.map +1 -1
- package/lib/rewards/syncCommitteeRewards.js.map +1 -1
- package/lib/signatureSets/attesterSlashings.js.map +1 -1
- package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
- package/lib/signatureSets/executionPayloadBid.d.ts +2 -2
- package/lib/signatureSets/executionPayloadBid.d.ts.map +1 -1
- package/lib/signatureSets/executionPayloadBid.js +7 -5
- package/lib/signatureSets/executionPayloadBid.js.map +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/indexedAttestation.js.map +1 -1
- package/lib/signatureSets/indexedPayloadAttestation.js.map +1 -1
- package/lib/signatureSets/proposer.js.map +1 -1
- package/lib/signatureSets/proposerPreferences.js.map +1 -1
- package/lib/signatureSets/proposerSlashings.js.map +1 -1
- package/lib/signatureSets/randao.js.map +1 -1
- package/lib/signatureSets/voluntaryExits.js.map +1 -1
- package/lib/slot/index.d.ts +1 -0
- package/lib/slot/index.d.ts.map +1 -1
- package/lib/slot/index.js +1 -0
- package/lib/slot/index.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/slot/upgradeStateToBellatrix.js.map +1 -1
- package/lib/slot/upgradeStateToCapella.js.map +1 -1
- package/lib/slot/upgradeStateToDeneb.js.map +1 -1
- package/lib/slot/upgradeStateToElectra.js.map +1 -1
- package/lib/slot/upgradeStateToFulu.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +13 -7
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/slot/upgradeStateToHeze.d.ts +7 -0
- package/lib/slot/upgradeStateToHeze.d.ts.map +1 -0
- package/lib/slot/upgradeStateToHeze.js +83 -0
- package/lib/slot/upgradeStateToHeze.js.map +1 -0
- package/lib/stateTransition.d.ts.map +1 -1
- package/lib/stateTransition.js +6 -5
- package/lib/stateTransition.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +3 -0
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +7 -0
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +16 -3
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js +4 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +3 -0
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js +6 -0
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/lib/stateView/stateViewFactory.js.map +1 -1
- package/lib/testUtils/infura.js.map +1 -1
- package/lib/testUtils/interop.js.map +1 -1
- package/lib/testUtils/params.d.ts.map +1 -1
- package/lib/testUtils/state.js +1 -1
- package/lib/testUtils/state.js.map +1 -1
- package/lib/testUtils/testFileCache.js.map +1 -1
- package/lib/testUtils/util.d.ts +17 -2
- package/lib/testUtils/util.d.ts.map +1 -1
- package/lib/testUtils/util.js +57 -4
- package/lib/testUtils/util.js.map +1 -1
- package/lib/types.d.ts +2 -2
- package/lib/types.d.ts.map +1 -1
- package/lib/util/aggregator.js.map +1 -1
- package/lib/util/altair.js.map +1 -1
- package/lib/util/array.js.map +1 -1
- package/lib/util/attestation.js.map +1 -1
- package/lib/util/attesterStatus.js.map +1 -1
- package/lib/util/balance.js.map +1 -1
- package/lib/util/blindedBlock.js.map +1 -1
- package/lib/util/blockRoot.js.map +1 -1
- package/lib/util/capella.js.map +1 -1
- package/lib/util/clock.d.ts +6 -0
- package/lib/util/clock.d.ts.map +1 -1
- package/lib/util/clock.js +1 -2
- package/lib/util/clock.js.map +1 -1
- package/lib/util/computeAnchorCheckpoint.js.map +1 -1
- package/lib/util/deposit.d.ts.map +1 -1
- package/lib/util/deposit.js +10 -8
- package/lib/util/deposit.js.map +1 -1
- package/lib/util/domain.js.map +1 -1
- package/lib/util/electra.js.map +1 -1
- package/lib/util/epoch.js.map +1 -1
- package/lib/util/epochShuffling.js.map +1 -1
- package/lib/util/execution.js.map +1 -1
- package/lib/util/finality.js.map +1 -1
- package/lib/util/fulu.js.map +1 -1
- package/lib/util/genesis.d.ts.map +1 -1
- package/lib/util/genesis.js +7 -2
- package/lib/util/genesis.js.map +1 -1
- 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/interop.js.map +1 -1
- package/lib/util/loadState/findModifiedInactivityScores.js.map +1 -1
- package/lib/util/loadState/findModifiedValidators.js.map +1 -1
- package/lib/util/loadState/loadState.d.ts.map +1 -1
- package/lib/util/loadState/loadState.js +36 -5
- package/lib/util/loadState/loadState.js.map +1 -1
- package/lib/util/loadState/loadValidator.js.map +1 -1
- package/lib/util/pendingDepositsLookup.d.ts +7 -10
- package/lib/util/pendingDepositsLookup.d.ts.map +1 -1
- package/lib/util/pendingDepositsLookup.js +10 -19
- package/lib/util/pendingDepositsLookup.js.map +1 -1
- package/lib/util/preVerifyBuilderDeposits.d.ts +52 -0
- package/lib/util/preVerifyBuilderDeposits.d.ts.map +1 -0
- package/lib/util/preVerifyBuilderDeposits.js +124 -0
- package/lib/util/preVerifyBuilderDeposits.js.map +1 -0
- package/lib/util/rootCache.js.map +1 -1
- package/lib/util/seed.js.map +1 -1
- package/lib/util/shuffling.js +1 -2
- package/lib/util/shuffling.js.map +1 -1
- package/lib/util/signatureSets.js +1 -2
- package/lib/util/signatureSets.js.map +1 -1
- package/lib/util/signingRoot.js.map +1 -1
- package/lib/util/slot.js.map +1 -1
- package/lib/util/ssz.d.ts +5 -0
- package/lib/util/ssz.d.ts.map +1 -1
- package/lib/util/ssz.js +8 -1
- package/lib/util/ssz.js.map +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/lib/util/syncCommittee.js.map +1 -1
- package/lib/util/targetUnslashedBalance.js.map +1 -1
- package/lib/util/validator.d.ts +5 -0
- package/lib/util/validator.d.ts.map +1 -1
- package/lib/util/validator.js +9 -0
- package/lib/util/validator.js.map +1 -1
- package/lib/util/weakSubjectivity.d.ts +1 -0
- package/lib/util/weakSubjectivity.d.ts.map +1 -1
- package/lib/util/weakSubjectivity.js +20 -8
- package/lib/util/weakSubjectivity.js.map +1 -1
- package/package.json +9 -9
- package/src/block/processDeposit.ts +75 -1
- package/src/block/processExecutionPayloadBid.ts +18 -8
- package/src/cache/builderDepositSignatureCache.ts +81 -0
- package/src/cache/epochCache.ts +14 -0
- package/src/cache/stateCache.ts +5 -2
- package/src/cache/types.ts +1 -0
- package/src/index.ts +4 -0
- package/src/lightClient/spec/utils.ts +9 -2
- package/src/metrics.ts +3 -2
- package/src/signatureSets/executionPayloadBid.ts +7 -9
- package/src/slot/index.ts +1 -0
- package/src/slot/upgradeStateToGloas.ts +17 -10
- package/src/slot/upgradeStateToHeze.ts +91 -0
- package/src/stateTransition.ts +5 -0
- package/src/stateView/beaconStateView.ts +13 -0
- package/src/stateView/interface.ts +21 -2
- package/src/stateView/nativeBeaconStateView.ts +9 -0
- package/src/testUtils/state.ts +1 -1
- package/src/testUtils/util.ts +75 -5
- package/src/types.ts +2 -0
- package/src/util/deposit.ts +11 -9
- package/src/util/genesis.ts +8 -2
- package/src/util/index.ts +1 -0
- package/src/util/loadState/loadState.ts +50 -11
- package/src/util/pendingDepositsLookup.ts +13 -24
- package/src/util/preVerifyBuilderDeposits.ts +153 -0
- package/src/util/ssz.ts +9 -1
- package/src/util/validator.ts +17 -0
- package/src/util/weakSubjectivity.ts +61 -22
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.46.0-dev.
|
|
14
|
+
"version": "1.46.0-dev.20c6ad786e",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
],
|
|
53
53
|
"scripts": {
|
|
54
54
|
"clean": "rm -rf lib && rm -f *.tsbuildinfo",
|
|
55
|
-
"build": "
|
|
55
|
+
"build": "tsc -p tsconfig.build.json",
|
|
56
56
|
"build:watch": "pnpm run build --watch",
|
|
57
57
|
"build:release": "pnpm clean && pnpm build",
|
|
58
58
|
"check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"",
|
|
59
|
-
"check-types": "
|
|
59
|
+
"check-types": "tsc",
|
|
60
60
|
"lint": "biome check src/ test/",
|
|
61
61
|
"lint:fix": "pnpm run lint --write",
|
|
62
62
|
"test": "pnpm test:unit",
|
|
@@ -71,14 +71,14 @@
|
|
|
71
71
|
"@chainsafe/pubkey-index-map": "^3.0.0",
|
|
72
72
|
"@chainsafe/ssz": "^1.6.2",
|
|
73
73
|
"@chainsafe/swap-or-not-shuffle": "^1.2.1",
|
|
74
|
-
"@lodestar/config": "^1.46.0-dev.
|
|
75
|
-
"@lodestar/params": "^1.46.0-dev.
|
|
76
|
-
"@lodestar/types": "^1.46.0-dev.
|
|
77
|
-
"@lodestar/utils": "^1.46.0-dev.
|
|
74
|
+
"@lodestar/config": "^1.46.0-dev.20c6ad786e",
|
|
75
|
+
"@lodestar/params": "^1.46.0-dev.20c6ad786e",
|
|
76
|
+
"@lodestar/types": "^1.46.0-dev.20c6ad786e",
|
|
77
|
+
"@lodestar/utils": "^1.46.0-dev.20c6ad786e",
|
|
78
78
|
"@vekexasia/bigint-buffer2": "^1.1.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@lodestar/api": "^1.46.0-dev.
|
|
81
|
+
"@lodestar/api": "^1.46.0-dev.20c6ad786e"
|
|
82
82
|
},
|
|
83
83
|
"keywords": [
|
|
84
84
|
"ethereum",
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"beacon",
|
|
87
87
|
"blockchain"
|
|
88
88
|
],
|
|
89
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "cbbb5f48c160095f75eca9b15ef3633de29712bd"
|
|
90
90
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
1
|
+
import {PublicKey, Signature, verify, verifyMultipleAggregateSignatures} from "@chainsafe/blst";
|
|
2
2
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
3
|
import {
|
|
4
4
|
DEPOSIT_CONTRACT_TREE_DEPTH,
|
|
@@ -138,6 +138,10 @@ export function addValidatorToRegistry(
|
|
|
138
138
|
state.balances.push(amount);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Verify a single deposit signature (proof of possession). See {@link verifyDepositSignatures} for
|
|
143
|
+
* the batch equivalent — the two MUST stay consistent (same domain, signing root, and checks).
|
|
144
|
+
*/
|
|
141
145
|
export function isValidDepositSignature(
|
|
142
146
|
config: BeaconConfig,
|
|
143
147
|
pubkey: Uint8Array,
|
|
@@ -164,3 +168,73 @@ export function isValidDepositSignature(
|
|
|
164
168
|
return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature
|
|
165
169
|
}
|
|
166
170
|
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Batch equivalent of {@link isValidDepositSignature} — verify many deposit signatures at once.
|
|
174
|
+
* MUST stay consistent with `isValidDepositSignature`: same fork-agnostic deposit domain, same
|
|
175
|
+
* `DepositMessage` signing root, same group + infinity checks. Tries a single aggregate verify and,
|
|
176
|
+
* on failure, falls back to verifying each deposit individually so the valid deposits in a batch
|
|
177
|
+
* containing an invalid one are still identified. Returns a boolean per input deposit; `slot` is not
|
|
178
|
+
* part of the signature check.
|
|
179
|
+
*
|
|
180
|
+
* Used by the pre-Gloas builder-deposit pre-verify scanner (see `preVerifyBuilderDeposits.ts`).
|
|
181
|
+
*/
|
|
182
|
+
export function verifyDepositSignatures(config: BeaconConfig, deposits: electra.PendingDeposit[]): boolean[] {
|
|
183
|
+
const results = new Array<boolean>(deposits.length).fill(false);
|
|
184
|
+
// fork-agnostic domain since deposits are valid across forks, matching isValidDepositSignature
|
|
185
|
+
const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH);
|
|
186
|
+
|
|
187
|
+
const signatureSets: {pk: PublicKey; msg: Uint8Array; sig: Signature}[] = [];
|
|
188
|
+
const signatureSetDepositIndices: number[] = [];
|
|
189
|
+
for (let i = 0; i < deposits.length; i++) {
|
|
190
|
+
const {pubkey, withdrawalCredentials, amount, signature} = deposits[i];
|
|
191
|
+
let pk: PublicKey;
|
|
192
|
+
let sig: Signature;
|
|
193
|
+
try {
|
|
194
|
+
// Parse without group/infinity checks; deferred to the verify call below so it can be
|
|
195
|
+
// batched across all sets.
|
|
196
|
+
pk = PublicKey.fromBytes(pubkey);
|
|
197
|
+
sig = Signature.fromBytes(signature);
|
|
198
|
+
} catch (_) {
|
|
199
|
+
// Malformed pubkey or signature bytes - invalid deposit, results[i] stays false
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const msg = computeSigningRoot(ssz.phase0.DepositMessage, {pubkey, withdrawalCredentials, amount}, domain);
|
|
203
|
+
signatureSets.push({pk, msg, sig});
|
|
204
|
+
signatureSetDepositIndices.push(i);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (signatureSets.length === 0) {
|
|
208
|
+
return results;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Deposit pubkeys and signatures are untrusted, so group + infinity checks are required.
|
|
212
|
+
// The trailing (true, true) args delegate those checks to blst, amortized across the batch.
|
|
213
|
+
let batchValid: boolean;
|
|
214
|
+
try {
|
|
215
|
+
batchValid =
|
|
216
|
+
signatureSets.length >= 2
|
|
217
|
+
? verifyMultipleAggregateSignatures(signatureSets, true, true)
|
|
218
|
+
: verify(signatureSets[0].msg, signatureSets[0].pk, signatureSets[0].sig, true, true);
|
|
219
|
+
} catch (_) {
|
|
220
|
+
batchValid = false;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (batchValid) {
|
|
224
|
+
for (const depositIndex of signatureSetDepositIndices) {
|
|
225
|
+
results[depositIndex] = true;
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
for (let s = 0; s < signatureSets.length; s++) {
|
|
229
|
+
try {
|
|
230
|
+
if (verify(signatureSets[s].msg, signatureSets[s].pk, signatureSets[s].sig, true, true)) {
|
|
231
|
+
results[signatureSetDepositIndices[s]] = true;
|
|
232
|
+
}
|
|
233
|
+
} catch (_) {
|
|
234
|
+
// invalid point / malformed → invalid signature, results[i] stays false
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return results;
|
|
240
|
+
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
BUILDER_INDEX_SELF_BUILD,
|
|
4
|
+
ForkSeq,
|
|
5
|
+
GENESIS_SLOT,
|
|
6
|
+
PAYLOAD_BUILDER_VERSION,
|
|
7
|
+
SLOTS_PER_EPOCH,
|
|
8
|
+
} from "@lodestar/params";
|
|
9
|
+
import {Slot, gloas, heze, ssz} from "@lodestar/types";
|
|
4
10
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
5
11
|
import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
|
|
6
12
|
import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
|
|
7
|
-
import {CachedBeaconStateGloas} from "../types.js";
|
|
13
|
+
import {CachedBeaconStateGloas, CachedBeaconStateHeze} from "../types.js";
|
|
8
14
|
import {canBuilderCoverBid, isActiveBuilder} from "../util/gloas.js";
|
|
9
15
|
import {getBlockRootAtSlot, getCurrentEpoch, getRandaoMix} from "../util/index.js";
|
|
10
16
|
|
|
11
17
|
export function processExecutionPayloadBid(
|
|
12
|
-
state: CachedBeaconStateGloas,
|
|
18
|
+
state: CachedBeaconStateGloas | CachedBeaconStateHeze,
|
|
13
19
|
signedBid: gloas.SignedExecutionPayloadBid
|
|
14
20
|
): Slot {
|
|
15
21
|
const bid = signedBid.message;
|
|
@@ -41,7 +47,7 @@ export function processExecutionPayloadBid(
|
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
// Verify that the builder has funds to cover the bid
|
|
44
|
-
if (!canBuilderCoverBid(state, builderIndex, amount)) {
|
|
50
|
+
if (!canBuilderCoverBid(state as CachedBeaconStateGloas, builderIndex, amount)) {
|
|
45
51
|
throw Error(`Invalid execution payload bid: builder ${builderIndex} has insufficient balance`);
|
|
46
52
|
}
|
|
47
53
|
|
|
@@ -100,17 +106,21 @@ export function processExecutionPayloadBid(
|
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
const parentSlot = state.latestExecutionPayloadBid.slot;
|
|
103
|
-
state.
|
|
109
|
+
if (state.config.getForkSeq(state.slot) >= ForkSeq.heze) {
|
|
110
|
+
state.latestExecutionPayloadBid = ssz.heze.ExecutionPayloadBid.toViewDU(bid as heze.ExecutionPayloadBid);
|
|
111
|
+
} else {
|
|
112
|
+
state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid);
|
|
113
|
+
}
|
|
104
114
|
|
|
105
115
|
return parentSlot;
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
function verifyExecutionPayloadBidSignature(
|
|
109
|
-
state: CachedBeaconStateGloas,
|
|
119
|
+
state: CachedBeaconStateGloas | CachedBeaconStateHeze,
|
|
110
120
|
pubkey: Uint8Array,
|
|
111
121
|
signedBid: gloas.SignedExecutionPayloadBid
|
|
112
122
|
): boolean {
|
|
113
|
-
const signingRoot = getExecutionPayloadBidSigningRoot(state.config,
|
|
123
|
+
const signingRoot = getExecutionPayloadBidSigningRoot(state.config, signedBid.message);
|
|
114
124
|
|
|
115
125
|
try {
|
|
116
126
|
const publicKey = PublicKey.fromBytes(pubkey);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {PubkeyHex, electra} from "@lodestar/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Caches deposit signature-verification results — passes (`true`) and failures (`false`) — so the
|
|
5
|
+
* Fulu → Gloas fork transition can skip the bulk verification cost AND skip re-verifying deposits
|
|
6
|
+
* already proven invalid. Covers both builder-prefix deposits (onboarding) and validator deposits
|
|
7
|
+
* that share a pubkey with a builder deposit (the ones `hasPendingValidator` checks at the fork).
|
|
8
|
+
*
|
|
9
|
+
* Keyed by the deposit's struct **value object** — `electra.PendingDeposit` is a
|
|
10
|
+
* `ContainerNodeStructType`, so its `node.value` is a stable object reused across
|
|
11
|
+
* prepareNextSlot-derived states and carried by reference through the gloas pendingDeposits
|
|
12
|
+
* migration. No merkle-root computation, no slot bucketing.
|
|
13
|
+
*
|
|
14
|
+
* Also tracks builder pubkeys seen so the scanner knows which validator deposits to pre-verify (only
|
|
15
|
+
* those sharing a pubkey with a builder deposit ever reach `hasPendingValidator`). The mapped boolean
|
|
16
|
+
* records whether a *valid* validator deposit for that pubkey has been found: once true, the scanner
|
|
17
|
+
* stops pre-verifying further validator deposits for it — `hasPendingValidator` short-circuits on the
|
|
18
|
+
* first valid signature at the fork, so the rest would never be read.
|
|
19
|
+
*
|
|
20
|
+
* Lifecycle owned by `prepareNextSlot`: filled during the pre-fork window, then `clear()`ed once the
|
|
21
|
+
* Gloas fork is finalized. `onboardBuildersFromPendingDeposits()` only reads it. A plain `Map` (not a
|
|
22
|
+
* `WeakMap`) is used so the drop is deterministic and the contents are inspectable for logging.
|
|
23
|
+
*
|
|
24
|
+
* Single instance across the application (created in `EpochCache.createFromState`, shared
|
|
25
|
+
* by-reference through `clone()`).
|
|
26
|
+
*/
|
|
27
|
+
export class BuilderDepositSignatureCache {
|
|
28
|
+
private validityByDeposit = new Map<electra.PendingDeposit, boolean>();
|
|
29
|
+
/** builder pubkey → whether a valid validator deposit sharing it has already been pre-verified. */
|
|
30
|
+
private builderPubkeys = new Map<PubkeyHex, boolean>();
|
|
31
|
+
|
|
32
|
+
setSignatureValidity(deposit: electra.PendingDeposit, isValid: boolean): void {
|
|
33
|
+
this.validityByDeposit.set(deposit, isValid);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getSignatureValidity(deposit: electra.PendingDeposit): boolean | null {
|
|
37
|
+
return this.validityByDeposit.get(deposit) ?? null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
isVerified(deposit: electra.PendingDeposit): boolean {
|
|
41
|
+
return this.validityByDeposit.has(deposit);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Record a builder deposit's pubkey so the scanner pre-verifies validator deposits for it.
|
|
45
|
+
* Idempotent; never downgrades a pubkey already marked as having a valid validator deposit. */
|
|
46
|
+
addBuilderPubkey(pubkeyHex: PubkeyHex): void {
|
|
47
|
+
if (!this.builderPubkeys.has(pubkeyHex)) {
|
|
48
|
+
this.builderPubkeys.set(pubkeyHex, false);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
isBuilderPubkey(pubkeyHex: PubkeyHex): boolean {
|
|
53
|
+
return this.builderPubkeys.has(pubkeyHex);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** True once a valid validator deposit sharing this builder pubkey has been pre-verified — the
|
|
57
|
+
* scanner then skips this pubkey's remaining validator deposits (as `hasPendingValidator` would). */
|
|
58
|
+
hasValidValidatorDeposit(pubkeyHex: PubkeyHex): boolean {
|
|
59
|
+
return this.builderPubkeys.get(pubkeyHex) === true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Mark that a valid validator deposit sharing this builder pubkey was found. */
|
|
63
|
+
setValidValidatorDeposit(pubkeyHex: PubkeyHex): void {
|
|
64
|
+
this.builderPubkeys.set(pubkeyHex, true);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Cumulative deposits verified & cached this window (pass + fail). */
|
|
68
|
+
get cachedDepositCount(): number {
|
|
69
|
+
return this.validityByDeposit.size;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Distinct builder pubkeys tracked this window. */
|
|
73
|
+
get builderPubkeyCount(): number {
|
|
74
|
+
return this.builderPubkeys.size;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
clear(): void {
|
|
78
|
+
this.validityByDeposit.clear();
|
|
79
|
+
this.builderPubkeys.clear();
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/cache/epochCache.ts
CHANGED
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
} from "../util/shuffling.js";
|
|
54
54
|
import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js";
|
|
55
55
|
import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js";
|
|
56
|
+
import {BuilderDepositSignatureCache} from "./builderDepositSignatureCache.js";
|
|
56
57
|
import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js";
|
|
57
58
|
import {EpochTransitionCache} from "./epochTransitionCache.js";
|
|
58
59
|
import {PubkeyCache, createPubkeyCache, syncPubkeys} from "./pubkeyCache.js";
|
|
@@ -112,6 +113,13 @@ export class EpochCache {
|
|
|
112
113
|
* Couples both index→pubkey and pubkey→index lookups, keeping them in sync atomically.
|
|
113
114
|
*/
|
|
114
115
|
pubkeyCache: PubkeyCache;
|
|
116
|
+
/**
|
|
117
|
+
* Shared across all clones of the same chain head. Holds builder deposit signature validity
|
|
118
|
+
* pre-verified by the prepareForNextSlot scheduler in the `GLOAS_PREVERIFY_WINDOW_EPOCHS` epochs
|
|
119
|
+
* leading up to GLOAS_FORK_EPOCH, so `onboardBuildersFromPendingDeposits()` at the fork transition
|
|
120
|
+
* can skip the bulk verification cost. There should only exist one for the entire application.
|
|
121
|
+
*/
|
|
122
|
+
builderDepositSignatureCache: BuilderDepositSignatureCache;
|
|
115
123
|
/**
|
|
116
124
|
* Indexes of the block proposers for the current epoch.
|
|
117
125
|
* For pre-fulu, this is computed and cached from the current shuffling.
|
|
@@ -245,6 +253,7 @@ export class EpochCache {
|
|
|
245
253
|
constructor(data: {
|
|
246
254
|
config: BeaconConfig;
|
|
247
255
|
pubkeyCache: PubkeyCache;
|
|
256
|
+
builderDepositSignatureCache: BuilderDepositSignatureCache;
|
|
248
257
|
proposers: number[];
|
|
249
258
|
proposersPrevEpoch: number[] | null;
|
|
250
259
|
proposersNextEpoch: ProposersDeferred;
|
|
@@ -277,6 +286,7 @@ export class EpochCache {
|
|
|
277
286
|
}) {
|
|
278
287
|
this.config = data.config;
|
|
279
288
|
this.pubkeyCache = data.pubkeyCache;
|
|
289
|
+
this.builderDepositSignatureCache = data.builderDepositSignatureCache;
|
|
280
290
|
this.proposers = data.proposers;
|
|
281
291
|
this.proposersPrevEpoch = data.proposersPrevEpoch;
|
|
282
292
|
this.proposersNextEpoch = data.proposersNextEpoch;
|
|
@@ -514,6 +524,8 @@ export class EpochCache {
|
|
|
514
524
|
return new EpochCache({
|
|
515
525
|
config,
|
|
516
526
|
pubkeyCache,
|
|
527
|
+
// Created once per application (shared by-reference through clone()).
|
|
528
|
+
builderDepositSignatureCache: new BuilderDepositSignatureCache(),
|
|
517
529
|
proposers,
|
|
518
530
|
// On first epoch, set to null to prevent unnecessary work since this is only used for metrics
|
|
519
531
|
proposersPrevEpoch: null,
|
|
@@ -558,6 +570,8 @@ export class EpochCache {
|
|
|
558
570
|
config: this.config,
|
|
559
571
|
// Common append-only structures shared with all states, no need to clone
|
|
560
572
|
pubkeyCache: this.pubkeyCache,
|
|
573
|
+
// Singleton per application, shared by-reference across clones
|
|
574
|
+
builderDepositSignatureCache: this.builderDepositSignatureCache,
|
|
561
575
|
// Immutable data
|
|
562
576
|
proposers: this.proposers,
|
|
563
577
|
proposersPrevEpoch: this.proposersPrevEpoch,
|
package/src/cache/stateCache.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
2
|
import {loadState} from "../util/loadState/loadState.js";
|
|
3
|
+
import {isViewDUNodesPopulated} from "../util/ssz.js";
|
|
3
4
|
import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js";
|
|
4
5
|
import {RewardCache, createEmptyRewardCache} from "./rewardCache.js";
|
|
5
6
|
import {
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
BeaconStateExecutions,
|
|
13
14
|
BeaconStateFulu,
|
|
14
15
|
BeaconStateGloas,
|
|
16
|
+
BeaconStateHeze,
|
|
15
17
|
BeaconStatePhase0,
|
|
16
18
|
} from "./types.js";
|
|
17
19
|
|
|
@@ -136,6 +138,7 @@ export type CachedBeaconStateDeneb = CachedBeaconState<BeaconStateDeneb>;
|
|
|
136
138
|
export type CachedBeaconStateElectra = CachedBeaconState<BeaconStateElectra>;
|
|
137
139
|
export type CachedBeaconStateFulu = CachedBeaconState<BeaconStateFulu>;
|
|
138
140
|
export type CachedBeaconStateGloas = CachedBeaconState<BeaconStateGloas>;
|
|
141
|
+
export type CachedBeaconStateHeze = CachedBeaconState<BeaconStateHeze>;
|
|
139
142
|
|
|
140
143
|
export type CachedBeaconStateAllForks = CachedBeaconState<BeaconStateAllForks>;
|
|
141
144
|
export type CachedBeaconStateExecutions = CachedBeaconState<BeaconStateExecutions>;
|
|
@@ -254,9 +257,9 @@ export function isCachedBeaconState<T extends BeaconStateAllForks>(
|
|
|
254
257
|
// This cache is populated during epoch transition, and should be preserved for performance.
|
|
255
258
|
// If the cache is missing too often, means that our clone strategy is not working well.
|
|
256
259
|
export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
257
|
-
return (state.validators
|
|
260
|
+
return isViewDUNodesPopulated(state.validators);
|
|
258
261
|
}
|
|
259
262
|
|
|
260
263
|
export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
261
|
-
return (state.balances
|
|
264
|
+
return isViewDUNodesPopulated(state.balances);
|
|
262
265
|
}
|
package/src/cache/types.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type BeaconStateDeneb = CompositeViewDU<SSZTypesFor<ForkName.deneb, "Beac
|
|
|
11
11
|
export type BeaconStateElectra = CompositeViewDU<SSZTypesFor<ForkName.electra, "BeaconState">>;
|
|
12
12
|
export type BeaconStateFulu = CompositeViewDU<SSZTypesFor<ForkName.fulu, "BeaconState">>;
|
|
13
13
|
export type BeaconStateGloas = CompositeViewDU<SSZTypesFor<ForkName.gloas, "BeaconState">>;
|
|
14
|
+
export type BeaconStateHeze = CompositeViewDU<SSZTypesFor<ForkName.heze, "BeaconState">>;
|
|
14
15
|
|
|
15
16
|
export type BeaconStateAllForks = CompositeViewDU<SSZTypesFor<ForkAll, "BeaconState">>;
|
|
16
17
|
export type BeaconStateExecutions = CompositeViewDU<SSZTypesFor<ForkPostBellatrix & ForkPreGloas, "BeaconState">>;
|
package/src/index.ts
CHANGED
|
@@ -52,6 +52,7 @@ export {
|
|
|
52
52
|
type IBeaconStateViewElectra,
|
|
53
53
|
type IBeaconStateViewFulu,
|
|
54
54
|
type IBeaconStateViewGloas,
|
|
55
|
+
type IBeaconStateViewHeze,
|
|
55
56
|
isStatePostAltair,
|
|
56
57
|
isStatePostBellatrix,
|
|
57
58
|
isStatePostCapella,
|
|
@@ -59,6 +60,7 @@ export {
|
|
|
59
60
|
isStatePostElectra,
|
|
60
61
|
isStatePostFulu,
|
|
61
62
|
isStatePostGloas,
|
|
63
|
+
isStatePostHeze,
|
|
62
64
|
} from "./stateView/interface.js";
|
|
63
65
|
export {createBeaconStateView, createBeaconStateViewForHistoricalRegen} from "./stateView/stateViewFactory.js";
|
|
64
66
|
export type {
|
|
@@ -71,6 +73,7 @@ export type {
|
|
|
71
73
|
BeaconStateExecutions,
|
|
72
74
|
BeaconStateFulu,
|
|
73
75
|
BeaconStateGloas,
|
|
76
|
+
BeaconStateHeze,
|
|
74
77
|
// Non-cached states
|
|
75
78
|
BeaconStatePhase0,
|
|
76
79
|
CachedBeaconStateAllForks,
|
|
@@ -82,6 +85,7 @@ export type {
|
|
|
82
85
|
CachedBeaconStateExecutions,
|
|
83
86
|
CachedBeaconStateFulu,
|
|
84
87
|
CachedBeaconStateGloas,
|
|
88
|
+
CachedBeaconStateHeze,
|
|
85
89
|
CachedBeaconStatePhase0,
|
|
86
90
|
} from "./types.js";
|
|
87
91
|
export * from "./util/index.js";
|
|
@@ -193,11 +193,11 @@ export function nextSyncCommitteeGindexAtFork(fork: ForkName): number {
|
|
|
193
193
|
return NEXT_SYNC_COMMITTEE_GINDEX;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
|
|
196
|
+
function getGindexDepth(gindex: number): number {
|
|
197
197
|
return Math.floor(Math.log2(gindex));
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
function getGindexIndex(gindex: number): number {
|
|
201
201
|
return gindex - 2 ** getGindexDepth(gindex);
|
|
202
202
|
}
|
|
203
203
|
|
|
@@ -263,6 +263,7 @@ export function upgradeLightClientHeader(
|
|
|
263
263
|
// Break if no further upgrades is required else fall through
|
|
264
264
|
if (ForkSeq[targetFork] <= ForkSeq.fulu) break;
|
|
265
265
|
|
|
266
|
+
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
266
267
|
case ForkName.gloas:
|
|
267
268
|
if (isGloasLightClientHeader(upgradedHeader)) {
|
|
268
269
|
break;
|
|
@@ -272,6 +273,12 @@ export function upgradeLightClientHeader(
|
|
|
272
273
|
|
|
273
274
|
// Break if no further upgrades is required else fall through
|
|
274
275
|
if (ForkSeq[targetFork] <= ForkSeq.gloas) break;
|
|
276
|
+
|
|
277
|
+
case ForkName.heze:
|
|
278
|
+
// No changes to LightClientHeader in Heze
|
|
279
|
+
|
|
280
|
+
// Break if no further upgrades is required else fall through
|
|
281
|
+
if (ForkSeq[targetFork] <= ForkSeq.heze) break;
|
|
275
282
|
}
|
|
276
283
|
return upgradedHeader;
|
|
277
284
|
}
|
package/src/metrics.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {ProposerRewardType} from "./block/types.js";
|
|
|
3
3
|
import {EpochTransitionStep} from "./epoch/index.js";
|
|
4
4
|
import {StateCloneSource, StateHashTreeRootSource} from "./stateTransition.js";
|
|
5
5
|
import {CachedBeaconStateAllForks} from "./types.js";
|
|
6
|
+
import {isViewDUNodesPopulated} from "./util/ssz.js";
|
|
6
7
|
|
|
7
8
|
export type BeaconStateTransitionMetrics = ReturnType<typeof getMetrics>;
|
|
8
9
|
|
|
@@ -159,9 +160,9 @@ export function onPostStateMetrics(postState: CachedBeaconStateAllForks, metrics
|
|
|
159
160
|
// This cache is populated during epoch transition, and should be preserved for performance.
|
|
160
161
|
// If the cache is missing too often, means that our clone strategy is not working well.
|
|
161
162
|
function isValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
162
|
-
return (state.validators
|
|
163
|
+
return isViewDUNodesPopulated(state.validators);
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
function isBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
166
|
-
return (state.balances
|
|
167
|
+
return isViewDUNodesPopulated(state.balances);
|
|
167
168
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {DOMAIN_BEACON_BUILDER} from "@lodestar/params";
|
|
3
|
-
import {
|
|
2
|
+
import {DOMAIN_BEACON_BUILDER, isForkPostGloas} from "@lodestar/params";
|
|
3
|
+
import {ExecutionPayloadBid, ssz, sszTypesFor} from "@lodestar/types";
|
|
4
4
|
import {computeSigningRoot} from "../util/index.js";
|
|
5
5
|
|
|
6
|
-
export function getExecutionPayloadBidSigningRoot(
|
|
7
|
-
config
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
): Uint8Array {
|
|
11
|
-
const domain = config.getDomain(stateSlot, DOMAIN_BEACON_BUILDER);
|
|
6
|
+
export function getExecutionPayloadBidSigningRoot(config: BeaconConfig, bid: ExecutionPayloadBid): Uint8Array {
|
|
7
|
+
const fork = config.getForkName(bid.slot);
|
|
8
|
+
const domain = config.getDomain(bid.slot, DOMAIN_BEACON_BUILDER);
|
|
9
|
+
const sszType = isForkPostGloas(fork) ? sszTypesFor(fork).ExecutionPayloadBid : ssz.gloas.ExecutionPayloadBid;
|
|
12
10
|
|
|
13
|
-
return computeSigningRoot(
|
|
11
|
+
return computeSigningRoot(sszType, bid, domain);
|
|
14
12
|
}
|
package/src/slot/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export {upgradeStateToDeneb} from "./upgradeStateToDeneb.js";
|
|
|
10
10
|
export {upgradeStateToElectra} from "./upgradeStateToElectra.js";
|
|
11
11
|
export {upgradeStateToFulu} from "./upgradeStateToFulu.js";
|
|
12
12
|
export {upgradeStateToGloas} from "./upgradeStateToGloas.js";
|
|
13
|
+
export {upgradeStateToHeze} from "./upgradeStateToHeze.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Dial state to next slot. Common for all forks
|
|
@@ -172,8 +172,8 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
|
|
|
172
172
|
const pendingDeposits = ssz.gloas.PendingDeposits.defaultViewDU();
|
|
173
173
|
const pendingDepositsLookup = PendingDepositsLookup.buildEmpty();
|
|
174
174
|
|
|
175
|
-
for (
|
|
176
|
-
const
|
|
175
|
+
for (const deposit of state.pendingDeposits.getAllReadonly()) {
|
|
176
|
+
const depositValue = deposit.toValue();
|
|
177
177
|
|
|
178
178
|
const validatorIndex = state.epochCtx.getValidatorIndex(deposit.pubkey);
|
|
179
179
|
const pubkeyHex = toPubkeyHex(deposit.pubkey);
|
|
@@ -181,7 +181,7 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
|
|
|
181
181
|
// Deposits for existing validators stay in the pending queue
|
|
182
182
|
if (isValidatorKnown(state, validatorIndex)) {
|
|
183
183
|
pendingDeposits.push(deposit);
|
|
184
|
-
pendingDepositsLookup.add(
|
|
184
|
+
pendingDepositsLookup.add(depositValue, pubkeyHex);
|
|
185
185
|
continue;
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -202,26 +202,33 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
|
|
|
202
202
|
// can pick it up later.
|
|
203
203
|
if (!isBuilderWithdrawalCredential(deposit.withdrawalCredentials)) {
|
|
204
204
|
pendingDeposits.push(deposit);
|
|
205
|
-
pendingDepositsLookup.add(
|
|
205
|
+
pendingDepositsLookup.add(depositValue, pubkeyHex);
|
|
206
206
|
continue;
|
|
207
207
|
}
|
|
208
|
-
if (
|
|
208
|
+
if (
|
|
209
|
+
pendingDepositsLookup.hasPendingValidator(state.config, pubkeyHex, state.epochCtx.builderDepositSignatureCache)
|
|
210
|
+
) {
|
|
209
211
|
pendingDeposits.push(deposit);
|
|
210
|
-
pendingDepositsLookup.add(
|
|
212
|
+
pendingDepositsLookup.add(depositValue, pubkeyHex);
|
|
211
213
|
continue;
|
|
212
214
|
}
|
|
213
215
|
|
|
214
216
|
// Verify the deposit signature (proof of possession). If invalid the deposit is silently
|
|
215
217
|
// dropped — stake is forfeited, matching the validator deposit contract behavior.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
//
|
|
219
|
+
// The prepareNextSlot scheduler pre-verifies these signatures in the epochs before the fork
|
|
220
|
+
// A cache miss falls back to verifying this one deposit — no worse than pre-cache.
|
|
221
|
+
const cached = state.epochCtx.builderDepositSignatureCache.getSignatureValidity(depositValue);
|
|
222
|
+
const isValid =
|
|
223
|
+
cached ??
|
|
224
|
+
isValidDepositSignature(
|
|
218
225
|
state.config,
|
|
219
226
|
deposit.pubkey,
|
|
220
227
|
deposit.withdrawalCredentials,
|
|
221
228
|
deposit.amount,
|
|
222
229
|
deposit.signature
|
|
223
|
-
)
|
|
224
|
-
) {
|
|
230
|
+
);
|
|
231
|
+
if (!isValid) {
|
|
225
232
|
continue;
|
|
226
233
|
}
|
|
227
234
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {ssz} from "@lodestar/types";
|
|
2
|
+
import {getCachedBeaconState} from "../cache/stateCache.js";
|
|
3
|
+
import {CachedBeaconStateGloas, CachedBeaconStateHeze} from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Upgrade a state from Gloas to Heze.
|
|
7
|
+
* Spec: heze/fork.md `upgrade_to_heze`.
|
|
8
|
+
*/
|
|
9
|
+
export function upgradeStateToHeze(stateGloas: CachedBeaconStateGloas): CachedBeaconStateHeze {
|
|
10
|
+
const {config} = stateGloas;
|
|
11
|
+
|
|
12
|
+
ssz.gloas.BeaconState.commitViewDU(stateGloas);
|
|
13
|
+
const stateHezeCloned = stateGloas;
|
|
14
|
+
|
|
15
|
+
const stateHezeView = ssz.heze.BeaconState.defaultViewDU();
|
|
16
|
+
|
|
17
|
+
stateHezeView.genesisTime = stateHezeCloned.genesisTime;
|
|
18
|
+
stateHezeView.genesisValidatorsRoot = stateHezeCloned.genesisValidatorsRoot;
|
|
19
|
+
stateHezeView.slot = stateHezeCloned.slot;
|
|
20
|
+
stateHezeView.fork = ssz.phase0.Fork.toViewDU({
|
|
21
|
+
previousVersion: stateGloas.fork.currentVersion,
|
|
22
|
+
currentVersion: config.HEZE_FORK_VERSION,
|
|
23
|
+
epoch: stateGloas.epochCtx.epoch,
|
|
24
|
+
});
|
|
25
|
+
stateHezeView.latestBlockHeader = stateHezeCloned.latestBlockHeader;
|
|
26
|
+
stateHezeView.blockRoots = stateHezeCloned.blockRoots;
|
|
27
|
+
stateHezeView.stateRoots = stateHezeCloned.stateRoots;
|
|
28
|
+
stateHezeView.historicalRoots = stateHezeCloned.historicalRoots;
|
|
29
|
+
stateHezeView.eth1Data = stateHezeCloned.eth1Data;
|
|
30
|
+
stateHezeView.eth1DataVotes = stateHezeCloned.eth1DataVotes;
|
|
31
|
+
stateHezeView.eth1DepositIndex = stateHezeCloned.eth1DepositIndex;
|
|
32
|
+
stateHezeView.validators = stateHezeCloned.validators;
|
|
33
|
+
stateHezeView.balances = stateHezeCloned.balances;
|
|
34
|
+
stateHezeView.randaoMixes = stateHezeCloned.randaoMixes;
|
|
35
|
+
stateHezeView.slashings = stateHezeCloned.slashings;
|
|
36
|
+
stateHezeView.previousEpochParticipation = stateHezeCloned.previousEpochParticipation;
|
|
37
|
+
stateHezeView.currentEpochParticipation = stateHezeCloned.currentEpochParticipation;
|
|
38
|
+
stateHezeView.justificationBits = stateHezeCloned.justificationBits;
|
|
39
|
+
stateHezeView.previousJustifiedCheckpoint = stateHezeCloned.previousJustifiedCheckpoint;
|
|
40
|
+
stateHezeView.currentJustifiedCheckpoint = stateHezeCloned.currentJustifiedCheckpoint;
|
|
41
|
+
stateHezeView.finalizedCheckpoint = stateHezeCloned.finalizedCheckpoint;
|
|
42
|
+
stateHezeView.inactivityScores = stateHezeCloned.inactivityScores;
|
|
43
|
+
stateHezeView.currentSyncCommittee = stateHezeCloned.currentSyncCommittee;
|
|
44
|
+
stateHezeView.nextSyncCommittee = stateHezeCloned.nextSyncCommittee;
|
|
45
|
+
stateHezeView.latestBlockHash = stateHezeCloned.latestBlockHash;
|
|
46
|
+
stateHezeView.nextWithdrawalIndex = stateHezeCloned.nextWithdrawalIndex;
|
|
47
|
+
stateHezeView.nextWithdrawalValidatorIndex = stateHezeCloned.nextWithdrawalValidatorIndex;
|
|
48
|
+
stateHezeView.historicalSummaries = stateHezeCloned.historicalSummaries;
|
|
49
|
+
stateHezeView.depositRequestsStartIndex = stateHezeCloned.depositRequestsStartIndex;
|
|
50
|
+
stateHezeView.depositBalanceToConsume = stateHezeCloned.depositBalanceToConsume;
|
|
51
|
+
stateHezeView.exitBalanceToConsume = stateHezeCloned.exitBalanceToConsume;
|
|
52
|
+
stateHezeView.earliestExitEpoch = stateHezeCloned.earliestExitEpoch;
|
|
53
|
+
stateHezeView.consolidationBalanceToConsume = stateHezeCloned.consolidationBalanceToConsume;
|
|
54
|
+
stateHezeView.earliestConsolidationEpoch = stateHezeCloned.earliestConsolidationEpoch;
|
|
55
|
+
stateHezeView.pendingDeposits = stateHezeCloned.pendingDeposits;
|
|
56
|
+
stateHezeView.pendingPartialWithdrawals = stateHezeCloned.pendingPartialWithdrawals;
|
|
57
|
+
stateHezeView.pendingConsolidations = stateHezeCloned.pendingConsolidations;
|
|
58
|
+
stateHezeView.proposerLookahead = stateHezeCloned.proposerLookahead;
|
|
59
|
+
stateHezeView.builders = stateHezeCloned.builders;
|
|
60
|
+
stateHezeView.nextWithdrawalBuilderIndex = stateHezeCloned.nextWithdrawalBuilderIndex;
|
|
61
|
+
stateHezeView.executionPayloadAvailability = stateHezeCloned.executionPayloadAvailability;
|
|
62
|
+
stateHezeView.builderPendingPayments = stateHezeCloned.builderPendingPayments;
|
|
63
|
+
stateHezeView.builderPendingWithdrawals = stateHezeCloned.builderPendingWithdrawals;
|
|
64
|
+
|
|
65
|
+
// [Modified in Heze:EIP7805] inclusion_list_bits = Bitvector[INCLUSION_LIST_COMMITTEE_SIZE]() (default zero)
|
|
66
|
+
const oldBid = stateHezeCloned.latestExecutionPayloadBid;
|
|
67
|
+
const newBid = ssz.heze.ExecutionPayloadBid.defaultViewDU();
|
|
68
|
+
newBid.parentBlockHash = oldBid.parentBlockHash;
|
|
69
|
+
newBid.parentBlockRoot = oldBid.parentBlockRoot;
|
|
70
|
+
newBid.blockHash = oldBid.blockHash;
|
|
71
|
+
newBid.prevRandao = oldBid.prevRandao;
|
|
72
|
+
newBid.feeRecipient = oldBid.feeRecipient;
|
|
73
|
+
newBid.gasLimit = oldBid.gasLimit;
|
|
74
|
+
newBid.builderIndex = oldBid.builderIndex;
|
|
75
|
+
newBid.slot = oldBid.slot;
|
|
76
|
+
newBid.value = oldBid.value;
|
|
77
|
+
newBid.executionPayment = oldBid.executionPayment;
|
|
78
|
+
newBid.blobKzgCommitments = oldBid.blobKzgCommitments;
|
|
79
|
+
newBid.executionRequestsRoot = oldBid.executionRequestsRoot;
|
|
80
|
+
stateHezeView.latestExecutionPayloadBid = newBid;
|
|
81
|
+
|
|
82
|
+
stateHezeView.payloadExpectedWithdrawals = stateHezeCloned.payloadExpectedWithdrawals;
|
|
83
|
+
stateHezeView.ptcWindow = stateHezeCloned.ptcWindow;
|
|
84
|
+
|
|
85
|
+
const stateHeze = getCachedBeaconState(stateHezeView, stateGloas);
|
|
86
|
+
stateHeze.commit();
|
|
87
|
+
// biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute
|
|
88
|
+
stateHeze["clearCache"]();
|
|
89
|
+
|
|
90
|
+
return stateHeze;
|
|
91
|
+
}
|