@lodestar/state-transition 1.35.0-dev.e9dd48f165 → 1.35.0-dev.fcf8d024ea

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.
Files changed (288) hide show
  1. package/README.md +1 -1
  2. package/lib/block/externalData.d.ts.map +1 -0
  3. package/lib/block/index.d.ts +2 -2
  4. package/lib/block/index.d.ts.map +1 -0
  5. package/lib/block/index.js +2 -2
  6. package/lib/block/index.js.map +1 -1
  7. package/lib/block/initiateValidatorExit.d.ts.map +1 -0
  8. package/lib/block/isValidIndexedAttestation.d.ts.map +1 -0
  9. package/lib/block/processAttestationPhase0.d.ts.map +1 -0
  10. package/lib/block/processAttestationPhase0.js +1 -2
  11. package/lib/block/processAttestationPhase0.js.map +1 -1
  12. package/lib/block/processAttestations.d.ts.map +1 -0
  13. package/lib/block/processAttestationsAltair.d.ts +1 -1
  14. package/lib/block/processAttestationsAltair.d.ts.map +1 -0
  15. package/lib/block/processAttestationsAltair.js +1 -1
  16. package/lib/block/processAttestationsAltair.js.map +1 -1
  17. package/lib/block/processAttesterSlashing.d.ts.map +1 -0
  18. package/lib/block/processAttesterSlashing.js.map +1 -1
  19. package/lib/block/processBlobKzgCommitments.d.ts.map +1 -0
  20. package/lib/block/processBlockHeader.d.ts.map +1 -0
  21. package/lib/block/processBlsToExecutionChange.d.ts.map +1 -0
  22. package/lib/block/processBlsToExecutionChange.js.map +1 -1
  23. package/lib/block/processConsolidationRequest.d.ts.map +1 -0
  24. package/lib/block/processConsolidationRequest.js.map +1 -1
  25. package/lib/block/processDeposit.d.ts +2 -2
  26. package/lib/block/processDeposit.d.ts.map +1 -0
  27. package/lib/block/processDeposit.js +1 -1
  28. package/lib/block/processDeposit.js.map +1 -1
  29. package/lib/block/processDepositRequest.d.ts.map +1 -0
  30. package/lib/block/processDepositRequest.js.map +1 -1
  31. package/lib/block/processEth1Data.d.ts.map +1 -0
  32. package/lib/block/processExecutionPayload.d.ts.map +1 -0
  33. package/lib/block/processOperations.d.ts.map +1 -0
  34. package/lib/block/processOperations.js.map +1 -1
  35. package/lib/block/processProposerSlashing.d.ts.map +1 -0
  36. package/lib/block/processRandao.d.ts.map +1 -0
  37. package/lib/block/processSyncCommittee.d.ts.map +1 -0
  38. package/lib/block/processSyncCommittee.js +1 -2
  39. package/lib/block/processSyncCommittee.js.map +1 -1
  40. package/lib/block/processVoluntaryExit.d.ts.map +1 -0
  41. package/lib/block/processWithdrawalRequest.d.ts.map +1 -0
  42. package/lib/block/processWithdrawalRequest.js.map +1 -1
  43. package/lib/block/processWithdrawals.d.ts.map +1 -0
  44. package/lib/block/processWithdrawals.js.map +1 -1
  45. package/lib/block/slashValidator.d.ts.map +1 -0
  46. package/lib/block/slashValidator.js.map +1 -1
  47. package/lib/block/types.d.ts.map +1 -0
  48. package/lib/cache/effectiveBalanceIncrements.d.ts.map +1 -0
  49. package/lib/cache/epochCache.d.ts.map +1 -0
  50. package/lib/cache/epochCache.js +130 -0
  51. package/lib/cache/epochCache.js.map +1 -1
  52. package/lib/cache/epochTransitionCache.d.ts.map +1 -0
  53. package/lib/cache/epochTransitionCache.js.map +1 -1
  54. package/lib/cache/pubkeyCache.d.ts.map +1 -0
  55. package/lib/cache/rewardCache.d.ts.map +1 -0
  56. package/lib/cache/stateCache.d.ts.map +1 -0
  57. package/lib/cache/syncCommitteeCache.d.ts.map +1 -0
  58. package/lib/cache/types.d.ts +2 -2
  59. package/lib/cache/types.d.ts.map +1 -0
  60. package/lib/constants/constants.d.ts.map +1 -0
  61. package/lib/constants/index.d.ts.map +1 -0
  62. package/lib/epoch/computeUnrealizedCheckpoints.d.ts.map +1 -0
  63. package/lib/epoch/getAttestationDeltas.d.ts.map +1 -0
  64. package/lib/epoch/getRewardsAndPenalties.d.ts.map +1 -0
  65. package/lib/epoch/index.d.ts.map +1 -0
  66. package/lib/epoch/index.js.map +1 -1
  67. package/lib/epoch/processEffectiveBalanceUpdates.d.ts.map +1 -0
  68. package/lib/epoch/processEth1DataReset.d.ts.map +1 -0
  69. package/lib/epoch/processHistoricalRootsUpdate.d.ts.map +1 -0
  70. package/lib/epoch/processHistoricalSummariesUpdate.d.ts.map +1 -0
  71. package/lib/epoch/processInactivityUpdates.d.ts.map +1 -0
  72. package/lib/epoch/processJustificationAndFinalization.d.ts.map +1 -0
  73. package/lib/epoch/processParticipationFlagUpdates.d.ts.map +1 -0
  74. package/lib/epoch/processParticipationRecordUpdates.d.ts.map +1 -0
  75. package/lib/epoch/processPendingAttestations.d.ts.map +1 -0
  76. package/lib/epoch/processPendingConsolidations.d.ts.map +1 -0
  77. package/lib/epoch/processPendingDeposits.d.ts.map +1 -0
  78. package/lib/epoch/processProposerLookahead.d.ts.map +1 -0
  79. package/lib/epoch/processRandaoMixesReset.d.ts.map +1 -0
  80. package/lib/epoch/processRegistryUpdates.d.ts.map +1 -0
  81. package/lib/epoch/processRewardsAndPenalties.d.ts.map +1 -0
  82. package/lib/epoch/processSlashings.d.ts.map +1 -0
  83. package/lib/epoch/processSlashings.js.map +1 -1
  84. package/lib/epoch/processSlashingsReset.d.ts.map +1 -0
  85. package/lib/epoch/processSyncCommitteeUpdates.d.ts.map +1 -0
  86. package/lib/index.d.ts +17 -17
  87. package/lib/index.d.ts.map +1 -0
  88. package/lib/index.js +16 -16
  89. package/lib/index.js.map +1 -1
  90. package/lib/metrics.d.ts.map +1 -0
  91. package/lib/signatureSets/attesterSlashings.d.ts.map +1 -0
  92. package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -0
  93. package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
  94. package/lib/signatureSets/index.d.ts +1 -1
  95. package/lib/signatureSets/index.d.ts.map +1 -0
  96. package/lib/signatureSets/index.js +1 -1
  97. package/lib/signatureSets/index.js.map +1 -1
  98. package/lib/signatureSets/indexedAttestation.d.ts.map +1 -0
  99. package/lib/signatureSets/proposer.d.ts.map +1 -0
  100. package/lib/signatureSets/proposerSlashings.d.ts.map +1 -0
  101. package/lib/signatureSets/randao.d.ts.map +1 -0
  102. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -0
  103. package/lib/slot/index.d.ts.map +1 -0
  104. package/lib/slot/upgradeStateToAltair.d.ts.map +1 -0
  105. package/lib/slot/upgradeStateToBellatrix.d.ts.map +1 -0
  106. package/lib/slot/upgradeStateToCapella.d.ts.map +1 -0
  107. package/lib/slot/upgradeStateToDeneb.d.ts +1 -2
  108. package/lib/slot/upgradeStateToDeneb.d.ts.map +1 -0
  109. package/lib/slot/upgradeStateToDeneb.js.map +1 -1
  110. package/lib/slot/upgradeStateToElectra.d.ts.map +1 -0
  111. package/lib/slot/upgradeStateToFulu.d.ts.map +1 -0
  112. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -0
  113. package/lib/slot/upgradeStateToGloas.js +2 -2
  114. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  115. package/lib/stateTransition.d.ts.map +1 -0
  116. package/lib/types.d.ts +2 -2
  117. package/lib/types.d.ts.map +1 -0
  118. package/lib/util/aggregator.d.ts.map +1 -0
  119. package/lib/util/altair.d.ts.map +1 -0
  120. package/lib/util/array.d.ts.map +1 -0
  121. package/lib/util/attestation.d.ts.map +1 -0
  122. package/lib/util/attesterStatus.d.ts.map +1 -0
  123. package/lib/util/balance.d.ts.map +1 -0
  124. package/lib/util/blindedBlock.d.ts.map +1 -0
  125. package/lib/util/blindedBlock.js.map +1 -1
  126. package/lib/util/blockRoot.d.ts.map +1 -0
  127. package/lib/util/calculateCommitteeAssignments.d.ts.map +1 -0
  128. package/lib/util/capella.d.ts.map +1 -0
  129. package/lib/util/computeAnchorCheckpoint.d.ts.map +1 -0
  130. package/lib/util/deposit.d.ts.map +1 -0
  131. package/lib/util/domain.d.ts.map +1 -0
  132. package/lib/util/electra.d.ts.map +1 -0
  133. package/lib/util/epoch.d.ts.map +1 -0
  134. package/lib/util/epochShuffling.d.ts.map +1 -0
  135. package/lib/util/execution.d.ts.map +1 -0
  136. package/lib/util/execution.js.map +1 -1
  137. package/lib/util/finality.d.ts.map +1 -0
  138. package/lib/util/fulu.d.ts.map +1 -0
  139. package/lib/util/genesis.d.ts.map +1 -0
  140. package/lib/util/genesis.js +3 -6
  141. package/lib/util/genesis.js.map +1 -1
  142. package/lib/util/index.d.ts +5 -5
  143. package/lib/util/index.d.ts.map +1 -0
  144. package/lib/util/index.js +5 -5
  145. package/lib/util/index.js.map +1 -1
  146. package/lib/util/interop.d.ts.map +1 -0
  147. package/lib/util/interop.js +1 -1
  148. package/lib/util/interop.js.map +1 -1
  149. package/lib/util/loadState/findModifiedInactivityScores.d.ts.map +1 -0
  150. package/lib/util/loadState/findModifiedValidators.d.ts.map +1 -0
  151. package/lib/util/loadState/index.d.ts.map +1 -0
  152. package/lib/util/loadState/loadState.d.ts.map +1 -0
  153. package/lib/util/loadState/loadValidator.d.ts.map +1 -0
  154. package/lib/util/rootCache.d.ts.map +1 -0
  155. package/lib/util/rootCache.js +5 -2
  156. package/lib/util/rootCache.js.map +1 -1
  157. package/lib/util/seed.d.ts.map +1 -0
  158. package/lib/util/seed.js +1 -2
  159. package/lib/util/seed.js.map +1 -1
  160. package/lib/util/shufflingDecisionRoot.d.ts.map +1 -0
  161. package/lib/util/signatureSets.d.ts.map +1 -0
  162. package/lib/util/signingRoot.d.ts.map +1 -0
  163. package/lib/util/slot.d.ts +0 -1
  164. package/lib/util/slot.d.ts.map +1 -0
  165. package/lib/util/slot.js +1 -5
  166. package/lib/util/slot.js.map +1 -1
  167. package/lib/util/sszBytes.d.ts.map +1 -0
  168. package/lib/util/syncCommittee.d.ts.map +1 -0
  169. package/lib/util/targetUnslashedBalance.d.ts.map +1 -0
  170. package/lib/util/validator.d.ts.map +1 -0
  171. package/lib/util/weakSubjectivity.d.ts.map +1 -0
  172. package/lib/util/weakSubjectivity.js.map +1 -1
  173. package/package.json +13 -11
  174. package/src/block/externalData.ts +26 -0
  175. package/src/block/index.ts +81 -0
  176. package/src/block/initiateValidatorExit.ts +62 -0
  177. package/src/block/isValidIndexedAttestation.ts +70 -0
  178. package/src/block/processAttestationPhase0.ts +158 -0
  179. package/src/block/processAttestations.ts +25 -0
  180. package/src/block/processAttestationsAltair.ts +184 -0
  181. package/src/block/processAttesterSlashing.ts +59 -0
  182. package/src/block/processBlobKzgCommitments.ts +21 -0
  183. package/src/block/processBlockHeader.ts +54 -0
  184. package/src/block/processBlsToExecutionChange.ts +78 -0
  185. package/src/block/processConsolidationRequest.ts +147 -0
  186. package/src/block/processDeposit.ts +166 -0
  187. package/src/block/processDepositRequest.ts +19 -0
  188. package/src/block/processEth1Data.ts +86 -0
  189. package/src/block/processExecutionPayload.ts +84 -0
  190. package/src/block/processOperations.ts +83 -0
  191. package/src/block/processProposerSlashing.ts +66 -0
  192. package/src/block/processRandao.ts +27 -0
  193. package/src/block/processSyncCommittee.ts +117 -0
  194. package/src/block/processVoluntaryExit.ts +55 -0
  195. package/src/block/processWithdrawalRequest.ts +98 -0
  196. package/src/block/processWithdrawals.ts +207 -0
  197. package/src/block/slashValidator.ts +98 -0
  198. package/src/block/types.ts +9 -0
  199. package/src/cache/effectiveBalanceIncrements.ts +39 -0
  200. package/src/cache/epochCache.ts +1213 -0
  201. package/src/cache/epochTransitionCache.ts +542 -0
  202. package/src/cache/pubkeyCache.ts +33 -0
  203. package/src/cache/rewardCache.ts +19 -0
  204. package/src/cache/stateCache.ts +268 -0
  205. package/src/cache/syncCommitteeCache.ts +96 -0
  206. package/src/cache/types.ts +18 -0
  207. package/src/constants/constants.ts +12 -0
  208. package/src/constants/index.ts +1 -0
  209. package/src/epoch/computeUnrealizedCheckpoints.ts +55 -0
  210. package/src/epoch/getAttestationDeltas.ts +169 -0
  211. package/src/epoch/getRewardsAndPenalties.ts +137 -0
  212. package/src/epoch/index.ts +202 -0
  213. package/src/epoch/processEffectiveBalanceUpdates.ts +111 -0
  214. package/src/epoch/processEth1DataReset.ts +17 -0
  215. package/src/epoch/processHistoricalRootsUpdate.ts +25 -0
  216. package/src/epoch/processHistoricalSummariesUpdate.ts +23 -0
  217. package/src/epoch/processInactivityUpdates.ts +60 -0
  218. package/src/epoch/processJustificationAndFinalization.ts +90 -0
  219. package/src/epoch/processParticipationFlagUpdates.ts +27 -0
  220. package/src/epoch/processParticipationRecordUpdates.ts +14 -0
  221. package/src/epoch/processPendingAttestations.ts +75 -0
  222. package/src/epoch/processPendingConsolidations.ts +59 -0
  223. package/src/epoch/processPendingDeposits.ts +136 -0
  224. package/src/epoch/processProposerLookahead.ts +39 -0
  225. package/src/epoch/processRandaoMixesReset.ts +18 -0
  226. package/src/epoch/processRegistryUpdates.ts +65 -0
  227. package/src/epoch/processRewardsAndPenalties.ts +58 -0
  228. package/src/epoch/processSlashings.ts +97 -0
  229. package/src/epoch/processSlashingsReset.ts +20 -0
  230. package/src/epoch/processSyncCommitteeUpdates.ts +44 -0
  231. package/src/index.ts +67 -0
  232. package/src/metrics.ts +169 -0
  233. package/src/signatureSets/attesterSlashings.ts +39 -0
  234. package/src/signatureSets/blsToExecutionChange.ts +43 -0
  235. package/src/signatureSets/index.ts +73 -0
  236. package/src/signatureSets/indexedAttestation.ts +51 -0
  237. package/src/signatureSets/proposer.ts +47 -0
  238. package/src/signatureSets/proposerSlashings.ts +41 -0
  239. package/src/signatureSets/randao.ts +31 -0
  240. package/src/signatureSets/voluntaryExits.ts +44 -0
  241. package/src/slot/index.ts +32 -0
  242. package/src/slot/upgradeStateToAltair.ts +149 -0
  243. package/src/slot/upgradeStateToBellatrix.ts +63 -0
  244. package/src/slot/upgradeStateToCapella.ts +71 -0
  245. package/src/slot/upgradeStateToDeneb.ts +40 -0
  246. package/src/slot/upgradeStateToElectra.ts +126 -0
  247. package/src/slot/upgradeStateToFulu.ts +31 -0
  248. package/src/slot/upgradeStateToGloas.ts +29 -0
  249. package/src/stateTransition.ts +305 -0
  250. package/src/types.ts +26 -0
  251. package/src/util/aggregator.ts +33 -0
  252. package/src/util/altair.ts +13 -0
  253. package/src/util/array.ts +53 -0
  254. package/src/util/attestation.ts +36 -0
  255. package/src/util/attesterStatus.ts +83 -0
  256. package/src/util/balance.ts +83 -0
  257. package/src/util/blindedBlock.ts +144 -0
  258. package/src/util/blockRoot.ts +72 -0
  259. package/src/util/calculateCommitteeAssignments.ts +43 -0
  260. package/src/util/capella.ts +8 -0
  261. package/src/util/computeAnchorCheckpoint.ts +38 -0
  262. package/src/util/deposit.ts +22 -0
  263. package/src/util/domain.ts +31 -0
  264. package/src/util/electra.ts +68 -0
  265. package/src/util/epoch.ts +135 -0
  266. package/src/util/epochShuffling.ts +185 -0
  267. package/src/util/execution.ts +177 -0
  268. package/src/util/finality.ts +17 -0
  269. package/src/util/fulu.ts +43 -0
  270. package/src/util/genesis.ts +340 -0
  271. package/src/util/index.ts +29 -0
  272. package/src/util/interop.ts +22 -0
  273. package/src/util/loadState/findModifiedInactivityScores.ts +47 -0
  274. package/src/util/loadState/findModifiedValidators.ts +46 -0
  275. package/src/util/loadState/index.ts +2 -0
  276. package/src/util/loadState/loadState.ts +225 -0
  277. package/src/util/loadState/loadValidator.ts +77 -0
  278. package/src/util/rootCache.ts +37 -0
  279. package/src/util/seed.ts +381 -0
  280. package/src/util/shufflingDecisionRoot.ts +78 -0
  281. package/src/util/signatureSets.ts +65 -0
  282. package/src/util/signingRoot.ts +13 -0
  283. package/src/util/slot.ts +22 -0
  284. package/src/util/sszBytes.ts +52 -0
  285. package/src/util/syncCommittee.ts +69 -0
  286. package/src/util/targetUnslashedBalance.ts +30 -0
  287. package/src/util/validator.ts +105 -0
  288. package/src/util/weakSubjectivity.ts +186 -0
