@lodestar/state-transition 1.48.0-dev.0dbea0de1b → 1.48.0-dev.224d7b3c98

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 (90) hide show
  1. package/lib/block/index.d.ts.map +1 -1
  2. package/lib/block/index.js +44 -13
  3. package/lib/block/index.js.map +1 -1
  4. package/lib/block/processExecutionPayloadBid.d.ts +2 -2
  5. package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
  6. package/lib/block/processExecutionPayloadBid.js +3 -2
  7. package/lib/block/processExecutionPayloadBid.js.map +1 -1
  8. package/lib/block/processOperations.d.ts.map +1 -1
  9. package/lib/block/processOperations.js +62 -33
  10. package/lib/block/processOperations.js.map +1 -1
  11. package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
  12. package/lib/block/processParentExecutionPayload.js +2 -16
  13. package/lib/block/processParentExecutionPayload.js.map +1 -1
  14. package/lib/block/processPayloadAttestation.d.ts +1 -1
  15. package/lib/block/processPayloadAttestation.d.ts.map +1 -1
  16. package/lib/block/processPayloadAttestation.js +2 -2
  17. package/lib/block/processPayloadAttestation.js.map +1 -1
  18. package/lib/block/types.d.ts +30 -0
  19. package/lib/block/types.d.ts.map +1 -1
  20. package/lib/block/types.js +32 -0
  21. package/lib/block/types.js.map +1 -1
  22. package/lib/epoch/processInactivityUpdates.d.ts.map +1 -1
  23. package/lib/epoch/processInactivityUpdates.js +7 -1
  24. package/lib/epoch/processInactivityUpdates.js.map +1 -1
  25. package/lib/epoch/processPtcWindow.d.ts.map +1 -1
  26. package/lib/epoch/processPtcWindow.js +12 -9
  27. package/lib/epoch/processPtcWindow.js.map +1 -1
  28. package/lib/index.d.ts +1 -1
  29. package/lib/index.d.ts.map +1 -1
  30. package/lib/index.js +1 -1
  31. package/lib/index.js.map +1 -1
  32. package/lib/lightClient/spec/index.d.ts +1 -1
  33. package/lib/lightClient/spec/index.d.ts.map +1 -1
  34. package/lib/lightClient/spec/index.js +1 -1
  35. package/lib/lightClient/spec/index.js.map +1 -1
  36. package/lib/lightClient/spec/utils.d.ts +2 -2
  37. package/lib/lightClient/spec/utils.d.ts.map +1 -1
  38. package/lib/lightClient/spec/utils.js +2 -2
  39. package/lib/lightClient/spec/utils.js.map +1 -1
  40. package/lib/metrics.d.ts +7 -1
  41. package/lib/metrics.d.ts.map +1 -1
  42. package/lib/metrics.js +12 -1
  43. package/lib/metrics.js.map +1 -1
  44. package/lib/rewards/blockRewards.d.ts.map +1 -1
  45. package/lib/rewards/blockRewards.js +1 -3
  46. package/lib/rewards/blockRewards.js.map +1 -1
  47. package/lib/signatureSets/index.d.ts.map +1 -1
  48. package/lib/signatureSets/index.js +8 -0
  49. package/lib/signatureSets/index.js.map +1 -1
  50. package/lib/slot/upgradeStateToGloas.js +1 -1
  51. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  52. package/lib/stateView/beaconStateView.d.ts +6 -1
  53. package/lib/stateView/beaconStateView.d.ts.map +1 -1
  54. package/lib/stateView/beaconStateView.js +12 -0
  55. package/lib/stateView/beaconStateView.js.map +1 -1
  56. package/lib/stateView/interface.d.ts +3 -1
  57. package/lib/stateView/interface.d.ts.map +1 -1
  58. package/lib/stateView/interface.js.map +1 -1
  59. package/lib/stateView/nativeBeaconStateView.d.ts +4 -1
  60. package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
  61. package/lib/stateView/nativeBeaconStateView.js +10 -0
  62. package/lib/stateView/nativeBeaconStateView.js.map +1 -1
  63. package/lib/util/gloas.d.ts.map +1 -1
  64. package/lib/util/gloas.js +1 -1
  65. package/lib/util/gloas.js.map +1 -1
  66. package/lib/util/seed.d.ts +1 -1
  67. package/lib/util/seed.d.ts.map +1 -1
  68. package/lib/util/seed.js +14 -11
  69. package/lib/util/seed.js.map +1 -1
  70. package/package.json +8 -8
  71. package/src/block/index.ts +53 -17
  72. package/src/block/processExecutionPayloadBid.ts +6 -5
  73. package/src/block/processOperations.ts +63 -45
  74. package/src/block/processParentExecutionPayload.ts +2 -27
  75. package/src/block/processPayloadAttestation.ts +3 -2
  76. package/src/block/types.ts +32 -0
  77. package/src/epoch/processInactivityUpdates.ts +8 -1
  78. package/src/epoch/processPtcWindow.ts +15 -8
  79. package/src/index.ts +1 -1
  80. package/src/lightClient/spec/index.ts +1 -1
  81. package/src/lightClient/spec/utils.ts +2 -2
  82. package/src/metrics.ts +13 -2
  83. package/src/rewards/blockRewards.ts +1 -3
  84. package/src/signatureSets/index.ts +17 -3
  85. package/src/slot/upgradeStateToGloas.ts +1 -1
  86. package/src/stateView/beaconStateView.ts +16 -0
  87. package/src/stateView/interface.ts +3 -0
  88. package/src/stateView/nativeBeaconStateView.ts +13 -1
  89. package/src/util/gloas.ts +1 -0
  90. package/src/util/seed.ts +25 -13
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/ChainSafe/lodestar/issues"
13
13
  },
