@lodestar/state-transition 1.39.1 → 1.40.0-dev.059f489b0f

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 (252) hide show
  1. package/lib/block/index.d.ts +1 -0
  2. package/lib/block/index.d.ts.map +1 -1
  3. package/lib/block/index.js +1 -0
  4. package/lib/block/index.js.map +1 -1
  5. package/lib/block/isValidIndexedAttestation.d.ts +4 -5
  6. package/lib/block/isValidIndexedAttestation.d.ts.map +1 -1
  7. package/lib/block/isValidIndexedAttestation.js +9 -10
  8. package/lib/block/isValidIndexedAttestation.js.map +1 -1
  9. package/lib/block/isValidIndexedPayloadAttestation.d.ts.map +1 -1
  10. package/lib/block/isValidIndexedPayloadAttestation.js +1 -1
  11. package/lib/block/isValidIndexedPayloadAttestation.js.map +1 -1
  12. package/lib/block/processAttestationPhase0.d.ts.map +1 -1
  13. package/lib/block/processAttestationPhase0.js +1 -1
  14. package/lib/block/processAttestationPhase0.js.map +1 -1
  15. package/lib/block/processAttestationsAltair.d.ts.map +1 -1
  16. package/lib/block/processAttestationsAltair.js +3 -4
  17. package/lib/block/processAttestationsAltair.js.map +1 -1
  18. package/lib/block/processAttesterSlashing.d.ts +3 -2
  19. package/lib/block/processAttesterSlashing.d.ts.map +1 -1
  20. package/lib/block/processAttesterSlashing.js +3 -3
  21. package/lib/block/processAttesterSlashing.js.map +1 -1
  22. package/lib/block/processBlockHeader.d.ts.map +1 -1
  23. package/lib/block/processBlockHeader.js +1 -2
  24. package/lib/block/processBlockHeader.js.map +1 -1
  25. package/lib/block/processBlsToExecutionChange.d.ts +3 -1
  26. package/lib/block/processBlsToExecutionChange.d.ts.map +1 -1
  27. package/lib/block/processBlsToExecutionChange.js +8 -13
  28. package/lib/block/processBlsToExecutionChange.js.map +1 -1
  29. package/lib/block/processConsolidationRequest.d.ts +1 -2
  30. package/lib/block/processConsolidationRequest.d.ts.map +1 -1
  31. package/lib/block/processConsolidationRequest.js +5 -4
  32. package/lib/block/processConsolidationRequest.js.map +1 -1
  33. package/lib/block/processDepositRequest.d.ts +8 -2
  34. package/lib/block/processDepositRequest.d.ts.map +1 -1
  35. package/lib/block/processDepositRequest.js +81 -8
  36. package/lib/block/processDepositRequest.js.map +1 -1
  37. package/lib/block/processExecutionPayload.d.ts.map +1 -1
  38. package/lib/block/processExecutionPayload.js +1 -2
  39. package/lib/block/processExecutionPayload.js.map +1 -1
  40. package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
  41. package/lib/block/processExecutionPayloadBid.js +17 -31
  42. package/lib/block/processExecutionPayloadBid.js.map +1 -1
  43. package/lib/block/processExecutionPayloadEnvelope.d.ts.map +1 -1
  44. package/lib/block/processExecutionPayloadEnvelope.js +27 -27
  45. package/lib/block/processExecutionPayloadEnvelope.js.map +1 -1
  46. package/lib/block/processOperations.js +2 -2
  47. package/lib/block/processOperations.js.map +1 -1
  48. package/lib/block/processPayloadAttestation.d.ts.map +1 -1
  49. package/lib/block/processPayloadAttestation.js +1 -1
  50. package/lib/block/processPayloadAttestation.js.map +1 -1
  51. package/lib/block/processProposerSlashing.d.ts +5 -2
  52. package/lib/block/processProposerSlashing.d.ts.map +1 -1
  53. package/lib/block/processProposerSlashing.js +8 -6
  54. package/lib/block/processProposerSlashing.js.map +1 -1
  55. package/lib/block/processSyncCommittee.d.ts +1 -2
  56. package/lib/block/processSyncCommittee.d.ts.map +1 -1
  57. package/lib/block/processSyncCommittee.js +6 -6
  58. package/lib/block/processSyncCommittee.js.map +1 -1
  59. package/lib/block/processVoluntaryExit.d.ts +1 -1
  60. package/lib/block/processVoluntaryExit.d.ts.map +1 -1
  61. package/lib/block/processVoluntaryExit.js +45 -3
  62. package/lib/block/processVoluntaryExit.js.map +1 -1
  63. package/lib/block/processWithdrawalRequest.js +1 -1
  64. package/lib/block/processWithdrawalRequest.js.map +1 -1
  65. package/lib/block/processWithdrawals.d.ts +1 -0
  66. package/lib/block/processWithdrawals.d.ts.map +1 -1
  67. package/lib/block/processWithdrawals.js +122 -68
  68. package/lib/block/processWithdrawals.js.map +1 -1
  69. package/lib/cache/epochCache.d.ts +8 -28
  70. package/lib/cache/epochCache.d.ts.map +1 -1
  71. package/lib/cache/epochCache.js +40 -180
  72. package/lib/cache/epochCache.js.map +1 -1
  73. package/lib/cache/epochTransitionCache.d.ts +5 -12
  74. package/lib/cache/epochTransitionCache.d.ts.map +1 -1
  75. package/lib/cache/epochTransitionCache.js +4 -14
  76. package/lib/cache/epochTransitionCache.js.map +1 -1
  77. package/lib/cache/stateCache.d.ts.map +1 -1
  78. package/lib/cache/stateCache.js +1 -2
  79. package/lib/cache/stateCache.js.map +1 -1
  80. package/lib/epoch/processBuilderPendingPayments.d.ts.map +1 -1
  81. package/lib/epoch/processBuilderPendingPayments.js +1 -4
  82. package/lib/epoch/processBuilderPendingPayments.js.map +1 -1
  83. package/lib/epoch/processPendingAttestations.d.ts.map +1 -1
  84. package/lib/epoch/processPendingAttestations.js +1 -1
  85. package/lib/epoch/processPendingAttestations.js.map +1 -1
  86. package/lib/epoch/processProposerLookahead.d.ts.map +1 -1
  87. package/lib/epoch/processProposerLookahead.js +3 -6
  88. package/lib/epoch/processProposerLookahead.js.map +1 -1
  89. package/lib/index.d.ts +1 -1
  90. package/lib/index.d.ts.map +1 -1
  91. package/lib/index.js +1 -1
  92. package/lib/index.js.map +1 -1
  93. package/lib/rewards/blockRewards.d.ts +2 -1
  94. package/lib/rewards/blockRewards.d.ts.map +1 -1
  95. package/lib/rewards/blockRewards.js +3 -2
  96. package/lib/rewards/blockRewards.js.map +1 -1
  97. package/lib/rewards/syncCommitteeRewards.d.ts.map +1 -1
  98. package/lib/rewards/syncCommitteeRewards.js +10 -11
  99. package/lib/rewards/syncCommitteeRewards.js.map +1 -1
  100. package/lib/signatureSets/attesterSlashings.d.ts +3 -4
  101. package/lib/signatureSets/attesterSlashings.d.ts.map +1 -1
  102. package/lib/signatureSets/attesterSlashings.js +6 -6
  103. package/lib/signatureSets/attesterSlashings.js.map +1 -1
  104. package/lib/signatureSets/blsToExecutionChange.d.ts +4 -5
  105. package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -1
  106. package/lib/signatureSets/blsToExecutionChange.js +2 -2
  107. package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
  108. package/lib/signatureSets/executionPayloadBid.d.ts +4 -0
  109. package/lib/signatureSets/executionPayloadBid.d.ts.map +1 -0
  110. package/lib/signatureSets/executionPayloadBid.js +8 -0
  111. package/lib/signatureSets/executionPayloadBid.js.map +1 -0
  112. package/lib/signatureSets/executionPayloadEnvelope.d.ts +4 -0
  113. package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -0
  114. package/lib/signatureSets/executionPayloadEnvelope.js +8 -0
  115. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -0
  116. package/lib/signatureSets/index.d.ts +3 -2
  117. package/lib/signatureSets/index.d.ts.map +1 -1
  118. package/lib/signatureSets/index.js +10 -8
  119. package/lib/signatureSets/index.js.map +1 -1
  120. package/lib/signatureSets/indexedAttestation.d.ts +3 -4
  121. package/lib/signatureSets/indexedAttestation.d.ts.map +1 -1
  122. package/lib/signatureSets/indexedAttestation.js +6 -6
  123. package/lib/signatureSets/indexedAttestation.js.map +1 -1
  124. package/lib/signatureSets/indexedPayloadAttestation.d.ts +5 -4
  125. package/lib/signatureSets/indexedPayloadAttestation.d.ts.map +1 -1
  126. package/lib/signatureSets/indexedPayloadAttestation.js +3 -3
  127. package/lib/signatureSets/indexedPayloadAttestation.js.map +1 -1
  128. package/lib/signatureSets/proposer.d.ts +3 -3
  129. package/lib/signatureSets/proposer.d.ts.map +1 -1
  130. package/lib/signatureSets/proposer.js +12 -12
  131. package/lib/signatureSets/proposer.js.map +1 -1
  132. package/lib/signatureSets/proposerSlashings.d.ts +2 -3
  133. package/lib/signatureSets/proposerSlashings.d.ts.map +1 -1
  134. package/lib/signatureSets/proposerSlashings.js +6 -6
  135. package/lib/signatureSets/proposerSlashings.js.map +1 -1
  136. package/lib/signatureSets/randao.d.ts +1 -1
  137. package/lib/signatureSets/randao.d.ts.map +1 -1
  138. package/lib/signatureSets/randao.js +4 -4
  139. package/lib/signatureSets/randao.js.map +1 -1
  140. package/lib/signatureSets/voluntaryExits.d.ts +2 -2
  141. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
  142. package/lib/signatureSets/voluntaryExits.js +6 -6
  143. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  144. package/lib/slot/index.d.ts.map +1 -1
  145. package/lib/slot/index.js +1 -1
  146. package/lib/slot/index.js.map +1 -1
  147. package/lib/types.d.ts +1 -1
  148. package/lib/types.d.ts.map +1 -1
  149. package/lib/util/electra.d.ts.map +1 -1
  150. package/lib/util/electra.js +1 -2
  151. package/lib/util/electra.js.map +1 -1
  152. package/lib/util/epochShuffling.d.ts +1 -34
  153. package/lib/util/epochShuffling.d.ts.map +1 -1
  154. package/lib/util/epochShuffling.js +1 -1
  155. package/lib/util/epochShuffling.js.map +1 -1
  156. package/lib/util/gloas.d.ts +46 -5
  157. package/lib/util/gloas.d.ts.map +1 -1
  158. package/lib/util/gloas.js +92 -6
  159. package/lib/util/gloas.js.map +1 -1
  160. package/lib/util/index.d.ts +2 -2
  161. package/lib/util/index.d.ts.map +1 -1
  162. package/lib/util/index.js +2 -2
  163. package/lib/util/index.js.map +1 -1
  164. package/lib/util/interop.js +1 -1
  165. package/lib/util/interop.js.map +1 -1
  166. package/lib/util/loadState/findModifiedInactivityScores.d.ts +1 -1
  167. package/lib/util/loadState/findModifiedInactivityScores.d.ts.map +1 -1
  168. package/lib/util/loadState/findModifiedInactivityScores.js +3 -2
  169. package/lib/util/loadState/findModifiedInactivityScores.js.map +1 -1
  170. package/lib/util/loadState/findModifiedValidators.d.ts +2 -2
  171. package/lib/util/loadState/findModifiedValidators.d.ts.map +1 -1
  172. package/lib/util/loadState/findModifiedValidators.js +4 -3
  173. package/lib/util/loadState/findModifiedValidators.js.map +1 -1
  174. package/lib/util/loadState/loadValidator.d.ts.map +1 -1
  175. package/lib/util/loadState/loadValidator.js +3 -2
  176. package/lib/util/loadState/loadValidator.js.map +1 -1
  177. package/lib/util/shuffling.d.ts +58 -0
  178. package/lib/util/shuffling.d.ts.map +1 -0
  179. package/lib/util/shuffling.js +175 -0
  180. package/lib/util/shuffling.js.map +1 -0
  181. package/lib/util/signatureSets.d.ts +38 -5
  182. package/lib/util/signatureSets.d.ts.map +1 -1
  183. package/lib/util/signatureSets.js +48 -6
  184. package/lib/util/signatureSets.js.map +1 -1
  185. package/lib/util/validator.d.ts +6 -1
  186. package/lib/util/validator.d.ts.map +1 -1
  187. package/lib/util/validator.js +26 -16
  188. package/lib/util/validator.js.map +1 -1
  189. package/package.json +8 -8
  190. package/src/block/index.ts +1 -0
  191. package/src/block/isValidIndexedAttestation.ts +18 -12
  192. package/src/block/isValidIndexedPayloadAttestation.ts +4 -1
  193. package/src/block/processAttestationPhase0.ts +2 -1
  194. package/src/block/processAttestationsAltair.ts +3 -10
  195. package/src/block/processAttesterSlashing.ts +16 -4
  196. package/src/block/processBlockHeader.ts +1 -2
  197. package/src/block/processBlsToExecutionChange.ts +14 -16
  198. package/src/block/processConsolidationRequest.ts +5 -5
  199. package/src/block/processDepositRequest.ts +101 -8
  200. package/src/block/processExecutionPayload.ts +1 -2
  201. package/src/block/processExecutionPayloadBid.ts +21 -44
  202. package/src/block/processExecutionPayloadEnvelope.ts +35 -32
  203. package/src/block/processOperations.ts +2 -2
  204. package/src/block/processPayloadAttestation.ts +1 -1
  205. package/src/block/processProposerSlashing.ts +22 -12
  206. package/src/block/processSyncCommittee.ts +4 -7
  207. package/src/block/processVoluntaryExit.ts +60 -5
  208. package/src/block/processWithdrawalRequest.ts +1 -1
  209. package/src/block/processWithdrawals.ts +169 -72
  210. package/src/cache/epochCache.ts +52 -214
  211. package/src/cache/epochTransitionCache.ts +9 -34
  212. package/src/cache/stateCache.ts +1 -2
  213. package/src/epoch/processBuilderPendingPayments.ts +1 -5
  214. package/src/epoch/processPendingAttestations.ts +1 -1
  215. package/src/epoch/processProposerLookahead.ts +3 -7
  216. package/src/index.ts +0 -2
  217. package/src/rewards/blockRewards.ts +6 -3
  218. package/src/rewards/syncCommitteeRewards.ts +10 -13
  219. package/src/signatureSets/attesterSlashings.ts +3 -7
  220. package/src/signatureSets/blsToExecutionChange.ts +5 -6
  221. package/src/signatureSets/executionPayloadBid.ts +14 -0
  222. package/src/signatureSets/executionPayloadEnvelope.ts +13 -0
  223. package/src/signatureSets/index.ts +8 -9
  224. package/src/signatureSets/indexedAttestation.ts +2 -7
  225. package/src/signatureSets/indexedPayloadAttestation.ts +9 -7
  226. package/src/signatureSets/proposer.ts +8 -12
  227. package/src/signatureSets/proposerSlashings.ts +4 -7
  228. package/src/signatureSets/randao.ts +4 -8
  229. package/src/signatureSets/voluntaryExits.ts +5 -10
  230. package/src/slot/index.ts +1 -1
  231. package/src/types.ts +1 -0
  232. package/src/util/electra.ts +1 -4
  233. package/src/util/epochShuffling.ts +2 -43
  234. package/src/util/gloas.ts +117 -11
  235. package/src/util/index.ts +2 -2
  236. package/src/util/interop.ts +1 -1
  237. package/src/util/loadState/findModifiedInactivityScores.ts +4 -2
  238. package/src/util/loadState/findModifiedValidators.ts +4 -3
  239. package/src/util/loadState/loadValidator.ts +3 -2
  240. package/src/util/shuffling.ts +234 -0
  241. package/src/util/signatureSets.ts +84 -8
  242. package/src/util/validator.ts +31 -16
  243. package/lib/util/calculateCommitteeAssignments.d.ts +0 -12
  244. package/lib/util/calculateCommitteeAssignments.d.ts.map +0 -1
  245. package/lib/util/calculateCommitteeAssignments.js +0 -26
  246. package/lib/util/calculateCommitteeAssignments.js.map +0 -1
  247. package/lib/util/shufflingDecisionRoot.d.ts +0 -20
  248. package/lib/util/shufflingDecisionRoot.d.ts.map +0 -1
  249. package/lib/util/shufflingDecisionRoot.js +0 -76
  250. package/lib/util/shufflingDecisionRoot.js.map +0 -1
  251. package/src/util/calculateCommitteeAssignments.ts +0 -43
  252. package/src/util/shufflingDecisionRoot.ts +0 -81