@@ -0,0 +1,184 @@
1
+ import {byteArrayEquals} from "@chainsafe/ssz";
2
+ import {
3
+ ForkSeq,
4
+ MIN_ATTESTATION_INCLUSION_DELAY,
5
+ PROPOSER_WEIGHT,
6
+ SLOTS_PER_EPOCH,
7
+ TIMELY_HEAD_FLAG_INDEX,
8
+ TIMELY_HEAD_WEIGHT,
9
+ TIMELY_SOURCE_FLAG_INDEX,
10
+ TIMELY_SOURCE_WEIGHT,
11
+ TIMELY_TARGET_FLAG_INDEX,
12
+ TIMELY_TARGET_WEIGHT,
13
+ WEIGHT_DENOMINATOR,
14
+ } from "@lodestar/params";
15
+ import {Attestation, Epoch, phase0} from "@lodestar/types";
16
+ import {intSqrt} from "@lodestar/utils";
17
+ import {BeaconStateTransitionMetrics} from "../metrics.js";
18
+ import {getAttestationWithIndicesSignatureSet} from "../signatureSets/indexedAttestation.js";
19
+ import {CachedBeaconStateAltair} from "../types.js";
20
+ import {increaseBalance, verifySignatureSet} from "../util/index.js";
21
+ import {RootCache} from "../util/rootCache.js";
22
+ import {checkpointToStr, isTimelyTarget, validateAttestation} from "./processAttestationPhase0.js";
23
+
24
+ const PROPOSER_REWARD_DOMINATOR = ((WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR) / PROPOSER_WEIGHT;
25
+
26
+ /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */
27
+ const TIMELY_SOURCE = 1 << TIMELY_SOURCE_FLAG_INDEX;
28
+ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX;
29
+ const TIMELY_HEAD = 1 << TIMELY_HEAD_FLAG_INDEX;
30
+ const SLOTS_PER_EPOCH_SQRT = intSqrt(SLOTS_PER_EPOCH);
31
+
32
+ export function processAttestationsAltair(
33
+ fork: ForkSeq,
34
+ state: CachedBeaconStateAltair,
35
+ attestations: Attestation[],
36
+ verifySignature = true,
37
+ metrics?: BeaconStateTransitionMetrics | null
38
+ ): void {
39
+ const {epochCtx} = state;
40
+ const {effectiveBalanceIncrements} = epochCtx;
41
+ const stateSlot = state.slot;
42
+ const rootCache = new RootCache(state);
43
+ const currentEpoch = epochCtx.epoch;
44
+
45
+ // Process all attestations first and then increase the balance of the proposer once
46
+ let proposerReward = 0;
47
+ let newSeenAttesters = 0;
48
+ let newSeenAttestersEffectiveBalance = 0;
49
+ for (const attestation of attestations) {
50
+ const data = attestation.data;
51
+
52
+ validateAttestation(fork, state, attestation);
53
+
54
+ // Retrieve the validator indices from the attestation participation bitfield
55
+ const attestingIndices = epochCtx.getAttestingIndices(fork, attestation);
56
+
57
+ // this check is done last because its the most expensive (if signature verification is toggled on)
58
+ // TODO: Why should we verify an indexed attestation that we just created? If it's just for the signature
59
+ // we can verify only that and nothing else.
60
+ if (verifySignature) {
61
+ const sigSet = getAttestationWithIndicesSignatureSet(state, attestation, attestingIndices);
62
+ if (!verifySignatureSet(sigSet)) {
63
+ throw new Error("Attestation signature is not valid");
64
+ }
65
+ }
66
+
67
+ const inCurrentEpoch = data.target.epoch === currentEpoch;
68
+ const epochParticipation = inCurrentEpoch ? state.currentEpochParticipation : state.previousEpochParticipation;
69
+
70
+ const flagsAttestation = getAttestationParticipationStatus(
71
+ fork,
72
+ data,
73
+ stateSlot - data.slot,
74
+ epochCtx.epoch,
75
+ rootCache
76
+ );
77
+
78
+ // For each participant, update their participation
79
+ // In epoch processing, this participation info is used to calculate balance updates
80
+ let totalBalanceIncrementsWithWeight = 0;
81
+ const validators = state.validators;
82
+ for (const validatorIndex of attestingIndices) {
83
+ const flags = epochParticipation.get(validatorIndex);
84
+
85
+ // For normal block, > 90% of attestations belong to current epoch
86
+ // At epoch boundary, 100% of attestations belong to previous epoch
87
+ // so we want to update the participation flag tree in batch
88
+
89
+ // Note ParticipationFlags type uses option {setBitwiseOR: true}, .set() does a |= operation
90
+ epochParticipation.set(validatorIndex, flagsAttestation);
91
+ // epochParticipation.setStatus(index, newStatus);
92
+
93
+ // Returns flags that are NOT set before (~ bitwise NOT) AND are set after
94
+ const flagsNewSet = ~flags & flagsAttestation;
95
+ if (flagsNewSet !== 0) {
96
+ newSeenAttesters++;
97
+ newSeenAttestersEffectiveBalance += effectiveBalanceIncrements[validatorIndex];
98
+ }
99
+
100
+ // Spec:
101
+ // baseReward = state.validators[index].effectiveBalance / EFFECTIVE_BALANCE_INCREMENT * baseRewardPerIncrement;
102
+ // proposerRewardNumerator += baseReward * totalWeight
103
+ let totalWeight = 0;
104
+ if ((flagsNewSet & TIMELY_SOURCE) === TIMELY_SOURCE) totalWeight += TIMELY_SOURCE_WEIGHT;
105
+ if ((flagsNewSet & TIMELY_TARGET) === TIMELY_TARGET) totalWeight += TIMELY_TARGET_WEIGHT;
106
+ if ((flagsNewSet & TIMELY_HEAD) === TIMELY_HEAD) totalWeight += TIMELY_HEAD_WEIGHT;
107
+
108
+ if (totalWeight > 0) {
109
+ totalBalanceIncrementsWithWeight += effectiveBalanceIncrements[validatorIndex] * totalWeight;
110
+ }
111
+
112
+ // TODO: describe issue. Compute progressive target balances
113
+ // When processing each attestation, increase the cummulative target balance. Only applies post-altair
114
+ if ((flagsNewSet & TIMELY_TARGET) === TIMELY_TARGET) {
115
+ const validator = validators.getReadonly(validatorIndex);
116
+ if (!validator.slashed) {
117
+ if (inCurrentEpoch) {
118
+ epochCtx.currentTargetUnslashedBalanceIncrements += effectiveBalanceIncrements[validatorIndex];
119
+ } else {
120
+ epochCtx.previousTargetUnslashedBalanceIncrements += effectiveBalanceIncrements[validatorIndex];
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ // Do the discrete math inside the loop to ensure a deterministic result
127
+ const totalIncrements = totalBalanceIncrementsWithWeight;
128
+ const proposerRewardNumerator = totalIncrements * state.epochCtx.baseRewardPerIncrement;
129
+ proposerReward += Math.floor(proposerRewardNumerator / PROPOSER_REWARD_DOMINATOR);
130
+ }
131
+
132
+ metrics?.newSeenAttestersPerBlock.set(newSeenAttesters);
133
+ metrics?.newSeenAttestersEffectiveBalancePerBlock.set(newSeenAttestersEffectiveBalance);
134
+ metrics?.attestationsPerBlock.set(attestations.length);
135
+
136
+ increaseBalance(state, epochCtx.getBeaconProposer(state.slot), proposerReward);
137
+ state.proposerRewards.attestations = proposerReward;
138
+ }
139
+
140
+ /**
141
+ * https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/beacon-chain.md#get_attestation_participation_flag_indices
142
+ */
143
+ export function getAttestationParticipationStatus(
144
+ fork: ForkSeq,
145
+ data: phase0.AttestationData,
146
+ inclusionDelay: number,
147
+ currentEpoch: Epoch,
148
+ rootCache: RootCache
149
+ ): number {
150
+ const justifiedCheckpoint =
151
+ data.target.epoch === currentEpoch ? rootCache.currentJustifiedCheckpoint : rootCache.previousJustifiedCheckpoint;
152
+
153
+ // The source and target votes are part of the FFG vote, the head vote is part of the fork choice vote
154
+ // Both are tracked to properly incentivise validators
155
+ //
156
+ // The source vote always matches the justified checkpoint (else its invalid)
157
+ // The target vote should match the most recent checkpoint (eg: the first root of the epoch)
158
+ // The head vote should match the root at the attestation slot (eg: the root at data.slot)
159
+ const isMatchingSource = checkpointValueEquals(data.source, justifiedCheckpoint);
160
+ if (!isMatchingSource) {
161
+ throw new Error(
162
+ `Attestation source does not equal justified checkpoint: source=${checkpointToStr(
163
+ data.source
164
+ )} justifiedCheckpoint=${checkpointToStr(justifiedCheckpoint)}`
165
+ );
166
+ }
167
+
168
+ const isMatchingTarget = byteArrayEquals(data.target.root, rootCache.getBlockRoot(data.target.epoch));
169
+
170
+ // a timely head is only be set if the target is _also_ matching
171
+ const isMatchingHead =
172
+ isMatchingTarget && byteArrayEquals(data.beaconBlockRoot, rootCache.getBlockRootAtSlot(data.slot));
173
+
174
+ let flags = 0;
175
+ if (isMatchingSource && inclusionDelay <= SLOTS_PER_EPOCH_SQRT) flags |= TIMELY_SOURCE;
176
+ if (isMatchingTarget && isTimelyTarget(fork, inclusionDelay)) flags |= TIMELY_TARGET;
177
+ if (isMatchingHead && inclusionDelay === MIN_ATTESTATION_INCLUSION_DELAY) flags |= TIMELY_HEAD;
178
+
179
+ return flags;
180
+ }
181
+
182
+ export function checkpointValueEquals(cp1: phase0.Checkpoint, cp2: phase0.Checkpoint): boolean {
183
+ return cp1.epoch === cp2.epoch && byteArrayEquals(cp1.root, cp2.root);
184
+ }
@@ -0,0 +1,59 @@
1
+ import {ForkSeq} from "@lodestar/params";
2
+ import {AttesterSlashing} from "@lodestar/types";
3
+ import {CachedBeaconStateAllForks} from "../types.js";
4
+ import {getAttesterSlashableIndices, isSlashableAttestationData, isSlashableValidator} from "../util/index.js";
5
+ import {isValidIndexedAttestationBigint} from "./isValidIndexedAttestation.js";
6
+ import {slashValidator} from "./slashValidator.js";
7
+
8
+ /**
9
+ * Process an AttesterSlashing operation. Initiates the exit of a validator, decreases the balance of the slashed
10
+ * validators and increases the block proposer balance.
11
+ *
12
+ * PERF: Work depends on number of AttesterSlashing per block. On regular networks the average is 0 / block.
13
+ */
14
+ export function processAttesterSlashing(
15
+ fork: ForkSeq,
16
+ state: CachedBeaconStateAllForks,
17
+ attesterSlashing: AttesterSlashing,
18
+ verifySignatures = true
19
+ ): void {
20
+ assertValidAttesterSlashing(state, attesterSlashing, verifySignatures);
21
+
22
+ const intersectingIndices = getAttesterSlashableIndices(attesterSlashing);
23
+
24
+ let slashedAny = false;
25
+ const validators = state.validators; // Get the validators sub tree once for all indices
26
+ // Spec requires to sort indexes beforehand
27
+ for (const index of intersectingIndices.sort((a, b) => a - b)) {
28
+ if (isSlashableValidator(validators.getReadonly(index), state.epochCtx.epoch)) {
29
+ slashValidator(fork, state, index);
30
+ slashedAny = true;
31
+ }
32
+ }
33
+
34
+ if (!slashedAny) {
35
+ throw new Error("AttesterSlashing did not result in any slashings");
36
+ }
37
+ }
38
+
39
+ export function assertValidAttesterSlashing(
40
+ state: CachedBeaconStateAllForks,
41
+ attesterSlashing: AttesterSlashing,
42
+ verifySignatures = true
43
+ ): void {
44
+ const attestation1 = attesterSlashing.attestation1;
45
+ const attestation2 = attesterSlashing.attestation2;
46
+
47
+ if (!isSlashableAttestationData(attestation1.data, attestation2.data)) {
48
+ throw new Error("AttesterSlashing is not slashable");
49
+ }
50
+
51
+ // In state transition, AttesterSlashing attestations are only partially validated. Their slot and epoch could
52
+ // be higher than the clock and the slashing would still be valid. Same applies to attestation data index, which
53
+ // can be any arbitrary value. Must use bigint variants to hash correctly to all possible values
54
+ for (const [i, attestation] of [attestation1, attestation2].entries()) {
55
+ if (!isValidIndexedAttestationBigint(state, attestation, verifySignatures)) {
56
+ throw new Error(`AttesterSlashing attestation${i} is invalid`);
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,21 @@
1
+ import {BlockExternalData, ExecutionPayloadStatus} from "./externalData.js";
2
+
3
+ /**
4
+ * https://github.com/ethereum/consensus-specs/blob/11a037fd9227e29ee809c9397b09f8cc3383a8c0/specs/eip4844/beacon-chain.md#blob-kzg-commitments
5
+ *
6
+ * def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody):
7
+ * assert verify_kzg_commitments_against_transactions(
8
+ * body.execution_payload.transactions,
9
+ * body.blob_kzg_commitments
10
+ * )
11
+ */
12
+ export function processBlobKzgCommitments(externalData: BlockExternalData): void {
13
+ switch (externalData.executionPayloadStatus) {
14
+ case ExecutionPayloadStatus.preMerge:
15
+ throw Error("executionPayloadStatus preMerge");
16
+ case ExecutionPayloadStatus.invalid:
17
+ throw Error("Invalid execution payload");
18
+ case ExecutionPayloadStatus.valid:
19
+ break; // ok
20
+ }
21
+ }
@@ -0,0 +1,54 @@
1
+ import {byteArrayEquals} from "@chainsafe/ssz";
2
+ import {BeaconBlock, BlindedBeaconBlock, ssz} from "@lodestar/types";
3
+ import {toRootHex} from "@lodestar/utils";
4
+ import {ZERO_HASH} from "../constants/index.js";
5
+ import {CachedBeaconStateAllForks} from "../types.js";
6
+ import {blindedOrFullBlockToHeader} from "../util/index.js";
7
+ /**
8
+ * Converts a Deposit record (created by the eth-execution deposit contract) into a Validator object that goes into the eth-consensus state.
9
+ *
10
+ * PERF: Fixed work independent of block contents.
11
+ * NOTE: `block` body root MUST be pre-cached.
12
+ */
13
+ export function processBlockHeader(state: CachedBeaconStateAllForks, block: BeaconBlock | BlindedBeaconBlock): void {
14
+ const slot = state.slot;
15
+ // verify that the slots match
16
+ if (block.slot !== slot) {
17
+ throw new Error(`Block slot does not match state slot blockSlot=${block.slot} stateSlot=${slot}`);
18
+ }
19
+ // Verify that the block is newer than latest block header
20
+ if (!(block.slot > state.latestBlockHeader.slot)) {
21
+ throw new Error(
22
+ `Block is not newer than latest block header blockSlot=${block.slot} latestBlockHeader.slot=${state.latestBlockHeader.slot}`
23
+ );
24
+ }
25
+ // verify that proposer index is the correct index
26
+ const proposerIndex = state.epochCtx.getBeaconProposer(slot);
27
+ if (block.proposerIndex !== proposerIndex) {
28
+ throw new Error(
29
+ `Block proposer index does not match state proposer index blockProposerIndex=${block.proposerIndex} stateProposerIndex=${proposerIndex}`
30
+ );
31
+ }
32
+
33
+ // verify that the parent matches
34
+ if (!byteArrayEquals(block.parentRoot, ssz.phase0.BeaconBlockHeader.hashTreeRoot(state.latestBlockHeader))) {
35
+ throw new Error(
36
+ `Block parent root ${toRootHex(block.parentRoot)} does not match state latest block, block slot=${slot}`
37
+ );
38
+ }
39
+
40
+ const blockHeader = blindedOrFullBlockToHeader(state.config, block);
41
+ // cache current block as the new latest block
42
+ state.latestBlockHeader = ssz.phase0.BeaconBlockHeader.toViewDU({
43
+ slot,
44
+ proposerIndex,
45
+ parentRoot: block.parentRoot,
46
+ stateRoot: ZERO_HASH,
47
+ bodyRoot: blockHeader.bodyRoot,
48
+ });
49
+
50
+ // verify proposer is not slashed. Only once per block, may use the slower read from tree
51
+ if (state.validators.getReadonly(proposerIndex).slashed) {
52
+ throw new Error("Block proposer is slashed");
53
+ }
54
+ }
@@ -0,0 +1,78 @@
1
+ import {digest} from "@chainsafe/as-sha256";
2
+ import {byteArrayEquals} from "@chainsafe/ssz";
3
+ import {BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX} from "@lodestar/params";
4
+ import {capella} from "@lodestar/types";
5
+ import {toHex} from "@lodestar/utils";
6
+ import {verifyBlsToExecutionChangeSignature} from "../signatureSets/index.js";
7
+ import {CachedBeaconStateCapella} from "../types.js";
8
+
9
+ export function processBlsToExecutionChange(
10
+ state: CachedBeaconStateCapella,
11
+ signedBlsToExecutionChange: capella.SignedBLSToExecutionChange
12
+ ): void {
13
+ const addressChange = signedBlsToExecutionChange.message;
14
+
15
+ const validation = isValidBlsToExecutionChange(state, signedBlsToExecutionChange, true);
16
+ if (!validation.valid) {
17
+ throw validation.error;
18
+ }
19
+
20
+ const validator = state.validators.get(addressChange.validatorIndex);
21
+ const newWithdrawalCredentials = new Uint8Array(32);
22
+ newWithdrawalCredentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX;
23
+ newWithdrawalCredentials.set(addressChange.toExecutionAddress, 12);
24
+
25
+ // Set the new credentials back
26
+ validator.withdrawalCredentials = newWithdrawalCredentials;
27
+ }
28
+
29
+ export function isValidBlsToExecutionChange(
30
+ state: CachedBeaconStateCapella,
31
+ signedBLSToExecutionChange: capella.SignedBLSToExecutionChange,
32
+ verifySignature = true
33
+ ): {valid: true} | {valid: false; error: Error} {
34
+ const addressChange = signedBLSToExecutionChange.message;
35
+
36
+ if (addressChange.validatorIndex >= state.validators.length) {
37
+ return {
38
+ valid: false,
39
+ error: Error(
40
+ `withdrawalValidatorIndex ${addressChange.validatorIndex} > state.validators len ${state.validators.length}`
41
+ ),
42
+ };
43
+ }
44
+
45
+ const validator = state.validators.getReadonly(addressChange.validatorIndex);
46
+ const {withdrawalCredentials} = validator;
47
+ if (withdrawalCredentials[0] !== BLS_WITHDRAWAL_PREFIX) {
48
+ return {
49
+ valid: false,
50
+ error: Error(
51
+ `Invalid withdrawalCredentials prefix expected=${BLS_WITHDRAWAL_PREFIX} actual=${withdrawalCredentials[0]}`
52
+ ),
53
+ };
54
+ }
55
+
56
+ const digestCredentials = digest(addressChange.fromBlsPubkey);
57
+ // Set the BLS_WITHDRAWAL_PREFIX on the digestCredentials for direct match
58
+ digestCredentials[0] = BLS_WITHDRAWAL_PREFIX;
59
+ if (!byteArrayEquals(withdrawalCredentials, digestCredentials)) {
60
+ return {
61
+ valid: false,
62
+ error: Error(
63
+ `Invalid withdrawalCredentials expected=${toHex(withdrawalCredentials)} actual=${toHex(digestCredentials)}`
64
+ ),
65
+ };
66
+ }
67
+
68
+ if (verifySignature && !verifyBlsToExecutionChangeSignature(state, signedBLSToExecutionChange)) {
69
+ return {
70
+ valid: false,
71
+ error: Error(
72
+ `Signature could not be verified for BLS to Execution Change for validatorIndex${addressChange.validatorIndex}`
73
+ ),
74
+ };
75
+ }
76
+
77
+ return {valid: true};
78
+ }
@@ -0,0 +1,147 @@
1
+ import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params";
2
+ import {electra, ssz} from "@lodestar/types";
3
+ import {CachedBeaconStateElectra} from "../types.js";
4
+ import {hasEth1WithdrawalCredential} from "../util/capella.js";
5
+ import {
6
+ hasCompoundingWithdrawalCredential,
7
+ hasExecutionWithdrawalCredential,
8
+ isPubkeyKnown,
9
+ switchToCompoundingValidator,
10
+ } from "../util/electra.js";
11
+ import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js";
12
+ import {getConsolidationChurnLimit, getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js";
13
+
14
+ // TODO Electra: Clean up necessary as there is a lot of overlap with isValidSwitchToCompoundRequest
15
+ export function processConsolidationRequest(
16
+ state: CachedBeaconStateElectra,
17
+ consolidationRequest: electra.ConsolidationRequest
18
+ ): void {
19
+ const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest;
20
+ if (!isPubkeyKnown(state, sourcePubkey) || !isPubkeyKnown(state, targetPubkey)) {
21
+ return;
22
+ }
23
+
24
+ const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey);
25
+ const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey);
26
+
27
+ if (sourceIndex === null || targetIndex === null) {
28
+ return;
29
+ }
30
+
31
+ if (isValidSwitchToCompoundRequest(state, consolidationRequest)) {
32
+ switchToCompoundingValidator(state, sourceIndex);
33
+ // Early return since we have already switched validator to compounding
34
+ return;
35
+ }
36
+
37
+ // Verify that source != target, so a consolidation cannot be used as an exit.
38
+ if (sourceIndex === targetIndex) {
39
+ return;
40
+ }
41
+
42
+ // If the pending consolidations queue is full, consolidation requests are ignored
43
+ if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) {
44
+ return;
45
+ }
46
+
47
+ // If there is too little available consolidation churn limit, consolidation requests are ignored
48
+ if (getConsolidationChurnLimit(state.epochCtx) <= MIN_ACTIVATION_BALANCE) {
49
+ return;
50
+ }
51
+
52
+ const sourceValidator = state.validators.get(sourceIndex);
53
+ const targetValidator = state.validators.getReadonly(targetIndex);
54
+ const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12);
55
+ const currentEpoch = state.epochCtx.epoch;
56
+
57
+ // Verify source withdrawal credentials
58
+ const hasCorrectCredential = hasExecutionWithdrawalCredential(sourceValidator.withdrawalCredentials);
59
+ const isCorrectSourceAddress = Buffer.compare(sourceWithdrawalAddress, sourceAddress) === 0;
60
+ if (!(hasCorrectCredential && isCorrectSourceAddress)) {
61
+ return;
62
+ }
63
+
64
+ // Verify that target has compounding withdrawal credentials
65
+ if (!hasCompoundingWithdrawalCredential(targetValidator.withdrawalCredentials)) {
66
+ return;
67
+ }
68
+
69
+ // Verify the source and the target are active
70
+ if (!isActiveValidator(sourceValidator, currentEpoch) || !isActiveValidator(targetValidator, currentEpoch)) {
71
+ return;
72
+ }
73
+
74
+ // Verify exits for source and target have not been initiated
75
+ if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH || targetValidator.exitEpoch !== FAR_FUTURE_EPOCH) {
76
+ return;
77
+ }
78
+
79
+ // Verify the source has been active long enough
80
+ if (currentEpoch < sourceValidator.activationEpoch + state.config.SHARD_COMMITTEE_PERIOD) {
81
+ return;
82
+ }
83
+
84
+ // Verify the source has no pending withdrawals in the queue
85
+ if (getPendingBalanceToWithdraw(state, sourceIndex) > 0) {
86
+ return;
87
+ }
88
+
89
+ // Initiate source validator exit and append pending consolidation
90
+ // TODO Electra: See if we can get rid of big int
91
+ const exitEpoch = computeConsolidationEpochAndUpdateChurn(state, BigInt(sourceValidator.effectiveBalance));
92
+ sourceValidator.exitEpoch = exitEpoch;
93
+ sourceValidator.withdrawableEpoch = exitEpoch + state.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY;
94
+
95
+ const pendingConsolidation = ssz.electra.PendingConsolidation.toViewDU({
96
+ sourceIndex,
97
+ targetIndex,
98
+ });
99
+ state.pendingConsolidations.push(pendingConsolidation);
100
+ }
101
+
102
+ /**
103
+ * Determine if we should set consolidation target validator to compounding credential
104
+ */
105
+ function isValidSwitchToCompoundRequest(
106
+ state: CachedBeaconStateElectra,
107
+ consolidationRequest: electra.ConsolidationRequest
108
+ ): boolean {
109
+ const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest;
110
+ const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey);
111
+ const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey);
112
+
113
+ // Verify pubkey exists
114
+ if (sourceIndex === null) {
115
+ // this check is mainly to make the compiler happy, pubkey is checked by the consumer already
116
+ return false;
117
+ }
118
+
119
+ // Switch to compounding requires source and target be equal
120
+ if (sourceIndex !== targetIndex) {
121
+ return false;
122
+ }
123
+
124
+ const sourceValidator = state.validators.getReadonly(sourceIndex);
125
+ const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12);
126
+ // Verify request has been authorized
127
+ if (Buffer.compare(sourceWithdrawalAddress, sourceAddress) !== 0) {
128
+ return false;
129
+ }
130
+
131
+ // Verify source withdrawal credentials
132
+ if (!hasEth1WithdrawalCredential(sourceValidator.withdrawalCredentials)) {
133
+ return false;
134
+ }
135
+
136
+ // Verify the source is active
137
+ if (!isActiveValidator(sourceValidator, state.epochCtx.epoch)) {
138
+ return false;
139
+ }
140
+
141
+ // Verify exit for source has not been initiated
142
+ if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH) {
143
+ return false;
144
+ }
145
+
146
+ return true;
147
+ }