@lodestar/state-transition 1.35.0-dev.fcf8d024ea → 1.35.0-dev.feed916580
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cache/types.d.ts +2 -2
- package/lib/util/genesis.js +3 -0
- package/lib/util/genesis.js.map +1 -1
- package/lib/util/slot.d.ts +1 -0
- package/lib/util/slot.js +5 -1
- package/lib/util/slot.js.map +1 -1
- package/package.json +11 -13
- package/lib/block/externalData.d.ts.map +0 -1
- package/lib/block/index.d.ts.map +0 -1
- package/lib/block/initiateValidatorExit.d.ts.map +0 -1
- package/lib/block/isValidIndexedAttestation.d.ts.map +0 -1
- package/lib/block/processAttestationPhase0.d.ts.map +0 -1
- package/lib/block/processAttestations.d.ts.map +0 -1
- package/lib/block/processAttestationsAltair.d.ts.map +0 -1
- package/lib/block/processAttesterSlashing.d.ts.map +0 -1
- package/lib/block/processBlobKzgCommitments.d.ts.map +0 -1
- package/lib/block/processBlockHeader.d.ts.map +0 -1
- package/lib/block/processBlsToExecutionChange.d.ts.map +0 -1
- package/lib/block/processConsolidationRequest.d.ts.map +0 -1
- package/lib/block/processDeposit.d.ts.map +0 -1
- package/lib/block/processDepositRequest.d.ts.map +0 -1
- package/lib/block/processEth1Data.d.ts.map +0 -1
- package/lib/block/processExecutionPayload.d.ts.map +0 -1
- package/lib/block/processOperations.d.ts.map +0 -1
- package/lib/block/processProposerSlashing.d.ts.map +0 -1
- package/lib/block/processRandao.d.ts.map +0 -1
- package/lib/block/processSyncCommittee.d.ts.map +0 -1
- package/lib/block/processVoluntaryExit.d.ts.map +0 -1
- package/lib/block/processWithdrawalRequest.d.ts.map +0 -1
- package/lib/block/processWithdrawals.d.ts.map +0 -1
- package/lib/block/slashValidator.d.ts.map +0 -1
- package/lib/block/types.d.ts.map +0 -1
- package/lib/cache/effectiveBalanceIncrements.d.ts.map +0 -1
- package/lib/cache/epochCache.d.ts.map +0 -1
- package/lib/cache/epochTransitionCache.d.ts.map +0 -1
- package/lib/cache/pubkeyCache.d.ts.map +0 -1
- package/lib/cache/rewardCache.d.ts.map +0 -1
- package/lib/cache/stateCache.d.ts.map +0 -1
- package/lib/cache/syncCommitteeCache.d.ts.map +0 -1
- package/lib/cache/types.d.ts.map +0 -1
- package/lib/constants/constants.d.ts.map +0 -1
- package/lib/constants/index.d.ts.map +0 -1
- package/lib/epoch/computeUnrealizedCheckpoints.d.ts.map +0 -1
- package/lib/epoch/getAttestationDeltas.d.ts.map +0 -1
- package/lib/epoch/getRewardsAndPenalties.d.ts.map +0 -1
- package/lib/epoch/index.d.ts.map +0 -1
- package/lib/epoch/processEffectiveBalanceUpdates.d.ts.map +0 -1
- package/lib/epoch/processEth1DataReset.d.ts.map +0 -1
- package/lib/epoch/processHistoricalRootsUpdate.d.ts.map +0 -1
- package/lib/epoch/processHistoricalSummariesUpdate.d.ts.map +0 -1
- package/lib/epoch/processInactivityUpdates.d.ts.map +0 -1
- package/lib/epoch/processJustificationAndFinalization.d.ts.map +0 -1
- package/lib/epoch/processParticipationFlagUpdates.d.ts.map +0 -1
- package/lib/epoch/processParticipationRecordUpdates.d.ts.map +0 -1
- package/lib/epoch/processPendingAttestations.d.ts.map +0 -1
- package/lib/epoch/processPendingConsolidations.d.ts.map +0 -1
- package/lib/epoch/processPendingDeposits.d.ts.map +0 -1
- package/lib/epoch/processProposerLookahead.d.ts.map +0 -1
- package/lib/epoch/processRandaoMixesReset.d.ts.map +0 -1
- package/lib/epoch/processRegistryUpdates.d.ts.map +0 -1
- package/lib/epoch/processRewardsAndPenalties.d.ts.map +0 -1
- package/lib/epoch/processSlashings.d.ts.map +0 -1
- package/lib/epoch/processSlashingsReset.d.ts.map +0 -1
- package/lib/epoch/processSyncCommitteeUpdates.d.ts.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/metrics.d.ts.map +0 -1
- package/lib/signatureSets/attesterSlashings.d.ts.map +0 -1
- package/lib/signatureSets/blsToExecutionChange.d.ts.map +0 -1
- package/lib/signatureSets/index.d.ts.map +0 -1
- package/lib/signatureSets/indexedAttestation.d.ts.map +0 -1
- package/lib/signatureSets/proposer.d.ts.map +0 -1
- package/lib/signatureSets/proposerSlashings.d.ts.map +0 -1
- package/lib/signatureSets/randao.d.ts.map +0 -1
- package/lib/signatureSets/voluntaryExits.d.ts.map +0 -1
- package/lib/slot/index.d.ts.map +0 -1
- package/lib/slot/upgradeStateToAltair.d.ts.map +0 -1
- package/lib/slot/upgradeStateToBellatrix.d.ts.map +0 -1
- package/lib/slot/upgradeStateToCapella.d.ts.map +0 -1
- package/lib/slot/upgradeStateToDeneb.d.ts.map +0 -1
- package/lib/slot/upgradeStateToElectra.d.ts.map +0 -1
- package/lib/slot/upgradeStateToFulu.d.ts.map +0 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +0 -1
- package/lib/stateTransition.d.ts.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/util/aggregator.d.ts.map +0 -1
- package/lib/util/altair.d.ts.map +0 -1
- package/lib/util/array.d.ts.map +0 -1
- package/lib/util/attestation.d.ts.map +0 -1
- package/lib/util/attesterStatus.d.ts.map +0 -1
- package/lib/util/balance.d.ts.map +0 -1
- package/lib/util/blindedBlock.d.ts.map +0 -1
- package/lib/util/blockRoot.d.ts.map +0 -1
- package/lib/util/calculateCommitteeAssignments.d.ts.map +0 -1
- package/lib/util/capella.d.ts.map +0 -1
- package/lib/util/computeAnchorCheckpoint.d.ts.map +0 -1
- package/lib/util/deposit.d.ts.map +0 -1
- package/lib/util/domain.d.ts.map +0 -1
- package/lib/util/electra.d.ts.map +0 -1
- package/lib/util/epoch.d.ts.map +0 -1
- package/lib/util/epochShuffling.d.ts.map +0 -1
- package/lib/util/execution.d.ts.map +0 -1
- package/lib/util/finality.d.ts.map +0 -1
- package/lib/util/fulu.d.ts.map +0 -1
- package/lib/util/genesis.d.ts.map +0 -1
- package/lib/util/index.d.ts.map +0 -1
- package/lib/util/interop.d.ts.map +0 -1
- package/lib/util/loadState/findModifiedInactivityScores.d.ts.map +0 -1
- package/lib/util/loadState/findModifiedValidators.d.ts.map +0 -1
- package/lib/util/loadState/index.d.ts.map +0 -1
- package/lib/util/loadState/loadState.d.ts.map +0 -1
- package/lib/util/loadState/loadValidator.d.ts.map +0 -1
- package/lib/util/rootCache.d.ts.map +0 -1
- package/lib/util/seed.d.ts.map +0 -1
- package/lib/util/shufflingDecisionRoot.d.ts.map +0 -1
- package/lib/util/signatureSets.d.ts.map +0 -1
- package/lib/util/signingRoot.d.ts.map +0 -1
- package/lib/util/slot.d.ts.map +0 -1
- package/lib/util/sszBytes.d.ts.map +0 -1
- package/lib/util/syncCommittee.d.ts.map +0 -1
- package/lib/util/targetUnslashedBalance.d.ts.map +0 -1
- package/lib/util/validator.d.ts.map +0 -1
- package/lib/util/weakSubjectivity.d.ts.map +0 -1
- package/src/block/externalData.ts +0 -26
- package/src/block/index.ts +0 -81
- package/src/block/initiateValidatorExit.ts +0 -62
- package/src/block/isValidIndexedAttestation.ts +0 -70
- package/src/block/processAttestationPhase0.ts +0 -158
- package/src/block/processAttestations.ts +0 -25
- package/src/block/processAttestationsAltair.ts +0 -184
- package/src/block/processAttesterSlashing.ts +0 -59
- package/src/block/processBlobKzgCommitments.ts +0 -21
- package/src/block/processBlockHeader.ts +0 -54
- package/src/block/processBlsToExecutionChange.ts +0 -78
- package/src/block/processConsolidationRequest.ts +0 -147
- package/src/block/processDeposit.ts +0 -166
- package/src/block/processDepositRequest.ts +0 -19
- package/src/block/processEth1Data.ts +0 -86
- package/src/block/processExecutionPayload.ts +0 -84
- package/src/block/processOperations.ts +0 -83
- package/src/block/processProposerSlashing.ts +0 -66
- package/src/block/processRandao.ts +0 -27
- package/src/block/processSyncCommittee.ts +0 -117
- package/src/block/processVoluntaryExit.ts +0 -55
- package/src/block/processWithdrawalRequest.ts +0 -98
- package/src/block/processWithdrawals.ts +0 -207
- package/src/block/slashValidator.ts +0 -98
- package/src/block/types.ts +0 -9
- package/src/cache/effectiveBalanceIncrements.ts +0 -39
- package/src/cache/epochCache.ts +0 -1213
- package/src/cache/epochTransitionCache.ts +0 -542
- package/src/cache/pubkeyCache.ts +0 -33
- package/src/cache/rewardCache.ts +0 -19
- package/src/cache/stateCache.ts +0 -268
- package/src/cache/syncCommitteeCache.ts +0 -96
- package/src/cache/types.ts +0 -18
- package/src/constants/constants.ts +0 -12
- package/src/constants/index.ts +0 -1
- package/src/epoch/computeUnrealizedCheckpoints.ts +0 -55
- package/src/epoch/getAttestationDeltas.ts +0 -169
- package/src/epoch/getRewardsAndPenalties.ts +0 -137
- package/src/epoch/index.ts +0 -202
- package/src/epoch/processEffectiveBalanceUpdates.ts +0 -111
- package/src/epoch/processEth1DataReset.ts +0 -17
- package/src/epoch/processHistoricalRootsUpdate.ts +0 -25
- package/src/epoch/processHistoricalSummariesUpdate.ts +0 -23
- package/src/epoch/processInactivityUpdates.ts +0 -60
- package/src/epoch/processJustificationAndFinalization.ts +0 -90
- package/src/epoch/processParticipationFlagUpdates.ts +0 -27
- package/src/epoch/processParticipationRecordUpdates.ts +0 -14
- package/src/epoch/processPendingAttestations.ts +0 -75
- package/src/epoch/processPendingConsolidations.ts +0 -59
- package/src/epoch/processPendingDeposits.ts +0 -136
- package/src/epoch/processProposerLookahead.ts +0 -39
- package/src/epoch/processRandaoMixesReset.ts +0 -18
- package/src/epoch/processRegistryUpdates.ts +0 -65
- package/src/epoch/processRewardsAndPenalties.ts +0 -58
- package/src/epoch/processSlashings.ts +0 -97
- package/src/epoch/processSlashingsReset.ts +0 -20
- package/src/epoch/processSyncCommitteeUpdates.ts +0 -44
- package/src/index.ts +0 -67
- package/src/metrics.ts +0 -169
- package/src/signatureSets/attesterSlashings.ts +0 -39
- package/src/signatureSets/blsToExecutionChange.ts +0 -43
- package/src/signatureSets/index.ts +0 -73
- package/src/signatureSets/indexedAttestation.ts +0 -51
- package/src/signatureSets/proposer.ts +0 -47
- package/src/signatureSets/proposerSlashings.ts +0 -41
- package/src/signatureSets/randao.ts +0 -31
- package/src/signatureSets/voluntaryExits.ts +0 -44
- package/src/slot/index.ts +0 -32
- package/src/slot/upgradeStateToAltair.ts +0 -149
- package/src/slot/upgradeStateToBellatrix.ts +0 -63
- package/src/slot/upgradeStateToCapella.ts +0 -71
- package/src/slot/upgradeStateToDeneb.ts +0 -40
- package/src/slot/upgradeStateToElectra.ts +0 -126
- package/src/slot/upgradeStateToFulu.ts +0 -31
- package/src/slot/upgradeStateToGloas.ts +0 -29
- package/src/stateTransition.ts +0 -305
- package/src/types.ts +0 -26
- package/src/util/aggregator.ts +0 -33
- package/src/util/altair.ts +0 -13
- package/src/util/array.ts +0 -53
- package/src/util/attestation.ts +0 -36
- package/src/util/attesterStatus.ts +0 -83
- package/src/util/balance.ts +0 -83
- package/src/util/blindedBlock.ts +0 -144
- package/src/util/blockRoot.ts +0 -72
- package/src/util/calculateCommitteeAssignments.ts +0 -43
- package/src/util/capella.ts +0 -8
- package/src/util/computeAnchorCheckpoint.ts +0 -38
- package/src/util/deposit.ts +0 -22
- package/src/util/domain.ts +0 -31
- package/src/util/electra.ts +0 -68
- package/src/util/epoch.ts +0 -135
- package/src/util/epochShuffling.ts +0 -185
- package/src/util/execution.ts +0 -177
- package/src/util/finality.ts +0 -17
- package/src/util/fulu.ts +0 -43
- package/src/util/genesis.ts +0 -340
- package/src/util/index.ts +0 -29
- package/src/util/interop.ts +0 -22
- package/src/util/loadState/findModifiedInactivityScores.ts +0 -47
- package/src/util/loadState/findModifiedValidators.ts +0 -46
- package/src/util/loadState/index.ts +0 -2
- package/src/util/loadState/loadState.ts +0 -225
- package/src/util/loadState/loadValidator.ts +0 -77
- package/src/util/rootCache.ts +0 -37
- package/src/util/seed.ts +0 -381
- package/src/util/shufflingDecisionRoot.ts +0 -78
- package/src/util/signatureSets.ts +0 -65
- package/src/util/signingRoot.ts +0 -13
- package/src/util/slot.ts +0 -22
- package/src/util/sszBytes.ts +0 -52
- package/src/util/syncCommittee.ts +0 -69
- package/src/util/targetUnslashedBalance.ts +0 -30
- package/src/util/validator.ts +0 -105
- package/src/util/weakSubjectivity.ts +0 -186
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
2
|
-
import {BeaconConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
4
|
-
DEPOSIT_CONTRACT_TREE_DEPTH,
|
|
5
|
-
DOMAIN_DEPOSIT,
|
|
6
|
-
EFFECTIVE_BALANCE_INCREMENT,
|
|
7
|
-
FAR_FUTURE_EPOCH,
|
|
8
|
-
ForkSeq,
|
|
9
|
-
GENESIS_SLOT,
|
|
10
|
-
MAX_EFFECTIVE_BALANCE,
|
|
11
|
-
} from "@lodestar/params";
|
|
12
|
-
import {BLSPubkey, Bytes32, UintNum64, electra, phase0, ssz} from "@lodestar/types";
|
|
13
|
-
import {verifyMerkleBranch} from "@lodestar/utils";
|
|
14
|
-
import {ZERO_HASH} from "../constants/index.js";
|
|
15
|
-
import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStateElectra} from "../types.js";
|
|
16
|
-
import {computeDomain, computeSigningRoot, getMaxEffectiveBalance, increaseBalance} from "../util/index.js";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Process a Deposit operation. Potentially adds a new validator to the registry. Mutates the validators and balances
|
|
20
|
-
* trees, pushing contigious values at the end.
|
|
21
|
-
*
|
|
22
|
-
* PERF: Work depends on number of Deposit per block. On regular networks the average is 0 / block.
|
|
23
|
-
*/
|
|
24
|
-
export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, deposit: phase0.Deposit): void {
|
|
25
|
-
// verify the merkle branch
|
|
26
|
-
if (
|
|
27
|
-
!verifyMerkleBranch(
|
|
28
|
-
ssz.phase0.DepositData.hashTreeRoot(deposit.data),
|
|
29
|
-
deposit.proof,
|
|
30
|
-
DEPOSIT_CONTRACT_TREE_DEPTH + 1,
|
|
31
|
-
state.eth1DepositIndex,
|
|
32
|
-
state.eth1Data.depositRoot
|
|
33
|
-
)
|
|
34
|
-
) {
|
|
35
|
-
throw new Error("Deposit has invalid merkle proof");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// deposits must be processed in order
|
|
39
|
-
state.eth1DepositIndex += 1;
|
|
40
|
-
|
|
41
|
-
applyDeposit(fork, state, deposit.data);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Adds a new validator into the registry. Or increase balance if already exist.
|
|
46
|
-
* Follows applyDeposit() in consensus spec. Will be used by processDeposit() and processDepositRequest()
|
|
47
|
-
*
|
|
48
|
-
*/
|
|
49
|
-
export function applyDeposit(
|
|
50
|
-
fork: ForkSeq,
|
|
51
|
-
state: CachedBeaconStateAllForks,
|
|
52
|
-
deposit: phase0.DepositData | electra.DepositRequest
|
|
53
|
-
): void {
|
|
54
|
-
const {config, epochCtx, validators} = state;
|
|
55
|
-
const {pubkey, withdrawalCredentials, amount, signature} = deposit;
|
|
56
|
-
|
|
57
|
-
const cachedIndex = epochCtx.getValidatorIndex(pubkey);
|
|
58
|
-
const isNewValidator = cachedIndex === null || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length;
|
|
59
|
-
|
|
60
|
-
if (fork < ForkSeq.electra) {
|
|
61
|
-
if (isNewValidator) {
|
|
62
|
-
if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, signature)) {
|
|
63
|
-
addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount);
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
// increase balance by deposit amount right away pre-electra
|
|
67
|
-
increaseBalance(state, cachedIndex, amount);
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
const stateElectra = state as CachedBeaconStateElectra;
|
|
71
|
-
const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({
|
|
72
|
-
pubkey,
|
|
73
|
-
withdrawalCredentials,
|
|
74
|
-
amount,
|
|
75
|
-
signature,
|
|
76
|
-
slot: GENESIS_SLOT, // Use GENESIS_SLOT to distinguish from a pending deposit request
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
if (isNewValidator) {
|
|
80
|
-
if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature)) {
|
|
81
|
-
addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, 0);
|
|
82
|
-
stateElectra.pendingDeposits.push(pendingDeposit);
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
stateElectra.pendingDeposits.push(pendingDeposit);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function addValidatorToRegistry(
|
|
91
|
-
fork: ForkSeq,
|
|
92
|
-
state: CachedBeaconStateAllForks,
|
|
93
|
-
pubkey: BLSPubkey,
|
|
94
|
-
withdrawalCredentials: Bytes32,
|
|
95
|
-
amount: UintNum64
|
|
96
|
-
): void {
|
|
97
|
-
const {validators, epochCtx} = state;
|
|
98
|
-
// add validator and balance entries
|
|
99
|
-
const effectiveBalance = Math.min(
|
|
100
|
-
amount - (amount % EFFECTIVE_BALANCE_INCREMENT),
|
|
101
|
-
fork < ForkSeq.electra ? MAX_EFFECTIVE_BALANCE : getMaxEffectiveBalance(withdrawalCredentials)
|
|
102
|
-
);
|
|
103
|
-
validators.push(
|
|
104
|
-
ssz.phase0.Validator.toViewDU({
|
|
105
|
-
pubkey,
|
|
106
|
-
withdrawalCredentials,
|
|
107
|
-
activationEligibilityEpoch: FAR_FUTURE_EPOCH,
|
|
108
|
-
activationEpoch: FAR_FUTURE_EPOCH,
|
|
109
|
-
exitEpoch: FAR_FUTURE_EPOCH,
|
|
110
|
-
withdrawableEpoch: FAR_FUTURE_EPOCH,
|
|
111
|
-
effectiveBalance,
|
|
112
|
-
slashed: false,
|
|
113
|
-
})
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const validatorIndex = validators.length - 1;
|
|
117
|
-
// TODO Electra: Review this
|
|
118
|
-
// Updating here is better than updating at once on epoch transition
|
|
119
|
-
// - Simplify genesis fn applyDeposits(): effectiveBalanceIncrements is populated immediately
|
|
120
|
-
// - Keep related code together to reduce risk of breaking this cache
|
|
121
|
-
// - Should have equal performance since it sets a value in a flat array
|
|
122
|
-
epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance);
|
|
123
|
-
|
|
124
|
-
// now that there is a new validator, update the epoch context with the new pubkey
|
|
125
|
-
epochCtx.addPubkey(validatorIndex, pubkey);
|
|
126
|
-
|
|
127
|
-
// Only after altair:
|
|
128
|
-
if (fork >= ForkSeq.altair) {
|
|
129
|
-
const stateAltair = state as CachedBeaconStateAltair;
|
|
130
|
-
|
|
131
|
-
stateAltair.inactivityScores.push(0);
|
|
132
|
-
|
|
133
|
-
// add participation caches
|
|
134
|
-
stateAltair.previousEpochParticipation.push(0);
|
|
135
|
-
stateAltair.currentEpochParticipation.push(0);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
state.balances.push(amount);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function isValidDepositSignature(
|
|
142
|
-
config: BeaconConfig,
|
|
143
|
-
pubkey: Uint8Array,
|
|
144
|
-
withdrawalCredentials: Uint8Array,
|
|
145
|
-
amount: number,
|
|
146
|
-
depositSignature: Uint8Array
|
|
147
|
-
): boolean {
|
|
148
|
-
// verify the deposit signature (proof of posession) which is not checked by the deposit contract
|
|
149
|
-
const depositMessage = {
|
|
150
|
-
pubkey,
|
|
151
|
-
withdrawalCredentials,
|
|
152
|
-
amount,
|
|
153
|
-
};
|
|
154
|
-
// fork-agnostic domain since deposits are valid across forks
|
|
155
|
-
const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH);
|
|
156
|
-
const signingRoot = computeSigningRoot(ssz.phase0.DepositMessage, depositMessage, domain);
|
|
157
|
-
try {
|
|
158
|
-
// Pubkeys must be checked for group + inf. This must be done only once when the validator deposit is processed
|
|
159
|
-
const publicKey = PublicKey.fromBytes(pubkey, true);
|
|
160
|
-
const signature = Signature.fromBytes(depositSignature, true);
|
|
161
|
-
|
|
162
|
-
return verify(signingRoot, publicKey, signature);
|
|
163
|
-
} catch (_e) {
|
|
164
|
-
return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature
|
|
165
|
-
}
|
|
166
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import {UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
|
|
2
|
-
import {electra, ssz} from "@lodestar/types";
|
|
3
|
-
import {CachedBeaconStateElectra} from "../types.js";
|
|
4
|
-
|
|
5
|
-
export function processDepositRequest(state: CachedBeaconStateElectra, depositRequest: electra.DepositRequest): void {
|
|
6
|
-
if (state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) {
|
|
7
|
-
state.depositRequestsStartIndex = depositRequest.index;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Create pending deposit
|
|
11
|
-
const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({
|
|
12
|
-
pubkey: depositRequest.pubkey,
|
|
13
|
-
withdrawalCredentials: depositRequest.withdrawalCredentials,
|
|
14
|
-
amount: depositRequest.amount,
|
|
15
|
-
signature: depositRequest.signature,
|
|
16
|
-
slot: state.slot,
|
|
17
|
-
});
|
|
18
|
-
state.pendingDeposits.push(pendingDeposit);
|
|
19
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import {Node} from "@chainsafe/persistent-merkle-tree";
|
|
2
|
-
import {CompositeViewDU} from "@chainsafe/ssz";
|
|
3
|
-
import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
4
|
-
import {phase0, ssz} from "@lodestar/types";
|
|
5
|
-
import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Store vote counts for every eth-execution block that has votes; if any eth-execution block wins majority support within a 1024-slot
|
|
9
|
-
* voting period, formally accept that eth-execution block and set it as the official "latest known eth-execution block" in the eth-consensus state.
|
|
10
|
-
*
|
|
11
|
-
* PERF: Processing cost depends on the current amount of votes.
|
|
12
|
-
* - Best case: Vote is already decided, zero work. See becomesNewEth1Data conditions
|
|
13
|
-
* - Worst case: 1023 votes and no majority vote yet.
|
|
14
|
-
*/
|
|
15
|
-
export function processEth1Data(state: CachedBeaconStateAllForks, eth1Data: phase0.Eth1Data): void {
|
|
16
|
-
// Convert to view first to hash once and compare hashes
|
|
17
|
-
const eth1DataView = ssz.phase0.Eth1Data.toViewDU(eth1Data);
|
|
18
|
-
|
|
19
|
-
if (becomesNewEth1Data(state, eth1DataView)) {
|
|
20
|
-
state.eth1Data = eth1DataView;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
state.eth1DataVotes.push(eth1DataView);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Returns true if adding the given `eth1Data` to `state.eth1DataVotes` would
|
|
28
|
-
* result in a change to `state.eth1Data`.
|
|
29
|
-
*/
|
|
30
|
-
export function becomesNewEth1Data(
|
|
31
|
-
state: BeaconStateAllForks,
|
|
32
|
-
newEth1Data: CompositeViewDU<typeof ssz.phase0.Eth1Data>
|
|
33
|
-
): boolean {
|
|
34
|
-
const SLOTS_PER_ETH1_VOTING_PERIOD = EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH;
|
|
35
|
-
|
|
36
|
-
// If there are not more than 50% votes, then we do not have to count to find a winner.
|
|
37
|
-
if ((state.eth1DataVotes.length + 1) * 2 <= SLOTS_PER_ETH1_VOTING_PERIOD) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Nothing to do if the state already has this as eth1data (happens a lot after majority vote is in)
|
|
42
|
-
if (isEqualEth1DataView(state.eth1Data, newEth1Data)) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Close to half the EPOCHS_PER_ETH1_VOTING_PERIOD it can be expensive to do so many comparisions.
|
|
47
|
-
// `eth1DataVotes.getAllReadonly()` navigates the tree once to fetch all the LeafNodes efficiently.
|
|
48
|
-
// Then isEqualEth1DataView compares cached roots (HashObject as of Jan 2022) which is much cheaper
|
|
49
|
-
// than doing structural equality, which requires tree -> value conversions
|
|
50
|
-
let sameVotesCount = 0;
|
|
51
|
-
// biome-ignore lint/complexity/noForEach: ssz api
|
|
52
|
-
state.eth1DataVotes.forEach((eth1DataVote) => {
|
|
53
|
-
if (isEqualEth1DataView(eth1DataVote, newEth1Data)) {
|
|
54
|
-
sameVotesCount++;
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// The +1 is to account for the `eth1Data` supplied to the function.
|
|
59
|
-
if ((sameVotesCount + 1) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD) {
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isEqualEth1DataView(
|
|
66
|
-
eth1DataA: CompositeViewDU<typeof ssz.phase0.Eth1Data>,
|
|
67
|
-
eth1DataB: CompositeViewDU<typeof ssz.phase0.Eth1Data>
|
|
68
|
-
): boolean {
|
|
69
|
-
return isEqualNode(eth1DataA.node, eth1DataB.node);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// TODO: Upstream to persistent-merkle-tree
|
|
73
|
-
function isEqualNode(nA: Node, nB: Node): boolean {
|
|
74
|
-
const hA = nA.rootHashObject;
|
|
75
|
-
const hB = nB.rootHashObject;
|
|
76
|
-
return (
|
|
77
|
-
hA.h0 === hB.h0 &&
|
|
78
|
-
hA.h1 === hB.h1 &&
|
|
79
|
-
hA.h2 === hB.h2 &&
|
|
80
|
-
hA.h3 === hB.h3 &&
|
|
81
|
-
hA.h4 === hB.h4 &&
|
|
82
|
-
hA.h5 === hB.h5 &&
|
|
83
|
-
hA.h6 === hB.h6 &&
|
|
84
|
-
hA.h7 === hB.h7
|
|
85
|
-
);
|
|
86
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import {byteArrayEquals} from "@chainsafe/ssz";
|
|
2
|
-
import {ForkName, ForkSeq, isForkPostDeneb} from "@lodestar/params";
|
|
3
|
-
import {BeaconBlockBody, BlindedBeaconBlockBody, deneb, isExecutionPayload} from "@lodestar/types";
|
|
4
|
-
import {toHex, toRootHex} from "@lodestar/utils";
|
|
5
|
-
import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js";
|
|
6
|
-
import {
|
|
7
|
-
executionPayloadToPayloadHeader,
|
|
8
|
-
getFullOrBlindedPayloadFromBody,
|
|
9
|
-
isMergeTransitionComplete,
|
|
10
|
-
} from "../util/execution.js";
|
|
11
|
-
import {computeEpochAtSlot, getRandaoMix} from "../util/index.js";
|
|
12
|
-
import {BlockExternalData, ExecutionPayloadStatus} from "./externalData.js";
|
|
13
|
-
|
|
14
|
-
export function processExecutionPayload(
|
|
15
|
-
fork: ForkSeq,
|
|
16
|
-
state: CachedBeaconStateBellatrix | CachedBeaconStateCapella,
|
|
17
|
-
body: BeaconBlockBody | BlindedBeaconBlockBody,
|
|
18
|
-
externalData: Omit<BlockExternalData, "dataAvailabilityStatus">
|
|
19
|
-
): void {
|
|
20
|
-
const payload = getFullOrBlindedPayloadFromBody(body);
|
|
21
|
-
const forkName = ForkName[ForkSeq[fork] as ForkName];
|
|
22
|
-
// Verify consistency of the parent hash, block number, base fee per gas and gas limit
|
|
23
|
-
// with respect to the previous execution payload header
|
|
24
|
-
if (isMergeTransitionComplete(state)) {
|
|
25
|
-
const {latestExecutionPayloadHeader} = state;
|
|
26
|
-
if (!byteArrayEquals(payload.parentHash, latestExecutionPayloadHeader.blockHash)) {
|
|
27
|
-
throw Error(
|
|
28
|
-
`Invalid execution payload parentHash ${toRootHex(payload.parentHash)} latest blockHash ${toRootHex(
|
|
29
|
-
latestExecutionPayloadHeader.blockHash
|
|
30
|
-
)}`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Verify random
|
|
36
|
-
const expectedRandom = getRandaoMix(state, state.epochCtx.epoch);
|
|
37
|
-
if (!byteArrayEquals(payload.prevRandao, expectedRandom)) {
|
|
38
|
-
throw Error(`Invalid execution payload random ${toHex(payload.prevRandao)} expected=${toHex(expectedRandom)}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Verify timestamp
|
|
42
|
-
//
|
|
43
|
-
// Note: inlined function in if statement
|
|
44
|
-
// def compute_timestamp_at_slot(state: BeaconState, slot: Slot) -> uint64:
|
|
45
|
-
// slots_since_genesis = slot - GENESIS_SLOT
|
|
46
|
-
// return uint64(state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT)
|
|
47
|
-
if (payload.timestamp !== state.genesisTime + state.slot * state.config.SECONDS_PER_SLOT) {
|
|
48
|
-
throw Error(`Invalid timestamp ${payload.timestamp} genesisTime=${state.genesisTime} slot=${state.slot}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (isForkPostDeneb(forkName)) {
|
|
52
|
-
const maxBlobsPerBlock = state.config.getMaxBlobsPerBlock(computeEpochAtSlot(state.slot));
|
|
53
|
-
const blobKzgCommitmentsLen = (body as deneb.BeaconBlockBody).blobKzgCommitments?.length ?? 0;
|
|
54
|
-
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
55
|
-
throw Error(`blobKzgCommitmentsLen of ${blobKzgCommitmentsLen} exceeds limit=${maxBlobsPerBlock}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Verify the execution payload is valid
|
|
60
|
-
//
|
|
61
|
-
// if executionEngine is null, executionEngine.onPayload MUST be called after running processBlock to get the
|
|
62
|
-
// correct randao mix. Since executionEngine will be an async call in most cases it is called afterwards to keep
|
|
63
|
-
// the state transition sync
|
|
64
|
-
//
|
|
65
|
-
// Equivalent to `assert executionEngine.notifyNewPayload(payload)`
|
|
66
|
-
if (isExecutionPayload(payload)) {
|
|
67
|
-
switch (externalData.executionPayloadStatus) {
|
|
68
|
-
case ExecutionPayloadStatus.preMerge:
|
|
69
|
-
throw Error("executionPayloadStatus preMerge");
|
|
70
|
-
case ExecutionPayloadStatus.invalid:
|
|
71
|
-
throw Error("Invalid execution payload");
|
|
72
|
-
case ExecutionPayloadStatus.valid:
|
|
73
|
-
break; // ok
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const payloadHeader = isExecutionPayload(payload) ? executionPayloadToPayloadHeader(fork, payload) : payload;
|
|
78
|
-
|
|
79
|
-
// TODO Deneb: Types are not happy by default. Since it's a generic type going through ViewDU
|
|
80
|
-
// transformation then into all forks compatible probably some weird intersection incompatibility happens
|
|
81
|
-
state.latestExecutionPayloadHeader = state.config
|
|
82
|
-
.getPostBellatrixForkTypes(state.slot)
|
|
83
|
-
.ExecutionPayloadHeader.toViewDU(payloadHeader) as typeof state.latestExecutionPayloadHeader;
|
|
84
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import {ForkSeq} from "@lodestar/params";
|
|
2
|
-
import {BeaconBlockBody, capella, electra} from "@lodestar/types";
|
|
3
|
-
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
4
|
-
import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js";
|
|
5
|
-
import {getEth1DepositCount} from "../util/deposit.js";
|
|
6
|
-
import {processAttestations} from "./processAttestations.js";
|
|
7
|
-
import {processAttesterSlashing} from "./processAttesterSlashing.js";
|
|
8
|
-
import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js";
|
|
9
|
-
import {processConsolidationRequest} from "./processConsolidationRequest.js";
|
|
10
|
-
import {processDeposit} from "./processDeposit.js";
|
|
11
|
-
import {processDepositRequest} from "./processDepositRequest.js";
|
|
12
|
-
import {processProposerSlashing} from "./processProposerSlashing.js";
|
|
13
|
-
import {processVoluntaryExit} from "./processVoluntaryExit.js";
|
|
14
|
-
import {processWithdrawalRequest} from "./processWithdrawalRequest.js";
|
|
15
|
-
import {ProcessBlockOpts} from "./types.js";
|
|
16
|
-
|
|
17
|
-
export {
|
|
18
|
-
processProposerSlashing,
|
|
19
|
-
processAttesterSlashing,
|
|
20
|
-
processAttestations,
|
|
21
|
-
processDeposit,
|
|
22
|
-
processVoluntaryExit,
|
|
23
|
-
processWithdrawalRequest,
|
|
24
|
-
processBlsToExecutionChange,
|
|
25
|
-
processDepositRequest,
|
|
26
|
-
processConsolidationRequest,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export function processOperations(
|
|
30
|
-
fork: ForkSeq,
|
|
31
|
-
state: CachedBeaconStateAllForks,
|
|
32
|
-
body: BeaconBlockBody,
|
|
33
|
-
opts: ProcessBlockOpts = {verifySignatures: true},
|
|
34
|
-
metrics?: BeaconStateTransitionMetrics | null
|
|
35
|
-
): void {
|
|
36
|
-
// verify that outstanding deposits are processed up to the maximum number of deposits
|
|
37
|
-
const maxDeposits = getEth1DepositCount(state);
|
|
38
|
-
if (body.deposits.length !== maxDeposits) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
`Block contains incorrect number of deposits: depositCount=${body.deposits.length} expected=${maxDeposits}`
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
for (const proposerSlashing of body.proposerSlashings) {
|
|
45
|
-
processProposerSlashing(fork, state, proposerSlashing, opts.verifySignatures);
|
|
46
|
-
}
|
|
47
|
-
for (const attesterSlashing of body.attesterSlashings) {
|
|
48
|
-
processAttesterSlashing(fork, state, attesterSlashing, opts.verifySignatures);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
processAttestations(fork, state, body.attestations, opts.verifySignatures, metrics);
|
|
52
|
-
|
|
53
|
-
for (const deposit of body.deposits) {
|
|
54
|
-
processDeposit(fork, state, deposit);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
for (const voluntaryExit of body.voluntaryExits) {
|
|
58
|
-
processVoluntaryExit(fork, state, voluntaryExit, opts.verifySignatures);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (fork >= ForkSeq.capella) {
|
|
62
|
-
for (const blsToExecutionChange of (body as capella.BeaconBlockBody).blsToExecutionChanges) {
|
|
63
|
-
processBlsToExecutionChange(state as CachedBeaconStateCapella, blsToExecutionChange);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (fork >= ForkSeq.electra) {
|
|
68
|
-
const stateElectra = state as CachedBeaconStateElectra;
|
|
69
|
-
const bodyElectra = body as electra.BeaconBlockBody;
|
|
70
|
-
|
|
71
|
-
for (const depositRequest of bodyElectra.executionRequests.deposits) {
|
|
72
|
-
processDepositRequest(stateElectra, depositRequest);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) {
|
|
76
|
-
processWithdrawalRequest(fork, stateElectra, elWithdrawalRequest);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
for (const elConsolidationRequest of bodyElectra.executionRequests.consolidations) {
|
|
80
|
-
processConsolidationRequest(stateElectra, elConsolidationRequest);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import {ForkSeq} from "@lodestar/params";
|
|
2
|
-
import {phase0, ssz} from "@lodestar/types";
|
|
3
|
-
import {getProposerSlashingSignatureSets} from "../signatureSets/index.js";
|
|
4
|
-
import {CachedBeaconStateAllForks} from "../types.js";
|
|
5
|
-
import {isSlashableValidator} from "../util/index.js";
|
|
6
|
-
import {verifySignatureSet} from "../util/signatureSets.js";
|
|
7
|
-
import {slashValidator} from "./slashValidator.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Process a ProposerSlashing operation. Initiates the exit of a validator, decreases the balance of the slashed
|
|
11
|
-
* validator and increases the block proposer balance.
|
|
12
|
-
*
|
|
13
|
-
* PERF: Work depends on number of ProposerSlashing per block. On regular networks the average is 0 / block.
|
|
14
|
-
*/
|
|
15
|
-
export function processProposerSlashing(
|
|
16
|
-
fork: ForkSeq,
|
|
17
|
-
state: CachedBeaconStateAllForks,
|
|
18
|
-
proposerSlashing: phase0.ProposerSlashing,
|
|
19
|
-
verifySignatures = true
|
|
20
|
-
): void {
|
|
21
|
-
assertValidProposerSlashing(state, proposerSlashing, verifySignatures);
|
|
22
|
-
|
|
23
|
-
slashValidator(fork, state, proposerSlashing.signedHeader1.message.proposerIndex);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function assertValidProposerSlashing(
|
|
27
|
-
state: CachedBeaconStateAllForks,
|
|
28
|
-
proposerSlashing: phase0.ProposerSlashing,
|
|
29
|
-
verifySignatures = true
|
|
30
|
-
): void {
|
|
31
|
-
const header1 = proposerSlashing.signedHeader1.message;
|
|
32
|
-
const header2 = proposerSlashing.signedHeader2.message;
|
|
33
|
-
|
|
34
|
-
// verify header slots match
|
|
35
|
-
if (header1.slot !== header2.slot) {
|
|
36
|
-
throw new Error(`ProposerSlashing slots do not match: slot1=${header1.slot} slot2=${header2.slot}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// verify header proposer indices match
|
|
40
|
-
if (header1.proposerIndex !== header2.proposerIndex) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`ProposerSlashing proposer indices do not match: proposerIndex1=${header1.proposerIndex} proposerIndex2=${header2.proposerIndex}`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// verify headers are different
|
|
47
|
-
if (ssz.phase0.BeaconBlockHeaderBigint.equals(header1, header2)) {
|
|
48
|
-
throw new Error("ProposerSlashing headers are equal");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// verify the proposer is slashable
|
|
52
|
-
const proposer = state.validators.getReadonly(header1.proposerIndex);
|
|
53
|
-
if (!isSlashableValidator(proposer, state.epochCtx.epoch)) {
|
|
54
|
-
throw new Error("ProposerSlashing proposer is not slashable");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// verify signatures
|
|
58
|
-
if (verifySignatures) {
|
|
59
|
-
const signatureSets = getProposerSlashingSignatureSets(state, proposerSlashing);
|
|
60
|
-
for (let i = 0; i < signatureSets.length; i++) {
|
|
61
|
-
if (!verifySignatureSet(signatureSets[i])) {
|
|
62
|
-
throw new Error(`ProposerSlashing header${i + 1} signature invalid`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import {digest} from "@chainsafe/as-sha256";
|
|
2
|
-
import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params";
|
|
3
|
-
import {BeaconBlock} from "@lodestar/types";
|
|
4
|
-
import {xor} from "@lodestar/utils";
|
|
5
|
-
import {verifyRandaoSignature} from "../signatureSets/index.js";
|
|
6
|
-
import {CachedBeaconStateAllForks} from "../types.js";
|
|
7
|
-
import {getRandaoMix} from "../util/index.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Commit a randao reveal to generate pseudorandomness seeds
|
|
11
|
-
*
|
|
12
|
-
* PERF: Fixed work independent of block contents.
|
|
13
|
-
*/
|
|
14
|
-
export function processRandao(state: CachedBeaconStateAllForks, block: BeaconBlock, verifySignature = true): void {
|
|
15
|
-
const {epochCtx} = state;
|
|
16
|
-
const epoch = epochCtx.epoch;
|
|
17
|
-
const randaoReveal = block.body.randaoReveal;
|
|
18
|
-
|
|
19
|
-
// verify RANDAO reveal
|
|
20
|
-
if (verifySignature && !verifyRandaoSignature(state, block)) {
|
|
21
|
-
throw new Error("RANDAO reveal is an invalid signature");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// mix in RANDAO reveal
|
|
25
|
-
const randaoMix = xor(getRandaoMix(state, epoch), digest(randaoReveal));
|
|
26
|
-
state.randaoMixes.set(epoch % EPOCHS_PER_HISTORICAL_VECTOR, randaoMix);
|
|
27
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import {byteArrayEquals} from "@chainsafe/ssz";
|
|
2
|
-
import {DOMAIN_SYNC_COMMITTEE, SYNC_COMMITTEE_SIZE} from "@lodestar/params";
|
|
3
|
-
import {altair, ssz} from "@lodestar/types";
|
|
4
|
-
import {G2_POINT_AT_INFINITY} from "../constants/index.js";
|
|
5
|
-
import {CachedBeaconStateAllForks} from "../types.js";
|
|
6
|
-
import {
|
|
7
|
-
ISignatureSet,
|
|
8
|
-
SignatureSetType,
|
|
9
|
-
computeSigningRoot,
|
|
10
|
-
decreaseBalance,
|
|
11
|
-
increaseBalance,
|
|
12
|
-
verifySignatureSet,
|
|
13
|
-
} from "../util/index.js";
|
|
14
|
-
|
|
15
|
-
export function processSyncAggregate(
|
|
16
|
-
state: CachedBeaconStateAllForks,
|
|
17
|
-
block: altair.BeaconBlock,
|
|
18
|
-
verifySignatures = true
|
|
19
|
-
): void {
|
|
20
|
-
const committeeIndices = state.epochCtx.currentSyncCommitteeIndexed.validatorIndices;
|
|
21
|
-
|
|
22
|
-
// different from the spec but not sure how to get through signature verification for default/empty SyncAggregate in the spec test
|
|
23
|
-
if (verifySignatures) {
|
|
24
|
-
// This is to conform to the spec - we want the signature to be verified
|
|
25
|
-
const participantIndices = block.body.syncAggregate.syncCommitteeBits.intersectValues(committeeIndices);
|
|
26
|
-
const signatureSet = getSyncCommitteeSignatureSet(state, block, participantIndices);
|
|
27
|
-
// When there's no participation we consider the signature valid and just ignore i
|
|
28
|
-
if (signatureSet !== null && !verifySignatureSet(signatureSet)) {
|
|
29
|
-
throw Error("Sync committee signature invalid");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const {syncParticipantReward, syncProposerReward} = state.epochCtx;
|
|
34
|
-
const {syncCommitteeBits} = block.body.syncAggregate;
|
|
35
|
-
const proposerIndex = state.epochCtx.getBeaconProposer(state.slot);
|
|
36
|
-
let proposerBalance = state.balances.get(proposerIndex);
|
|
37
|
-
|
|
38
|
-
for (let i = 0; i < SYNC_COMMITTEE_SIZE; i++) {
|
|
39
|
-
const index = committeeIndices[i];
|
|
40
|
-
|
|
41
|
-
if (syncCommitteeBits.get(i)) {
|
|
42
|
-
// Positive rewards for participants
|
|
43
|
-
if (index === proposerIndex) {
|
|
44
|
-
proposerBalance += syncParticipantReward;
|
|
45
|
-
} else {
|
|
46
|
-
increaseBalance(state, index, syncParticipantReward);
|
|
47
|
-
}
|
|
48
|
-
// Proposer reward
|
|
49
|
-
proposerBalance += syncProposerReward;
|
|
50
|
-
state.proposerRewards.syncAggregate += syncProposerReward;
|
|
51
|
-
} else {
|
|
52
|
-
// Negative rewards for non participants
|
|
53
|
-
if (index === proposerIndex) {
|
|
54
|
-
proposerBalance = Math.max(0, proposerBalance - syncParticipantReward);
|
|
55
|
-
} else {
|
|
56
|
-
decreaseBalance(state, index, syncParticipantReward);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Apply proposer balance
|
|
62
|
-
state.balances.set(proposerIndex, proposerBalance);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function getSyncCommitteeSignatureSet(
|
|
66
|
-
state: CachedBeaconStateAllForks,
|
|
67
|
-
block: altair.BeaconBlock,
|
|
68
|
-
/** Optional parameter to prevent computing it twice */
|
|
69
|
-
participantIndices?: number[]
|
|
70
|
-
): ISignatureSet | null {
|
|
71
|
-
const {epochCtx} = state;
|
|
72
|
-
const {syncAggregate} = block.body;
|
|
73
|
-
const signature = syncAggregate.syncCommitteeSignature;
|
|
74
|
-
|
|
75
|
-
// The spec uses the state to get the previous slot
|
|
76
|
-
// ```python
|
|
77
|
-
// previous_slot = max(state.slot, Slot(1)) - Slot(1)
|
|
78
|
-
// ```
|
|
79
|
-
// However we need to run the function getSyncCommitteeSignatureSet() for all the blocks in a epoch
|
|
80
|
-
// with the same state when verifying blocks in batch on RangeSync. Therefore we use the block.slot.
|
|
81
|
-
const previousSlot = Math.max(block.slot, 1) - 1;
|
|
82
|
-
|
|
83
|
-
// The spec uses the state to get the root at previousSlot
|
|
84
|
-
// ```python
|
|
85
|
-
// get_block_root_at_slot(state, previous_slot)
|
|
86
|
-
// ```
|
|
87
|
-
// However we need to run the function getSyncCommitteeSignatureSet() for all the blocks in a epoch
|
|
88
|
-
// with the same state when verifying blocks in batch on RangeSync.
|
|
89
|
-
//
|
|
90
|
-
// On skipped slots state block roots just copy the latest block, so using the parentRoot here is equivalent.
|
|
91
|
-
// So getSyncCommitteeSignatureSet() can be called with a state in any slot (with the correct shuffling)
|
|
92
|
-
const rootSigned = block.parentRoot;
|
|
93
|
-
|
|
94
|
-
if (!participantIndices) {
|
|
95
|
-
const committeeIndices = state.epochCtx.currentSyncCommitteeIndexed.validatorIndices;
|
|
96
|
-
participantIndices = syncAggregate.syncCommitteeBits.intersectValues(committeeIndices);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// When there's no participation we consider the signature valid and just ignore it
|
|
100
|
-
if (participantIndices.length === 0) {
|
|
101
|
-
// Must set signature as G2_POINT_AT_INFINITY when participating bits are empty
|
|
102
|
-
// https://github.com/ethereum/eth2.0-specs/blob/30f2a076377264677e27324a8c3c78c590ae5e20/specs/altair/bls.md#eth2_fast_aggregate_verify
|
|
103
|
-
if (byteArrayEquals(signature, G2_POINT_AT_INFINITY)) {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
throw Error("Empty sync committee signature is not infinity");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const domain = state.config.getDomain(state.slot, DOMAIN_SYNC_COMMITTEE, previousSlot);
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
type: SignatureSetType.aggregate,
|
|
113
|
-
pubkeys: participantIndices.map((i) => epochCtx.index2pubkey[i]),
|
|
114
|
-
signingRoot: computeSigningRoot(ssz.Root, rootSigned, domain),
|
|
115
|
-
signature,
|
|
116
|
-
};
|
|
117
|
-
}
|