@@ -1,5 +1,6 @@
1
+ import {BeaconConfig} from "@lodestar/config";
1
2
  import {ForkSeq} from "@lodestar/params";
2
- import {AttesterSlashing} from "@lodestar/types";
3
+ import {AttesterSlashing, Slot} from "@lodestar/types";
3
4
  import {Index2PubkeyCache} from "../cache/pubkeyCache.js";
4
5
  import {CachedBeaconStateAllForks} from "../types.js";
5
6
  import {getAttesterSlashableIndices, isSlashableAttestationData, isSlashableValidator} from "../util/index.js";
@@ -19,7 +20,14 @@ export function processAttesterSlashing(
19
20
  verifySignatures = true
20
21
  ): void {
21
22
  const {epochCtx} = state;
22
- assertValidAttesterSlashing(epochCtx.index2pubkey, state, attesterSlashing, verifySignatures);
23
+ assertValidAttesterSlashing(
24
+ state.config,
25
+ epochCtx.index2pubkey,
26
+ state.slot,
27
+ state.validators.length,
28
+ attesterSlashing,
29
+ verifySignatures
30
+ );
23
31
 
24
32
  const intersectingIndices = getAttesterSlashableIndices(attesterSlashing);
25
33
 
@@ -39,8 +47,10 @@ export function processAttesterSlashing(
39
47
  }
40
48
 
41
49
  export function assertValidAttesterSlashing(
50
+ config: BeaconConfig,
42
51
  index2pubkey: Index2PubkeyCache,
43
- state: CachedBeaconStateAllForks,
52
+ stateSlot: Slot,
53
+ validatorsLen: number,
44
54
  attesterSlashing: AttesterSlashing,
45
55
  verifySignatures = true
46
56
  ): void {
@@ -55,7 +65,9 @@ export function assertValidAttesterSlashing(
55
65
  // be higher than the clock and the slashing would still be valid. Same applies to attestation data index, which
56
66
  // can be any arbitrary value. Must use bigint variants to hash correctly to all possible values
57
67
  for (const [i, attestation] of [attestation1, attestation2].entries()) {
58
- if (!isValidIndexedAttestationBigint(state.config, index2pubkey, state, attestation, verifySignatures)) {
68
+ if (
69
+ !isValidIndexedAttestationBigint(config, index2pubkey, stateSlot, validatorsLen, attestation, verifySignatures)
70
+ ) {
59
71
  throw new Error(`AttesterSlashing attestation${i} is invalid`);
60
72
  }
61
73
  }
@@ -1,6 +1,5 @@
1
- import {byteArrayEquals} from "@chainsafe/ssz";
2
1
  import {BeaconBlock, BlindedBeaconBlock, ssz} from "@lodestar/types";
3
- import {toRootHex} from "@lodestar/utils";
2
+ import {byteArrayEquals, toRootHex} from "@lodestar/utils";
4
3
  import {ZERO_HASH} from "../constants/index.js";
5
4
  import {CachedBeaconStateAllForks} from "../types.js";
6
5
  import {blindedOrFullBlockToHeader} from "../util/index.js";
@@ -1,8 +1,9 @@
1
1
  import {digest} from "@chainsafe/as-sha256";
2
- import {byteArrayEquals} from "@chainsafe/ssz";
2
+ import {BeaconConfig} from "@lodestar/config";
3
3
  import {BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX} from "@lodestar/params";
4
4
  import {capella} from "@lodestar/types";
5
- import {toHex} from "@lodestar/utils";
5
+ import {Validator} from "@lodestar/types/phase0";
6
+ import {byteArrayEquals, toHex} from "@lodestar/utils";
6
7
  import {verifyBlsToExecutionChangeSignature} from "../signatureSets/index.js";
7
8
  import {CachedBeaconStateCapella} from "../types.js";
8
9
 
@@ -12,12 +13,18 @@ export function processBlsToExecutionChange(
12
13
  ): void {
13
14
  const addressChange = signedBlsToExecutionChange.message;
14
15
 
15
- const validation = isValidBlsToExecutionChange(state, signedBlsToExecutionChange, true);
16
+ if (addressChange.validatorIndex >= state.validators.length) {
17
+ throw Error(
18
+ `withdrawalValidatorIndex ${addressChange.validatorIndex} >= state.validators len ${state.validators.length}`
19
+ );
20
+ }
21
+
22
+ const validator = state.validators.get(addressChange.validatorIndex);
23
+ const validation = isValidBlsToExecutionChange(state.config, validator, signedBlsToExecutionChange, true);
16
24
  if (!validation.valid) {
17
25
  throw validation.error;
18
26
  }
19
27
 
20
- const validator = state.validators.get(addressChange.validatorIndex);
21
28
  const newWithdrawalCredentials = new Uint8Array(32);
22
29
  newWithdrawalCredentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX;
23
30
  newWithdrawalCredentials.set(addressChange.toExecutionAddress, 12);
@@ -27,22 +34,13 @@ export function processBlsToExecutionChange(
27
34
  }
28
35
 
29
36
  export function isValidBlsToExecutionChange(
30
- state: CachedBeaconStateCapella,
37
+ config: BeaconConfig,
38
+ validator: Validator,
31
39
  signedBLSToExecutionChange: capella.SignedBLSToExecutionChange,
32
40
  verifySignature = true
33
41
  ): {valid: true} | {valid: false; error: Error} {
34
42
  const addressChange = signedBLSToExecutionChange.message;
35
43
 
36
- if (addressChange.validatorIndex >= state.validators.length) {
37
- return {
38
- valid: false,
39
- error: Error(
40
- `withdrawalValidatorIndex ${addressChange.validatorIndex} > state.validators len ${state.validators.length}`
41
- ),
42
- };
43
- }
44
-
45
- const validator = state.validators.getReadonly(addressChange.validatorIndex);
46
44
  const {withdrawalCredentials} = validator;
47
45
  if (withdrawalCredentials[0] !== BLS_WITHDRAWAL_PREFIX) {
48
46
  return {
@@ -65,7 +63,7 @@ export function isValidBlsToExecutionChange(
65
63
  };
66
64
  }
67
65
 
68
- if (verifySignature && !verifyBlsToExecutionChangeSignature(state, signedBLSToExecutionChange)) {
66
+ if (verifySignature && !verifyBlsToExecutionChangeSignature(config, signedBLSToExecutionChange)) {
69
67
  return {
70
68
  valid: false,
71
69
  error: Error(
@@ -1,5 +1,6 @@
1
- import {FAR_FUTURE_EPOCH, ForkSeq, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params";
1
+ import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params";
2
2
  import {electra, ssz} from "@lodestar/types";
3
+ import {byteArrayEquals} from "@lodestar/utils";
3
4
  import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
4
5
  import {hasEth1WithdrawalCredential} from "../util/capella.js";
5
6
  import {
@@ -13,7 +14,6 @@ import {getConsolidationChurnLimit, getPendingBalanceToWithdraw, isActiveValidat
13
14
 
14
15
  // TODO Electra: Clean up necessary as there is a lot of overlap with isValidSwitchToCompoundRequest
15
16
  export function processConsolidationRequest(
16
- fork: ForkSeq,
17
17
  state: CachedBeaconStateElectra | CachedBeaconStateGloas,
18
18
  consolidationRequest: electra.ConsolidationRequest
19
19
  ): void {
@@ -57,7 +57,7 @@ export function processConsolidationRequest(
57
57
 
58
58
  // Verify source withdrawal credentials
59
59
  const hasCorrectCredential = hasExecutionWithdrawalCredential(sourceValidator.withdrawalCredentials);
60
- const isCorrectSourceAddress = Buffer.compare(sourceWithdrawalAddress, sourceAddress) === 0;
60
+ const isCorrectSourceAddress = byteArrayEquals(sourceWithdrawalAddress, sourceAddress);
61
61
  if (!(hasCorrectCredential && isCorrectSourceAddress)) {
62
62
  return;
63
63
  }
@@ -83,7 +83,7 @@ export function processConsolidationRequest(
83
83
  }
84
84
 
85
85
  // Verify the source has no pending withdrawals in the queue
86
- if (getPendingBalanceToWithdraw(fork, state, sourceIndex) > 0) {
86
+ if (getPendingBalanceToWithdraw(state, sourceIndex) > 0) {
87
87
  return;
88
88
  }
89
89
 
@@ -125,7 +125,7 @@ function isValidSwitchToCompoundRequest(
125
125
  const sourceValidator = state.validators.getReadonly(sourceIndex);
126
126
  const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12);
127
127
  // Verify request has been authorized
128
- if (Buffer.compare(sourceWithdrawalAddress, sourceAddress) !== 0) {
128
+ if (!byteArrayEquals(sourceWithdrawalAddress, sourceAddress)) {
129
129
  return false;
130
130
  }
131
131
 
@@ -1,21 +1,114 @@
1
- import {UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
2
- import {electra, ssz} from "@lodestar/types";
1
+ import {FAR_FUTURE_EPOCH, ForkSeq, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
2
+ import {BLSPubkey, Bytes32, UintNum64, electra, ssz} from "@lodestar/types";
3
3
  import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
4
+ import {findBuilderIndexByPubkey, isBuilderWithdrawalCredential} from "../util/gloas.js";
5
+ import {computeEpochAtSlot, isValidatorKnown} from "../util/index.js";
6
+ import {isValidDepositSignature} from "./processDeposit.js";
7
+
8
+ /**
9
+ * Apply a deposit for a builder. Either increases balance for existing builder or adds new builder to registry.
10
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.1/specs/gloas/beacon-chain.md#new-apply_deposit_for_builder
11
+ */
12
+ export function applyDepositForBuilder(
13
+ state: CachedBeaconStateGloas,
14
+ pubkey: BLSPubkey,
15
+ withdrawalCredentials: Bytes32,
16
+ amount: UintNum64,
17
+ signature: Bytes32
18
+ ): void {
19
+ const builderIndex = findBuilderIndexByPubkey(state, pubkey);
20
+
21
+ if (builderIndex !== null) {
22
+ // Existing builder - increase balance
23
+ const builder = state.builders.get(builderIndex);
24
+ builder.balance += amount;
25
+ } else {
26
+ // New builder - verify signature and add to registry
27
+ if (isValidDepositSignature(state.config, pubkey, withdrawalCredentials, amount, signature)) {
28
+ addBuilderToRegistry(state, pubkey, withdrawalCredentials, amount);
29
+ }
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Add a new builder to the builders registry.
35
+ * Reuses slots from exited and fully withdrawn builders if available.
36
+ */
37
+ function addBuilderToRegistry(
38
+ state: CachedBeaconStateGloas,
39
+ pubkey: BLSPubkey,
40
+ withdrawalCredentials: Bytes32,
41
+ amount: UintNum64
42
+ ): void {
43
+ const currentEpoch = computeEpochAtSlot(state.slot);
44
+
45
+ // Try to find a reusable slot from an exited builder with zero balance
46
+ let builderIndex = state.builders.length;
47
+ for (let i = 0; i < state.builders.length; i++) {
48
+ const builder = state.builders.getReadonly(i);
49
+ if (builder.withdrawableEpoch <= currentEpoch && builder.balance === 0) {
50
+ builderIndex = i;
51
+ break;
52
+ }
53
+ }
54
+
55
+ // Create new builder
56
+ const newBuilder = ssz.gloas.Builder.toViewDU({
57
+ pubkey,
58
+ version: withdrawalCredentials[0],
59
+ executionAddress: withdrawalCredentials.subarray(12),
60
+ balance: amount,
61
+ depositEpoch: currentEpoch,
62
+ withdrawableEpoch: FAR_FUTURE_EPOCH,
63
+ });
64
+
65
+ if (builderIndex < state.builders.length) {
66
+ // Reuse existing slot
67
+ state.builders.set(builderIndex, newBuilder);
68
+ } else {
69
+ // Append to end
70
+ state.builders.push(newBuilder);
71
+ }
72
+ }
4
73
 
5
74
  export function processDepositRequest(
75
+ fork: ForkSeq,
6
76
  state: CachedBeaconStateElectra | CachedBeaconStateGloas,
7
77
  depositRequest: electra.DepositRequest
8
78
  ): void {
9
- if (state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) {
79
+ const {pubkey, withdrawalCredentials, amount, signature} = depositRequest;
80
+
81
+ // Check if this is a builder or validator deposit
82
+ if (fork >= ForkSeq.gloas) {
83
+ const stateGloas = state as CachedBeaconStateGloas;
84
+ const builderIndex = findBuilderIndexByPubkey(stateGloas, pubkey);
85
+ const validatorIndex = state.epochCtx.getValidatorIndex(pubkey);
86
+
87
+ // Regardless of the withdrawal credentials prefix, if a builder/validator
88
+ // already exists with this pubkey, apply the deposit to their balance
89
+ const isBuilder = builderIndex !== null;
90
+ const isValidator = isValidatorKnown(state, validatorIndex);
91
+ const isBuilderPrefix = isBuilderWithdrawalCredential(withdrawalCredentials);
92
+
93
+ // Route to builder if it's an existing builder OR has builder prefix and is not a validator
94
+ if (isBuilder || (isBuilderPrefix && !isValidator)) {
95
+ // Apply builder deposits immediately
96
+ applyDepositForBuilder(stateGloas, pubkey, withdrawalCredentials, amount, signature);
97
+ return;
98
+ }
99
+ }
100
+
101
+ // Only set deposit_requests_start_index in Electra fork, not Gloas
102
+ if (fork < ForkSeq.gloas && state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) {
10
103
  state.depositRequestsStartIndex = depositRequest.index;
11
104
  }
12
105
 
13
- // Create pending deposit
106
+ // Add validator deposits to the queue
14
107
  const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({
15
- pubkey: depositRequest.pubkey,
16
- withdrawalCredentials: depositRequest.withdrawalCredentials,
17
- amount: depositRequest.amount,
18
- signature: depositRequest.signature,
108
+ pubkey,
109
+ withdrawalCredentials,
110
+ amount,
111
+ signature,
19
112
  slot: state.slot,
20
113
  });
21
114
  state.pendingDeposits.push(pendingDeposit);
@@ -1,7 +1,6 @@
1
- import {byteArrayEquals} from "@chainsafe/ssz";
2
1
  import {ForkName, ForkSeq, isForkPostDeneb} from "@lodestar/params";
3
2
  import {BeaconBlockBody, BlindedBeaconBlockBody, deneb, isExecutionPayload} from "@lodestar/types";
4
- import {toHex, toRootHex} from "@lodestar/utils";
3
+ import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
5
4
  import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js";
6
5
  import {
7
6
  executionPayloadToPayloadHeader,
@@ -1,68 +1,47 @@
1
1
  import {PublicKey, Signature, verify} from "@chainsafe/blst";
2
- import {byteArrayEquals} from "@chainsafe/ssz";
3
- import {
4
- DOMAIN_BEACON_BUILDER,
5
- FAR_FUTURE_EPOCH,
6
- ForkPostGloas,
7
- MIN_ACTIVATION_BALANCE,
8
- SLOTS_PER_EPOCH,
9
- } from "@lodestar/params";
2
+ import {BUILDER_INDEX_SELF_BUILD, ForkPostGloas, SLOTS_PER_EPOCH} from "@lodestar/params";
10
3
  import {BeaconBlock, gloas, ssz} from "@lodestar/types";
11
- import {toHex, toRootHex} from "@lodestar/utils";
4
+ import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
12
5
  import {G2_POINT_AT_INFINITY} from "../constants/constants.ts";
6
+ import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
13
7
  import {CachedBeaconStateGloas} from "../types.ts";
14
- import {hasBuilderWithdrawalCredential} from "../util/gloas.ts";
15
- import {computeSigningRoot, getCurrentEpoch, getRandaoMix, isActiveValidator} from "../util/index.ts";
8
+ import {canBuilderCoverBid, isActiveBuilder} from "../util/gloas.ts";
9
+ import {getCurrentEpoch, getRandaoMix} from "../util/index.ts";
16
10
 
17
11
  export function processExecutionPayloadBid(state: CachedBeaconStateGloas, block: BeaconBlock<ForkPostGloas>): void {
18
12
  const signedBid = block.body.signedExecutionPayloadBid;
19
13
  const bid = signedBid.message;
20
14
  const {builderIndex, value: amount} = bid;
21
- const builder = state.validators.getReadonly(builderIndex);
22
15
 
23
16
  // For self-builds, amount must be zero regardless of withdrawal credential prefix
24
- if (builderIndex === block.proposerIndex) {
17
+ if (builderIndex === BUILDER_INDEX_SELF_BUILD) {
25
18
  if (amount !== 0) {
26
19
  throw Error(`Invalid execution payload bid: self-build with non-zero amount ${amount}`);
27
20
  }
28
21
  if (!byteArrayEquals(signedBid.signature, G2_POINT_AT_INFINITY)) {
29
22
  throw Error("Invalid execution payload bid: self-build with non-zero signature");
30
23
  }
31
- // Non-self builds require builder withdrawal credential
32
- } else {
33
- if (!hasBuilderWithdrawalCredential(builder.withdrawalCredentials)) {
34
- throw Error(`Invalid execution payload bid: builder ${builderIndex} does not have builder withdrawal credential`);
24
+ }
25
+ // Non-self builds require active builder with valid signature
26
+ else {
27
+ const builder = state.builders.getReadonly(builderIndex);
28
+
29
+ // Verify that the builder is active
30
+ if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
31
+ throw Error(`Invalid execution payload bid: builder ${builderIndex} is not active`);
32
+ }
33
+
34
+ // Verify that the builder has funds to cover the bid
35
+ if (!canBuilderCoverBid(state, builderIndex, amount)) {
36
+ throw Error(`Invalid execution payload bid: builder ${builderIndex} has insufficient balance`);
35
37
  }
36
38
 
39
+ // Verify that the bid signature is valid
37
40
  if (!verifyExecutionPayloadBidSignature(state, builder.pubkey, signedBid)) {
38
41
  throw Error(`Invalid execution payload bid: invalid signature for builder ${builderIndex}`);
39
42
  }
40
43
  }
41
44
 
42
- if (!isActiveValidator(builder, getCurrentEpoch(state))) {
43
- throw Error(`Invalid execution payload bid: builder ${builderIndex} is not active`);
44
- }
45
-
46
- if (builder.slashed) {
47
- throw Error(`Invalid execution payload bid: builder ${builderIndex} is slashed`);
48
- }
49
-
50
- const pendingPayments = state.builderPendingPayments
51
- .getAllReadonly()
52
- .filter((payment) => payment.withdrawal.builderIndex === builderIndex)
53
- .reduce((acc, payment) => acc + payment.withdrawal.amount, 0);
54
- const pendingWithdrawals = state.builderPendingWithdrawals
55
- .getAllReadonly()
56
- .filter((withdrawal) => withdrawal.builderIndex === builderIndex)
57
- .reduce((acc, withdrawal) => acc + withdrawal.amount, 0);
58
-
59
- if (
60
- amount !== 0 &&
61
- state.balances.get(builderIndex) < amount + pendingPayments + pendingWithdrawals + MIN_ACTIVATION_BALANCE
62
- ) {
63
- throw Error("Insufficient builder balance");
64
- }
65
-
66
45
  if (bid.slot !== block.slot) {
67
46
  throw Error(`Bid slot ${bid.slot} does not match block slot ${block.slot}`);
68
47
  }
@@ -91,7 +70,6 @@ export function processExecutionPayloadBid(state: CachedBeaconStateGloas, block:
91
70
  feeRecipient: bid.feeRecipient,
92
71
  amount,
93
72
  builderIndex,
94
- withdrawableEpoch: FAR_FUTURE_EPOCH,
95
73
  }),
96
74
  });
97
75
 
@@ -106,8 +84,7 @@ function verifyExecutionPayloadBidSignature(
106
84
  pubkey: Uint8Array,
107
85
  signedBid: gloas.SignedExecutionPayloadBid
108
86
  ): boolean {
109
- const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_BUILDER);
110
- const signingRoot = computeSigningRoot(ssz.gloas.ExecutionPayloadBid, signedBid.message, domain);
87
+ const signingRoot = getExecutionPayloadBidSigningRoot(state.config, state.slot, signedBid.message);
111
88
 
112
89
  try {
113
90
  const publicKey = PublicKey.fromBytes(pubkey);
@@ -1,10 +1,14 @@
1
1
  import {PublicKey, Signature, verify} from "@chainsafe/blst";
2
- import {byteArrayEquals} from "@chainsafe/ssz";
3
- import {DOMAIN_BEACON_BUILDER, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
2
+ import {
3
+ BUILDER_INDEX_SELF_BUILD,
4
+ DOMAIN_BEACON_BUILDER,
5
+ SLOTS_PER_EPOCH,
6
+ SLOTS_PER_HISTORICAL_ROOT,
7
+ } from "@lodestar/params";
4
8
  import {gloas, ssz} from "@lodestar/types";
5
- import {toHex, toRootHex} from "@lodestar/utils";
9
+ import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
6
10
  import {CachedBeaconStateGloas} from "../types.ts";
7
- import {computeExitEpochAndUpdateChurn, computeSigningRoot, computeTimeAtSlot} from "../util/index.ts";
11
+ import {computeSigningRoot, computeTimeAtSlot} from "../util/index.ts";
8
12
  import {processConsolidationRequest} from "./processConsolidationRequest.ts";
9
13
  import {processDepositRequest} from "./processDepositRequest.ts";
10
14
  import {processWithdrawalRequest} from "./processWithdrawalRequest.ts";
@@ -19,13 +23,8 @@ export function processExecutionPayloadEnvelope(
19
23
  const payload = envelope.payload;
20
24
  const fork = state.config.getForkSeq(envelope.slot);
21
25
 
22
- if (verify) {
23
- const builderIndex = envelope.builderIndex;
24
- const pubkey = state.validators.getReadonly(builderIndex).pubkey;
25
-
26
- if (!verifyExecutionPayloadEnvelopeSignature(state, pubkey, signedEnvelope)) {
27
- throw new Error("Payload Envelope has invalid signature");
28
- }
26
+ if (verify && !verifyExecutionPayloadEnvelopeSignature(state, signedEnvelope)) {
27
+ throw Error(`Execution payload envelope has invalid signature builderIndex=${envelope.builderIndex}`);
29
28
  }
30
29
 
31
30
  validateExecutionPayloadEnvelope(state, envelope);
@@ -33,7 +32,7 @@ export function processExecutionPayloadEnvelope(
33
32
  const requests = envelope.executionRequests;
34
33
 
35
34
  for (const deposit of requests.deposits) {
36
- processDepositRequest(state, deposit);
35
+ processDepositRequest(fork, state, deposit);
37
36
  }
38
37
 
39
38
  for (const withdrawal of requests.withdrawals) {
@@ -41,7 +40,7 @@ export function processExecutionPayloadEnvelope(
41
40
  }
42
41
 
43
42
  for (const consolidation of requests.consolidations) {
44
- processConsolidationRequest(fork, state, consolidation);
43
+ processConsolidationRequest(state, consolidation);
45
44
  }
46
45
 
47
46
  // Queue the builder payment
@@ -50,9 +49,6 @@ export function processExecutionPayloadEnvelope(
50
49
  const amount = payment.withdrawal.amount;
51
50
 
52
51
  if (amount > 0) {
53
- const exitQueueEpoch = computeExitEpochAndUpdateChurn(state, BigInt(amount));
54
-
55
- payment.withdrawal.withdrawableEpoch = exitQueueEpoch + state.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY;
56
52
  state.builderPendingWithdrawals.push(payment.withdrawal);
57
53
  }
58
54
 
@@ -75,6 +71,7 @@ function validateExecutionPayloadEnvelope(
75
71
  ): void {
76
72
  const payload = envelope.payload;
77
73
 
74
+ // Cache latest block header state root
78
75
  if (byteArrayEquals(state.latestBlockHeader.stateRoot, ssz.Root.defaultValue())) {
79
76
  const previousStateRoot = state.hashTreeRoot();
80
77
  state.latestBlockHeader.stateRoot = previousStateRoot;
@@ -87,20 +84,18 @@ function validateExecutionPayloadEnvelope(
87
84
  );
88
85
  }
89
86
 
90
- // Verify consistency with the beacon block
91
87
  if (envelope.slot !== state.slot) {
92
88
  throw new Error(`Slot mismatch between envelope and state envelope=${envelope.slot} state=${state.slot}`);
93
89
  }
94
90
 
95
- const committedBid = state.latestExecutionPayloadBid;
96
91
  // Verify consistency with the committed bid
92
+ const committedBid = state.latestExecutionPayloadBid;
97
93
  if (envelope.builderIndex !== committedBid.builderIndex) {
98
94
  throw new Error(
99
95
  `Builder index mismatch between envelope and committed bid envelope=${envelope.builderIndex} committedBid=${committedBid.builderIndex}`
100
96
  );
101
97
  }
102
98
 
103
- // Verify consistency with the committed bid
104
99
  const envelopeKzgRoot = ssz.deneb.BlobKzgCommitments.hashTreeRoot(envelope.blobKzgCommitments);
105
100
  if (!byteArrayEquals(committedBid.blobKzgCommitmentsRoot, envelopeKzgRoot)) {
106
101
  throw new Error(
@@ -108,11 +103,18 @@ function validateExecutionPayloadEnvelope(
108
103
  );
109
104
  }
110
105
 
111
- // Verify the withdrawals root
112
- const envelopeWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(envelope.payload.withdrawals);
113
- if (!byteArrayEquals(state.latestWithdrawalsRoot, envelopeWithdrawalsRoot)) {
106
+ if (!byteArrayEquals(committedBid.prevRandao, payload.prevRandao)) {
107
+ throw new Error(
108
+ `Prev randao mismatch between committed bid and payload committedBid=${toHex(committedBid.prevRandao)} payload=${toHex(payload.prevRandao)}`
109
+ );
110
+ }
111
+
112
+ // Verify consistency with expected withdrawals
113
+ const payloadWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(payload.withdrawals);
114
+ const expectedWithdrawalsRoot = state.payloadExpectedWithdrawals.hashTreeRoot();
115
+ if (!byteArrayEquals(payloadWithdrawalsRoot, expectedWithdrawalsRoot)) {
114
116
  throw new Error(
115
- `Withdrawals root mismatch between envelope and latest withdrawals root envelope=${toRootHex(envelopeWithdrawalsRoot)} latestWithdrawalRoot=${toRootHex(state.latestWithdrawalsRoot)}`
117
+ `Withdrawals mismatch between payload and expected withdrawals payload=${toRootHex(payloadWithdrawalsRoot)} expected=${toRootHex(expectedWithdrawalsRoot)}`
116
118
  );
117
119
  }
118
120
 
@@ -137,13 +139,6 @@ function validateExecutionPayloadEnvelope(
137
139
  );
138
140
  }
139
141
 
140
- // Verify prev_randao matches committed bid
141
- if (!byteArrayEquals(committedBid.prevRandao, payload.prevRandao)) {
142
- throw new Error(
143
- `Prev randao mismatch between committed bid and payload committedBid=${toHex(committedBid.prevRandao)} payload=${toHex(payload.prevRandao)}`
144
- );
145
- }
146
-
147
142
  // Verify timestamp
148
143
  if (payload.timestamp !== computeTimeAtSlot(state.config, state.slot, state.genesisTime)) {
149
144
  throw new Error(
@@ -164,14 +159,22 @@ function validateExecutionPayloadEnvelope(
164
159
 
165
160
  function verifyExecutionPayloadEnvelopeSignature(
166
161
  state: CachedBeaconStateGloas,
167
- pubkey: Uint8Array,
168
162
  signedEnvelope: gloas.SignedExecutionPayloadEnvelope
169
163
  ): boolean {
164
+ const builderIndex = signedEnvelope.message.builderIndex;
165
+
170
166
  const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_BUILDER);
171
167
  const signingRoot = computeSigningRoot(ssz.gloas.ExecutionPayloadEnvelope, signedEnvelope.message, domain);
172
168
 
173
169
  try {
174
- const publicKey = PublicKey.fromBytes(pubkey);
170
+ let publicKey: PublicKey;
171
+
172
+ if (builderIndex === BUILDER_INDEX_SELF_BUILD) {
173
+ const validatorIndex = state.latestBlockHeader.proposerIndex;
174
+ publicKey = state.epochCtx.index2pubkey[validatorIndex];
175
+ } else {
176
+ publicKey = PublicKey.fromBytes(state.builders.getReadonly(builderIndex).pubkey);
177
+ }
175
178
  const signature = Signature.fromBytes(signedEnvelope.signature, true);
176
179
 
177
180
  return verify(signingRoot, publicKey, signature);
@@ -75,7 +75,7 @@ export function processOperations(
75
75
  const bodyElectra = body as electra.BeaconBlockBody;
76
76
 
77
77
  for (const depositRequest of bodyElectra.executionRequests.deposits) {
78
- processDepositRequest(stateElectra, depositRequest);
78
+ processDepositRequest(fork, stateElectra, depositRequest);
79
79
  }
80
80
 
81
81
  for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) {
@@ -83,7 +83,7 @@ export function processOperations(
83
83
  }
84
84
 
85
85
  for (const elConsolidationRequest of bodyElectra.executionRequests.consolidations) {
86
- processConsolidationRequest(fork, stateElectra, elConsolidationRequest);
86
+ processConsolidationRequest(stateElectra, elConsolidationRequest);
87
87
  }
88
88
  }
89
89
 
@@ -1,5 +1,5 @@
1
- import {byteArrayEquals} from "@chainsafe/ssz";
2
1
  import {gloas} from "@lodestar/types";
2
+ import {byteArrayEquals} from "@lodestar/utils";
3
3
  import {CachedBeaconStateGloas} from "../types.ts";
4
4
  import {isValidIndexedPayloadAttestation} from "./isValidIndexedPayloadAttestation.ts";
5
5
 
@@ -1,5 +1,8 @@
1
+ import {BeaconConfig} from "@lodestar/config";
1
2
  import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
2
- import {phase0, ssz} from "@lodestar/types";
3
+ import {Slot, phase0, ssz} from "@lodestar/types";
4
+ import {Validator} from "@lodestar/types/phase0";
5
+ import {Index2PubkeyCache} from "../cache/pubkeyCache.js";
3
6
  import {getProposerSlashingSignatureSets} from "../signatureSets/index.js";
4
7
  import {CachedBeaconStateAllForks, CachedBeaconStateGloas} from "../types.js";
5
8
  import {computeEpochAtSlot, isSlashableValidator} from "../util/index.js";
@@ -18,7 +21,15 @@ export function processProposerSlashing(
18
21
  proposerSlashing: phase0.ProposerSlashing,
19
22
  verifySignatures = true
20
23
  ): void {
21
- assertValidProposerSlashing(state, proposerSlashing, verifySignatures);
24
+ const proposer = state.validators.getReadonly(proposerSlashing.signedHeader1.message.proposerIndex);
25
+ assertValidProposerSlashing(
26
+ state.config,
27
+ state.epochCtx.index2pubkey,
28
+ state.slot,
29
+ proposerSlashing,
30
+ proposer,
31
+ verifySignatures
32
+ );
22
33
 
23
34
  if (fork >= ForkSeq.gloas) {
24
35
  const slot = Number(proposerSlashing.signedHeader1.message.slot);
@@ -45,8 +56,11 @@ export function processProposerSlashing(
45
56
  }
46
57
 
47
58
  export function assertValidProposerSlashing(
48
- state: CachedBeaconStateAllForks,
59
+ config: BeaconConfig,
60
+ index2pubkey: Index2PubkeyCache,
61
+ stateSlot: Slot,
49
62
  proposerSlashing: phase0.ProposerSlashing,
63
+ proposer: Validator,
50
64
  verifySignatures = true
51
65
  ): void {
52
66
  const header1 = proposerSlashing.signedHeader1.message;
@@ -70,21 +84,17 @@ export function assertValidProposerSlashing(
70
84
  }
71
85
 
72
86
  // verify the proposer is slashable
73
- const proposer = state.validators.getReadonly(header1.proposerIndex);
74
- if (!isSlashableValidator(proposer, state.epochCtx.epoch)) {
87
+ // ideally we would get the proposer from state.validators using proposerIndex but that requires access to state
88
+ // instead of that we pass in the proposer directly from the consumer side
89
+ if (!isSlashableValidator(proposer, computeEpochAtSlot(stateSlot))) {
75
90
  throw new Error("ProposerSlashing proposer is not slashable");
76
91
  }
77
92
 
78
93
  // verify signatures
79
94
  if (verifySignatures) {
80
- const signatureSets = getProposerSlashingSignatureSets(
81
- state.config,
82
- state.epochCtx.index2pubkey,
83
- state.slot,
84
- proposerSlashing
85
- );
95
+ const signatureSets = getProposerSlashingSignatureSets(config, stateSlot, proposerSlashing);
86
96
  for (let i = 0; i < signatureSets.length; i++) {
87
- if (!verifySignatureSet(signatureSets[i])) {
97
+ if (!verifySignatureSet(signatureSets[i], index2pubkey)) {
88
98
  throw new Error(`ProposerSlashing header${i + 1} signature invalid`);
89
99
  }
90
100
  }