@lodestar/state-transition 1.47.0-dev.6325e4e1fe → 1.47.0-dev.6c2e8e6b0f

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 (165) 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/rewards/attestationsRewards.d.ts +1 -1
  56. package/lib/rewards/attestationsRewards.d.ts.map +1 -1
  57. package/lib/rewards/attestationsRewards.js.map +1 -1
  58. package/lib/rewards/syncCommitteeRewards.d.ts +1 -1
  59. package/lib/rewards/syncCommitteeRewards.d.ts.map +1 -1
  60. package/lib/rewards/syncCommitteeRewards.js +3 -1
  61. package/lib/rewards/syncCommitteeRewards.js.map +1 -1
  62. package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -1
  63. package/lib/signatureSets/blsToExecutionChange.js +1 -2
  64. package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
  65. package/lib/signatureSets/executionPayloadEnvelope.d.ts +2 -3
  66. package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
  67. package/lib/signatureSets/executionPayloadEnvelope.js +6 -7
  68. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
  69. package/lib/signatureSets/proposer.d.ts +1 -2
  70. package/lib/signatureSets/proposer.d.ts.map +1 -1
  71. package/lib/signatureSets/proposer.js +2 -2
  72. package/lib/signatureSets/proposer.js.map +1 -1
  73. package/lib/signatureSets/randao.d.ts +1 -2
  74. package/lib/signatureSets/randao.d.ts.map +1 -1
  75. package/lib/signatureSets/randao.js +2 -2
  76. package/lib/signatureSets/randao.js.map +1 -1
  77. package/lib/signatureSets/voluntaryExits.d.ts +1 -2
  78. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
  79. package/lib/signatureSets/voluntaryExits.js +3 -4
  80. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  81. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
  82. package/lib/slot/upgradeStateToGloas.js +27 -18
  83. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  84. package/lib/stateTransition.js +1 -1
  85. package/lib/stateTransition.js.map +1 -1
  86. package/lib/stateView/stateViewFactory.d.ts +1 -1
  87. package/lib/stateView/stateViewFactory.d.ts.map +1 -1
  88. package/lib/stateView/stateViewFactory.js +2 -13
  89. package/lib/stateView/stateViewFactory.js.map +1 -1
  90. package/lib/testUtils/index.d.ts +1 -0
  91. package/lib/testUtils/index.d.ts.map +1 -1
  92. package/lib/testUtils/index.js +1 -0
  93. package/lib/testUtils/index.js.map +1 -1
  94. package/lib/testUtils/interopPubkeyCache.d.ts +7 -0
  95. package/lib/testUtils/interopPubkeyCache.d.ts.map +1 -0
  96. package/lib/testUtils/interopPubkeyCache.js +92 -0
  97. package/lib/testUtils/interopPubkeyCache.js.map +1 -0
  98. package/lib/testUtils/state.d.ts.map +1 -1
  99. package/lib/testUtils/state.js +5 -5
  100. package/lib/testUtils/state.js.map +1 -1
  101. package/lib/testUtils/testFileCache.d.ts.map +1 -1
  102. package/lib/testUtils/testFileCache.js +3 -0
  103. package/lib/testUtils/testFileCache.js.map +1 -1
  104. package/lib/testUtils/util.d.ts +1 -1
  105. package/lib/testUtils/util.d.ts.map +1 -1
  106. package/lib/testUtils/util.js +27 -35
  107. package/lib/testUtils/util.js.map +1 -1
  108. package/lib/util/gloas.d.ts +6 -0
  109. package/lib/util/gloas.d.ts.map +1 -1
  110. package/lib/util/gloas.js +25 -11
  111. package/lib/util/gloas.js.map +1 -1
  112. package/lib/util/interop.d.ts +1 -1
  113. package/lib/util/interop.d.ts.map +1 -1
  114. package/lib/util/interop.js +1 -1
  115. package/lib/util/interop.js.map +1 -1
  116. package/lib/util/signatureSets.d.ts +5 -13
  117. package/lib/util/signatureSets.d.ts.map +1 -1
  118. package/lib/util/signatureSets.js +30 -39
  119. package/lib/util/signatureSets.js.map +1 -1
  120. package/lib/util/syncCommittee.js +1 -1
  121. package/lib/util/syncCommittee.js.map +1 -1
  122. package/package.json +11 -12
  123. package/src/block/isValidIndexedAttestation.ts +2 -8
  124. package/src/block/isValidIndexedPayloadAttestation.ts +1 -4
  125. package/src/block/processAttestationPhase0.ts +0 -1
  126. package/src/block/processAttestationsAltair.ts +2 -2
  127. package/src/block/processAttesterSlashing.ts +2 -13
  128. package/src/block/processDeposit.ts +35 -47
  129. package/src/block/processExecutionPayloadBid.ts +8 -6
  130. package/src/block/processProposerSlashing.ts +2 -11
  131. package/src/block/processRandao.ts +1 -1
  132. package/src/block/processSyncCommittee.ts +1 -1
  133. package/src/block/processVoluntaryExit.ts +1 -4
  134. package/src/cache/epochCache.ts +6 -7
  135. package/src/cache/stateCache.ts +1 -1
  136. package/src/cache/syncCommitteeCache.ts +3 -2
  137. package/src/epoch/processSyncCommitteeUpdates.ts +1 -1
  138. package/src/index.ts +1 -6
  139. package/src/lightClient/spec/store.ts +1 -1
  140. package/src/lightClient/spec/utils.ts +1 -1
  141. package/src/lightClient/spec/validateLightClientUpdate.ts +1 -1
  142. package/src/rewards/attestationsRewards.ts +1 -1
  143. package/src/rewards/syncCommitteeRewards.ts +4 -2
  144. package/src/signatureSets/blsToExecutionChange.ts +1 -2
  145. package/src/signatureSets/executionPayloadEnvelope.ts +14 -15
  146. package/src/signatureSets/proposer.ts +1 -3
  147. package/src/signatureSets/randao.ts +2 -3
  148. package/src/signatureSets/voluntaryExits.ts +2 -5
  149. package/src/slot/upgradeStateToGloas.ts +28 -21
  150. package/src/stateTransition.ts +1 -1
  151. package/src/stateView/stateViewFactory.ts +2 -14
  152. package/src/testUtils/index.ts +1 -0
  153. package/src/testUtils/interopPubkeyCache.ts +100 -0
  154. package/src/testUtils/state.ts +5 -11
  155. package/src/testUtils/testFileCache.ts +3 -0
  156. package/src/testUtils/util.ts +26 -38
  157. package/src/util/gloas.ts +40 -11
  158. package/src/util/interop.ts +1 -1
  159. package/src/util/signatureSets.ts +34 -51
  160. package/src/util/syncCommittee.ts +1 -1
  161. package/lib/cache/pubkeyCache.d.ts +0 -28
  162. package/lib/cache/pubkeyCache.d.ts.map +0 -1
  163. package/lib/cache/pubkeyCache.js +0 -49
  164. package/lib/cache/pubkeyCache.js.map +0 -1
  165. package/src/cache/pubkeyCache.ts +0 -74