14
- "version": "1.48.0-dev.0dbea0de1b",
14
+ "version": "1.48.0-dev.224d7b3c98",
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
@@ -68,16 +68,16 @@
68
68
  "@chainsafe/as-sha256": "^1.2.5",
69
69
  "@chainsafe/lodestar-z": "catalog:",
70
70
  "@chainsafe/persistent-merkle-tree": "^1.3.1",
71
- "@chainsafe/ssz": "^1.6.3",
71
+ "@chainsafe/ssz": "^1.8.0",
72
72
  "@chainsafe/swap-or-not-shuffle": "^1.2.1",
73
- "@lodestar/config": "^1.48.0-dev.0dbea0de1b",
74
- "@lodestar/params": "^1.48.0-dev.0dbea0de1b",
75
- "@lodestar/types": "^1.48.0-dev.0dbea0de1b",
76
- "@lodestar/utils": "^1.48.0-dev.0dbea0de1b",
73
+ "@lodestar/config": "^1.48.0-dev.224d7b3c98",
74
+ "@lodestar/params": "^1.48.0-dev.224d7b3c98",
75
+ "@lodestar/types": "^1.48.0-dev.224d7b3c98",
76
+ "@lodestar/utils": "^1.48.0-dev.224d7b3c98",
77
77
  "@vekexasia/bigint-buffer2": "^1.1.1"
78
78
  },
79
79
  "devDependencies": {
80
- "@lodestar/api": "^1.48.0-dev.0dbea0de1b"
80
+ "@lodestar/api": "^1.48.0-dev.224d7b3c98"
81
81
  },
82
82
  "keywords": [
83
83
  "ethereum",
@@ -85,5 +85,5 @@
85
85
  "beacon",
86
86
  "blockchain"
87
87
  ],
88
- "gitHead": "865965f50b18da8a70d0fe3f00c2c6b0f1058aba"
88
+ "gitHead": "3d2d869dc9e61e02a1e3b7d85d0b00b99e54703f"
89
89
  }
@@ -20,7 +20,7 @@ import {processPayloadAttestation} from "./processPayloadAttestation.js";
20
20
  import {processRandao} from "./processRandao.js";
21
21
  import {processSyncAggregate} from "./processSyncCommittee.js";
22
22
  import {processWithdrawals} from "./processWithdrawals.js";
23
- import {ProcessBlockOpts, ProposerRewardType} from "./types.js";
23
+ import {BlockProcessStep, ProcessBlockOpts, ProposerRewardType} from "./types.js";
24
24
 
25
25
  // Spec tests
26
26
  export {
@@ -53,24 +53,38 @@ export function processBlock(
53
53
  ): void {
54
54
  const {verifySignatures = true} = opts ?? {};
55
55
 
56
+ // Capture the parent block's slot before processBlockHeader overwrites latestBlockHeader
57
+ const parentSlot: Slot | null =
58
+ fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).latestBlockHeader.slot : null;
59
+
56
60
  // Apply the parent's deferred payload effects before everything else. Must run before
57
61
  // processBlockHeader and processExecutionPayloadBid so subsequent steps see the updated state.
58
62
  if (fork >= ForkSeq.gloas) {
63
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processParentExecutionPayload});
59
64
  processParentExecutionPayload(state as CachedBeaconStateGloas, block as BeaconBlock<ForkPostGloas>);
65
+ timer?.();
60
66
  }
61
67
 
62
- processBlockHeader(state, block);
68
+ {
69
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processBlockHeader});
70
+ processBlockHeader(state, block);
71
+ timer?.();
72
+ }
63
73
 
64
- if (fork >= ForkSeq.gloas) {
65
- // Parent payload's execution requests were already applied by processParentExecutionPayload above
66
- processWithdrawals(fork, state as CachedBeaconStateGloas);
67
- } else if (fork >= ForkSeq.capella) {
68
- const fullOrBlindedPayload = getFullOrBlindedPayload(block);
69
- processWithdrawals(
70
- fork,
71
- state as CachedBeaconStateCapella,
72
- fullOrBlindedPayload as capella.FullOrBlindedExecutionPayload
73
- );
74
+ if (fork >= ForkSeq.capella) {
75
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processWithdrawals});
76
+ if (fork >= ForkSeq.gloas) {
77
+ // Parent payload's execution requests were already applied by processParentExecutionPayload above
78
+ processWithdrawals(fork, state as CachedBeaconStateGloas);
79
+ } else {
80
+ const fullOrBlindedPayload = getFullOrBlindedPayload(block);
81
+ processWithdrawals(
82
+ fork,
83
+ state as CachedBeaconStateCapella,
84
+ fullOrBlindedPayload as capella.FullOrBlindedExecutionPayload
85
+ );
86
+ }
87
+ timer?.();
74
88
  }
