@lodestar/state-transition 1.35.0-dev.8ea34e52ba → 1.35.0-dev.901d719660

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 (283) hide show
  1. package/lib/block/externalData.d.ts.map +1 -0
  2. package/lib/block/index.d.ts +2 -2
  3. package/lib/block/index.d.ts.map +1 -0
  4. package/lib/block/index.js +2 -2
  5. package/lib/block/index.js.map +1 -1
  6. package/lib/block/initiateValidatorExit.d.ts.map +1 -0
  7. package/lib/block/isValidIndexedAttestation.d.ts.map +1 -0
  8. package/lib/block/processAttestationPhase0.d.ts.map +1 -0
  9. package/lib/block/processAttestationPhase0.js +1 -2
  10. package/lib/block/processAttestationPhase0.js.map +1 -1
  11. package/lib/block/processAttestations.d.ts.map +1 -0
  12. package/lib/block/processAttestationsAltair.d.ts +1 -1
  13. package/lib/block/processAttestationsAltair.d.ts.map +1 -0
  14. package/lib/block/processAttestationsAltair.js +1 -1
  15. package/lib/block/processAttestationsAltair.js.map +1 -1
  16. package/lib/block/processAttesterSlashing.d.ts.map +1 -0
  17. package/lib/block/processAttesterSlashing.js.map +1 -1
  18. package/lib/block/processBlobKzgCommitments.d.ts.map +1 -0
  19. package/lib/block/processBlockHeader.d.ts.map +1 -0
  20. package/lib/block/processBlsToExecutionChange.d.ts.map +1 -0
  21. package/lib/block/processBlsToExecutionChange.js.map +1 -1
  22. package/lib/block/processConsolidationRequest.d.ts.map +1 -0
  23. package/lib/block/processConsolidationRequest.js.map +1 -1
  24. package/lib/block/processDeposit.d.ts +2 -2
  25. package/lib/block/processDeposit.d.ts.map +1 -0
  26. package/lib/block/processDeposit.js +1 -1
  27. package/lib/block/processDeposit.js.map +1 -1
  28. package/lib/block/processDepositRequest.d.ts.map +1 -0
  29. package/lib/block/processDepositRequest.js.map +1 -1
  30. package/lib/block/processEth1Data.d.ts.map +1 -0
  31. package/lib/block/processExecutionPayload.d.ts.map +1 -0
  32. package/lib/block/processExecutionPayload.js +3 -3
  33. package/lib/block/processExecutionPayload.js.map +1 -1
  34. package/lib/block/processOperations.d.ts.map +1 -0
  35. package/lib/block/processOperations.js.map +1 -1
  36. package/lib/block/processProposerSlashing.d.ts.map +1 -0
  37. package/lib/block/processRandao.d.ts.map +1 -0
  38. package/lib/block/processSyncCommittee.d.ts.map +1 -0
  39. package/lib/block/processSyncCommittee.js +1 -2
  40. package/lib/block/processSyncCommittee.js.map +1 -1
  41. package/lib/block/processVoluntaryExit.d.ts.map +1 -0
  42. package/lib/block/processWithdrawalRequest.d.ts.map +1 -0
  43. package/lib/block/processWithdrawalRequest.js.map +1 -1
  44. package/lib/block/processWithdrawals.d.ts.map +1 -0
  45. package/lib/block/processWithdrawals.js.map +1 -1
  46. package/lib/block/slashValidator.d.ts.map +1 -0
  47. package/lib/block/slashValidator.js.map +1 -1
  48. package/lib/block/types.d.ts.map +1 -0
  49. package/lib/cache/effectiveBalanceIncrements.d.ts.map +1 -0
  50. package/lib/cache/epochCache.d.ts.map +1 -0
  51. package/lib/cache/epochTransitionCache.d.ts.map +1 -0
  52. package/lib/cache/epochTransitionCache.js.map +1 -1
  53. package/lib/cache/pubkeyCache.d.ts.map +1 -0
  54. package/lib/cache/rewardCache.d.ts.map +1 -0
  55. package/lib/cache/stateCache.d.ts.map +1 -0
  56. package/lib/cache/syncCommitteeCache.d.ts.map +1 -0
  57. package/lib/cache/types.d.ts +2 -2
  58. package/lib/cache/types.d.ts.map +1 -0
  59. package/lib/constants/constants.d.ts.map +1 -0
  60. package/lib/constants/index.d.ts.map +1 -0
  61. package/lib/epoch/computeUnrealizedCheckpoints.d.ts.map +1 -0
  62. package/lib/epoch/getAttestationDeltas.d.ts.map +1 -0
  63. package/lib/epoch/getRewardsAndPenalties.d.ts.map +1 -0
  64. package/lib/epoch/index.d.ts.map +1 -0
  65. package/lib/epoch/index.js.map +1 -1
  66. package/lib/epoch/processEffectiveBalanceUpdates.d.ts.map +1 -0
  67. package/lib/epoch/processEth1DataReset.d.ts.map +1 -0
  68. package/lib/epoch/processHistoricalRootsUpdate.d.ts.map +1 -0
  69. package/lib/epoch/processHistoricalSummariesUpdate.d.ts.map +1 -0
  70. package/lib/epoch/processInactivityUpdates.d.ts.map +1 -0
  71. package/lib/epoch/processJustificationAndFinalization.d.ts.map +1 -0
  72. package/lib/epoch/processParticipationFlagUpdates.d.ts.map +1 -0
  73. package/lib/epoch/processParticipationRecordUpdates.d.ts.map +1 -0
  74. package/lib/epoch/processPendingAttestations.d.ts.map +1 -0
  75. package/lib/epoch/processPendingConsolidations.d.ts.map +1 -0
  76. package/lib/epoch/processPendingDeposits.d.ts.map +1 -0
  77. package/lib/epoch/processProposerLookahead.d.ts.map +1 -0
  78. package/lib/epoch/processRandaoMixesReset.d.ts.map +1 -0
  79. package/lib/epoch/processRegistryUpdates.d.ts.map +1 -0
  80. package/lib/epoch/processRewardsAndPenalties.d.ts.map +1 -0
  81. package/lib/epoch/processSlashings.d.ts.map +1 -0
  82. package/lib/epoch/processSlashings.js.map +1 -1
  83. package/lib/epoch/processSlashingsReset.d.ts.map +1 -0
  84. package/lib/epoch/processSyncCommitteeUpdates.d.ts.map +1 -0
  85. package/lib/index.d.ts +17 -17
  86. package/lib/index.d.ts.map +1 -0
  87. package/lib/index.js +16 -16
  88. package/lib/index.js.map +1 -1
  89. package/lib/metrics.d.ts.map +1 -0
  90. package/lib/signatureSets/attesterSlashings.d.ts.map +1 -0
  91. package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -0
  92. package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
  93. package/lib/signatureSets/index.d.ts +1 -1
  94. package/lib/signatureSets/index.d.ts.map +1 -0
  95. package/lib/signatureSets/index.js +1 -1
  96. package/lib/signatureSets/index.js.map +1 -1
  97. package/lib/signatureSets/indexedAttestation.d.ts.map +1 -0
  98. package/lib/signatureSets/proposer.d.ts.map +1 -0
  99. package/lib/signatureSets/proposerSlashings.d.ts.map +1 -0
  100. package/lib/signatureSets/randao.d.ts.map +1 -0
  101. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -0
  102. package/lib/slot/index.d.ts.map +1 -0
  103. package/lib/slot/upgradeStateToAltair.d.ts.map +1 -0
  104. package/lib/slot/upgradeStateToBellatrix.d.ts.map +1 -0
  105. package/lib/slot/upgradeStateToCapella.d.ts.map +1 -0
  106. package/lib/slot/upgradeStateToDeneb.d.ts +1 -2
  107. package/lib/slot/upgradeStateToDeneb.d.ts.map +1 -0
  108. package/lib/slot/upgradeStateToDeneb.js.map +1 -1
  109. package/lib/slot/upgradeStateToElectra.d.ts.map +1 -0
  110. package/lib/slot/upgradeStateToFulu.d.ts.map +1 -0
  111. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -0
  112. package/lib/stateTransition.d.ts.map +1 -0
  113. package/lib/types.d.ts +2 -2
  114. package/lib/types.d.ts.map +1 -0
  115. package/lib/util/aggregator.d.ts.map +1 -0
  116. package/lib/util/altair.d.ts.map +1 -0
  117. package/lib/util/array.d.ts.map +1 -0
  118. package/lib/util/attestation.d.ts.map +1 -0
  119. package/lib/util/attesterStatus.d.ts.map +1 -0
  120. package/lib/util/balance.d.ts.map +1 -0
  121. package/lib/util/blindedBlock.d.ts.map +1 -0
  122. package/lib/util/blindedBlock.js.map +1 -1
  123. package/lib/util/blockRoot.d.ts.map +1 -0
  124. package/lib/util/calculateCommitteeAssignments.d.ts.map +1 -0
  125. package/lib/util/capella.d.ts.map +1 -0
  126. package/lib/util/computeAnchorCheckpoint.d.ts.map +1 -0
  127. package/lib/util/deposit.d.ts.map +1 -0
  128. package/lib/util/domain.d.ts.map +1 -0
  129. package/lib/util/electra.d.ts.map +1 -0
  130. package/lib/util/epoch.d.ts.map +1 -0
  131. package/lib/util/epochShuffling.d.ts.map +1 -0
  132. package/lib/util/execution.d.ts.map +1 -0
  133. package/lib/util/execution.js.map +1 -1
  134. package/lib/util/finality.d.ts.map +1 -0
  135. package/lib/util/fulu.d.ts.map +1 -0
  136. package/lib/util/genesis.d.ts.map +1 -0
  137. package/lib/util/genesis.js +0 -3
  138. package/lib/util/genesis.js.map +1 -1
  139. package/lib/util/index.d.ts +5 -5
  140. package/lib/util/index.d.ts.map +1 -0
  141. package/lib/util/index.js +5 -5
  142. package/lib/util/index.js.map +1 -1
  143. package/lib/util/interop.d.ts.map +1 -0
  144. package/lib/util/interop.js +1 -1
  145. package/lib/util/interop.js.map +1 -1
  146. package/lib/util/loadState/findModifiedInactivityScores.d.ts.map +1 -0
  147. package/lib/util/loadState/findModifiedValidators.d.ts.map +1 -0
  148. package/lib/util/loadState/index.d.ts.map +1 -0
  149. package/lib/util/loadState/loadState.d.ts.map +1 -0
  150. package/lib/util/loadState/loadValidator.d.ts.map +1 -0
  151. package/lib/util/rootCache.d.ts.map +1 -0
  152. package/lib/util/seed.d.ts.map +1 -0
  153. package/lib/util/seed.js +1 -2
  154. package/lib/util/seed.js.map +1 -1
  155. package/lib/util/shufflingDecisionRoot.d.ts.map +1 -0
  156. package/lib/util/signatureSets.d.ts.map +1 -0
  157. package/lib/util/signingRoot.d.ts.map +1 -0
  158. package/lib/util/slot.d.ts +0 -1
  159. package/lib/util/slot.d.ts.map +1 -0
  160. package/lib/util/slot.js +3 -7
  161. package/lib/util/slot.js.map +1 -1
  162. package/lib/util/sszBytes.d.ts.map +1 -0
  163. package/lib/util/syncCommittee.d.ts.map +1 -0
  164. package/lib/util/targetUnslashedBalance.d.ts.map +1 -0
  165. package/lib/util/validator.d.ts.map +1 -0
  166. package/lib/util/weakSubjectivity.d.ts.map +1 -0
  167. package/lib/util/weakSubjectivity.js.map +1 -1
  168. package/package.json +13 -11
  169. package/src/block/externalData.ts +26 -0
  170. package/src/block/index.ts +81 -0
  171. package/src/block/initiateValidatorExit.ts +62 -0
  172. package/src/block/isValidIndexedAttestation.ts +70 -0
  173. package/src/block/processAttestationPhase0.ts +158 -0
  174. package/src/block/processAttestations.ts +25 -0
  175. package/src/block/processAttestationsAltair.ts +184 -0
  176. package/src/block/processAttesterSlashing.ts +59 -0
  177. package/src/block/processBlobKzgCommitments.ts +21 -0
  178. package/src/block/processBlockHeader.ts +54 -0
  179. package/src/block/processBlsToExecutionChange.ts +78 -0
  180. package/src/block/processConsolidationRequest.ts +147 -0
  181. package/src/block/processDeposit.ts +166 -0
  182. package/src/block/processDepositRequest.ts +19 -0
  183. package/src/block/processEth1Data.ts +86 -0
  184. package/src/block/processExecutionPayload.ts +84 -0
  185. package/src/block/processOperations.ts +83 -0
  186. package/src/block/processProposerSlashing.ts +66 -0
  187. package/src/block/processRandao.ts +27 -0
  188. package/src/block/processSyncCommittee.ts +117 -0
  189. package/src/block/processVoluntaryExit.ts +55 -0
  190. package/src/block/processWithdrawalRequest.ts +98 -0
  191. package/src/block/processWithdrawals.ts +207 -0
  192. package/src/block/slashValidator.ts +98 -0
  193. package/src/block/types.ts +9 -0
  194. package/src/cache/effectiveBalanceIncrements.ts +39 -0
  195. package/src/cache/epochCache.ts +1213 -0
  196. package/src/cache/epochTransitionCache.ts +542 -0
  197. package/src/cache/pubkeyCache.ts +33 -0
  198. package/src/cache/rewardCache.ts +19 -0
  199. package/src/cache/stateCache.ts +268 -0
  200. package/src/cache/syncCommitteeCache.ts +96 -0
  201. package/src/cache/types.ts +18 -0
  202. package/src/constants/constants.ts +12 -0
  203. package/src/constants/index.ts +1 -0
  204. package/src/epoch/computeUnrealizedCheckpoints.ts +55 -0
  205. package/src/epoch/getAttestationDeltas.ts +169 -0
  206. package/src/epoch/getRewardsAndPenalties.ts +137 -0
  207. package/src/epoch/index.ts +202 -0
  208. package/src/epoch/processEffectiveBalanceUpdates.ts +111 -0
  209. package/src/epoch/processEth1DataReset.ts +17 -0
  210. package/src/epoch/processHistoricalRootsUpdate.ts +25 -0
  211. package/src/epoch/processHistoricalSummariesUpdate.ts +23 -0
  212. package/src/epoch/processInactivityUpdates.ts +60 -0
  213. package/src/epoch/processJustificationAndFinalization.ts +90 -0
  214. package/src/epoch/processParticipationFlagUpdates.ts +27 -0
  215. package/src/epoch/processParticipationRecordUpdates.ts +14 -0
  216. package/src/epoch/processPendingAttestations.ts +75 -0
  217. package/src/epoch/processPendingConsolidations.ts +59 -0
  218. package/src/epoch/processPendingDeposits.ts +136 -0
  219. package/src/epoch/processProposerLookahead.ts +39 -0
  220. package/src/epoch/processRandaoMixesReset.ts +18 -0
  221. package/src/epoch/processRegistryUpdates.ts +65 -0
  222. package/src/epoch/processRewardsAndPenalties.ts +58 -0
  223. package/src/epoch/processSlashings.ts +97 -0
  224. package/src/epoch/processSlashingsReset.ts +20 -0
  225. package/src/epoch/processSyncCommitteeUpdates.ts +44 -0
  226. package/src/index.ts +67 -0
  227. package/src/metrics.ts +169 -0
  228. package/src/signatureSets/attesterSlashings.ts +39 -0
  229. package/src/signatureSets/blsToExecutionChange.ts +43 -0
  230. package/src/signatureSets/index.ts +73 -0
  231. package/src/signatureSets/indexedAttestation.ts +51 -0
  232. package/src/signatureSets/proposer.ts +47 -0
  233. package/src/signatureSets/proposerSlashings.ts +41 -0
  234. package/src/signatureSets/randao.ts +31 -0
  235. package/src/signatureSets/voluntaryExits.ts +44 -0
  236. package/src/slot/index.ts +32 -0
  237. package/src/slot/upgradeStateToAltair.ts +149 -0
  238. package/src/slot/upgradeStateToBellatrix.ts +63 -0
  239. package/src/slot/upgradeStateToCapella.ts +71 -0
  240. package/src/slot/upgradeStateToDeneb.ts +40 -0
  241. package/src/slot/upgradeStateToElectra.ts +126 -0
  242. package/src/slot/upgradeStateToFulu.ts +31 -0
  243. package/src/slot/upgradeStateToGloas.ts +29 -0
  244. package/src/stateTransition.ts +305 -0
  245. package/src/types.ts +26 -0
  246. package/src/util/aggregator.ts +33 -0
  247. package/src/util/altair.ts +13 -0
  248. package/src/util/array.ts +53 -0
  249. package/src/util/attestation.ts +36 -0
  250. package/src/util/attesterStatus.ts +83 -0
  251. package/src/util/balance.ts +83 -0
  252. package/src/util/blindedBlock.ts +144 -0
  253. package/src/util/blockRoot.ts +72 -0
  254. package/src/util/calculateCommitteeAssignments.ts +43 -0
  255. package/src/util/capella.ts +8 -0
  256. package/src/util/computeAnchorCheckpoint.ts +38 -0
  257. package/src/util/deposit.ts +22 -0
  258. package/src/util/domain.ts +31 -0
  259. package/src/util/electra.ts +68 -0
  260. package/src/util/epoch.ts +135 -0
  261. package/src/util/epochShuffling.ts +185 -0
  262. package/src/util/execution.ts +177 -0
  263. package/src/util/finality.ts +17 -0
  264. package/src/util/fulu.ts +43 -0
  265. package/src/util/genesis.ts +340 -0
  266. package/src/util/index.ts +29 -0
  267. package/src/util/interop.ts +22 -0
  268. package/src/util/loadState/findModifiedInactivityScores.ts +47 -0
  269. package/src/util/loadState/findModifiedValidators.ts +46 -0
  270. package/src/util/loadState/index.ts +2 -0
  271. package/src/util/loadState/loadState.ts +225 -0
  272. package/src/util/loadState/loadValidator.ts +77 -0
  273. package/src/util/rootCache.ts +37 -0
  274. package/src/util/seed.ts +381 -0
  275. package/src/util/shufflingDecisionRoot.ts +78 -0
  276. package/src/util/signatureSets.ts +65 -0
  277. package/src/util/signingRoot.ts +13 -0
  278. package/src/util/slot.ts +22 -0
  279. package/src/util/sszBytes.ts +52 -0
  280. package/src/util/syncCommittee.ts +69 -0
  281. package/src/util/targetUnslashedBalance.ts +30 -0
  282. package/src/util/validator.ts +105 -0
  283. package/src/util/weakSubjectivity.ts +186 -0
