@lodestar/state-transition 1.35.0-dev.f80d2d52da → 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,225 @@
1
+ import {ChainForkConfig} from "@lodestar/config";
2
+ import {ForkSeq} from "@lodestar/params";
3
+ import {deserializeContainerIgnoreFields, ssz} from "@lodestar/types";
4
+ import {BeaconStateAllForks, BeaconStateAltair} from "../../types.js";
5
+ import {VALIDATOR_BYTES_SIZE, getForkFromStateBytes, getStateTypeFromBytes} from "../sszBytes.js";
6
+ import {findModifiedInactivityScores} from "./findModifiedInactivityScores.js";
7
+ import {findModifiedValidators} from "./findModifiedValidators.js";
8
+ import {loadValidator} from "./loadValidator.js";
9
+
10
+ type MigrateStateOutput = {state: BeaconStateAllForks; modifiedValidators: number[]};
11
+
12
+ /**
13
+ * Load state from bytes given a seed state so that we share the same base tree. This gives some benefits:
14
+ * - Have single base tree across the application
15
+ * - Faster to load state
16
+ * - Less memory usage
17
+ * - Utilize the cached HashObjects in seed state due to a lot of validators are not changed, also the inactivity scores.
18
+ * @returns the new state and modified validators
19
+ */
20
+ export function loadState(
21
+ config: ChainForkConfig,
22
+ seedState: BeaconStateAllForks,
23
+ stateBytes: Uint8Array,
24
+ seedValidatorsBytes?: Uint8Array
25
+ ): MigrateStateOutput {
26
+ // casting only to make typescript happy
27
+ const stateType = getStateTypeFromBytes(config, stateBytes) as typeof ssz.capella.BeaconState;
28
+ const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
29
+ const fieldRanges = stateType.getFieldRanges(dataView, 0, stateBytes.length);
30
+ const allFields = Object.keys(stateType.fields);
31
+ const validatorsFieldIndex = allFields.indexOf("validators");
32
+ // start with default view has the same performance to start with seed state
33
+ // and it is not fork dependent
34
+ const migratedState = deserializeContainerIgnoreFields(
35
+ stateType,
36
+ stateBytes,
37
+ ["validators", "inactivityScores"],
38
+ fieldRanges
39
+ ) as BeaconStateAllForks;
40
+
41
+ // validators are rarely changed
42
+ const validatorsRange = fieldRanges[validatorsFieldIndex];
43
+ const modifiedValidators = loadValidators(
44
+ migratedState,
45
+ seedState,
46
+ stateBytes.subarray(validatorsRange.start, validatorsRange.end),
47
+ seedValidatorsBytes
48
+ );
49
+
50
+ // inactivityScores are rarely changed
51
+ // this saves ~500ms of hashTreeRoot() time of state
52
+ const fork = getForkFromStateBytes(config, stateBytes);
53
+ const seedFork = config.getForkSeq(seedState.slot);
54
+
55
+ if (fork >= ForkSeq.altair && seedFork >= ForkSeq.altair) {
56
+ const inactivityScoresIndex = allFields.indexOf("inactivityScores");
57
+ const inactivityScoresRange = fieldRanges[inactivityScoresIndex];
58
+ loadInactivityScores(
59
+ migratedState as BeaconStateAltair,
60
+ seedState as BeaconStateAltair,
61
+ stateBytes.subarray(inactivityScoresRange.start, inactivityScoresRange.end)
62
+ );
63
+ }
64
+ migratedState.commit();
65
+
66
+ return {state: migratedState, modifiedValidators};
67
+ }
68
+
69
+ /**
70
+ * Load state and validators Uint8Array from state bytes.
71
+ */
72
+ export function loadStateAndValidators(
73
+ chainForkConfig: ChainForkConfig,
74
+ stateBytes: Uint8Array
75
+ ): {state: BeaconStateAllForks; validatorsBytes: Uint8Array} {
76
+ // stateType could be any types, casting just to make typescript happy
77
+ const stateType = getStateTypeFromBytes(chainForkConfig, stateBytes) as typeof ssz.phase0.BeaconState;
78
+ const state = stateType.deserializeToViewDU(stateBytes);
79
+ const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
80
+ const fieldRanges = stateType.getFieldRanges(dataView, 0, stateBytes.length);
81
+ const allFields = Object.keys(stateType.fields);
82
+ const validatorFieldIndex = allFields.indexOf("validators");
83
+ const validatorRange = fieldRanges[validatorFieldIndex];
84
+ const validatorsBytes = stateBytes.subarray(validatorRange.start, validatorRange.end);
85
+ return {state, validatorsBytes};
86
+ }
87
+
88
+ /**
89
+ * This value is rarely changed as monitored 3 month state diffs on mainnet as of Sep 2023.
90
+ * Reusing this data helps save hashTreeRoot time of state ~500ms
91
+ *
92
+ * Given the below tree:
93
+ *
94
+ * seedState.inactivityScores ====> ROOT
95
+ * / \
96
+ * Hash01 Hash23
97
+ * / \ / \
98
+ * Sco0 Sco1 Sco2 Sco3
99
+ *
100
+ * if score 3 is modified, the new tree looks like this:
101
+ *
102
+ * migratedState.inactivityScores ====> ROOTa
103
+ * / \
104
+ * Hash01 Hash23a
105
+ * / \ / \
106
+ * Sco0 Sco1 Sco2 Sco3a
107
+ */
108
+ function loadInactivityScores(
109
+ migratedState: BeaconStateAltair,
110
+ seedState: BeaconStateAltair,
111
+ inactivityScoresBytes: Uint8Array
112
+ ): void {
113
+ // migratedState starts with the same inactivityScores to seed state
114
+ migratedState.inactivityScores = seedState.inactivityScores.clone();
115
+ const oldValidator = migratedState.inactivityScores.length;
116
+ // UintNum64 = 8 bytes
117
+ const newValidator = inactivityScoresBytes.length / 8;
118
+ const minValidator = Math.min(oldValidator, newValidator);
119
+ const oldInactivityScores = migratedState.inactivityScores.serialize();
120
+ const isMoreValidator = newValidator >= oldValidator;
121
+ const modifiedValidators: number[] = [];
122
+ findModifiedInactivityScores(
123
+ isMoreValidator ? oldInactivityScores : oldInactivityScores.subarray(0, minValidator * 8),
124
+ isMoreValidator ? inactivityScoresBytes.subarray(0, minValidator * 8) : inactivityScoresBytes,
125
+ modifiedValidators
126
+ );
127
+
128
+ for (const validatorIndex of modifiedValidators) {
129
+ migratedState.inactivityScores.set(
130
+ validatorIndex,
131
+ ssz.UintNum64.deserialize(inactivityScoresBytes.subarray(validatorIndex * 8, (validatorIndex + 1) * 8))
132
+ );
133
+ }
134
+
135
+ if (isMoreValidator) {
136
+ // add new inactivityScores
137
+ for (let validatorIndex = oldValidator; validatorIndex < newValidator; validatorIndex++) {
138
+ migratedState.inactivityScores.push(
139
+ ssz.UintNum64.deserialize(inactivityScoresBytes.subarray(validatorIndex * 8, (validatorIndex + 1) * 8))
140
+ );
141
+ }
142
+ } else {
143
+ if (newValidator - 1 < 0) {
144
+ migratedState.inactivityScores = ssz.altair.InactivityScores.defaultViewDU();
145
+ } else {
146
+ migratedState.inactivityScores = migratedState.inactivityScores.sliceTo(newValidator - 1);
147
+ }
148
+ }
149
+ }
150
+
151
+ /**
152
+ * As of Sep 2023, common validators of 2 mainnet states are rarely changed. However, the benchmark shows that
153
+ * 10k modified validators is not an issue. (see packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts)
154
+ *
155
+ * This method loads validators from bytes given a seed state so that they share the same base tree. This gives some benefits:
156
+ * - Have single base tree across the application
157
+ * - Faster to load state
158
+ * - Less memory usage
159
+ * - Utilize the cached HashObjects in seed state due to a lot of validators are not changed
160
+ *
161
+ * Given the below tree:
162
+ *
163
+ * seedState.validators ====> ROOT
164
+ * / \
165
+ * Hash01 Hash23
166
+ * / \ / \
167
+ * Val0 Val1 Val2 Val3
168
+ *
169
+ * if validator 3 is modified, the new tree looks like this:
170
+ *
171
+ * migratedState.validators ====> ROOTa
172
+ * / \
173
+ * Hash01 Hash23a
174
+ * / \ / \
175
+ * Val0 Val1 Val2 Val3a
176
+ *
177
+ * @param migratedState state to be migrated, the validators are loaded to this state
178
+ * @returns modified validator indices
179
+ */
180
+ function loadValidators(
181
+ migratedState: BeaconStateAllForks,
182
+ seedState: BeaconStateAllForks,
183
+ newValidatorsBytes: Uint8Array,
184
+ seedStateValidatorsBytes?: Uint8Array
185
+ ): number[] {
186
+ const seedValidatorCount = seedState.validators.length;
187
+ const newValidatorCount = Math.floor(newValidatorsBytes.length / VALIDATOR_BYTES_SIZE);
188
+ const isMoreValidator = newValidatorCount >= seedValidatorCount;
189
+ const minValidatorCount = Math.min(seedValidatorCount, newValidatorCount);
190
+ // migrated state starts with the same validators to seed state
191
+ migratedState.validators = seedState.validators.clone();
192
+ // 80% of validators serialization time comes from memory allocation
193
+ // seedStateValidatorsBytes is an optimization at beacon-node side to avoid memory allocation here
194
+ const seedValidatorsBytes = seedStateValidatorsBytes ?? seedState.validators.serialize();
195
+ const modifiedValidators: number[] = [];
196
+ findModifiedValidators(
197
+ isMoreValidator ? seedValidatorsBytes : seedValidatorsBytes.subarray(0, minValidatorCount * VALIDATOR_BYTES_SIZE),
198
+ isMoreValidator ? newValidatorsBytes.subarray(0, minValidatorCount * VALIDATOR_BYTES_SIZE) : newValidatorsBytes,
199
+ modifiedValidators
200
+ );
201
+
202
+ for (const i of modifiedValidators) {
203
+ const seedValidator = seedState.validators.get(i);
204
+ const newValidatorBytes = newValidatorsBytes.subarray(i * VALIDATOR_BYTES_SIZE, (i + 1) * VALIDATOR_BYTES_SIZE);
205
+ migratedState.validators.set(i, loadValidator(seedValidator, newValidatorBytes));
206
+ }
207
+
208
+ if (newValidatorCount >= seedValidatorCount) {
209
+ // add new validators
210
+ for (let validatorIndex = seedValidatorCount; validatorIndex < newValidatorCount; validatorIndex++) {
211
+ migratedState.validators.push(
212
+ ssz.phase0.Validator.deserializeToViewDU(
213
+ newValidatorsBytes.subarray(
214
+ validatorIndex * VALIDATOR_BYTES_SIZE,
215
+ (validatorIndex + 1) * VALIDATOR_BYTES_SIZE
216
+ )
217
+ )
218
+ );
219
+ modifiedValidators.push(validatorIndex);
220
+ }
221
+ } else {
222
+ migratedState.validators = migratedState.validators.sliceTo(newValidatorCount - 1);
223
+ }
224
+ return modifiedValidators;
225
+ }
@@ -0,0 +1,77 @@
1
+ import {CompositeViewDU} from "@chainsafe/ssz";
2
+ import {ChainForkConfig} from "@lodestar/config";
3
+ import {ValidatorIndex, deserializeContainerIgnoreFields, ssz} from "@lodestar/types";
4
+ import {getStateTypeFromBytes} from "../sszBytes.js";
5
+
6
+ /**
7
+ * Load validator from bytes given a seed validator.
8
+ * - Reuse pubkey and withdrawal credentials if possible to save memory
9
+ * - If it's a new validator, deserialize it
10
+ */
11
+ export function loadValidator(
12
+ seedValidator: CompositeViewDU<typeof ssz.phase0.Validator>,
13
+ newValidatorBytes: Uint8Array
14
+ ): CompositeViewDU<typeof ssz.phase0.Validator> {
15
+ const ignoredFields = getSameFields(seedValidator, newValidatorBytes);
16
+ if (ignoredFields.length > 0) {
17
+ const newValidatorValue = deserializeContainerIgnoreFields(ssz.phase0.Validator, newValidatorBytes, ignoredFields);
18
+ for (const field of ignoredFields) {
19
+ newValidatorValue[field] = seedValidator[field];
20
+ }
21
+ return ssz.phase0.Validator.toViewDU(newValidatorValue);
22
+ }
23
+ return ssz.phase0.Validator.deserializeToViewDU(newValidatorBytes);
24
+ }
25
+
26
+ /**
27
+ * Return pubkey or withdrawalCredentials or both if they are the same.
28
+ */
29
+ function getSameFields(
30
+ validator: CompositeViewDU<typeof ssz.phase0.Validator>,
31
+ validatorBytes: Uint8Array
32
+ ): ("pubkey" | "withdrawalCredentials")[] {
33
+ const ignoredFields: ("pubkey" | "withdrawalCredentials")[] = [];
34
+ const pubkey = validatorBytes.subarray(0, 48);
35
+ if (Buffer.compare(pubkey, validator.pubkey) === 0) {
36
+ ignoredFields.push("pubkey");
37
+ }
38
+
39
+ const withdrawalCredentials = validatorBytes.subarray(48, 80);
40
+ if (Buffer.compare(withdrawalCredentials, validator.withdrawalCredentials) === 0) {
41
+ ignoredFields.push("withdrawalCredentials");
42
+ }
43
+
44
+ return ignoredFields;
45
+ }
46
+
47
+ /**
48
+ * Extract and deserialize validator effective balances from state bytes
49
+ */
50
+ export function getEffectiveBalancesFromStateBytes(
51
+ config: ChainForkConfig,
52
+ stateBytes: Uint8Array,
53
+ validatorIndices: ValidatorIndex[]
54
+ ): number[] {
55
+ // stateType could be any types, casting just to make typescript happy
56
+ const stateType = getStateTypeFromBytes(config, stateBytes) as typeof ssz.phase0.BeaconState;
57
+ const stateView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
58
+ const stateFieldRanges = stateType.getFieldRanges(stateView, 0, stateBytes.length);
59
+ const stateFields = Object.keys(stateType.fields);
60
+ const validatorsFieldIndex = stateFields.indexOf("validators");
61
+ const validatorsRange = stateFieldRanges[validatorsFieldIndex];
62
+ const validatorsBytes = stateBytes.subarray(validatorsRange.start, validatorsRange.end);
63
+ const validatorSize = ssz.phase0.Validator.fixedSize as number;
64
+
65
+ const effectiveBalances: number[] = [];
66
+
67
+ for (const index of validatorIndices) {
68
+ const validatorBytes = validatorsBytes.subarray(index * validatorSize, (index + 1) * validatorSize);
69
+ if (validatorBytes.byteLength === 0) {
70
+ throw Error(`Validator index ${index} out of range`);
71
+ }
72
+ const validator = ssz.phase0.Validator.deserialize(validatorBytes);
73
+ effectiveBalances.push(validator.effectiveBalance);
74
+ }
75
+
76
+ return effectiveBalances;
77
+ }
@@ -0,0 +1,37 @@
1
+ import {Epoch, Root, Slot, phase0} from "@lodestar/types";
2
+ import {CachedBeaconStateAllForks} from "../types.js";
3
+ import {getBlockRoot, getBlockRootAtSlot} from "./blockRoot.js";
4
+
5
+ /**
6
+ * Cache to prevent accessing the state tree to fetch block roots repeteadly.
7
+ * In normal network conditions the same root is read multiple times, specially the target.
8
+ */
9
+ export class RootCache {
10
+ readonly currentJustifiedCheckpoint: phase0.Checkpoint;
11
+ readonly previousJustifiedCheckpoint: phase0.Checkpoint;
12
+ private readonly blockRootEpochCache = new Map<Epoch, Root>();
13
+ private readonly blockRootSlotCache = new Map<Slot, Root>();
14
+
15
+ constructor(private readonly state: CachedBeaconStateAllForks) {
16
+ this.currentJustifiedCheckpoint = state.currentJustifiedCheckpoint;
17
+ this.previousJustifiedCheckpoint = state.previousJustifiedCheckpoint;
18
+ }
19
+
20
+ getBlockRoot(epoch: Epoch): Root {
21
+ let root = this.blockRootEpochCache.get(epoch);
22
+ if (!root) {
23
+ root = getBlockRoot(this.state, epoch);
24
+ this.blockRootEpochCache.set(epoch, root);
25
+ }
26
+ return root;
27
+ }
28
+
29
+ getBlockRootAtSlot(slot: Slot): Root {
30
+ let root = this.blockRootSlotCache.get(slot);
31
+ if (!root) {
32
+ root = getBlockRootAtSlot(this.state, slot);
33
+ this.blockRootSlotCache.set(slot, root);
34
+ }
35
+ return root;
36
+ }
37
+ }