@@ -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";
@@ -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,14 +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
18
  import type {BeaconStateTransitionMetrics} from "../metrics.js";
19
19
  import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
20
- import {addBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
20
+ import {appendBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
21
21
  import {isValidatorKnown} from "../util/index.js";
22
22
  import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
23
23
  import {progressiveListRootNode} from "../util/ssz.js";
@@ -73,11 +73,21 @@ export function upgradeStateToGloas(
73
73
  );
74
74
  stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
75
75
  stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
76
- stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
77
- stateGloasView.latestExecutionPayloadBid.gasLimit = BigInt(stateFulu.latestExecutionPayloadHeader.gasLimit);
78
- stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(
79
- ssz.gloas.ExecutionRequests.defaultValue()
80
- );
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;
81
91
  stateGloasView.nextWithdrawalIndex = stateGloasCloned.nextWithdrawalIndex;
82
92
  stateGloasView.nextWithdrawalValidatorIndex = stateGloasCloned.nextWithdrawalValidatorIndex;
83
93
  stateGloasView.historicalSummaries = stateGloasCloned.historicalSummaries;
@@ -187,9 +197,10 @@ function onboardBuildersFromPendingDeposits(
187
197
  let sigFromCache = 0;
188
198
  let sigVerified = 0;
189
199
 
190
- // Track pubkeys of new builders added when applying deposits. `state.builders` starts empty
191
- // at the fork, so every builder pubkey here is one added in an earlier iteration.
192
- const builderPubkeys = new Set<string>();
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>();
193
204
 
194
205
  const pendingDeposits = ssz.gloas.PendingDeposits.defaultViewDU();
195
206
  const pendingDepositsLookup = PendingDepositsLookup.buildEmpty();
@@ -208,15 +219,10 @@ function onboardBuildersFromPendingDeposits(
208
219
  continue;
209
220
  }
210
221
 
211
- if (builderPubkeys.has(pubkeyHex)) {
222
+ const builderIndex = builderIndexByPubkey.get(pubkeyHex);
223
+ if (builderIndex !== undefined) {
212
224
  // Top up an already-onboarded builder
213
- // TODO GLOAS: linear search; consider builder pubkey cache when we drop the upgrade-time set
214
- for (let j = 0; j < state.builders.length; j++) {
215
- if (toPubkeyHex(state.builders.getReadonly(j).pubkey) === pubkeyHex) {
216
- state.builders.get(j).balance += deposit.amount;
217
- break;
218
- }
219
- }
225
+ state.builders.get(builderIndex).balance += deposit.amount;
220
226
  topups++;
221
227
  continue;
222
228
  }
@@ -264,7 +270,7 @@ function onboardBuildersFromPendingDeposits(
264
270
  continue;
265
271
  }
266
272
 
267
- addBuilderToRegistry(
273
+ appendBuilderToRegistry(
268
274
  state,
269
275
  deposit.pubkey,
270
276
  PAYLOAD_BUILDER_VERSION,
@@ -272,7 +278,8 @@ function onboardBuildersFromPendingDeposits(
272
278
  deposit.amount,
273
279
  deposit.slot
274
280
  );
275
- builderPubkeys.add(pubkeyHex);
281
+ // appendBuilderToRegistry() pushes, so the new builder is the last entry
282
+ builderIndexByPubkey.set(pubkeyHex, state.builders.length - 1);
276
283
  onboarded++;
277
284
  }
278
285
 
@@ -113,7 +113,7 @@ export function stateTransition(
113
113
  postState = processSlotsWithTransientCache(postState, blockSlot, options, {metrics, validatorMonitor});
114
114
 
115
115
  // Verify proposer signature only
116
- if (verifyProposer && !verifyProposerSignature(postState.config, postState.epochCtx.pubkeyCache, signedBlock)) {
116
+ if (verifyProposer && !verifyProposerSignature(postState.config, signedBlock)) {
117
117
  throw new Error("Invalid block signature");
118
118
  }
119
119
 
@@ -1,5 +1,5 @@
1
+ import {type PubkeyCache, pubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
1
2
  import {BeaconConfig} from "@lodestar/config";
2
- import {PubkeyCache, createPubkeyCache} from "../cache/pubkeyCache.js";
3
3
  import {createCachedBeaconState} from "../cache/stateCache.js";
4
4
  import {BeaconStateAllForks} from "../cache/types.js";
5
5
  import {getStateTypeFromBytes} from "../util/sszBytes.js";
@@ -40,17 +40,6 @@ export function createBeaconStateView(opts: NodeJSOpts | NativeOpts): IBeaconSta
40
40
 
41
41
  // ---- createBeaconStateViewForHistoricalRegen (regen path) ----
42
42
 
43
- // Reused across all historical state regen calls in the worker thread
44
- const pubkeyCacheRegen = createPubkeyCache();
45
-
46
- function syncPubkeyCache(state: BeaconStateAllForks, pubkeyCache: PubkeyCache): void {
47
- const newCount = state.validators.length;
48
- for (let i = pubkeyCache.size; i < newCount; i++) {
49
- const pubkey = state.validators.getReadonly(i).pubkey;
50
- pubkeyCache.set(i, pubkey);
51
- }
52
- }
53
-
54
43
  type RegenNodeJSOpts = {
55
44
  useNative: false;
56
45
  config: BeaconConfig;
@@ -74,7 +63,6 @@ export function createBeaconStateViewForHistoricalRegen(opts: RegenNodeJSOpts |
74
63
  }
75
64
  const {config, stateBytes} = opts;
76
65
  const state = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes);
77
- syncPubkeyCache(state, pubkeyCacheRegen);
78
- const cachedState = createCachedBeaconState(state, {config, pubkeyCache: pubkeyCacheRegen}, {skipSyncPubkeys: true});
66
+ const cachedState = createCachedBeaconState(state, {config, pubkeyCache}, {skipSyncPubkeys: true});
79
67
  return new BeaconStateView(cachedState);
80
68
  }
@@ -1,5 +1,6 @@
1
1
  export * from "./cache.js";
2
2
  export * from "./interop.js";
3
+ export * from "./interopPubkeyCache.js";
3
4
  export * from "./params.js";
4
5
  export * from "./testFileCache.js";
5
6
  export * from "./util.js";
@@ -0,0 +1,100 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {pubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
4
+ import {interopSecretKey} from "../util/interop.js";
5
+ import {testCachePath} from "./cache.js";
6
+
7
+ /**
8
+ * This util persists generated keys as a PKIX snapshot in the local test-cache dir, so
9
+ * they are generated once per machine and reloaded for tests.
10
+ *
11
+ * The snapshot grows to satisfy larger requests. Smaller requests may load more entries
12
+ * than they need since cache contents do not define validator-registry membership.
13
+ */
14
+
15
+ /** Below this count, generating keys is faster than snapshot bookkeeping (~80ms) */
16
+ const MIN_PERSIST_SIZE = 1000;
17
+ const MAX_SNAPSHOT_CAPACITY = 0xffffffff;
18
+ const defaultSnapshotPath = path.join(testCachePath, "interop-pubkeys.pkix");
19
+
20
+ /** Sentinel pubkeys used to verify cache contents, memoized as they are re-checked often */
21
+ const interopPubkeyByIndex = new Map<number, Uint8Array>();
22
+
23
+ function interopPubkey(index: number): Uint8Array {
24
+ let pubkey = interopPubkeyByIndex.get(index);
25
+ if (!pubkey) {
26
+ pubkey = interopSecretKey(index).toPublicKey().toBytes();
27
+ interopPubkeyByIndex.set(index, pubkey);
28
+ }
29
+ return pubkey;
30
+ }
31
+
32
+ function isInteropKeyAt(index: number): boolean {
33
+ const pubkey = pubkeyCache.get(index);
34
+ return pubkey !== undefined && Buffer.compare(pubkey.toBytes(), interopPubkey(index)) === 0;
35
+ }
36
+
37
+ /**
38
+ * True if cache entries [0, count) are the index-matching interop pubkeys. Checking the
39
+ * two endpoints suffices: the native cache is append-only and never remaps an index, so
40
+ * replacing any entry in between would have required a reset() clearing index 0 too.
41
+ */
42
+ function hasInteropPrefix(count: number): boolean {
43
+ return pubkeyCache.size >= count && isInteropKeyAt(0) && isInteropKeyAt(count - 1);
44
+ }
45
+
46
+ function loadSnapshot(snapshotPath: string): void {
47
+ if (!fs.existsSync(snapshotPath)) return;
48
+
49
+ try {
50
+ pubkeyCache.load(snapshotPath, MAX_SNAPSHOT_CAPACITY);
51
+ } catch {
52
+ // Stale ABI, corrupt or torn file: drop it so future runs regenerate it
53
+ fs.rmSync(snapshotPath, {force: true});
54
+ }
55
+ }
56
+
57
+ function saveSnapshot(snapshotPath: string): void {
58
+ fs.mkdirSync(path.dirname(snapshotPath), {recursive: true});
59
+ // Write-then-rename so concurrent test processes never observe a partial file
60
+ const tmpPath = `${snapshotPath}.tmp-${process.pid}`;
61
+ try {
62
+ pubkeyCache.save(tmpPath);
63
+ fs.renameSync(tmpPath, snapshotPath);
64
+ } catch {
65
+ fs.rmSync(tmpPath, {force: true});
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Ensure the process-wide pubkey cache holds the interop pubkeys for indices [0, vc),
71
+ * loading persisted snapshots and generating as few keys as possible. No-op if the cache
72
+ * already holds them.
73
+ */
74
+ export function ensureInteropPubkeyCache(vc: number, snapshotPath = defaultSnapshotPath): void {
75
+ if (vc <= 0 || hasInteropPrefix(vc)) return;
76
+
77
+ // The cache is append-only, so extend a shorter interop prefix in place. Otherwise,
78
+ // replace unrelated contents with the persisted interop cache when available.
79
+ const size = pubkeyCache.size;
80
+ const sizeToExtend = size > 0 && size < vc && hasInteropPrefix(size) ? size : 0;
81
+ if (sizeToExtend === 0) {
82
+ pubkeyCache.reset();
83
+ loadSnapshot(snapshotPath);
84
+ }
85
+
86
+ let loadedSize = pubkeyCache.size;
87
+ if (loadedSize > 0 && !hasInteropPrefix(loadedSize)) {
88
+ pubkeyCache.reset();
89
+ loadedSize = 0;
90
+ }
91
+ if (loadedSize >= vc) return;
92
+
93
+ for (let i = loadedSize; i < vc; i++) {
94
+ pubkeyCache.append(i, interopSecretKey(i).toPublicKey().toBytes());
95
+ }
96
+
97
+ if (vc >= MIN_PERSIST_SIZE) {
98
+ saveSnapshot(snapshotPath);
99
+ }
100
+ }
@@ -1,3 +1,4 @@
1
+ import {pubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
1
2
  import {ChainForkConfig, createBeaconConfig} from "@lodestar/config";
2
3
  import {config, config as minimalConfig} from "@lodestar/config/default";
3
4
  import {
@@ -11,13 +12,7 @@ import {phase0, ssz} from "@lodestar/types";
11
12
  import {EpochCacheOpts} from "../cache/epochCache.js";
12
13
  import {BeaconStateCache} from "../cache/stateCache.js";
13
14
  import {ZERO_HASH} from "../constants/index.js";
14
- import {
15
- BeaconStateAllForks,
16
- BeaconStatePhase0,
17
- CachedBeaconStateAllForks,
18
- createCachedBeaconState,
19
- createPubkeyCache,
20
- } from "../index.js";
15
+ import {BeaconStateAllForks, BeaconStatePhase0, CachedBeaconStateAllForks, createCachedBeaconState} from "../index.js";
21
16
  import {newZeroedArray} from "../util/index.js";
22
17
 
23
18
  /**
@@ -86,10 +81,10 @@ export function generateCachedState(
86
81
  opts: TestBeaconState = {}
87
82
  ): CachedBeaconStateAllForks {
88
83
  const state = generateState(opts);
84
+ pubkeyCache.reset();
89
85
  return createCachedBeaconState(state, {
90
86
  config: createBeaconConfig(config, state.genesisValidatorsRoot),
91
- // This is a test state, there's no need to have a global shared cache of keys
92
- pubkeyCache: createPubkeyCache(),
87
+ pubkeyCache,
93
88
  });
94
89
  }
95
90
 
@@ -102,8 +97,7 @@ export function createCachedBeaconStateTest<T extends BeaconStateAllForks>(
102
97
  state,
103
98
  {
104
99
  config: createBeaconConfig(configCustom, state.genesisValidatorsRoot),
105
- // This is a test state, there's no need to have a global shared cache of keys
106
- pubkeyCache: createPubkeyCache(),
100
+ pubkeyCache,
107
101
  },
108
102
  opts
109
103
  );
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import {pubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
3
4
  import {getClient} from "@lodestar/api";
4
5
  import {ChainForkConfig, createChainForkConfig} from "@lodestar/config";
5
6
  import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
@@ -40,6 +41,7 @@ export async function getNetworkCachedState(
40
41
 
41
42
  if (fs.existsSync(filepath)) {
42
43
  const stateSsz = fs.readFileSync(filepath);
44
+ pubkeyCache.reset();
43
45
  return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config);
44
46
  }
45
47
 
@@ -57,6 +59,7 @@ export async function getNetworkCachedState(
57
59
  ]);
58
60
 
59
61
  fs.writeFileSync(filepath, stateSsz);
62
+ pubkeyCache.reset();
60
63
  return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config);
61
64
  }
62
65
 
@@ -1,4 +1,5 @@
1
- import {PublicKey, SecretKey} from "@chainsafe/blst";
1
+ import {PublicKey, SecretKey} from "@chainsafe/lodestar-z/blst";
2
+ import {pubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
2
3
  import {BitArray, fromHexString} from "@chainsafe/ssz";
3
4
  import {BeaconConfig, createBeaconConfig, createChainForkConfig} from "@lodestar/config";
4
5
  import {config} from "@lodestar/config/default";
@@ -22,7 +23,6 @@ import {
22
23
  computeCommitteeCount,
23
24
  computeEpochAtSlot,
24
25
  createCachedBeaconState,
25
- createPubkeyCache,
26
26
  newFilledArray,
27
27
  processSlots,
28
28
  } from "../index.js";
@@ -40,7 +40,7 @@ import {interopSecretKey} from "../util/interop.js";
40
40
  import {computeSigningRoot} from "../util/signingRoot.js";
41
41
  import {getNextSyncCommittee} from "../util/syncCommittee.js";
42
42
  import {getActiveValidatorIndices} from "../util/validator.js";
43
- import {interopPubkeysCached} from "./interop.js";
43
+ import {ensureInteropPubkeyCache} from "./interopPubkeyCache.js";
44
44
 
45
45
  let phase0State: BeaconStatePhase0 | null = null;
46
46
  let phase0CachedState23637: CachedBeaconStatePhase0 | null = null;
@@ -69,47 +69,45 @@ export const perfStateId = `${numValidators} vs - 7PWei`;
69
69
 
70
70
  /** Cache interop secret keys */
71
71
  const secretKeyByModIndex = new Map<number, SecretKey>();
72
+ const pubkeysByCount = new Map<number, Uint8Array[]>();
72
73
  const epoch = 23638;
73
74
  export const perfStateEpoch = epoch;
74
75
 
75
76
  export function getPubkeys(vc = numValidators) {
76
- const pubkeysMod = interopPubkeysCached(keypairsMod);
77
- const pubkeysModObj = pubkeysMod.map((pk) => PublicKey.fromBytes(pk));
78
- const pubkeys = Array.from({length: vc}, (_, i) => pubkeysMod[i % keypairsMod]);
77
+ ensureInteropPubkeyCache(vc);
78
+ let pubkeys = pubkeysByCount.get(vc);
79
+ if (!pubkeys) {
80
+ for (const [count, cached] of pubkeysByCount) {
81
+ if (count >= vc) {
82
+ pubkeys = cached.slice(0, vc);
83
+ break;
84
+ }
85
+ }
86
+ pubkeys ??= Array.from({length: vc}, (_, i) => pubkeyCache.getPubkeyBytesOrThrow(i));
87
+ pubkeysByCount.set(vc, pubkeys);
88
+ }
89
+ const pubkeysMod = pubkeys;
90
+ const pubkeysModObj = pubkeys.slice(0, keypairsMod).map((pk) => PublicKey.fromBytes(pk));
79
91
  return {pubkeysMod, pubkeysModObj, pubkeys};
80
92
  }
81
93
 
82
94
  /** Get secret key of a validatorIndex, if the pubkeys are generated with `getPubkeys()` */
83
95
  export function getSecretKeyFromIndex(validatorIndex: number): SecretKey {
84
- return interopSecretKey(validatorIndex % keypairsMod);
96
+ return interopSecretKey(validatorIndex);
85
97
  }
86
98
 
87
99
  /** Get secret key of a validatorIndex, if the pubkeys are generated with `getPubkeys()` */
88
100
  export function getSecretKeyFromIndexCached(validatorIndex: number): SecretKey {
89
- const keyIndex = validatorIndex % keypairsMod;
90
- let sk = secretKeyByModIndex.get(keyIndex);
101
+ let sk = secretKeyByModIndex.get(validatorIndex);
91
102
  if (!sk) {
92
- sk = interopSecretKey(keyIndex);
93
- secretKeyByModIndex.set(keyIndex, sk);
103
+ sk = interopSecretKey(validatorIndex);
104
+ secretKeyByModIndex.set(validatorIndex, sk);
94
105
  }
95
106
  return sk;
96
107
  }
97
108
 
98
- function getPubkeyCaches({pubkeysMod}: ReturnType<typeof getPubkeys>, vc = numValidators) {
99
- // Manually sync pubkeys to prevent doing BLS opts 110_000 times
100
- const pubkeyCache = createPubkeyCache();
101
- for (let i = 0; i < vc; i++) {
102
- const pubkey = pubkeysMod[i % keypairsMod];
103
- pubkeyCache.set(i, pubkey);
104
- }
105
-
106
- return {pubkeyCache};
107
- }
108
-
109
109
  export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean}): CachedBeaconStatePhase0 {
110
- // Generate only some publicKeys
111
- const {pubkeys, pubkeysMod, pubkeysModObj} = getPubkeys();
112
- const {pubkeyCache} = getPubkeyCaches({pubkeys, pubkeysMod, pubkeysModObj});
110
+ const {pubkeys} = getPubkeys();
113
111
 
114
112
  if (!phase0State) {
115
113
  const state = buildPerformanceStatePhase0();
@@ -218,8 +216,7 @@ export function generatePerfTestCachedStateAltair(opts?: {
218
216
  vc?: number;
219
217
  }): CachedBeaconStateAltair {
220
218
  const vc = opts?.vc ?? numValidators;
221
- const {pubkeys, pubkeysMod, pubkeysModObj} = getPubkeys(vc);
222
- const {pubkeyCache} = getPubkeyCaches({pubkeys, pubkeysMod, pubkeysModObj}, vc);
219
+ const {pubkeys} = getPubkeys(vc);
223
220
 
224
221
  const altairConfig = createChainForkConfig({ALTAIR_FORK_EPOCH: 0});
225
222
 
@@ -259,8 +256,7 @@ export function generatePerfTestCachedStateElectra(opts?: {
259
256
  vc?: number;
260
257
  }): CachedBeaconStateElectra {
261
258
  const vc = opts?.vc ?? numValidators;
262
- const {pubkeys, pubkeysMod, pubkeysModObj} = getPubkeys(vc);
263
- const {pubkeyCache} = getPubkeyCaches({pubkeys, pubkeysMod, pubkeysModObj}, vc);
259
+ const {pubkeys} = getPubkeys(vc);
264
260
 
265
261
  const electraConfig = createChainForkConfig({
266
262
  ALTAIR_FORK_EPOCH: 0,
@@ -495,15 +491,7 @@ export function generateTestCachedBeaconStateOnlyValidators({
495
491
  vc: number;
496
492
  slot: Slot;
497
493
  }): CachedBeaconStateAllForks {
498
- // Generate only some publicKeys
499
- const {pubkeys, pubkeysMod} = getPubkeys(vc);
500
-
501
- // Manually sync pubkeys to prevent doing BLS opts 110_000 times
502
- const pubkeyCache = createPubkeyCache();
503
- for (let i = 0; i < vc; i++) {
504
- const pubkey = pubkeysMod[i % keypairsMod];
505
- pubkeyCache.set(i, pubkey);
506
- }
494
+ const {pubkeys} = getPubkeys(vc);
507
495
 
508
496
  const state = ssz.phase0.BeaconState.defaultViewDU();
509
497
  state.slot = slot;