@@ -0,0 +1,268 @@
1
+ import {PublicKey} from "@chainsafe/blst";
2
+ import {BeaconConfig} from "@lodestar/config";
3
+ import {loadState} from "../util/loadState/loadState.js";
4
+ import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js";
5
+ import {RewardCache, createEmptyRewardCache} from "./rewardCache.js";
6
+ import {
7
+ BeaconStateAllForks,
8
+ BeaconStateAltair,
9
+ BeaconStateBellatrix,
10
+ BeaconStateCapella,
11
+ BeaconStateDeneb,
12
+ BeaconStateElectra,
13
+ BeaconStateExecutions,
14
+ BeaconStateFulu,
15
+ BeaconStateGloas,
16
+ BeaconStatePhase0,
17
+ } from "./types.js";
18
+
19
+ export type BeaconStateCache = {
20
+ config: BeaconConfig;
21
+ epochCtx: EpochCache;
22
+ /** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */
23
+ readonly clonedCount: number;
24
+ readonly clonedCountWithTransferCache: number;
25
+ readonly createdWithTransferCache: boolean;
26
+ proposerRewards: RewardCache;
27
+ };
28
+
29
+ type Mutable<T> = {
30
+ -readonly [P in keyof T]: T[P];
31
+ };
32
+
33
+ type BeaconStateCacheMutable = Mutable<BeaconStateCache>;
34
+
35
+ /**
36
+ * `BeaconState` with various caches
37
+ *
38
+ * Currently contains the following:
39
+ * - The full list of network params, ssz types, and fork schedule
40
+ * - The ssz type for the state
41
+ * - The full merkle tree representation of the state
42
+ * - A cache of shufflings, committees, proposers, expanded pubkeys
43
+ * - A flat copy of validators (for fast access/iteration)
44
+ *
45
+ * ### BeaconState data representation tradeoffs:
46
+ *
47
+ * Requirements of a BeaconState:
48
+ * - Block processing and epoch processing be performant to not block the node. This functions requires to iterate over
49
+ * very large arrays fast, while doing random mutations or big mutations. After them the state must be hashed.
50
+ * Processing times: (ideal / current / maximum)
51
+ * - block processing: 20ms / 200ms / 500ms
52
+ * - epoch processing: 200ms / 2s / 4s
53
+ *
54
+ * - BeaconState must be memory efficient. Data should only be represented once in a succint manner. Uint8Arrays are
55
+ * expensive, native types are not.
56
+ * - BeaconState must be hashed efficiently. Data must be merkelized before hashing so the conversion to merkelized
57
+ * must be fast or be done already. It must must persist a hashing cache that should be structurally shared between
58
+ * states for memory efficiency.
59
+ * - BeaconState raw data changes sparsingly, so it should be structurally shared between states for memory efficiency
60
+ *
61
+ * Summary of goals:
62
+ * - Structurally share data + hashing cache
63
+ * - Very fast read and iteration over large arrays
64
+ * - Fast bulk writes and somewhat fast single writes
65
+ * - Fast merkelization of data for hashing
66
+ *
67
+ * #### state.validators
68
+ *
69
+ * 91% of all memory merkelized is state.validators. In normal network conditions state.validators changes rarely.
70
+ * However for epoch processing the entire array must be iterated and read. So we need fast reads and slow writes.
71
+ * Tradeoffs to achieve that:
72
+ * - Represent leaf data with native JS types (deserialized form)
73
+ * - Use a single Tree for structurally sharing leaf data + hashing cache
74
+ * - Keep only the root cached on leaf nodes
75
+ * - Micro-optimizations (TODO):
76
+ * - Keep also the root of the node above pubkey and withdrawal creds. Will never change
77
+ * - Keep pubkey + withdrawal creds in the same Uint8Array
78
+ * - Have a global pubkey + withdrawal creds Uint8Array global cache, like with the index2pubkey cache
79
+ *
80
+ * ------------------
81
+ *
82
+ * _Previous JSDocs for `BeaconStateContext`_
83
+ *
84
+ * Cache useful data associated to a specific state.
85
+ * Optimize processing speed of block processing + gossip validation while having a low memory cost.
86
+ *
87
+ * Previously BeaconStateContext included:
88
+ * ```ts
89
+ * validators: CachedValidatorList & T["validators"];
90
+ * balances: CachedBalanceList & T["balances"];
91
+ * inactivityScores: CachedInactivityScoreList & Number64[];
92
+ * ```
93
+ *
94
+ * Those caches where removed since they are no strictly necessary to make the epoch transition faster,
95
+ * but have a high memory cost. Note that all data was duplicated between the Tree and MutableVector.
96
+ * 1. TreeView, for efficient hashing
97
+ * 2. MutableVector (persistent-ts) with StructBacked validator objects for fast accessing and iteration
98
+ *
99
+ * ### validators
100
+ * state.validators is the heaviest data structure in the state. As TreeView, the leafs account for 91% with
101
+ * 200_000 validators. It requires ~ 2_000_000 Uint8Array instances with total memory of ~ 400MB.
102
+ * However its contents don't change very often. Validators only change when;
103
+ * - they first deposit
104
+ * - they dip from 32 effective balance to 31 (pretty much only when inactive for very long, or slashed)
105
+ * - they activate (once)
106
+ * - they exit (once)
107
+ * - they get slashed (max once)
108
+ *
109
+ * ### balances
110
+ * The balances array completely changes at the epoch boundary, where almost all the validator balances
111
+ * are updated. However it may have tiny changes during block processing if:
112
+ * - On a valid deposit
113
+ * - Validator gets slashed
114
+ * - On altair, the block proposer. Optimized to only happen once per block
115
+ *
116
+ * ### epochParticipation
117
+ * epochParticipation changes continuously through the epoch for each partipation bit of each valid attestation in the state.
118
+ * The entire structure is dropped after two epochs.
119
+ *
120
+ * ### inactivityScores
121
+ * inactivityScores can be changed only:
122
+ * - At the epoch transition. It only changes when a validator is offline. So it may change a bit but not
123
+ * a lot on normal network conditions.
124
+ * - During block processing, when a validator joins a new 0 entry is pushed
125
+ *
126
+ * RESULT: Don't keep a duplicated structure around always. During block processing just push to the tree. During
127
+ * epoch processing some temporary flat structures are computed but dropped after processing the epoch.
128
+ */
129
+ export type CachedBeaconState<T extends BeaconStateAllForks> = T & BeaconStateCache;
130
+
131
+ export type CachedBeaconStatePhase0 = CachedBeaconState<BeaconStatePhase0>;
132
+ export type CachedBeaconStateAltair = CachedBeaconState<BeaconStateAltair>;
133
+ export type CachedBeaconStateBellatrix = CachedBeaconState<BeaconStateBellatrix>;
134
+ export type CachedBeaconStateCapella = CachedBeaconState<BeaconStateCapella>;
135
+ export type CachedBeaconStateDeneb = CachedBeaconState<BeaconStateDeneb>;
136
+ export type CachedBeaconStateElectra = CachedBeaconState<BeaconStateElectra>;
137
+ export type CachedBeaconStateFulu = CachedBeaconState<BeaconStateFulu>;
138
+ export type CachedBeaconStateGloas = CachedBeaconState<BeaconStateGloas>;
139
+
140
+ export type CachedBeaconStateAllForks = CachedBeaconState<BeaconStateAllForks>;
141
+ export type CachedBeaconStateExecutions = CachedBeaconState<BeaconStateExecutions>;
142
+ /**
143
+ * Create CachedBeaconState computing a new EpochCache instance
144
+ * TODO ELECTRA: rename this to createFinalizedCachedBeaconState() as it's intended for finalized state only
145
+ */
146
+ export function createCachedBeaconState<T extends BeaconStateAllForks>(
147
+ state: T,
148
+ immutableData: EpochCacheImmutableData,
149
+ opts?: EpochCacheOpts
150
+ ): T & BeaconStateCache {
151
+ const epochCache = EpochCache.createFromState(state, immutableData, opts);
152
+ const cachedState = getCachedBeaconState(state, {
153
+ config: immutableData.config,
154
+ epochCtx: epochCache,
155
+ clonedCount: 0,
156
+ clonedCountWithTransferCache: 0,
157
+ createdWithTransferCache: false,
158
+ proposerRewards: createEmptyRewardCache(),
159
+ });
160
+
161
+ return cachedState;
162
+ }
163
+
164
+ /**
165
+ * Create a CachedBeaconState given a cached seed state and state bytes
166
+ * This guarantees that the returned state shares the same tree with the seed state
167
+ * Check loadState() api for more details
168
+ * // TODO: rename to loadUnfinalizedCachedBeaconState() due to ELECTRA
169
+ */
170
+ export function loadCachedBeaconState<T extends BeaconStateAllForks & BeaconStateCache>(
171
+ cachedSeedState: T,
172
+ stateBytes: Uint8Array,
173
+ opts?: EpochCacheOpts,
174
+ seedValidatorsBytes?: Uint8Array
175
+ ): T {
176
+ const {state: migratedState, modifiedValidators} = loadState(
177
+ cachedSeedState.config,
178
+ cachedSeedState,
179
+ stateBytes,
180
+ seedValidatorsBytes
181
+ );
182
+ const {pubkey2index, index2pubkey, shufflingCache} = cachedSeedState.epochCtx;
183
+ // Get the validators sub tree once for all the loop
184
+ const validators = migratedState.validators;
185
+ for (const validatorIndex of modifiedValidators) {
186
+ const validator = validators.getReadonly(validatorIndex);
187
+ const pubkey = validator.pubkey;
188
+ pubkey2index.set(pubkey, validatorIndex);
189
+ index2pubkey[validatorIndex] = PublicKey.fromBytes(pubkey);
190
+ }
191
+
192
+ return createCachedBeaconState(
193
+ migratedState,
194
+ {
195
+ config: cachedSeedState.config,
196
+ pubkey2index,
197
+ index2pubkey,
198
+ shufflingCache,
199
+ },
200
+ {...(opts ?? {}), ...{skipSyncPubkeys: true}}
201
+ ) as T;
202
+ }
203
+
204
+ /**
205
+ * Attach an already computed BeaconStateCache to a BeaconState object
206
+ */
207
+ export function getCachedBeaconState<T extends BeaconStateAllForks>(
208
+ state: T,
209
+ cache: BeaconStateCache
210
+ ): T & BeaconStateCache {
211
+ const cachedState = state as T & BeaconStateCache;
212
+ cachedState.config = cache.config;
213
+ cachedState.epochCtx = cache.epochCtx;
214
+ (cachedState as BeaconStateCacheMutable).clonedCount = cache.clonedCount;
215
+ (cachedState as BeaconStateCacheMutable).clonedCountWithTransferCache = cache.clonedCountWithTransferCache;
216
+ (cachedState as BeaconStateCacheMutable).createdWithTransferCache = cache.createdWithTransferCache;
217
+ cachedState.proposerRewards = cache.proposerRewards;
218
+
219
+ // Overwrite .clone function to preserve cache
220
+ // TreeViewDU.clone() creates a new object that does not have the attached cache
221
+ const viewDUClone = cachedState.clone.bind(cachedState);
222
+
223
+ function clone(this: T & BeaconStateCache, dontTransferCache?: boolean): T & BeaconStateCache {
224
+ const viewDUCloned = viewDUClone(dontTransferCache);
225
+
226
+ // Override `readonly` attribute in single place where `.clonedCount` is incremented
227
+ (this as BeaconStateCacheMutable).clonedCount++;
228
+
229
+ if (!dontTransferCache) {
230
+ (this as BeaconStateCacheMutable).clonedCountWithTransferCache++;
231
+ }
232
+
233
+ return getCachedBeaconState(viewDUCloned, {
234
+ config: this.config,
235
+ epochCtx: this.epochCtx.clone(),
236
+ clonedCount: 0,
237
+ clonedCountWithTransferCache: 0,
238
+ createdWithTransferCache: !dontTransferCache,
239
+ proposerRewards: createEmptyRewardCache(), // this sets the rewards to 0 while cloning new state
240
+ }) as T & BeaconStateCache;
241
+ }
242
+
243
+ cachedState.clone = clone as typeof viewDUClone;
244
+
245
+ return cachedState;
246
+ }
247
+
248
+ /**
249
+ * Typeguard to check if a state contains a BeaconStateCache
250
+ */
251
+ export function isCachedBeaconState<T extends BeaconStateAllForks>(
252
+ state: T | (T & BeaconStateCache)
253
+ ): state is T & BeaconStateCache {
254
+ return (state as T & BeaconStateCache).epochCtx !== undefined;
255
+ }
256
+
257
+ // Given a CachedBeaconState, check if validators array internal cache is populated.
258
+ // This cache is populated during epoch transition, and should be preserved for performance.
259
+ // If the cache is missing too often, means that our clone strategy is not working well.
260
+ export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
261
+ // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute
262
+ return state.validators["nodesPopulated"] === true;
263
+ }
264
+
265
+ export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
266
+ // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute
267
+ return state.balances["nodesPopulated"] === true;
268
+ }
@@ -0,0 +1,96 @@
1
+ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map";
2
+ import {CompositeViewDU} from "@chainsafe/ssz";
3
+ import {ValidatorIndex, ssz} from "@lodestar/types";
4
+ import {toPubkeyHex} from "@lodestar/utils";
5
+
6
+ type ValidatorSyncCommitteeIndexMap = Map<ValidatorIndex, number[]>;
7
+
8
+ export type SyncCommitteeCache = {
9
+ /**
10
+ * Update freq: every ~ 27h.
11
+ * Memory cost: 512 Number integers.
12
+ */
13
+ validatorIndices: Uint32Array;
14
+ /**
15
+ * Update freq: every ~ 27h.
16
+ * Memory cost: Map of Number -> Number with 512 entries.
17
+ * Note: it stores the position indices in sync committee for each sync committee validator
18
+ */
19
+ validatorIndexMap: ValidatorSyncCommitteeIndexMap;
20
+ };
21
+
22
+ /** Placeholder object for pre-altair fork */
23
+ export class SyncCommitteeCacheEmpty implements SyncCommitteeCache {
24
+ get validatorIndices(): Uint32Array {
25
+ throw Error("Empty SyncCommitteeCache");
26
+ }
27
+
28
+ get validatorIndexMap(): ValidatorSyncCommitteeIndexMap {
29
+ throw Error("Empty SyncCommitteeCache");
30
+ }
31
+ }
32
+
33
+ export function getSyncCommitteeCache(validatorIndices: Uint32Array): SyncCommitteeCache {
34
+ return {
35
+ validatorIndices,
36
+ validatorIndexMap: computeValidatorSyncCommitteeIndexMap(validatorIndices),
37
+ };
38
+ }
39
+
40
+ export function computeSyncCommitteeCache(
41
+ syncCommittee: CompositeViewDU<typeof ssz.altair.SyncCommittee>,
42
+ pubkey2index: PubkeyIndexMap
43
+ ): SyncCommitteeCache {
44
+ const validatorIndices = computeSyncCommitteeValidatorIndices(syncCommittee, pubkey2index);
45
+ const validatorIndexMap = computeValidatorSyncCommitteeIndexMap(validatorIndices);
46
+ return {
47
+ validatorIndices,
48
+ validatorIndexMap,
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Compute all position index in sync committee for all validatorIndexes in `syncCommitteeIndexes`.
54
+ * Helps reduce work necessary to verify a validatorIndex belongs in a sync committee and which.
55
+ * This is similar to compute_subnets_for_sync_committee in https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/validator.md
56
+ */
57
+ export function computeValidatorSyncCommitteeIndexMap(
58
+ validatorIndices: ArrayLike<ValidatorIndex>
59
+ ): ValidatorSyncCommitteeIndexMap {
60
+ const map = new Map<ValidatorIndex, number[]>();
61
+
62
+ for (let i = 0, len = validatorIndices.length; i < len; i++) {
63
+ const validatorIndex = validatorIndices[i];
64
+ let indexes = map.get(validatorIndex);
65
+ if (!indexes) {
66
+ indexes = [];
67
+ map.set(validatorIndex, indexes);
68
+ }
69
+ if (!indexes.includes(i)) {
70
+ indexes.push(i);
71
+ }
72
+ }
73
+
74
+ return map;
75
+ }
76
+
77
+ /**
78
+ * Extract validator indices from current and next sync committee
79
+ */
80
+ function computeSyncCommitteeValidatorIndices(
81
+ syncCommittee: CompositeViewDU<typeof ssz.altair.SyncCommittee>,
82
+ pubkey2index: PubkeyIndexMap
83
+ ): Uint32Array {
84
+ const pubkeys = syncCommittee.pubkeys.getAllReadonly();
85
+ const validatorIndices = new Uint32Array(pubkeys.length);
86
+ for (const [i, pubkey] of pubkeys.entries()) {
87
+ const validatorIndex = pubkey2index.get(pubkey);
88
+ if (validatorIndex === null) {
89
+ throw Error(`SyncCommittee pubkey is unknown ${toPubkeyHex(pubkey)}`);
90
+ }
91
+
92
+ validatorIndices[i] = validatorIndex;
93
+ }
94
+
95
+ return validatorIndices;
96
+ }
@@ -0,0 +1,18 @@
1
+ import {CompositeViewDU} from "@chainsafe/ssz";
2
+ import {ForkAll, ForkName, ForkPostBellatrix, ForkPreGloas} from "@lodestar/params";
3
+ import {Epoch, RootHex, SSZTypesFor} from "@lodestar/types";
4
+ import {EpochShuffling} from "../util/epochShuffling.js";
5
+
6
+ export type BeaconStatePhase0 = CompositeViewDU<SSZTypesFor<ForkName.phase0, "BeaconState">>;
7
+ export type BeaconStateAltair = CompositeViewDU<SSZTypesFor<ForkName.altair, "BeaconState">>;
8
+ export type BeaconStateBellatrix = CompositeViewDU<SSZTypesFor<ForkName.bellatrix, "BeaconState">>;
9
+ export type BeaconStateCapella = CompositeViewDU<SSZTypesFor<ForkName.capella, "BeaconState">>;
10
+ export type BeaconStateDeneb = CompositeViewDU<SSZTypesFor<ForkName.deneb, "BeaconState">>;
11
+ export type BeaconStateElectra = CompositeViewDU<SSZTypesFor<ForkName.electra, "BeaconState">>;
12
+ export type BeaconStateFulu = CompositeViewDU<SSZTypesFor<ForkName.fulu, "BeaconState">>;
13
+ export type BeaconStateGloas = CompositeViewDU<SSZTypesFor<ForkName.gloas, "BeaconState">>;
14
+
15
+ export type BeaconStateAllForks = CompositeViewDU<SSZTypesFor<ForkAll, "BeaconState">>;
16
+ export type BeaconStateExecutions = CompositeViewDU<SSZTypesFor<ForkPostBellatrix & ForkPreGloas, "BeaconState">>;
17
+
18
+ export type ShufflingGetter = (shufflingEpoch: Epoch, dependentRoot: RootHex) => EpochShuffling | null;
@@ -0,0 +1,12 @@
1
+ export const ZERO_HASH = new Uint8Array(32).fill(0);
2
+ export const EMPTY_SIGNATURE = new Uint8Array(96).fill(0);
3
+ export const SECONDS_PER_DAY = 86400;
4
+ export const BASE_REWARDS_PER_EPOCH = 4;
5
+ export const G2_POINT_AT_INFINITY = new Uint8Array(
6
+ Buffer.from(
7
+ "c000000000000000000000000000000000000000000000000000000000000000" +
8
+ "0000000000000000000000000000000000000000000000000000000000000000" +
9
+ "0000000000000000000000000000000000000000000000000000000000000000",
10
+ "hex"
11
+ )
12
+ );
@@ -0,0 +1 @@
1
+ export * from "./constants.js";
@@ -0,0 +1,55 @@
1
+ import {ForkSeq, GENESIS_EPOCH} from "@lodestar/params";
2
+ import {phase0} from "@lodestar/types";
3
+ import {beforeProcessEpoch} from "../cache/epochTransitionCache.js";
4
+ import {CachedBeaconStateAllForks} from "../types.js";
5
+ import {
6
+ processJustificationAndFinalization,
7
+ weighJustificationAndFinalization,
8
+ } from "./processJustificationAndFinalization.js";
9
+
10
+ /**
11
+ * Compute on-the-fly justified / finalized checkpoints.
12
+ * - For phase0, we need to create the cache through beforeProcessEpoch
13
+ * - For other forks, use the progressive balances inside EpochCache
14
+ */
15
+ export function computeUnrealizedCheckpoints(state: CachedBeaconStateAllForks): {
16
+ justifiedCheckpoint: phase0.Checkpoint;
17
+ finalizedCheckpoint: phase0.Checkpoint;
18
+ } {
19
+ let stateRealizedCheckpoints: CachedBeaconStateAllForks;
20
+
21
+ // For phase0, we need to create the cache through beforeProcessEpoch
22
+ if (state.config.getForkSeq(state.slot) === ForkSeq.phase0) {
23
+ // Clone state to mutate below true = do not transfer cache
24
+ stateRealizedCheckpoints = state.clone(true);
25
+ const epochTransitionCache = beforeProcessEpoch(stateRealizedCheckpoints);
26
+ processJustificationAndFinalization(stateRealizedCheckpoints, epochTransitionCache);
27
+ }
28
+
29
+ // For other forks, use the progressive balances inside EpochCache
30
+ else {
31
+ // same logic to processJustificationAndFinalization
32
+ if (state.epochCtx.epoch <= GENESIS_EPOCH + 1) {
33
+ stateRealizedCheckpoints = state;
34
+ }
35
+
36
+ // Clone state and use progressive balances
37
+ else {
38
+ // Clone state to mutate below true = do not transfer cache
39
+ stateRealizedCheckpoints = state.clone(true);
40
+
41
+ weighJustificationAndFinalization(
42
+ stateRealizedCheckpoints,
43
+ state.epochCtx.totalActiveBalanceIncrements,
44
+ // minimum of total progressive unslashed balance should be 1
45
+ Math.max(state.epochCtx.previousTargetUnslashedBalanceIncrements, 1),
46
+ Math.max(state.epochCtx.currentTargetUnslashedBalanceIncrements, 1)
47
+ );
48
+ }
49
+ }
50
+
51
+ return {
52
+ justifiedCheckpoint: stateRealizedCheckpoints.currentJustifiedCheckpoint,
53
+ finalizedCheckpoint: stateRealizedCheckpoints.finalizedCheckpoint,
54
+ };
55
+ }
@@ -0,0 +1,169 @@
1
+ import {
2
+ BASE_REWARD_FACTOR,
3
+ EFFECTIVE_BALANCE_INCREMENT,
4
+ INACTIVITY_PENALTY_QUOTIENT,
5
+ MIN_EPOCHS_TO_INACTIVITY_PENALTY,
6
+ PROPOSER_REWARD_QUOTIENT,
7
+ } from "@lodestar/params";
8
+ import {bigIntSqrt, bnToNum} from "@lodestar/utils";
9
+ import {BASE_REWARDS_PER_EPOCH as BASE_REWARDS_PER_EPOCH_CONST} from "../constants/index.js";
10
+ import {CachedBeaconStatePhase0, EpochTransitionCache} from "../types.js";
11
+ import {hasMarkers} from "../util/attesterStatus.js";
12
+ import {newZeroedArray} from "../util/index.js";
13
+
14
+ /**
15
+ * Redefine constants in attesterStatus to improve performance
16
+ */
17
+ const FLAG_PREV_SOURCE_ATTESTER = 1 << 0;
18
+ const FLAG_PREV_TARGET_ATTESTER = 1 << 1;
19
+ const FLAG_PREV_HEAD_ATTESTER = 1 << 2;
20
+ const FLAG_UNSLASHED = 1 << 6;
21
+ const FLAG_ELIGIBLE_ATTESTER = 1 << 7;
22
+
23
+ const FLAG_PREV_SOURCE_ATTESTER_OR_UNSLASHED = FLAG_PREV_SOURCE_ATTESTER | FLAG_UNSLASHED;
24
+ const FLAG_PREV_TARGET_ATTESTER_OR_UNSLASHED = FLAG_PREV_TARGET_ATTESTER | FLAG_UNSLASHED;
25
+ const FLAG_PREV_HEAD_ATTESTER_OR_UNSLASHED = FLAG_PREV_HEAD_ATTESTER | FLAG_UNSLASHED;
26
+
27
+ type RewardPenaltyItem = {
28
+ baseReward: number;
29
+ proposerReward: number;
30
+ maxAttesterReward: number;
31
+ sourceCheckpointReward: number;
32
+ targetCheckpointReward: number;
33
+ headReward: number;
34
+ basePenalty: number;
35
+ finalityDelayPenalty: number;
36
+ };
37
+
38
+ /**
39
+ * Return attestation reward/penalty deltas for each validator.
40
+ *
41
+ * - On normal mainnet conditions
42
+ * - prevSourceAttester: 98%
43
+ * - prevTargetAttester: 96%
44
+ * - prevHeadAttester: 93%
45
+ * - currSourceAttester: 95%
46
+ * - currTargetAttester: 93%
47
+ * - currHeadAttester: 91%
48
+ * - unslashed: 100%
49
+ * - eligibleAttester: 98%
50
+ */
51
+ export function getAttestationDeltas(
52
+ state: CachedBeaconStatePhase0,
53
+ cache: EpochTransitionCache
54
+ ): [number[], number[]] {
55
+ const {flags, proposerIndices, inclusionDelays} = cache;
56
+ const validatorCount = flags.length;
57
+ const rewards = newZeroedArray(validatorCount);
58
+ const penalties = newZeroedArray(validatorCount);
59
+
60
+ // no need this as we make sure it in EpochTransitionCache
61
+ // let totalBalance = bigIntMax(epochTransitionCache.totalActiveStake, increment);
62
+ const totalBalance = cache.totalActiveStakeByIncrement;
63
+ const totalBalanceInGwei = BigInt(totalBalance) * BigInt(EFFECTIVE_BALANCE_INCREMENT);
64
+
65
+ // increment is factored out from balance totals to avoid overflow
66
+ const prevEpochSourceStakeByIncrement = cache.prevEpochUnslashedStake.sourceStakeByIncrement;
67
+ const prevEpochTargetStakeByIncrement = cache.prevEpochUnslashedStake.targetStakeByIncrement;
68
+ const prevEpochHeadStakeByIncrement = cache.prevEpochUnslashedStake.headStakeByIncrement;
69
+
70
+ // sqrt first, before factoring out the increment for later usage
71
+ const balanceSqRoot = bnToNum(bigIntSqrt(totalBalanceInGwei));
72
+ const finalityDelay = cache.prevEpoch - state.finalizedCheckpoint.epoch;
73
+
74
+ const BASE_REWARDS_PER_EPOCH = BASE_REWARDS_PER_EPOCH_CONST;
75
+ const proposerRewardQuotient = PROPOSER_REWARD_QUOTIENT;
76
+ const isInInactivityLeak = finalityDelay > MIN_EPOCHS_TO_INACTIVITY_PENALTY;
77
+
78
+ // effectiveBalance is multiple of EFFECTIVE_BALANCE_INCREMENT and less than MAX_EFFECTIVE_BALANCE
79
+ // so there are limited values of them like 32, 31, 30
80
+ const rewardPnaltyItemCache = new Map<number, RewardPenaltyItem>();
81
+ const {effectiveBalanceIncrements} = state.epochCtx;
82
+ for (let i = 0; i < flags.length; i++) {
83
+ const flag = flags[i];
84
+ const effectiveBalanceIncrement = effectiveBalanceIncrements[i];
85
+ const effectiveBalance = effectiveBalanceIncrement * EFFECTIVE_BALANCE_INCREMENT;
86
+
87
+ let rewardItem = rewardPnaltyItemCache.get(effectiveBalanceIncrement);
88
+ if (!rewardItem) {
89
+ const baseReward = Math.floor(
90
+ Math.floor((effectiveBalance * BASE_REWARD_FACTOR) / balanceSqRoot) / BASE_REWARDS_PER_EPOCH
91
+ );
92
+ const proposerReward = Math.floor(baseReward / proposerRewardQuotient);
93
+ rewardItem = {
94
+ baseReward,
95
+ proposerReward,
96
+ maxAttesterReward: baseReward - proposerReward,
97
+ sourceCheckpointReward: isInInactivityLeak
98
+ ? baseReward
99
+ : Math.floor((baseReward * prevEpochSourceStakeByIncrement) / totalBalance),
100
+ targetCheckpointReward: isInInactivityLeak
101
+ ? baseReward
102
+ : Math.floor((baseReward * prevEpochTargetStakeByIncrement) / totalBalance),
103
+ headReward: isInInactivityLeak
104
+ ? baseReward
105
+ : Math.floor((baseReward * prevEpochHeadStakeByIncrement) / totalBalance),
106
+ basePenalty: baseReward * BASE_REWARDS_PER_EPOCH_CONST - proposerReward,
107
+ finalityDelayPenalty: Math.floor((effectiveBalance * finalityDelay) / INACTIVITY_PENALTY_QUOTIENT),
108
+ };
109
+ rewardPnaltyItemCache.set(effectiveBalanceIncrement, rewardItem);
110
+ }
111
+
112
+ const {
113
+ baseReward,
114
+ proposerReward,
115
+ maxAttesterReward,
116
+ sourceCheckpointReward,
117
+ targetCheckpointReward,
118
+ headReward,
119
+ basePenalty,
120
+ finalityDelayPenalty,
121
+ } = rewardItem;
122
+
123
+ // inclusion speed bonus
124
+ if (hasMarkers(flag, FLAG_PREV_SOURCE_ATTESTER_OR_UNSLASHED)) {
125
+ rewards[proposerIndices[i]] += proposerReward;
126
+ rewards[i] += Math.floor(maxAttesterReward / inclusionDelays[i]);
127
+ }
128
+
129
+ if (hasMarkers(flag, FLAG_ELIGIBLE_ATTESTER)) {
130
+ // expected FFG source
131
+ if (hasMarkers(flag, FLAG_PREV_SOURCE_ATTESTER_OR_UNSLASHED)) {
132
+ // justification-participation reward
133
+ rewards[i] += sourceCheckpointReward;
134
+ } else {
135
+ // justification-non-participation R-penalty
136
+ penalties[i] += baseReward;
137
+ }
138
+
139
+ // expected FFG target
140
+ if (hasMarkers(flag, FLAG_PREV_TARGET_ATTESTER_OR_UNSLASHED)) {
141
+ // boundary-attestation reward
142
+ rewards[i] += targetCheckpointReward;
143
+ } else {
144
+ // boundary-attestation-non-participation R-penalty
145
+ penalties[i] += baseReward;
146
+ }
147
+
148
+ // expected head
149
+ if (hasMarkers(flag, FLAG_PREV_HEAD_ATTESTER_OR_UNSLASHED)) {
150
+ // canonical-participation reward
151
+ rewards[i] += headReward;
152
+ } else {
153
+ // non-canonical-participation R-penalty
154
+ penalties[i] += baseReward;
155
+ }
156
+
157
+ // take away max rewards if we're not finalizing
158
+ if (isInInactivityLeak) {
159
+ penalties[i] += basePenalty;
160
+
161
+ if (!hasMarkers(flag, FLAG_PREV_TARGET_ATTESTER_OR_UNSLASHED)) {
162
+ penalties[i] += finalityDelayPenalty;
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ return [rewards, penalties];
169
+ }