@lodestar/state-transition 1.47.0-dev.b2cbfa50c2 → 1.47.0-dev.bd761ec9ea

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 (176) hide show
  1. package/lib/block/isValidIndexedAttestation.d.ts +2 -3
  2. package/lib/block/isValidIndexedAttestation.d.ts.map +1 -1
  3. package/lib/block/isValidIndexedAttestation.js +4 -4
  4. package/lib/block/isValidIndexedAttestation.js.map +1 -1
  5. package/lib/block/isValidIndexedPayloadAttestation.d.ts.map +1 -1
  6. package/lib/block/isValidIndexedPayloadAttestation.js +1 -1
  7. package/lib/block/isValidIndexedPayloadAttestation.js.map +1 -1
  8. package/lib/block/processAttestationPhase0.d.ts.map +1 -1
  9. package/lib/block/processAttestationPhase0.js +1 -1
  10. package/lib/block/processAttestationPhase0.js.map +1 -1
  11. package/lib/block/processAttestationsAltair.js +2 -2
  12. package/lib/block/processAttestationsAltair.js.map +1 -1
  13. package/lib/block/processAttesterSlashing.d.ts +1 -2
  14. package/lib/block/processAttesterSlashing.d.ts.map +1 -1
  15. package/lib/block/processAttesterSlashing.js +3 -3
  16. package/lib/block/processAttesterSlashing.js.map +1 -1
  17. package/lib/block/processDeposit.d.ts.map +1 -1
  18. package/lib/block/processDeposit.js +21 -46
  19. package/lib/block/processDeposit.js.map +1 -1
  20. package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
  21. package/lib/block/processExecutionPayloadBid.js +2 -5
  22. package/lib/block/processExecutionPayloadBid.js.map +1 -1
  23. package/lib/block/processProposerSlashing.d.ts +1 -2
  24. package/lib/block/processProposerSlashing.d.ts.map +1 -1
  25. package/lib/block/processProposerSlashing.js +3 -3
  26. package/lib/block/processProposerSlashing.js.map +1 -1
  27. package/lib/block/processRandao.js +1 -1
  28. package/lib/block/processRandao.js.map +1 -1
  29. package/lib/block/processSyncCommittee.js +1 -1
  30. package/lib/block/processSyncCommittee.js.map +1 -1
  31. package/lib/block/processVoluntaryExit.d.ts.map +1 -1
  32. package/lib/block/processVoluntaryExit.js +1 -2
  33. package/lib/block/processVoluntaryExit.js.map +1 -1
  34. package/lib/cache/epochCache.d.ts +2 -2
  35. package/lib/cache/epochCache.d.ts.map +1 -1
  36. package/lib/cache/epochCache.js +5 -6
  37. package/lib/cache/epochCache.js.map +1 -1
  38. package/lib/cache/stateCache.js +1 -1
  39. package/lib/cache/stateCache.js.map +1 -1
  40. package/lib/cache/syncCommitteeCache.d.ts +2 -3
  41. package/lib/cache/syncCommitteeCache.d.ts.map +1 -1
  42. package/lib/cache/syncCommitteeCache.js.map +1 -1
  43. package/lib/epoch/processSyncCommitteeUpdates.js +1 -1
  44. package/lib/epoch/processSyncCommitteeUpdates.js.map +1 -1
  45. package/lib/index.d.ts +1 -2
  46. package/lib/index.d.ts.map +1 -1
  47. package/lib/index.js +1 -2
  48. package/lib/index.js.map +1 -1
  49. package/lib/lightClient/spec/store.d.ts +1 -1
  50. package/lib/lightClient/spec/store.d.ts.map +1 -1
  51. package/lib/lightClient/spec/utils.js +1 -1
  52. package/lib/lightClient/spec/utils.js.map +1 -1
  53. package/lib/lightClient/spec/validateLightClientUpdate.js +1 -1
  54. package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
  55. package/lib/metrics.d.ts +11 -0
  56. package/lib/metrics.d.ts.map +1 -1
  57. package/lib/metrics.js +22 -0
  58. package/lib/metrics.js.map +1 -1
  59. package/lib/rewards/attestationsRewards.d.ts +1 -1
  60. package/lib/rewards/attestationsRewards.d.ts.map +1 -1
  61. package/lib/rewards/attestationsRewards.js.map +1 -1
  62. package/lib/rewards/syncCommitteeRewards.d.ts +1 -1
  63. package/lib/rewards/syncCommitteeRewards.d.ts.map +1 -1
  64. package/lib/rewards/syncCommitteeRewards.js +3 -1
  65. package/lib/rewards/syncCommitteeRewards.js.map +1 -1
  66. package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -1
  67. package/lib/signatureSets/blsToExecutionChange.js +1 -2
  68. package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
  69. package/lib/signatureSets/executionPayloadEnvelope.d.ts +2 -3
  70. package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
  71. package/lib/signatureSets/executionPayloadEnvelope.js +6 -7
  72. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
  73. package/lib/signatureSets/proposer.d.ts +1 -2
  74. package/lib/signatureSets/proposer.d.ts.map +1 -1
  75. package/lib/signatureSets/proposer.js +2 -2
  76. package/lib/signatureSets/proposer.js.map +1 -1
  77. package/lib/signatureSets/randao.d.ts +1 -2
  78. package/lib/signatureSets/randao.d.ts.map +1 -1
  79. package/lib/signatureSets/randao.js +2 -2
  80. package/lib/signatureSets/randao.js.map +1 -1
  81. package/lib/signatureSets/voluntaryExits.d.ts +1 -2
  82. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
  83. package/lib/signatureSets/voluntaryExits.js +3 -4
  84. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  85. package/lib/slot/upgradeStateToGloas.d.ts +2 -1
  86. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
  87. package/lib/slot/upgradeStateToGloas.js +65 -21
  88. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  89. package/lib/stateTransition.js +8 -3
  90. package/lib/stateTransition.js.map +1 -1
  91. package/lib/stateView/stateViewFactory.d.ts +1 -1
  92. package/lib/stateView/stateViewFactory.d.ts.map +1 -1
  93. package/lib/stateView/stateViewFactory.js +2 -13
  94. package/lib/stateView/stateViewFactory.js.map +1 -1
  95. package/lib/testUtils/index.d.ts +1 -0
  96. package/lib/testUtils/index.d.ts.map +1 -1
  97. package/lib/testUtils/index.js +1 -0
  98. package/lib/testUtils/index.js.map +1 -1
  99. package/lib/testUtils/interopPubkeyCache.d.ts +7 -0
  100. package/lib/testUtils/interopPubkeyCache.d.ts.map +1 -0
  101. package/lib/testUtils/interopPubkeyCache.js +92 -0
  102. package/lib/testUtils/interopPubkeyCache.js.map +1 -0
  103. package/lib/testUtils/state.d.ts.map +1 -1
  104. package/lib/testUtils/state.js +5 -5
  105. package/lib/testUtils/state.js.map +1 -1
  106. package/lib/testUtils/testFileCache.d.ts.map +1 -1
  107. package/lib/testUtils/testFileCache.js +3 -0
  108. package/lib/testUtils/testFileCache.js.map +1 -1
  109. package/lib/testUtils/util.d.ts +1 -1
  110. package/lib/testUtils/util.d.ts.map +1 -1
  111. package/lib/testUtils/util.js +27 -35
  112. package/lib/testUtils/util.js.map +1 -1
  113. package/lib/util/gloas.d.ts +6 -0
  114. package/lib/util/gloas.d.ts.map +1 -1
  115. package/lib/util/gloas.js +25 -11
  116. package/lib/util/gloas.js.map +1 -1
  117. package/lib/util/interop.d.ts +1 -1
  118. package/lib/util/interop.d.ts.map +1 -1
  119. package/lib/util/interop.js +1 -1
  120. package/lib/util/interop.js.map +1 -1
  121. package/lib/util/pendingDepositsLookup.d.ts +12 -0
  122. package/lib/util/pendingDepositsLookup.d.ts.map +1 -1
  123. package/lib/util/pendingDepositsLookup.js +19 -1
  124. package/lib/util/pendingDepositsLookup.js.map +1 -1
  125. package/lib/util/signatureSets.d.ts +5 -13
  126. package/lib/util/signatureSets.d.ts.map +1 -1
  127. package/lib/util/signatureSets.js +30 -39
  128. package/lib/util/signatureSets.js.map +1 -1
  129. package/lib/util/syncCommittee.js +1 -1
  130. package/lib/util/syncCommittee.js.map +1 -1
  131. package/package.json +11 -12
  132. package/src/block/isValidIndexedAttestation.ts +2 -8
  133. package/src/block/isValidIndexedPayloadAttestation.ts +1 -4
  134. package/src/block/processAttestationPhase0.ts +0 -1
  135. package/src/block/processAttestationsAltair.ts +2 -2
  136. package/src/block/processAttesterSlashing.ts +2 -13
  137. package/src/block/processDeposit.ts +35 -47
  138. package/src/block/processExecutionPayloadBid.ts +8 -6
  139. package/src/block/processProposerSlashing.ts +2 -11
  140. package/src/block/processRandao.ts +1 -1
  141. package/src/block/processSyncCommittee.ts +1 -1
  142. package/src/block/processVoluntaryExit.ts +1 -4
  143. package/src/cache/epochCache.ts +6 -7
  144. package/src/cache/stateCache.ts +1 -1
  145. package/src/cache/syncCommitteeCache.ts +3 -2
  146. package/src/epoch/processSyncCommitteeUpdates.ts +1 -1
  147. package/src/index.ts +1 -6
  148. package/src/lightClient/spec/store.ts +1 -1
  149. package/src/lightClient/spec/utils.ts +1 -1
  150. package/src/lightClient/spec/validateLightClientUpdate.ts +1 -1
  151. package/src/metrics.ts +23 -0
  152. package/src/rewards/attestationsRewards.ts +1 -1
  153. package/src/rewards/syncCommitteeRewards.ts +4 -2
  154. package/src/signatureSets/blsToExecutionChange.ts +1 -2
  155. package/src/signatureSets/executionPayloadEnvelope.ts +14 -15
  156. package/src/signatureSets/proposer.ts +1 -3
  157. package/src/signatureSets/randao.ts +2 -3
  158. package/src/signatureSets/voluntaryExits.ts +2 -5
  159. package/src/slot/upgradeStateToGloas.ts +75 -24
  160. package/src/stateTransition.ts +8 -3
  161. package/src/stateView/stateViewFactory.ts +2 -14
  162. package/src/testUtils/index.ts +1 -0
  163. package/src/testUtils/interopPubkeyCache.ts +100 -0
  164. package/src/testUtils/state.ts +5 -11
  165. package/src/testUtils/testFileCache.ts +3 -0
  166. package/src/testUtils/util.ts +26 -38
  167. package/src/util/gloas.ts +40 -11
  168. package/src/util/interop.ts +1 -1
  169. package/src/util/pendingDepositsLookup.ts +20 -1
  170. package/src/util/signatureSets.ts +34 -51
  171. package/src/util/syncCommittee.ts +1 -1
  172. package/lib/cache/pubkeyCache.d.ts +0 -28
  173. package/lib/cache/pubkeyCache.d.ts.map +0 -1
  174. package/lib/cache/pubkeyCache.js +0 -49
  175. package/lib/cache/pubkeyCache.js.map +0 -1
  176. package/src/cache/pubkeyCache.ts +0 -74