75
89
 
76
90
  // The call to the process_execution_payload must happen before the call to the process_randao as the former depends
@@ -83,26 +97,48 @@ export function processBlock(
83
97
  fork >= ForkSeq.bellatrix &&
84
98
  isExecutionEnabled(state as CachedBeaconStateBellatrix, block)
85
99
  ) {
100
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processExecutionPayload});
86
101
  processExecutionPayload(fork, state as CachedBeaconStateBellatrix, block.body, externalData);
102
+ timer?.();
87
103
  }
88
104
 
89
- let parentSlot: Slot | null = null;
90
105
  if (fork >= ForkSeq.gloas) {
91
- parentSlot = processExecutionPayloadBid(
106
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processExecutionPayloadBid});
107
+ processExecutionPayloadBid(
92
108
  state as CachedBeaconStateGloas,
93
109
  (block as BeaconBlock<ForkPostGloas>).body.signedExecutionPayloadBid
94
110
  );
111
+ timer?.();
112
+ }
113
+
114
+ {
115
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processRandao});
116
+ processRandao(state, block, verifySignatures);
117
+ timer?.();
118
+ }
119
+
120
+ {
121
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processEth1Data});
122
+ processEth1Data(state, block.body.eth1Data);
123
+ timer?.();
124
+ }
125
+
126
+ {
127
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processOperations});
128
+ processOperations(fork, state, block.body, parentSlot, opts, metrics);
129
+ timer?.();
95
130
  }
96
131
 
97
- processRandao(state, block, verifySignatures);
98
- processEth1Data(state, block.body.eth1Data);
99
- processOperations(fork, state, block.body, parentSlot, opts, metrics);
100
132
  if (fork >= ForkSeq.altair) {
133
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processSyncAggregate});
101
134
  processSyncAggregate(state, block as altair.BeaconBlock, verifySignatures);
135
+ timer?.();
102
136
  }
103
137
 