@@ -1,4 +1,3 @@
1
- import {PublicKey, Signature, verify} from "@chainsafe/blst";
2
1
  import {
3
2
  BUILDER_INDEX_SELF_BUILD,
4
3
  ForkSeq,
@@ -12,7 +11,13 @@ import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
12
11
  import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
13
12
  import {CachedBeaconStateGloas, CachedBeaconStateHeze} from "../types.js";
14
13
  import {canBuilderCoverBid, isActiveBuilder} from "../util/gloas.js";
15
- import {getBlockRootAtSlot, getCurrentEpoch, getRandaoMix} from "../util/index.js";
14
+ import {
15
+ createSingleSignatureSetFromComponents,
16
+ getBlockRootAtSlot,
17
+ getCurrentEpoch,
18
+ getRandaoMix,
19
+ verifySignatureSet,
20
+ } from "../util/index.js";
16
21
 
17
22
  export function processExecutionPayloadBid(
18
23
  state: CachedBeaconStateGloas | CachedBeaconStateHeze,
@@ -123,10 +128,7 @@ function verifyExecutionPayloadBidSignature(
123
128
  const signingRoot = getExecutionPayloadBidSigningRoot(state.config, signedBid.message);
124
129
 
125
130
  try {
126
- const publicKey = PublicKey.fromBytes(pubkey);
127
- const signature = Signature.fromBytes(signedBid.signature, true);
128
-
129
- return verify(signingRoot, publicKey, signature);
131
+ return verifySignatureSet(createSingleSignatureSetFromComponents(pubkey, signingRoot, signedBid.signature));
130
132
  } catch (_e) {
131
133
  return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature
132
134
  }
@@ -2,7 +2,6 @@ import {BeaconConfig} from "@lodestar/config";
2
2
  import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
3
3
  import {Slot, phase0, ssz} from "@lodestar/types";
4
4
  import {Validator} from "@lodestar/types/phase0";
5
- import {PubkeyCache} from "../cache/pubkeyCache.js";
6
5
  import {getProposerSlashingSignatureSets} from "../signatureSets/index.js";
7
6
  import {CachedBeaconStateAllForks, CachedBeaconStateGloas} from "../types.js";
8
7
  import {computeEpochAtSlot, isSlashableValidator} from "../util/index.js";
@@ -22,14 +21,7 @@ export function processProposerSlashing(
22
21
  verifySignatures = true
23
22
  ): void {
24
23
  const proposer = state.validators.getReadonly(proposerSlashing.signedHeader1.message.proposerIndex);
25
- assertValidProposerSlashing(
26
- state.config,
27
- state.epochCtx.pubkeyCache,
28
- state.slot,
29
- proposerSlashing,
30
- proposer,
31
- verifySignatures
32
- );
24
+ assertValidProposerSlashing(state.config, state.slot, proposerSlashing, proposer, verifySignatures);
33
25
 
34
26
  if (fork >= ForkSeq.gloas) {
35
27
  // Remove the BuilderPendingPayment corresponding to this proposal if it is still in the
@@ -62,7 +54,6 @@ export function processProposerSlashing(
62
54
 
63
55
  export function assertValidProposerSlashing(
64
56
  config: BeaconConfig,
65
- pubkeyCache: PubkeyCache,
66
57
  stateSlot: Slot,
67
58
  proposerSlashing: phase0.ProposerSlashing,
68
59
  proposer: Validator,
@@ -99,7 +90,7 @@ export function assertValidProposerSlashing(
99
90
  if (verifySignatures) {
100
91
  const signatureSets = getProposerSlashingSignatureSets(config, stateSlot, proposerSlashing);
101
92
  for (let i = 0; i < signatureSets.length; i++) {
102
- if (!verifySignatureSet(signatureSets[i], pubkeyCache)) {
93
+ if (!verifySignatureSet(signatureSets[i])) {
103
94
  throw new Error(`ProposerSlashing header${i + 1} signature invalid`);
104
95
  }
105
96
  }
@@ -17,7 +17,7 @@ export function processRandao(state: CachedBeaconStateAllForks, block: BeaconBlo
17
17
  const randaoReveal = block.body.randaoReveal;
18
18
 
19
19
  // verify RANDAO reveal
20
- if (verifySignature && !verifyRandaoSignature(config, epochCtx.pubkeyCache, block)) {
20
+ if (verifySignature && !verifyRandaoSignature(config, block)) {
21
21
  throw new Error("RANDAO reveal is an invalid signature");
22
22
  }
23
23
 
@@ -32,7 +32,7 @@ export function processSyncAggregate(
32
32
  participantIndices
33
33
  );
34
34
  // When there's no participation we consider the signature valid and just ignore it
35
- if (signatureSet !== null && !verifySignatureSet(signatureSet, state.epochCtx.pubkeyCache)) {
35
+ if (signatureSet !== null && !verifySignatureSet(signatureSet)) {
36
36
  throw Error("Sync committee signature invalid");
37
37
  }
38
38
  }
@@ -93,10 +93,7 @@ function getValidatorVoluntaryExitValidity(
93
93
  }
94
94
 
95
95
  // Verify signature
96
- if (
97
- verifySignature &&
98
- !verifyVoluntaryExitSignature(config, epochCtx.pubkeyCache, new BeaconStateView(state), signedVoluntaryExit)
99
- ) {
96
+ if (verifySignature && !verifyVoluntaryExitSignature(config, new BeaconStateView(state), signedVoluntaryExit)) {
100
97
  return VoluntaryExitValidity.invalidSignature;
101
98
  }
102
99
 
@@ -1,4 +1,5 @@
1
- import {PublicKey} from "@chainsafe/blst";
1
+ import {PublicKey} from "@chainsafe/lodestar-z/blst";
2
+ import {type PubkeyCache, pubkeyCache as defaultPubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
2
3
  import {BeaconConfig, ChainConfig, createBeaconConfig} from "@lodestar/config";
3
4
  import {
4
5
  ATTESTATION_SUBNET_COUNT,
@@ -56,7 +57,6 @@ import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalanc
56
57
  import {BuilderDepositSignatureCache} from "./builderDepositSignatureCache.js";
57
58
  import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js";
58
59
  import {EpochTransitionCache} from "./epochTransitionCache.js";
59
- import {PubkeyCache, createPubkeyCache, syncPubkeys} from "./pubkeyCache.js";
60
60
  import {CachedBeaconStateAllForks, CachedBeaconStateFulu, CachedBeaconStateGloas} from "./stateCache.js";
61
61
  import {
62
62
  SyncCommitteeCache,
@@ -341,10 +341,10 @@ export class EpochCache {
341
341
  const validators = state.validators.getAllReadonlyValues();
342
342
  const validatorCount = validators.length;
343
343
 
344
- // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches
344
+ // syncPubkeys here to ensure EpochCacheImmutableData is populated before computing the rest of caches
345
345
  // - computeSyncCommitteeCache() needs a fully populated pubkeyCache
346
346
  if (!opts?.skipSyncPubkeys) {
347
- syncPubkeys(pubkeyCache, validators);
347
+ pubkeyCache.syncPubkeys(validators);
348
348
  }
349
349
 
350
350
  const effectiveBalanceIncrements = getEffectiveBalanceIncrementsWithLen(validatorCount);
@@ -908,7 +908,7 @@ export class EpochCache {
908
908
  }
909
909
 
910
910
  addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void {
911
- this.pubkeyCache.set(index, pubkey);
911
+ this.pubkeyCache.append(index, pubkey);
912
912
  }
913
913
 
914
914
  getShufflingAtSlot(slot: Slot): EpochShuffling {
@@ -1123,7 +1123,6 @@ export function createEmptyEpochCacheImmutableData(
1123
1123
  ): EpochCacheImmutableData {
1124
1124
  return {
1125
1125
  config: createBeaconConfig(chainConfig, state.genesisValidatorsRoot),
1126
- // This is a test state, there's no need to have a global shared cache of keys
1127
- pubkeyCache: createPubkeyCache(),
1126
+ pubkeyCache: defaultPubkeyCache,
1128
1127
  };
1129
1128
  }
@@ -187,7 +187,7 @@ export function loadCachedBeaconState<T extends CachedBeaconStateAllForks>(
187
187
  const validators = migratedState.validators;
188
188
  for (const validatorIndex of modifiedValidators) {
189
189
  const validator = validators.getReadonly(validatorIndex);
190
- pubkeyCache.set(validatorIndex, validator.pubkey);
190
+ pubkeyCache.append(validatorIndex, validator.pubkey);
191
191
  }
192
192
 
193
193
  return createCachedBeaconState(
@@ -1,3 +1,4 @@
1
+ import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
1
2
  import {CompositeViewDU} from "@chainsafe/ssz";
2
3
  import {ValidatorIndex, ssz} from "@lodestar/types";
3
4
  import {toPubkeyHex} from "@lodestar/utils";
@@ -38,7 +39,7 @@ export function getSyncCommitteeCache(validatorIndices: Uint32Array): SyncCommit
38
39
 
39
40
  export function computeSyncCommitteeCache(
40
41
  syncCommittee: CompositeViewDU<typeof ssz.altair.SyncCommittee>,
41
- pubkeyCache: {getIndex(pubkey: Uint8Array): number | null}
42
+ pubkeyCache: PubkeyCache
42
43
  ): SyncCommitteeCache {
43
44
  const validatorIndices = computeSyncCommitteeValidatorIndices(syncCommittee, pubkeyCache);
44
45
  const validatorIndexMap = computeValidatorSyncCommitteeIndexMap(validatorIndices);
@@ -78,7 +79,7 @@ export function computeValidatorSyncCommitteeIndexMap(
78
79
  */
79
80
  function computeSyncCommitteeValidatorIndices(
80
81
  syncCommittee: CompositeViewDU<typeof ssz.altair.SyncCommittee>,
81
- pubkeyCache: {getIndex(pubkey: Uint8Array): number | null}
82
+ pubkeyCache: PubkeyCache
82
83
  ): Uint32Array {
83
84
  const pubkeys = syncCommittee.pubkeys.getAllReadonly();
84
85
  const validatorIndices = new Uint32Array(pubkeys.length);
@@ -1,4 +1,4 @@
1
- import {aggregateSerializedPublicKeys} from "@chainsafe/blst";
1
+ import {aggregateSerializedPublicKeys} from "@chainsafe/lodestar-z/blst";
2
2
  import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, ForkSeq} from "@lodestar/params";
3
3
  import {ssz} from "@lodestar/types";
4
4
  import {CachedBeaconStateAltair} from "../types.js";
package/src/index.ts CHANGED
@@ -1,8 +1,4 @@
1
- export {
2
- type BlockExternalData,
3
- DataAvailabilityStatus,
4
- ExecutionPayloadStatus,
5
- } from "./block/externalData.js";
1
+ export {type BlockExternalData, DataAvailabilityStatus, ExecutionPayloadStatus} from "./block/externalData.js";
6
2
  export {getAttestationParticipationStatus, processAttestationsAltair} from "./block/processAttestationsAltair.js";
7
3
  export {assertValidAttesterSlashing} from "./block/processAttesterSlashing.js";
8
4
  export {isValidBlsToExecutionChange} from "./block/processBlsToExecutionChange.js";
@@ -25,7 +21,6 @@ export {
25
21
  createEmptyEpochCacheImmutableData,
26
22
  } from "./cache/epochCache.js";
27
23
  export {type EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js";
28
- export {type PubkeyCache, createPubkeyCache, syncPubkeys} from "./cache/pubkeyCache.js";
29
24
  // Main state caches
30
25
  export {
31
26
  type BeaconStateCache,
@@ -1,4 +1,4 @@
1
- import type {PublicKey} from "@chainsafe/blst";
1
+ import type {PublicKey} from "@chainsafe/lodestar-z/blst";
2
2
  import {BeaconConfig} from "@lodestar/config";
3
3
  import {LightClientBootstrap, LightClientHeader, LightClientUpdate, SyncPeriod} from "@lodestar/types";
4
4
  import {computeSyncPeriodAtSlot} from "../../util/epoch.js";
@@ -1,4 +1,4 @@
1
- import {PublicKey} from "@chainsafe/blst";
1
+ import {PublicKey} from "@chainsafe/lodestar-z/blst";
2
2
  import {Tree} from "@chainsafe/persistent-merkle-tree";
3
3
  import {BitArray} from "@chainsafe/ssz";
4
4
  import {ChainForkConfig} from "@lodestar/config";
@@ -1,4 +1,4 @@
1
- import {PublicKey, Signature, fastAggregateVerify} from "@chainsafe/blst";
1
+ import {PublicKey, Signature, fastAggregateVerify} from "@chainsafe/lodestar-z/blst";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
3
  import {DOMAIN_SYNC_COMMITTEE, GENESIS_SLOT, MIN_SYNC_COMMITTEE_PARTICIPANTS} from "@lodestar/params";
4
4
  import {LightClientUpdate, Root, ssz} from "@lodestar/types";
package/src/metrics.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import {ForkName} from "@lodestar/params";
1
2
  import {MetricsRegister} from "@lodestar/utils";
2
3
  import {ProposerRewardType} from "./block/types.js";
3
4
  import {EpochTransitionStep} from "./epoch/index.js";
@@ -31,6 +32,28 @@ export function getMetrics(register: MetricsRegister) {
31
32
  labelNames: ["step"],
32
33
  buckets: [0.01, 0.05, 0.1, 0.2, 0.5, 0.75, 1],
33
34
  }),
35
+ forkUpgradeTime: register.histogram<{fork: ForkName}>({
36
+ name: "lodestar_stfn_fork_upgrade_seconds",
37
+ help: "Time to upgrade the state at a fork boundary in seconds",
38
+ labelNames: ["fork"],
39
+ // The gloas upgrade is unbounded (see onboardBuildersTime), hence the long tail
40
+ buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30],
41
+ }),
42
+ onboardBuildersTime: register.histogram({
43
+ name: "lodestar_stfn_gloas_onboard_builders_seconds",
44
+ help: "Time spent in onboardBuildersFromPendingDeposits at the gloas fork transition",
45
+ buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30],
46
+ }),
47
+ onboardBuildersDeposits: register.gauge<{outcome: "onboarded" | "topup" | "kept" | "dropped"}>({
48
+ name: "lodestar_stfn_gloas_onboard_builders_deposits",
49
+ help: "Pending deposits handled at the gloas fork transition, by outcome",
50
+ labelNames: ["outcome"],
51
+ }),
52
+ onboardBuildersSignatureChecks: register.gauge<{source: "cache" | "verified"}>({
53
+ name: "lodestar_stfn_gloas_onboard_builders_signature_checks",
54
+ help: "Builder deposit signature checks at the gloas fork transition. `verified` means the pre-verify cache missed and BLS ran inline, on the fork transition's critical path",
55
+ labelNames: ["source"],
56
+ }),
34
57
  processBlockTime: register.histogram({
35
58
  name: "lodestar_stfn_process_block_seconds",
36
59
  help: "Time to process a single block in seconds",
@@ -1,3 +1,4 @@
1
+ import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
1
2
  import {BeaconConfig} from "@lodestar/config";
2
3
  import {
3
4
  EFFECTIVE_BALANCE_INCREMENT,
@@ -15,7 +16,6 @@ import {
15
16
  import {ValidatorIndex, rewards} from "@lodestar/types";
16
17
  import {fromHex} from "@lodestar/utils";
17
18
  import {EpochTransitionCache, beforeProcessEpoch} from "../cache/epochTransitionCache.js";
18
- import {PubkeyCache} from "../cache/pubkeyCache.js";
19
19
  import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js";
20
20
  import {
21
21
  FLAG_ELIGIBLE_ATTESTER,
@@ -1,7 +1,8 @@
1
+ import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
1
2
  import {BeaconConfig} from "@lodestar/config";
2
3
  import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params";
3
4
  import {BeaconBlock, ValidatorIndex, altair, rewards} from "@lodestar/types";
4
- import {PubkeyCache} from "../cache/pubkeyCache.js";
5
+ import {toPubkeyHex} from "@lodestar/utils";
5
6
  import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../cache/stateCache.js";
6
7
 
7
8
  export async function computeSyncCommitteeRewards(
@@ -48,7 +49,8 @@ export async function computeSyncCommitteeRewards(
48
49
  if (validatorIds.length) {
49
50
  const filtersSet = new Set(validatorIds);
50
51
  return rewards.filter((reward) => {
51
- const pubkeyHex = pubkeyCache.get(reward.validatorIndex)?.toHex();
52
+ const pubkey = pubkeyCache.getPubkeyBytes(reward.validatorIndex);
53
+ const pubkeyHex = pubkey === undefined ? undefined : toPubkeyHex(pubkey);
52
54
  return filtersSet.has(reward.validatorIndex) || (pubkeyHex !== undefined && filtersSet.has(pubkeyHex));
53
55
  });
54
56
  }
@@ -1,4 +1,3 @@
1
- import {PublicKey} from "@chainsafe/blst";
2
1
  import {BeaconConfig} from "@lodestar/config";
3
2
  import {DOMAIN_BLS_TO_EXECUTION_CHANGE, ForkName} from "@lodestar/params";
4
3
  import {capella, ssz} from "@lodestar/types";
@@ -26,7 +25,7 @@ export function getBlsToExecutionChangeSignatureSet(
26
25
  type: SignatureSetType.single,
27
26
  // The withdrawal pubkey is the same as signedBLSToExecutionChange's fromBlsPubkey as it should
28
27
  // be validated against the withdrawal credentials digest
29
- pubkey: PublicKey.fromBytes(signedBLSToExecutionChange.message.fromBlsPubkey, true),
28
+ pubkey: signedBLSToExecutionChange.message.fromBlsPubkey,
30
29
  signingRoot: computeSigningRoot(ssz.capella.BLSToExecutionChange, signedBLSToExecutionChange.message, domain),
31
30
  signature: signedBLSToExecutionChange.signature,
32
31
  };
@@ -1,11 +1,13 @@
1
- import {PublicKey} from "@chainsafe/blst";
2
1
  import {BeaconConfig} from "@lodestar/config";
3
2
  import {BUILDER_INDEX_SELF_BUILD, DOMAIN_BEACON_BUILDER} from "@lodestar/params";
4
3
  import {ValidatorIndex, gloas, ssz} from "@lodestar/types";
5
- import {PubkeyCache} from "../cache/pubkeyCache.js";
6
4
  import {IBeaconStateView, isStatePostGloas} from "../stateView/interface.js";
7
5
  import {computeSigningRoot} from "../util/index.js";
8
- import {type SingleSignatureSet, createSingleSignatureSetFromComponents} from "../util/signatureSets.js";
6
+ import {
7
+ type ISignatureSet,
8
+ createIndexedSignatureSetFromComponents,
9
+ createSingleSignatureSetFromComponents,
10
+ } from "../util/signatureSets.js";
9
11
 
10
12
  export function getExecutionPayloadEnvelopeSigningRoot(
11
13
  config: BeaconConfig,
@@ -18,24 +20,21 @@ export function getExecutionPayloadEnvelopeSigningRoot(
18
20
 
19
21
  export function getExecutionPayloadEnvelopeSignatureSet(
20
22
  config: BeaconConfig,
21
- pubkeyCache: PubkeyCache,
22
23
  state: IBeaconStateView,
23
24
  signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
24
25
  proposerIndex: ValidatorIndex
25
- ): SingleSignatureSet {
26
+ ): ISignatureSet {
26
27
  if (!isStatePostGloas(state)) {
27
28
  throw new Error(`Expected gloas+ state for execution payload envelope signature, got fork=${state.forkName}`);
28
29
  }
29
30
 
30
31
  const envelope = signedEnvelope.message;
31
- const pubkey =
32
- envelope.builderIndex === BUILDER_INDEX_SELF_BUILD
33
- ? pubkeyCache.getOrThrow(proposerIndex)
34
- : PublicKey.fromBytes(state.getBuilder(envelope.builderIndex).pubkey);
35
-
36
- return createSingleSignatureSetFromComponents(
37
- pubkey,
38
- getExecutionPayloadEnvelopeSigningRoot(config, envelope),
39
- signedEnvelope.signature
40
- );
32
+ const signingRoot = getExecutionPayloadEnvelopeSigningRoot(config, envelope);
33
+ return envelope.builderIndex === BUILDER_INDEX_SELF_BUILD
34
+ ? createIndexedSignatureSetFromComponents(proposerIndex, signingRoot, signedEnvelope.signature)
35
+ : createSingleSignatureSetFromComponents(
36
+ state.getBuilder(envelope.builderIndex).pubkey,
37
+ signingRoot,
38
+ signedEnvelope.signature
39
+ );
41
40
  }
@@ -1,17 +1,15 @@
1
1
  import {BeaconConfig} from "@lodestar/config";
2
2
  import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params";
3
3
  import {SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, isBlindedBeaconBlock, phase0, ssz} from "@lodestar/types";
4
- import {PubkeyCache} from "../cache/pubkeyCache.js";
5
4
  import {computeSigningRoot} from "../util/index.js";
6
5
  import {ISignatureSet, SignatureSetType, verifySignatureSet} from "../util/signatureSets.js";
7
6
 
8
7
  export function verifyProposerSignature(
9
8
  config: BeaconConfig,
10
- pubkeyCache: PubkeyCache,
11
9
  signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock
12
10
  ): boolean {
13
11
  const signatureSet = getBlockProposerSignatureSet(config, signedBlock);
14
- return verifySignatureSet(signatureSet, pubkeyCache);
12
+ return verifySignatureSet(signatureSet);
15
13
  }
16
14
 
17
15
  export function getBlockProposerSignatureSet(
@@ -1,7 +1,6 @@
1
1
  import {BeaconConfig} from "@lodestar/config";
2
2
  import {DOMAIN_RANDAO} from "@lodestar/params";
3
3
  import {BeaconBlock, ssz} from "@lodestar/types";
4
- import {PubkeyCache} from "../cache/pubkeyCache.js";
5
4
  import {
6
5
  ISignatureSet,
7
6
  SignatureSetType,
@@ -10,8 +9,8 @@ import {
10
9
  verifySignatureSet,
11
10
  } from "../util/index.js";
12
11
 
13
- export function verifyRandaoSignature(config: BeaconConfig, pubkeyCache: PubkeyCache, block: BeaconBlock): boolean {
14
- return verifySignatureSet(getRandaoRevealSignatureSet(config, block), pubkeyCache);
12
+ export function verifyRandaoSignature(config: BeaconConfig, block: BeaconBlock): boolean {
13
+ return verifySignatureSet(getRandaoRevealSignatureSet(config, block));
15
14
  }
16
15
 
17
16
  /**
@@ -1,8 +1,6 @@
1
- import {PublicKey} from "@chainsafe/blst";
2
1
  import {BeaconConfig} from "@lodestar/config";
3
2
  import {ForkSeq} from "@lodestar/params";
4
3
  import {SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types";
5
- import {PubkeyCache} from "../cache/pubkeyCache.js";
6
4
  import {IBeaconStateView, IBeaconStateViewGloas, isStatePostGloas} from "../stateView/interface.js";
7
5
  import {
8
6
  ISignatureSet,
@@ -16,11 +14,10 @@ import {
16
14
 
17
15
  export function verifyVoluntaryExitSignature(
18
16
  config: BeaconConfig,
19
- pubkeyCache: PubkeyCache,
20
17
  state: IBeaconStateView,
21
18
  signedVoluntaryExit: phase0.SignedVoluntaryExit
22
19
  ): boolean {
23
- return verifySignatureSet(getVoluntaryExitSignatureSet(config, state, signedVoluntaryExit), pubkeyCache);
20
+ return verifySignatureSet(getVoluntaryExitSignatureSet(config, state, signedVoluntaryExit));
24
21
  }
25
22
 
26
23
  /**
@@ -81,7 +78,7 @@ export function getBuilderVoluntaryExitSignatureSet(
81
78
 
82
79
  return {
83
80
  type: SignatureSetType.single,
84
- pubkey: PublicKey.fromBytes(builder.pubkey),
81
+ pubkey: builder.pubkey,
85
82
  signingRoot: computeSigningRoot(ssz.phase0.VoluntaryExit, signedVoluntaryExit.message, domain),
86
83
  signature: signedVoluntaryExit.signature,
87
84
  };
@@ -10,13 +10,14 @@ import {
10
10
  ProgressiveListCompositeType,
11
11
  ValueOf,
12
12
  } from "@chainsafe/ssz";
13
- import {PAYLOAD_BUILDER_VERSION, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
14
- import {ssz} from "@lodestar/types";
13
+ import {BUILDER_INDEX_SELF_BUILD, PAYLOAD_BUILDER_VERSION, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
14
+ import {BuilderIndex, ssz} from "@lodestar/types";
15
15
  import {toPubkeyHex} from "@lodestar/utils";
16
16
  import {isValidDepositSignature} from "../block/processDeposit.js";
17
17
  import {getCachedBeaconState} from "../cache/stateCache.js";
18
+ import type {BeaconStateTransitionMetrics} from "../metrics.js";
18
19
  import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
19
- import {addBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
20
+ import {appendBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
20
21
  import {isValidatorKnown} from "../util/index.js";
21
22
  import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
22
23
  import {progressiveListRootNode} from "../util/ssz.js";
@@ -24,7 +25,10 @@ import {progressiveListRootNode} from "../util/ssz.js";
24
25
  /**
25
26
  * Upgrade a state from Fulu to Gloas.
26
27
  */
27
- export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBeaconStateGloas {
28
+ export function upgradeStateToGloas(
29
+ stateFulu: CachedBeaconStateFulu,
30
+ metrics?: BeaconStateTransitionMetrics | null
31
+ ): CachedBeaconStateGloas {
28
32
  const {config} = stateFulu;
29
33
 
30
34
  ssz.fulu.BeaconState.commitViewDU(stateFulu);
@@ -69,11 +73,21 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
69
73
  );
70
74
  stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
71
75
  stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
72
- stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
73
- stateGloasView.latestExecutionPayloadBid.gasLimit = BigInt(stateFulu.latestExecutionPayloadHeader.gasLimit);
74
- stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(
75
- ssz.gloas.ExecutionRequests.defaultValue()
76
- );
76
+ const latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU({
77
+ parentBlockHash: stateFulu.latestExecutionPayloadHeader.parentHash,
78
+ parentBlockRoot: stateFulu.latestBlockHeader.parentRoot,
79
+ blockHash: stateFulu.latestExecutionPayloadHeader.blockHash,
80
+ prevRandao: stateFulu.latestExecutionPayloadHeader.prevRandao,
81
+ feeRecipient: ssz.ExecutionAddress.defaultValue(),
82
+ gasLimit: BigInt(stateFulu.latestExecutionPayloadHeader.gasLimit),
83
+ builderIndex: BUILDER_INDEX_SELF_BUILD,
84
+ slot: stateFulu.latestBlockHeader.slot,
85
+ value: 0,
86
+ executionPayment: 0n,
87
+ blobKzgCommitments: ssz.gloas.BlobKzgCommitments.defaultValue(),
88
+ executionRequestsRoot: ssz.gloas.ExecutionRequests.hashTreeRoot(ssz.gloas.ExecutionRequests.defaultValue()),
89
+ });
90
+ stateGloasView.latestExecutionPayloadBid = latestExecutionPayloadBid;
77
91
  stateGloasView.nextWithdrawalIndex = stateGloasCloned.nextWithdrawalIndex;
78
92
  stateGloasView.nextWithdrawalValidatorIndex = stateGloasCloned.nextWithdrawalValidatorIndex;
79
93
  stateGloasView.historicalSummaries = stateGloasCloned.historicalSummaries;
@@ -106,7 +120,7 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
106
120
  const stateGloas = getCachedBeaconState(stateGloasView, stateFulu);
107
121
 
108
122
  // Process pending builder deposits at the fork boundary
109
- onboardBuildersFromPendingDeposits(stateGloas);
123
+ onboardBuildersFromPendingDeposits(stateGloas, metrics);
110
124
 
111
125
  stateGloas.commit();
112
126
  // Clear cache to ensure the cache of fulu fields is not used by new gloas fields
@@ -164,10 +178,29 @@ function migrateBasicListToGloas<ElementType extends BasicType<unknown>>(
164
178
  * Applies any pending deposits for builders to onboard builders during the fork transition
165
179
  * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.8/specs/gloas/fork.md#new-onboard_builders_from_pending_deposits
166
180
  */
167
- function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void {
168
- // Track pubkeys of new builders added when applying deposits. `state.builders` starts empty
169
- // at the fork, so every builder pubkey here is one added in an earlier iteration.
170
- const builderPubkeys = new Set<string>();
181
+ function onboardBuildersFromPendingDeposits(
182
+ state: CachedBeaconStateGloas,
183
+ metrics?: BeaconStateTransitionMetrics | null
184
+ ): void {
185
+ const timer = metrics?.onboardBuildersTime.startTimer();
186
+
187
+ // Counted so the duration above is interpretable: this loop walks the whole pending
188
+ // deposit queue, and its cost is dominated by whichever branch the queue happens to
189
+ // hit. `verified` signature checks are the ones the pre-verify cache missed, i.e. BLS
190
+ // running inline on the fork transition's critical path. The signature totals include
191
+ // the checks hasPendingValidator() does internally, which dominate when a builder
192
+ // deposit is preceded by same-pubkey validator deposits.
193
+ let onboarded = 0;
194
+ let topups = 0;
195
+ let kept = 0;
196
+ let dropped = 0;
197
+ let sigFromCache = 0;
198
+ let sigVerified = 0;
199
+
200
+ // Track pubkeys of new builders added when applying deposits, mapped to their registry
201
+ // index. `state.builders` starts empty at the fork and this loop only ever appends, so the
202
+ // index is stable and a top-up can go straight to it instead of scanning.
203
+ const builderIndexByPubkey = new Map<string, BuilderIndex>();
171
204
 
172
205
  const pendingDeposits = ssz.gloas.PendingDeposits.defaultViewDU();
173
206
  const pendingDepositsLookup = PendingDepositsLookup.buildEmpty();
@@ -182,18 +215,15 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
182
215
  if (isValidatorKnown(state, validatorIndex)) {
183
216
  pendingDeposits.push(deposit);
184
217
  pendingDepositsLookup.add(depositValue, pubkeyHex);
218
+ kept++;
185
219
  continue;
186
220
  }
187
221
 
188
- if (builderPubkeys.has(pubkeyHex)) {
222
+ const builderIndex = builderIndexByPubkey.get(pubkeyHex);
223
+ if (builderIndex !== undefined) {
189
224
  // Top up an already-onboarded builder
190
- // TODO GLOAS: linear search; consider builder pubkey cache when we drop the upgrade-time set
191
- for (let j = 0; j < state.builders.length; j++) {
192
- if (toPubkeyHex(state.builders.getReadonly(j).pubkey) === pubkeyHex) {
193
- state.builders.get(j).balance += deposit.amount;
194
- break;
195
- }
196
- }
225
+ state.builders.get(builderIndex).balance += deposit.amount;
226
+ topups++;
197
227
  continue;
198
228
  }
199
229
 
@@ -203,6 +233,7 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
203
233
  if (!isBuilderWithdrawalCredential(deposit.withdrawalCredentials)) {
204
234
  pendingDeposits.push(deposit);
205
235
  pendingDepositsLookup.add(depositValue, pubkeyHex);
236
+ kept++;
206
237
  continue;
207
238
  }
208
239
  if (
@@ -210,6 +241,7 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
210
241
  ) {
211
242
  pendingDeposits.push(deposit);
212
243
  pendingDepositsLookup.add(depositValue, pubkeyHex);
244
+ kept++;
213
245
  continue;
214
246
  }
215
247
 
@@ -219,6 +251,11 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
219
251
  // The prepareNextSlot scheduler pre-verifies these signatures in the epochs before the fork
220
252
  // A cache miss falls back to verifying this one deposit — no worse than pre-cache.
221
253
  const cached = state.epochCtx.builderDepositSignatureCache.getSignatureValidity(depositValue);
254
+ if (cached === null) {
255
+ sigVerified++;
256
+ } else {
257
+ sigFromCache++;
258
+ }
222
259
  const isValid =
223
260
  cached ??
224
261
  isValidDepositSignature(
@@ -229,10 +266,11 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
229
266
  deposit.signature
230
267
  );
231
268
  if (!isValid) {
269
+ dropped++;
232
270
  continue;
233
271
  }
234
272
 
235
- addBuilderToRegistry(
273
+ appendBuilderToRegistry(
236
274
  state,
237
275
  deposit.pubkey,
238
276
  PAYLOAD_BUILDER_VERSION,
@@ -240,8 +278,21 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
240
278
  deposit.amount,
241
279
  deposit.slot
242
280
  );
243
- builderPubkeys.add(pubkeyHex);
281
+ // appendBuilderToRegistry() pushes, so the new builder is the last entry
282
+ builderIndexByPubkey.set(pubkeyHex, state.builders.length - 1);
283
+ onboarded++;
244
284
  }
245
285
 
246
286
  state.pendingDeposits = pendingDeposits;
287
+
288
+ timer?.();
289
+ if (metrics) {
290
+ metrics.onboardBuildersDeposits.set({outcome: "onboarded"}, onboarded);
291
+ metrics.onboardBuildersDeposits.set({outcome: "topup"}, topups);
292
+ metrics.onboardBuildersDeposits.set({outcome: "kept"}, kept);
293
+ metrics.onboardBuildersDeposits.set({outcome: "dropped"}, dropped);
294
+ const lookupChecks = pendingDepositsLookup.signatureChecks;
295
+ metrics.onboardBuildersSignatureChecks.set({source: "cache"}, sigFromCache + lookupChecks.fromCache);
296
+ metrics.onboardBuildersSignatureChecks.set({source: "verified"}, sigVerified + lookupChecks.verified);
297
+ }
247
298
  }