104
138
  if (fork >= ForkSeq.deneb) {
139
+ const timer = metrics?.processBlockStepTime.startTimer({step: BlockProcessStep.processBlobKzgCommitments});
105
140
  processBlobKzgCommitments(externalData);
141
+ timer?.();
106
142
  // Only throw PreData so beacon can also sync/process blocks optimistically
107
143
  // and let forkChoice handle it
108
144
  if (externalData.dataAvailabilityStatus === DataAvailabilityStatus.PreData) {
@@ -5,7 +5,7 @@ import {
5
5
  PAYLOAD_BUILDER_VERSION,
6
6
  SLOTS_PER_EPOCH,
7
7
  } from "@lodestar/params";
8
- import {Slot, gloas, heze, ssz} from "@lodestar/types";
8
+ import {gloas, heze, ssz} from "@lodestar/types";
9
9
  import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
10
10
  import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
11
11
  import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
@@ -22,7 +22,7 @@ import {
22
22
  export function processExecutionPayloadBid(
23
23
  state: CachedBeaconStateGloas | CachedBeaconStateHeze,
24
24
  signedBid: gloas.SignedExecutionPayloadBid
25
- ): Slot {
25
+ ): void {
26
26
  const bid = signedBid.message;
27
27
  const {builderIndex, value: amount} = bid;
28
28
 
@@ -76,6 +76,10 @@ export function processExecutionPayloadBid(
76
76
  );
77
77
  }
78
78
 
79
+ if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
80
+ throw Error(`Block hash ${toRootHex(bid.blockHash)} of bid must not equal its parent block hash`);
81
+ }
82
+
79
83
  const parentBlockRoot = getBlockRootAtSlot(state, state.slot - 1);
80
84
  if (!byteArrayEquals(bid.parentBlockRoot, parentBlockRoot)) {
81
85
  throw Error(
@@ -110,14 +114,11 @@ export function processExecutionPayloadBid(
110
114
  state.builderPendingPayments.set(SLOTS_PER_EPOCH + (bid.slot % SLOTS_PER_EPOCH), pendingPaymentView);
111
115
  }
112
116
 
113
- const parentSlot = state.latestExecutionPayloadBid.slot;
114
117
  if (state.config.getForkSeq(state.slot) >= ForkSeq.heze) {
115
118
  state.latestExecutionPayloadBid = ssz.heze.ExecutionPayloadBid.toViewDU(bid as heze.ExecutionPayloadBid);
116
119
  } else {
117
120
  state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid);
118
121
  }
119
-
120
- return parentSlot;
121
122
  }
122
123
 
123
124
  function verifyExecutionPayloadBidSignature(
@@ -1,12 +1,4 @@
1
- import {
2
- ForkSeq,
3
- MAX_ATTESTATIONS_ELECTRA,
4
- MAX_ATTESTER_SLASHINGS_ELECTRA,
5
- MAX_BLS_TO_EXECUTION_CHANGES,
6
- MAX_PAYLOAD_ATTESTATIONS,
7
- MAX_PROPOSER_SLASHINGS,
8
- MAX_VOLUNTARY_EXITS,
9
- } from "@lodestar/params";
1
+ import {ForkSeq} from "@lodestar/params";
10
2
  import {BeaconBlockBody, Slot, capella, electra, gloas} from "@lodestar/types";
11
3
  import {BeaconStateTransitionMetrics} from "../metrics.js";
12
4
  import {
@@ -26,7 +18,7 @@ import {processPayloadAttestation} from "./processPayloadAttestation.js";
26
18
  import {processProposerSlashing} from "./processProposerSlashing.js";
27
19
  import {processVoluntaryExit} from "./processVoluntaryExit.js";
28
20
  import {processWithdrawalRequest} from "./processWithdrawalRequest.js";
29
- import {ProcessBlockOpts} from "./types.js";
21
+ import {ProcessBlockOpts, ProcessOperationsStep} from "./types.js";
30
22
 
31
23
  export {
32
24
  processProposerSlashing,
@@ -48,10 +40,6 @@ export function processOperations(
48
40
  opts: ProcessBlockOpts = {verifySignatures: true},
49
41
  metrics?: BeaconStateTransitionMetrics | null
50
42
  ): void {
51
- if (fork >= ForkSeq.gloas) {
52
- assertGloasOperationLimits(body as gloas.BeaconBlockBody);
53
- }
54
-
55
43
  // verify that outstanding deposits are processed up to the maximum number of deposits.
56
44
  // From Fulu the eth1 bridge deposit mechanism was removed, so blocks must not contain any deposits.
57
45
  const maxDeposits = fork >= ForkSeq.fulu ? 0 : getEth1DepositCount(state);
@@ -61,64 +49,94 @@ export function processOperations(
61
49
  );
62
50
  }
63
51
 
64
- for (const proposerSlashing of body.proposerSlashings) {
65
- processProposerSlashing(fork, state, proposerSlashing, opts.verifySignatures);
52
+ {
53
+ const timer = metrics?.processOperationsStepTime.startTimer({step: ProcessOperationsStep.processProposerSlashing});
54
+ for (const proposerSlashing of body.proposerSlashings) {
55
+ processProposerSlashing(fork, state, proposerSlashing, opts.verifySignatures);
56
+ }
57
+ timer?.();
66
58
  }
67
- for (const attesterSlashing of body.attesterSlashings) {
68
- processAttesterSlashing(fork, state, attesterSlashing, opts.verifySignatures);
59
+
60
+ {
61
+ const timer = metrics?.processOperationsStepTime.startTimer({step: ProcessOperationsStep.processAttesterSlashing});
62
+ for (const attesterSlashing of body.attesterSlashings) {
63
+ processAttesterSlashing(fork, state, attesterSlashing, opts.verifySignatures);
64
+ }
65
+ timer?.();
69
66
  }
70
67
 
71
- processAttestations(fork, state, body.attestations, parentSlot, opts.verifySignatures, metrics);
68
+ {
69
+ const timer = metrics?.processOperationsStepTime.startTimer({step: ProcessOperationsStep.processAttestations});
70
+ processAttestations(fork, state, body.attestations, parentSlot, opts.verifySignatures, metrics);
71
+ timer?.();
72
+ }
72
73
 
73
- for (const deposit of body.deposits) {
74
- processDeposit(fork, state, deposit);
74
+ {
75
+ const timer = metrics?.processOperationsStepTime.startTimer({step: ProcessOperationsStep.processDeposit});
76
+ for (const deposit of body.deposits) {
77
+ processDeposit(fork, state, deposit);
78
+ }
79
+ timer?.();
75
80
  }
76
81
 
77
- for (const voluntaryExit of body.voluntaryExits) {
78
- processVoluntaryExit(fork, state, voluntaryExit, opts.verifySignatures);
82
+ {
83
+ const timer = metrics?.processOperationsStepTime.startTimer({step: ProcessOperationsStep.processVoluntaryExit});
84
+ for (const voluntaryExit of body.voluntaryExits) {
85
+ processVoluntaryExit(fork, state, voluntaryExit, opts.verifySignatures);
86
+ }
87
+ timer?.();
79
88
  }
80
89
 
81
90
  if (fork >= ForkSeq.capella) {
91
+ const timer = metrics?.processOperationsStepTime.startTimer({
92
+ step: ProcessOperationsStep.processBlsToExecutionChange,
93
+ });
82
94
  for (const blsToExecutionChange of (body as capella.BeaconBlockBody).blsToExecutionChanges) {
83
95
  processBlsToExecutionChange(state as CachedBeaconStateCapella, blsToExecutionChange);
84
96
  }
97
+ timer?.();
85
98
  }
86
99
 
87
100
  if (fork >= ForkSeq.electra && fork < ForkSeq.gloas) {
88
101
  const stateElectra = state as CachedBeaconStateElectra;
89
102
  const bodyElectra = body as electra.BeaconBlockBody;
90
103
 
91
- for (const depositRequest of bodyElectra.executionRequests.deposits) {
92
- processDepositRequest(fork, stateElectra, depositRequest);
104
+ {
105
+ const timer = metrics?.processOperationsStepTime.startTimer({step: ProcessOperationsStep.processDepositRequest});
106
+ for (const depositRequest of bodyElectra.executionRequests.deposits) {
107
+ processDepositRequest(fork, stateElectra, depositRequest);
108
+ }
109
+ timer?.();
93
110
  }
94
111
 
95
- for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) {
96
- processWithdrawalRequest(fork, stateElectra, elWithdrawalRequest);
112
+ {
113
+ const timer = metrics?.processOperationsStepTime.startTimer({
114
+ step: ProcessOperationsStep.processWithdrawalRequest,
115
+ });
116
+ for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) {
117
+ processWithdrawalRequest(fork, stateElectra, elWithdrawalRequest);
118
+ }
119
+ timer?.();
97
120
  }
98
121
 
99
- for (const elConsolidationRequest of bodyElectra.executionRequests.consolidations) {
100
- processConsolidationRequest(stateElectra, elConsolidationRequest);
122
+ {
123
+ const timer = metrics?.processOperationsStepTime.startTimer({
124
+ step: ProcessOperationsStep.processConsolidationRequest,
125
+ });
126
+ for (const elConsolidationRequest of bodyElectra.executionRequests.consolidations) {
127
+ processConsolidationRequest(stateElectra, elConsolidationRequest);
128
+ }
129
+ timer?.();
101
130
  }
102
131
  }
103
132
 
104
133
  if (fork >= ForkSeq.gloas) {
134
+ const timer = metrics?.processOperationsStepTime.startTimer({
135
+ step: ProcessOperationsStep.processPayloadAttestation,
136
+ });
105
137
  for (const payloadAttestation of (body as gloas.BeaconBlockBody).payloadAttestations) {
106
- processPayloadAttestation(state as CachedBeaconStateGloas, payloadAttestation);
138
+ processPayloadAttestation(state as CachedBeaconStateGloas, payloadAttestation, opts.verifySignatures);
107
139
  }
108
- }
109
- }
110
-
111
- function assertGloasOperationLimits(body: gloas.BeaconBlockBody): void {
112
- assertMaxLength("proposerSlashings", body.proposerSlashings.length, MAX_PROPOSER_SLASHINGS);
113
- assertMaxLength("attesterSlashings", body.attesterSlashings.length, MAX_ATTESTER_SLASHINGS_ELECTRA);
114
- assertMaxLength("attestations", body.attestations.length, MAX_ATTESTATIONS_ELECTRA);
115
- assertMaxLength("voluntaryExits", body.voluntaryExits.length, MAX_VOLUNTARY_EXITS);
116
- assertMaxLength("blsToExecutionChanges", body.blsToExecutionChanges.length, MAX_BLS_TO_EXECUTION_CHANGES);
117
- assertMaxLength("payloadAttestations", body.payloadAttestations.length, MAX_PAYLOAD_ATTESTATIONS);
118
- }
119
-
120
- function assertMaxLength(name: string, length: number, limit: number): void {
121
- if (length > limit) {
122
- throw new Error(`Block contains too many ${name}: count=${length} limit=${limit}`);
140
+ timer?.();
123
141
  }
124
142
  }
@@ -1,12 +1,4 @@
1
- import {
2
- ForkPostGloas,
3
- MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
4
- MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
5
- MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
6
- MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
7
- SLOTS_PER_EPOCH,
8
- SLOTS_PER_HISTORICAL_ROOT,
9
- } from "@lodestar/params";
1
+ import {ForkPostGloas, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
10
2
  import {BeaconBlock, gloas, ssz} from "@lodestar/types";
11
3
  import {byteArrayEquals, toRootHex} from "@lodestar/utils";
12
4
  import {CachedBeaconStateGloas} from "../types.js";
@@ -55,11 +47,9 @@ export function processParentExecutionPayload(state: CachedBeaconStateGloas, blo
55
47
  * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/beacon-chain.md#new-apply_parent_execution_payload
56
48
  */
57
49
  export function applyParentExecutionPayload(state: CachedBeaconStateGloas, requests: gloas.ExecutionRequests): void {
58
- assertExecutionRequestsWithinLimits(requests);
59
-
60
50
  const fork = state.config.getForkSeq(state.slot);
61
51
  const parentBid = state.latestExecutionPayloadBid;
62
- const parentSlot = parentBid.slot;
52
+ const parentSlot = state.latestBlockHeader.slot;
63
53
  const parentEpoch = computeEpochAtSlot(parentSlot);
64
54
  const currentEpoch = computeEpochAtSlot(state.slot);
65
55
 
@@ -126,21 +116,6 @@ function settleBuilderPayment(state: CachedBeaconStateGloas, paymentIndex: numbe
126
116
  state.builderPendingPayments.set(paymentIndex, ssz.gloas.BuilderPendingPayment.defaultViewDU());
127
117
  }
128
118
 
129
- function assertExecutionRequestsWithinLimits(requests: gloas.ExecutionRequests): void {
130
- assertMaxLength("withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD);
131
- assertMaxLength("consolidations", requests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD);
132
- // New in GLOAS:EIP8282
133
- assertMaxLength("builderDeposits", requests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD);
134
- // New in GLOAS:EIP8282
135
- assertMaxLength("builderExits", requests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD);
136
- }
137
-
138
- function assertMaxLength(name: string, length: number, limit: number): void {
139
- if (length > limit) {
140
- throw new Error(`Too many parent execution request ${name} count=${length} limit=${limit}`);
141
- }
142
- }
143
-
144
119
  function assertEmptyExecutionRequests(requests: gloas.ExecutionRequests): void {
145
120
  if (
146
121
  requests.deposits.length !== 0 ||
@@ -5,7 +5,8 @@ import {isValidIndexedPayloadAttestation} from "./isValidIndexedPayloadAttestati
5
5
 
6
6
  export function processPayloadAttestation(
7
7
  state: CachedBeaconStateGloas,
8
- payloadAttestation: gloas.PayloadAttestation
8
+ payloadAttestation: gloas.PayloadAttestation,
9
+ verifySignature = true
9
10
  ): void {
10
11
  const data = payloadAttestation.data;
11
12
 
@@ -19,7 +20,7 @@ export function processPayloadAttestation(
19
20
 
20
21
  const indexedPayloadAttestation = state.epochCtx.getIndexedPayloadAttestation(data.slot, payloadAttestation);
21
22
 
22
- if (!isValidIndexedPayloadAttestation(state, indexedPayloadAttestation, true)) {
23
+ if (!isValidIndexedPayloadAttestation(state, indexedPayloadAttestation, verifySignature)) {
23
24
  throw Error("Invalid payload attestation");
24
25
  }
25
26
  }
@@ -7,3 +7,35 @@ export enum ProposerRewardType {
7
7
  syncAggregate = "sync_aggregate",
8
8
  slashing = "slashing",
9
9
  }
10
+
11
+ /**
12
+ * Steps of `processBlock()` tracked in metrics
13
+ */
14
+ export enum BlockProcessStep {
15
+ processParentExecutionPayload = "processParentExecutionPayload",
16
+ processBlockHeader = "processBlockHeader",
17
+ processWithdrawals = "processWithdrawals",
18
+ processExecutionPayload = "processExecutionPayload",
19
+ processExecutionPayloadBid = "processExecutionPayloadBid",
20
+ processRandao = "processRandao",
21
+ processEth1Data = "processEth1Data",
22
+ processOperations = "processOperations",
23
+ processSyncAggregate = "processSyncAggregate",
24
+ processBlobKzgCommitments = "processBlobKzgCommitments",
25
+ }
26
+
27
+ /**
28
+ * Steps of `processOperations()` tracked in metrics
29
+ */
30
+ export enum ProcessOperationsStep {
31
+ processProposerSlashing = "processProposerSlashing",
32
+ processAttesterSlashing = "processAttesterSlashing",
33
+ processAttestations = "processAttestations",
34
+ processDeposit = "processDeposit",
35
+ processVoluntaryExit = "processVoluntaryExit",
36
+ processBlsToExecutionChange = "processBlsToExecutionChange",
37
+ processDepositRequest = "processDepositRequest",
38
+ processWithdrawalRequest = "processWithdrawalRequest",
39
+ processConsolidationRequest = "processConsolidationRequest",
40
+ processPayloadAttestation = "processPayloadAttestation",
41
+ }
@@ -37,6 +37,7 @@ export function processInactivityUpdates(state: CachedBeaconStateAltair, cache:
37
37
 
38
38
  inactivityScoresArr.length = state.validators.length;
39
39
  inactivityScores.getAll(inactivityScoresArr);
40
+ let shouldSetInactivityScores = false;
40
41
 
41
42
  for (let i = 0; i < flags.length; i++) {
42
43
  const flag = flags[i];
@@ -53,8 +54,14 @@ export function processInactivityUpdates(state: CachedBeaconStateAltair, cache:
53
54
  inactivityScore -= Math.min(INACTIVITY_SCORE_RECOVERY_RATE, inactivityScore);
54
55
  }
55
56
  if (inactivityScore !== prevInactivityScore) {
56
- inactivityScores.set(i, inactivityScore);
57
+ inactivityScoresArr[i] = inactivityScore;
58
+ shouldSetInactivityScores = true;
57
59
  }
58
60
  }
59
61
  }
62
+
63
+ if (shouldSetInactivityScores) {
64
+ // Rebuilding the full view is slightly slower than individual sets only when very few scores change.
65
+ state.inactivityScores = state.type.fields.inactivityScores.toViewDU(inactivityScoresArr);
66
+ }
60
67
  }
@@ -1,4 +1,4 @@
1
- import {MIN_SEED_LOOKAHEAD} from "@lodestar/params";
1
+ import {MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
2
2
  import {ssz} from "@lodestar/types";
3
3
  import {CachedBeaconStateGloas, EpochTransitionCache} from "../types.js";
4
4
  import {computeEpochShuffling} from "../util/epochShuffling.js";
@@ -22,17 +22,24 @@ export function processPtcWindow(state: CachedBeaconStateGloas, cache: EpochTran
22
22
  state,
23
23
  nextEpoch,
24
24
  nextEpochShuffling.committees,
25
+ nextEpochShuffling.shuffling,
25
26
  state.epochCtx.effectiveBalanceIncrements
26
27
  );
27
28
 
28
29
  // Stash for finalProcessEpoch to shift into epoch cache
29
30
  cache.nextEpochPayloadTimelinessCommittees = newNextPayloadTimelinessCommittees;
30
31
 
31
- // Write shifted window to state: current(N) + next(N+1) + newlyComputed(N+2)
32
- // From the perspective of upcoming epoch N+1, this is previous + current + next
33
- state.ptcWindow = ssz.gloas.PtcWindow.toViewDU([
34
- ...state.epochCtx.payloadTimelinessCommittees,
35
- ...state.epochCtx.nextPayloadTimelinessCommittees,
36
- ...newNextPayloadTimelinessCommittees,
37
- ]);
32
+ // Shift the current and next epochs forward by reusing their SSZ subtrees and cached hashes.
33
+ // Only the newly computed epoch needs new subtrees.
34
+ const ptcWindow = state.ptcWindow;
35
+ const retainedLength = ptcWindow.length - SLOTS_PER_EPOCH;
36
+ for (let i = 0; i < retainedLength; i++) {
37
+ ptcWindow.set(i, ptcWindow.getReadonly(i + SLOTS_PER_EPOCH));
38
+ }
39
+ for (let i = 0; i < SLOTS_PER_EPOCH; i++) {
40
+ ptcWindow.set(
41
+ retainedLength + i,
42
+ ssz.gloas.PayloadTimelinessCommittee.toViewDU(newNextPayloadTimelinessCommittees[i])
43
+ );
44
+ }
38
45
  }
package/src/index.ts CHANGED
@@ -13,7 +13,7 @@ export {
13
13
  } from "./block/processVoluntaryExit.js";
14
14
  // Withdrawals for new blocks
15
15
  export {getExpectedWithdrawals} from "./block/processWithdrawals.js";
16
- export {ProposerRewardType} from "./block/types.js";
16
+ export {BlockProcessStep, ProcessOperationsStep, ProposerRewardType} from "./block/types.js";
17
17
  export {
18
18
  type EffectiveBalanceIncrements,
19
19
  getEffectiveBalanceIncrementsWithLen,
@@ -32,7 +32,7 @@ export {
32
32
  type SyncCommitteeFast,
33
33
  } from "./store.js";
34
34
  export {
35
- getLcExecutionRoot,
35
+ getLightClientExecutionRoot,
36
36
  getSafetyThreshold,
37
37
  isFinalityUpdate,
38
38
  isSyncCommitteeUpdate,
@@ -207,9 +207,9 @@ function getGindexIndex(gindex: number): number {
207
207
  * Gloas headers removed `execution` so Pre-Gloas headers upgraded to the Gloas format
208
208
  * require reconstruction of the original execution payload header root.
209
209
  *
210
- * Spec: https://github.com/ethereum/consensus-specs/blob/e762dd6e2c45ee05648b5787e7d261279aec226a/specs/gloas/light-client/sync-protocol.md#modified-get_lc_execution_root
210
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/light-client/sync-protocol.md#modified-get_lc_execution_root
211
211
  */
212
- export function getLcExecutionRoot(config: ChainForkConfig, header: LightClientHeader): Uint8Array {
212
+ export function getLightClientExecutionRoot(config: ChainForkConfig, header: LightClientHeader): Uint8Array {
213
213
  const epoch = computeEpochAtSlot(header.beacon.slot);
214
214
 
215
215
  if (!isGloasLightClientHeader(header)) {
package/src/metrics.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import {ForkName} from "@lodestar/params";
2
2
  import {MetricsRegister} from "@lodestar/utils";
3
- import {ProposerRewardType} from "./block/types.js";
3
+ import {BlockProcessStep, ProcessOperationsStep, ProposerRewardType} from "./block/types.js";
4
4
  import {EpochTransitionStep} from "./epoch/index.js";
5
5
  import {StateCloneSource, StateHashTreeRootSource} from "./stateTransition.js";
6
6
  import {CachedBeaconStateAllForks} from "./types.js";
@@ -57,10 +57,21 @@ export function getMetrics(register: MetricsRegister) {
57
57
  processBlockTime: register.histogram({
58
58
  name: "lodestar_stfn_process_block_seconds",
59
59
  help: "Time to process a single block in seconds",
60
- // TODO: Add metrics for each step
61
60
  // Block processing can take 5-40ms, 100ms max
62
61
  buckets: [0.005, 0.01, 0.02, 0.05, 0.1, 1],
63
62
  }),
63
+ processBlockStepTime: register.histogram<{step: BlockProcessStep}>({
64
+ name: "lodestar_stfn_process_block_step_seconds",
65
+ help: "Time to call each step of process block in seconds",
66
+ labelNames: ["step"],
67
+ buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1],
68
+ }),
69
+ processOperationsStepTime: register.histogram<{step: ProcessOperationsStep}>({
70
+ name: "lodestar_stfn_process_operations_step_seconds",
71
+ help: "Time to call each step of process operations in seconds",
72
+ labelNames: ["step"],
73
+ buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1],
74
+ }),
64
75
  processBlockCommitTime: register.histogram({
65
76
  name: "lodestar_stfn_process_block_commit_seconds",
66
77
  help: "Time to call commit after process a single block in seconds",
@@ -42,9 +42,7 @@ export async function computeBlockRewards(
42
42
  let syncAggregateReward = cachedSyncAggregateReward;
43
43
 
44
44
  if (blockAttestationReward === 0) {
45
- const parentSlot = isForkPostGloas(fork)
46
- ? (preState as CachedBeaconStateGloas).latestExecutionPayloadBid.slot
47
- : null;
45
+ const parentSlot = isForkPostGloas(fork) ? (preState as CachedBeaconStateGloas).latestBlockHeader.slot : null;
48
46
  blockAttestationReward =
49
47
  fork === ForkName.phase0
50
48
  ? computeBlockAttestationRewardPhase0(block as phase0.BeaconBlock, preState as CachedBeaconStatePhase0)
@@ -1,13 +1,14 @@
1
1
  import {BeaconConfig} from "@lodestar/config";
2
2
  import {ForkSeq} from "@lodestar/params";
3
- import {IndexedAttestation, SignedBeaconBlock, altair, capella} from "@lodestar/types";
3
+ import {IndexedAttestation, SignedBeaconBlock, altair, capella, gloas} from "@lodestar/types";
4
4
  import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js";
5
5
  import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js";
6
- import {IBeaconStateView} from "../stateView/interface.js";
7
- import {ISignatureSet} from "../util/index.js";
6
+ import {IBeaconStateView, IBeaconStateViewGloas} from "../stateView/interface.js";
7
+ import {ISignatureSet, createAggregateSignatureSetFromComponents} from "../util/index.js";
8
8
  import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js";
9
9
  import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js";
10
10
  import {getAttestationsSignatureSets} from "./indexedAttestation.js";
11
+ import {getPayloadAttestationDataSigningRoot} from "./indexedPayloadAttestation.js";
11
12
  import {getBlockProposerSignatureSet} from "./proposer.js";
12
13
  import {getProposerSlashingsSignatureSets} from "./proposerSlashings.js";
13
14
  import {getRandaoRevealSignatureSet} from "./randao.js";
@@ -79,5 +80,18 @@ export function getBlockSignatureSets(
79
80
  }
80
81
  }
81
82
 
83
+ if (fork >= ForkSeq.gloas) {
84
+ for (const payloadAttestation of (signedBlock as gloas.SignedBeaconBlock).message.body.payloadAttestations) {
85
+ const ptc = (state as IBeaconStateViewGloas).getPayloadTimelinessCommittee(payloadAttestation.data.slot);
86
+ signatureSets.push(
87
+ createAggregateSignatureSetFromComponents(
88
+ payloadAttestation.aggregationBits.intersectValues(ptc),
89
+ getPayloadAttestationDataSigningRoot(config, payloadAttestation.data),
90
+ payloadAttestation.signature
91
+ )
92
+ );
93
+ }
94
+ }
95
+
82
96
  return signatureSets;
83
97
  }
@@ -110,7 +110,7 @@ export function upgradeStateToGloas(
110
110
  ssz.gloas.PendingConsolidations
111
111
  );
112
112
  stateGloasView.proposerLookahead = stateGloasCloned.proposerLookahead;
113
- stateGloasView.ptcWindow = ssz.gloas.PtcWindow.toViewDU(initializePtcWindow(stateFulu));
113
+ stateGloasView.ptcWindow = ssz.gloas.PayloadTimelinessCommitteeWindow.toViewDU(initializePtcWindow(stateFulu));
114
114
 
115
115
  for (let i = 0; i < SLOTS_PER_HISTORICAL_ROOT; i++) {
116
116
  stateGloasView.executionPayloadAvailability.set(i, true);